MCPcopy
hub / github.com/tdewolff/canvas / RayIntersections

Method RayIntersections

path_intersection.go:24–83  ·  view source on GitHub ↗

RayIntersections returns the intersections of a path with a ray starting at (x,y) to (∞,y). An intersection is tangent only when it is at (x,y), i.e. the start of the ray. The parameter T along the ray is zero at the start but NaN otherwise. Intersections are sorted along the ray. This function runs

(x, y float64)

Source from the content-addressed store, hash-verified

22// along the ray is zero at the start but NaN otherwise. Intersections are sorted along the ray.
23// This function runs in O(n) with n the number of path segments.
24func (p *Path) RayIntersections(x, y float64) []Intersection {
25 var start, end Point
26 var zs []Intersection
27 for i := 0; i < len(p.d); {
28 cmd := p.d[i]
29 switch cmd {
30 case MoveToCmd:
31 end = Point{p.d[i+1], p.d[i+2]}
32 case LineToCmd, CloseCmd:
33 end = Point{p.d[i+1], p.d[i+2]}
34 ymin := math.Min(start.Y, end.Y)
35 ymax := math.Max(start.Y, end.Y)
36 xmax := math.Max(start.X, end.X)
37 if Interval(y, ymin, ymax) && x <= xmax+Epsilon {
38 zs = intersectionLineLine(zs, Point{x, y}, Point{xmax + 1.0, y}, start, end)
39 }
40 case QuadToCmd:
41 cp := Point{p.d[i+1], p.d[i+2]}
42 end = Point{p.d[i+3], p.d[i+4]}
43 ymin := math.Min(math.Min(start.Y, end.Y), cp.Y)
44 ymax := math.Max(math.Max(start.Y, end.Y), cp.Y)
45 xmax := math.Max(math.Max(start.X, end.X), cp.X)
46 if Interval(y, ymin, ymax) && x <= xmax+Epsilon {
47 zs = intersectionLineQuad(zs, Point{x, y}, Point{xmax + 1.0, y}, start, cp, end)
48 }
49 case CubeToCmd:
50 cp1 := Point{p.d[i+1], p.d[i+2]}
51 cp2 := Point{p.d[i+3], p.d[i+4]}
52 end = Point{p.d[i+5], p.d[i+6]}
53 ymin := math.Min(math.Min(start.Y, end.Y), math.Min(cp1.Y, cp2.Y))
54 ymax := math.Max(math.Max(start.Y, end.Y), math.Max(cp1.Y, cp2.Y))
55 xmax := math.Max(math.Max(start.X, end.X), math.Max(cp1.X, cp2.X))
56 if Interval(y, ymin, ymax) && x <= xmax+Epsilon {
57 zs = intersectionLineCube(zs, Point{x, y}, Point{xmax + 1.0, y}, start, cp1, cp2, end)
58 }
59 case ArcToCmd:
60 rx, ry, phi := p.d[i+1], p.d[i+2], p.d[i+3]
61 large, sweep := toArcFlags(p.d[i+4])
62 end = Point{p.d[i+5], p.d[i+6]}
63 cx, cy, theta0, theta1 := ellipseToCenter(start.X, start.Y, rx, ry, phi, large, sweep, end.X, end.Y)
64 if Interval(y, cy-math.Max(rx, ry), cy+math.Max(rx, ry)) && x <= cx+math.Max(rx, ry)+Epsilon {
65 zs = intersectionLineEllipse(zs, Point{x, y}, Point{cx + rx + 1.0, y}, Point{cx, cy}, Point{rx, ry}, phi, theta0, theta1)
66 }
67 }
68 i += cmdLen(cmd)
69 start = end
70 }
71 for i := range zs {
72 if zs[i].T[0] != 0.0 {
73 zs[i].T[0] = math.NaN()
74 }
75 }
76 sort.SliceStable(zs, func(i, j int) bool {
77 if Equal(zs[i].X, zs[j].X) {
78 return false
79 }
80 return zs[i].X < zs[j].X
81 })

Callers 3

WindingsAtMethod · 0.80
CrossingsAtMethod · 0.80
FillingMethod · 0.80

Calls 9

IntervalFunction · 0.85
intersectionLineLineFunction · 0.85
intersectionLineQuadFunction · 0.85
intersectionLineCubeFunction · 0.85
toArcFlagsFunction · 0.85
ellipseToCenterFunction · 0.85
intersectionLineEllipseFunction · 0.85
cmdLenFunction · 0.85
EqualFunction · 0.85

Tested by

no test coverage detected