From 966c506f3cd58372c94f134a556ca2d406c863da Mon Sep 17 00:00:00 2001 From: Andrew Bell Date: Fri, 10 May 2019 14:17:55 -0400 Subject: [PATCH] Fix WKT generation for polygons with islands. --- filters/private/hexer/HexGrid.cpp | 20 ++++------ filters/private/hexer/Path.cpp | 65 ++++++++++++++++++++++--------- filters/private/hexer/Path.hpp | 13 +++++-- 3 files changed, 64 insertions(+), 34 deletions(-) diff --git a/filters/private/hexer/HexGrid.cpp b/filters/private/hexer/HexGrid.cpp index 6892ef703a..8a54c8ff82 100644 --- a/filters/private/hexer/HexGrid.cpp +++ b/filters/private/hexer/HexGrid.cpp @@ -368,27 +368,23 @@ void HexGrid::cleanPossibleRoot(Segment s, Path *p) } } -void HexGrid::toWKT(std::ostream& output) const +void HexGrid::toWKT(std::ostream& out) const { - auto outputPath = [this,&output](size_t pathNum) + auto writePath = [this, &out](size_t pathNum) { - Path *p = rootPaths()[pathNum]; - - output << "("; - p->toWKT(output); - output << ")"; + rootPaths()[pathNum]->toWKT(out); }; - output << "MULTIPOLYGON ("; + out << "MULTIPOLYGON ("; if (rootPaths().size()) - outputPath(0); + writePath(0); for (size_t pi = 1; pi < rootPaths().size(); ++pi) { - output << ","; - outputPath(pi); + out << ","; + writePath(pi); } - output << ")"; + out << ")"; } size_t HexGrid::densePointCount() const diff --git a/filters/private/hexer/Path.cpp b/filters/private/hexer/Path.cpp index d102c4c4b3..a16845ef62 100644 --- a/filters/private/hexer/Path.cpp +++ b/filters/private/hexer/Path.cpp @@ -66,34 +66,63 @@ vector Path::points() const return points; } -void Path::toWKT( std::ostream& output) const +void Path::writeRing(std::ostream& out) const { - vector pts = points(); - - auto outputPoint = [&output](Point& p) + auto outputPoint = [&out](const Point& p) { - output << p.m_x << " " << p.m_y; + out << p.m_x << " " << p.m_y; }; - output << "("; + const vector& pts = points(); + assert(pts.size() > 2); + out << "("; + outputPoint(pts.front()); + for (auto it = pts.begin() + 1; it != pts.end(); ++it) + { + out << ", "; + outputPoint(*it); + } + out << ")"; +} - auto pi = pts.begin(); - if (pi != pts.end()) - outputPoint(*pi++); - for (; pi != pts.end(); ++pi) +// WKT (or GeoJSON) doesn't allow nesting of polygons. You can just have +// polygons and holes. Islands within the holes need to be described as +// separate polygons. To that end, we grather the islands from all holes +// and return them to be processed as separate polygons. +PathPtrList Path::writePolygon(std::ostream& out) const +{ + PathPtrList islands; + + out << "("; + writeRing(out); + const PathPtrList& paths = subPaths(); + for (auto& p : paths) { - output << ", "; - outputPoint(*pi); + out << ", "; + p->writeRing(out); + const PathPtrList& subs(p->subPaths()); + islands.insert(islands.end(), subs.begin(), subs.end()); } + out << ")"; + return islands; +} - output << ")"; - vector paths = subPaths(); - for (size_t pi = 0; pi != paths.size(); ++pi) +void Path::toWKT(std::ostream& out) const +{ + PathPtrList islands = writePolygon(out); + + // See the note on writePolygon() + while (islands.size()) { - Path* p = paths[pi]; - output <<","; - p->toWKT(output); + PathPtrList paths; + paths.swap(islands); + for (Path *p : paths) + { + out << ", "; + PathPtrList subIslands = p->writePolygon(out); + islands.insert(islands.end(), subIslands.begin(), subIslands.end()); + } } } diff --git a/filters/private/hexer/Path.hpp b/filters/private/hexer/Path.hpp index 9d3a448fa9..8b34c548ae 100644 --- a/filters/private/hexer/Path.hpp +++ b/filters/private/hexer/Path.hpp @@ -49,6 +49,8 @@ enum Orientation }; class HexGrid; +class Path; +using PathPtrList = std::vector; class Path { @@ -59,8 +61,8 @@ class Path ~Path() { - for (std::vector::size_type i = 0; i < m_children.size(); ++i) - delete m_children[i]; + for (auto p : m_children) + delete p; } void push_back(const Segment& s) @@ -85,7 +87,7 @@ class Path Orientation orientation() const { return m_orientation; } std::vector points() const; - std::vector subPaths() const + PathPtrList subPaths() const { return m_children; } void toWKT( std::ostream& output) const; @@ -95,12 +97,15 @@ class Path /// Parent path (NULL if root path) Path *m_parent; /// Children - std::vector m_children; + PathPtrList m_children; /// Orientation of path AT EXTRACTION - segments are ALWAYS ordered /// clockwise. Orientation m_orientation; /// List of segments that make up the path. std::vector m_segs; + + void writeRing(std::ostream& out) const; + PathPtrList writePolygon(std::ostream& out) const; }; } //namespace hexer