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 }