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 - Contour Line
- Noise Line - Noise Line
- Ocean Fish - Ocean Fish
- Circle Loop2
For these kinds of art, the package provides as many parameters to control the appearance. 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) NewCircleGrid(circleNumMin, circleNumMax int)
NewContourLine(lineNum int) NewContourLine(lineNum int)
NewNoiseLine(n int) NewNoiseLine(n int)
NewCircleLoop2(depth int)
``` ```
## Docs ## Docs
@ -181,6 +183,29 @@ func main() {
![](images/circlegrid.png) ![](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 ### Silk Smoke
```go ```go
@ -390,7 +415,7 @@ func main() {
## Contribution ## 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://inconvergent.net/
- https://fronkonstin.com/ - https://fronkonstin.com/
@ -406,4 +431,5 @@ Thanks for the following sites and repos, I got lots of ideas, inspiration, code
- https://openprocessing.org/sketch/1071233 - https://openprocessing.org/sketch/1071233
- https://twitter.com/okazz_ - https://twitter.com/okazz_
- https://openprocessing.org/sketch/738638 - https://openprocessing.org/sketch/738638
- https://openprocessing.org/sketch/1102157 - 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 perlinAmpFalloff = 0.5
) )
type perlinNoise struct { type PerlinNoise struct {
perlin []float64 perlin []float64
} }
func NewPerlinNoise() *perlinNoise { func NewPerlinNoise() *PerlinNoise {
perlin := &perlinNoise{perlin: nil} perlin := &PerlinNoise{perlin: nil}
perlin.perlin = make([]float64, perlinSize+1) perlin.perlin = make([]float64, perlinSize+1)
for i, _ := range perlin.perlin { for i, _ := range perlin.perlin {
@ -29,7 +29,19 @@ func NewPerlinNoise() *perlinNoise {
return perlin 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 { if x < 0 {
x = -x x = -x
} }

View file

@ -29,7 +29,7 @@ func (cl *contourLine) Generative(c *canva) {
for j := 0; j < 1500; j++ { 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 x += math.Cos(theta) * 0.4
y += math.Sin(theta) * 0.4 y += math.Sin(theta) * 0.4

View file

@ -111,7 +111,7 @@ nl := generativeart.NewNoiseLine(1000)
## Ocean Fish ## 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 ### parameters
@ -122,4 +122,18 @@ nl := generativeart.NewNoiseLine(1000)
o := generativeart.NewOceanFish(100, 8) o := generativeart.NewOceanFish(100, 8)
``` ```
![](../images/oceanfish.png) ![](../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++ { for j := 0; j < l; j++ {
var ns = 0.0005 var ns = 0.0005
w := math.Sin(math.Pi*float64(j)/float64(l-1)) * 5 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.SetColor(cl)
ctex.DrawCircle(x, y, w) ctex.DrawCircle(x, y, w)
ctex.Fill() ctex.Fill()