add circle move

This commit is contained in:
Yongwei Xing 2021-03-16 11:33:09 +08:00
parent 4a07d63005
commit 27fac585da
11 changed files with 151 additions and 55 deletions

View file

@ -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

60
circlemove.go Normal file
View file

@ -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()
}
}

View file

@ -14,14 +14,14 @@ const (
func Blend(src, dest *image.RGBA, mode BlendMode) *image.RGBA {
img := image.NewRGBA(src.Bounds())
for i := 0; i <src.Bounds().Max.X; i++ {
for j :=0; j<src.Bounds().Max.Y; j++ {
for i := 0; i < src.Bounds().Max.X; i++ {
for j := 0; j < src.Bounds().Max.Y; j++ {
switch mode {
case Add:
if compareColor(src.At(i, j), Black) {
img.Set(i, j, dest.At(i, j))
if compareColor(src.RGBAAt(i, j), Black) {
img.Set(i, j, dest.RGBAAt(i, j))
} else {
img.SetRGBA(i, j, add(src.At(i, j), dest.At(i, j)))
img.SetRGBA(i, j, add(src.RGBAAt(i, j), dest.RGBAAt(i, j)))
}
}
}
@ -29,9 +29,9 @@ func Blend(src, dest *image.RGBA, mode BlendMode) *image.RGBA {
return img
}
func compareColor(src, dst color.Color) bool {
sr, sg, sb ,sa := src.RGBA()
dr, dg, db, da := dst.RGBA()
func compareColor(src, dst color.RGBA) bool {
sr, sg, sb, sa := src.R, src.G, src.B, src.A
dr, dg, db, da := dst.R, dst.G, dst.B, dst.A
if sr == dr && sg == dg && sb == db && sa == da {
return true
@ -39,24 +39,18 @@ func compareColor(src, dst color.Color) bool {
return false
}
func add(srcC, dstC color.Color) color.RGBA {
func add(srcC, dstC color.RGBA) color.RGBA {
c := color.RGBA{}
sr, sg, sb ,sa := srcC.RGBA()
dr, dg, db, da := dstC.RGBA()
sr, sg, sb, sa := srcC.R, srcC.G, srcC.B, srcC.A
dr, dg, db, da := dstC.R, dstC.G, dstC.B, dstC.A
//aSrc := float64(sa)/255.0
//aDst := 1.0 - aSrc
aSrc := float64(sa) / 255.0
aDst := 1.0 - aSrc
//c.R = uint8(float64(sr) * aSrc + float64(dr)*aDst)
//c.G = uint8(float64(sg) * aSrc + float64(dg)*aDst)
//c.B = uint8(float64(sb) * aSrc + float64(db)*aDst)
//c.A = uint8(float64(sa) * aSrc + float64(da)*aDst)
c.R = uint8(ConstrainInt(int(uint32(float64(sr)*0.05)+dr), 0, 255))
c.G = uint8(ConstrainInt(int(uint32(float64(sg)*0.05)+dg), 0, 255))
c.B = uint8(ConstrainInt(int(uint32(float64(sb)*0.05)+db), 0, 255))
c.A = uint8(ConstrainInt(int(uint32(float64(sa)*0.9)+da), 0, 255))
//c.A = uint8(float64(sa) * aSrc + float64(da)*aDst)
c.R = uint8(ConstrainInt(int(float64(sr)*aSrc+float64(dr)*aDst), 0, 255))
c.G = uint8(ConstrainInt(int(float64(sg)*aSrc+float64(dg)*aDst), 0, 255))
c.B = uint8(ConstrainInt(int(float64(sb)*aSrc+float64(db)*aDst), 0, 255))
c.A = uint8(ConstrainInt(int(float64(sa)*aSrc+float64(da)*aDst), 0, 255))
return c
}
}

View file

@ -15,15 +15,15 @@ func ConstrainInt(val, low, high int) int {
return MaxInt(MinInt(val, high), low)
}
func MinInt(a, b int)int {
func MinInt(a, b int) int {
if a < b {
return a
}
return b
}
func MaxInt(a, b int)int {
if a > b{
func MaxInt(a, b int) int {
if a > b {
return a
}
return b

View file

@ -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) {
}
})
}
}
}

17
common/vector.go Normal file
View file

@ -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
}

View file

@ -162,4 +162,17 @@ ph := generativeart.NewPixelHole(60)
d := generativeart.NewDotsWave(300)
```
![](../images/dotswave.png)
![](../images/dotswave.png)
## Circle Move
### parameters
- circleNum: The number of the circle in the image.
```go
cm := generativeart.NewCircleMove(1000)
```
![](../images/circlemove.png)

View file

@ -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")
}

View file

@ -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,

BIN
images/circlemove.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 KiB

View file

@ -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<float64(nPoints+1); j+=1.0 {
a := j/float64(nPoints) * math.Pi * 2
for j := 0.0; j < float64(nPoints+1); j += 1.0 {
a := j / float64(nPoints) * math.Pi * 2
px := math.Cos(a)
py := math.Sin(a)
n := noise.Noise2D(xOffset + px * inc, yOffset + py * inc)*r
n := noise.Noise2D(xOffset+px*inc, yOffset+py*inc) * r
px *= n
py *= n
ctex.LineTo(px, py)
@ -54,12 +52,9 @@ func (o *solarFlare) Generative(c *canva) {
ctex.Pop()
c.img = common.Blend(img, c.img, common.Add)
//cc := NewCanva(0,0)
//cc.img = c.img
//cc.ToPNG(fmt.Sprintf("xxxx%v.png", r))
xOffset += offsetInc
yOffset += offsetInc
r*=m
r *= m
}
}
}
}