diff --git a/README.md b/README.md index 6d6dd3b..a8d1bbf 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ This package is still working in progress. More types would be added. Welcome an - Circle Loop2 - Pixel Hole - Dots Wave +- Circle Move For these kinds of art, the package provides as many parameters to control the appearance. @@ -71,6 +72,7 @@ NewNoiseLine(n int) NewCircleLoop2(depth int) NewPixelHole(dotN int) NewDotsWave(dotsN int) +NewCircleMove(circleNum int) ``` ## Docs @@ -419,22 +421,20 @@ func main() { ![](images/silksky.png) -### Maze +### Circle Move ```go func main() { rand.Seed(time.Now().Unix()) - c := generativeart.NewCanva(600, 600) - c.SetBackground(generativeart.Azure) - c.SetLineWidth(3) - c.SetLineColor(generativeart.Orange) + c := generativeart.NewCanva(1200, 500) + c.SetBackground(common.White) c.FillBackground() - c.Draw(generativeart.NewMaze(20)) - c.ToPNG("maze.png") + c.Draw(generativeart.NewCircleMove(1000)) + c.ToPNG("circlemove.png") } ``` -![](images/maze.png) +![](images/circlemove.png) ### Random Circle diff --git a/circlemove.go b/circlemove.go new file mode 100644 index 0000000..ff67389 --- /dev/null +++ b/circlemove.go @@ -0,0 +1,60 @@ +package generativeart + +import ( + "github.com/fogleman/gg" + "github.com/jdxyw/generativeart/common" + "math" + "math/rand" +) + +type circleMove struct { + circleNum int +} + +func NewCircleMove(circleNum int) *circleMove { + return &circleMove{ + circleNum: circleNum, + } +} + +// Generative draws a sircle moving images. +func (cm *circleMove) Generative(c *canva) { + ctex := gg.NewContextForRGBA(c.img) + ctex.SetLineWidth(0.3) + noise := common.NewPerlinNoise() + cl := rand.Intn(255) + for i := 0; i < cm.circleNum; i++ { + //var sx, sy float64 + var cxx float64 + var np = 300.0 + for j := 0.0; j < np; j += 1.0 { + theta := common.Remap(j, 0, np, 0, math.Pi*2) + cx := float64(i)*3 - 200.0 + cy := float64(c.height)/2 + math.Sin(float64(i)/50)*float64(c.height)/12.0 + xx := math.Cos(theta+cx/10)*float64(c.height)/6.0 + yy := math.Sin(theta+cx/10)*float64(c.height)/6.0 + p := common.NewVector(xx, yy) + xx = (xx + cx) / 150 + yy = (yy + cy) / 150 + p.Multiple(1 + 1.5*noise.Noise2D(xx, yy)) + ctex.LineTo(cx+p.X, cy+p.Y) + cxx = cx + } + hue := int(cxx/4) - cl + if hue < 0 { + hue += 255 + } + + h := common.HSV{ + H: hue, + S: 180, + V: 120, + } + + rgba := h.ToRGB(255, 255, 255) + rgba.A = 255 + ctex.SetColor(rgba) + ctex.Stroke() + ctex.ClosePath() + } +} diff --git a/common/blend.go b/common/blend.go index 23dede2..0af8504 100644 --- a/common/blend.go +++ b/common/blend.go @@ -14,14 +14,14 @@ const ( func Blend(src, dest *image.RGBA, mode BlendMode) *image.RGBA { img := image.NewRGBA(src.Bounds()) - for i := 0; i b{ +func MaxInt(a, b int) int { + if a > b { return a } return b diff --git a/common/calculation_test.go b/common/calculation_test.go index f52acdc..f39d14e 100644 --- a/common/calculation_test.go +++ b/common/calculation_test.go @@ -13,9 +13,9 @@ func TestConstrain(t *testing.T) { args args want float64 }{ - {name: "testcase1", args: args{val: 1.0, low:0.5, high: 1.5}, want: 1.0}, - {name: "testcase2", args: args{val: 0.4, low:0.5, high: 1.5}, want: 0.5}, - {name: "testcase3", args: args{val: -1.0, low:-3.5, high: 1.5}, want: -1.0}, + {name: "testcase1", args: args{val: 1.0, low: 0.5, high: 1.5}, want: 1.0}, + {name: "testcase2", args: args{val: 0.4, low: 0.5, high: 1.5}, want: 0.5}, + {name: "testcase3", args: args{val: -1.0, low: -3.5, high: 1.5}, want: -1.0}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -48,4 +48,4 @@ func TestConstrainInt(t *testing.T) { } }) } -} \ No newline at end of file +} diff --git a/common/vector.go b/common/vector.go new file mode 100644 index 0000000..d814468 --- /dev/null +++ b/common/vector.go @@ -0,0 +1,17 @@ +package common + +type Vector struct { + X, Y float64 +} + +func NewVector(x, y float64) *Vector { + return &Vector{ + X: x, + Y: y, + } +} + +func (v *Vector) Multiple(z float64) { + v.X = v.X * z + v.Y = v.Y * z +} diff --git a/docs/doc.md b/docs/doc.md index ad6f5ec..6cc6725 100644 --- a/docs/doc.md +++ b/docs/doc.md @@ -162,4 +162,17 @@ ph := generativeart.NewPixelHole(60) d := generativeart.NewDotsWave(300) ``` -![](../images/dotswave.png) \ No newline at end of file +![](../images/dotswave.png) + +## Circle Move + +### parameters + +- circleNum: The number of the circle in the image. + + +```go +cm := generativeart.NewCircleMove(1000) +``` + +![](../images/circlemove.png) \ No newline at end of file diff --git a/example/example_circlemove.go b/example/example_circlemove.go new file mode 100644 index 0000000..26bef51 --- /dev/null +++ b/example/example_circlemove.go @@ -0,0 +1,17 @@ +package main + +import ( + "github.com/jdxyw/generativeart" + "github.com/jdxyw/generativeart/common" + "math/rand" + "time" +) + +func main() { + rand.Seed(time.Now().Unix()) + c := generativeart.NewCanva(1200, 500) + c.SetBackground(common.White) + c.FillBackground() + c.Draw(generativeart.NewCircleMove(1000)) + c.ToPNG("circlemove.png") +} diff --git a/generativeart.go b/generativeart.go index 85f47c7..2a86004 100644 --- a/generativeart.go +++ b/generativeart.go @@ -31,11 +31,11 @@ type Options struct { } // NewCanva returns a canva. -func NewCanva(h, w int) *canva { +func NewCanva(w, h int) *canva { return &canva{ height: h, width: w, - img: image.NewRGBA(image.Rect(0, 0, h, w)), + img: image.NewRGBA(image.Rect(0, 0, w, h)), // Set some defaults value opts: Options{ background: common.Azure, diff --git a/images/circlemove.png b/images/circlemove.png new file mode 100644 index 0000000..8e41661 Binary files /dev/null and b/images/circlemove.png differ diff --git a/solarflare.go b/solarflare.go index e112276..770683d 100644 --- a/solarflare.go +++ b/solarflare.go @@ -16,7 +16,6 @@ func NewSolarFlare() *solarFlare { return &solarFlare{} } - // Generative draws a solar flare images. func (o *solarFlare) Generative(c *canva) { var xOffset, yOffset float64 @@ -26,14 +25,13 @@ func (o *solarFlare) Generative(c *canva) { var m = 1.005 noise := common.NewPerlinNoise() - for r < 200 { - for i :=0; i <10; i++ { - nPoints := int(2*math.Pi*r) + for i := 0; i < 10; i++ { + nPoints := int(2 * math.Pi * r) nPoints = common.MinInt(nPoints, 500) img := image.NewRGBA(image.Rect(0, 0, c.width, c.height)) - draw.Draw(img, img.Bounds(), &image.Uniform{color.RGBA{0,0,0,255}}, image.ZP, draw.Src) + draw.Draw(img, img.Bounds(), &image.Uniform{color.Black}, image.ZP, draw.Src) ctex := gg.NewContextForRGBA(img) ctex.Push() @@ -41,11 +39,11 @@ func (o *solarFlare) Generative(c *canva) { ctex.SetLineWidth(1.0) ctex.SetColor(c.opts.lineColor) - for j :=0.0; j