From 0dc310e99a989e22062636e737d10ce16b0c219c Mon Sep 17 00:00:00 2001 From: Danny Hermes Date: Mon, 22 Jan 2018 11:15:28 -0800 Subject: [PATCH] Adding test case that requires more than default number of MAX_CANDIDATES. Also updating all "hardcoded" references to 64 (in `.f90` files) to now refer to `MAX_CANDIDATES`. --- src/bezier/curve_intersection.f90 | 16 +++--- src/bezier/surface_intersection.f90 | 6 +-- tests/unit/test__geometric_intersection.py | 63 +++++++++++++++++++++- 3 files changed, 73 insertions(+), 12 deletions(-) diff --git a/src/bezier/curve_intersection.f90 b/src/bezier/curve_intersection.f90 index 56e6fea9..f021b6da 100644 --- a/src/bezier/curve_intersection.f90 +++ b/src/bezier/curve_intersection.f90 @@ -823,13 +823,13 @@ subroutine all_intersections( & ! a C compatible interface is exposed as ``all_intersections_abi``. ! Possible error states: - ! * Status_SUCCESS : On success. - ! * Status_PARALLEL : Via ``intersect_one_round()``. - ! * Status_WIGGLE_FAIL: Via ``intersect_one_round()``. - ! * Status_NO_CONVERGE: If the curves don't converge to linear after - ! ``MAX_INTERSECT_SUBDIVISIONS``. - ! * (N >= 64) : The number of candidates if it exceeds the limit - ! ``MAX_CANDIDATES == 64``. + ! * Status_SUCCESS : On success. + ! * Status_PARALLEL : Via ``intersect_one_round()``. + ! * Status_WIGGLE_FAIL : Via ``intersect_one_round()``. + ! * Status_NO_CONVERGE : If the curves don't converge to linear after + ! ``MAX_INTERSECT_SUBDIVISIONS``. + ! * (N >= MAX_CANDIDATES): The number of candidates if it exceeds the limit + ! ``MAX_CANDIDATES`` (64 is the default). integer(c_int), intent(in) :: num_nodes_first real(c_double), intent(in) :: nodes_first(num_nodes_first, 2) @@ -926,7 +926,7 @@ subroutine all_intersections_abi( & ! * Status_NO_CONVERGE : Via ``all_intersections()``. ! * Status_INSUFFICIENT_SPACE: If ``intersections_size`` is smaller than ! the number of intersections. - ! * (N >= 64) : Via ``all_intersections()``. + ! * (N >= MAX_CANDIDATES) : Via ``all_intersections()``. integer(c_int), intent(in) :: num_nodes_first real(c_double), intent(in) :: nodes_first(num_nodes_first, 2) diff --git a/src/bezier/surface_intersection.f90 b/src/bezier/surface_intersection.f90 index ebdb6bb2..27fa582f 100644 --- a/src/bezier/surface_intersection.f90 +++ b/src/bezier/surface_intersection.f90 @@ -795,7 +795,7 @@ subroutine surfaces_intersection_points( & ! * Status_PARALLEL : Via ``curve_intersection.all_intersections()``. ! * Status_WIGGLE_FAIL : Via ``curve_intersection.all_intersections()``. ! * Status_NO_CONVERGE : Via ``curve_intersection.all_intersections()``. - ! * (N >= 64) : Via ``curve_intersection.all_intersections()``. + ! * (N >= MAX_CANDIDATES): Via ``curve_intersection.all_intersections()``. ! * Status_EDGE_END : Via ``add_st_vals()``. ! * Status_BAD_TANGENT : Via ``add_st_vals()``. ! * Status_SAME_CURVATURE: Via ``add_st_vals()``. @@ -1345,7 +1345,7 @@ subroutine surfaces_intersect( & ! * Status_PARALLEL : Via ``surfaces_intersection_points()``. ! * Status_WIGGLE_FAIL : Via ``surfaces_intersection_points()``. ! * Status_NO_CONVERGE : Via ``surfaces_intersection_points()``. - ! * (N >= 64) : Via ``surfaces_intersection_points()``. + ! * (N >= MAX_CANDIDATES): Via ``surfaces_intersection_points()``. ! * Status_EDGE_END : Via ``surfaces_intersection_points()``. ! * Status_BAD_TANGENT : Via ``surfaces_intersection_points()``. ! * Status_SAME_CURVATURE: Via ``surfaces_intersection_points()``. @@ -1448,7 +1448,7 @@ subroutine surfaces_intersect_abi( & ! * Status_PARALLEL : Via ``surfaces_intersect()``. ! * Status_WIGGLE_FAIL : Via ``surfaces_intersect()``. ! * Status_NO_CONVERGE : Via ``surfaces_intersect()``. - ! * (N >= 64) : Via ``surfaces_intersect()``. + ! * (N >= MAX_CANDIDATES) : Via ``surfaces_intersect()``. ! * Status_EDGE_END : Via ``surfaces_intersect()``. ! * Status_BAD_TANGENT : Via ``surfaces_intersect()``. ! * Status_SAME_CURVATURE : Via ``surfaces_intersect()``. diff --git a/tests/unit/test__geometric_intersection.py b/tests/unit/test__geometric_intersection.py index c26556d4..c525650d 100644 --- a/tests/unit/test__geometric_intersection.py +++ b/tests/unit/test__geometric_intersection.py @@ -1222,7 +1222,7 @@ def test_workspace_too_small(self): self.assertEqual(self.workspace_size(), 2) -class Test__set_max_candidates(unittest.TestCase): +class Test__set_max_candidates(utils.NumPyTestCase): # NOTE: This is also a test for ``_get_max_candidates``. @staticmethod @@ -1248,6 +1248,61 @@ def test_it(self): # Put things back the way they were. self._call_function_under_test(curr_candidates) + @staticmethod + def intersect(nodes1, nodes2): + from bezier import _geometric_intersection + + return _geometric_intersection._all_intersections(nodes1, nodes2) + + def test_on_intersection(self): + from bezier import _geometric_intersection + + template = _geometric_intersection._TOO_MANY_TEMPLATE + # B1(s) = [s(2s - 1), s(3 - 2s)] + # f1(x, y) = 4(x^2 + 2xy - 3x + y^2 - y) + nodes1 = np.asfortranarray([ + [0.0, 0.0], + [-0.5, 1.5], + [1.0, 1.0], + ]) + # B2(s) = [(1 - 2s)(s - 1), 2s^2 - s + 1] + # f2(x, y) = 4(x^2 + 2xy - x + y^2 - 3y + 2) + nodes2 = np.asfortranarray([ + [-1.0, 1.0], + [0.5, 0.5], + [0.0, 2.0], + ]) + + curr_candidates = self.get_max_candidates() + self.assertEqual(curr_candidates, 64) + + # First, show failure with the default. + with self.assertRaises(NotImplementedError) as exc_info: + self.intersect(nodes1, nodes2) + self.assertEqual(exc_info.exception.args, (template.format(88),)) + + # Then, show failure with twice the limit. + self._call_function_under_test(128) + with self.assertRaises(NotImplementedError) as exc_info: + self.intersect(nodes1, nodes2) + self.assertEqual(exc_info.exception.args, (template.format(184),)) + + # Then, show failure with (almost) four times the limit. + self._call_function_under_test(255) + with self.assertRaises(NotImplementedError) as exc_info: + self.intersect(nodes1, nodes2) + self.assertEqual(exc_info.exception.args, (template.format(256),)) + + # Then, show success. + self._call_function_under_test(256) + result = self.intersect(nodes1, nodes2) + # f2(*B1(s)) = 8(2s - 1)^2 + # f1(*B2(t)) = 8(2t - 1)^2 + self.assertEqual(result, np.asfortranarray([[0.5, 0.5]])) + + # Put things back the way they were. + self._call_function_under_test(curr_candidates) + @utils.needs_curve_intersection_speedup class Test_speedup_set_max_candidates(Test__set_max_candidates): @@ -1265,6 +1320,12 @@ def get_max_candidates(): return _curve_intersection_speedup.get_max_candidates() + @staticmethod + def intersect(nodes1, nodes2): + from bezier import _curve_intersection_speedup + + return _curve_intersection_speedup.all_intersections(nodes1, nodes2) + class Test__set_similar_ulps(unittest.TestCase): # NOTE: This is also a test for ``_get_similar_ulps``.