Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2d99ead

Browse files
diegopetrolameeseeksmachine
authored andcommitted
Backport PR matplotlib#20395: Pathing issue
1 parent 88f23d3 commit 2d99ead

File tree

2 files changed

+31
-12
lines changed

2 files changed

+31
-12
lines changed

lib/matplotlib/tests/test_path.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,16 @@ def test_path_intersect_path(phi):
410410
b = transform.transform_path(Path([(0, 1), (0, 2), (0, 5)]))
411411
assert a.intersects_path(b) and b.intersects_path(a)
412412

413+
# a and b are collinear but do not intersect
414+
a = transform.transform_path(Path([(1, -1), (0, -1)]))
415+
b = transform.transform_path(Path([(0, 1), (0.9, 1)]))
416+
assert not a.intersects_path(b) and not b.intersects_path(a)
417+
418+
# a and b are collinear but do not intersect
419+
a = transform.transform_path(Path([(0., -5.), (1., -5.)]))
420+
b = transform.transform_path(Path([(1., 5.), (0., 5.)]))
421+
assert not a.intersects_path(b) and not b.intersects_path(a)
422+
413423

414424
@pytest.mark.parametrize('offset', range(-720, 361, 45))
415425
def test_full_arc(offset):

src/_path.h

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -838,21 +838,27 @@ inline bool segments_intersect(const double &x1,
838838
// determinant
839839
double den = ((y4 - y3) * (x2 - x1)) - ((x4 - x3) * (y2 - y1));
840840

841-
if (isclose(den, 0.0)) { // collinear segments
842-
if (x1 == x2 && x2 == x3) { // segments have infinite slope (vertical lines)
843-
// and lie on the same line
844-
return (fmin(y1, y2) <= fmin(y3, y4) && fmin(y3, y4) <= fmax(y1, y2)) ||
845-
(fmin(y3, y4) <= fmin(y1, y2) && fmin(y1, y2) <= fmax(y3, y4));
846-
}
847-
else {
848-
double intercept = (y1*x2 - y2*x1)*(x4 - x3) - (y3*x4 - y4*x3)*(x1 - x2);
849-
if (isclose(intercept, 0.0)) { // segments lie on the same line
841+
// If den == 0 we have two possibilities:
842+
if (isclose(den, 0.0)) {
843+
float t_area = (x2*y3 - x3*y2) - x1*(y3 - y2) + y1*(x3 - x2);
844+
// 1 - If the area of the triangle made by the 3 first points (2 from the first segment
845+
// plus one from the second) is zero, they are collinear
846+
if (isclose(t_area, 0.0)) {
847+
if (x1 == x2 && x2 == x3) { // segments have infinite slope (vertical lines)
848+
// and lie on the same line
849+
return (fmin(y1, y2) <= fmin(y3, y4) && fmin(y3, y4) <= fmax(y1, y2)) ||
850+
(fmin(y3, y4) <= fmin(y1, y2) && fmin(y1, y2) <= fmax(y3, y4));
851+
}
852+
else {
850853
return (fmin(x1, x2) <= fmin(x3, x4) && fmin(x3, x4) <= fmax(x1, x2)) ||
851-
(fmin(x3, x4) <= fmin(x1, x2) && fmin(x1, x2) <= fmax(x3, x4));
854+
(fmin(x3, x4) <= fmin(x1, x2) && fmin(x1, x2) <= fmax(x3, x4));
855+
852856
}
853857
}
854-
855-
return false;
858+
// 2 - If t_area is not zero, the segments are parallel, but not collinear
859+
else {
860+
return false;
861+
}
856862
}
857863

858864
const double n1 = ((x4 - x3) * (y1 - y3)) - ((y4 - y3) * (x1 - x3));
@@ -870,6 +876,7 @@ inline bool segments_intersect(const double &x1,
870876
template <class PathIterator1, class PathIterator2>
871877
bool path_intersects_path(PathIterator1 &p1, PathIterator2 &p2)
872878
{
879+
873880
typedef PathNanRemover<py::PathIterator> no_nans_t;
874881
typedef agg::conv_curve<no_nans_t> curve_t;
875882

@@ -894,12 +901,14 @@ bool path_intersects_path(PathIterator1 &p1, PathIterator2 &p2)
894901
}
895902
c2.rewind(0);
896903
c2.vertex(&x21, &y21);
904+
897905

898906
while (c2.vertex(&x22, &y22) != agg::path_cmd_stop) {
899907
// if the segment in path 2 is (almost) 0 length, skip to next vertex
900908
if ((isclose((x21 - x22) * (x21 - x22) + (y21 - y22) * (y21 - y22), 0))){
901909
continue;
902910
}
911+
903912
if (segments_intersect(x11, y11, x12, y12, x21, y21, x22, y22)) {
904913
return true;
905914
}

0 commit comments

Comments
 (0)