Skip to content

Commit c6043fc

Browse files
authored
Add files via upload
An algorithm to find intersection between 2 lines.
1 parent fcf82a1 commit c6043fc

File tree

1 file changed

+116
-0
lines changed

1 file changed

+116
-0
lines changed

maths/line_intersection.py

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# Function to calculate determinant of a 2x2 matrix
2+
def determinant(a: float, b: float, c: float, d: float) -> float:
3+
"""
4+
Calculates the determinant of a 2x2 matrix:
5+
6+
| a b |
7+
| c d |
8+
9+
Args:
10+
a, b, c, d (float): Elements of the 2x2 matrix.
11+
12+
Returns:
13+
float: The determinant of the matrix.
14+
"""
15+
return a * d - c * b
16+
17+
18+
# Function to compute the line equation coefficients from two points
19+
def line_coefficients(p1: list[float] | tuple, p2: list[float] | tuple) -> tuple:
20+
"""
21+
Computes the coefficients A, B, C of the line equation Ax + By + C = 0
22+
from two points.
23+
24+
Args:
25+
p1 (List[float] | tuple): First point (x, y).
26+
p2 (List[float] | tuple): Second point (x, y).
27+
28+
Returns:
29+
tuple: Coefficients (A, B, C) of the line equation.
30+
"""
31+
if p1[0] == p2[0]: # Vertical line
32+
return 1, 0, p1[0]
33+
else: # Non-vertical line
34+
a = (p2[1] - p1[1]) / (p2[0] - p1[0])
35+
b = -1
36+
c = p2[1] - a * p2[0]
37+
return a, b, c
38+
39+
40+
def segment_intersection(
41+
v1: list[float] | tuple,
42+
v2: list[float] | tuple,
43+
v1_prime: list[float] | tuple,
44+
v2_prime: list[float] | tuple,
45+
as_segments: bool = True,
46+
) -> list[float] | None:
47+
"""
48+
Finds the intersection point of two line segments or lines, if it exists.
49+
50+
Args:
51+
v1 (List[float] | tuple): First point of the first segment (x, y).
52+
v2 (List[float] | tuple): Second point of the first segment (x, y).
53+
v1_prime (List[float] | tuple): First point of the second segment (x, y).
54+
v2_prime (List[float] | tuple): Second point of the second segment (x, y).
55+
as_segments (bool): treat the inputs as line segments (True) or as infinite lines (False).
56+
57+
Returns:
58+
List[float] | None:
59+
Returns the intersection point [x, y] if the segments/lines intersect, otherwise None.
60+
61+
References:
62+
Cramer's rule: https://en.wikipedia.org/wiki/Cramer%27s_rule
63+
64+
Examples:
65+
>>> segment_intersection([0, 0], [1, 1], [1, 0], [0, 1])
66+
[0.5, 0.5]
67+
68+
# No intersection
69+
>>> segment_intersection([0, 0], [1, 1], [2, 2], [3, 3]) is None
70+
True
71+
72+
# Parallel lines
73+
>>> segment_intersection([0, 0], [0, 1], [1, 0], [1, 1]) is None
74+
True
75+
76+
# Parallel infinite lines (ignoring segment boundaries)
77+
>>> segment_intersection([0, 0], [1, 1], [2, 2], [3, 3], as_segments=False) is None
78+
True
79+
80+
# Intersecting infinite lines
81+
>>> segment_intersection([0, 0], [1, 1], [1, 0], [0, 1], as_segments=False)
82+
[0.5, 0.5]
83+
"""
84+
85+
# Compute line coefficients for the two segments/lines
86+
a, b, c = line_coefficients(v1, v2)
87+
a_prime, b_prime, c_prime = line_coefficients(v1_prime, v2_prime)
88+
89+
# Calculate the determinant (D) of the coefficient matrix
90+
d = determinant(a, b, a_prime, b_prime)
91+
92+
if d == 0:
93+
# If D == 0, the lines are parallel or coincident (no unique solution)
94+
return None
95+
96+
# Cramer's rule to solve for x and y
97+
dx = determinant(-c, b, -c_prime, b_prime)
98+
dy = determinant(a, -c, a_prime, -c_prime)
99+
100+
# Intersection point of the lines
101+
x, y = dx / d, dy / d
102+
103+
if as_segments:
104+
# Check if the intersection point lies within the bounds of both line segments
105+
if (
106+
min(v1[0], v2[0]) <= x <= max(v1[0], v2[0])
107+
and min(v1_prime[0], v2_prime[0]) <= x <= max(v1_prime[0], v2_prime[0])
108+
and min(v1[1], v2[1]) <= y <= max(v1[1], v2[1])
109+
and min(v1_prime[1], v2_prime[1]) <= y <= max(v1_prime[1], v2_prime[1])
110+
):
111+
return [x, y]
112+
113+
return None
114+
else:
115+
# Return the intersection point of the infinite lines
116+
return [x, y]

0 commit comments

Comments
 (0)