generativeart/arts/randcircle.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())
}
}
}