Skip to content

Commit

Permalink
Feat: Add check_coplanar kwarg to Line.intersect_line (#320)
Browse files Browse the repository at this point in the history
Co-authored-by: Andrew Hynes <andrewjhynes@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
3 people committed Dec 29, 2022
1 parent b62d39e commit eaa889d
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 14 deletions.
7 changes: 5 additions & 2 deletions src/skspatial/objects/line.py
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,7 @@ def distance_line(self, other: Line) -> np.float64:

return distance

def intersect_line(self, other: Line, **kwargs) -> Point:
def intersect_line(self, other: Line, check_coplanar: bool = True, **kwargs) -> Point:
"""
Intersect the line with another.
Expand All @@ -485,6 +485,9 @@ def intersect_line(self, other: Line, **kwargs) -> Point:
----------
other : Line
Other line.
check_coplanar : bool, optional
Check that the lines are coplanar (default True).
If False, this method may not return an actual intersection point, but an approximate one.
kwargs : dict, optional
Additional keywords passed to :meth:`Vector.is_parallel`.
Expand Down Expand Up @@ -560,7 +563,7 @@ def intersect_line(self, other: Line, **kwargs) -> Point:
if self.direction.is_parallel(other.direction, **kwargs):
raise ValueError("The lines must not be parallel.")

if not self.is_coplanar(other):
if check_coplanar and not self.is_coplanar(other):
raise ValueError("The lines must be coplanar.")

# Vector from line A to line B.
Expand Down
7 changes: 5 additions & 2 deletions src/skspatial/objects/line_segment.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,17 @@ def contains_point(self, point: array_like, **kwargs) -> bool:

return math.isclose(similarity, -1, **kwargs)

def intersect_line_segment(self, other: LineSegment) -> Point:
def intersect_line_segment(self, other: LineSegment, **kwargs) -> Point:
"""
Intersect the line segment with another.
Parameters
----------
other : LineSegment
kwargs : dict, optional
Additional keyword arguments passed to :meth:`Line.intersect_line`.
Returns
-------
Point
Expand Down Expand Up @@ -145,7 +148,7 @@ def intersect_line_segment(self, other: LineSegment) -> Point:
line_a = Line.from_points(self.point_a, self.point_b)
line_b = Line.from_points(other.point_a, other.point_b)

point_intersection = line_a.intersect_line(line_b)
point_intersection = line_a.intersect_line(line_b, **kwargs)

point_on_segment_a = self.contains_point(point_intersection)
point_on_segment_b = other.contains_point(point_intersection)
Expand Down
9 changes: 7 additions & 2 deletions src/skspatial/objects/triangle.py
Original file line number Diff line number Diff line change
Expand Up @@ -498,12 +498,17 @@ def altitude(self, vertex: str) -> Line:

raise ValueError("The vertex must be 'A', 'B', or 'C'.")

def orthocenter(self) -> Point:
def orthocenter(self, **kwargs) -> Point:
"""
Return the orthocenter of the triangle.
The orthocenter is the intersection point of the three altitudes.
Parameters
----------
kwargs : dict, optional
Additional keywords passed to :meth:`Line.intersect_line`.
Returns
-------
Point
Expand All @@ -523,7 +528,7 @@ def orthocenter(self) -> Point:
line_alt_a = self.altitude('A')
line_alt_b = self.altitude('B')

return line_alt_a.intersect_line(line_alt_b)
return line_alt_a.intersect_line(line_alt_b, **kwargs)

def classify(self, **kwargs: float) -> str:
"""
Expand Down
18 changes: 10 additions & 8 deletions tests/unit/objects/test_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,18 +213,20 @@ def test_distance_line(line_a, line_b, dist_expected):


@pytest.mark.parametrize(
("line_a", "line_b", "array_expected"),
("line_a", "line_b", "array_expected", "check_coplanar"),
[
(Line([0, 0], [1, 0]), Line([0, 0], [1, 1]), [0, 0]),
(Line([0, 0], [1, 0]), Line([5, 5], [1, 1]), [0, 0]),
(Line([0, 0], [1, 0]), Line([9, 0], [1, 1]), [9, 0]),
(Line([0, 0], [1, 1]), Line([4, 0], [1, -1]), [2, 2]),
(Line([0, 0, 0], [1, 1, 1]), Line([4, 4, 0], [-1, -1, 1]), [2, 2, 2]),
(Line([0, 0], [1, 0]), Line([0, 0], [1, 1]), [0, 0], True),
(Line([0, 0], [1, 0]), Line([5, 5], [1, 1]), [0, 0], True),
(Line([0, 0], [1, 0]), Line([9, 0], [1, 1]), [9, 0], True),
(Line([0, 0], [1, 1]), Line([4, 0], [1, -1]), [2, 2], True),
(Line([0, 0, 0], [1, 1, 1]), Line([4, 4, 0], [-1, -1, 1]), [2, 2, 2], True),
(Line([0, 0, 0], [1, 1, 0]), Line([4, 5, 0], [-1, 0, 0]), [5, 5, 0], True),
(Line([0, 0, 0], [1, 1, 0]), Line([4, 5, 1], [-1, 0, 0]), [5, 5, 0], False),
],
)
def test_intersect_line(line_a, line_b, array_expected):
def test_intersect_line(line_a, line_b, array_expected, check_coplanar):

point_intersection = line_a.intersect_line(line_b)
point_intersection = line_a.intersect_line(line_b, check_coplanar)
assert point_intersection.is_close(array_expected)


Expand Down

0 comments on commit eaa889d

Please sign in to comment.