refactor perline noise; add circle loop2

This commit is contained in:
Yongwei Xing 2021-03-11 11:24:14 +08:00
parent a1f1c00a3a
commit 3328f24db7
9 changed files with 186 additions and 10 deletions

View file

@ -35,6 +35,7 @@ This package is still working in progress. More types would be added. Welcome an
- Contour Line
- Noise Line
- Ocean Fish
- Circle Loop2
For these kinds of art, the package provides as many parameters to control the appearance.
@ -66,6 +67,7 @@ NewColorCircle2(circleNum int)
NewCircleGrid(circleNumMin, circleNumMax int)
NewContourLine(lineNum int)
NewNoiseLine(n int)
NewCircleLoop2(depth int)
```
## Docs
@ -181,6 +183,29 @@ func main() {
![](images/circlegrid.png)
## Circle Composes Circle
```go
func main() {
rand.Seed(time.Now().Unix())
colors := []color.RGBA{
{0xF9, 0xC8, 0x0E, 0xFF},
{0xF8, 0x66, 0x24, 0xFF},
{0xEA, 0x35, 0x46, 0xFF},
{0x66, 0x2E, 0x9B, 0xFF},
{0x43, 0xBC, 0xCD, 0xFF},
}
c := generativeart.NewCanva(500, 500)
c.SetBackground(color.RGBA{8, 10, 20, 255})
c.FillBackground()
c.SetColorSchema(colors)
c.Draw(generativeart.NewCircleLoop2(7))
c.ToPNG("colorloop2.png")
}
```
![](images/colorloop2.png)
### Silk Smoke
```go
@ -390,7 +415,7 @@ func main() {
## Contribution
Thanks for the following sites and repos, I got lots of ideas, inspiration, code and tricks from them. The list would be very long, sorry for forgetting some of them.
Thanks for the following sites and repos, I got lots of ideas, inspiration, code, and tricks from them. The list would be very long; sorry for forgetting some of them.
- https://inconvergent.net/
- https://fronkonstin.com/
@ -407,3 +432,4 @@ Thanks for the following sites and repos, I got lots of ideas, inspiration, code
- https://twitter.com/okazz_
- https://openprocessing.org/sketch/738638
- https://openprocessing.org/sketch/1102157
- https://openprocessing.org/sketch/1071233

80
circleloop2.go Normal file
View file

@ -0,0 +1,80 @@
package generativeart
import (
"github.com/fogleman/gg"
"github.com/jdxyw/generativeart/common"
"math"
"math/rand"
)
type circleLoop2 struct {
depth int
noise *common.PerlinNoise
}
func NewCircleLoop2(depth int) *circleLoop2 {
return &circleLoop2{
depth: depth,
noise: common.NewPerlinNoise(),
}
}
// Generative draws a circle composed by many colored circles.
func (cl *circleLoop2) Generative(c *canva) {
ctex := gg.NewContextForRGBA(c.img)
ctex.Translate(float64(c.width)/2, float64(c.height)/2)
cl.recursionDraw(ctex, c, float64(c.width), cl.depth)
}
func (cl *circleLoop2) recursionDraw(ctex *gg.Context, c *canva, x float64, depth int) {
if depth <= 0 {
return
}
cl.draw(ctex, c, x)
cl.recursionDraw(ctex, c, 1*x/4.0, depth-1)
cl.recursionDraw(ctex, c, 2*x/4.0, depth-1)
cl.recursionDraw(ctex, c, 3*x/4.0, depth-1)
}
func (cl *circleLoop2) draw(ctex *gg.Context, c *canva, x float64) {
var lw float64
if rand.Float64() < 0.8 {
lw = 1
} else {
lw = common.RandomRangeFloat64(1.0, common.RandomRangeFloat64(1, 3))
}
ctex.SetLineWidth(lw)
noise := cl.noise.Noise3D(x*0.02+123.234, (1-x)*0.02, 345.4123)
noise = math.Pow(noise, 0.5)
a2 := common.Remap(noise, 0.15, 0.85, 0.1, 0.6)
px := math.Pow(x/float64(c.height), a2) * float64(c.height)
py := math.Pow(1-x/float64(c.height), a2)*float64(c.height) -
common.RandomRangeFloat64(0, common.RandomRangeFloat64(float64(c.height)*0.18, common.RandomRangeFloat64(float64(c.height)*0.18, float64(c.height)*0.7)))
cls := c.opts.colorSchema[rand.Intn(len(c.opts.colorSchema))]
ctex.SetColor(cls)
nCircles := common.RandomRangeInt(1, 6)
if rand.Float64() < 0.03 {
nCircles = common.RandomRangeInt(8, 10)
}
r := math.Pow(rand.Float64(), 2) * 50
var flag bool
if rand.Float64() < 0.7 {
flag = true
}
for i := 0; i < nCircles; i++ {
if flag {
ctex.DrawCircle(px*0.39, py*0.39, rand.Float64()*float64(i)*r/float64(nCircles))
} else {
ctex.DrawCircle(px*0.39, py*0.39, float64(i)*r/float64(nCircles))
}
ctex.Stroke()
}
ctex.Rotate(x / float64(c.height) * 0.2)
}

19
common/calculation.go Normal file
View file

@ -0,0 +1,19 @@
package common
import "math"
// Constrain returns a value between a minimum and maximum value.
func Constrain(val, low, high float64) float64 {
return math.Max(math.Min(val, high), low)
}
// Remap re-maps a number from one range to another.
func Remap(n, start1, stop1, start2, stop2 float64) float64 {
newval := (n-start1)/(stop1-start1)*(stop2-start2) + start2
if start2 < stop2 {
return Constrain(newval, start2, stop2)
} else {
return Constrain(newval, stop2, start2)
}
}

View file

@ -15,12 +15,12 @@ const (
perlinAmpFalloff = 0.5
)
type perlinNoise struct {
type PerlinNoise struct {
perlin []float64
}
func NewPerlinNoise() *perlinNoise {
perlin := &perlinNoise{perlin: nil}
func NewPerlinNoise() *PerlinNoise {
perlin := &PerlinNoise{perlin: nil}
perlin.perlin = make([]float64, perlinSize+1)
for i, _ := range perlin.perlin {
@ -29,7 +29,19 @@ func NewPerlinNoise() *perlinNoise {
return perlin
}
func (p *perlinNoise) Noise(x, y, z float64) float64 {
func (p *PerlinNoise) Noise1D(x float64) float64 {
return p.noise(x, 0, 0)
}
func (p *PerlinNoise) Noise2D(x, y float64) float64 {
return p.noise(x, y, 0)
}
func (p *PerlinNoise) Noise3D(x, y, z float64) float64 {
return p.noise(x, y, z)
}
func (p *PerlinNoise) noise(x, y, z float64) float64 {
if x < 0 {
x = -x
}

View file

@ -29,7 +29,7 @@ func (cl *contourLine) Generative(c *canva) {
for j := 0; j < 1500; j++ {
theta := noise.Noise(x/800.0, y/800.0, 0) * math.Pi * 2 * 800
theta := noise.Noise2D(x/800.0, y/800.0) * math.Pi * 2 * 800
x += math.Cos(theta) * 0.4
y += math.Sin(theta) * 0.4

View file

@ -111,7 +111,7 @@ nl := generativeart.NewNoiseLine(1000)
## Ocean Fish
`Ocean Fish` draws a ocean and some fishes in the center.
`Ocean Fish` draws an ocean and some fishes in the center.
### parameters
@ -123,3 +123,17 @@ o := generativeart.NewOceanFish(100, 8)
```
![](../images/oceanfish.png)
## Circle Loop2
`Circle loop2` draws a circle composed by colored circles.
### parameters
- depth: Control the number of circles.
```go
cl := generativeart.NewCircleLoop2(7)
```
![](../images/colorloop2.png)

View file

@ -0,0 +1,25 @@
package main
import (
"github.com/jdxyw/generativeart"
"image/color"
"math/rand"
"time"
)
func main() {
rand.Seed(time.Now().Unix())
colors := []color.RGBA{
{0xF9, 0xC8, 0x0E, 0xFF},
{0xF8, 0x66, 0x24, 0xFF},
{0xEA, 0x35, 0x46, 0xFF},
{0x66, 0x2E, 0x9B, 0xFF},
{0x43, 0xBC, 0xCD, 0xFF},
}
c := generativeart.NewCanva(500, 500)
c.SetBackground(color.RGBA{8, 10, 20, 255})
c.FillBackground()
c.SetColorSchema(colors)
c.Draw(generativeart.NewCircleLoop2(7))
c.ToPNG("colorloop2.png")
}

BIN
images/colorloop2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 KiB

View file

@ -45,7 +45,7 @@ func (nl *noiseLine) Generative(c *canva) {
for j := 0; j < l; j++ {
var ns = 0.0005
w := math.Sin(math.Pi*float64(j)/float64(l-1)) * 5
theta := noise.Noise(x*ns, y*ns, t) * 100
theta := noise.Noise3D(x*ns, y*ns, t) * 100
ctex.SetColor(cl)
ctex.DrawCircle(x, y, w)
ctex.Fill()