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
|
||||
- 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
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 {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
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)
|
||||
```
|
||||
|
||||
![](../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.
|
||||
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
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{}
|
||||
}
|
||||
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue