Selaa lähdekoodia

added geometry._intersect_line_segments()

Fabian Peter Hammerle 5 vuotta sitten
vanhempi
commit
04f397bd60
3 muutettua tiedostoa jossa 54 lisäystä ja 4 poistoa
  1. 22 1
      freesurfer_surface/geometry.py
  2. 30 1
      tests/geometry/test_intersect.py
  3. 2 2
      tests/geometry/test_line.py

+ 22 - 1
freesurfer_surface/geometry.py

@@ -24,7 +24,7 @@ class _Line:
     def __repr__(self) -> str:
         return 'line(t) = {} + {} t'.format(self.point, self.vector)
 
-    def _intersect_line(self, other: '_Line') \
+    def intersect_line(self, other: '_Line') \
             -> typing.Union[numpy.ndarray, bool]:
         # https://en.wikipedia.org/wiki/Skew_lines#Distance
         lines_normal_vector = numpy.cross(self.vector, other.vector)
@@ -48,3 +48,24 @@ def _intersect_planes(normal_vector_a: numpy.ndarray,
         numpy.vstack((constant_a, constant_b, 0)),
     )
     return _Line(point=point.reshape(3), vector=line_vector)
+
+
+def _between(lower_limit: numpy.ndarray,
+             point: numpy.ndarray,
+             upper_limit: numpy.ndarray) -> bool:
+    return (lower_limit <= point).all() and (point <= upper_limit).all()
+
+
+def _intersect_line_segments(points_a: numpy.ndarray,
+                             points_b: numpy.ndarray) \
+        -> typing.Union[numpy.ndarray, bool]:
+    lines = [_Line(points[0], points[1] - points[0])
+             for points in [points_a, points_b]]
+    point = lines[0].intersect_line(lines[1])
+    if isinstance(point, bool):
+        return point
+    for points in [points_a, points_b]:
+        if not _between(points[0], point, points[1]) \
+            and not _between(points[1], point, points[0]):
+            return False
+    return point

+ 30 - 1
tests/geometry/test_intersect.py

@@ -1,7 +1,8 @@
 import numpy
 import pytest
 
-from freesurfer_surface.geometry import _intersect_planes, _Line
+from freesurfer_surface.geometry \
+    import _Line, _intersect_planes, _intersect_line_segments
 
 
 @pytest.mark.parametrize(
@@ -37,3 +38,31 @@ def test__intersect_planes(normal_vector_a, constant_a,
                              constant_a)
         assert numpy.isclose(numpy.inner(normal_vector_b, other_point),
                              constant_b)
+
+
+@pytest.mark.parametrize(('points_a', 'points_b', 'expected_point'), [
+    (([0, 0, 0], [0, 0, 2]), ([0, -1, 1], [0, 1, 1]), [0, 0, 1]),
+    (([0, 0, 0], [0, 0, 2]), ([0, 0, 1], [0, 1, 1]), [0, 0, 1]),
+    (([0, 0, 0], [0, 0, 2]), ([0, -1, 1], [0, 0, 1]), [0, 0, 1]),
+    (([0, 0, 0], [0, 0, 2]), ([0, 0, 1], [0, -1, 1]), [0, 0, 1]),
+    (([0, 0, 0], [2, 4, 8]), ([0, 0, 4], [2, 4, 4]), [1, 2, 4]),
+    (([0, 0, 0], [2, 4, 8]), ([0, 0, 2], [2, 4, 2]), [0.5, 1, 2]),
+    (([2, 4, 8], [0, 0, 0]), ([0, 0, 2], [2, 4, 2]), [0.5, 1, 2]),
+    (([2, 4, 8], [0, 0, 0]), ([2, 4, 2], [0, 0, 2]), [0.5, 1, 2]),
+    (([3, 5, 9], [1, 1, 1]), ([3, 5, 3], [1, 1, 3]), [1.5, 2, 3]),
+    (([0, 0, 0], [0, 0, 4]), ([0, -8, 0], [0, 8, 0]), [0, 0, 0]),
+    (([0, 0, 0], [0, 0, 4]), ([0, -8, 3], [0, 8, 3]), [0, 0, 3]),
+    (([0, 0, 0], [0, 0, 4]), ([0, -8, 4], [0, 8, 4]), [0, 0, 4]),
+    (([0, 0, 0], [0, 0, 4]), ([0, -8, 4.1], [0, 8, 4.1]), False),
+    (([0, 0, 0], [0, 0, 4]), ([0, -8, -1], [0, 8, -1]), False),
+    (([0, 0, 0], [0, 0, 4]), ([0, 0, 0], [0, 0, 4]), True),
+])
+def test_intersect_line_segments(points_a, points_b, expected_point):
+    # pylint: disable=protected-access
+    point = _intersect_line_segments(numpy.array(points_a),
+                                     numpy.array(points_b))
+    if isinstance(expected_point, bool):
+        assert isinstance(point, bool)
+        assert point == expected_point
+    else:
+        assert numpy.allclose(point, expected_point)

+ 2 - 2
tests/geometry/test_line.py

@@ -105,9 +105,9 @@ def test_repr():
      _Line(point=(5, 10, 10), vector=(8, 16, 14)),
      False),
 ])
-def test__intersect_line(line_a, line_b, expected_point):
+def test_intersect_line(line_a, line_b, expected_point):
     # pylint: disable=protected-access
-    point = line_a._intersect_line(line_b)
+    point = line_a.intersect_line(line_b)
     if isinstance(expected_point, bool):
         assert isinstance(point, bool)
         assert point == expected_point