6#include "osmpbfwriter.h"
9#include "fileformat.pb.h"
10#include "osmformat.pb.h"
19static constexpr const std::size_t BLOCK_SIZE_LIMIT = 16'777'216;
21OsmPbfWriter::OsmPbfWriter() =
default;
22OsmPbfWriter::~OsmPbfWriter() =
default;
29 writeRelations(dataSet);
36void OsmPbfWriter::writeNodes(
const OSM::DataSet &dataSet)
38 if (dataSet.nodes.empty()) {
43 int64_t prevLat = 900'000'000ll;
44 int64_t prevLon = 1'800'000'000ll;
46 OSMPBF::DenseNodes *denseBlock =
nullptr;
47 for(
auto const &node: dataSet.nodes) {
48 createBlockIfNeeded();
50 denseBlock = m_block->add_primitivegroup()->mutable_dense();
53 denseBlock->add_id(node.id - prevId);
56 denseBlock->add_lat((int64_t)node.coordinate.latitude - prevLat);
57 prevLat = node.coordinate.latitude;
58 denseBlock->add_lon((int64_t)node.coordinate.longitude - prevLon);
59 prevLon = node.coordinate.longitude;
61 for (
const auto &tag : node.tags) {
62 denseBlock->add_keys_vals(stringTableEntry(tag.key.name()));
63 denseBlock->add_keys_vals(stringTableEntry(tag.value.constData()));
64 m_blockSizeEstimate += 2 *
sizeof(int32_t);
67 denseBlock->add_keys_vals(0);
68 m_blockSizeEstimate += 3 *
sizeof(int64_t) +
sizeof(int32_t);
70 if (blockSizeLimitReached()) {
79 OSMPBF::PrimitiveGroup *group =
nullptr;
80 for(
auto const &way : dataSet.ways) {
81 createBlockIfNeeded();
83 group = m_block->add_primitivegroup();
86 auto w = group->add_ways();
88 m_blockSizeEstimate +=
sizeof(int64_t);
91 for (
const auto &
id : way.nodes) {
92 w->add_refs(
id - prevId);
94 m_blockSizeEstimate +=
sizeof(int64_t);
96 for (
const auto &tag : way.tags) {
97 w->add_keys(stringTableEntry(tag.key.name()));
98 w->add_vals(stringTableEntry(tag.value.constData()));
99 m_blockSizeEstimate += 2 *
sizeof(int32_t);
102 if (blockSizeLimitReached()) {
109static OSMPBF::Relation_MemberType pbfMemberType(
OSM::Type t)
112 case OSM::Type::Null:
114 case OSM::Type::Node:
115 return OSMPBF::Relation_MemberType::Relation_MemberType_NODE;
117 return OSMPBF::Relation_MemberType::Relation_MemberType_WAY;
118 case OSM::Type::Relation:
119 return OSMPBF::Relation_MemberType::Relation_MemberType_RELATION;
121 return OSMPBF::Relation_MemberType::Relation_MemberType_NODE;
124void OsmPbfWriter::writeRelations(
const OSM::DataSet &dataSet)
126 OSMPBF::PrimitiveGroup *group =
nullptr;
127 for (
const auto &rel :dataSet.relations) {
128 createBlockIfNeeded();
130 group = m_block->add_primitivegroup();
133 auto r = group->add_relations();
135 m_blockSizeEstimate +=
sizeof(int64_t);
137 for (
const auto &tag : rel.tags) {
138 r->add_keys(stringTableEntry(tag.key.name()));
139 r->add_vals(stringTableEntry(tag.value.constData()));
140 m_blockSizeEstimate += 2 *
sizeof(int32_t);
143 int64_t prevMemId = 0;
144 for (
const auto &mem : rel.members) {
145 r->add_roles_sid(stringTableEntry(mem.role().name()));
146 r->add_memids(mem.id - prevMemId);
148 r->add_types(pbfMemberType(mem.type()));
149 m_blockSizeEstimate += 2*
sizeof(int32_t) +
sizeof(int64_t);
152 if (blockSizeLimitReached()) {
159int32_t OsmPbfWriter::stringTableEntry(
const char *s)
162 const auto it = m_stringTable.find(s);
163 if (it == m_stringTable.end()) {
164 auto st = m_block->mutable_stringtable();
166 m_stringTable[s] = st->s_size() - 1;
167 m_blockSizeEstimate += std::strlen(s) + 1 +
sizeof(int32_t);
168 return st->s_size() - 1;
174void OsmPbfWriter::createBlockIfNeeded()
177 m_block = std::make_unique<OSMPBF::PrimitiveBlock>();
178 m_blockSizeEstimate = 0;
179 m_block->mutable_stringtable()->add_s(
"");
183bool OsmPbfWriter::blockSizeLimitReached()
const
185 return m_blockSizeEstimate >BLOCK_SIZE_LIMIT;
188void OsmPbfWriter::writeBlob()
191 auto rawBlobData = m_block->SerializeAsString();
192 auto zlibBlobData = blob.mutable_zlib_data();
193 zlibBlobData->resize(32 * 1024ul * 1024ul);
196 zStream.next_in = (uint8_t*)rawBlobData.data();
197 zStream.avail_in = rawBlobData.size();
198 zStream.next_out = (uint8_t*)zlibBlobData->data();
199 zStream.avail_out = zlibBlobData->size();
200 zStream.zalloc =
nullptr;
201 zStream.zfree =
nullptr;
202 zStream.opaque =
nullptr;
203 deflateInit(&zStream, Z_DEFAULT_COMPRESSION);
205 const auto ret = deflate(&zStream, Z_FINISH);
206 if (ret == Z_STREAM_END) {
210 qWarning() <<
"zlib compression error!" << ret;
213 if (zStream.avail_out == 0) {
217 qFatal(
"zlib output buffer underrun");
221 zlibBlobData->resize(zlibBlobData->size() - zStream.avail_out);
223 deflateEnd(&zStream);
224 blob.set_raw_size((int32_t)rawBlobData.size());
226 OSMPBF::BlobHeader header;
227 header.set_type(
"OSMData");
228 header.set_datasize((int32_t)blob.ByteSizeLong());
230 auto blobHeaderSize = (int32_t)header.ByteSizeLong();
231 blobHeaderSize = qToBigEndian(blobHeaderSize);
232 m_io->
write(
reinterpret_cast<const char*
>(&blobHeaderSize),
sizeof(blobHeaderSize));
233 m_io->
write(header.SerializeAsString().c_str(), header.ByteSizeLong());
234 m_io->
write(blob.SerializeAsString().c_str(), blob.ByteSizeLong());
237 m_blockSizeEstimate = 0;
238 m_stringTable.clear();
A set of nodes, ways and relations.
Low-level types and functions to work with raw OSM data as efficiently as possible.
qint64 write(const QByteArray &data)