add circle move
This commit is contained in:
parent
4a07d63005
commit
27fac585da
11 changed files with 151 additions and 55 deletions
16
README.md
16
README.md
|
@ -37,6 +37,7 @@ This package is still working in progress. More types would be added. Welcome an
|
||||||
- Circle Loop2
|
- Circle Loop2
|
||||||
- Pixel Hole
|
- Pixel Hole
|
||||||
- Dots Wave
|
- Dots Wave
|
||||||
|
- Circle Move
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
|
@ -71,6 +72,7 @@ NewNoiseLine(n int)
|
||||||
NewCircleLoop2(depth int)
|
NewCircleLoop2(depth int)
|
||||||
NewPixelHole(dotN int)
|
NewPixelHole(dotN int)
|
||||||
NewDotsWave(dotsN int)
|
NewDotsWave(dotsN int)
|
||||||
|
NewCircleMove(circleNum int)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Docs
|
## Docs
|
||||||
|
@ -419,22 +421,20 @@ func main() {
|
||||||
|
|
||||||
![](images/silksky.png)
|
![](images/silksky.png)
|
||||||
|
|
||||||
### Maze
|
### Circle Move
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func main() {
|
func main() {
|
||||||
rand.Seed(time.Now().Unix())
|
rand.Seed(time.Now().Unix())
|
||||||
c := generativeart.NewCanva(600, 600)
|
c := generativeart.NewCanva(1200, 500)
|
||||||
c.SetBackground(generativeart.Azure)
|
c.SetBackground(common.White)
|
||||||
c.SetLineWidth(3)
|
|
||||||
c.SetLineColor(generativeart.Orange)
|
|
||||||
c.FillBackground()
|
c.FillBackground()
|
||||||
c.Draw(generativeart.NewMaze(20))
|
c.Draw(generativeart.NewCircleMove(1000))
|
||||||
c.ToPNG("maze.png")
|
c.ToPNG("circlemove.png")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
![](images/maze.png)
|
![](images/circlemove.png)
|
||||||
|
|
||||||
### Random Circle
|
### Random Circle
|
||||||
|
|
||||||
|
|
60
circlemove.go
Normal file
60
circlemove.go
Normal 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()
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,14 +14,14 @@ const (
|
||||||
func Blend(src, dest *image.RGBA, mode BlendMode) *image.RGBA {
|
func Blend(src, dest *image.RGBA, mode BlendMode) *image.RGBA {
|
||||||
img := image.NewRGBA(src.Bounds())
|
img := image.NewRGBA(src.Bounds())
|
||||||
|
|
||||||
for i := 0; i <src.Bounds().Max.X; i++ {
|
for i := 0; i < src.Bounds().Max.X; i++ {
|
||||||
for j :=0; j<src.Bounds().Max.Y; j++ {
|
for j := 0; j < src.Bounds().Max.Y; j++ {
|
||||||
switch mode {
|
switch mode {
|
||||||
case Add:
|
case Add:
|
||||||
if compareColor(src.At(i, j), Black) {
|
if compareColor(src.RGBAAt(i, j), Black) {
|
||||||
img.Set(i, j, dest.At(i, j))
|
img.Set(i, j, dest.RGBAAt(i, j))
|
||||||
} else {
|
} 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
|
return img
|
||||||
}
|
}
|
||||||
|
|
||||||
func compareColor(src, dst color.Color) bool {
|
func compareColor(src, dst color.RGBA) bool {
|
||||||
sr, sg, sb ,sa := src.RGBA()
|
sr, sg, sb, sa := src.R, src.G, src.B, src.A
|
||||||
dr, dg, db, da := dst.RGBA()
|
dr, dg, db, da := dst.R, dst.G, dst.B, dst.A
|
||||||
|
|
||||||
if sr == dr && sg == dg && sb == db && sa == da {
|
if sr == dr && sg == dg && sb == db && sa == da {
|
||||||
return true
|
return true
|
||||||
|
@ -39,24 +39,18 @@ func compareColor(src, dst color.Color) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func add(srcC, dstC color.Color) color.RGBA {
|
func add(srcC, dstC color.RGBA) color.RGBA {
|
||||||
c := color.RGBA{}
|
c := color.RGBA{}
|
||||||
sr, sg, sb ,sa := srcC.RGBA()
|
sr, sg, sb, sa := srcC.R, srcC.G, srcC.B, srcC.A
|
||||||
dr, dg, db, da := dstC.RGBA()
|
dr, dg, db, da := dstC.R, dstC.G, dstC.B, dstC.A
|
||||||
|
|
||||||
//aSrc := float64(sa)/255.0
|
aSrc := float64(sa) / 255.0
|
||||||
//aDst := 1.0 - aSrc
|
aDst := 1.0 - aSrc
|
||||||
|
|
||||||
//c.R = uint8(float64(sr) * aSrc + float64(dr)*aDst)
|
c.R = uint8(ConstrainInt(int(float64(sr)*aSrc+float64(dr)*aDst), 0, 255))
|
||||||
//c.G = uint8(float64(sg) * aSrc + float64(dg)*aDst)
|
c.G = uint8(ConstrainInt(int(float64(sg)*aSrc+float64(dg)*aDst), 0, 255))
|
||||||
//c.B = uint8(float64(sb) * aSrc + float64(db)*aDst)
|
c.B = uint8(ConstrainInt(int(float64(sb)*aSrc+float64(db)*aDst), 0, 255))
|
||||||
//c.A = uint8(float64(sa) * aSrc + float64(da)*aDst)
|
c.A = uint8(ConstrainInt(int(float64(sa)*aSrc+float64(da)*aDst), 0, 255))
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,15 +15,15 @@ func ConstrainInt(val, low, high int) int {
|
||||||
return MaxInt(MinInt(val, high), low)
|
return MaxInt(MinInt(val, high), low)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MinInt(a, b int)int {
|
func MinInt(a, b int) int {
|
||||||
if a < b {
|
if a < b {
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
func MaxInt(a, b int)int {
|
func MaxInt(a, b int) int {
|
||||||
if a > b{
|
if a > b {
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
return b
|
return b
|
||||||
|
|
|
@ -13,9 +13,9 @@ func TestConstrain(t *testing.T) {
|
||||||
args args
|
args args
|
||||||
want float64
|
want float64
|
||||||
}{
|
}{
|
||||||
{name: "testcase1", args: args{val: 1.0, low:0.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: "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: "testcase3", args: args{val: -1.0, low: -3.5, high: 1.5}, want: -1.0},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
@ -48,4 +48,4 @@ func TestConstrainInt(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
17
common/vector.go
Normal file
17
common/vector.go
Normal 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
|
||||||
|
}
|
15
docs/doc.md
15
docs/doc.md
|
@ -162,4 +162,17 @@ ph := generativeart.NewPixelHole(60)
|
||||||
d := generativeart.NewDotsWave(300)
|
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)
|
17
example/example_circlemove.go
Normal file
17
example/example_circlemove.go
Normal 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")
|
||||||
|
}
|
|
@ -31,11 +31,11 @@ type Options struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCanva returns a canva.
|
// NewCanva returns a canva.
|
||||||
func NewCanva(h, w int) *canva {
|
func NewCanva(w, h int) *canva {
|
||||||
return &canva{
|
return &canva{
|
||||||
height: h,
|
height: h,
|
||||||
width: w,
|
width: w,
|
||||||
img: image.NewRGBA(image.Rect(0, 0, h, w)),
|
img: image.NewRGBA(image.Rect(0, 0, w, h)),
|
||||||
// Set some defaults value
|
// Set some defaults value
|
||||||
opts: Options{
|
opts: Options{
|
||||||
background: common.Azure,
|
background: common.Azure,
|
||||||
|
|
BIN
images/circlemove.png
Normal file
BIN
images/circlemove.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 315 KiB |
|
@ -16,7 +16,6 @@ func NewSolarFlare() *solarFlare {
|
||||||
return &solarFlare{}
|
return &solarFlare{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Generative draws a solar flare images.
|
// Generative draws a solar flare images.
|
||||||
func (o *solarFlare) Generative(c *canva) {
|
func (o *solarFlare) Generative(c *canva) {
|
||||||
var xOffset, yOffset float64
|
var xOffset, yOffset float64
|
||||||
|
@ -26,14 +25,13 @@ func (o *solarFlare) Generative(c *canva) {
|
||||||
var m = 1.005
|
var m = 1.005
|
||||||
noise := common.NewPerlinNoise()
|
noise := common.NewPerlinNoise()
|
||||||
|
|
||||||
|
|
||||||
for r < 200 {
|
for r < 200 {
|
||||||
for i :=0; i <10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
nPoints := int(2*math.Pi*r)
|
nPoints := int(2 * math.Pi * r)
|
||||||
nPoints = common.MinInt(nPoints, 500)
|
nPoints = common.MinInt(nPoints, 500)
|
||||||
|
|
||||||
img := image.NewRGBA(image.Rect(0, 0, c.width, c.height))
|
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 := gg.NewContextForRGBA(img)
|
||||||
|
|
||||||
ctex.Push()
|
ctex.Push()
|
||||||
|
@ -41,11 +39,11 @@ func (o *solarFlare) Generative(c *canva) {
|
||||||
ctex.SetLineWidth(1.0)
|
ctex.SetLineWidth(1.0)
|
||||||
ctex.SetColor(c.opts.lineColor)
|
ctex.SetColor(c.opts.lineColor)
|
||||||
|
|
||||||
for j :=0.0; j<float64(nPoints+1); j+=1.0 {
|
for j := 0.0; j < float64(nPoints+1); j += 1.0 {
|
||||||
a := j/float64(nPoints) * math.Pi * 2
|
a := j / float64(nPoints) * math.Pi * 2
|
||||||
px := math.Cos(a)
|
px := math.Cos(a)
|
||||||
py := math.Sin(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
|
px *= n
|
||||||
py *= n
|
py *= n
|
||||||
ctex.LineTo(px, py)
|
ctex.LineTo(px, py)
|
||||||
|
@ -54,12 +52,9 @@ func (o *solarFlare) Generative(c *canva) {
|
||||||
ctex.Pop()
|
ctex.Pop()
|
||||||
|
|
||||||
c.img = common.Blend(img, c.img, common.Add)
|
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
|
xOffset += offsetInc
|
||||||
yOffset += offsetInc
|
yOffset += offsetInc
|
||||||
r*=m
|
r *= m
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue