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