Repository navigation
Expand file tree
/
Copy pathfiller_dashed.go
More file actions
73 lines (67 loc) · 2.12 KB
/
Copy pathfiller_dashed.go
File metadata and controls
73 lines (67 loc) · 2.12 KB
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
// SPDX-License-Identifier: MIT
// Derived from Rough.js 4.0.4, Copyright (c) 2019 Preet Shihn.
package rough
import "math"
type dashedFiller struct {
helper renderHelper
}
func (f *dashedFiller) fillPolygon(points []Point, o *ResolvedOptions) OpSet {
lines := polygonHachureLines(points, o)
return OpSet{Type: OpSetFillSketch, Ops: f.dashedLine(lines, o)}
}
func (f *dashedFiller) dashedLine(lines []Line, o *ResolvedOptions) []Op {
offset := o.DashOffset
if offset < 0 {
if o.HachureGap < 0 {
offset = o.StrokeWidth * 4
} else {
offset = o.HachureGap
}
}
gap := o.DashGap
if gap < 0 {
if o.HachureGap < 0 {
gap = o.StrokeWidth * 4
} else {
gap = o.HachureGap
}
}
ops := make([]Op, 0)
for _, line := range lines {
length := lineLength(line)
// Hachure endpoints are integer scan-line intersections before they are
// rotated back. Go and V8's trigonometric implementations can leave the
// rotation-preserved length on opposite sides of an exact dash boundary
// by one ULP (for example, 1.9999999999999998 versus 2). Snap only that
// immediately adjacent representation so the structural Math.floor
// decision remains stable while all non-boundary arithmetic is unchanged.
count := math.Floor(snapOneULPToInteger(length / (offset + gap)))
startOffset := (length + gap - count*(offset+gap)) / 2
p1, p2 := line[0], line[1]
if p1[0] > p2[0] {
p1, p2 = line[1], line[0]
}
alpha := math.Atan((p2[1] - p1[1]) / (p2[0] - p1[0]))
for i := 0.0; i < count; i++ {
lstart := i * (offset + gap)
lend := lstart + offset
start := Point{
p1[0] + lstart*math.Cos(alpha) + startOffset*math.Cos(alpha),
p1[1] + lstart*math.Sin(alpha) + startOffset*math.Sin(alpha),
}
end := Point{
p1[0] + lend*math.Cos(alpha) + startOffset*math.Cos(alpha),
p1[1] + lend*math.Sin(alpha) + startOffset*math.Sin(alpha),
}
ops = append(ops, f.helper.doubleLineOps(start[0], start[1], end[0], end[1], o)...)
}
}
return ops
}
func snapOneULPToInteger(v float64) float64 {
nearest := math.Round(v)
if v == nearest || math.Nextafter(v, nearest) == nearest {
return nearest
}
return v
}