forked from fogleman/primitive
/
ellipse.go
94 lines (84 loc) · 1.79 KB
/
ellipse.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package primitive
import (
"fmt"
"math"
"math/rand"
"github.com/fogleman/gg"
)
type Ellipse struct {
W, H int
X, Y int
Rx, Ry int
Circle bool
rnd *rand.Rand
}
func NewRandomEllipse(w, h int, rnd *rand.Rand) *Ellipse {
x := rnd.Intn(w)
y := rnd.Intn(h)
rx := rnd.Intn(w / 2)
ry := rnd.Intn(h / 2)
return &Ellipse{w, h, x, y, rx, ry, false, rnd}
}
func NewRandomCircle(w, h int, rnd *rand.Rand) *Ellipse {
x := rnd.Intn(w)
y := rnd.Intn(h)
r := rnd.Intn(w / 4)
return &Ellipse{w, h, x, y, r, r, true, rnd}
}
func (c *Ellipse) Draw(dc *gg.Context) {
dc.DrawEllipse(float64(c.X), float64(c.Y), float64(c.Rx), float64(c.Ry))
}
func (c *Ellipse) SVG(attrs string) string {
return fmt.Sprintf(
"<ellipse %s cx=\"%d\" cy=\"%d\" rx=\"%d\" ry=\"%d\" />",
attrs, c.X, c.Y, c.Rx, c.Ry)
}
func (c *Ellipse) Copy() Shape {
a := *c
return &a
}
func (c *Ellipse) Mutate() {
rnd := c.rnd
switch rnd.Intn(3) {
case 0:
c.X = clampInt(c.X+rnd.Intn(21)-10, 0, c.W-1)
c.Y = clampInt(c.Y+rnd.Intn(21)-10, 0, c.H-1)
case 1:
c.Rx = clampInt(c.Rx+rnd.Intn(21)-10, 0, c.W-1)
if c.Circle {
c.Ry = c.Rx
}
case 2:
c.Ry = clampInt(c.Ry+rnd.Intn(21)-10, 0, c.W-1)
if c.Circle {
c.Rx = c.Ry
}
}
}
func (c *Ellipse) Rasterize() []Scanline {
lines := make([]Scanline, 0, c.Ry*2)
aspect := float64(c.Rx) / float64(c.Ry)
for dy := 0; dy < c.Ry; dy++ {
y1 := c.Y - dy
y2 := c.Y + dy
if (y1 < 0 || y1 >= c.H) && (y2 < 0 || y2 >= c.H) {
continue
}
w := int(math.Sqrt(float64(c.Ry*c.Ry-dy*dy)) * aspect)
x1 := c.X - w
x2 := c.X + w
if x1 < 0 {
x1 = 0
}
if x2 >= c.W {
x2 = c.W - 1
}
if y1 >= 0 && y1 < c.H {
lines = append(lines, Scanline{y1, x1, x2})
}
if y2 >= 0 && y2 < c.H && dy > 0 {
lines = append(lines, Scanline{y2, x1, x2})
}
}
return lines
}