1package drawing
2
3// NewDashVertexConverter creates a new dash converter.
4func NewDashVertexConverter(dash []float64, dashOffset float64, flattener Flattener) *DashVertexConverter {
5	var dasher DashVertexConverter
6	dasher.dash = dash
7	dasher.currentDash = 0
8	dasher.dashOffset = dashOffset
9	dasher.next = flattener
10	return &dasher
11}
12
13// DashVertexConverter is a converter for dash vertexes.
14type DashVertexConverter struct {
15	next           Flattener
16	x, y, distance float64
17	dash           []float64
18	currentDash    int
19	dashOffset     float64
20}
21
22// LineTo implements the pathbuilder interface.
23func (dasher *DashVertexConverter) LineTo(x, y float64) {
24	dasher.lineTo(x, y)
25}
26
27// MoveTo implements the pathbuilder interface.
28func (dasher *DashVertexConverter) MoveTo(x, y float64) {
29	dasher.next.MoveTo(x, y)
30	dasher.x, dasher.y = x, y
31	dasher.distance = dasher.dashOffset
32	dasher.currentDash = 0
33}
34
35// LineJoin implements the pathbuilder interface.
36func (dasher *DashVertexConverter) LineJoin() {
37	dasher.next.LineJoin()
38}
39
40// Close implements the pathbuilder interface.
41func (dasher *DashVertexConverter) Close() {
42	dasher.next.Close()
43}
44
45// End implements the pathbuilder interface.
46func (dasher *DashVertexConverter) End() {
47	dasher.next.End()
48}
49
50func (dasher *DashVertexConverter) lineTo(x, y float64) {
51	rest := dasher.dash[dasher.currentDash] - dasher.distance
52	for rest < 0 {
53		dasher.distance = dasher.distance - dasher.dash[dasher.currentDash]
54		dasher.currentDash = (dasher.currentDash + 1) % len(dasher.dash)
55		rest = dasher.dash[dasher.currentDash] - dasher.distance
56	}
57	d := distance(dasher.x, dasher.y, x, y)
58	for d >= rest {
59		k := rest / d
60		lx := dasher.x + k*(x-dasher.x)
61		ly := dasher.y + k*(y-dasher.y)
62		if dasher.currentDash%2 == 0 {
63			// line
64			dasher.next.LineTo(lx, ly)
65		} else {
66			// gap
67			dasher.next.End()
68			dasher.next.MoveTo(lx, ly)
69		}
70		d = d - rest
71		dasher.x, dasher.y = lx, ly
72		dasher.currentDash = (dasher.currentDash + 1) % len(dasher.dash)
73		rest = dasher.dash[dasher.currentDash]
74	}
75	dasher.distance = d
76	if dasher.currentDash%2 == 0 {
77		// line
78		dasher.next.LineTo(x, y)
79	} else {
80		// gap
81		dasher.next.End()
82		dasher.next.MoveTo(x, y)
83	}
84	if dasher.distance >= dasher.dash[dasher.currentDash] {
85		dasher.distance = dasher.distance - dasher.dash[dasher.currentDash]
86		dasher.currentDash = (dasher.currentDash + 1) % len(dasher.dash)
87	}
88	dasher.x, dasher.y = x, y
89}
90