From 81a3cff59dfa92fb3ac19a31a34384de4bb208fa Mon Sep 17 00:00:00 2001 From: Diego Date: Mon, 7 Jun 2021 15:46:55 -0300 Subject: [PATCH 1/2] added check for collinearity --- lib/matplotlib/tests/test_path.py | 10 ++++++++++ src/_path.h | 33 ++++++++++++++++++++----------- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/lib/matplotlib/tests/test_path.py b/lib/matplotlib/tests/test_path.py index 8bd7777eca0d..3abe388f2b6c 100644 --- a/lib/matplotlib/tests/test_path.py +++ b/lib/matplotlib/tests/test_path.py @@ -410,6 +410,16 @@ def test_path_intersect_path(phi): b = transform.transform_path(Path([(0, 1), (0, 2), (0, 5)])) assert a.intersects_path(b) and b.intersects_path(a) + # test added to adress issue #20328 + a = transform.transform_path(Path([(1, -1), (0, -1)])) + b = transform.transform_path(Path([(0, 1), (0.9, 1)])) + assert not a.intersects_path(b) and not b.intersects_path(a) + + # test added to adress issue #20328 + a = transform.transform_path(Path([(0., -5.), (1., -5.)])) + b = transform.transform_path(Path([(1., 5.), (0., 5.)])) + assert not a.intersects_path(b) and not b.intersects_path(a) + @pytest.mark.parametrize('offset', range(-720, 361, 45)) def test_full_arc(offset): diff --git a/src/_path.h b/src/_path.h index 49d862eafcad..106b13b606d0 100644 --- a/src/_path.h +++ b/src/_path.h @@ -833,21 +833,27 @@ inline bool segments_intersect(const double &x1, // determinant double den = ((y4 - y3) * (x2 - x1)) - ((x4 - x3) * (y2 - y1)); - if (isclose(den, 0.0)) { // 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)) || - (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 (isclose(intercept, 0.0)) { // segments lie on the same line + // If den == 0 we have two possibilities: + if (isclose(den, 0.0)) { + float t_area = (x2*y3 - x3*y2) - x1*(y3 - y2) + y1*(x3 - x2); + // 1 - If the area of the triangle made by the 3 first points (2 from the first segment + // plus one from the second) is zero, they are collinear + if (isclose(t_area, 0.0)) { + 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 { 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)); + (fmin(x3, x4) <= fmin(x1, x2) && fmin(x1, x2) <= fmax(x3, x4)); + } } - - return false; + // 2 - If t_area is not zero, the segments are parallel, but not collinear + else { + return false; + } } const double n1 = ((x4 - x3) * (y1 - y3)) - ((y4 - y3) * (x1 - x3)); @@ -865,6 +871,7 @@ inline bool segments_intersect(const double &x1, template bool path_intersects_path(PathIterator1 &p1, PathIterator2 &p2) { + typedef PathNanRemover no_nans_t; typedef agg::conv_curve curve_t; @@ -889,12 +896,14 @@ bool path_intersects_path(PathIterator1 &p1, PathIterator2 &p2) } c2.rewind(0); c2.vertex(&x21, &y21); + while (c2.vertex(&x22, &y22) != agg::path_cmd_stop) { // if the segment in path 2 is (almost) 0 length, skip to next vertex if ((isclose((x21 - x22) * (x21 - x22) + (y21 - y22) * (y21 - y22), 0))){ continue; } + if (segments_intersect(x11, y11, x12, y12, x21, y21, x22, y22)) { return true; } From d81113416e3e0e88d95d891be8058fdd649fc918 Mon Sep 17 00:00:00 2001 From: Diego Petrola Date: Fri, 11 Jun 2021 09:52:25 -0300 Subject: [PATCH 2/2] modified comments --- lib/matplotlib/tests/test_path.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/tests/test_path.py b/lib/matplotlib/tests/test_path.py index 3abe388f2b6c..ed818257bb17 100644 --- a/lib/matplotlib/tests/test_path.py +++ b/lib/matplotlib/tests/test_path.py @@ -410,12 +410,12 @@ def test_path_intersect_path(phi): b = transform.transform_path(Path([(0, 1), (0, 2), (0, 5)])) assert a.intersects_path(b) and b.intersects_path(a) - # test added to adress issue #20328 + # a and b are collinear but do not intersect a = transform.transform_path(Path([(1, -1), (0, -1)])) b = transform.transform_path(Path([(0, 1), (0.9, 1)])) assert not a.intersects_path(b) and not b.intersects_path(a) - # test added to adress issue #20328 + # a and b are collinear but do not intersect a = transform.transform_path(Path([(0., -5.), (1., -5.)])) b = transform.transform_path(Path([(1., 5.), (0., 5.)])) assert not a.intersects_path(b) and not b.intersects_path(a)