1 /*
2 SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6
7 #include "datatypes.h"
8
9 using namespace OSM;
10
11 DataSet::DataSet() = default;
12 DataSet::DataSet(DataSet &&) = default;
~DataSet()13 DataSet::~DataSet()
14 {
15 std::for_each(m_stringPool.begin(), m_stringPool.end(), free);
16 }
17
18 DataSet& DataSet::operator=(DataSet &&) = default;
19
20 template<typename T>
makeStringKey(const char * name,DataSet::StringMemory memOpt,std::vector<T> & registry)21 T DataSet::makeStringKey(const char *name, DataSet::StringMemory memOpt, std::vector<T> ®istry)
22 {
23 const auto it = std::lower_bound(registry.begin(), registry.end(), name, [](T lhs, const char *rhs) {
24 return std::strcmp(lhs.name(), rhs) < 0;
25 });
26 if (it == registry.end() || std::strcmp((*it).name(), name) != 0) {
27 if (memOpt == StringIsTransient) {
28 auto s = strdup(name);
29 m_stringPool.push_back(s);
30 name = s;
31 }
32 T k(name);
33 registry.insert(it, k);
34 return k;
35 }
36 return (*it);
37 }
38
makeTagKey(const char * keyName,DataSet::StringMemory keyMemOpt)39 TagKey DataSet::makeTagKey(const char *keyName, DataSet::StringMemory keyMemOpt)
40 {
41 return makeStringKey(keyName, keyMemOpt, m_tagKeyRegistry);
42 }
43
makeRole(const char * roleName,DataSet::StringMemory memOpt)44 Role DataSet::makeRole(const char *roleName, DataSet::StringMemory memOpt)
45 {
46 return makeStringKey(roleName, memOpt, m_roleRegistry);
47 }
48
49 template <typename T>
stringKey(const char * name,const std::vector<T> & registry) const50 T DataSet::stringKey(const char *name, const std::vector<T> ®istry) const
51 {
52 const auto it = std::lower_bound(registry.begin(), registry.end(), name, [](T lhs, const char *rhs) {
53 return std::strcmp(lhs.name(), rhs) < 0;
54 });
55 if (it == registry.end() || std::strcmp((*it).name(), name) != 0) {
56 return {};
57 }
58 return (*it);
59 }
60
tagKey(const char * keyName) const61 TagKey DataSet::tagKey(const char *keyName) const
62 {
63 return stringKey(keyName, m_tagKeyRegistry);
64 }
65
role(const char * roleName) const66 Role DataSet::role(const char *roleName) const
67 {
68 return stringKey(roleName, m_roleRegistry);
69 }
70
node(Id id) const71 const Node* DataSet::node(Id id) const
72 {
73 const auto it = std::lower_bound(nodes.begin(), nodes.end(), id);
74 if (it != nodes.end() && (*it).id == id) {
75 return &(*it);
76 }
77 return nullptr;
78 }
79
way(Id id) const80 const Way* DataSet::way(Id id) const
81 {
82 const auto it = std::lower_bound(ways.begin(), ways.end(), id);
83 if (it != ways.end() && (*it).id == id) {
84 return &(*it);
85 }
86 return nullptr;
87 }
88
way(Id id)89 Way* DataSet::way(Id id)
90 {
91 const auto it = std::lower_bound(ways.begin(), ways.end(), id);
92 if (it != ways.end() && (*it).id == id) {
93 return &(*it);
94 }
95 return nullptr;
96 }
97
relation(Id id) const98 const Relation* DataSet::relation(Id id) const
99 {
100 const auto it = std::lower_bound(relations.begin(), relations.end(), id);
101 if (it != relations.end() && (*it).id == id) {
102 return &(*it);
103 }
104 return nullptr;
105 }
106
addNode(Node && node)107 void DataSet::addNode(Node &&node)
108 {
109 const auto it = std::lower_bound(nodes.begin(), nodes.end(), node);
110 if (it != nodes.end() && (*it).id == node.id) {
111 // do we need to merge something here?
112 return;
113 }
114 nodes.insert(it, std::move(node));
115 }
116
addWay(Way && way)117 void DataSet::addWay(Way &&way)
118 {
119 const auto it = std::lower_bound(ways.begin(), ways.end(), way);
120 if (it != ways.end() && (*it).id == way.id) {
121 // already there?
122 return;
123 }
124 ways.insert(it, std::move(way));
125 }
126
addRelation(Relation && rel)127 void DataSet::addRelation(Relation &&rel)
128 {
129 const auto it = std::lower_bound(relations.begin(), relations.end(), rel);
130 if (it != relations.end() && (*it).id == rel.id) {
131 // do we need to merge something here?
132 return;
133 }
134 relations.insert(it, std::move(rel));
135 }
136
nextInternalId() const137 OSM::Id DataSet::nextInternalId() const
138 {
139 static OSM::Id nextId = 0;
140 return --nextId;
141 }
142
143 // resolve ids for elements split in Marble vector tiles
144 template <typename T>
actualIdString(const T & elem)145 static QString actualIdString(const T &elem)
146 {
147 const auto mxoid = OSM::tagValue(elem, "mx:oid");
148 return mxoid.isEmpty() ? QString::number(elem.id) : QString::fromUtf8(mxoid);
149 }
150
url() const151 QString OSM::Node::url() const
152 {
153 return QStringLiteral("https://openstreetmap.org/node/") + actualIdString(*this);
154 }
155
isClosed() const156 bool OSM::Way::isClosed() const
157 {
158 return nodes.size() >= 2 && nodes.front() == nodes.back();
159 }
160
url() const161 QString OSM::Way::url() const
162 {
163 return QStringLiteral("https://openstreetmap.org/way/") + actualIdString(*this);
164 }
165
url() const166 QString OSM::Relation::url() const
167 {
168 return QStringLiteral("https://openstreetmap.org/relation/") + actualIdString(*this);
169 }
170
operator <<(QDebug debug,OSM::Coordinate coord)171 QDebug operator<<(QDebug debug, OSM::Coordinate coord)
172 {
173 QDebugStateSaver saver(debug);
174 debug.nospace() << '(' << coord.latF() << ',' << coord.lonF() << ')';
175 return debug;
176 }
177
operator <<(QDebug debug,OSM::BoundingBox bbox)178 QDebug operator<<(QDebug debug, OSM::BoundingBox bbox)
179 {
180 QDebugStateSaver saver(debug);
181 debug.nospace() << '[' << bbox.min.latF() << ',' << bbox.min.lonF() << '|' << bbox.max.latF() << ',' << bbox.max.lonF() << ']';
182 return debug;
183 }
184