From c6043fc5d94542c3d01b61d0fdaccbe601ca850b Mon Sep 17 00:00:00 2001 From: FireCoder-N Date: Sat, 5 Oct 2024 20:37:28 +0300 Subject: [PATCH 1/4] Add files via upload An algorithm to find intersection between 2 lines. --- maths/line_intersection.py | 116 +++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 maths/line_intersection.py diff --git a/maths/line_intersection.py b/maths/line_intersection.py new file mode 100644 index 000000000000..02666f286e78 --- /dev/null +++ b/maths/line_intersection.py @@ -0,0 +1,116 @@ +# Function to calculate determinant of a 2x2 matrix +def determinant(a: float, b: float, c: float, d: float) -> float: + """ + Calculates the determinant of a 2x2 matrix: + + | a b | + | c d | + + Args: + a, b, c, d (float): Elements of the 2x2 matrix. + + Returns: + float: The determinant of the matrix. + """ + return a * d - c * b + + +# Function to compute the line equation coefficients from two points +def line_coefficients(p1: list[float] | tuple, p2: list[float] | tuple) -> tuple: + """ + Computes the coefficients A, B, C of the line equation Ax + By + C = 0 + from two points. + + Args: + p1 (List[float] | tuple): First point (x, y). + p2 (List[float] | tuple): Second point (x, y). + + Returns: + tuple: Coefficients (A, B, C) of the line equation. + """ + if p1[0] == p2[0]: # Vertical line + return 1, 0, p1[0] + else: # Non-vertical line + a = (p2[1] - p1[1]) / (p2[0] - p1[0]) + b = -1 + c = p2[1] - a * p2[0] + return a, b, c + + +def segment_intersection( + v1: list[float] | tuple, + v2: list[float] | tuple, + v1_prime: list[float] | tuple, + v2_prime: list[float] | tuple, + as_segments: bool = True, +) -> list[float] | None: + """ + Finds the intersection point of two line segments or lines, if it exists. + + Args: + v1 (List[float] | tuple): First point of the first segment (x, y). + v2 (List[float] | tuple): Second point of the first segment (x, y). + v1_prime (List[float] | tuple): First point of the second segment (x, y). + v2_prime (List[float] | tuple): Second point of the second segment (x, y). + as_segments (bool): treat the inputs as line segments (True) or as infinite lines (False). + + Returns: + List[float] | None: + Returns the intersection point [x, y] if the segments/lines intersect, otherwise None. + + References: + Cramer's rule: https://en.wikipedia.org/wiki/Cramer%27s_rule + + Examples: + >>> segment_intersection([0, 0], [1, 1], [1, 0], [0, 1]) + [0.5, 0.5] + + # No intersection + >>> segment_intersection([0, 0], [1, 1], [2, 2], [3, 3]) is None + True + + # Parallel lines + >>> segment_intersection([0, 0], [0, 1], [1, 0], [1, 1]) is None + True + + # Parallel infinite lines (ignoring segment boundaries) + >>> segment_intersection([0, 0], [1, 1], [2, 2], [3, 3], as_segments=False) is None + True + + # Intersecting infinite lines + >>> segment_intersection([0, 0], [1, 1], [1, 0], [0, 1], as_segments=False) + [0.5, 0.5] + """ + + # Compute line coefficients for the two segments/lines + a, b, c = line_coefficients(v1, v2) + a_prime, b_prime, c_prime = line_coefficients(v1_prime, v2_prime) + + # Calculate the determinant (D) of the coefficient matrix + d = determinant(a, b, a_prime, b_prime) + + if d == 0: + # If D == 0, the lines are parallel or coincident (no unique solution) + return None + + # Cramer's rule to solve for x and y + dx = determinant(-c, b, -c_prime, b_prime) + dy = determinant(a, -c, a_prime, -c_prime) + + # Intersection point of the lines + x, y = dx / d, dy / d + + if as_segments: + # Check if the intersection point lies within the bounds of both line segments + if ( + min(v1[0], v2[0]) <= x <= max(v1[0], v2[0]) + and min(v1_prime[0], v2_prime[0]) <= x <= max(v1_prime[0], v2_prime[0]) + and min(v1[1], v2[1]) <= y <= max(v1[1], v2[1]) + and min(v1_prime[1], v2_prime[1]) <= y <= max(v1_prime[1], v2_prime[1]) + ): + return [x, y] + + return None + else: + # Return the intersection point of the infinite lines + return [x, y] From f7febf5c2b23dbb62ae67ed4362f66044b98b738 Mon Sep 17 00:00:00 2001 From: FireCoder-N Date: Sat, 5 Oct 2024 20:55:25 +0300 Subject: [PATCH 2/4] Added doctest to function --- maths/line_intersection.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/maths/line_intersection.py b/maths/line_intersection.py index 02666f286e78..5603145aa76e 100644 --- a/maths/line_intersection.py +++ b/maths/line_intersection.py @@ -18,7 +18,7 @@ def determinant(a: float, b: float, c: float, d: float) -> float: # Function to compute the line equation coefficients from two points def line_coefficients(p1: list[float] | tuple, p2: list[float] | tuple) -> tuple: """ - Computes the coefficients A, B, C of the line equation Ax + By + C = 0 + Computes the coefficients A, B, C of the line equation Ax + By + C = 0 from two points. Args: @@ -27,7 +27,25 @@ def line_coefficients(p1: list[float] | tuple, p2: list[float] | tuple) -> tuple Returns: tuple: Coefficients (A, B, C) of the line equation. + + Examples: + # Vertical line (x = constant) + >>> line_coefficients([1, 0], [1, 2]) + (1, 0, 1) + + # Horizontal line (y = constant) + >>> line_coefficients([0, 1], [2, 1]) + (0.0, -1, 1) + + # Diagonal line (positive slope) + >>> line_coefficients([0, 0], [1, 1]) + (1.0, -1, 0) + + # Diagonal line (negative slope) + >>> line_coefficients([0, 1], [1, 0]) + (-1.0, -1, 1) """ + if p1[0] == p2[0]: # Vertical line return 1, 0, p1[0] else: # Non-vertical line From f6348d760971b4993bfc7bf5946ca34044e29a84 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 5 Oct 2024 17:55:47 +0000 Subject: [PATCH 3/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- maths/line_intersection.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/maths/line_intersection.py b/maths/line_intersection.py index 5603145aa76e..e8ba3a956f28 100644 --- a/maths/line_intersection.py +++ b/maths/line_intersection.py @@ -18,7 +18,7 @@ def determinant(a: float, b: float, c: float, d: float) -> float: # Function to compute the line equation coefficients from two points def line_coefficients(p1: list[float] | tuple, p2: list[float] | tuple) -> tuple: """ - Computes the coefficients A, B, C of the line equation Ax + By + C = 0 + Computes the coefficients A, B, C of the line equation Ax + By + C = 0 from two points. Args: @@ -27,7 +27,7 @@ def line_coefficients(p1: list[float] | tuple, p2: list[float] | tuple) -> tuple Returns: tuple: Coefficients (A, B, C) of the line equation. - + Examples: # Vertical line (x = constant) >>> line_coefficients([1, 0], [1, 2]) @@ -45,7 +45,7 @@ def line_coefficients(p1: list[float] | tuple, p2: list[float] | tuple) -> tuple >>> line_coefficients([0, 1], [1, 0]) (-1.0, -1, 1) """ - + if p1[0] == p2[0]: # Vertical line return 1, 0, p1[0] else: # Non-vertical line From 924b44599ebab710b6dfaf3c3f78fb2a06afd0eb Mon Sep 17 00:00:00 2001 From: DIMITRIOS-NESTORAS MANOLIS Date: Sat, 5 Oct 2024 21:13:31 +0300 Subject: [PATCH 4/4] fixed ruff issues --- maths/line_intersection.py | 50 +++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/maths/line_intersection.py b/maths/line_intersection.py index e8ba3a956f28..898541bad66a 100644 --- a/maths/line_intersection.py +++ b/maths/line_intersection.py @@ -1,18 +1,38 @@ # Function to calculate determinant of a 2x2 matrix -def determinant(a: float, b: float, c: float, d: float) -> float: +def determinant(m00: float, m01: float, m10: float, m11: float) -> float: """ Calculates the determinant of a 2x2 matrix: - | a b | - | c d | + | m00 m01 | + | m10 m11 | Args: - a, b, c, d (float): Elements of the 2x2 matrix. + m00 (float): Element in the first row, first column. + m01 (float): Element in the first row, second column. + m10 (float): Element in the second row, first column. + m11 (float): Element in the second row, second column. Returns: float: The determinant of the matrix. + + Examples: + # Determinant of the identity matrix (should be 1) + >>> determinant(1, 0, 0, 1) + 1 + + # Determinant of a matrix with two equal rows (should be 0) + >>> determinant(1, 2, 1, 2) + 0 + + # Determinant of a matrix with a negative determinant + >>> determinant(1, 2, 3, 4) + -2 + + # Determinant of a matrix with larger numbers + >>> determinant(10, 20, 30, 40) + -200 """ - return a * d - c * b + return m00 * m11 - m10 * m01 # Function to compute the line equation coefficients from two points @@ -35,15 +55,15 @@ def line_coefficients(p1: list[float] | tuple, p2: list[float] | tuple) -> tuple # Horizontal line (y = constant) >>> line_coefficients([0, 1], [2, 1]) - (0.0, -1, 1) + (0.0, -1, 1.0) # Diagonal line (positive slope) >>> line_coefficients([0, 0], [1, 1]) - (1.0, -1, 0) + (1.0, -1, 0.0) # Diagonal line (negative slope) >>> line_coefficients([0, 1], [1, 0]) - (-1.0, -1, 1) + (-1.0, -1, 1.0) """ if p1[0] == p2[0]: # Vertical line @@ -70,11 +90,13 @@ def segment_intersection( v2 (List[float] | tuple): Second point of the first segment (x, y). v1_prime (List[float] | tuple): First point of the second segment (x, y). v2_prime (List[float] | tuple): Second point of the second segment (x, y). - as_segments (bool): treat the inputs as line segments (True) or as infinite lines (False). + as_segments (bool): + treat the inputs as line segments (True) + or as infinite lines (False). Returns: List[float] | None: - Returns the intersection point [x, y] if the segments/lines intersect, otherwise None. + Returns the intersection point [x, y] if existent, otherwise None. References: Cramer's rule: https://en.wikipedia.org/wiki/Cramer%27s_rule @@ -91,13 +113,13 @@ def segment_intersection( >>> segment_intersection([0, 0], [0, 1], [1, 0], [1, 1]) is None True - # Parallel infinite lines (ignoring segment boundaries) - >>> segment_intersection([0, 0], [1, 1], [2, 2], [3, 3], as_segments=False) is None - True - # Intersecting infinite lines >>> segment_intersection([0, 0], [1, 1], [1, 0], [0, 1], as_segments=False) [0.5, 0.5] + + # Parallel infinite lines (ignoring segment boundaries) + >>> segment_intersection([0, 0], [1, 1], [2, 2], [3, 3], False) is None + True """ # Compute line coefficients for the two segments/lines