From 87046f5d18ce3a5d64607ba430e79be870beb8a5 Mon Sep 17 00:00:00 2001 From: Robert Date: Sun, 18 Apr 2021 15:44:48 +0200 Subject: [PATCH 1/8] Added nodiscard --- lib/osmparser/include/osmimember.hpp | 10 +- lib/osmparser/include/osmobject.hpp | 20 +- lib/osmparser/include/osmrelation.hpp | 16 +- lib/osmparser/include/osmway.hpp | 6 +- lib/osmparser/include/util.hpp | 8 +- src/multipolygon.cpp | 299 ++++++-------------------- 6 files changed, 99 insertions(+), 260 deletions(-) diff --git a/lib/osmparser/include/osmimember.hpp b/lib/osmparser/include/osmimember.hpp index b426f72..cc92650 100644 --- a/lib/osmparser/include/osmimember.hpp +++ b/lib/osmparser/include/osmimember.hpp @@ -22,12 +22,12 @@ namespace osmp IMember(const IMember& other) = delete; virtual ~IMember() {} - IMember::Type GetType() const; + [[nodiscard]] IMember::Type GetType() const; - const std::vector& GetTags() const; - size_t GetTagsSize() const; - const Tag& GetTag(size_t index) const; - std::string GetTag(const std::string& key) const; + [[nodiscard]] const std::vector& GetTags() const; + [[nodiscard]] size_t GetTagsSize() const; + [[nodiscard]] const Tag& GetTag(size_t index) const; + [[nodiscard]] std::string GetTag(const std::string& key) const; protected: IMember(const tinyxml2::XMLElement* element, Object* parent, IMember::Type type); diff --git a/lib/osmparser/include/osmobject.hpp b/lib/osmparser/include/osmobject.hpp index 9870fcd..b8421fe 100644 --- a/lib/osmparser/include/osmobject.hpp +++ b/lib/osmparser/include/osmobject.hpp @@ -15,20 +15,20 @@ namespace osmp class Object { public: - Object(const std::string& file); + explicit Object(const std::string& file); ~Object(); - std::vector> GetNodes() const; - size_t GetNodesSize() const; - std::shared_ptr GetNode(uint64_t id) const; + [[nodiscard]] std::vector> GetNodes() const; + [[nodiscard]] size_t GetNodesSize() const; + [[nodiscard]] std::shared_ptr GetNode(uint64_t id) const; - std::vector> GetWays() const; - size_t GetWaysSize() const; - std::shared_ptr GetWay(uint64_t id) const; + [[nodiscard]] std::vector> GetWays() const; + [[nodiscard]] size_t GetWaysSize() const; + [[nodiscard]] std::shared_ptr GetWay(uint64_t id) const; - std::vector> GetRelations() const; - size_t GetRelationsSize() const; - std::shared_ptr GetRelation(uint64_t id) const; + [[nodiscard]] std::vector> GetRelations() const; + [[nodiscard]] size_t GetRelationsSize() const; + [[nodiscard]] std::shared_ptr GetRelation(uint64_t id) const; public: const std::string version; diff --git a/lib/osmparser/include/osmrelation.hpp b/lib/osmparser/include/osmrelation.hpp index c0272a2..f489ea8 100644 --- a/lib/osmparser/include/osmrelation.hpp +++ b/lib/osmparser/include/osmrelation.hpp @@ -21,17 +21,17 @@ namespace osmp public: Relation(const tinyxml2::XMLElement* xml, Object* parent); - std::string GetRelationType(); + [[nodiscard]] std::string GetRelationType(); - const std::vector& GetNodes() const; - size_t GetNodesSize() const; - const Member& GetNode(size_t index) const; + [[nodiscard]] const std::vector& GetNodes() const; + [[nodiscard]] size_t GetNodesSize() const; + [[nodiscard]] const Member& GetNode(size_t index) const; - const std::vector& GetWays() const; - size_t GetWaysSize() const; - const Member& GetWay(size_t index) const; + [[nodiscard]] const std::vector& GetWays() const; + [[nodiscard]] size_t GetWaysSize() const; + [[nodiscard]] const Member& GetWay(size_t index) const; - bool HasNullMembers() const { return hasNullMembers; } + [[nodiscard]] bool HasNullMembers() const { return hasNullMembers; } private: std::string relationType; diff --git a/lib/osmparser/include/osmway.hpp b/lib/osmparser/include/osmway.hpp index 2813075..634a758 100644 --- a/lib/osmparser/include/osmway.hpp +++ b/lib/osmparser/include/osmway.hpp @@ -16,9 +16,9 @@ namespace osmp public: Way(const tinyxml2::XMLElement* way_elem, Object* parent); - const std::vector>& GetNodes() const; - size_t GetNodesSize() const; - const std::shared_ptr& GetNode(size_t index) const; + [[nodiscard]] const std::vector>& GetNodes() const; + [[nodiscard]] size_t GetNodesSize() const; + [[nodiscard]] const std::shared_ptr& GetNode(size_t index) const; public: bool area, closed; // Closed := Startpoint = endpoint, Area := Closed AND certain conditions are not met diff --git a/lib/osmparser/include/util.hpp b/lib/osmparser/include/util.hpp index 403d8e4..2482127 100644 --- a/lib/osmparser/include/util.hpp +++ b/lib/osmparser/include/util.hpp @@ -14,8 +14,8 @@ namespace osmp double minlat, minlon, maxlat, maxlon; } Bounds; - std::string GetSafeAttributeString(const tinyxml2::XMLElement* elem, const std::string& name); - double GetSafeAttributeFloat(const tinyxml2::XMLElement* elem, const std::string& name); - uint64_t GetSafeAttributeUint64(const tinyxml2::XMLElement* elem, const std::string& name); - bool GetSafeAttributeBool(const tinyxml2::XMLElement* elem, const std::string& name); + [[nodiscard]] std::string GetSafeAttributeString(const tinyxml2::XMLElement* elem, const std::string& name); + [[nodiscard]] double GetSafeAttributeFloat(const tinyxml2::XMLElement* elem, const std::string& name); + [[nodiscard]] uint64_t GetSafeAttributeUint64(const tinyxml2::XMLElement* elem, const std::string& name); + [[nodiscard]] bool GetSafeAttributeBool(const tinyxml2::XMLElement* elem, const std::string& name); } \ No newline at end of file diff --git a/src/multipolygon.cpp b/src/multipolygon.cpp index a6becce..460e0f6 100644 --- a/src/multipolygon.cpp +++ b/src/multipolygon.cpp @@ -18,256 +18,95 @@ struct TriangulationData { std::vector segments; }; +struct Ring { + std::vector members; + int ring; +}; + // Map values from one interval [A, B] to another [a, b] inline double Map(double A, double B, double a, double b, double x) { return (x - A) * (b - a) / (B - A) + a; } +// TODO: Implement better algorithm +bool SelfIntersecting(const Ring & ring) +{ + struct Segment { + std::shared_ptr p1, p2; + }; + + // Get all segments + std::vector segments; + for (const osmp::Relation::Member member : ring.members) + { + std::vector> nodes = std::dynamic_pointer_cast(member.member)->GetNodes(); + for (auto it = nodes.begin(); it != nodes.end() - 1; it++) + { + segments.push_back({ + *it, *(it + 1) + }); + } + } + + // Check for self intersection (O(n^2)...) + for (auto it = segments.begin(); it != segments.end(); it++) + { + for (auto jt = segments.begin(); jt != segments.end(); jt++) + { + if (it == jt) continue; + + double A1 = (it->p1->lat - it->p2->lat) / (it->p1->lon - it->p2->lon); + double A2 = (jt->p1->lat - jt->p2->lat) / (jt->p1->lon - jt->p2->lon); + if (A1 == A2) // Parallel + continue; + + double b1 = it->p1->lat - A1 * it->p1->lon; + double b2 = jt->p1->lat - A2 * jt->p1->lon; + + double Xa = (b2 - b1) / (A1 - A2); + double Ya = A1 * Xa + b1; + + if ((Xa < std::max(std::min(it->p1->lon, it->p2->lon), std::min(jt->p1->lon, jt->p2->lon))) || + (Xa > std::min(std::max(it->p1->lon, it->p2->lon), std::max(jt->p1->lon, jt->p2->lon)))) + continue; + else + return true; + } + } + + return false; +} + Multipolygon::Multipolygon(const std::shared_ptr& relation, int width, int height, osmp::Bounds bounds) : r(255), g(0), b(255), visible(true), rendering(RenderType::FILL), id(relation->id) { if (relation->HasNullMembers()) return; - // BREAKIF(7344428); - // BREAKIF(6427823); + const std::vector& members = relation->GetWays(); - std::vector data; + // Implement https://wiki.openstreetmap.org/wiki/Relation:multipolygon/Algorithm + // Ring assignment - std::vector ways = relation->GetWays(); - std::vector> nodes; - int run = 1; + // RA-1 + std::vector rings; + int ringCount = 0; - bool lastWasInner = false; - bool hasSeenOuter = false; - std::vector> outerWays; - std::vector> innerWays; - // Pre processing - for (osmp::Relation::Member member : ways) { - std::shared_ptr way = std::dynamic_pointer_cast(member.member); - if (member.role == "inner") + // RA-2 + rings.push_back({ {members[0]}, ringCount }); + + // RA-3 + if (rings[ringCount].members.front().member == rings[ringCount].members.back().member) + { + if (SelfIntersecting(rings[ringCount])) { - if (!hasSeenOuter) // TODO: Find better way to sort things - continue; - - if (innerWays.empty() || !lastWasInner) - innerWays.push_back({}); - - innerWays.back().push_back(member); - lastWasInner = true; - } - else - { - hasSeenOuter = true; - if (outerWays.empty() || lastWasInner) - outerWays.push_back({}); - - outerWays.back().push_back(member); - lastWasInner = false; + // Backtracking ?? } } - - if (outerWays.empty()) // There must always be an outer ring, anything else makes no sense - return; - - auto jt = outerWays.begin(); - bool currentIsInner = false; - while (!outerWays.empty() || !innerWays.empty()) + else // RA-4 { - std::vector member = *jt; - auto it = member.begin(); - while (!member.empty()) - { - if (it == member.end()) - it = member.begin(); - std::shared_ptr way = std::dynamic_pointer_cast(it->member); - // Several possible scenarios: - // Closed way - // Outer edge - // Append all nodes to the triangulation data - // Inner edge - // Append all nodes to the triangulation data - // Calculate average of nodes to get coordinates of the hole - // - // Open way - // Read next way until way is closed. This MUST happen, if the way remains open the OSM data is faulty and should be discarded - // Continue with Closed way algorithm - - bool inner = (it->role == "inner"); - std::vector> wayNodes = way->GetNodes(); - - if (run == 1) { - nodes.insert(nodes.begin(), wayNodes.begin(), wayNodes.end()); - } - else { - if (nodes.back() == wayNodes.front()) { - nodes.insert(nodes.end(), wayNodes.begin() + 1, wayNodes.end()); - } - else if (nodes.back() == wayNodes.back()) { - nodes.insert(nodes.end(), wayNodes.rbegin() + 1, wayNodes.rend()); - } - else if (nodes.front() == wayNodes.back()) { - nodes.insert(nodes.begin(), wayNodes.begin(), wayNodes.end() - 1); - } - else if (nodes.front() == wayNodes.front()) { - nodes.insert(nodes.begin(), wayNodes.rbegin(), wayNodes.rend() - 1); - } - else { - it++; - continue; - } - } - - it = member.erase(it); - - run++; - - if (!(way->closed)) { - if (nodes.size() > 1 && nodes.front() == nodes.back()) - { - // nodes.pop_back(); - } - else - { - continue; - } - } - - nodes.pop_back(); - - if (!inner || data.empty()) - { - data.push_back({}); - } - TriangulationData& td = data.back(); - - // Push all vertices to data - std::vector vertices; - std::map duplicates; - int n = td.vertices.size() / 2; - for (const std::shared_ptr& node : nodes) { - double x = Map(bounds.minlon, bounds.maxlon, 0, width, node->lon); - double y = height - Map(bounds.minlat, bounds.maxlat, 0, height, node->lat); - - auto xit = std::find(td.vertices.begin(), td.vertices.end(), x); - auto yit = std::find(td.vertices.begin(), td.vertices.end(), y); - if (std::distance(xit, yit) == 1) { - duplicates.insert(std::make_pair(n, std::distance(td.vertices.begin(), xit) / 2)); - } - else { - vertices.push_back(x); - vertices.push_back(y); - } - n++; - } - - if (inner) - { - // Calculate data of hole by using the average position of all inner vertices (that should work right?, probably not...) - REAL holeX = 0.0f; - REAL holeY = 0.0f;; - for (int i = 0; i < vertices.size(); i += 2) - { - holeX += vertices[i]; - holeY += vertices[i + 1]; - } - holeX /= (vertices.size() / 2); - holeY /= (vertices.size() / 2); - - td.holes.push_back(holeX); - td.holes.push_back(holeY); - } - - // Get segments - int segNum = td.vertices.size() / 2; - for (int i = 0; i < vertices.size(); i += 2) { - auto dit = duplicates.find(segNum); - if (dit != duplicates.end()) - { - td.segments.push_back(dit->second); - } - else - { - td.segments.push_back(segNum++); - } - - dit = duplicates.find(segNum); - if (dit != duplicates.end()) - { - td.segments.push_back(dit->second); - } - else - { - td.segments.push_back(segNum); - } - } - td.segments.back() = td.vertices.size() / 2; - - td.vertices.insert(td.vertices.end(), vertices.begin(), vertices.end()); - nodes.clear(); - run = 1; - } - - if (currentIsInner) { - innerWays.erase(innerWays.begin()); - jt = outerWays.begin(); - } - else { - outerWays.erase(outerWays.begin()); - jt = innerWays.begin(); - } - - currentIsInner = !currentIsInner; - } - - char* triswitches = "zpNBQ"; - for (TriangulationData& td : data) - { - triangulateio in; - - in.numberofpoints = td.vertices.size() / 2; - in.pointlist = td.vertices.data(); - in.pointmarkerlist = NULL; - - in.numberofpointattributes = 0; - in.numberofpointattributes = NULL; - - in.numberofholes = td.holes.size() / 2; - in.holelist = td.holes.data(); - - in.numberofsegments = td.segments.size() / 2; - in.segmentlist = td.segments.data(); - in.segmentmarkerlist = NULL; - - in.numberofregions = 0; - in.regionlist = NULL; - - triangulateio out; - out.pointlist = NULL; - out.pointmarkerlist = NULL; - out.trianglelist = NULL; - out.segmentlist = NULL; - out.segmentmarkerlist = NULL; - - triangulate(triswitches, &in, &out, NULL); - - // TODO: memory leak go brrrr - polygons.push_back({}); - for (int i = 0; i < in.numberofpoints * 2; i += 2) { - polygons.back().vertices.push_back({ in.pointlist[i], in.pointlist[i + 1] }); - // polygons.back().vertices.push_back(in.pointlist[i + 1]); - } - for (int i = 0; i < out.numberoftriangles * 3; i++) { - polygons.back().indices.push_back(out.trianglelist[i]); - } - for (int i = 0; i < in.numberofsegments * 2; i++) { - polygons.back().segments.push_back(in.segmentlist[i]); - } - - trifree(out.trianglelist); - trifree(out.segmentlist); } From 569812c0a57a8e44cabf2afd6d6c715deec05e7e Mon Sep 17 00:00:00 2001 From: Robert Date: Sun, 18 Apr 2021 17:34:00 +0200 Subject: [PATCH 2/8] Refactored osmp --- include/multipolygon.hpp | 2 +- lib/osmparser/include/osmimember.hpp | 5 ++-- lib/osmparser/include/osmnode.hpp | 13 ++++++-- lib/osmparser/include/osmobject.hpp | 22 ++++++-------- lib/osmparser/include/osmrelation.hpp | 43 ++++++++++++++++++--------- lib/osmparser/include/osmtag.hpp | 2 ++ lib/osmparser/include/osmway.hpp | 18 +++++++---- lib/osmparser/include/util.hpp | 14 +++++++++ lib/osmparser/src/osmnode.cpp | 16 +++++++++- lib/osmparser/src/osmobject.cpp | 36 +++++++++++----------- lib/osmparser/src/osmrelation.cpp | 41 ++++++++++++++++--------- lib/osmparser/src/osmway.cpp | 21 ++++++++++--- src/main.cpp | 16 +++++----- src/multipolygon.cpp | 14 ++++----- 14 files changed, 171 insertions(+), 92 deletions(-) diff --git a/include/multipolygon.hpp b/include/multipolygon.hpp index 654e543..c86a836 100644 --- a/include/multipolygon.hpp +++ b/include/multipolygon.hpp @@ -10,7 +10,7 @@ struct SDL_Renderer; class Multipolygon { public: - Multipolygon(const std::shared_ptr& relation, int width, int height, osmp::Bounds bounds); + Multipolygon(const osmp::Relation& relation, int width, int height, const osmp::Bounds& bounds); void SetColor(int r, int g, int b); void Draw(SDL_Renderer* renderer); diff --git a/lib/osmparser/include/osmimember.hpp b/lib/osmparser/include/osmimember.hpp index cc92650..b9846d9 100644 --- a/lib/osmparser/include/osmimember.hpp +++ b/lib/osmparser/include/osmimember.hpp @@ -24,7 +24,7 @@ namespace osmp [[nodiscard]] IMember::Type GetType() const; - [[nodiscard]] const std::vector& GetTags() const; + [[nodiscard]] const TagList& GetTags() const; [[nodiscard]] size_t GetTagsSize() const; [[nodiscard]] const Tag& GetTag(size_t index) const; [[nodiscard]] std::string GetTag(const std::string& key) const; @@ -36,8 +36,7 @@ namespace osmp IMember::Type type; Object* parent; - std::vector tags; - // std::map tags; + TagList tags; public: uint64_t id; diff --git a/lib/osmparser/include/osmnode.hpp b/lib/osmparser/include/osmnode.hpp index 76d7627..52a538e 100644 --- a/lib/osmparser/include/osmnode.hpp +++ b/lib/osmparser/include/osmnode.hpp @@ -1,7 +1,7 @@ #pragma once #include -#include "util.hpp" +#include #include #include @@ -9,10 +9,17 @@ namespace osmp { class Object; - class Node : public IMember + class INode : public IMember { public: - Node(const tinyxml2::XMLElement* xml, Object* parent); + INode(const INode& other) = delete; + INode(const INode&& other) = delete; + virtual ~INode() {} + + friend Node CreateNode(const tinyxml2::XMLElement* element, Object* parent); + + protected: + INode(const tinyxml2::XMLElement* xml, Object* parent); public: double lat, lon; diff --git a/lib/osmparser/include/osmobject.hpp b/lib/osmparser/include/osmobject.hpp index b8421fe..7cb02c6 100644 --- a/lib/osmparser/include/osmobject.hpp +++ b/lib/osmparser/include/osmobject.hpp @@ -8,27 +8,23 @@ namespace osmp { - class Node; - class Way; - class Relation; - class Object { public: explicit Object(const std::string& file); ~Object(); - [[nodiscard]] std::vector> GetNodes() const; + [[nodiscard]] Nodes GetNodes() const; [[nodiscard]] size_t GetNodesSize() const; - [[nodiscard]] std::shared_ptr GetNode(uint64_t id) const; + [[nodiscard]] Node GetNode(uint64_t id) const; - [[nodiscard]] std::vector> GetWays() const; + [[nodiscard]] Ways GetWays() const; [[nodiscard]] size_t GetWaysSize() const; - [[nodiscard]] std::shared_ptr GetWay(uint64_t id) const; + [[nodiscard]] Way GetWay(uint64_t id) const; - [[nodiscard]] std::vector> GetRelations() const; + [[nodiscard]] Relations GetRelations() const; [[nodiscard]] size_t GetRelationsSize() const; - [[nodiscard]] std::shared_ptr GetRelation(uint64_t id) const; + [[nodiscard]] Relation GetRelation(uint64_t id) const; public: const std::string version; @@ -37,8 +33,8 @@ namespace osmp Bounds bounds; private: - std::map> nodes; - std::map> ways; - std::map> relations; + std::map nodes; + std::map ways; + std::map relations; }; } \ No newline at end of file diff --git a/lib/osmparser/include/osmrelation.hpp b/lib/osmparser/include/osmrelation.hpp index f489ea8..e270a31 100644 --- a/lib/osmparser/include/osmrelation.hpp +++ b/lib/osmparser/include/osmrelation.hpp @@ -9,35 +9,50 @@ namespace osmp { class Object; + class IMember; - class Relation : public IMember + typedef struct sMemberNode { + Node node; + std::string role; + } MemberNode; + + typedef struct sMemberWay { + Way way; + std::string role; + } MemberWay; + + typedef std::vector MemberNodes; + typedef std::vector MemberWays; + + class IRelation : public IMember { public: - typedef struct sMember { - std::shared_ptr member; - std::string role; - } Member; + IRelation(const IRelation& other) = delete; + IRelation(const IRelation&& other) = delete; + virtual ~IRelation() {} - public: - Relation(const tinyxml2::XMLElement* xml, Object* parent); + friend Relation CreateRelation(const tinyxml2::XMLElement* xml, Object* parent); - [[nodiscard]] std::string GetRelationType(); + [[nodiscard]] std::string GetRelationType() const; - [[nodiscard]] const std::vector& GetNodes() const; + [[nodiscard]] const MemberNodes& GetNodes() const; [[nodiscard]] size_t GetNodesSize() const; - [[nodiscard]] const Member& GetNode(size_t index) const; + [[nodiscard]] const MemberNode& GetNode(size_t index) const; - [[nodiscard]] const std::vector& GetWays() const; + [[nodiscard]] const MemberWays& GetWays() const; [[nodiscard]] size_t GetWaysSize() const; - [[nodiscard]] const Member& GetWay(size_t index) const; + [[nodiscard]] const MemberWay& GetWay(size_t index) const; [[nodiscard]] bool HasNullMembers() const { return hasNullMembers; } + protected: + IRelation(const tinyxml2::XMLElement* xml, Object* parent); + private: std::string relationType; bool hasNullMembers; - std::vector nodes; - std::vector ways; + MemberNodes nodes; + MemberWays ways; }; } \ No newline at end of file diff --git a/lib/osmparser/include/osmtag.hpp b/lib/osmparser/include/osmtag.hpp index a4e1f22..cdfb098 100644 --- a/lib/osmparser/include/osmtag.hpp +++ b/lib/osmparser/include/osmtag.hpp @@ -33,4 +33,6 @@ namespace osmp std::string k; // TODO: Should/could be an enum std::string v; } Tag; + + typedef std::vector TagList; } diff --git a/lib/osmparser/include/osmway.hpp b/lib/osmparser/include/osmway.hpp index 634a758..66110f5 100644 --- a/lib/osmparser/include/osmway.hpp +++ b/lib/osmparser/include/osmway.hpp @@ -9,21 +9,27 @@ namespace osmp { class Object; - class Node; - class Way : public IMember + class IWay : public IMember { public: - Way(const tinyxml2::XMLElement* way_elem, Object* parent); + IWay(const IWay& other) = delete; + IWay(const IWay&& other) = delete; + virtual ~IWay() {} - [[nodiscard]] const std::vector>& GetNodes() const; + friend Way CreateWay(const tinyxml2::XMLElement* way_elem, Object* parent); + + [[nodiscard]] const Nodes& GetNodes() const; [[nodiscard]] size_t GetNodesSize() const; - [[nodiscard]] const std::shared_ptr& GetNode(size_t index) const; + [[nodiscard]] Node GetNode(size_t index) const; + + protected: + IWay(const tinyxml2::XMLElement* way_elem, Object* parent); public: bool area, closed; // Closed := Startpoint = endpoint, Area := Closed AND certain conditions are not met private: - std::vector> nodes; + Nodes nodes; }; } \ No newline at end of file diff --git a/lib/osmparser/include/util.hpp b/lib/osmparser/include/util.hpp index 2482127..bfcb169 100644 --- a/lib/osmparser/include/util.hpp +++ b/lib/osmparser/include/util.hpp @@ -1,6 +1,8 @@ #pragma once #include +#include +#include namespace tinyxml2 { @@ -9,6 +11,18 @@ namespace tinyxml2 namespace osmp { + class INode; + class IWay; + class IRelation; + + typedef std::shared_ptr Node; + typedef std::shared_ptr Way; + typedef std::shared_ptr Relation; + + typedef std::vector Nodes; + typedef std::vector Ways; + typedef std::vector Relations; + typedef struct sBounds { double minlat, minlon, maxlat, maxlon; diff --git a/lib/osmparser/src/osmnode.cpp b/lib/osmparser/src/osmnode.cpp index 41a0efa..3770645 100644 --- a/lib/osmparser/src/osmnode.cpp +++ b/lib/osmparser/src/osmnode.cpp @@ -6,11 +6,25 @@ namespace xml = tinyxml2; namespace osmp { - Node::Node(const tinyxml2::XMLElement* node_elem, Object* parent) : + INode::INode(const tinyxml2::XMLElement* node_elem, Object* parent) : IMember(node_elem, parent, IMember::Type::NODE) { // Get Attribute lat = GetSafeAttributeFloat(node_elem, "lat"); lon = GetSafeAttributeFloat(node_elem, "lon"); } + + + namespace { + struct ConcreteNode : public INode { + ConcreteNode(const tinyxml2::XMLElement* node_elem, Object* parent) : + INode(node_elem, parent) + {} + }; + } + + Node CreateNode(const tinyxml2::XMLElement* node_elem, Object* parent) + { + return std::make_shared(node_elem, parent); + } } \ No newline at end of file diff --git a/lib/osmparser/src/osmobject.cpp b/lib/osmparser/src/osmobject.cpp index fca53bb..45e0db8 100644 --- a/lib/osmparser/src/osmobject.cpp +++ b/lib/osmparser/src/osmobject.cpp @@ -39,7 +39,7 @@ namespace osmp xml::XMLElement* node_elem = root->FirstChildElement("node"); while (node_elem != nullptr) { - std::shared_ptr new_node = std::make_shared(node_elem, this); + Node new_node = CreateNode(node_elem, this); nodes.insert(std::make_pair(new_node->id, new_node)); node_elem = node_elem->NextSiblingElement("node"); @@ -49,7 +49,7 @@ namespace osmp xml::XMLElement* way_elem = root->FirstChildElement("way"); while (way_elem != nullptr) { - std::shared_ptr new_way = std::make_shared(way_elem, this); + Way new_way = CreateWay(way_elem, this); ways.insert(std::make_pair(new_way->id, new_way)); way_elem = way_elem->NextSiblingElement("way"); @@ -59,7 +59,7 @@ namespace osmp xml::XMLElement* relation_elem = root->FirstChildElement("relation"); while (relation_elem != nullptr) { - std::shared_ptr new_way = std::make_shared(relation_elem, this); + Relation new_way = CreateRelation(relation_elem, this); relations.insert(std::make_pair(new_way->id, new_way)); relation_elem = relation_elem->NextSiblingElement("relation"); @@ -71,10 +71,10 @@ namespace osmp } - std::vector> Object::GetNodes() const + Nodes Object::GetNodes() const { - std::vector> vecNodes; - for (std::map>::const_iterator it = nodes.begin(); it != nodes.end(); it++) + Nodes vecNodes; + for (std::map::const_iterator it = nodes.begin(); it != nodes.end(); it++) vecNodes.push_back(it->second); return vecNodes; @@ -85,19 +85,19 @@ namespace osmp return nodes.size(); } - std::shared_ptr Object::GetNode(uint64_t id) const + Node Object::GetNode(uint64_t id) const { - std::map>::const_iterator node = nodes.find(id); + std::map::const_iterator node = nodes.find(id); if (node != nodes.end()) return node->second; return nullptr; } - std::vector> Object::GetWays() const + Ways Object::GetWays() const { - std::vector> vecWays; - for (std::map>::const_iterator it = ways.begin(); it != ways.end(); it++) + Ways vecWays; + for (std::map::const_iterator it = ways.begin(); it != ways.end(); it++) vecWays.push_back(it->second); return vecWays; @@ -108,19 +108,19 @@ namespace osmp return ways.size(); } - std::shared_ptr Object::GetWay(uint64_t id) const + Way Object::GetWay(uint64_t id) const { - std::map>::const_iterator way = ways.find(id); + std::map::const_iterator way = ways.find(id); if (way != ways.end()) return way->second; return nullptr; } - std::vector> Object::GetRelations() const + Relations Object::GetRelations() const { - std::vector> vecRelations; - for (std::map>::const_iterator it = relations.begin(); it != relations.end(); it++) + Relations vecRelations; + for (std::map::const_iterator it = relations.begin(); it != relations.end(); it++) vecRelations.push_back(it->second); return vecRelations; @@ -131,9 +131,9 @@ namespace osmp return relations.size(); } - std::shared_ptr Object::GetRelation(uint64_t id) const + Relation Object::GetRelation(uint64_t id) const { - std::map>::const_iterator relation = relations.find(id); + std::map::const_iterator relation = relations.find(id); if (relation != relations.end()) return relation->second; diff --git a/lib/osmparser/src/osmrelation.cpp b/lib/osmparser/src/osmrelation.cpp index 87320e7..0e8f7c0 100644 --- a/lib/osmparser/src/osmrelation.cpp +++ b/lib/osmparser/src/osmrelation.cpp @@ -1,3 +1,4 @@ +#include "..\include\osmrelation.hpp" #include #include @@ -11,7 +12,7 @@ namespace xml = tinyxml2; namespace osmp { - Relation::Relation(const xml::XMLElement* xml, Object* parent) : + IRelation::IRelation(const xml::XMLElement* xml, Object* parent) : IMember(xml, parent, IMember::Type::RELATION), hasNullMembers(false) { const xml::XMLElement* member_element = xml->FirstChildElement("member"); @@ -21,54 +22,66 @@ namespace osmp uint64_t ref = GetSafeAttributeUint64(member_element, "ref"); std::string role = GetSafeAttributeString(member_element, "role"); - std::shared_ptr member = nullptr; if (memberType == "node") { - member = parent->GetNode(ref); - nodes.push_back({ member, role }); + Node node = parent->GetNode(ref); + nodes.push_back({ node, role }); } else if (memberType == "way") { - member = parent->GetWay(ref); - if (member == nullptr) { + Way way = parent->GetWay(ref); + if (way == nullptr) { hasNullMembers = true; } - ways.push_back({ member, role }); + ways.push_back({ way, role }); } member_element = member_element->NextSiblingElement("member"); } } - std::string Relation::GetRelationType() + namespace { + struct ConcreteRelation : public IRelation { + ConcreteRelation(const tinyxml2::XMLElement* way_elem, Object* parent) : + IRelation(way_elem, parent) + {} + }; + } + + Relation CreateRelation(const tinyxml2::XMLElement* xml, Object* parent) + { + return std::make_shared(xml, parent); + } + + std::string IRelation::GetRelationType() const { return GetTag("type"); } - const std::vector& Relation::GetNodes() const + const MemberNodes& IRelation::GetNodes() const { return nodes; } - size_t Relation::GetNodesSize() const + size_t IRelation::GetNodesSize() const { return nodes.size(); } - const Relation::Member& Relation::GetNode(size_t index) const + const MemberNode& IRelation::GetNode(size_t index) const { return nodes[index]; } - const std::vector& Relation::GetWays() const + const MemberWays& IRelation::GetWays() const { return ways; } - size_t Relation::GetWaysSize() const + size_t IRelation::GetWaysSize() const { return ways.size(); } - const Relation::Member& Relation::GetWay(size_t index) const + const MemberWay& IRelation::GetWay(size_t index) const { return ways[index]; } diff --git a/lib/osmparser/src/osmway.cpp b/lib/osmparser/src/osmway.cpp index 524d9f6..0325966 100644 --- a/lib/osmparser/src/osmway.cpp +++ b/lib/osmparser/src/osmway.cpp @@ -10,7 +10,7 @@ namespace xml = tinyxml2; namespace osmp { - Way::Way(const tinyxml2::XMLElement* way_elem, Object* parent) : + IWay::IWay(const tinyxml2::XMLElement* way_elem, Object* parent) : IMember(way_elem, parent, IMember::Type::WAY) { area = GetSafeAttributeBool(way_elem, "area"); @@ -35,17 +35,30 @@ namespace osmp } } - const std::vector>& Way::GetNodes() const + namespace { + struct ConcreteWay : public IWay { + ConcreteWay(const tinyxml2::XMLElement* way_elem, Object* parent) : + IWay(way_elem, parent) + {} + }; + } + + Way CreateWay(const tinyxml2::XMLElement* way_elem, Object* parent) + { + return std::make_shared(way_elem, parent); + } + + const Nodes& IWay::GetNodes() const { return nodes; } - size_t Way::GetNodesSize() const + size_t IWay::GetNodesSize() const { return nodes.size(); } - const std::shared_ptr& Way::GetNode(size_t index) const + Node IWay::GetNode(size_t index) const { return nodes[index]; } diff --git a/src/main.cpp b/src/main.cpp index 1dba678..db31917 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -44,14 +44,14 @@ int main(int argc, char** argv) int windowWidth = windowHeight * aspectRatio; // Fetch all the ways - std::vector> ways = obj->GetWays(); + osmp::Ways ways = obj->GetWays(); // Turn them into renderable ways by mapping the global coordinates to screen coordinates (do this smarter in the future pls) std::vector buildings; std::vector highways; - for (std::shared_ptr way : ways) + for (osmp::Way way : ways) { - const std::vector>& nodes = way->GetNodes(); + const osmp::Nodes& nodes = way->GetNodes(); std::string highwayVal = way->GetTag("highway"); std::string railwayVal = way->GetTag("railway"); if (way->area) @@ -119,9 +119,9 @@ int main(int argc, char** argv) } // Fetch all relations - std::vector> relations = obj->GetRelations(); + osmp::Relations relations = obj->GetRelations(); std::vector multipolygons; - for (const std::shared_ptr& relation : relations) + for (const osmp::Relation& relation : relations) { if (relation->GetRelationType() == "multipolygon" && !relation->HasNullMembers()) { @@ -174,9 +174,9 @@ int main(int argc, char** argv) SDL_SetRenderDrawColor(renderer, 240, 240, 250, 255); SDL_RenderClear(renderer); - for (Multipolygon& multipolygon : multipolygons) { - multipolygon.Draw(renderer); - } + // for (Multipolygon& multipolygon : multipolygons) { + // multipolygon.Draw(renderer); + // } //for (Area& area : buildings) //{ diff --git a/src/multipolygon.cpp b/src/multipolygon.cpp index 460e0f6..6bcb6ca 100644 --- a/src/multipolygon.cpp +++ b/src/multipolygon.cpp @@ -19,7 +19,7 @@ struct TriangulationData { }; struct Ring { - std::vector members; + osmp::MemberWays ways; int ring; }; @@ -33,14 +33,14 @@ inline double Map(double A, double B, double a, double b, double x) bool SelfIntersecting(const Ring & ring) { struct Segment { - std::shared_ptr p1, p2; + osmp::Node p1, p2; }; // Get all segments std::vector segments; - for (const osmp::Relation::Member member : ring.members) + for (const osmp::MemberWay way : ring.ways) { - std::vector> nodes = std::dynamic_pointer_cast(member.member)->GetNodes(); + osmp::Nodes nodes = way.way->GetNodes(); for (auto it = nodes.begin(); it != nodes.end() - 1; it++) { segments.push_back({ @@ -78,13 +78,13 @@ bool SelfIntersecting(const Ring & ring) return false; } -Multipolygon::Multipolygon(const std::shared_ptr& relation, int width, int height, osmp::Bounds bounds) : +Multipolygon::Multipolygon(const osmp::Relation& relation, int width, int height, const osmp::Bounds& bounds) : r(255), g(0), b(255), visible(true), rendering(RenderType::FILL), id(relation->id) { if (relation->HasNullMembers()) return; - const std::vector& members = relation->GetWays(); + const osmp::MemberWays& members = relation->GetWays(); // Implement https://wiki.openstreetmap.org/wiki/Relation:multipolygon/Algorithm // Ring assignment @@ -97,7 +97,7 @@ Multipolygon::Multipolygon(const std::shared_ptr& relation, int rings.push_back({ {members[0]}, ringCount }); // RA-3 - if (rings[ringCount].members.front().member == rings[ringCount].members.back().member) + if (rings[ringCount].ways.front().way == rings[ringCount].ways.back().way) { if (SelfIntersecting(rings[ringCount])) { From 001e8e3abac5c795246167c4412f245d6e85d9a6 Mon Sep 17 00:00:00 2001 From: Robert Date: Sun, 18 Apr 2021 17:58:56 +0200 Subject: [PATCH 3/8] deleting osmp --- lib/osmparser/CMakeLists.txt | 26 ----- lib/osmparser/include/osmimember.hpp | 50 --------- lib/osmparser/include/osmnode.hpp | 27 ----- lib/osmparser/include/osmobject.hpp | 40 -------- lib/osmparser/include/osmp.hpp | 8 -- lib/osmparser/include/osmrelation.hpp | 58 ----------- lib/osmparser/include/osmtag.hpp | 38 ------- lib/osmparser/include/osmway.hpp | 35 ------- lib/osmparser/include/util.hpp | 35 ------- lib/osmparser/src/osmimember.cpp | 66 ------------ lib/osmparser/src/osmnode.cpp | 30 ------ lib/osmparser/src/osmobject.cpp | 142 -------------------------- lib/osmparser/src/osmrelation.cpp | 88 ---------------- lib/osmparser/src/osmway.cpp | 65 ------------ lib/osmparser/src/util.cpp | 49 --------- 15 files changed, 757 deletions(-) delete mode 100644 lib/osmparser/CMakeLists.txt delete mode 100644 lib/osmparser/include/osmimember.hpp delete mode 100644 lib/osmparser/include/osmnode.hpp delete mode 100644 lib/osmparser/include/osmobject.hpp delete mode 100644 lib/osmparser/include/osmp.hpp delete mode 100644 lib/osmparser/include/osmrelation.hpp delete mode 100644 lib/osmparser/include/osmtag.hpp delete mode 100644 lib/osmparser/include/osmway.hpp delete mode 100644 lib/osmparser/include/util.hpp delete mode 100644 lib/osmparser/src/osmimember.cpp delete mode 100644 lib/osmparser/src/osmnode.cpp delete mode 100644 lib/osmparser/src/osmobject.cpp delete mode 100644 lib/osmparser/src/osmrelation.cpp delete mode 100644 lib/osmparser/src/osmway.cpp delete mode 100644 lib/osmparser/src/util.cpp diff --git a/lib/osmparser/CMakeLists.txt b/lib/osmparser/CMakeLists.txt deleted file mode 100644 index e8bf4ac..0000000 --- a/lib/osmparser/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -cmake_minimum_required(VERSION 3.10) - -find_package(tinyxml2 CONFIG REQUIRED) - -file(GLOB_RECURSE CPP_FILES - "src/*.cpp" -) - -file(GLOB_RECURSE HPP_FILES - "include/*.hpp" -) - -get_target_property(TINYXML2_INCLUDE_DIR tinyxml2::tinyxml2 INTERFACE_INCLUDE_DIRECTORIES) - -add_library(osmp STATIC - ${CPP_FILES} -) - -target_include_directories(osmp PUBLIC - include - ${TINYXML2_INCLUDE_DIR} -) - -target_link_libraries(osmp PRIVATE - tinyxml2::tinyxml2 -) \ No newline at end of file diff --git a/lib/osmparser/include/osmimember.hpp b/lib/osmparser/include/osmimember.hpp deleted file mode 100644 index b9846d9..0000000 --- a/lib/osmparser/include/osmimember.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -#include -#include -#include - -#include -#include - -namespace osmp -{ - class Object; - - class IMember - { - public: - enum class Type { - NODE, WAY, RELATION - }; - - public: - IMember(const IMember& other) = delete; - virtual ~IMember() {} - - [[nodiscard]] IMember::Type GetType() const; - - [[nodiscard]] const TagList& GetTags() const; - [[nodiscard]] size_t GetTagsSize() const; - [[nodiscard]] const Tag& GetTag(size_t index) const; - [[nodiscard]] std::string GetTag(const std::string& key) const; - - protected: - IMember(const tinyxml2::XMLElement* element, Object* parent, IMember::Type type); - - protected: - IMember::Type type; - Object* parent; - - TagList tags; - - public: - uint64_t id; - std::string user; - unsigned int uid; - bool visible; - std::string version; - unsigned int changeset; - std::string timestamp; - }; -} \ No newline at end of file diff --git a/lib/osmparser/include/osmnode.hpp b/lib/osmparser/include/osmnode.hpp deleted file mode 100644 index 52a538e..0000000 --- a/lib/osmparser/include/osmnode.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once -#include - -#include -#include -#include - -namespace osmp -{ - class Object; - - class INode : public IMember - { - public: - INode(const INode& other) = delete; - INode(const INode&& other) = delete; - virtual ~INode() {} - - friend Node CreateNode(const tinyxml2::XMLElement* element, Object* parent); - - protected: - INode(const tinyxml2::XMLElement* xml, Object* parent); - - public: - double lat, lon; - }; -} \ No newline at end of file diff --git a/lib/osmparser/include/osmobject.hpp b/lib/osmparser/include/osmobject.hpp deleted file mode 100644 index 7cb02c6..0000000 --- a/lib/osmparser/include/osmobject.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once -#include -#include -#include -#include - -#include - -namespace osmp -{ - class Object - { - public: - explicit Object(const std::string& file); - ~Object(); - - [[nodiscard]] Nodes GetNodes() const; - [[nodiscard]] size_t GetNodesSize() const; - [[nodiscard]] Node GetNode(uint64_t id) const; - - [[nodiscard]] Ways GetWays() const; - [[nodiscard]] size_t GetWaysSize() const; - [[nodiscard]] Way GetWay(uint64_t id) const; - - [[nodiscard]] Relations GetRelations() const; - [[nodiscard]] size_t GetRelationsSize() const; - [[nodiscard]] Relation GetRelation(uint64_t id) const; - - public: - const std::string version; - const std::string generator; - - Bounds bounds; - - private: - std::map nodes; - std::map ways; - std::map relations; - }; -} \ No newline at end of file diff --git a/lib/osmparser/include/osmp.hpp b/lib/osmparser/include/osmp.hpp deleted file mode 100644 index a0ea337..0000000 --- a/lib/osmparser/include/osmp.hpp +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include \ No newline at end of file diff --git a/lib/osmparser/include/osmrelation.hpp b/lib/osmparser/include/osmrelation.hpp deleted file mode 100644 index e270a31..0000000 --- a/lib/osmparser/include/osmrelation.hpp +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once -#include -#include - -#include -#include -#include - -namespace osmp -{ - class Object; - class IMember; - - typedef struct sMemberNode { - Node node; - std::string role; - } MemberNode; - - typedef struct sMemberWay { - Way way; - std::string role; - } MemberWay; - - typedef std::vector MemberNodes; - typedef std::vector MemberWays; - - class IRelation : public IMember - { - public: - IRelation(const IRelation& other) = delete; - IRelation(const IRelation&& other) = delete; - virtual ~IRelation() {} - - friend Relation CreateRelation(const tinyxml2::XMLElement* xml, Object* parent); - - [[nodiscard]] std::string GetRelationType() const; - - [[nodiscard]] const MemberNodes& GetNodes() const; - [[nodiscard]] size_t GetNodesSize() const; - [[nodiscard]] const MemberNode& GetNode(size_t index) const; - - [[nodiscard]] const MemberWays& GetWays() const; - [[nodiscard]] size_t GetWaysSize() const; - [[nodiscard]] const MemberWay& GetWay(size_t index) const; - - [[nodiscard]] bool HasNullMembers() const { return hasNullMembers; } - - protected: - IRelation(const tinyxml2::XMLElement* xml, Object* parent); - - private: - std::string relationType; - bool hasNullMembers; - - MemberNodes nodes; - MemberWays ways; - }; -} \ No newline at end of file diff --git a/lib/osmparser/include/osmtag.hpp b/lib/osmparser/include/osmtag.hpp deleted file mode 100644 index cdfb098..0000000 --- a/lib/osmparser/include/osmtag.hpp +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include - -namespace osmp -{ - enum class TagKey { - NONE, - AERIALWAY, AEROWAY, AMENITY, BARRIER, BOUNDARY, - BUILDING, CRAFT, EMERGENCY, GEOLOGICAL, HEALTHCARE, - HIGHWAY, HISTORIC, LANDUSE, LEISURE, MANMADE, MILITARY, - NATURAL, OFFICE, PLACE, POWER, PUBLIC_TRANSPORT, - RAILWAY, ROUTE, SHOP, SPORT, TELECOM, TOURISM, WATER, WATERWAY - }; - - /* - enum class TagValue { - NONE, - - BUILDING_APARTMENTS, BUILDING_BUNGALOW, BUILDING_CABIN, BUILDING_DETACHED, BUILDING_DORMITORY, BUILDING_FARM, BUILDING_GER, - BUILDING_HOTEL, BUILDING_HOUSE, BUILDING_HOUSEBOAT, BUILDING_RESIDENTIAL, BUILDING_SEMIDETACHED_HOUSE, BUILDING_STATIC_CARAVAN, - BUILDING_TERRACE, BUILDING_COMMERCIAL, BUILDING_INDUSTRIAL, BUILDING_KIOSK, BUILDING_OFFICE, BUILDING_RETAIL, BUILDING_SUPERMARKET, - BUILDING_WAREHOUSE, BUILDING_CATHEDRAL, BUILDING_CHAPEL, BUILDING_CHURCH, BUILDING_MONASTERY, BUILDING_MOSQUE, BUILDING_PRESBYTERY, - BUILDING_RELIGIOUS, BUILDING_SHRINE, BUILDING_SYNAGOGUE, BUILDING_TEMPLE, BUILDING_BAKEHOUSE, BUILDING_CIVIC, BUILDING_FIRE_STATION, - BUILDING_GOVERNMENT, BUILDING_HOSPITAL, BUILDING_PUBLIC, BUILDING_TOILETS, BUILDING_TRAIN_STATION, BUILDING_TRANSPORTATION, - BUILDING_KINDERGARTEN, BUILDING_SCHOOL, BUILDING_UNIVERSITY - - }; - */ - - typedef struct sTag - { - std::string k; // TODO: Should/could be an enum - std::string v; - } Tag; - - typedef std::vector TagList; -} diff --git a/lib/osmparser/include/osmway.hpp b/lib/osmparser/include/osmway.hpp deleted file mode 100644 index 66110f5..0000000 --- a/lib/osmparser/include/osmway.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once -#include -#include - -#include -#include -#include - -namespace osmp -{ - class Object; - - class IWay : public IMember - { - public: - IWay(const IWay& other) = delete; - IWay(const IWay&& other) = delete; - virtual ~IWay() {} - - friend Way CreateWay(const tinyxml2::XMLElement* way_elem, Object* parent); - - [[nodiscard]] const Nodes& GetNodes() const; - [[nodiscard]] size_t GetNodesSize() const; - [[nodiscard]] Node GetNode(size_t index) const; - - protected: - IWay(const tinyxml2::XMLElement* way_elem, Object* parent); - - public: - bool area, closed; // Closed := Startpoint = endpoint, Area := Closed AND certain conditions are not met - - private: - Nodes nodes; - }; -} \ No newline at end of file diff --git a/lib/osmparser/include/util.hpp b/lib/osmparser/include/util.hpp deleted file mode 100644 index bfcb169..0000000 --- a/lib/osmparser/include/util.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace tinyxml2 -{ - class XMLElement; -} - -namespace osmp -{ - class INode; - class IWay; - class IRelation; - - typedef std::shared_ptr Node; - typedef std::shared_ptr Way; - typedef std::shared_ptr Relation; - - typedef std::vector Nodes; - typedef std::vector Ways; - typedef std::vector Relations; - - typedef struct sBounds - { - double minlat, minlon, maxlat, maxlon; - } Bounds; - - [[nodiscard]] std::string GetSafeAttributeString(const tinyxml2::XMLElement* elem, const std::string& name); - [[nodiscard]] double GetSafeAttributeFloat(const tinyxml2::XMLElement* elem, const std::string& name); - [[nodiscard]] uint64_t GetSafeAttributeUint64(const tinyxml2::XMLElement* elem, const std::string& name); - [[nodiscard]] bool GetSafeAttributeBool(const tinyxml2::XMLElement* elem, const std::string& name); -} \ No newline at end of file diff --git a/lib/osmparser/src/osmimember.cpp b/lib/osmparser/src/osmimember.cpp deleted file mode 100644 index e038607..0000000 --- a/lib/osmparser/src/osmimember.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include - -#include -#include - -namespace xml = tinyxml2; - -namespace osmp -{ - IMember::IMember(const xml::XMLElement* element, Object* parent, IMember::Type type) : - type(type), parent(parent) - { - // Get Attribute - id = GetSafeAttributeUint64(element, "id"); - user = GetSafeAttributeString(element, "user"); - uid = GetSafeAttributeUint64(element, "uid"); - visible = GetSafeAttributeBool(element, "visible"); - version = GetSafeAttributeString(element, "version"); - changeset = GetSafeAttributeUint64(element, "changeset"); - timestamp = GetSafeAttributeString(element, "timestamp"); - - const xml::XMLElement* tag_element = element->FirstChildElement("tag"); - while (tag_element != nullptr) - { - tags.push_back({ - GetSafeAttributeString(tag_element, "k"), - GetSafeAttributeString(tag_element, "v"), - }); - - tag_element = tag_element->NextSiblingElement("tag"); - } - } - - IMember::Type IMember::GetType() const - { - return type; - } - - const std::vector& IMember::GetTags() const - { - return tags; - } - - size_t IMember::GetTagsSize() const - { - return tags.size(); - } - - const Tag& IMember::GetTag(size_t index) const - { - return tags[index]; - } - - std::string IMember::GetTag(const std::string& key) const - { - for (const Tag& tag : tags) - { - if (tag.k == key) - { - return tag.v; - } - } - - return ""; - } -} diff --git a/lib/osmparser/src/osmnode.cpp b/lib/osmparser/src/osmnode.cpp deleted file mode 100644 index 3770645..0000000 --- a/lib/osmparser/src/osmnode.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include - -#include - -namespace xml = tinyxml2; - -namespace osmp -{ - INode::INode(const tinyxml2::XMLElement* node_elem, Object* parent) : - IMember(node_elem, parent, IMember::Type::NODE) - { - // Get Attribute - lat = GetSafeAttributeFloat(node_elem, "lat"); - lon = GetSafeAttributeFloat(node_elem, "lon"); - } - - - namespace { - struct ConcreteNode : public INode { - ConcreteNode(const tinyxml2::XMLElement* node_elem, Object* parent) : - INode(node_elem, parent) - {} - }; - } - - Node CreateNode(const tinyxml2::XMLElement* node_elem, Object* parent) - { - return std::make_shared(node_elem, parent); - } -} \ No newline at end of file diff --git a/lib/osmparser/src/osmobject.cpp b/lib/osmparser/src/osmobject.cpp deleted file mode 100644 index 45e0db8..0000000 --- a/lib/osmparser/src/osmobject.cpp +++ /dev/null @@ -1,142 +0,0 @@ -#include - -#include -#include - -#include - -#include -#include -#include - -namespace xml = tinyxml2; - -namespace osmp -{ - Object::Object(const std::string& file) : - bounds({ 0.0f, 0.0f, 0.0f, 0.0f }) - { - xml::XMLDocument doc; - xml::XMLError result = doc.LoadFile(file.c_str()); - if (result != xml::XML_SUCCESS) - { - std::cerr << "Error: " << result << std::endl; - return; - } - - xml::XMLElement* root = doc.FirstChildElement(); - - // Get bounds - xml::XMLElement* bounds_elem = root->FirstChildElement("bounds"); - bounds = { - GetSafeAttributeFloat(bounds_elem, "minlat"), - GetSafeAttributeFloat(bounds_elem, "minlon"), - GetSafeAttributeFloat(bounds_elem, "maxlat"), - GetSafeAttributeFloat(bounds_elem, "maxlon") - }; - - // Get nodes - xml::XMLElement* node_elem = root->FirstChildElement("node"); - while (node_elem != nullptr) - { - Node new_node = CreateNode(node_elem, this); - nodes.insert(std::make_pair(new_node->id, new_node)); - - node_elem = node_elem->NextSiblingElement("node"); - } - - // Get ways - xml::XMLElement* way_elem = root->FirstChildElement("way"); - while (way_elem != nullptr) - { - Way new_way = CreateWay(way_elem, this); - ways.insert(std::make_pair(new_way->id, new_way)); - - way_elem = way_elem->NextSiblingElement("way"); - } - - // Get relations - xml::XMLElement* relation_elem = root->FirstChildElement("relation"); - while (relation_elem != nullptr) - { - Relation new_way = CreateRelation(relation_elem, this); - relations.insert(std::make_pair(new_way->id, new_way)); - - relation_elem = relation_elem->NextSiblingElement("relation"); - } - } - - Object::~Object() - { - - } - - Nodes Object::GetNodes() const - { - Nodes vecNodes; - for (std::map::const_iterator it = nodes.begin(); it != nodes.end(); it++) - vecNodes.push_back(it->second); - - return vecNodes; - } - - size_t Object::GetNodesSize() const - { - return nodes.size(); - } - - Node Object::GetNode(uint64_t id) const - { - std::map::const_iterator node = nodes.find(id); - if (node != nodes.end()) - return node->second; - - return nullptr; - } - - Ways Object::GetWays() const - { - Ways vecWays; - for (std::map::const_iterator it = ways.begin(); it != ways.end(); it++) - vecWays.push_back(it->second); - - return vecWays; - } - - size_t Object::GetWaysSize() const - { - return ways.size(); - } - - Way Object::GetWay(uint64_t id) const - { - std::map::const_iterator way = ways.find(id); - if (way != ways.end()) - return way->second; - - return nullptr; - } - - Relations Object::GetRelations() const - { - Relations vecRelations; - for (std::map::const_iterator it = relations.begin(); it != relations.end(); it++) - vecRelations.push_back(it->second); - - return vecRelations; - } - - size_t Object::GetRelationsSize() const - { - return relations.size(); - } - - Relation Object::GetRelation(uint64_t id) const - { - std::map::const_iterator relation = relations.find(id); - if (relation != relations.end()) - return relation->second; - - return nullptr; - } -} \ No newline at end of file diff --git a/lib/osmparser/src/osmrelation.cpp b/lib/osmparser/src/osmrelation.cpp deleted file mode 100644 index 0e8f7c0..0000000 --- a/lib/osmparser/src/osmrelation.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "..\include\osmrelation.hpp" -#include - -#include - -#include -#include -#include -#include - -namespace xml = tinyxml2; - -namespace osmp -{ - IRelation::IRelation(const xml::XMLElement* xml, Object* parent) : - IMember(xml, parent, IMember::Type::RELATION), hasNullMembers(false) - { - const xml::XMLElement* member_element = xml->FirstChildElement("member"); - while (member_element != nullptr) - { - std::string memberType = GetSafeAttributeString(member_element, "type"); - uint64_t ref = GetSafeAttributeUint64(member_element, "ref"); - std::string role = GetSafeAttributeString(member_element, "role"); - - if (memberType == "node") { - Node node = parent->GetNode(ref); - nodes.push_back({ node, role }); - } - else if (memberType == "way") { - Way way = parent->GetWay(ref); - if (way == nullptr) { - hasNullMembers = true; - } - ways.push_back({ way, role }); - } - - member_element = member_element->NextSiblingElement("member"); - } - } - - namespace { - struct ConcreteRelation : public IRelation { - ConcreteRelation(const tinyxml2::XMLElement* way_elem, Object* parent) : - IRelation(way_elem, parent) - {} - }; - } - - Relation CreateRelation(const tinyxml2::XMLElement* xml, Object* parent) - { - return std::make_shared(xml, parent); - } - - std::string IRelation::GetRelationType() const - { - return GetTag("type"); - } - - const MemberNodes& IRelation::GetNodes() const - { - return nodes; - } - - size_t IRelation::GetNodesSize() const - { - return nodes.size(); - } - - const MemberNode& IRelation::GetNode(size_t index) const - { - return nodes[index]; - } - - const MemberWays& IRelation::GetWays() const - { - return ways; - } - - size_t IRelation::GetWaysSize() const - { - return ways.size(); - } - - const MemberWay& IRelation::GetWay(size_t index) const - { - return ways[index]; - } -} \ No newline at end of file diff --git a/lib/osmparser/src/osmway.cpp b/lib/osmparser/src/osmway.cpp deleted file mode 100644 index 0325966..0000000 --- a/lib/osmparser/src/osmway.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include - -#include - -#include -#include -#include - -namespace xml = tinyxml2; - -namespace osmp -{ - IWay::IWay(const tinyxml2::XMLElement* way_elem, Object* parent) : - IMember(way_elem, parent, IMember::Type::WAY) - { - area = GetSafeAttributeBool(way_elem, "area"); - closed = false; - - const xml::XMLElement* nd_elem = way_elem->FirstChildElement("nd"); - while (nd_elem != nullptr) - { - nodes.push_back( - parent->GetNode(GetSafeAttributeUint64(nd_elem, "ref")) - ); - - nd_elem = nd_elem->NextSiblingElement("nd"); - } - - if (nodes.front() == nodes.back()) - { - closed = true; - - if (!area && GetTag("barrier") == "" && GetTag("highway") == "") // this code sucks, it can be done better - area = true; - } - } - - namespace { - struct ConcreteWay : public IWay { - ConcreteWay(const tinyxml2::XMLElement* way_elem, Object* parent) : - IWay(way_elem, parent) - {} - }; - } - - Way CreateWay(const tinyxml2::XMLElement* way_elem, Object* parent) - { - return std::make_shared(way_elem, parent); - } - - const Nodes& IWay::GetNodes() const - { - return nodes; - } - - size_t IWay::GetNodesSize() const - { - return nodes.size(); - } - - Node IWay::GetNode(size_t index) const - { - return nodes[index]; - } -} \ No newline at end of file diff --git a/lib/osmparser/src/util.cpp b/lib/osmparser/src/util.cpp deleted file mode 100644 index 8490796..0000000 --- a/lib/osmparser/src/util.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include - -#include -#include - -namespace xml = tinyxml2; - -namespace osmp -{ -#define FAILED(err) (err != xml::XML_SUCCESS) - - std::string GetSafeAttributeString(const tinyxml2::XMLElement* elem, const std::string& name) - { - const char* buffer; - - xml::XMLError result = elem->QueryStringAttribute(name.c_str(), &buffer); - if (FAILED(result)) - return ""; - - std::string returnStr(buffer); - return returnStr; - } - - double GetSafeAttributeFloat(const tinyxml2::XMLElement* elem, const std::string& name) - { - double returnVal = 0.0f; - - xml::XMLError result = elem->QueryDoubleAttribute(name.c_str(), &returnVal); - - return returnVal; - } - - uint64_t GetSafeAttributeUint64(const tinyxml2::XMLElement* elem, const std::string& name) - { - uint64_t returnVal = 0; - - xml::XMLError result = elem->QueryUnsigned64Attribute(name.c_str(), &returnVal); - return returnVal; - } - - bool GetSafeAttributeBool(const tinyxml2::XMLElement* elem, const std::string& name) - { - bool returnVal = false; - - xml::XMLError result = elem->QueryBoolAttribute(name.c_str(), &returnVal); - - return returnVal; - } -} \ No newline at end of file From 93daff82687bde8d428012a126e32814d004e2fc Mon Sep 17 00:00:00 2001 From: Robert Date: Sun, 18 Apr 2021 17:59:36 +0200 Subject: [PATCH 4/8] adding osmp as submodule --- .gitmodules | 3 +++ lib/osmparser | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 lib/osmparser diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..3435792 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib/osmparser"] + path = lib/osmparser + url = https://github.com/Lauchmelder23/OSMParser diff --git a/lib/osmparser b/lib/osmparser new file mode 160000 index 0000000..7c814c5 --- /dev/null +++ b/lib/osmparser @@ -0,0 +1 @@ +Subproject commit 7c814c591b2dde646194eb4585e5cdfe1ba245c6 From c318a767682d061513219501464841c8a9f1bada Mon Sep 17 00:00:00 2001 From: Robert Date: Sun, 18 Apr 2021 19:36:30 +0200 Subject: [PATCH 5/8] Updated submodule --- lib/osmparser | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/osmparser b/lib/osmparser index 7c814c5..3d3abac 160000 --- a/lib/osmparser +++ b/lib/osmparser @@ -1 +1 @@ -Subproject commit 7c814c591b2dde646194eb4585e5cdfe1ba245c6 +Subproject commit 3d3abacee8242c08b350ca068dee82b95a102917 From ce3e87fb484e96c8eaf101aca2df9457a755dc47 Mon Sep 17 00:00:00 2001 From: Robert Date: Sun, 18 Apr 2021 21:56:04 +0200 Subject: [PATCH 6/8] Implemented Ring Assignment --- src/main.cpp | 6 +- src/multipolygon.cpp | 290 +++++++++++++++++++++++++++---------------- 2 files changed, 189 insertions(+), 107 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index db31917..c3042b9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -174,9 +174,9 @@ int main(int argc, char** argv) SDL_SetRenderDrawColor(renderer, 240, 240, 250, 255); SDL_RenderClear(renderer); - // for (Multipolygon& multipolygon : multipolygons) { - // multipolygon.Draw(renderer); - // } + for (Multipolygon& multipolygon : multipolygons) { + multipolygon.Draw(renderer); + } //for (Area& area : buildings) //{ diff --git a/src/multipolygon.cpp b/src/multipolygon.cpp index 6bcb6ca..4985b06 100644 --- a/src/multipolygon.cpp +++ b/src/multipolygon.cpp @@ -19,8 +19,8 @@ struct TriangulationData { }; struct Ring { - osmp::MemberWays ways; - int ring; + osmp::Nodes nodes; + bool inner; }; // Map values from one interval [A, B] to another [a, b] @@ -30,52 +30,82 @@ inline double Map(double A, double B, double a, double b, double x) } // TODO: Implement better algorithm -bool SelfIntersecting(const Ring & ring) +bool OnSegment(const osmp::Node& p, const osmp::Node& q, const osmp::Node& r); +int Orientation(const osmp::Node& p, const osmp::Node& q, const osmp::Node& r); +bool Intersect(const osmp::Node& p1, const osmp::Node& p2, const osmp::Node& q1, const osmp::Node& q2); +bool SelfIntersecting(const Ring& ring); + +[[nodiscard]] +bool BuildRing(Ring& ring, osmp::MemberWays& unassigned) { - struct Segment { - osmp::Node p1, p2; - }; - - // Get all segments - std::vector segments; - for (const osmp::MemberWay way : ring.ways) + const osmp::MemberWays original = unassigned; + + // RA-2 + int attempts = 0; + ring = Ring{ unassigned[attempts].way->GetNodes(), unassigned[attempts].role == "inner" }; + unassigned.erase(unassigned.begin() + attempts); + + + while (!unassigned.empty()) { - osmp::Nodes nodes = way.way->GetNodes(); - for (auto it = nodes.begin(); it != nodes.end() - 1; it++) + RA3: + // RA-3 + if (ring.nodes.front() == ring.nodes.back()) { - segments.push_back({ - *it, *(it + 1) - }); - } - } + if (SelfIntersecting(ring)) + { + unassigned = original; + attempts += 1; + if (unassigned.size() == attempts) + return false; - // Check for self intersection (O(n^2)...) - for (auto it = segments.begin(); it != segments.end(); it++) - { - for (auto jt = segments.begin(); jt != segments.end(); jt++) - { - if (it == jt) continue; - - double A1 = (it->p1->lat - it->p2->lat) / (it->p1->lon - it->p2->lon); - double A2 = (jt->p1->lat - jt->p2->lat) / (jt->p1->lon - jt->p2->lon); - if (A1 == A2) // Parallel - continue; - - double b1 = it->p1->lat - A1 * it->p1->lon; - double b2 = jt->p1->lat - A2 * jt->p1->lon; - - double Xa = (b2 - b1) / (A1 - A2); - double Ya = A1 * Xa + b1; - - if ((Xa < std::max(std::min(it->p1->lon, it->p2->lon), std::min(jt->p1->lon, jt->p2->lon))) || - (Xa > std::min(std::max(it->p1->lon, it->p2->lon), std::max(jt->p1->lon, jt->p2->lon)))) - continue; + ring = Ring{ unassigned[attempts].way->GetNodes(), unassigned[attempts].role == "inner" }; + } else + { + ring.nodes.pop_back(); return true; + } + } + else // RA-4 + { + osmp::Node lastNode = ring.nodes.back(); + for (auto it = unassigned.begin(); it != unassigned.end(); it++) + { + if (it->way->GetNodes().front() == lastNode) + { + ring.nodes.insert(ring.nodes.end(), it->way->GetNodes().begin() + 1, it->way->GetNodes().end()); + unassigned.erase(it); + goto RA3; + } + else if (it->way->GetNodes().back() == lastNode) + { + ring.nodes.insert(ring.nodes.end(), it->way->GetNodes().rbegin() + 1, it->way->GetNodes().rend()); + unassigned.erase(it); + goto RA3; + } + } + + // No ring found + unassigned = original; + return false; } } +} - return false; +[[nodiscard]] +bool AssignRings(std::vector& rings, const osmp::MemberWays& members) +{ + // Ring assignment + osmp::MemberWays unassigned = members; + while (!unassigned.empty()) + { + rings.push_back({}); + if (!BuildRing(rings.back(), unassigned) || rings.size() > members.size()) + return false; + } + + return true; } Multipolygon::Multipolygon(const osmp::Relation& relation, int width, int height, const osmp::Bounds& bounds) : @@ -86,30 +116,29 @@ Multipolygon::Multipolygon(const osmp::Relation& relation, int width, int height const osmp::MemberWays& members = relation->GetWays(); - // Implement https://wiki.openstreetmap.org/wiki/Relation:multipolygon/Algorithm - // Ring assignment + /* Implement https://wiki.openstreetmap.org/wiki/Relation:multipolygon/Algorithm */ - // RA-1 std::vector rings; - int ringCount = 0; - - // RA-2 - rings.push_back({ {members[0]}, ringCount }); - - // RA-3 - if (rings[ringCount].ways.front().way == rings[ringCount].ways.back().way) + if (!AssignRings(rings, members)) { - if (SelfIntersecting(rings[ringCount])) + std::cerr << "Assigning rings has failed for multipolygon " << id << std::endl; + } + + // TODO: Temporarily render rings: + for (const Ring& ring : rings) + { + Polygon polygon; + for (const osmp::Node& node : ring.nodes) { - // Backtracking ?? + polygon.vertices.push_back({ + Map(bounds.minlon, bounds.maxlon, 0, width, node->lon), + height - Map(bounds.minlat, bounds.maxlat, 0, height, node->lat) + }); } - } - else // RA-4 - { + polygons.push_back(polygon); } - // TODO: Make a color map std::string tag = ""; @@ -498,57 +527,110 @@ void Multipolygon::Draw(SDL_Renderer* renderer) if (!visible) return; - // if (id != 6427823) - // return; - for (const Polygon& polygon : polygons) { - switch(rendering) - { - case RenderType::FILL: - for (int i = 0; i < polygon.indices.size(); i += 3) // Be a graphics card - { - - filledTrigonRGBA(renderer, - polygon.vertices[polygon.indices[i + 0]].x, polygon.vertices[polygon.indices[i + 0]].y, - polygon.vertices[polygon.indices[i + 1]].x, polygon.vertices[polygon.indices[i + 1]].y, - polygon.vertices[polygon.indices[i + 2]].x, polygon.vertices[polygon.indices[i + 2]].y, - r, g, b, 255 + for (auto it = polygon.vertices.begin(); it != polygon.vertices.end() - 1; it++) { + thickLineRGBA(renderer, + it->x, it->y, + (it+1)->x, (it+1)->y, + 2, + r, g, b, 255 ); - } - break; - - case RenderType::OUTLINE: - for(int i = 0; i < polygon.segments.size(); i += 2) - { - thickLineRGBA(renderer, - polygon.vertices[polygon.segments[i + 0]].x, polygon.vertices[polygon.segments[i + 0]].y, - polygon.vertices[polygon.segments[i + 1]].x, polygon.vertices[polygon.segments[i + 1]].y, - 5, r, g, b, 255 - ); - } - break; - - case RenderType::INDOOR: - for (int i = 0; i < polygon.indices.size(); i += 3) // Be a graphics card - { - - filledTrigonRGBA(renderer, - polygon.vertices[polygon.indices[i + 0]].x, polygon.vertices[polygon.indices[i + 0]].y, - polygon.vertices[polygon.indices[i + 1]].x, polygon.vertices[polygon.indices[i + 1]].y, - polygon.vertices[polygon.indices[i + 2]].x, polygon.vertices[polygon.indices[i + 2]].y, - r, g, b, 255 - ); - } - - for (int i = 0; i < polygon.segments.size(); i += 2) - { - lineRGBA(renderer, - polygon.vertices[polygon.segments[i + 0]].x, polygon.vertices[polygon.segments[i + 0]].y, - polygon.vertices[polygon.segments[i + 1]].x, polygon.vertices[polygon.segments[i + 1]].y, - 10, 10, 15, 255 - ); - } - break; } } + + //for (const Polygon& polygon : polygons) { + // switch(rendering) + // { + // case RenderType::FILL: + // for (int i = 0; i < polygon.indices.size(); i += 3) // Be a graphics card + // { + + // filledTrigonRGBA(renderer, + // polygon.vertices[polygon.indices[i + 0]].x, polygon.vertices[polygon.indices[i + 0]].y, + // polygon.vertices[polygon.indices[i + 1]].x, polygon.vertices[polygon.indices[i + 1]].y, + // polygon.vertices[polygon.indices[i + 2]].x, polygon.vertices[polygon.indices[i + 2]].y, + // r, g, b, 255 + // ); + // } + // break; + + // case RenderType::OUTLINE: + // for(int i = 0; i < polygon.segments.size(); i += 2) + // { + // thickLineRGBA(renderer, + // polygon.vertices[polygon.segments[i + 0]].x, polygon.vertices[polygon.segments[i + 0]].y, + // polygon.vertices[polygon.segments[i + 1]].x, polygon.vertices[polygon.segments[i + 1]].y, + // 5, r, g, b, 255 + // ); + // } + // break; + + // case RenderType::INDOOR: + // for (int i = 0; i < polygon.indices.size(); i += 3) // Be a graphics card + // { + + // filledTrigonRGBA(renderer, + // polygon.vertices[polygon.indices[i + 0]].x, polygon.vertices[polygon.indices[i + 0]].y, + // polygon.vertices[polygon.indices[i + 1]].x, polygon.vertices[polygon.indices[i + 1]].y, + // polygon.vertices[polygon.indices[i + 2]].x, polygon.vertices[polygon.indices[i + 2]].y, + // r, g, b, 255 + // ); + // } + + // for (int i = 0; i < polygon.segments.size(); i += 2) + // { + // lineRGBA(renderer, + // polygon.vertices[polygon.segments[i + 0]].x, polygon.vertices[polygon.segments[i + 0]].y, + // polygon.vertices[polygon.segments[i + 1]].x, polygon.vertices[polygon.segments[i + 1]].y, + // 10, 10, 15, 255 + // ); + // } + // break; + // } + //} +} + +bool Intersect(const osmp::Node& p0, const osmp::Node& p1, const osmp::Node& p2, const osmp::Node& p3) +{ + if (p0 == p2 || p0 == p3 || p1 == p2 || p1 == p3) return false; + + float s1_x, s1_y, s2_x, s2_y, sn, tn, sd, td, t; + s1_x = p1->lon - p0->lon; s1_y = p1->lat - p0->lat; + s2_x = p3->lon - p2->lon; s2_y = p3->lat - p2->lat; + + sn = -s1_y * (p0->lon - p2->lon) + s1_x * (p0->lat - p2->lat); + sd = -s2_x * s1_y + s1_x * s2_y; + tn = s2_x * (p0->lat - p2->lat) - s2_y * (p0->lon - p2->lon); + td = -s2_x * s1_y + s1_x * s2_y; + + return (sn >= 0 && sn <= sd && tn >= 0 && tn <= td); +} +bool SelfIntersecting(const Ring& ring) +{ + struct Segment { + osmp::Node p1, p2; + }; + + // Get all segments + std::vector segments; + for (auto it = ring.nodes.begin(); it != ring.nodes.end() - 1; it++) + { + segments.push_back({ + *it, *(it + 1) + }); + } + + // Check for self intersection (O(n^2)...) + for (auto it = segments.begin(); it != segments.end(); it++) + { + for (auto jt = segments.begin(); jt != segments.end(); jt++) + { + if (it == jt) continue; + + if (Intersect(it->p1, it->p2, jt->p1, jt->p2)) + return true; + } + } + + return false; } From e7d189dc8bf548ca2abb400c951c48cb47737120 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 19 Apr 2021 01:23:46 +0200 Subject: [PATCH 7/8] started work on ring grouping --- src/multipolygon.cpp | 284 +++++++++++++++++++++++++++++-------------- 1 file changed, 193 insertions(+), 91 deletions(-) diff --git a/src/multipolygon.cpp b/src/multipolygon.cpp index 4985b06..648b70e 100644 --- a/src/multipolygon.cpp +++ b/src/multipolygon.cpp @@ -1,6 +1,7 @@ #include "..\include\multipolygon.hpp" #include +#include #include #include #include @@ -12,6 +13,7 @@ #include #define BREAKIF(x) if(relation->id == x) __debugbreak() +#define INDEXOF(x, y, n) (y * n + x) struct TriangulationData { std::vector vertices, holes; @@ -23,6 +25,10 @@ struct Ring { bool inner; }; +struct RingGroup { + std::vector rings; +}; + // Map values from one interval [A, B] to another [a, b] inline double Map(double A, double B, double a, double b, double x) { @@ -30,83 +36,16 @@ inline double Map(double A, double B, double a, double b, double x) } // TODO: Implement better algorithm -bool OnSegment(const osmp::Node& p, const osmp::Node& q, const osmp::Node& r); -int Orientation(const osmp::Node& p, const osmp::Node& q, const osmp::Node& r); -bool Intersect(const osmp::Node& p1, const osmp::Node& p2, const osmp::Node& q1, const osmp::Node& q2); -bool SelfIntersecting(const Ring& ring); +[[nodiscard]] bool Intersect(double p1_x, double p1_y, double p2_x, double p2_y, double q1_x, double q1_y, double q2_x, double q2_y); +[[nodiscard]] bool Intersect(const osmp::Node& p1, const osmp::Node& p2, const osmp::Node& q1, const osmp::Node& q2); +[[nodiscard]] bool SelfIntersecting(const Ring& ring); -[[nodiscard]] -bool BuildRing(Ring& ring, osmp::MemberWays& unassigned) -{ - const osmp::MemberWays original = unassigned; +[[nodiscard]] bool BuildRing(Ring& ring, osmp::MemberWays& unassigned); +[[nodiscard]] bool AssignRings(std::vector& rings, const osmp::MemberWays& members); - // RA-2 - int attempts = 0; - ring = Ring{ unassigned[attempts].way->GetNodes(), unassigned[attempts].role == "inner" }; - unassigned.erase(unassigned.begin() + attempts); - - - while (!unassigned.empty()) - { - RA3: - // RA-3 - if (ring.nodes.front() == ring.nodes.back()) - { - if (SelfIntersecting(ring)) - { - unassigned = original; - attempts += 1; - if (unassigned.size() == attempts) - return false; - - ring = Ring{ unassigned[attempts].way->GetNodes(), unassigned[attempts].role == "inner" }; - } - else - { - ring.nodes.pop_back(); - return true; - } - } - else // RA-4 - { - osmp::Node lastNode = ring.nodes.back(); - for (auto it = unassigned.begin(); it != unassigned.end(); it++) - { - if (it->way->GetNodes().front() == lastNode) - { - ring.nodes.insert(ring.nodes.end(), it->way->GetNodes().begin() + 1, it->way->GetNodes().end()); - unassigned.erase(it); - goto RA3; - } - else if (it->way->GetNodes().back() == lastNode) - { - ring.nodes.insert(ring.nodes.end(), it->way->GetNodes().rbegin() + 1, it->way->GetNodes().rend()); - unassigned.erase(it); - goto RA3; - } - } - - // No ring found - unassigned = original; - return false; - } - } -} - -[[nodiscard]] -bool AssignRings(std::vector& rings, const osmp::MemberWays& members) -{ - // Ring assignment - osmp::MemberWays unassigned = members; - while (!unassigned.empty()) - { - rings.push_back({}); - if (!BuildRing(rings.back(), unassigned) || rings.size() > members.size()) - return false; - } - - return true; -} +[[nodiscard]] bool PointInsideRing(const Ring& ring, const osmp::Node& point); +[[nodiscard]] bool IsRingContained(const Ring& r1, const Ring& r2); +[[nodiscard]] bool GroupRings(std::vector& ringGroup, const std::vector& rings); Multipolygon::Multipolygon(const osmp::Relation& relation, int width, int height, const osmp::Bounds& bounds) : r(255), g(0), b(255), visible(true), rendering(RenderType::FILL), id(relation->id) @@ -124,6 +63,9 @@ Multipolygon::Multipolygon(const osmp::Relation& relation, int width, int height std::cerr << "Assigning rings has failed for multipolygon " << id << std::endl; } + std::vector ringGroup; + GroupRings(ringGroup, rings); + // TODO: Temporarily render rings: for (const Ring& ring : rings) { @@ -590,20 +532,34 @@ void Multipolygon::Draw(SDL_Renderer* renderer) //} } +bool Intersect(double p0_x, double p0_y, double p1_x, double p1_y, double p2_x, double p2_y, double p3_x, double p3_y) +{ + if ((p0_x == p2_x && p0_y == p2_y) || + (p0_x == p3_x && p0_y == p3_y) || + (p1_x == p2_x && p1_y == p2_y) || + (p1_x == p3_x && p1_y == p3_y)) + return false; + + float s1_x, s1_y, s2_x, s2_y; + s1_x = p1_x - p0_x; s1_y = p1_y - p0_y; + s2_x = p3_x - p2_x; s2_y = p3_y - p2_y; + + float s, t; + s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y); + t = (s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y); + + if (s >= 0 && s <= 1 && t >= 0 && t <= 1) + { + // Collision detected + return 1; + } + + return 0; // No collision +} + bool Intersect(const osmp::Node& p0, const osmp::Node& p1, const osmp::Node& p2, const osmp::Node& p3) { - if (p0 == p2 || p0 == p3 || p1 == p2 || p1 == p3) return false; - - float s1_x, s1_y, s2_x, s2_y, sn, tn, sd, td, t; - s1_x = p1->lon - p0->lon; s1_y = p1->lat - p0->lat; - s2_x = p3->lon - p2->lon; s2_y = p3->lat - p2->lat; - - sn = -s1_y * (p0->lon - p2->lon) + s1_x * (p0->lat - p2->lat); - sd = -s2_x * s1_y + s1_x * s2_y; - tn = s2_x * (p0->lat - p2->lat) - s2_y * (p0->lon - p2->lon); - td = -s2_x * s1_y + s1_x * s2_y; - - return (sn >= 0 && sn <= sd && tn >= 0 && tn <= td); + return Intersect(p0->lon, p0->lat, p1->lon, p1->lat, p2->lon, p2->lat, p3->lon, p3->lat); } bool SelfIntersecting(const Ring& ring) { @@ -613,11 +569,20 @@ bool SelfIntersecting(const Ring& ring) // Get all segments std::vector segments; - for (auto it = ring.nodes.begin(); it != ring.nodes.end() - 1; it++) + for (auto it = ring.nodes.begin(); it != ring.nodes.end(); it++) { - segments.push_back({ - *it, *(it + 1) - }); + if (it == ring.nodes.end() - 1) + { + segments.push_back({ + *it, ring.nodes.front() + }); + } + else + { + segments.push_back({ + *it, *(it + 1) + }); + } } // Check for self intersection (O(n^2)...) @@ -634,3 +599,140 @@ bool SelfIntersecting(const Ring& ring) return false; } + +bool BuildRing(Ring& ring, osmp::MemberWays& unassigned) +{ + const osmp::MemberWays original = unassigned; + + // RA-2 + int attempts = 0; + ring = Ring{ unassigned[attempts].way->GetNodes(), unassigned[attempts].role == "inner" }; + unassigned.erase(unassigned.begin() + attempts); + +RA3: + // RA-3 + if (ring.nodes.front() == ring.nodes.back()) + { + if (SelfIntersecting(ring)) + { + unassigned = original; + attempts += 1; + if (unassigned.size() == attempts) + return false; + + ring = Ring{ unassigned[attempts].way->GetNodes(), unassigned[attempts].role == "inner" }; + goto RA3; + } + else + { + ring.nodes.pop_back(); + return true; + } + } + else // RA-4 + { + osmp::Node lastNode = ring.nodes.back(); + for (auto it = unassigned.begin(); it != unassigned.end(); it++) + { + if (it->way->GetNodes().front() == lastNode) + { + ring.nodes.insert(ring.nodes.end(), it->way->GetNodes().begin() + 1, it->way->GetNodes().end()); + unassigned.erase(it); + goto RA3; + } + else if (it->way->GetNodes().back() == lastNode) + { + ring.nodes.insert(ring.nodes.end(), it->way->GetNodes().rbegin() + 1, it->way->GetNodes().rend()); + unassigned.erase(it); + goto RA3; + } + } + + // No ring found + unassigned = original; + return false; + } +} + +bool AssignRings(std::vector& rings, const osmp::MemberWays& members) +{ + // Ring assignment + osmp::MemberWays unassigned = members; + while (!unassigned.empty()) + { + rings.push_back({}); + if (!BuildRing(rings.back(), unassigned) || rings.size() > members.size()) + return false; + } + + return true; +} + +bool cmp(const osmp::Node& a, const osmp::Node& b) +{ + return (a->lon < b->lon); +} + +bool PointInsideRing(const Ring& ring, const osmp::Node& point) +{ + const osmp::Node& rightestNode = *(std::max_element(ring.nodes.begin(), ring.nodes.end(), cmp)); + + int intersections = 0; + for (auto it = ring.nodes.begin(); it != ring.nodes.end(); it++) + { + const osmp::Node& jt = ((it == ring.nodes.end() - 1) ? ring.nodes.front() : *(it + 1)); + intersections += Intersect((*it)->GetLon(), (*it)->GetLat(), + jt->GetLon(), jt->GetLat(), + point->GetLon(), point->GetLat(), + rightestNode->GetLon() + 1.0f, point->GetLat() + ); + } + + return (intersections % 2 != 0); +} + +bool IsRingContained(const Ring& r1, const Ring& r2) +{ + // Test if any line segments are intersecting + // I don't think this is needed actually, the rings shouldn't overlap so testing if a node is inside is enough! + // Gonna leave this here tho in case we *do* need to see if a ring is completely contained + //for (auto it = r1.nodes.begin(); it != r1.nodes.end(); it++) + //{ + // for (auto jt = r2.nodes.begin(); jt != r2.nodes.end(); jt++) + // { + // osmp::Node n1 = ((it == r1.nodes.end() - 1) ? r1.nodes.front() : *(it + 1)); + // osmp::Node n2 = ((jt == r2.nodes.end() - 1) ? r2.nodes.front() : *(jt + 1)); + + // if (Intersect(*it, n1, *jt, n2)) + // return false; + // } + //} + + if (PointInsideRing(r1, r2.nodes.front())) + return true; + + return false; +} + +bool GroupRings(std::vector& ringGroups, const std::vector& rings) +{ + //RG-1 + int ringNum = rings.size(); + std::vector containmentMatrix(ringNum * ringNum); + + for (int i = 0; i < ringNum; i++) + { + for (int j = 0; j < ringNum; j++) + { + if (i == j) { + containmentMatrix[INDEXOF(i, j, ringNum)] = false; + continue; + } + + containmentMatrix[INDEXOF(i, j, ringNum)] = IsRingContained(rings[i], rings[j]); + } + } + __debugbreak(); + + return true; +} From 079d5f2b9979514c185e933926ee26dc9da170dd Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 19 Apr 2021 14:39:38 +0200 Subject: [PATCH 8/8] Finished multipolygon assembly --- src/main.cpp | 8 +- src/multipolygon.cpp | 343 +++++++++++++++++++++++++++++++++---------- 2 files changed, 271 insertions(+), 80 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index c3042b9..4d6c1b9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -178,10 +178,10 @@ int main(int argc, char** argv) multipolygon.Draw(renderer); } - //for (Area& area : buildings) - //{ - // filledPolygonRGBA(renderer, area.x, area.y, area.length, area.r, area.g, area.b, 255); - //} + for (Area& area : buildings) + { + filledPolygonRGBA(renderer, area.x, area.y, area.length, area.r, area.g, area.b, 255); + } for (Highway& highway : highways) { diff --git a/src/multipolygon.cpp b/src/multipolygon.cpp index 648b70e..52196c4 100644 --- a/src/multipolygon.cpp +++ b/src/multipolygon.cpp @@ -23,6 +23,8 @@ struct TriangulationData { struct Ring { osmp::Nodes nodes; bool inner; + int index; + bool hole = false; }; struct RingGroup { @@ -40,12 +42,15 @@ inline double Map(double A, double B, double a, double b, double x) [[nodiscard]] bool Intersect(const osmp::Node& p1, const osmp::Node& p2, const osmp::Node& q1, const osmp::Node& q2); [[nodiscard]] bool SelfIntersecting(const Ring& ring); -[[nodiscard]] bool BuildRing(Ring& ring, osmp::MemberWays& unassigned); +[[nodiscard]] bool BuildRing(Ring& ring, osmp::MemberWays& unassigned, int ringCount); [[nodiscard]] bool AssignRings(std::vector& rings, const osmp::MemberWays& members); +void FindAllContainedRings(const std::vector& containmentMatrix, int container, int numRings, std::vector& buffer); +void FindAllContainedRingsThatArentContainedByUnusedRings(const std::vector& containmentMatrix, int container, int numRings, const std::vector& unusedRings, std::vector& buffer); +[[nodiscard]] int FindUncontainedRing(const std::vector& containmentMatrix, int rings, const std::vector& unusedRings); [[nodiscard]] bool PointInsideRing(const Ring& ring, const osmp::Node& point); [[nodiscard]] bool IsRingContained(const Ring& r1, const Ring& r2); -[[nodiscard]] bool GroupRings(std::vector& ringGroup, const std::vector& rings); +[[nodiscard]] bool GroupRings(std::vector& ringGroup, std::vector& rings); Multipolygon::Multipolygon(const osmp::Relation& relation, int width, int height, const osmp::Bounds& bounds) : r(255), g(0), b(255), visible(true), rendering(RenderType::FILL), id(relation->id) @@ -63,22 +68,110 @@ Multipolygon::Multipolygon(const osmp::Relation& relation, int width, int height std::cerr << "Assigning rings has failed for multipolygon " << id << std::endl; } - std::vector ringGroup; - GroupRings(ringGroup, rings); + std::vector ringGroups; + GroupRings(ringGroups, rings); - // TODO: Temporarily render rings: - for (const Ring& ring : rings) + char* triSwitches = "zpNBQ"; + for (const RingGroup& ringGroup : ringGroups) { - Polygon polygon; - for (const osmp::Node& node : ring.nodes) + TriangulationData td; + + bool valid = true; + for (const Ring& ring : ringGroup.rings) { - polygon.vertices.push_back({ - Map(bounds.minlon, bounds.maxlon, 0, width, node->lon), - height - Map(bounds.minlat, bounds.maxlat, 0, height, node->lat) - }); + std::vector vertices; + for (const osmp::Node& node : ring.nodes) { + double x = Map(bounds.minlon, bounds.maxlon, 0, width, node->lon); + double y = height - Map(bounds.minlat, bounds.maxlat, 0, height, node->lat); + + vertices.push_back(x); + vertices.push_back(y); + } + + int segment = td.vertices.size() / 2; + for (int i = 0; i < vertices.size() / 2; i += 1) { + td.segments.push_back(segment + i); + td.segments.push_back(segment + i + 1); + } + td.segments.back() = td.vertices.size() / 2; + + td.vertices.insert(td.vertices.end(), vertices.begin(), vertices.end()); + + if (ring.hole) { + double holeX = 0.0f; + double holeY = 0.0f; + for (int i = 0; i < vertices.size(); i += 2) + { + holeX += vertices[i]; + holeY += vertices[i + 1]; + } + + holeX /= vertices.size() / 2; + holeY /= vertices.size() / 2; + + td.holes.push_back(holeX); + td.holes.push_back(holeY); + } } - polygons.push_back(polygon); + // TODO: Find better way to check for duplicates + for (int i = 0; i < td.vertices.size(); i += 2) { + for (int j = 0; j < td.vertices.size(); j += 2) { + if (i == j) continue; + + if (td.vertices[i] == td.vertices[j] && td.vertices[i + 1] == td.vertices[j + 1]) + { + valid = false; + break; + } + } + } + + if (valid) + { + triangulateio in; + + in.numberofpoints = td.vertices.size() / 2; + in.pointlist = td.vertices.data(); + in.pointmarkerlist = NULL; + + in.numberofpointattributes = 0; + in.numberofpointattributes = NULL; + + in.numberofholes = td.holes.size() / 2; + in.holelist = td.holes.data(); + + in.numberofsegments = td.segments.size() / 2; + in.segmentlist = td.segments.data(); + in.segmentmarkerlist = NULL; + + in.numberofregions = 0; + in.regionlist = NULL; + + triangulateio out; + out.pointlist = NULL; + out.pointmarkerlist = NULL; + out.trianglelist = NULL; + out.segmentlist = NULL; + out.segmentmarkerlist = NULL; + + triangulate(triSwitches, &in, &out, NULL); + + polygons.push_back({}); + for (int i = 0; i < in.numberofpoints * 2; i += 2) { + polygons.back().vertices.push_back({ in.pointlist[i], in.pointlist[i + 1] }); + // polygons.back().vertices.push_back(in.pointlist[i + 1]); + } + for (int i = 0; i < out.numberoftriangles * 3; i++) { + polygons.back().indices.push_back(out.trianglelist[i]); + } + for (int i = 0; i < in.numberofsegments * 2; i++) { + polygons.back().segments.push_back(in.segmentlist[i]); + } + + trifree(out.trianglelist); + trifree(out.segmentlist); + } } // TODO: Make a color map @@ -469,67 +562,67 @@ void Multipolygon::Draw(SDL_Renderer* renderer) if (!visible) return; - for (const Polygon& polygon : polygons) { - for (auto it = polygon.vertices.begin(); it != polygon.vertices.end() - 1; it++) { - thickLineRGBA(renderer, - it->x, it->y, - (it+1)->x, (it+1)->y, - 2, - r, g, b, 255 - ); - } - } - //for (const Polygon& polygon : polygons) { - // switch(rendering) - // { - // case RenderType::FILL: - // for (int i = 0; i < polygon.indices.size(); i += 3) // Be a graphics card - // { - - // filledTrigonRGBA(renderer, - // polygon.vertices[polygon.indices[i + 0]].x, polygon.vertices[polygon.indices[i + 0]].y, - // polygon.vertices[polygon.indices[i + 1]].x, polygon.vertices[polygon.indices[i + 1]].y, - // polygon.vertices[polygon.indices[i + 2]].x, polygon.vertices[polygon.indices[i + 2]].y, - // r, g, b, 255 + // for (auto it = polygon.vertices.begin(); it != polygon.vertices.end() - 1; it++) { + // thickLineRGBA(renderer, + // it->x, it->y, + // (it+1)->x, (it+1)->y, + // 2, + // r, g, b, 255 // ); - // } - // break; - - // case RenderType::OUTLINE: - // for(int i = 0; i < polygon.segments.size(); i += 2) - // { - // thickLineRGBA(renderer, - // polygon.vertices[polygon.segments[i + 0]].x, polygon.vertices[polygon.segments[i + 0]].y, - // polygon.vertices[polygon.segments[i + 1]].x, polygon.vertices[polygon.segments[i + 1]].y, - // 5, r, g, b, 255 - // ); - // } - // break; - - // case RenderType::INDOOR: - // for (int i = 0; i < polygon.indices.size(); i += 3) // Be a graphics card - // { - - // filledTrigonRGBA(renderer, - // polygon.vertices[polygon.indices[i + 0]].x, polygon.vertices[polygon.indices[i + 0]].y, - // polygon.vertices[polygon.indices[i + 1]].x, polygon.vertices[polygon.indices[i + 1]].y, - // polygon.vertices[polygon.indices[i + 2]].x, polygon.vertices[polygon.indices[i + 2]].y, - // r, g, b, 255 - // ); - // } - - // for (int i = 0; i < polygon.segments.size(); i += 2) - // { - // lineRGBA(renderer, - // polygon.vertices[polygon.segments[i + 0]].x, polygon.vertices[polygon.segments[i + 0]].y, - // polygon.vertices[polygon.segments[i + 1]].x, polygon.vertices[polygon.segments[i + 1]].y, - // 10, 10, 15, 255 - // ); - // } - // break; // } //} + + for (const Polygon& polygon : polygons) { + switch(rendering) + { + case RenderType::FILL: + for (int i = 0; i < polygon.indices.size(); i += 3) // Be a graphics card + { + + filledTrigonRGBA(renderer, + polygon.vertices[polygon.indices[i + 0]].x, polygon.vertices[polygon.indices[i + 0]].y, + polygon.vertices[polygon.indices[i + 1]].x, polygon.vertices[polygon.indices[i + 1]].y, + polygon.vertices[polygon.indices[i + 2]].x, polygon.vertices[polygon.indices[i + 2]].y, + r, g, b, 255 + ); + } + break; + + case RenderType::OUTLINE: + for(int i = 0; i < polygon.segments.size(); i += 2) + { + thickLineRGBA(renderer, + polygon.vertices[polygon.segments[i + 0]].x, polygon.vertices[polygon.segments[i + 0]].y, + polygon.vertices[polygon.segments[i + 1]].x, polygon.vertices[polygon.segments[i + 1]].y, + 5, r, g, b, 255 + ); + } + break; + + case RenderType::INDOOR: + for (int i = 0; i < polygon.indices.size(); i += 3) // Be a graphics card + { + + filledTrigonRGBA(renderer, + polygon.vertices[polygon.indices[i + 0]].x, polygon.vertices[polygon.indices[i + 0]].y, + polygon.vertices[polygon.indices[i + 1]].x, polygon.vertices[polygon.indices[i + 1]].y, + polygon.vertices[polygon.indices[i + 2]].x, polygon.vertices[polygon.indices[i + 2]].y, + r, g, b, 255 + ); + } + + for (int i = 0; i < polygon.segments.size(); i += 2) + { + lineRGBA(renderer, + polygon.vertices[polygon.segments[i + 0]].x, polygon.vertices[polygon.segments[i + 0]].y, + polygon.vertices[polygon.segments[i + 1]].x, polygon.vertices[polygon.segments[i + 1]].y, + 10, 10, 15, 255 + ); + } + break; + } + } } bool Intersect(double p0_x, double p0_y, double p1_x, double p1_y, double p2_x, double p2_y, double p3_x, double p3_y) @@ -600,13 +693,13 @@ bool SelfIntersecting(const Ring& ring) return false; } -bool BuildRing(Ring& ring, osmp::MemberWays& unassigned) +bool BuildRing(Ring& ring, osmp::MemberWays& unassigned, int ringCount) { const osmp::MemberWays original = unassigned; // RA-2 int attempts = 0; - ring = Ring{ unassigned[attempts].way->GetNodes(), unassigned[attempts].role == "inner" }; + ring = Ring{ unassigned[attempts].way->GetNodes(), unassigned[attempts].role == "inner", ringCount }; unassigned.erase(unassigned.begin() + attempts); RA3: @@ -620,7 +713,7 @@ RA3: if (unassigned.size() == attempts) return false; - ring = Ring{ unassigned[attempts].way->GetNodes(), unassigned[attempts].role == "inner" }; + ring = Ring{ unassigned[attempts].way->GetNodes(), unassigned[attempts].role == "inner", ringCount }; goto RA3; } else @@ -658,11 +751,14 @@ bool AssignRings(std::vector& rings, const osmp::MemberWays& members) { // Ring assignment osmp::MemberWays unassigned = members; + int ringCount = 0; while (!unassigned.empty()) { rings.push_back({}); - if (!BuildRing(rings.back(), unassigned) || rings.size() > members.size()) + if (!BuildRing(rings.back(), unassigned, ringCount) || rings.size() > members.size()) return false; + + ringCount++; } return true; @@ -673,6 +769,61 @@ bool cmp(const osmp::Node& a, const osmp::Node& b) return (a->lon < b->lon); } +void FindAllContainedRings(const std::vector& containmentMatrix, int container, int numRings, std::vector& buffer) +{ + buffer.clear(); + for (int j = 0; j < numRings; j++) { + if (containmentMatrix[INDEXOF(container, j, numRings)]) + buffer.push_back(j); + } +} + +void FindAllContainedRingsThatArentContainedByUnusedRings(const std::vector& containmentMatrix, int container, int numRings, const std::vector& unusedRings, std::vector& buffer) +{ + FindAllContainedRings(containmentMatrix, container, numRings, buffer); + + for (auto j = buffer.begin(); j != buffer.end(); ) { + bool foundRing = false; + for (const Ring& ring : unusedRings) { + if (containmentMatrix[INDEXOF(ring.index, *j, numRings)]) { + foundRing = true; + break; + } + } + + if(foundRing) + j = buffer.erase(j); + else + ++j; + } +} + +bool Compare(const Ring& ring, int index) { + return (ring.index == index); +} + +int FindUncontainedRing(const std::vector& containmentMatrix, int rings, const std::vector& unusedRings) +{ + for (int j = 0; j < rings; j++) { + if (std::find_if(unusedRings.begin(), unusedRings.end(), [j](const Ring& ring) { return (ring.index == j); }) == unusedRings.end()) + continue; + + bool isContained = false; + for (int i = 0; i < rings; i++) { + if (containmentMatrix[INDEXOF(i, j, rings)]) + { + isContained = true; + break; + } + } + + if (!isContained) + return j; + } + + return -1; +} + bool PointInsideRing(const Ring& ring, const osmp::Node& point) { const osmp::Node& rightestNode = *(std::max_element(ring.nodes.begin(), ring.nodes.end(), cmp)); @@ -714,8 +865,10 @@ bool IsRingContained(const Ring& r1, const Ring& r2) return false; } -bool GroupRings(std::vector& ringGroups, const std::vector& rings) +bool GroupRings(std::vector& ringGroups, std::vector& rings) { + const std::vector original = rings; + //RG-1 int ringNum = rings.size(); std::vector containmentMatrix(ringNum * ringNum); @@ -732,7 +885,45 @@ bool GroupRings(std::vector& ringGroups, const std::vector& rin containmentMatrix[INDEXOF(i, j, ringNum)] = IsRingContained(rings[i], rings[j]); } } - __debugbreak(); + + // RG-2 / RG-3 + while (!rings.empty()) // TODO: Make this time out + { + int uncontainedRing = FindUncontainedRing(containmentMatrix, ringNum, rings); + if (uncontainedRing == -1) { + std::cerr << "Failed to find uncontained ring in step RG-2" << std::endl; + return false; + } + auto it = std::find_if(rings.begin(), rings.end(), [uncontainedRing](const Ring& ring) { return (ring.index == uncontainedRing); }); + if (it == rings.end()) + { + std::cerr << "Uncontained Ring is out of range" << std::endl; + return false; + } + + ringGroups.push_back({ {*it} }); + rings.erase(it); + + + // RG-4 + std::vector containedRings; + FindAllContainedRingsThatArentContainedByUnusedRings(containmentMatrix, uncontainedRing, ringNum, rings, containedRings); + + for (auto it = rings.begin(); it != rings.end(); ) { + if (std::find(containedRings.begin(), containedRings.end(), it->index) != containedRings.end()) { + ringGroups.back().rings.push_back(*it); + ringGroups.back().rings.back().hole = true; + it = rings.erase(it); + } + else { + it++; + } + } + + // TODO: RG-5 / RG-6 will be left out for now as they're optional. + // At least RG-6 should be implemented because not doing so might crash Triangle + + } return true; }