From 3f2ec3363f75d9f78aac640d141a28d00613e714 Mon Sep 17 00:00:00 2001 From: Taras Kuzyo Date: Mon, 2 Jul 2018 14:09:03 +0300 Subject: [PATCH 01/13] added function to check if a point lies on a segment --- src/_path.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/_path.h b/src/_path.h index 81ba393043d8..e9d4028fafe1 100644 --- a/src/_path.h +++ b/src/_path.h @@ -812,6 +812,24 @@ int count_bboxes_overlapping_bbox(agg::rect_d &a, BBoxArray &bboxes) return count; } +// returns true if a point (x0, y0) +// is on a segment [(x1, y1), (x2, y2)] +inline bool segment_contains(const double &x1, + const double &y1, + const double &x2, + const double &y2, + const double &x0, + const double &y0) +{ + // first check if (x0, y0) lies on the segment's line + double intersect = (y0 - y1)*(x2 - x1) - (x0 - x1)*(y2 - y1); + if (intersect != 0.0) { + return false; + } + return fmin(x1, x2) <= x0 && x0 <= fmax(x1, x2) && + fmin(y1, y2) <= y0 && y0 <= fmax(y1, y2); +} + inline bool segments_intersect(const double &x1, const double &y1, const double &x2, From f1efaaa34c9212428cdea2b14697a3d38948814d Mon Sep 17 00:00:00 2001 From: Taras Kuzyo Date: Mon, 2 Jul 2018 14:10:17 +0300 Subject: [PATCH 02/13] check if collinear segments have common points in segments_intersect --- src/_path.h | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/_path.h b/src/_path.h index e9d4028fafe1..d9018c2a1f33 100644 --- a/src/_path.h +++ b/src/_path.h @@ -839,8 +839,23 @@ inline bool segments_intersect(const double &x1, const double &x4, const double &y4) { + // determinant double den = ((y4 - y3) * (x2 - x1)) - ((x4 - x3) * (y2 - y1)); - if (den == 0.0) { + if (den == 0.0) { // collinear segments + // check if any of segments' edges are contained + // in the other segment + if (segment_contains(x3, y3, x4, y4, x1, y1)) { + return true; + } + if (segment_contains(x3, y3, x4, y4, x2, y2)) { + return true; + } + if (segment_contains(x1, y1, x2, y2, x3, y3)) { + return true; + } + if (segment_contains(x1, y1, x2, y2, x4, y4)) { + return true; + } return false; } From e0bcb6413c5fe43279674367abb8e04073741162 Mon Sep 17 00:00:00 2001 From: Taras Kuzyo Date: Mon, 2 Jul 2018 20:01:17 +0300 Subject: [PATCH 03/13] test cases added for Path.intersects_path --- lib/matplotlib/tests/test_path.py | 36 +++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/lib/matplotlib/tests/test_path.py b/lib/matplotlib/tests/test_path.py index fe9067b635c7..7c07f681534d 100644 --- a/lib/matplotlib/tests/test_path.py +++ b/lib/matplotlib/tests/test_path.py @@ -211,6 +211,42 @@ def test_path_deepcopy(): path2 = Path(verts, codes) copy.deepcopy(path1) copy.deepcopy(path2) + + +def test_path_intersect_path(): + + # a and b are orthogonal and intersect at (0, 3) + a = Path([(0,1),(0,3)]) + b = Path([(1,3),(0,3)]) + assert a.intersects_path(b) and b.intersects_path(a) + + # a and b are collinear and intersect at (0, 3) + a = Path([(0,1),(0,3)]) + b = Path([(0,5),(0,3)]) + assert a.intersects_path(b) and b.intersects_path(a) + + # self-intersect + assert a.intersects_path(a) + + # a contains b + a = Path([(0,0),(5,5)]) + b = Path([(1,1),(3,3)]) + assert a.intersects_path(b) and b.intersects_path(a) + + # a and b are collinear but do not intersect + a = Path([(0,1),(0,5)]) + b = Path([(3,0),(3,3)]) + assert not a.intersects_path(b) and not b.intersects_path(a) + + # a and b are on the same line but do not intersect + a = Path([(0,1),(0,5)]) + b = Path([(0,6),(0,7)]) + assert not a.intersects_path(b) and not b.intersects_path(a) + + # b is the same as a but with extra point + a = Path([(0,1),(0,5)]) + b = Path([(0,1),(0,2),(0,5)]) + assert a.intersects_path(b) and b.intersects_path(a) @pytest.mark.parametrize('offset', range(-720, 361, 45)) From 48aea1ad50e8ae6399919a8f92e2852df689cf12 Mon Sep 17 00:00:00 2001 From: Taras Kuzyo Date: Mon, 2 Jul 2018 21:46:27 +0300 Subject: [PATCH 04/13] PEP8 check --- lib/matplotlib/tests/test_path.py | 42 +++++++++++++++---------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/lib/matplotlib/tests/test_path.py b/lib/matplotlib/tests/test_path.py index 7c07f681534d..412fe34dfb08 100644 --- a/lib/matplotlib/tests/test_path.py +++ b/lib/matplotlib/tests/test_path.py @@ -211,41 +211,41 @@ def test_path_deepcopy(): path2 = Path(verts, codes) copy.deepcopy(path1) copy.deepcopy(path2) - - + + def test_path_intersect_path(): - + # a and b are orthogonal and intersect at (0, 3) - a = Path([(0,1),(0,3)]) - b = Path([(1,3),(0,3)]) + a = Path([(0, 1), (0, 3)]) + b = Path([(1, 3), (0, 3)]) assert a.intersects_path(b) and b.intersects_path(a) - + # a and b are collinear and intersect at (0, 3) - a = Path([(0,1),(0,3)]) - b = Path([(0,5),(0,3)]) + a = Path([(0, 1), (0, 3)]) + b = Path([(0, 5), (0, 3)]) assert a.intersects_path(b) and b.intersects_path(a) - + # self-intersect assert a.intersects_path(a) - + # a contains b - a = Path([(0,0),(5,5)]) - b = Path([(1,1),(3,3)]) + a = Path([(0, 0), (5, 5)]) + b = Path([(1, 1), (3, 3)]) assert a.intersects_path(b) and b.intersects_path(a) - + # a and b are collinear but do not intersect - a = Path([(0,1),(0,5)]) - b = Path([(3,0),(3,3)]) + a = Path([(0, 1), (0, 5)]) + b = Path([(3, 0), (3, 3)]) assert not a.intersects_path(b) and not b.intersects_path(a) - + # a and b are on the same line but do not intersect - a = Path([(0,1),(0,5)]) - b = Path([(0,6),(0,7)]) + a = Path([(0, 1), (0, 5)]) + b = Path([(0, 6), (0, 7)]) assert not a.intersects_path(b) and not b.intersects_path(a) - + # b is the same as a but with extra point - a = Path([(0,1),(0,5)]) - b = Path([(0,1),(0,2),(0,5)]) + a = Path([(0, 1), (0, 5)]) + b = Path([(0, 1), (0, 2), (0, 5)]) assert a.intersects_path(b) and b.intersects_path(a) From 3bfebfbbebd0e7ba9e668ce91360d79e66e5141a Mon Sep 17 00:00:00 2001 From: Taras Kuzyo Date: Wed, 4 Jul 2018 09:34:35 +0300 Subject: [PATCH 05/13] added a test case for a range of slopes of intersecting paths --- lib/matplotlib/tests/test_path.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/matplotlib/tests/test_path.py b/lib/matplotlib/tests/test_path.py index 412fe34dfb08..f5172a172728 100644 --- a/lib/matplotlib/tests/test_path.py +++ b/lib/matplotlib/tests/test_path.py @@ -247,6 +247,19 @@ def test_path_intersect_path(): a = Path([(0, 1), (0, 5)]) b = Path([(0, 1), (0, 2), (0, 5)]) assert a.intersects_path(b) and b.intersects_path(a) + + # check a range of slopes + base = 10 + a = Path([(-base, 0), (-base/2, base/2), (base/2, base/2), (base, 0)]) + c = Path([(-base, -base/2), (base, -base/2)]) + for phi in np.linspace(0, np.pi, 180): + x = base * np.cos(phi) + y = base * np.sin(phi) + b = Path([(0, 0), (x, y)]) + # a and b should always intersect + assert a.intersects_path(b) and b.intersects_path(a) + # a and c should never intersect + assert not a.intersects_path(c) and not c.intersects_path(a) @pytest.mark.parametrize('offset', range(-720, 361, 45)) From 45a25e9d0a75398edb798e7afb889c1a21aaa912 Mon Sep 17 00:00:00 2001 From: Taras Kuzyo Date: Wed, 4 Jul 2018 13:00:31 +0300 Subject: [PATCH 06/13] changed the way segments are compared provided their slopes and intercepts match --- lib/matplotlib/tests/test_path.py | 2 +- src/_path.h | 38 ++++++++----------------------- 2 files changed, 11 insertions(+), 29 deletions(-) diff --git a/lib/matplotlib/tests/test_path.py b/lib/matplotlib/tests/test_path.py index f5172a172728..eff9cbfa1288 100644 --- a/lib/matplotlib/tests/test_path.py +++ b/lib/matplotlib/tests/test_path.py @@ -247,7 +247,7 @@ def test_path_intersect_path(): a = Path([(0, 1), (0, 5)]) b = Path([(0, 1), (0, 2), (0, 5)]) assert a.intersects_path(b) and b.intersects_path(a) - + # check a range of slopes base = 10 a = Path([(-base, 0), (-base/2, base/2), (base/2, base/2), (base, 0)]) diff --git a/src/_path.h b/src/_path.h index d9018c2a1f33..c705df989750 100644 --- a/src/_path.h +++ b/src/_path.h @@ -812,23 +812,6 @@ int count_bboxes_overlapping_bbox(agg::rect_d &a, BBoxArray &bboxes) return count; } -// returns true if a point (x0, y0) -// is on a segment [(x1, y1), (x2, y2)] -inline bool segment_contains(const double &x1, - const double &y1, - const double &x2, - const double &y2, - const double &x0, - const double &y0) -{ - // first check if (x0, y0) lies on the segment's line - double intersect = (y0 - y1)*(x2 - x1) - (x0 - x1)*(y2 - y1); - if (intersect != 0.0) { - return false; - } - return fmin(x1, x2) <= x0 && x0 <= fmax(x1, x2) && - fmin(y1, y2) <= y0 && y0 <= fmax(y1, y2); -} inline bool segments_intersect(const double &x1, const double &y1, @@ -844,17 +827,16 @@ inline bool segments_intersect(const double &x1, if (den == 0.0) { // collinear segments // check if any of segments' edges are contained // in the other segment - if (segment_contains(x3, y3, x4, y4, x1, y1)) { - return true; - } - if (segment_contains(x3, y3, x4, y4, x2, y2)) { - return true; - } - if (segment_contains(x1, y1, x2, y2, x3, y3)) { - return true; - } - if (segment_contains(x1, y1, x2, y2, x4, y4)) { - return true; + double intercept = (y1*x2 - y2*x1)*(x4 - x3) - (y3*x4 - y4*x3)*(x1 - x2); + if (intercept == 0) { + if (x2 - x1 == 0) { // infinite slope + return (fmin(y1, y2) <= fmin(y3, y4) && fmin(y3, y4) <= fmax(y1, y2)) || + (fmin(y3, y4) <= fmin(y1, y1) && fmin(y1, y2) <= fmax(y3, y4)); + } + else { + return (fmin(x1, x2) <= fmin(x3, x4) && fmin(x3, x4) <= fmax(x1, x2)) || + (fmin(x3, x4) <= fmin(x1, x1) && fmin(x1, x2) <= fmax(x3, x4)); + } } return false; } From 196a277a2301ab8c61e015e8f709b8b6fca4dae7 Mon Sep 17 00:00:00 2001 From: Taras Kuzyo Date: Wed, 4 Jul 2018 14:35:20 +0300 Subject: [PATCH 07/13] typo fix --- lib/matplotlib/tests/test_path.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/tests/test_path.py b/lib/matplotlib/tests/test_path.py index eff9cbfa1288..459b73f2421f 100644 --- a/lib/matplotlib/tests/test_path.py +++ b/lib/matplotlib/tests/test_path.py @@ -259,7 +259,7 @@ def test_path_intersect_path(): # a and b should always intersect assert a.intersects_path(b) and b.intersects_path(a) # a and c should never intersect - assert not a.intersects_path(c) and not c.intersects_path(a) + assert not b.intersects_path(c) and not c.intersects_path(b) @pytest.mark.parametrize('offset', range(-720, 361, 45)) From aaff396c6bd6c123e333f397207dd4765cc0b0f9 Mon Sep 17 00:00:00 2001 From: Taras Kuzyo Date: Wed, 4 Jul 2018 14:45:56 +0300 Subject: [PATCH 08/13] simplified logic of segments_intersect when handling the infinite slope case --- src/_path.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/_path.h b/src/_path.h index c705df989750..43cd76a5238a 100644 --- a/src/_path.h +++ b/src/_path.h @@ -825,19 +825,19 @@ inline bool segments_intersect(const double &x1, // determinant double den = ((y4 - y3) * (x2 - x1)) - ((x4 - x3) * (y2 - y1)); if (den == 0.0) { // collinear segments - // check if any of segments' edges are contained - // in the other segment - double intercept = (y1*x2 - y2*x1)*(x4 - x3) - (y3*x4 - y4*x3)*(x1 - x2); - if (intercept == 0) { - if (x2 - x1 == 0) { // infinite slope - return (fmin(y1, y2) <= fmin(y3, y4) && fmin(y3, y4) <= fmax(y1, y2)) || - (fmin(y3, y4) <= fmin(y1, y1) && fmin(y1, y2) <= fmax(y3, y4)); - } - else { + if (x1 == x2 && x2 == x3) { // segments have infinite slope (vertical lines) + // and lie on the same line + return (fmin(y1, y2) <= fmin(y3, y4) && fmin(y3, y4) <= fmax(y1, y2)) || + (fmin(y3, y4) <= fmin(y1, y2) && fmin(y1, y2) <= fmax(y3, y4)); + } + else { + double intercept = (y1*x2 - y2*x1)*(x4 - x3) - (y3*x4 - y4*x3)*(x1 - x2); + if (intercept == 0.0) { // segments lie on the same line return (fmin(x1, x2) <= fmin(x3, x4) && fmin(x3, x4) <= fmax(x1, x2)) || - (fmin(x3, x4) <= fmin(x1, x1) && fmin(x1, x2) <= fmax(x3, x4)); + (fmin(x3, x4) <= fmin(x1, x2) && fmin(x1, x2) <= fmax(x3, x4)); } } + return false; } From dab359b66eb9e5cfa82b0a8064ea625ab3f9b8ba Mon Sep 17 00:00:00 2001 From: Taras Kuzyo Date: Tue, 26 Feb 2019 16:29:55 +0200 Subject: [PATCH 09/13] implemented isclose for path intersect check; added more test cases --- lib/matplotlib/tests/test_path.py | 119 ++++++++++++++++++------------ src/_path.h | 23 +++++- 2 files changed, 93 insertions(+), 49 deletions(-) diff --git a/lib/matplotlib/tests/test_path.py b/lib/matplotlib/tests/test_path.py index ed13c3ae9c18..87b1f385c465 100644 --- a/lib/matplotlib/tests/test_path.py +++ b/lib/matplotlib/tests/test_path.py @@ -274,52 +274,79 @@ def test_path_deepcopy(): def test_path_intersect_path(): - - # a and b are orthogonal and intersect at (0, 3) - a = Path([(0, 1), (0, 3)]) - b = Path([(1, 3), (0, 3)]) - assert a.intersects_path(b) and b.intersects_path(a) - - # a and b are collinear and intersect at (0, 3) - a = Path([(0, 1), (0, 3)]) - b = Path([(0, 5), (0, 3)]) - assert a.intersects_path(b) and b.intersects_path(a) - - # self-intersect - assert a.intersects_path(a) - - # a contains b - a = Path([(0, 0), (5, 5)]) - b = Path([(1, 1), (3, 3)]) - assert a.intersects_path(b) and b.intersects_path(a) - - # a and b are collinear but do not intersect - a = Path([(0, 1), (0, 5)]) - b = Path([(3, 0), (3, 3)]) - assert not a.intersects_path(b) and not b.intersects_path(a) - - # a and b are on the same line but do not intersect - a = Path([(0, 1), (0, 5)]) - b = Path([(0, 6), (0, 7)]) - assert not a.intersects_path(b) and not b.intersects_path(a) - - # b is the same as a but with extra point - a = Path([(0, 1), (0, 5)]) - b = Path([(0, 1), (0, 2), (0, 5)]) - assert a.intersects_path(b) and b.intersects_path(a) - - # check a range of slopes - base = 10 - a = Path([(-base, 0), (-base/2, base/2), (base/2, base/2), (base, 0)]) - c = Path([(-base, -base/2), (base, -base/2)]) - for phi in np.linspace(0, np.pi, 180): - x = base * np.cos(phi) - y = base * np.sin(phi) - b = Path([(0, 0), (x, y)]) - # a and b should always intersect - assert a.intersects_path(b) and b.intersects_path(a) - # a and c should never intersect - assert not b.intersects_path(c) and not c.intersects_path(b) + # test for the range of intersection angles + for phi in np.linspace(0, 2*np.pi, 180): + + transform = transforms.Affine2D().rotate(phi) + + # a nd b intersect at angle phi + a = Path([(-2, 0), (2, 0)]) + b = transform.transform_path(a) + assert a.intersects_path(b) and b.intersects_path(a), np.rad2deg(phi) + + # a and b touch at angle phi at (0, 0) + a = Path([(0, 0), (2, 0)]) + b = transform.transform_path(a) + assert a.intersects_path(b) and b.intersects_path(a), np.rad2deg(phi) + + # a and b are orthogonal and intersect at (0, 3) + a = transform.transform_path(Path([(0, 1), (0, 3)])) + b = transform.transform_path(Path([(1, 3), (0, 3)])) + assert a.intersects_path(b) and b.intersects_path(a), np.rad2deg(phi) + + # a and b are collinear and intersect at (0, 3) + a = transform.transform_path(Path([(0, 1), (0, 3)])) + b = transform.transform_path(Path([(0, 5), (0, 3)])) + assert a.intersects_path(b) and b.intersects_path(a), np.rad2deg(phi) + + # self-intersect + assert a.intersects_path(a), np.rad2deg(phi) + + # a contains b + a = transform.transform_path(Path([(0, 0), (5, 5)])) + b = transform.transform_path(Path([(1, 1), (3, 3)])) + assert a.intersects_path(b) and b.intersects_path(a), np.rad2deg(phi) + + # a and b are collinear but do not intersect + a = transform.transform_path(Path([(0, 1), (0, 5)])) + b = transform.transform_path(Path([(3, 0), (3, 3)])) + assert not a.intersects_path(b) and not b.intersects_path(a), np.rad2deg(phi) + + # a and b are on the same line but do not intersect + a = transform.transform_path(Path([(0, 1), (0, 5)])) + b = transform.transform_path(Path([(0, 6), (0, 7)])) + assert not a.intersects_path(b) and not b.intersects_path(a), np.rad2deg(phi) + + # Note: 1e-13 is the absolute tolerance error used for + # `isclose` function from src/_path.h + + # a and b are parallel but do not touch + for power in range(5, 13): + eps = 10**(-power) + a = transform.transform_path(Path([(0, 1), (0, 5)])) + b = transform.transform_path(Path([(0 + eps, 1), (0 + eps, 5)])) + assert not a.intersects_path(b) and not b.intersects_path(a), eps + + # a and b are on the same line but do not intersect (really close) + for power in range(5, 13): + eps = 10**(-power) + a = transform.transform_path(Path([(0, 1), (0, 5)])) + b = transform.transform_path(Path([(0, 5 + eps), (0, 7)])) + assert not a.intersects_path(b) and not b.intersects_path(a), eps + + # a and b are on the same line and intersect (really close) + for power in range(5, 13): + eps = 10**(-power) + a = transform.transform_path(Path([(0, 1), (0, 5)])) + b = transform.transform_path(Path([(0, 5 - eps), (0, 7)])) + assert a.intersects_path(b) and b.intersects_path(a), np.rad2deg(phi) + + # b is the same as a but with an extra point + a = transform.transform_path(Path([(0, 1), (0, 5)])) + b = transform.transform_path(Path([(0, 1), (0, 2), (0, 5)])) + assert a.intersects_path(b) and b.intersects_path(a), np.rad2deg(phi) + + return @pytest.mark.parametrize('offset', range(-720, 361, 45)) diff --git a/src/_path.h b/src/_path.h index eda2a5dd459e..4c26d754d540 100644 --- a/src/_path.h +++ b/src/_path.h @@ -3,6 +3,8 @@ #ifndef MPL_PATH_H #define MPL_PATH_H +#include + #include #include #include @@ -814,6 +816,13 @@ int count_bboxes_overlapping_bbox(agg::rect_d &a, BBoxArray &bboxes) } +inline bool isclose(double a, double b, double rtol, double atol) +{ + // as per python's math.isclose + return fabs(a-b) <= fmax(rtol * fmax(fabs(a), fabs(b)), atol); +} + + inline bool segments_intersect(const double &x1, const double &y1, const double &x2, @@ -823,9 +832,14 @@ inline bool segments_intersect(const double &x1, const double &x4, const double &y4) { + // relative and absolute tolerance values are chosen empirically + // it looks the atol value matters here bacause of round-off errors + const double rtol = 1e-10; + const double atol = 1e-13; // determinant double den = ((y4 - y3) * (x2 - x1)) - ((x4 - x3) * (y2 - y1)); - if (den == 0.0) { // collinear segments + + if (isclose(den, 0.0, rtol, atol)) { // collinear segments if (x1 == x2 && x2 == x3) { // segments have infinite slope (vertical lines) // and lie on the same line return (fmin(y1, y2) <= fmin(y3, y4) && fmin(y3, y4) <= fmax(y1, y2)) || @@ -833,7 +847,7 @@ inline bool segments_intersect(const double &x1, } else { double intercept = (y1*x2 - y2*x1)*(x4 - x3) - (y3*x4 - y4*x3)*(x1 - x2); - if (intercept == 0.0) { // segments lie on the same line + if (isclose(intercept, 0.0, rtol, atol)) { // segments lie on the same line return (fmin(x1, x2) <= fmin(x3, x4) && fmin(x3, x4) <= fmax(x1, x2)) || (fmin(x3, x4) <= fmin(x1, x2) && fmin(x1, x2) <= fmax(x3, x4)); } @@ -848,7 +862,10 @@ inline bool segments_intersect(const double &x1, double u1 = n1 / den; double u2 = n2 / den; - return (u1 >= 0.0 && u1 <= 1.0 && u2 >= 0.0 && u2 <= 1.0); + return ((u1 > 0.0 || isclose(u1, 0.0, rtol, atol)) && + (u1 < 1.0 || isclose(u1, 1.0, rtol, atol)) && + (u2 > 0.0 || isclose(u2, 0.0, rtol, atol)) && + (u2 < 1.0 || isclose(u2, 1.0, rtol, atol))); } template From fe91a6d6fb815d6642d5a3d56aac511ffce75c88 Mon Sep 17 00:00:00 2001 From: Taras Date: Tue, 26 Feb 2019 16:40:34 +0200 Subject: [PATCH 10/13] removed debug include --- src/_path.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/_path.h b/src/_path.h index 4c26d754d540..4a38aed5a621 100644 --- a/src/_path.h +++ b/src/_path.h @@ -3,8 +3,6 @@ #ifndef MPL_PATH_H #define MPL_PATH_H -#include - #include #include #include From 2320585e721af9017ebe6a01fe6440db43518dba Mon Sep 17 00:00:00 2001 From: Taras Kuzyo Date: Tue, 26 Feb 2019 17:26:01 +0200 Subject: [PATCH 11/13] flake8 fixes --- lib/matplotlib/tests/test_path.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/matplotlib/tests/test_path.py b/lib/matplotlib/tests/test_path.py index 87b1f385c465..f9d16cf5dfd4 100644 --- a/lib/matplotlib/tests/test_path.py +++ b/lib/matplotlib/tests/test_path.py @@ -282,22 +282,22 @@ def test_path_intersect_path(): # a nd b intersect at angle phi a = Path([(-2, 0), (2, 0)]) b = transform.transform_path(a) - assert a.intersects_path(b) and b.intersects_path(a), np.rad2deg(phi) + assert a.intersects_path(b) and b.intersects_path(a) # a and b touch at angle phi at (0, 0) a = Path([(0, 0), (2, 0)]) b = transform.transform_path(a) - assert a.intersects_path(b) and b.intersects_path(a), np.rad2deg(phi) + assert a.intersects_path(b) and b.intersects_path(a) # a and b are orthogonal and intersect at (0, 3) a = transform.transform_path(Path([(0, 1), (0, 3)])) b = transform.transform_path(Path([(1, 3), (0, 3)])) - assert a.intersects_path(b) and b.intersects_path(a), np.rad2deg(phi) + assert a.intersects_path(b) and b.intersects_path(a) # a and b are collinear and intersect at (0, 3) a = transform.transform_path(Path([(0, 1), (0, 3)])) b = transform.transform_path(Path([(0, 5), (0, 3)])) - assert a.intersects_path(b) and b.intersects_path(a), np.rad2deg(phi) + assert a.intersects_path(b) and b.intersects_path(a) # self-intersect assert a.intersects_path(a), np.rad2deg(phi) @@ -305,19 +305,19 @@ def test_path_intersect_path(): # a contains b a = transform.transform_path(Path([(0, 0), (5, 5)])) b = transform.transform_path(Path([(1, 1), (3, 3)])) - assert a.intersects_path(b) and b.intersects_path(a), np.rad2deg(phi) + assert a.intersects_path(b) and b.intersects_path(a) # a and b are collinear but do not intersect a = transform.transform_path(Path([(0, 1), (0, 5)])) b = transform.transform_path(Path([(3, 0), (3, 3)])) - assert not a.intersects_path(b) and not b.intersects_path(a), np.rad2deg(phi) + assert not a.intersects_path(b) and not b.intersects_path(a) # a and b are on the same line but do not intersect a = transform.transform_path(Path([(0, 1), (0, 5)])) b = transform.transform_path(Path([(0, 6), (0, 7)])) - assert not a.intersects_path(b) and not b.intersects_path(a), np.rad2deg(phi) + assert not a.intersects_path(b) and not b.intersects_path(a) - # Note: 1e-13 is the absolute tolerance error used for + # Note: 1e-13 is the absolute tolerance error used for # `isclose` function from src/_path.h # a and b are parallel but do not touch @@ -325,26 +325,26 @@ def test_path_intersect_path(): eps = 10**(-power) a = transform.transform_path(Path([(0, 1), (0, 5)])) b = transform.transform_path(Path([(0 + eps, 1), (0 + eps, 5)])) - assert not a.intersects_path(b) and not b.intersects_path(a), eps + assert not a.intersects_path(b) and not b.intersects_path(a) # a and b are on the same line but do not intersect (really close) for power in range(5, 13): eps = 10**(-power) a = transform.transform_path(Path([(0, 1), (0, 5)])) b = transform.transform_path(Path([(0, 5 + eps), (0, 7)])) - assert not a.intersects_path(b) and not b.intersects_path(a), eps + assert not a.intersects_path(b) and not b.intersects_path(a) # a and b are on the same line and intersect (really close) for power in range(5, 13): eps = 10**(-power) a = transform.transform_path(Path([(0, 1), (0, 5)])) b = transform.transform_path(Path([(0, 5 - eps), (0, 7)])) - assert a.intersects_path(b) and b.intersects_path(a), np.rad2deg(phi) + assert a.intersects_path(b) and b.intersects_path(a) # b is the same as a but with an extra point a = transform.transform_path(Path([(0, 1), (0, 5)])) b = transform.transform_path(Path([(0, 1), (0, 2), (0, 5)])) - assert a.intersects_path(b) and b.intersects_path(a), np.rad2deg(phi) + assert a.intersects_path(b) and b.intersects_path(a) return From b6ff77efe56f487a64b814057fbb0ebc444d3d6b Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Sat, 2 Mar 2019 21:21:49 +0200 Subject: [PATCH 12/13] typo fix Co-Authored-By: TarasKuzyo --- lib/matplotlib/tests/test_path.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/tests/test_path.py b/lib/matplotlib/tests/test_path.py index f9d16cf5dfd4..077cb8a8f743 100644 --- a/lib/matplotlib/tests/test_path.py +++ b/lib/matplotlib/tests/test_path.py @@ -279,7 +279,7 @@ def test_path_intersect_path(): transform = transforms.Affine2D().rotate(phi) - # a nd b intersect at angle phi + # a and b intersect at angle phi a = Path([(-2, 0), (2, 0)]) b = transform.transform_path(a) assert a.intersects_path(b) and b.intersects_path(a) From 3344d136fd26c382d575763b27a298c2bc76d5cf Mon Sep 17 00:00:00 2001 From: Taras Kuzyo Date: Sat, 2 Mar 2019 22:30:02 +0200 Subject: [PATCH 13/13] reduced the number of checks to 30 angles and 4 eps values --- lib/matplotlib/tests/test_path.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/matplotlib/tests/test_path.py b/lib/matplotlib/tests/test_path.py index f9d16cf5dfd4..ff8f38596cb1 100644 --- a/lib/matplotlib/tests/test_path.py +++ b/lib/matplotlib/tests/test_path.py @@ -275,9 +275,13 @@ def test_path_deepcopy(): def test_path_intersect_path(): # test for the range of intersection angles - for phi in np.linspace(0, 2*np.pi, 180): + base_angles = np.array([0, 15, 30, 45, 60, 75, 90, 105, 120, 135]) + angles = np.concatenate([base_angles, base_angles + 1, base_angles - 1]) + eps_array = [1e-5, 1e-8, 1e-10, 1e-12] - transform = transforms.Affine2D().rotate(phi) + for phi in angles: + + transform = transforms.Affine2D().rotate(np.deg2rad(phi)) # a nd b intersect at angle phi a = Path([(-2, 0), (2, 0)]) @@ -300,7 +304,7 @@ def test_path_intersect_path(): assert a.intersects_path(b) and b.intersects_path(a) # self-intersect - assert a.intersects_path(a), np.rad2deg(phi) + assert a.intersects_path(a) # a contains b a = transform.transform_path(Path([(0, 0), (5, 5)])) @@ -321,22 +325,19 @@ def test_path_intersect_path(): # `isclose` function from src/_path.h # a and b are parallel but do not touch - for power in range(5, 13): - eps = 10**(-power) + for eps in eps_array: a = transform.transform_path(Path([(0, 1), (0, 5)])) b = transform.transform_path(Path([(0 + eps, 1), (0 + eps, 5)])) assert not a.intersects_path(b) and not b.intersects_path(a) # a and b are on the same line but do not intersect (really close) - for power in range(5, 13): - eps = 10**(-power) + for eps in eps_array: a = transform.transform_path(Path([(0, 1), (0, 5)])) b = transform.transform_path(Path([(0, 5 + eps), (0, 7)])) assert not a.intersects_path(b) and not b.intersects_path(a) # a and b are on the same line and intersect (really close) - for power in range(5, 13): - eps = 10**(-power) + for eps in eps_array: a = transform.transform_path(Path([(0, 1), (0, 5)])) b = transform.transform_path(Path([(0, 5 - eps), (0, 7)])) assert a.intersects_path(b) and b.intersects_path(a) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy