forked from fogleman/primitive
-
Notifications
You must be signed in to change notification settings - Fork 0
/
worker.go
108 lines (99 loc) · 2.91 KB
/
worker.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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package primitive
import (
"image"
"math/rand"
"time"
"github.com/golang/freetype/raster"
)
type Worker struct {
W, H int
Target *image.RGBA
Current *image.RGBA
Buffer *image.RGBA
Rasterizer *raster.Rasterizer
Lines []Scanline
Heatmap *Heatmap
Rnd *rand.Rand
Score float64
Counter int
}
func NewWorker(target *image.RGBA) *Worker {
w := target.Bounds().Size().X
h := target.Bounds().Size().Y
worker := Worker{}
worker.W = w
worker.H = h
worker.Target = target
worker.Buffer = image.NewRGBA(target.Bounds())
worker.Rasterizer = raster.NewRasterizer(w, h)
worker.Lines = make([]Scanline, 0, 4096) // TODO: based on height
worker.Heatmap = NewHeatmap(w, h)
worker.Rnd = rand.New(rand.NewSource(time.Now().UnixNano()))
return &worker
}
func (worker *Worker) Init(current *image.RGBA, score float64) {
worker.Current = current
worker.Score = score
worker.Counter = 0
worker.Heatmap.Clear()
}
func (worker *Worker) Energy(shape Shape, alpha int) float64 {
worker.Counter++
lines := shape.Rasterize()
// worker.Heatmap.Add(lines)
color := computeColor(worker.Target, worker.Current, lines, alpha)
copyLines(worker.Buffer, worker.Current, lines)
drawLines(worker.Buffer, color, lines)
return differencePartial(worker.Target, worker.Current, worker.Buffer, worker.Score, lines)
}
func (worker *Worker) BestHillClimbState(t ShapeType, a, n, age, m int) *State {
var bestEnergy float64
var bestState *State
for i := 0; i < m; i++ {
state := worker.BestRandomState(t, a, n)
before := state.Energy()
state = HillClimb(state, age).(*State)
energy := state.Energy()
vv("%dx random: %.6f -> %dx hill climb: %.6f\n", n, before, age, energy)
if i == 0 || energy < bestEnergy {
bestEnergy = energy
bestState = state
}
}
return bestState
}
func (worker *Worker) BestRandomState(t ShapeType, a, n int) *State {
var bestEnergy float64
var bestState *State
for i := 0; i < n; i++ {
state := worker.RandomState(t, a)
energy := state.Energy()
if i == 0 || energy < bestEnergy {
bestEnergy = energy
bestState = state
}
}
return bestState
}
func (worker *Worker) RandomState(t ShapeType, a int) *State {
switch t {
default:
return worker.RandomState(ShapeType(worker.Rnd.Intn(8)+1), a)
case ShapeTypeTriangle:
return NewState(worker, NewRandomTriangle(worker), a)
case ShapeTypeRectangle:
return NewState(worker, NewRandomRectangle(worker), a)
case ShapeTypeEllipse:
return NewState(worker, NewRandomEllipse(worker), a)
case ShapeTypeCircle:
return NewState(worker, NewRandomCircle(worker), a)
case ShapeTypeRotatedRectangle:
return NewState(worker, NewRandomRotatedRectangle(worker), a)
case ShapeTypeQuadratic:
return NewState(worker, NewRandomQuadratic(worker), a)
case ShapeTypeRotatedEllipse:
return NewState(worker, NewRandomRotatedEllipse(worker), a)
case ShapeTypePolygon:
return NewState(worker, NewRandomPolygon(worker, 4, false), a)
}
}