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