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 #include "element.h"
0008 #include "pathutil.h"
0009 
0010 using namespace OSM;
0011 
0012 Id Element::id() const
0013 {
0014     switch (type()) {
0015         case Type::Null:
0016             return {};
0017         case Type::Node:
0018             return node()->id;
0019         case Type::Way:
0020             return way()->id;
0021         case Type::Relation:
0022             return relation()->id;
0023     }
0024 
0025     Q_UNREACHABLE();
0026     return {};
0027 }
0028 
0029 Coordinate Element::center() const
0030 {
0031     switch (type()) {
0032         case Type::Null:
0033             return {};
0034         case Type::Node:
0035             return node()->coordinate;
0036         case Type::Way:
0037             return way()->bbox.center();
0038         case Type::Relation:
0039             return relation()->bbox.center();
0040     }
0041 
0042     Q_UNREACHABLE();
0043     return {};
0044 }
0045 
0046 BoundingBox Element::boundingBox() const
0047 {
0048     switch (type()) {
0049         case Type::Null:
0050             return {};
0051         case Type::Node:
0052             return BoundingBox(node()->coordinate, node()->coordinate);
0053         case Type::Way:
0054             return way()->bbox;
0055         case Type::Relation:
0056             return relation()->bbox;
0057     }
0058 
0059     Q_UNREACHABLE();
0060     return {};
0061 }
0062 
0063 QByteArray Element::tagValue(TagKey key) const
0064 {
0065     switch (type()) {
0066         case Type::Null:
0067             return {};
0068         case Type::Node:
0069             return OSM::tagValue(*node(), key);
0070         case Type::Way:
0071             return OSM::tagValue(*way(), key);
0072         case Type::Relation:
0073             return OSM::tagValue(*relation(), key);
0074     }
0075 
0076     Q_UNREACHABLE();
0077     return {};
0078 }
0079 
0080 QByteArray Element::tagValue(const char *keyName) const
0081 {
0082     switch (type()) {
0083         case Type::Null:
0084             return {};
0085         case Type::Node:
0086             return OSM::tagValue(*node(), keyName);
0087         case Type::Way:
0088             return OSM::tagValue(*way(), keyName);
0089         case Type::Relation:
0090             return OSM::tagValue(*relation(), keyName);
0091     }
0092 
0093     Q_UNREACHABLE();
0094     return {};
0095 }
0096 
0097 QByteArray Element::tagValue(const OSM::Languages &languages, const char *keyName) const
0098 {
0099     switch (type()) {
0100         case Type::Null:
0101             return {};
0102         case Type::Node:
0103             return OSM::tagValue(*node(), languages, keyName);
0104         case Type::Way:
0105             return OSM::tagValue(*way(), languages, keyName);
0106         case Type::Relation:
0107             return OSM::tagValue(*relation(), languages, keyName);
0108     }
0109 
0110     Q_UNREACHABLE();
0111     return {};
0112 }
0113 
0114 bool Element::hasTag(TagKey key) const
0115 {
0116     return std::binary_search(tagsBegin(), tagsEnd(), key);
0117 }
0118 
0119 std::vector<Tag>::const_iterator OSM::Element::tagsBegin() const
0120 {
0121     switch (type()) {
0122         case Type::Null:
0123             Q_UNREACHABLE();
0124         case Type::Node:
0125             return node()->tags.begin();
0126         case Type::Way:
0127             return way()->tags.begin();
0128         case Type::Relation:
0129             return relation()->tags.begin();
0130     }
0131     Q_UNREACHABLE();
0132 }
0133 
0134 std::vector<Tag>::const_iterator OSM::Element::tagsEnd() const
0135 {
0136     switch (type()) {
0137         case Type::Null:
0138             Q_UNREACHABLE();
0139         case Type::Node:
0140             return node()->tags.end();
0141         case Type::Way:
0142             return way()->tags.end();
0143         case Type::Relation:
0144             return relation()->tags.end();
0145     }
0146     Q_UNREACHABLE();
0147 }
0148 
0149 QString Element::url() const
0150 {
0151     switch (type()) {
0152         case Type::Null:
0153             return {};
0154         case Type::Node:
0155             return node()->url();
0156         case Type::Way:
0157             return way()->url();
0158         case Type::Relation:
0159             return relation()->url();
0160     }
0161 
0162     Q_UNREACHABLE();
0163     return {};
0164 }
0165 
0166 std::vector<const Node*> Element::outerPath(const DataSet &dataSet) const
0167 {
0168     switch (type()) {
0169         case Type::Null:
0170             return {};
0171         case Type::Node:
0172             return {node()};
0173         case Type::Way:
0174         {
0175             std::vector<const Node*> nodes;
0176             appendNodesFromWay(dataSet, nodes, way()->nodes.begin(), way()->nodes.end());
0177             return nodes;
0178         }
0179         case Type::Relation:
0180         {
0181             if (tagValue("type") != "multipolygon") {
0182                 return {};
0183             }
0184 
0185             // collect the relevant ways
0186             std::vector<const Way*> ways;
0187             for (const auto &member : relation()->members) {
0188                 if (std::strcmp(member.role().name(), "outer") != 0) {
0189                     continue;
0190                 }
0191                 if (auto way = dataSet.way(member.id)) {
0192                     ways.push_back(way);
0193                 }
0194             }
0195 
0196             // stitch them together (there is no well-defined order)
0197             std::vector<const Node*> nodes;
0198             assemblePath(dataSet, std::move(ways), nodes);
0199             return nodes;
0200         }
0201     }
0202 
0203     Q_UNREACHABLE();
0204     return {};
0205 }
0206 
0207 void Element::recomputeBoundingBox(const DataSet &dataSet)
0208 {
0209     switch (type()) {
0210         case Type::Null:
0211         case Type::Node:
0212             break;
0213         case Type::Way:
0214             way()->bbox = std::accumulate(way()->nodes.begin(), way()->nodes.end(), OSM::BoundingBox(), [&dataSet](auto bbox, auto nodeId) {
0215                 if (auto node = dataSet.node(nodeId)) {
0216                     return OSM::unite(bbox, {node->coordinate, node->coordinate});
0217                 }
0218                 return bbox;
0219             });
0220             break;
0221         case Type::Relation:
0222             relation()->bbox = {};
0223             for_each_member(dataSet, *relation(), [this, &dataSet](auto mem) {
0224                 mem.recomputeBoundingBox(dataSet);
0225                 relation()->bbox = OSM::unite(relation()->bbox, mem.boundingBox());
0226             });
0227             break;
0228     }
0229 }
0230 
0231 
0232 UniqueElement::~UniqueElement()
0233 {
0234     switch (m_element.type()) {
0235         case OSM::Type::Null:
0236             break;
0237         case OSM::Type::Node:
0238             delete m_element.node();
0239             break;
0240         case OSM::Type::Way:
0241             delete m_element.way();
0242             break;
0243         case OSM::Type::Relation:
0244             delete m_element.relation();
0245             break;
0246     }
0247 }
0248 
0249 void UniqueElement::setId(Id id)
0250 {
0251     switch (m_element.type()) {
0252         case OSM::Type::Null:
0253             return;
0254         case OSM::Type::Node:
0255             const_cast<Node*>(m_element.node())->id = id;
0256             break;
0257         case OSM::Type::Way:
0258             const_cast<Way*>(m_element.way())->id = id;
0259             break;
0260         case OSM::Type::Relation:
0261             const_cast<Relation*>(m_element.relation())->id = id;
0262             break;
0263     }
0264 }
0265 
0266 void UniqueElement::setTagValue(TagKey key, QByteArray &&value)
0267 {
0268     switch (m_element.type()) {
0269         case OSM::Type::Null:
0270             return;
0271         case OSM::Type::Node:
0272             OSM::setTagValue(*const_cast<Node*>(m_element.node()), key, std::move(value));
0273             break;
0274         case OSM::Type::Way:
0275             OSM::setTagValue(*const_cast<Way*>(m_element.way()), key, std::move(value));
0276             break;
0277         case OSM::Type::Relation:
0278             OSM::setTagValue(*const_cast<Relation*>(m_element.relation()), key, std::move(value));
0279             break;
0280     }
0281 }
0282 
0283 void UniqueElement::removeTag(TagKey key)
0284 {
0285     switch (m_element.type()) {
0286         case OSM::Type::Null:
0287             return;
0288         case OSM::Type::Node:
0289             OSM::removeTag(*const_cast<Node*>(m_element.node()), key);
0290             break;
0291         case OSM::Type::Way:
0292             OSM::removeTag(*const_cast<Way*>(m_element.way()), key);
0293             break;
0294         case OSM::Type::Relation:
0295             OSM::removeTag(*const_cast<Relation*>(m_element.relation()), key);
0296             break;
0297     }
0298 }
0299 
0300 UniqueElement OSM::copy_element(Element e)
0301 {
0302     switch (e.type()) {
0303         case OSM::Type::Null:
0304             return UniqueElement();
0305         case OSM::Type::Node:
0306             return UniqueElement(new Node(*e.node()));
0307         case OSM::Type::Way:
0308             return UniqueElement(new Way(*e.way()));
0309         case OSM::Type::Relation:
0310             return UniqueElement(new Relation(*e.relation()));
0311     }
0312     Q_UNREACHABLE();
0313     return UniqueElement();
0314 }