From 69a360c48fd70085337d155429e2bac7ede4dc1a Mon Sep 17 00:00:00 2001 From: Patrick Brosi Date: Fri, 17 Aug 2018 15:07:20 +0200 Subject: [PATCH] handle cases where multiple endpoints are colinear as non-intersecting for line segments (because otherwise it cannot be used to check if intersection() has undefined behaviour, as there will be an infinite number of intersections) --- src/util/geo/Geo.h | 8 ++++++-- src/util/tests/TestMain.cpp | 6 ++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/util/geo/Geo.h b/src/util/geo/Geo.h index 0a7c0e6..cd93423 100644 --- a/src/util/geo/Geo.h +++ b/src/util/geo/Geo.h @@ -398,9 +398,13 @@ inline bool contains(const std::vector>& multigeo, // _____________________________________________________________________________ template inline bool intersects(const LineSegment& ls1, const LineSegment& ls2) { + // two line segments intersect of there is a single, well-defined intersection + // point between them. If more than 1 endpoint is colinear with any line, + // the segments have infinite intersections. We handle this case as non- + // intersecting return intersects(getBoundingBox(ls1), getBoundingBox(ls2)) && - (contains(ls1.first, ls2) || contains(ls1.second, ls2) || - contains(ls2.first, ls1) || contains(ls2.second, ls1) || + (((contains(ls1.first, ls2) ^ contains(ls1.second, ls2)) ^ + (contains(ls2.first, ls1) ^ contains(ls2.second, ls1))) || (((crossProd(ls1.first, ls2) < 0) ^ (crossProd(ls1.second, ls2) < 0)) && ((crossProd(ls2.first, ls1) < 0) ^ diff --git a/src/util/tests/TestMain.cpp b/src/util/tests/TestMain.cpp index 26b35a8..677d574 100644 --- a/src/util/tests/TestMain.cpp +++ b/src/util/tests/TestMain.cpp @@ -972,12 +972,14 @@ CASE("geometry") { EXPECT(geo::intersects(lsa, lsb)); - EXPECT(geo::intersects(lsa, lsa)); - EXPECT(geo::intersects(lsb, lsb)); + EXPECT(!geo::intersects(lsa, lsa)); + EXPECT(!geo::intersects(lsb, lsb)); EXPECT(!geo::intersects(lsa, lsc)); EXPECT(!geo::intersects(geo::Point(871569.2, 6104550.4), geo::Point(871581.2, 6104536), geo::Point(871580.3, 6104541.3), geo::Point(871625.7, 6104510.1))); + EXPECT(!geo::intersects(geo::Point(0, 0), geo::Point(1, 1), geo::Point(0.5, 0.5), geo::Point(1.5, 1.5))); + geo::Line l{geo::Point(1, 1), geo::Point(2, 2), geo::Point(2, 4)}; EXPECT(!geo::contains(geo::Point(1, 2), l)); EXPECT(geo::contains(geo::Point(2, 2), l));