File indexing completed on 2024-12-01 10:29:53
0001 /* 0002 SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "datatypes.h" 0008 0009 using namespace OSM; 0010 0011 DataSet::DataSet() = default; 0012 DataSet::DataSet(DataSet &&) = default; 0013 DataSet::~DataSet() 0014 { 0015 std::for_each(m_stringPool.begin(), m_stringPool.end(), free); 0016 } 0017 0018 DataSet& DataSet::operator=(DataSet &&) = default; 0019 0020 template<typename T> 0021 T DataSet::makeStringKey(const char *name, DataSet::StringMemory memOpt, std::vector<T> ®istry) 0022 { 0023 const auto it = std::lower_bound(registry.begin(), registry.end(), name, [](T lhs, const char *rhs) { 0024 return std::strcmp(lhs.name(), rhs) < 0; 0025 }); 0026 if (it == registry.end() || std::strcmp((*it).name(), name) != 0) { 0027 if (memOpt == StringIsTransient) { 0028 auto s = strdup(name); 0029 m_stringPool.push_back(s); 0030 name = s; 0031 } 0032 T k(name); 0033 registry.insert(it, k); 0034 return k; 0035 } 0036 return (*it); 0037 } 0038 0039 TagKey DataSet::makeTagKey(const char *keyName, DataSet::StringMemory keyMemOpt) 0040 { 0041 return makeStringKey(keyName, keyMemOpt, m_tagKeyRegistry); 0042 } 0043 0044 Role DataSet::makeRole(const char *roleName, DataSet::StringMemory memOpt) 0045 { 0046 return makeStringKey(roleName, memOpt, m_roleRegistry); 0047 } 0048 0049 template <typename T> 0050 T DataSet::stringKey(const char *name, const std::vector<T> ®istry) const 0051 { 0052 const auto it = std::lower_bound(registry.begin(), registry.end(), name, [](T lhs, const char *rhs) { 0053 return std::strcmp(lhs.name(), rhs) < 0; 0054 }); 0055 if (it == registry.end() || std::strcmp((*it).name(), name) != 0) { 0056 return {}; 0057 } 0058 return (*it); 0059 } 0060 0061 TagKey DataSet::tagKey(const char *keyName) const 0062 { 0063 return stringKey(keyName, m_tagKeyRegistry); 0064 } 0065 0066 Role DataSet::role(const char *roleName) const 0067 { 0068 return stringKey(roleName, m_roleRegistry); 0069 } 0070 0071 const Node* DataSet::node(Id id) const 0072 { 0073 const auto it = std::lower_bound(nodes.begin(), nodes.end(), id); 0074 if (it != nodes.end() && (*it).id == id) { 0075 return &(*it); 0076 } 0077 return nullptr; 0078 } 0079 0080 const Way* DataSet::way(Id id) const 0081 { 0082 const auto it = std::lower_bound(ways.begin(), ways.end(), id); 0083 if (it != ways.end() && (*it).id == id) { 0084 return &(*it); 0085 } 0086 return nullptr; 0087 } 0088 0089 Way* DataSet::way(Id id) 0090 { 0091 const auto it = std::lower_bound(ways.begin(), ways.end(), id); 0092 if (it != ways.end() && (*it).id == id) { 0093 return &(*it); 0094 } 0095 return nullptr; 0096 } 0097 0098 const Relation* DataSet::relation(Id id) const 0099 { 0100 const auto it = std::lower_bound(relations.begin(), relations.end(), id); 0101 if (it != relations.end() && (*it).id == id) { 0102 return &(*it); 0103 } 0104 return nullptr; 0105 } 0106 0107 void DataSet::addNode(Node &&node) 0108 { 0109 const auto it = std::lower_bound(nodes.begin(), nodes.end(), node); 0110 if (it != nodes.end() && (*it).id == node.id) { 0111 // do we need to merge something here? 0112 return; 0113 } 0114 nodes.insert(it, std::move(node)); 0115 } 0116 0117 void DataSet::addWay(Way &&way) 0118 { 0119 const auto it = std::lower_bound(ways.begin(), ways.end(), way); 0120 if (it != ways.end() && (*it).id == way.id) { 0121 // already there? 0122 return; 0123 } 0124 ways.insert(it, std::move(way)); 0125 } 0126 0127 void DataSet::addRelation(Relation &&rel) 0128 { 0129 const auto it = std::lower_bound(relations.begin(), relations.end(), rel); 0130 if (it != relations.end() && (*it).id == rel.id) { 0131 // do we need to merge something here? 0132 return; 0133 } 0134 relations.insert(it, std::move(rel)); 0135 } 0136 0137 OSM::Id DataSet::nextInternalId() const 0138 { 0139 static OSM::Id nextId = 0; 0140 return --nextId; 0141 } 0142 0143 // resolve ids for elements split in Marble vector tiles 0144 template <typename T> 0145 static QString actualIdString(const T &elem) 0146 { 0147 const auto mxoid = OSM::tagValue(elem, "mx:oid"); 0148 return mxoid.isEmpty() ? QString::number(elem.id) : QString::fromUtf8(mxoid); 0149 } 0150 0151 QString OSM::Node::url() const 0152 { 0153 return QStringLiteral("https://openstreetmap.org/node/") + actualIdString(*this); 0154 } 0155 0156 bool OSM::Way::isClosed() const 0157 { 0158 return nodes.size() >= 2 && nodes.front() == nodes.back(); 0159 } 0160 0161 QString OSM::Way::url() const 0162 { 0163 return QStringLiteral("https://openstreetmap.org/way/") + actualIdString(*this); 0164 } 0165 0166 QString OSM::Relation::url() const 0167 { 0168 return QStringLiteral("https://openstreetmap.org/relation/") + actualIdString(*this); 0169 } 0170 0171 QDebug operator<<(QDebug debug, OSM::Coordinate coord) 0172 { 0173 QDebugStateSaver saver(debug); 0174 debug.nospace() << '(' << coord.latF() << ',' << coord.lonF() << ')'; 0175 return debug; 0176 } 0177 0178 QDebug operator<<(QDebug debug, OSM::BoundingBox bbox) 0179 { 0180 QDebugStateSaver saver(debug); 0181 debug.nospace() << '[' << bbox.min.latF() << ',' << bbox.min.lonF() << '|' << bbox.max.latF() << ',' << bbox.max.lonF() << ']'; 0182 return debug; 0183 }