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