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 #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     return {};
0025 }
0026 
0027 Coordinate Element::center() const
0028 {
0029     switch (type()) {
0030         case Type::Null:
0031             return {};
0032         case Type::Node:
0033             return node()->coordinate;
0034         case Type::Way:
0035             return way()->bbox.center();
0036         case Type::Relation:
0037             return relation()->bbox.center();
0038     }
0039 
0040     return {};
0041 }
0042 
0043 BoundingBox Element::boundingBox() const
0044 {
0045     switch (type()) {
0046         case Type::Null:
0047             return {};
0048         case Type::Node:
0049             return BoundingBox(node()->coordinate, node()->coordinate);
0050         case Type::Way:
0051             return way()->bbox;
0052         case Type::Relation:
0053             return relation()->bbox;
0054     }
0055 
0056     return {};
0057 }
0058 
0059 QByteArray Element::tagValue(TagKey key) const
0060 {
0061     switch (type()) {
0062         case Type::Null:
0063             return {};
0064         case Type::Node:
0065             return OSM::tagValue(*node(), key);
0066         case Type::Way:
0067             return OSM::tagValue(*way(), key);
0068         case Type::Relation:
0069             return OSM::tagValue(*relation(), key);
0070     }
0071 
0072     return {};
0073 }
0074 
0075 QByteArray Element::tagValue(const char *keyName) const
0076 {
0077     switch (type()) {
0078         case Type::Null:
0079             return {};
0080         case Type::Node:
0081             return OSM::tagValue(*node(), keyName);
0082         case Type::Way:
0083             return OSM::tagValue(*way(), keyName);
0084         case Type::Relation:
0085             return OSM::tagValue(*relation(), keyName);
0086     }
0087 
0088     return {};
0089 }
0090 
0091 QByteArray Element::tagValue(const char *keyName, const QLocale &locale) const
0092 {
0093     switch (type()) {
0094         case Type::Null:
0095             return {};
0096         case Type::Node:
0097             return OSM::tagValue(*node(), keyName, locale);
0098         case Type::Way:
0099             return OSM::tagValue(*way(), keyName, locale);
0100         case Type::Relation:
0101             return OSM::tagValue(*relation(), keyName, locale);
0102     }
0103 
0104     return {};
0105 }
0106 
0107 std::vector<Tag>::const_iterator OSM::Element::tagsBegin() const
0108 {
0109     switch (type()) {
0110         case Type::Null:
0111             Q_UNREACHABLE();
0112         case Type::Node:
0113             return node()->tags.begin();
0114         case Type::Way:
0115             return way()->tags.begin();
0116         case Type::Relation:
0117             return relation()->tags.begin();
0118     }
0119     Q_UNREACHABLE();
0120 }
0121 
0122 std::vector<Tag>::const_iterator OSM::Element::tagsEnd() const
0123 {
0124     switch (type()) {
0125         case Type::Null:
0126             Q_UNREACHABLE();
0127         case Type::Node:
0128             return node()->tags.end();
0129         case Type::Way:
0130             return way()->tags.end();
0131         case Type::Relation:
0132             return relation()->tags.end();
0133     }
0134     Q_UNREACHABLE();
0135 }
0136 
0137 QString Element::url() const
0138 {
0139     switch (type()) {
0140         case Type::Null:
0141             return {};
0142         case Type::Node:
0143             return node()->url();
0144         case Type::Way:
0145             return way()->url();
0146         case Type::Relation:
0147             return relation()->url();
0148     }
0149 
0150     return {};
0151 }
0152 
0153 std::vector<const Node*> Element::outerPath(const DataSet &dataSet) const
0154 {
0155     switch (type()) {
0156         case Type::Null:
0157             return {};
0158         case Type::Node:
0159             return {node()};
0160         case Type::Way:
0161         {
0162             std::vector<const Node*> nodes;
0163             appendNodesFromWay(dataSet, nodes, way()->nodes.begin(), way()->nodes.end());
0164             return nodes;
0165         }
0166         case Type::Relation:
0167         {
0168             if (tagValue("type") != "multipolygon") {
0169                 return {};
0170             }
0171 
0172             // collect the relevant ways
0173             std::vector<const Way*> ways;
0174             for (const auto &member : relation()->members) {
0175                 if (std::strcmp(member.role().name(), "outer") != 0) {
0176                     continue;
0177                 }
0178                 if (auto way = dataSet.way(member.id)) {
0179                     ways.push_back(way);
0180                 }
0181             }
0182 
0183             // stitch them together (there is no well-defined order)
0184             std::vector<const Node*> nodes;
0185             assemblePath(dataSet, std::move(ways), nodes);
0186             return nodes;
0187         }
0188     }
0189 
0190     return {};
0191 }
0192 
0193 void Element::recomputeBoundingBox(const DataSet &dataSet)
0194 {
0195     switch (type()) {
0196         case Type::Null:
0197         case Type::Node:
0198             break;
0199         case Type::Way:
0200             way()->bbox = std::accumulate(way()->nodes.begin(), way()->nodes.end(), OSM::BoundingBox(), [&dataSet](auto bbox, auto nodeId) {
0201                 if (auto node = dataSet.node(nodeId)) {
0202                     return OSM::unite(bbox, {node->coordinate, node->coordinate});
0203                 }
0204                 return bbox;
0205             });
0206             break;
0207         case Type::Relation:
0208             relation()->bbox = {};
0209             for_each_member(dataSet, *relation(), [this, &dataSet](auto mem) {
0210                 mem.recomputeBoundingBox(dataSet);
0211                 relation()->bbox = OSM::unite(relation()->bbox, mem.boundingBox());
0212             });
0213             break;
0214     }
0215 }
0216 
0217 
0218 UniqueElement::~UniqueElement()
0219 {
0220     switch (m_element.type()) {
0221         case OSM::Type::Null:
0222             break;
0223         case OSM::Type::Node:
0224             delete m_element.node();
0225             break;
0226         case OSM::Type::Way:
0227             delete m_element.way();
0228             break;
0229         case OSM::Type::Relation:
0230             delete m_element.relation();
0231             break;
0232     }
0233 }
0234 
0235 void UniqueElement::setTagValue(TagKey key, const QByteArray &value)
0236 {
0237     switch (m_element.type()) {
0238         case OSM::Type::Null:
0239             return;
0240         case OSM::Type::Node:
0241             OSM::setTagValue(*const_cast<Node*>(m_element.node()), key, value);
0242             break;
0243         case OSM::Type::Way:
0244             OSM::setTagValue(*const_cast<Way*>(m_element.way()), key, value);
0245             break;
0246         case OSM::Type::Relation:
0247             OSM::setTagValue(*const_cast<Relation*>(m_element.relation()), key, value);
0248             break;
0249     }
0250 }