Skip to content

Commit 7396665

Browse files
Fix #168 (#185)
* Add broken tests for #168 * Fix #168 --------- Co-authored-by: Simon <[email protected]>
1 parent 27ad5c8 commit 7396665

File tree

2 files changed

+43
-48
lines changed

2 files changed

+43
-48
lines changed

src/lines.jl

Lines changed: 29 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,66 +2,47 @@
22
"""
33
intersects(a::Line, b::Line) -> Bool, Point
44
5-
Intersection of 2 line segmens `a` and `b`.
6-
Returns intersection_found::Bool, intersection_point::Point
5+
Intersection of 2 line segments `a` and `b`.
6+
Returns `(intersection_found::Bool, intersection_point::Point)`
77
"""
8+
# 2D Line-segment intersection algorithm by Paul Bourke and many others.
9+
# http://paulbourke.net/geometry/pointlineplane/
810
function intersects(a::Line{2,T1}, b::Line{2,T2}) where {T1,T2}
911
T = promote_type(T1, T2)
10-
v1, v2 = a
11-
v3, v4 = b
12-
MT = Mat{2,2,T,4}
1312
p0 = zero(Point2{T})
1413

15-
verticalA = v1[1] == v2[1]
16-
verticalB = v3[1] == v4[1]
17-
18-
# if a segment is vertical the linear algebra might have trouble
19-
# so we will rotate the segments such that neither is vertical
20-
dorotation = verticalA || verticalB
21-
22-
if dorotation
23-
θ = T(0.0)
24-
if verticalA && verticalB
25-
θ = T/ 4)
26-
elseif verticalA || verticalB # obviously true, but make it clear
27-
θ34 = -atan(v4[2] - v3[2], v4[1] - v3[1])
28-
θ12 = -atan(v2[2] - v1[2], v2[1] - v1[1])
29-
θ = verticalA ? θ34 : θ12
30-
θ = abs(θ) == T(0) ? (θ12 + θ34) / 2 : θ
31-
θ = abs(θ) == T(pi) ? (θ12 + θ34) / 2 : θ
32-
end
33-
rotation = MT(cos(θ), sin(θ), -sin(θ), cos(θ))
34-
v1 = rotation * v1
35-
v2 = rotation * v2
36-
v3 = rotation * v3
37-
v4 = rotation * v4
38-
end
14+
x1, y1 = a[1]
15+
x2, y2 = a[2]
16+
x3, y3 = b[1]
17+
x4, y4 = b[2]
3918

40-
a = det(MT(v1[1] - v2[1], v1[2] - v2[2], v3[1] - v4[1], v3[2] - v4[2]))
19+
denominator = ((y4 - y3) * (x2 - x1)) - ((x4 - x3) * (y2 - y1))
20+
numerator_a = ((x4 - x3) * (y1 - y3)) - ((y4 - y3) * (x1 - x3))
21+
numerator_b = ((x2 - x1) * (y1 - y3)) - ((y2 - y1) * (x1 - x3))
4122

42-
(abs(a) < eps(T)) && return false, p0 # Lines are parallel
23+
if denominator == 0
24+
# no intersection: lines are parallel
25+
return false, p0
26+
end
4327

44-
d1 = det(MT(v1[1], v1[2], v2[1], v2[2]))
45-
d2 = det(MT(v3[1], v3[2], v4[1], v4[2]))
46-
x = det(MT(d1, v1[1] - v2[1], d2, v3[1] - v4[1])) / a
47-
y = det(MT(d1, v1[2] - v2[2], d2, v3[2] - v4[2])) / a
28+
# If we ever need to know if the lines are coincident, we can get that too:
29+
# denominator == numerator_a == numerator_b == 0 && return :coincident_lines
4830

49-
(x < prevfloat(min(v1[1], v2[1])) || x > nextfloat(max(v1[1], v2[1]))) &&
50-
return false, p0
51-
(y < prevfloat(min(v1[2], v2[2])) || y > nextfloat(max(v1[2], v2[2]))) &&
52-
return false, p0
53-
(x < prevfloat(min(v3[1], v4[1])) || x > nextfloat(max(v3[1], v4[1]))) &&
54-
return false, p0
55-
(y < prevfloat(min(v3[2], v4[2])) || y > nextfloat(max(v3[2], v4[2]))) &&
56-
return false, p0
31+
# unknown_a and b tell us how far along the line segment the intersection is.
32+
unknown_a = numerator_a / denominator
33+
unknown_b = numerator_b / denominator
5734

58-
point = Point2{T}(x, y)
59-
# don't forget to rotate the answer back
60-
if dorotation
61-
point = transpose(rotation) * point
35+
# Values between [0, 1] mean the intersection point of the lines rests on
36+
# both of the line segments.
37+
if 0 <= unknown_a <= 1 && 0 <= unknown_b <= 1
38+
# Substituting an unknown back lets us find the intersection point.
39+
x = x1 + (unknown_a * (x2 - x1))
40+
y = y1 + (unknown_a * (y2 - y1))
41+
return true, Point2{T}(x, y)
6242
end
6343

64-
return true, point
44+
# lines intersect, but outside of at least one of these line segments.
45+
return false, p0
6546
end
6647

6748
function simple_concat(vec::AbstractVector, range, endpoint::P) where {P}

test/runtests.jl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,20 @@ end
629629
found, point = intersects(d, e)
630630
@test found && point Point(0.0, 4.0)
631631
@test intersects(a, f) === (false, Point(0.0, 0.0))
632+
633+
# issue #168
634+
# If these tests fail then you can increase the tolerance on the checks so
635+
# long as you know what you're doing :)
636+
line_helper(a, b, c, d) = Line(Point(a, b), Point(c, d))
637+
b, loc = intersects(line_helper(-3.1, 15.588457268119894, 3.1, 15.588457268119894),
638+
line_helper(2.0866025403784354, 17.37050807568877, -4.0866025403784505, 13.806406460551015))
639+
@test b
640+
@test loc Point(-1.0000000000000058, 15.588457268119894)
641+
642+
b, loc = intersects(line_helper(5743.933982822018, 150.0, 5885.355339059327, -50.0),
643+
line_helper(5760.0, 100.0, 5760.0, 140.0))
644+
@test b
645+
@test loc Point(5760.0, 127.27922061357884)
632646
end
633647

634648
@testset "Offsetintegers" begin

0 commit comments

Comments
 (0)