commit 7c814c591b2dde646194eb4585e5cdfe1ba245c6 Author: Robert Date: Sun Apr 18 17:58:08 2021 +0200 Extracted submodule diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..e8bf4ac --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,26 @@ +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/include/osmimember.hpp b/include/osmimember.hpp new file mode 100644 index 0000000..b9846d9 --- /dev/null +++ b/include/osmimember.hpp @@ -0,0 +1,50 @@ +#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/include/osmnode.hpp b/include/osmnode.hpp new file mode 100644 index 0000000..52a538e --- /dev/null +++ b/include/osmnode.hpp @@ -0,0 +1,27 @@ +#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/include/osmobject.hpp b/include/osmobject.hpp new file mode 100644 index 0000000..7cb02c6 --- /dev/null +++ b/include/osmobject.hpp @@ -0,0 +1,40 @@ +#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/include/osmp.hpp b/include/osmp.hpp new file mode 100644 index 0000000..a0ea337 --- /dev/null +++ b/include/osmp.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include +#include +#include +#include +#include +#include \ No newline at end of file diff --git a/include/osmrelation.hpp b/include/osmrelation.hpp new file mode 100644 index 0000000..e270a31 --- /dev/null +++ b/include/osmrelation.hpp @@ -0,0 +1,58 @@ +#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/include/osmtag.hpp b/include/osmtag.hpp new file mode 100644 index 0000000..cdfb098 --- /dev/null +++ b/include/osmtag.hpp @@ -0,0 +1,38 @@ +#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/include/osmway.hpp b/include/osmway.hpp new file mode 100644 index 0000000..66110f5 --- /dev/null +++ b/include/osmway.hpp @@ -0,0 +1,35 @@ +#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/include/util.hpp b/include/util.hpp new file mode 100644 index 0000000..bfcb169 --- /dev/null +++ b/include/util.hpp @@ -0,0 +1,35 @@ +#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/src/osmimember.cpp b/src/osmimember.cpp new file mode 100644 index 0000000..e038607 --- /dev/null +++ b/src/osmimember.cpp @@ -0,0 +1,66 @@ +#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/src/osmnode.cpp b/src/osmnode.cpp new file mode 100644 index 0000000..3770645 --- /dev/null +++ b/src/osmnode.cpp @@ -0,0 +1,30 @@ +#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/src/osmobject.cpp b/src/osmobject.cpp new file mode 100644 index 0000000..45e0db8 --- /dev/null +++ b/src/osmobject.cpp @@ -0,0 +1,142 @@ +#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/src/osmrelation.cpp b/src/osmrelation.cpp new file mode 100644 index 0000000..0e8f7c0 --- /dev/null +++ b/src/osmrelation.cpp @@ -0,0 +1,88 @@ +#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/src/osmway.cpp b/src/osmway.cpp new file mode 100644 index 0000000..0325966 --- /dev/null +++ b/src/osmway.cpp @@ -0,0 +1,65 @@ +#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/src/util.cpp b/src/util.cpp new file mode 100644 index 0000000..8490796 --- /dev/null +++ b/src/util.cpp @@ -0,0 +1,49 @@ +#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