132 lines
2.7 KiB
Go
132 lines
2.7 KiB
Go
package arts
|
|
|
|
import (
|
|
"github.com/fogleman/gg"
|
|
"github.com/jdxyw/generativeart"
|
|
"github.com/jdxyw/generativeart/common"
|
|
"math"
|
|
"math/rand"
|
|
)
|
|
|
|
type circle struct {
|
|
x, y float64
|
|
radius float64
|
|
dx, dy float64
|
|
}
|
|
|
|
type randCircle struct {
|
|
maxCircle int
|
|
maxStepsPerCircle int
|
|
minSteps float64
|
|
maxSteps float64
|
|
minRadius float64
|
|
maxRadius float64
|
|
isRandColor bool
|
|
}
|
|
|
|
func NewRandCicle(mc, msp int, minStep, maxStep, minr, maxr float64, isRandColor bool) *randCircle {
|
|
return &randCircle{
|
|
maxCircle: mc,
|
|
maxStepsPerCircle: msp,
|
|
minSteps: minStep,
|
|
maxSteps: maxStep,
|
|
minRadius: minr,
|
|
maxRadius: maxr,
|
|
isRandColor: isRandColor,
|
|
}
|
|
}
|
|
|
|
func newCircleSlice(cn, w, h int, minStep, maxStep, minRadius, maxRadius float64) []circle {
|
|
var circles []circle
|
|
|
|
for i := 0; i < cn; i++ {
|
|
x := rand.Intn(w) + 1
|
|
y := rand.Intn(h) + 1
|
|
radius := float64(rand.Intn(int(minRadius))) + maxRadius - minRadius
|
|
angle := rand.Float64() * math.Pi * 2.0
|
|
step := minStep + rand.Float64()*(maxStep-minStep)
|
|
circles = append(circles, circle{
|
|
x: float64(x),
|
|
y: float64(y),
|
|
radius: radius,
|
|
dx: step * math.Cos(angle),
|
|
dy: step * math.Sin(angle),
|
|
})
|
|
}
|
|
|
|
return circles
|
|
}
|
|
|
|
func circleSliceUpdate(cs []circle, w, h int) []circle {
|
|
var circles []circle
|
|
|
|
for _, c := range cs {
|
|
c.x += c.dx
|
|
c.y += c.dy
|
|
|
|
if c.x <= 0 {
|
|
c.x = 0
|
|
c.dx *= -1
|
|
}
|
|
|
|
if c.y <= 0 {
|
|
c.y = 0
|
|
c.dy *= -1
|
|
}
|
|
|
|
if c.x > float64(w) {
|
|
c.x = float64(w)
|
|
c.dx *= -1
|
|
}
|
|
|
|
if c.y > float64(h) {
|
|
c.y = float64(h)
|
|
c.dy *= -1
|
|
}
|
|
|
|
circles = append(circles, c)
|
|
}
|
|
|
|
return circles
|
|
}
|
|
|
|
// Generative draws a random circles image.
|
|
func (r *randCircle) Generative(c *generativeart.Canva) {
|
|
ctex := gg.NewContextForRGBA(c.Img())
|
|
|
|
for j := 0; j < c.Opts().NIters(); j++ {
|
|
cn := rand.Intn(r.maxCircle) + int(r.maxCircle/3)
|
|
circles := newCircleSlice(cn, c.Width(), c.Height(), r.minSteps, r.maxSteps, r.minRadius, r.maxRadius)
|
|
|
|
for i := 0; i < r.maxStepsPerCircle; i++ {
|
|
for _, c1 := range circles {
|
|
for _, c2 := range circles {
|
|
|
|
cl := c.Opts().LineColor()
|
|
if r.isRandColor {
|
|
cl = c.Opts().ColorSchema()[rand.Intn(len(c.Opts().ColorSchema()))]
|
|
}
|
|
|
|
if c1 == c2 {
|
|
continue
|
|
}
|
|
|
|
distance := common.Distance(c1.x, c1.y, c2.x, c2.y)
|
|
|
|
if distance <= c1.radius+c2.radius {
|
|
cx := (c1.x + c2.x) / 2
|
|
cy := (c1.y + c2.y) / 2
|
|
|
|
ctex.SetRGBA255(int(cl.R), int(cl.G), int(cl.B), 30)
|
|
ctex.SetLineWidth(c.Opts().LineWidth())
|
|
ctex.DrawEllipse(cx, cy, distance/2, distance/2)
|
|
ctex.Stroke()
|
|
}
|
|
}
|
|
}
|
|
|
|
circles = circleSliceUpdate(circles, c.Width(), c.Height())
|
|
}
|
|
}
|
|
}
|