File indexing completed on 2024-12-08 10:16:03
0001 /* 0002 SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #ifndef OSM_ELEMENT_H 0008 #define OSM_ELEMENT_H 0009 0010 #include "datatypes.h" 0011 #include "internal.h" 0012 0013 #include <cstdint> 0014 0015 namespace OSM { 0016 0017 /** A reference to any of OSM::Node/OSM::Way/OSM::Relation. 0018 * Lifetime of the referenced object needs to extend beyond the lifetime of this. 0019 */ 0020 class Element 0021 { 0022 public: 0023 inline constexpr Element() : m_elem(nullptr, static_cast<uint8_t>(Type::Null)) {} 0024 inline Element(const Node *node) : m_elem(node, static_cast<uint8_t>(Type::Node)) {} 0025 inline Element(const Way *way) : m_elem(way, static_cast<uint8_t>(Type::Way)) {} 0026 inline Element(const Relation *relation) : m_elem(relation, static_cast<uint8_t>(Type::Relation)) {} 0027 0028 inline bool operator==(Element other) const { return m_elem == other.m_elem; } 0029 inline bool operator!=(Element other) const { return m_elem != other.m_elem; } 0030 inline bool operator<(Element other) const { return m_elem < other.m_elem; } 0031 explicit inline operator bool() const { return type() != OSM::Type::Null; } 0032 0033 inline Type type() const { return static_cast<Type>(m_elem.tag()); } 0034 inline const Node* node() const { return static_cast<const Node*>(m_elem.get()); } 0035 inline const Way* way() const { return static_cast<const Way*>(m_elem.get()); } 0036 inline const Relation* relation() const { return static_cast<const Relation*>(m_elem.get()); } 0037 Id id() const; 0038 0039 Coordinate center() const; 0040 BoundingBox boundingBox() const; 0041 QByteArray tagValue(TagKey key) const; 0042 QByteArray tagValue(const char *keyName) const; 0043 QByteArray tagValue(const char *keyName, const QLocale &locale) const; 0044 /** Returns the value of the first non-empty tag. 0045 * Both OSM::TagKey (fast) and const char* (slow) keys are accepted. 0046 */ 0047 template <typename K, typename ...Args> QByteArray tagValue(K key, Args... args) const; 0048 template <typename K, typename ...Args> QByteArray tagValue(K key, Args... args, const QLocale &locale) const; 0049 /** Returns whether or not this element has any tags set. */ 0050 inline bool hasTags() const { return std::distance(tagsBegin(), tagsEnd()) > 0; } 0051 0052 std::vector<Tag>::const_iterator tagsBegin() const; 0053 std::vector<Tag>::const_iterator tagsEnd() const; 0054 QString url() const; 0055 0056 /** Returns all nodes belonging to the outer path of this element. 0057 * In the simplest case that's a single closed polygon, but it can also be a sequence of multiple 0058 * closed loop polygons, or a polyline. 0059 */ 0060 std::vector<const Node*> outerPath(const DataSet &dataSet) const; 0061 0062 /** Recompute the bounding box of this element. 0063 * We usually assume those to be provided by Overpass/osmconvert, but there seem to be cases where those 0064 * aren't reliable. 0065 */ 0066 void recomputeBoundingBox(const DataSet &dataSet); 0067 0068 private: 0069 Internal::TaggedPointer<const void> m_elem; 0070 }; 0071 0072 template <typename K, typename ...Args> 0073 QByteArray Element::tagValue(K k, Args... args) const 0074 { 0075 const auto v = tagValue(k); 0076 if (!v.isEmpty()) { 0077 return v; 0078 } 0079 return tagValue(args...); 0080 } 0081 0082 template <typename K, typename ...Args> 0083 QByteArray Element::tagValue(K key, Args... args, const QLocale &locale) const 0084 { 0085 const auto v = tagValue(key, locale); 0086 if (!v.isEmpty()) { 0087 return v; 0088 } 0089 return tagValue(args..., locale); 0090 } 0091 0092 0093 /** A std::unique_ptr-like object for OSM element types. */ 0094 class UniqueElement 0095 { 0096 public: 0097 explicit inline UniqueElement() = default; 0098 explicit inline UniqueElement(Node *node) : m_element(node) {} 0099 explicit inline UniqueElement(Way *way) : m_element(way) {} 0100 explicit inline UniqueElement(Relation *rel) : m_element(rel) {} 0101 0102 UniqueElement(const UniqueElement&) = delete; 0103 inline UniqueElement(UniqueElement &&other) { 0104 m_element = other.m_element; 0105 other.m_element = {}; 0106 } 0107 0108 ~UniqueElement(); 0109 0110 UniqueElement& operator=(const UniqueElement&) = delete; 0111 UniqueElement& operator=(UniqueElement &&other) { 0112 m_element = other.m_element; 0113 other.m_element = {}; 0114 return *this; 0115 } 0116 0117 constexpr inline Element element() const { return m_element; } 0118 constexpr inline operator Element() const { return m_element; } 0119 0120 void setTagValue(TagKey key, const QByteArray &value); 0121 0122 private: 0123 Element m_element; 0124 }; 0125 0126 0127 /** Utility function similar to SQL COALESCE for OSM::Element, ie. this returns the first non-null element passed as argument. */ 0128 constexpr Element coalesce(Element e) { return e; } 0129 template <typename ...Args> 0130 constexpr Element coalesce(Element e, Args... args) { return e ? e : coalesce(args...); } 0131 0132 enum ForeachFlag : uint8_t { 0133 IncludeRelations = 1, 0134 IncludeWays = 2, 0135 IncludeNodes = 4, 0136 IterateAll = IncludeRelations | IncludeWays | IncludeNodes, 0137 }; 0138 0139 template <typename Func> 0140 inline void for_each(const DataSet &dataSet, Func func, uint8_t flags = IterateAll) 0141 { 0142 if (flags & IncludeRelations) { 0143 for (const auto &rel : dataSet.relations) { 0144 func(Element(&rel)); 0145 } 0146 } 0147 if (flags & IncludeWays) { 0148 for (const auto &way : dataSet.ways) { 0149 func(Element(&way)); 0150 } 0151 } 0152 if (flags & IncludeNodes) { 0153 for (const auto &node : dataSet.nodes) { 0154 func(Element(&node)); 0155 } 0156 } 0157 } 0158 0159 template <typename Func> 0160 inline void for_each_node(const DataSet &dataSet, const Way &way, Func func) 0161 { 0162 for (auto nodeId : way.nodes) { 0163 if (auto node = dataSet.node(nodeId)) { 0164 func(*node); 0165 } 0166 } 0167 } 0168 0169 template <typename Func> 0170 inline void for_each_member(const DataSet &dataSet, const Relation &rel, Func func) 0171 { 0172 for (const auto &mem : rel.members) { 0173 switch (mem.type()) { 0174 case Type::Null: 0175 break; 0176 case Type::Node: 0177 if (auto node = dataSet.node(mem.id)) { 0178 func(Element(node)); 0179 } 0180 break; 0181 case Type::Way: 0182 if (auto way = dataSet.way(mem.id)) { 0183 func(Element(way)); 0184 } 0185 break; 0186 case Type::Relation: 0187 if (auto rel = dataSet.relation(mem.id)) { 0188 func(Element(rel)); 0189 } 0190 break; 0191 } 0192 } 0193 } 0194 0195 } 0196 0197 Q_DECLARE_METATYPE(OSM::Element) 0198 0199 #endif // OSM_ELEMENT_H