KOSMIndoorMap

o5mwriter.cpp
1/*
2 SPDX-FileCopyrightText: 2023 Volker Krause <vkrause@kde.org>
3 SPDX-License-Identifier: LGPL-2.0-or-later
4*/
5
6#include "o5mwriter.h"
7#include "o5m.h"
8#include "datatypes.h"
9
10#include <QBuffer>
11#include <QIODevice>
12
13using namespace OSM;
14
15static void writeByte(uint8_t b, QIODevice *io)
16{
17 io->write(reinterpret_cast<const char*>(&b), 1);
18}
19
20static void writeUnsigned(uint64_t n, QIODevice *io)
21{
22 do {
23 uint8_t b = ((n >> 7) > 0 ? O5M_NUMBER_CONTINUATION : 0) | (n & O5M_NUMBER_MASK);
24 writeByte(b, io);
25 n >>= 7;
26 } while (n > 0);
27}
28
29static void writeSigned(int64_t n, QIODevice *io)
30{
31 uint64_t u = n < 0 ? (-n - 1) : n;
32 u <<= 1;
33 u |= n < 0 ? O5M_NUMBER_SIGNED_BIT : 0;
34 writeUnsigned(u, io);
35}
36
37static void writeHeader(QIODevice *io)
38{
39 writeByte(O5M_BLOCK_RESET, io);
40 writeByte(O5M_BLOCK_HEADER, io);
41 writeByte(4, io);
42 io->write(O5M_HEADER, 4);
43}
44
45static void writeTrailer(QIODevice *io)
46{
47 writeByte(O5M_TRAILER, io);
48}
49
50void O5mWriter::writeToIODevice(const OSM::DataSet& dataSet, QIODevice* io)
51{
52 writeHeader(io);
53 writeNodes(dataSet, io);
54 writeWays(dataSet, io);
55 writeRelations(dataSet, io);
56 writeTrailer(io);
57
58 m_stringTable.clear();
59}
60
61void O5mWriter::writeNodes(const OSM::DataSet &dataSet, QIODevice *io)
62{
63 if (dataSet.nodes.empty()) {
64 return;
65 }
66
67 writeByte(O5M_BLOCK_RESET, io);
68 m_stringTable.clear();
69
70 OSM::Id prevId = 0;
71 int64_t prevLat = 900'000'000ll;
72 int64_t prevLon = 1'800'000'000ll;
73
74 QByteArray bufferData;
75 QBuffer buffer(&bufferData);
76 for(auto const &node: dataSet.nodes) {
77 bufferData.clear();
78 buffer.open(QIODevice::WriteOnly);
79 writeByte(O5M_BLOCK_NODE, io);
80
81 writeSigned((int64_t)node.id - (int64_t)prevId, &buffer);
82 prevId = node.id;
83
84 writeByte(0x0, &buffer);
85 writeSigned((int64_t)node.coordinate.longitude - prevLon, &buffer);
86 prevLon = node.coordinate.longitude;
87 writeSigned((int64_t)node.coordinate.latitude - prevLat, &buffer);
88 prevLat = node.coordinate.latitude;
89
90 writeTags(node, &buffer);
91
92 buffer.close();
93 writeUnsigned(bufferData.size(), io);
94 io->write(bufferData.constData(), bufferData.size());
95 }
96}
97
98void O5mWriter::writeWays(const OSM::DataSet &dataSet, QIODevice *io)
99{
100 if (dataSet.ways.empty()) {
101 return;
102 }
103
104 writeByte(O5M_BLOCK_RESET, io);
105 m_stringTable.clear();
106 OSM::Id prevId = 0;
107 OSM::Id prevNodeId = 0;
108
109 QByteArray bufferData;
110 QBuffer buffer(&bufferData);
111 QByteArray referencesBufferData;
112 QBuffer referencesBuffer(&referencesBufferData);
113
114 for (auto const &way: dataSet.ways) {
115 writeByte(O5M_BLOCK_WAY, io);
116
117 bufferData.clear();
118 buffer.open(QIODevice::WriteOnly);
119 writeSigned((int64_t)way.id - (int64_t)prevId, &buffer);
120 prevId = way.id;
121 writeByte(0x0, &buffer);
122
123 referencesBufferData.clear();
124 referencesBuffer.open(QIODevice::WriteOnly);
125 for (const auto &node : way.nodes) {
126 writeSigned((int64_t)node - (int64_t)prevNodeId, &referencesBuffer);
127 prevNodeId = node;
128 }
129 referencesBuffer.close();
130 writeUnsigned(referencesBufferData.size(), &buffer);
131 buffer.write(referencesBufferData.constData(), referencesBufferData.size());
132 writeTags(way, &buffer);
133 buffer.close();
134 writeUnsigned(bufferData.size(), io);
135 io->write(bufferData.constData(), bufferData.size());
136 }
137}
138
139void O5mWriter::writeRelations(const OSM::DataSet &dataSet, QIODevice *io)
140{
141 if (dataSet.relations.empty()) {
142 return;
143 }
144
145 writeByte(O5M_BLOCK_RESET, io);
146 m_stringTable.clear();
147 OSM::Id prevId = 0;
148 OSM::Id prevMemberId[3] = { 0, 0, 0 };
149
150 QByteArray bufferData;
151 QBuffer buffer(&bufferData);
152 QByteArray referencesBufferData;
153 QBuffer referencesBuffer(&referencesBufferData);
154 QByteArray role;
155
156 for (auto const &relation: dataSet.relations) {
157 writeByte(O5M_BLOCK_RELATION, io);
158
159 bufferData.clear();
160 buffer.open(QIODevice::WriteOnly);
161
162 writeSigned((int64_t)relation.id - (int64_t)prevId, &buffer);
163 prevId = relation.id;
164 writeByte(0x0, &buffer);
165
166 referencesBufferData.clear();
167 referencesBuffer.open(QIODevice::WriteOnly);
168
169 for (const auto &member : relation.members) {
170 role.clear();
171 switch (member.type()) {
172 case OSM::Type::Node:
173 writeSigned((int64_t)member.id - (int64_t)prevMemberId[0], &referencesBuffer);
174 prevMemberId[0] = member.id;
175 role += (const char)O5M_MEMTYPE_NODE;
176 role += member.role().name();
177 writeStringPair(role.constData(), nullptr, &referencesBuffer);
178 break;
179 case OSM::Type::Way:
180 writeSigned((int64_t)member.id - (int64_t)prevMemberId[1], &referencesBuffer);
181 prevMemberId[1] = member.id;
182 role += (const char)O5M_MEMTYPE_WAY;
183 role += member.role().name();
184 writeStringPair(role.constData(), nullptr, &referencesBuffer);
185 break;
186 case OSM::Type::Relation:
187 writeSigned((int64_t)member.id - (int64_t)prevMemberId[2], &referencesBuffer);
188 prevMemberId[2] = member.id;
189 role += (const char)O5M_MEMTYPE_RELATION;
190 role += member.role().name();
191 writeStringPair(role.constData(), nullptr, &referencesBuffer);
192 break;
193 case OSM::Type::Null:
194 assert(false);
195 break;
196 }
197 }
198
199 referencesBuffer.close();
200 writeUnsigned(referencesBufferData.size(), &buffer);
201 buffer.write(referencesBufferData.constData(), referencesBufferData.size());
202 writeTags(relation, &buffer);
203 buffer.close();
204 writeUnsigned(bufferData.size(), io);
205 io->write(bufferData.constData(), bufferData.size());
206 }
207}
208
209template <typename T>
210void O5mWriter::writeTags(const T &elem, QIODevice *io)
211{
212 for (auto &tag : elem.tags) {
213 writeStringPair(tag.key.name(), tag.value.constData(), io);
214 }
215}
216
217void O5mWriter::writeStringPair(const char *s1, const char *s2, QIODevice *io)
218{
219 assert(s1);
220 O5mStringPair p;
221 p.s1 = s1;
222 if (s2) {
223 p.s2 = s2;
224 }
225 const auto it = m_stringTable.find(p);
226 if (it != m_stringTable.end()) {
227 writeUnsigned(m_stringTable.size() - it->second, io);
228 } else {
229 writeByte(0x0, io);
230 io->write(s1);
231 writeByte(0x0, io);
232 if (s2) {
233 io->write(s2);
234 writeByte(0x0, io);
235 }
236 if ((std::strlen(s1) + (s2 ? std::strlen(s2) : 0) <= O5M_STRING_TABLE_MAXLEN) && (m_stringTable.size() <= O5M_STRING_TABLE_SIZE)) {
237 m_stringTable[p] = m_stringTable.size();
238 }
239 }
240}
A set of nodes, ways and relations.
Definition datatypes.h:340
Low-level types and functions to work with raw OSM data as efficiently as possible.
int64_t Id
OSM element identifier.
Definition datatypes.h:30
Common declarations for O5M file format I/O.
void clear()
const char * constData() const const
qsizetype size() const const
qint64 write(const QByteArray &data)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:20:03 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.