diff --git a/src/util/geo/Box.h b/src/util/geo/Box.h index 4b0e3ff..3c41e80 100644 --- a/src/util/geo/Box.h +++ b/src/util/geo/Box.h @@ -38,6 +38,20 @@ class Box { Point _ll, _ur; }; +template +class RotatedBox { + public: + RotatedBox() : _box() {} + RotatedBox(const Box& box) : _box(box), _deg(0), _center() {} + RotatedBox(const Point& ll, const Point& ur) : _box(ll, ur), _deg(0), _center() {} + + + private: + Box _box; + double _deg; + Point _center; +}; + } // namespace geo } // namespace util diff --git a/src/util/geo/Geo.h b/src/util/geo/Geo.h index 949a483..4787c90 100644 --- a/src/util/geo/Geo.h +++ b/src/util/geo/Geo.h @@ -7,6 +7,7 @@ #define _USE_MATH_DEFINES #include +#include #include #include "util/Misc.h" #include "util/geo/Box.h" @@ -215,6 +216,90 @@ inline bool contains(const Point& p, const Line& l) { return false; } +// _____________________________________________________________________________ +template +inline bool contains(const Point& p, const Polygon& poly) { + // see https://de.wikipedia.org/wiki/Punkt-in-Polygon-Test_nach_Jordan + int8_t c = -1; + + for (size_t i = 1; i < poly.getOuter().size(); i++) { + c *= polyContCheck(p, poly.getOuter()[i - 1], poly.getOuter()[i]); + if (c == 0) return true; + } + + c *= polyContCheck(p, poly.getOuter().back(), poly.getOuter()[0]); + + return c >= 0; +} + +// _____________________________________________________________________________ +template +inline int8_t polyContCheck(const Point& a, Point b, Point c) { + if (a.getY() == b.getY() && a.getY() == c.getY()) + return (!((b.getX() <= a.getX() && a.getX() <= c.getX()) || + (c.getX() <= a.getX() && a.getX() <= b.getX()))); + if (a.getY() == b.getY() && a.getX() == b.getX()) return 0; + if (b.getY() > c.getY()) { + Point tmp = b; + b = c; + c = tmp; + } + if (a.getY() <= b.getY() || a.getY() > c.getY()) return 1; + + double d = (b.getX() - a.getX()) * (c.getY() - a.getY()) - + (b.getY() - a.getY()) * (c.getX() - a.getX()); + if (d > 0) return -1; + if (d < 0) return 1; + return 0; +} + +// _____________________________________________________________________________ +template +inline bool contains(const Polygon& polyC, const Polygon& poly) { + for (const auto& p : polyC.getOuter()) { + if (!contains(p, poly)) return false; + } + return true; +} + +// _____________________________________________________________________________ +template +inline bool contains(const Line& l, const Polygon& poly) { + for (const auto& p : l) { + if (!contains(p, poly)) return false; + } + return true; +} + +// _____________________________________________________________________________ +template +inline bool contains(const Box& b, const Polygon& poly) { + return contains(b.getLowerLeft(), poly) && + contains(b.getUpperRight(), poly) && + contains(Point(b.getUpperRight().getX(), b.getLowerLeft().getY()), + poly) && + contains(Point(b.getLowerLeft().getX(), b.getUpperRight().getY()), + poly); +} + +// _____________________________________________________________________________ +template +inline bool contains(const Polygon& poly, const Box& b) { + for (const auto& p : poly.getOuter()) { + if (!contains(p, b)) return false; + } + return true; +} + +// _____________________________________________________________________________ +template +inline bool contains(const Polygon& poly, const Line& l) { + for (const auto& p : poly.getOuter()) { + if (!contains(p, l)) return false; + } + return true; +} + // _____________________________________________________________________________ template inline bool intersects(const LineSegment& ls1, const LineSegment& ls2) { @@ -439,8 +524,7 @@ inline double innerProd(double x1, double y1, double x2, double y2, double x3, template inline double innerProd(const Point& a, const Point& b, const Point& c) { - return innerProd(a.template getX(), a.template getY(), b.template getX(), - b.template getY(), c.template getX(), c.template getY()); + return innerProd(a.getX(), a.getY(), b.getX(), b.getY(), c.getX(), c.getY()); } // _____________________________________________________________________________ @@ -486,6 +570,12 @@ inline std::string getWKT(const Line& l) { return ss.str(); } +// _____________________________________________________________________________ +template +inline std::string getWKT(const LineSegment& l) { + return getWKT(Line{l.first, l.second}); +} + // _____________________________________________________________________________ template inline std::string getWKT(const Box& l) { @@ -744,6 +834,14 @@ inline Box getBoundingBox(const Line& l) { return ret; } +// _____________________________________________________________________________ +template +inline Box getBoundingBox(const Polygon& pol) { + Box ret; + for (const auto& p : pol.getOuter()) ret = extendBox(p, ret); + return ret; +} + // _____________________________________________________________________________ template inline Box getBoundingBox(const LineSegment& ls) { diff --git a/src/util/geo/Polygon.h b/src/util/geo/Polygon.h index 2841830..1cef21f 100644 --- a/src/util/geo/Polygon.h +++ b/src/util/geo/Polygon.h @@ -15,7 +15,8 @@ namespace geo { template class Polygon { public: - // maximum inverse box as default value of box + Polygon() {} + Polygon(const Line& l) : _outer(l) {} const std::vector>& getOuter() const { return _outer; } diff --git a/src/util/tests/TestMain.cpp b/src/util/tests/TestMain.cpp index b15c2b5..053f20f 100644 --- a/src/util/tests/TestMain.cpp +++ b/src/util/tests/TestMain.cpp @@ -942,6 +942,29 @@ CASE("geometry") { EXPECT(geo::intersects(Box(Point(0, 0), Point(3, 3)), boxa)); EXPECT(geo::intersects(Box(Point(1.5, 1.5), Point(3, 3)), boxa)); EXPECT(geo::intersects(Box(Point(0, 0), Point(1.5, 1.5)), boxa)); + + Polygon poly({Point(1, 1), Point(3, 2), Point(4, 3), Point(6, 3), Point(5, 1)}); + EXPECT(geo::getWKT(poly) == "POLYGON ((1 1, 3 2, 4 3, 6 3, 5 1))"); + EXPECT(geo::contains(Point(4, 2), poly)); + EXPECT(!geo::contains(Point(3, 3), poly)); + EXPECT(geo::contains(Point(1, 1), poly)); + EXPECT(geo::contains(Point(3, 2), poly)); + EXPECT(geo::contains(Point(4, 3), poly)); + EXPECT(geo::contains(Point(6, 3), poly)); + EXPECT(geo::contains(Point(5, 1), poly)); + + EXPECT(geo::contains(Line{Point(6, 3), Point(5, 1)}, poly)); + EXPECT(!geo::contains(Line{Point(6, 3), Point(50, 1)}, poly)); + EXPECT(geo::contains(Line{Point(4, 2), Point(4.5, 2)}, poly)); + EXPECT(geo::contains(Line{Point(4, 2), Point(5, 1)}, poly)); + + Box polybox(Point(1, 1), Point(6, 4)); + EXPECT(geo::contains(poly, polybox)); + EXPECT(!geo::contains(polybox, poly)); + Box polybox2(Point(4, 1), Point(5, 2)); + EXPECT(geo::contains(polybox2, poly)); + EXPECT(geo::contains(poly, getBoundingBox(poly))); + } };