@@ -7,7 +7,7 @@ Returns `(intersection_found::Bool, intersection_point::Point)`
77"""
88# 2D Line-segment intersection algorithm by Paul Bourke and many others.
99# http://paulbourke.net/geometry/pointlineplane/
10- function intersects (a:: Line{2,T1} , b:: Line{2,T2} ) where {T1,T2}
10+ function intersects (a:: Line{2,T1} , b:: Line{2,T2} ; eps = 0 ) where {T1,T2}
1111 T = promote_type (T1, T2)
1212 p0 = zero (Point2{T})
1313
@@ -34,7 +34,7 @@ function intersects(a::Line{2,T1}, b::Line{2,T2}) where {T1,T2}
3434
3535 # Values between [0, 1] mean the intersection point of the lines rests on
3636 # both of the line segments.
37- if 0 <= unknown_a <= 1 && 0 <= unknown_b <= 1
37+ if eps <= unknown_a <= 1 - eps && eps <= unknown_b <= 1 - eps
3838 # Substituting an unknown back lets us find the intersection point.
3939 x = x1 + (unknown_a * (x2 - x1))
4040 y = y1 + (unknown_a * (y2 - y1))
6262"""
6363 self_intersections(points::AbstractVector{<:Point})
6464
65- Finds all self intersections of polygon `points`
65+ Finds all self intersections of in a continuous line described by `points`.
66+
67+ Note that if two points are the same, they will generate a self intersection
68+ unless they are the first and last point or part of consecutive segments.
6669"""
67- function self_intersections (points:: AbstractVector{<:Point} )
70+ function self_intersections (points:: AbstractVector{<:VecTypes{D, T}} ) where {D, T}
6871 sections = similar (points, 0 )
69- intersections = Int[]
70-
71- wraparound (i) = mod1 (i, length (points) - 1 )
72-
73- for (i, (a, b)) in enumerate (consecutive_pairs (points))
74- for (j, (a2, b2)) in enumerate (consecutive_pairs (points))
75- is1, is2 = wraparound (i + 1 ), wraparound (i - 1 )
76- if i != j &&
77- is1 != j &&
78- is2 != j &&
79- ! (i in intersections) &&
80- ! (j in intersections)
81- intersected, p = intersects (Line (a, b), Line (a2, b2))
82- if intersected
83- push! (intersections, i, j)
84- push! (sections, p)
85- end
72+ intersections = Tuple{Int, Int}[]
73+
74+ N = length (points)
75+
76+ for i in 1 : N- 3
77+ a = points[i]; b = points[i+ 1 ]
78+ # i+1 == j describes consecutive segments which are always "intersecting"
79+ # at point i+1/j. Skip those (start at i+2)
80+ # Special case: We assume points[1] == points[end] so 1 -> 2 and N-1 -> N
81+ # always "intersect" at 1/N. Skip this too (end at N-2 in this case)
82+ for j in i+ 2 : N- 1 - (i == 1 )
83+ a2 = points[j]; b2 = points[j+ 1 ]
84+ intersected, p = intersects (Line (a, b), Line (a2, b2))
85+ if intersected
86+ push! (intersections, (i, j))
87+ push! (sections, p)
8688 end
8789 end
8890 end
9597Splits polygon `points` into it's self intersecting parts. Only 1 intersection
9698is handled right now.
9799"""
98- function split_intersections (points:: AbstractVector{<:Point} )
100+ function split_intersections (points:: AbstractVector{<:VecTypes{N, T}} ) where {N, T}
99101 intersections, sections = self_intersections (points)
100102 return if isempty (intersections)
101103 return [points]
102- elseif length (intersections) == 2 && length (sections) == 1
103- a, b = intersections
104+ elseif length (intersections) == 1 && length (sections) == 1
105+ a, b = intersections[ 1 ]
104106 p = sections[1 ]
105- a, b = min (a, b), max (a, b)
106- poly1 = simple_concat (points, (a + 1 ): (b - 1 ), p)
107+ poly1 = simple_concat (points, (a + 1 ): b, p)
107108 poly2 = simple_concat (points, (b + 1 ): (length (points) + a), p)
108109 return [poly1, poly2]
109110 else
0 commit comments