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

Skip to content

Commit 3cf46cb

Browse files
authored
Pathing issue (#20395)
* added check for collinearity
1 parent 103c3ab commit 3cf46cb

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
@@ -833,21 +833,27 @@ inline bool segments_intersect(const double &x1,
833833
// determinant
834834
double den = ((y4 - y3) * (x2 - x1)) - ((x4 - x3) * (y2 - y1));
835835

836-
if (isclose(den, 0.0)) { // collinear segments
837-
if (x1 == x2 && x2 == x3) { // segments have infinite slope (vertical lines)
838-
// and lie on the same line
839-
return (fmin(y1, y2) <= fmin(y3, y4) && fmin(y3, y4) <= fmax(y1, y2)) ||
840-
(fmin(y3, y4) <= fmin(y1, y2) && fmin(y1, y2) <= fmax(y3, y4));
841-
}
842-
else {
843-
double intercept = (y1*x2 - y2*x1)*(x4 - x3) - (y3*x4 - y4*x3)*(x1 - x2);
844-
if (isclose(intercept, 0.0)) { // segments lie on the same line
836+
// If den == 0 we have two possibilities:
837+
if (isclose(den, 0.0)) {
838+
float t_area = (x2*y3 - x3*y2) - x1*(y3 - y2) + y1*(x3 - x2);
839+
// 1 - If the area of the triangle made by the 3 first points (2 from the first segment
840+
// plus one from the second) is zero, they are collinear
841+
if (isclose(t_area, 0.0)) {
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 {
845848
return (fmin(x1, x2) <= fmin(x3, x4) && fmin(x3, x4) <= fmax(x1, x2)) ||
846-
(fmin(x3, x4) <= fmin(x1, x2) && fmin(x1, x2) <= fmax(x3, x4));
849+
(fmin(x3, x4) <= fmin(x1, x2) && fmin(x1, x2) <= fmax(x3, x4));
850+
847851
}
848852
}
849-
850-
return false;
853+
// 2 - If t_area is not zero, the segments are parallel, but not collinear
854+
else {
855+
return false;
856+
}
851857
}
852858

853859
const double n1 = ((x4 - x3) * (y1 - y3)) - ((y4 - y3) * (x1 - x3));
@@ -865,6 +871,7 @@ inline bool segments_intersect(const double &x1,
865871
template <class PathIterator1, class PathIterator2>
866872
bool path_intersects_path(PathIterator1 &p1, PathIterator2 &p2)
867873
{
874+
868875
typedef PathNanRemover<py::PathIterator> no_nans_t;
869876
typedef agg::conv_curve<no_nans_t> curve_t;
870877

@@ -889,12 +896,14 @@ bool path_intersects_path(PathIterator1 &p1, PathIterator2 &p2)
889896
}
890897
c2.rewind(0);
891898
c2.vertex(&x21, &y21);
899+
892900

893901
while (c2.vertex(&x22, &y22) != agg::path_cmd_stop) {
894902
// if the segment in path 2 is (almost) 0 length, skip to next vertex
895903
if ((isclose((x21 - x22) * (x21 - x22) + (y21 - y22) * (y21 - y22), 0))){
896904
continue;
897905
}
906+
898907
if (segments_intersect(x11, y11, x12, y12, x21, y21, x22, y22)) {
899908
return true;
900909
}

0 commit comments

Comments
 (0)