@@ -7,7 +7,7 @@ Returns `(intersection_found::Bool, intersection_point::Point)`
7
7
"""
8
8
# 2D Line-segment intersection algorithm by Paul Bourke and many others.
9
9
# 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}
11
11
T = promote_type (T1, T2)
12
12
p0 = zero (Point2{T})
13
13
@@ -34,7 +34,7 @@ function intersects(a::Line{2,T1}, b::Line{2,T2}) where {T1,T2}
34
34
35
35
# Values between [0, 1] mean the intersection point of the lines rests on
36
36
# 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
38
38
# Substituting an unknown back lets us find the intersection point.
39
39
x = x1 + (unknown_a * (x2 - x1))
40
40
y = y1 + (unknown_a * (y2 - y1))
62
62
"""
63
63
self_intersections(points::AbstractVector{<:Point})
64
64
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.
66
69
"""
67
- function self_intersections (points:: AbstractVector{<:Point} )
70
+ function self_intersections (points:: AbstractVector{<:VecTypes{D, T}} ) where {D, T}
68
71
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)
86
88
end
87
89
end
88
90
end
95
97
Splits polygon `points` into it's self intersecting parts. Only 1 intersection
96
98
is handled right now.
97
99
"""
98
- function split_intersections (points:: AbstractVector{<:Point} )
100
+ function split_intersections (points:: AbstractVector{<:VecTypes{N, T}} ) where {N, T}
99
101
intersections, sections = self_intersections (points)
100
102
return if isempty (intersections)
101
103
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 ]
104
106
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)
107
108
poly2 = simple_concat (points, (b + 1 ): (length (points) + a), p)
108
109
return [poly1, poly2]
109
110
else
0 commit comments