/** * Add a node to the block using DenseNodes. * * @param node The node to add. */ void write_dense_node(const shared_ptr<Osmium::OSM::Node const>& node) { // add a DenseNodes-Section to the PrimitiveGroup OSMPBF::DenseNodes* dense = pbf_nodes->mutable_dense(); // copy the id, delta encoded dense->add_id(m_delta_id.update(node->id())); // copy the longitude, delta encoded dense->add_lon(m_delta_lon.update(lonlat2int(node->get_lon()))); // copy the latitude, delta encoded dense->add_lat(m_delta_lat.update(lonlat2int(node->get_lat()))); // in the densenodes structure keys and vals are encoded in an intermixed // array, individual nodes are seperated by a value of 0 (0 in the StringTable // is always unused) // so for three nodes the keys_vals array may look like this: 3 5 2 1 0 0 8 5 // the first node has two tags (3=>5 and 2=>1), the second node has does not // have any tags and the third node has a single tag (8=>5) Osmium::OSM::TagList::const_iterator end = node->tags().end(); for (Osmium::OSM::TagList::const_iterator it = node->tags().begin(); it != end; ++it) { dense->add_keys_vals(string_table.record_string(it->key())); dense->add_keys_vals(string_table.record_string(it->value())); } dense->add_keys_vals(0); if (should_add_metadata()) { // add a DenseInfo-Section to the PrimitiveGroup OSMPBF::DenseInfo* denseinfo = dense->mutable_denseinfo(); denseinfo->add_version(node->version()); if (m_add_visible) { denseinfo->add_visible(node->visible()); } // copy the timestamp, delta encoded denseinfo->add_timestamp(m_delta_timestamp.update(timestamp2int(node->timestamp()))); // copy the changeset, delta encoded denseinfo->add_changeset(m_delta_changeset.update(node->changeset())); // copy the user id, delta encoded denseinfo->add_uid(m_delta_uid.update(node->uid())); // record the user-name to the interim stringtable and copy the // interim string-id to the pbf-object denseinfo->add_user_sid(string_table.record_string(node->user())); } }
void OsmPbfWriterPrivate::writeBlock(bool forceWrite) { if ( (forceWrite && (nodesList.count() + waysList.count() + relationsList.count() > 0) ) || (nodesList.count() + waysList.count() + relationsList.count() >= entitiesPerBlockLimit) ) { OSMPBF::PrimitiveBlock currentFileBlockParsed; int32_t granularityCoordinate = 100, granularityDate = 1000; int64_t offsetLat = 0, offsetLon = 0; //FIXME: keep order of addition //Extract all strings to hash for future reference //FIXME extract granularities and offset QHash<QString, int32_t> stringTableHash; for (QList<OsmStructures::Node>::const_iterator iNode = nodesList.constBegin(); iNode != nodesList.constEnd() ; ++iNode) addEntityStringsToTable(&stringTableHash, *iNode); for (QList<OsmStructures::Way>::const_iterator iWay = waysList.constBegin(); iWay != waysList.constEnd() ; ++iWay) addEntityStringsToTable(&stringTableHash, *iWay); for (QList<OsmStructures::Relation>::const_iterator iRelation = relationsList.constBegin(); iRelation != relationsList.constEnd() ; ++iRelation) { addEntityStringsToTable(&stringTableHash, *iRelation); for (QSet<OsmStructures::RelationMember>::const_iterator iRelationMember = iRelation->members.constBegin(); iRelationMember != iRelation->members.constEnd() ; ++iRelationMember) { addStringToTable(&stringTableHash, iRelationMember->role); } } //Create list of strings from hash (sorted by value) int32_t stringsCount = stringTableHash.count() + 1; QScopedArrayPointer<QString> stringTableList(new QString[stringsCount]); stringTableList[0] = QString(""); for (QHash<QString, int32_t>::const_iterator iString = stringTableHash.constBegin() ; iString != stringTableHash.constEnd() ; ++iString) { stringTableList[iString.value()] = iString.key(); } //Write list of string to block stringtable for (int iIndex = 0 ; iIndex < stringsCount ; iIndex++) { currentFileBlockParsed.mutable_stringtable()->add_s(stringTableList[iIndex].toUtf8().data(), stringTableList[iIndex].toUtf8().length()); } stringTableList.reset(); //Write granularities and offsets if (granularityCoordinate != 100) currentFileBlockParsed.set_granularity(granularityCoordinate); if (granularityDate != 1000) currentFileBlockParsed.set_date_granularity(granularityDate); if (offsetLat != 0) currentFileBlockParsed.set_lat_offset(offsetLat); if (offsetLon != 0) currentFileBlockParsed.set_lon_offset(offsetLon); //Write nodes if (nodesList.count() > 0) { OSMPBF::PrimitiveGroup* nodesGroup = currentFileBlockParsed.add_primitivegroup(); int64_t denseId = 0, denseLat = 0, denseLon = 0; int64_t denseTimestamp = 0, denseChangeset = 0, denseUid = 0, denseUser = 0; for (QList<OsmStructures::Node>::const_iterator iNode = nodesList.constBegin(); iNode != nodesList.constEnd() ; ++iNode) { if ( ( (iNode->getLatNanoDegree() - offsetLat) % granularityCoordinate ) || (iNode->getLonNanoDegree() - offsetLon) % granularityCoordinate ) qFatal("Loosing precision"); int64_t lat_int = (iNode->getLatNanoDegree() - offsetLat) / granularityCoordinate; int64_t lon_int = (iNode->getLonNanoDegree() - offsetLon) / granularityCoordinate; if (useDenseNodes) { OSMPBF::DenseNodes* pbfDense = nodesGroup->mutable_dense(); pbfDense->add_id(iNode->id - denseId); pbfDense->add_lat(lat_int - denseLat); pbfDense->add_lon(lon_int - denseLon); denseId = iNode->id; denseLat = lat_int; denseLon = lon_int; pbfDense->mutable_denseinfo()->add_version(iNode->version); if (iNode->timestamp.toMSecsSinceEpoch() % granularityDate) qFatal("Loosing precision"); int64_t timestamp_value = iNode->timestamp.toMSecsSinceEpoch() / granularityDate; int32_t user_sid = stringTableHash.value(iNode->user); pbfDense->mutable_denseinfo()->add_timestamp(timestamp_value - denseTimestamp); pbfDense->mutable_denseinfo()->add_changeset(iNode->changeset - denseChangeset); pbfDense->mutable_denseinfo()->add_uid(iNode->uid - denseUid); pbfDense->mutable_denseinfo()->add_user_sid(user_sid - denseUser); denseTimestamp = timestamp_value; denseChangeset = iNode->changeset; denseUid = iNode->uid; denseUser = user_sid; for (QHash<QString, QString>::const_iterator iTagString = iNode->tags.constBegin() ; iTagString != iNode->tags.constEnd() ; ++iTagString) { pbfDense->add_keys_vals(stringTableHash.value(iTagString.key())); pbfDense->add_keys_vals(stringTableHash.value(iTagString.value())); } pbfDense->add_keys_vals(0); } else { OSMPBF::Node* pbfNode = nodesGroup->add_nodes(); pbfNode->set_id(iNode->id); pbfNode->set_lon(lat_int); pbfNode->set_lat(lon_int); packEntityInfo(pbfNode->mutable_info(), *iNode, granularityDate, stringTableHash); for (QHash<QString, QString>::const_iterator iTagString = iNode->tags.constBegin() ; iTagString != iNode->tags.constEnd() ; ++iTagString) { pbfNode->add_keys(stringTableHash.value(iTagString.key())); pbfNode->add_vals(stringTableHash.value(iTagString.value())); } } } } //write ways if (waysList.count() > 0) { OSMPBF::PrimitiveGroup* waysGroup = currentFileBlockParsed.add_primitivegroup(); for (QList<OsmStructures::Way>::const_iterator iWay = waysList.constBegin(); iWay != waysList.constEnd() ; ++iWay) { OSMPBF::Way* pbfWay = waysGroup->add_ways(); pbfWay->set_id(iWay->id); int64_t currentNodeId = 0; for (QList<int64_t>::const_iterator iNodeId = iWay->nodes.constBegin() ; iNodeId != iWay->nodes.constEnd() ; ++iNodeId) { pbfWay->add_refs(*iNodeId - currentNodeId); currentNodeId = *iNodeId; } packEntityInfo(pbfWay->mutable_info(), *iWay, granularityDate, stringTableHash); for (QHash<QString, QString>::const_iterator iTagString = iWay->tags.constBegin() ; iTagString != iWay->tags.constEnd() ; ++iTagString) { pbfWay->add_keys(stringTableHash.value(iTagString.key())); pbfWay->add_vals(stringTableHash.value(iTagString.value())); } } } //write relations if (relationsList.count() > 0) { OSMPBF::PrimitiveGroup* relationsGroup = currentFileBlockParsed.add_primitivegroup(); for (QList<OsmStructures::Relation>::const_iterator iRelation = relationsList.constBegin(); iRelation != relationsList.constEnd() ; ++iRelation) { OSMPBF::Relation *pbfRelation = relationsGroup->add_relations(); pbfRelation->set_id(iRelation->id); int64_t currentMemberId = 0; for (QSet<OsmStructures::RelationMember>::const_iterator iRelationMember = iRelation->members.constBegin(); iRelationMember != iRelation->members.constEnd() ; ++iRelationMember) { pbfRelation->add_roles_sid(stringTableHash.value(iRelationMember->role)); pbfRelation->add_memids(iRelationMember->memberRef.id - currentMemberId); currentMemberId = iRelationMember->memberRef.id; OSMPBF::Relation_MemberType currentType; switch (iRelationMember->memberRef.type) { case OsmStructures::EnumOsmNode: currentType = OSMPBF::Relation_MemberType_NODE; break; case OsmStructures::EnumOsmWay: currentType = OSMPBF::Relation_MemberType_WAY; break; case OsmStructures::EnumOsmRelation: currentType = OSMPBF::Relation_MemberType_RELATION; break; default: throw std::exception(); break; } pbfRelation->add_types(currentType); } packEntityInfo(pbfRelation->mutable_info(), *iRelation, granularityDate, stringTableHash); for (QHash<QString, QString>::const_iterator iTagString = iRelation->tags.constBegin() ; iTagString != iRelation->tags.constEnd() ; ++iTagString) { pbfRelation->add_keys(stringTableHash.value(iTagString.key())); pbfRelation->add_vals(stringTableHash.value(iTagString.value())); } } } QByteArray currentFileBlockPacked = packPbfMessageToArray(currentFileBlockParsed); writeFileblock("OSMData", currentFileBlockPacked); nodesList.clear(); waysList.clear(); relationsList.clear(); } }