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> &registry)
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> &registry) 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 }