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 }