summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDennis Nienhüser <nienhueser@kde.org>2016-08-07 08:03:14 (GMT)
committerDennis Nienhüser <nienhueser@kde.org>2016-08-07 08:03:14 (GMT)
commita6ce72f9d6002a644c9e684cde6e617cf79b623b (patch)
tree6ac59343d6e66bfc50eb9ed54029ec86b0a8f57c
parent9cf50760efcea2c3ecb75a81b868424b91782f62 (diff)
Basic O5M writer
- produces identical files to osmconvert when only looking at nodes and changing Marble's internal tag representation to keep the order of tags - bounds and version information not implemented yet - basic support for ways and relations, but still differences to osmconvert. Needs further changes in OSM parsing in Marble
-rw-r--r--src/plugins/runner/osm/CMakeLists.txt2
-rw-r--r--src/plugins/runner/osm/OsmRelation.cpp27
-rw-r--r--src/plugins/runner/osm/OsmRelation.h2
-rw-r--r--src/plugins/runner/osm/translators/O5mWriter.cpp297
-rw-r--r--src/plugins/runner/osm/translators/O5mWriter.h51
-rw-r--r--src/plugins/runner/osm/translators/OsmConverter.cpp108
-rw-r--r--src/plugins/runner/osm/translators/OsmConverter.h52
-rw-r--r--src/plugins/runner/osm/translators/OsmDocumentTagTranslator.cpp57
-rw-r--r--src/plugins/runner/osm/translators/OsmDocumentTagTranslator.h4
-rw-r--r--src/plugins/runner/osm/writers/OsmNodeTagWriter.cpp29
-rw-r--r--src/plugins/runner/osm/writers/OsmNodeTagWriter.h7
-rw-r--r--src/plugins/runner/osm/writers/OsmTagTagWriter.cpp4
12 files changed, 551 insertions, 89 deletions
diff --git a/src/plugins/runner/osm/CMakeLists.txt b/src/plugins/runner/osm/CMakeLists.txt
index f5b27ec..c90fe00 100644
--- a/src/plugins/runner/osm/CMakeLists.txt
+++ b/src/plugins/runner/osm/CMakeLists.txt
@@ -17,6 +17,8 @@ set( osm_writers_SRCS
)
set( osm_translators_SRCS
translators/OsmDocumentTagTranslator.cpp
+ translators/O5mWriter.cpp
+ translators/OsmConverter.cpp
)
set( osm_SRCS
diff --git a/src/plugins/runner/osm/OsmRelation.cpp b/src/plugins/runner/osm/OsmRelation.cpp
index 015c80b..1fe5735 100644
--- a/src/plugins/runner/osm/OsmRelation.cpp
+++ b/src/plugins/runner/osm/OsmRelation.cpp
@@ -48,7 +48,7 @@ void OsmRelation::addMember(qint64 reference, const QString &role, const QString
m_members << member;
}
-void OsmRelation::create(GeoDataDocument *document, const OsmWays &ways, const OsmNodes &nodes, QSet<qint64> &usedNodes, QSet<qint64> &usedWays) const
+void OsmRelation::create(GeoDataDocument *document, OsmWays &ways, const OsmNodes &nodes, QSet<qint64> &usedNodes, QSet<qint64> &usedWays) const
{
if (!m_osmData.containsTag("type", "multipolygon")) {
return;
@@ -67,7 +67,8 @@ void OsmRelation::create(GeoDataDocument *document, const OsmWays &ways, const O
mDebug() << "Polygons with " << outer.size() << " ways are not yet supported";
return;
}
- GeoDataFeature::GeoDataVisualCategory outerCategory = OsmPresetLibrary::determineVisualCategory(m_osmData);
+ OsmPlacemarkData osmData = m_osmData;
+ GeoDataFeature::GeoDataVisualCategory outerCategory = OsmPresetLibrary::determineVisualCategory(osmData);
if (outerCategory == GeoDataFeature::None) {
// Try to determine the visual category from the relation members
bool categoriesAreSame = true;
@@ -96,23 +97,24 @@ void OsmRelation::create(GeoDataDocument *document, const OsmWays &ways, const O
// Schedule way for removal: It's a non-styled way only used to create the outer boundary in this polygon
usedWays << wayId;
} // else we keep it
+ foreach(qint64 nodeId, ways[wayId].references()) {
+ ways[wayId].osmData().addNodeReference(nodes[nodeId].coordinates(), nodes[nodeId].osmData());
+ }
}
- if (m_osmData.containsTag("historic", "castle") && m_osmData.containsTag("castle_type", "kremlin")) {
+ if (osmData.containsTag("historic", "castle") && osmData.containsTag("castle_type", "kremlin")) {
outerCategory = GeoDataFeature::None;
}
GeoDataPlacemark* placemark = new GeoDataPlacemark;
- placemark->setName(m_osmData.tagValue("name"));
- placemark->setOsmData(m_osmData);
+ placemark->setName(osmData.tagValue("name"));
placemark->setVisualCategory(outerCategory);
placemark->setStyle( GeoDataStyle::Ptr() );
placemark->setVisible(shouldRender && outerCategory != GeoDataFeature::None);
GeoDataPolygon* polygon = new GeoDataPolygon;
polygon->setOuterBoundary(outer[0]);
- // @todo: How to get the reference here?
- // placemark->osmData().addMemberReference(-1, );
+ osmData.addMemberReference(-1, ways[*outerWays.begin()].osmData());
if (placemark->visualCategory() == GeoDataFeature::Bathymetry) {
// In case of a bathymetry store elevation info since it is required during styling
@@ -127,22 +129,27 @@ void OsmRelation::create(GeoDataDocument *document, const OsmWays &ways, const O
QStringList const innerRoles = QStringList() << "inner";
QSet<qint64> innerWays;
QList<GeoDataLinearRing> inner = rings(innerRoles, ways, nodes, usedNodes, innerWays);
+ int index = 0;
foreach(qint64 wayId, innerWays) {
Q_ASSERT(ways.contains(wayId));
if (OsmPresetLibrary::determineVisualCategory(ways[wayId].osmData()) == GeoDataFeature::None) {
// Schedule way for removal: It's a non-styled way only used to create the inner boundary in this polygon
usedWays << wayId;
}
+ foreach(qint64 nodeId, ways[wayId].references()) {
+ ways[wayId].osmData().addNodeReference(nodes[nodeId].coordinates(), nodes[nodeId].osmData());
+ }
+ osmData.addMemberReference(index, ways[wayId].osmData());
+ ++index;
}
foreach(const GeoDataLinearRing &ring, inner) {
- // @todo: How to get the reference here?
- // placemark->osmData().addMemberReference(polygon->innerBoundaries().size(), );
polygon->appendInnerBoundary(ring);
}
placemark->setGeometry(polygon);
+ placemark->setOsmData(osmData);
usedNodes |= outerNodes;
- OsmObjectManager::registerId( m_osmData.id() );
+ OsmObjectManager::registerId( osmData.id() );
document->append(placemark);
}
diff --git a/src/plugins/runner/osm/OsmRelation.h b/src/plugins/runner/osm/OsmRelation.h
index ef3f75c..d2784eb 100644
--- a/src/plugins/runner/osm/OsmRelation.h
+++ b/src/plugins/runner/osm/OsmRelation.h
@@ -32,7 +32,7 @@ public:
const OsmPlacemarkData & osmData() const;
- void create(GeoDataDocument* document, const OsmWays &ways, const OsmNodes &nodes, QSet<qint64> &usedNodes, QSet<qint64> &usedWays) const;
+ void create(GeoDataDocument* document, OsmWays &ways, const OsmNodes &nodes, QSet<qint64> &usedNodes, QSet<qint64> &usedWays) const;
private:
struct OsmMember
diff --git a/src/plugins/runner/osm/translators/O5mWriter.cpp b/src/plugins/runner/osm/translators/O5mWriter.cpp
new file mode 100644
index 0000000..863f64b
--- /dev/null
+++ b/src/plugins/runner/osm/translators/O5mWriter.cpp
@@ -0,0 +1,297 @@
+//
+// This file is part of the Marble Virtual Globe.
+//
+// This program is free software licensed under the GNU LGPL. You can
+// find a copy of this license in LICENSE.txt in the top directory of
+// the source code.
+//
+// Copyright 2016 Dennis Nienhüser <nienhueser@kde.org>
+//
+
+#include "O5mWriter.h"
+
+#include "GeoDataTypes.h"
+#include "GeoDataDocument.h"
+#include "GeoDataPlacemark.h"
+#include "GeoDataLineString.h"
+#include "GeoDataLinearRing.h"
+#include "GeoWriter.h"
+#include "osm/OsmPlacemarkData.h"
+
+#include <QDataStream>
+#include <QBuffer>
+
+namespace Marble
+{
+
+bool O5mWriter::write(QIODevice *device, const GeoDataDocument &document)
+{
+ if (!device || !device->isWritable()) {
+ return false;
+ }
+
+ OsmConverter converter;
+ converter.read(&document);
+
+ QDataStream stream(device);
+ writeHeader(stream);
+ writeNodes(converter.nodes(), stream);
+ writeWays(converter.ways(), stream);
+ writePolygons(converter.polygons(), stream);
+ writeTrailer(stream);
+
+ return true;
+}
+
+void O5mWriter::writeHeader(QDataStream &stream) const
+{
+ stream << qint8(0xff); // o5m file start indicator
+ stream << qint8(0xe0); // o5m header block indicator
+ stream << qint8(0x04) << qint8(0x6f) << qint8(0x35) << qint8(0x6d) << qint8(0x32); // o5m header
+}
+
+void O5mWriter::writeNodes(const OsmConverter::Nodes &nodes, QDataStream &stream) const
+{
+ if (nodes.empty()) {
+ return;
+ }
+
+ stream << qint8(0xff); // reset delta encoding counters
+ StringTable stringTable;
+ qint64 lastId = 0;
+ double lastLon = 0.0;
+ double lastLat = 0.0;
+
+ foreach(const auto & node, nodes) {
+ if (node.second.id() == lastId) {
+ continue;
+ }
+
+ stream << qint8(0x10); // node section start indicator
+
+ QBuffer buffer;
+ buffer.open(QIODevice::WriteOnly);
+ QDataStream bufferStream(&buffer);
+
+ OsmPlacemarkData const & osmData = node.second;
+ qint64 idDiff = osmData.id() - lastId;
+ writeSigned(idDiff, bufferStream);
+ writeVersion(osmData, bufferStream);
+ GeoDataCoordinates const coordinates = node.first;
+ double const lon = coordinates.longitude(GeoDataCoordinates::Degree);
+ double const lat = coordinates.latitude(GeoDataCoordinates::Degree);
+ writeSigned(deltaTo(lon, lastLon), bufferStream);
+ writeSigned(deltaTo(lat, lastLat), bufferStream);
+ writeTags(osmData, stringTable, bufferStream);
+
+ writeUnsigned(buffer.size(), stream);
+ stream.writeRawData(buffer.data(), buffer.size());
+
+ lastId = osmData.id();
+ lastLon = lon;
+ lastLat = lat;
+ }
+}
+
+void O5mWriter::writeWays(const OsmConverter::Ways &ways, QDataStream &stream) const
+{
+ if (ways.empty()) {
+ return;
+ }
+
+ stream << qint8(0xff); // reset delta encoding counters
+ StringTable stringTable;
+ qint64 lastId = 0;
+ qint64 lastReferenceId = 0;
+
+ foreach(const auto & way, ways) {
+ Q_ASSERT(way.first);
+ if (way.second.id() == lastId) {
+ continue;
+ }
+
+ stream << qint8(0x11); // way start indicator
+ OsmPlacemarkData const & osmData = way.second;
+
+ QBuffer buffer;
+ buffer.open(QIODevice::WriteOnly);
+ QDataStream bufferStream(&buffer);
+
+ qint64 idDiff = osmData.id() - lastId;
+ writeSigned(idDiff, bufferStream);
+ lastId = osmData.id();
+ writeVersion(osmData, bufferStream);
+
+ QBuffer referencesBuffer;
+ referencesBuffer.open(QIODevice::WriteOnly);
+ QDataStream referencesStream(&referencesBuffer);
+ writeReferences(*way.first, lastReferenceId, osmData, referencesStream);
+ writeUnsigned(referencesBuffer.size(), bufferStream);
+ bufferStream.writeRawData(referencesBuffer.data(), referencesBuffer.size());
+
+ writeTags(osmData, stringTable, bufferStream);
+
+ writeUnsigned(buffer.size(), stream);
+ stream.writeRawData(buffer.data(), buffer.size());
+ }
+}
+
+void O5mWriter::writePolygons(const OsmConverter::Polygons &polygons, QDataStream &stream) const
+{
+ if (polygons.empty()) {
+ return;
+ }
+
+ stream << qint8(0xff); // reset delta encoding counters
+ StringTable stringTable;
+ qint64 lastId = 0;
+ qint64 lastReferenceId = 0;
+
+ foreach(const auto & polygon, polygons) {
+ if (polygon.second.id() == lastId) {
+ continue;
+ }
+
+ stream << qint8(0x12); // relation start indicator
+ OsmPlacemarkData const & osmData = polygon.second;
+
+ QBuffer buffer;
+ buffer.open(QIODevice::WriteOnly);
+ QDataStream bufferStream(&buffer);
+
+ qint64 idDiff = osmData.id() - lastId;
+ writeSigned(idDiff, bufferStream);
+ lastId = osmData.id();
+ writeVersion(osmData, bufferStream);
+
+ QBuffer referencesBuffer;
+ referencesBuffer.open(QIODevice::WriteOnly);
+ QDataStream referencesStream(&referencesBuffer);
+ writeRelationMembers(*polygon.first, lastReferenceId, osmData, stringTable, referencesStream);
+ writeUnsigned(referencesBuffer.size(), bufferStream);
+ bufferStream.writeRawData(referencesBuffer.data(), referencesBuffer.size());
+
+ writeTags(osmData, stringTable, bufferStream);
+
+ writeUnsigned(buffer.size(), stream);
+ stream.writeRawData(buffer.data(), buffer.size());
+ }
+}
+
+void O5mWriter::writeTrailer(QDataStream &stream) const
+{
+ stream << qint8(0xfe); // o5m file end indicator
+}
+
+void O5mWriter::writeRelationMembers(const GeoDataPolygon &polygon, qint64 &lastId, const OsmPlacemarkData &osmData, StringTable &stringTable, QDataStream &stream) const
+{
+ qint64 id = osmData.memberReference(-1).id();
+ qint64 idDiff = id - lastId;
+ writeSigned(idDiff, stream);
+ lastId = id;
+ writeStringPair(StringPair("1outer", QString()), stringTable, stream); // type=way, role=outer
+ for (int index = 0; index < polygon.innerBoundaries().size(); ++index) {
+ id = osmData.memberReference( index ).id();
+ qint64 idDiff = id - lastId;
+ writeSigned(idDiff, stream);
+ writeStringPair(StringPair("1inner", QString()), stringTable, stream); // type=way, role=inner
+ lastId = id;
+ }
+}
+
+void O5mWriter::writeReferences(const GeoDataLineString &lineString, qint64 &lastId, const OsmPlacemarkData &osmData, QDataStream &stream) const
+{
+ QVector<GeoDataCoordinates>::const_iterator it = lineString.constBegin();
+ QVector<GeoDataCoordinates>::ConstIterator const end = lineString.constEnd();
+
+ for ( ; it != end; ++it ) {
+ qint64 id = osmData.nodeReference( *it ).id();
+ qint64 idDiff = id - lastId;
+ writeSigned(idDiff, stream);
+ lastId = id;
+ }
+
+ if (!lineString.isEmpty() && lineString.isClosed()) {
+ auto const startId = osmData.nodeReference(lineString.first()).id();
+ auto const endId = osmData.nodeReference(lineString.last()).id();
+ if (startId != endId) {
+ qint64 idDiff = startId - lastId;
+ writeSigned(idDiff, stream);
+ lastId = startId;
+ }
+ }
+}
+
+void O5mWriter::writeVersion(const OsmPlacemarkData &, QDataStream &stream) const
+{
+ stream << qint8(0x00); // no version information
+ /** @todo implement */
+}
+
+void O5mWriter::writeTags(const OsmPlacemarkData &osmData, StringTable &stringTable, QDataStream &stream) const
+{
+ for (auto iter=osmData.tagsBegin(), end = osmData.tagsEnd(); iter != end; ++iter) {
+ writeStringPair(StringPair(iter.key(), iter.value()), stringTable, stream);
+ }
+}
+
+void O5mWriter::writeStringPair(const StringPair &pair, StringTable &stringTable, QDataStream &stream) const
+{
+ auto const iter = stringTable.find(pair);
+ if (iter == stringTable.cend()) {
+ QByteArray data;
+ data.push_back(char(0x00));
+ data.push_back(pair.first.toUtf8());
+ if (!pair.second.isEmpty()) {
+ data.push_back(char(0x00));
+ data.push_back(pair.second.toUtf8());
+ }
+ data.push_back(char(0x00));
+ stream.writeRawData(data, data.size());
+ stringTable.insert(pair, stringTable.size());
+ } else {
+ auto const reference = stringTable.size() - iter.value();
+ writeUnsigned(reference, stream);
+ }
+}
+
+void O5mWriter::writeSigned(qint32 value, QDataStream &stream) const
+{
+ bool const negative = value < 0;
+ if (negative) {
+ value = -value - 1;
+ }
+ quint8 word = (value >> 6) > 0 ? (1<<7) : 0;
+ word |= ( (value << 1) & 0x7e);
+ if (negative) {
+ word |= 0x01;
+ }
+ value >>= 6;
+ stream << word;
+
+ while (value > 0) {
+ word = ((value >> 7) > 0 ? 0x80 : 0x00) | (value & 0x7f);
+ stream << word;
+ value >>= 7;
+ }
+}
+
+void O5mWriter::writeUnsigned(quint32 value, QDataStream &stream) const
+{
+ do {
+ quint8 word = (value >> 7 & 0x7f) != 0x00 ? (1<<7) : 0;
+ word |= value & 0x7f;
+ value >>= 7;
+ stream << word;
+ } while ((value & 0x7f) != 0x0);
+}
+
+qint32 O5mWriter::deltaTo(double value, double previous) const
+{
+ double const diff = value - previous;
+ return qRound(diff * 1e7);
+}
+
+MARBLE_ADD_WRITER(O5mWriter, "o5m")
+
+}
diff --git a/src/plugins/runner/osm/translators/O5mWriter.h b/src/plugins/runner/osm/translators/O5mWriter.h
new file mode 100644
index 0000000..7f5482e
--- /dev/null
+++ b/src/plugins/runner/osm/translators/O5mWriter.h
@@ -0,0 +1,51 @@
+//
+// This file is part of the Marble Virtual Globe.
+//
+// This program is free software licensed under the GNU LGPL. You can
+// find a copy of this license in LICENSE.txt in the top directory of
+// the source code.
+//
+// Copyright 2016 Dennis Nienhüser <nienhueser@kde.org>
+//
+
+#ifndef MARBLE_O5MWRITER_H
+#define MARBLE_O5MWRITER_H
+
+#include "osm/OsmPlacemarkData.h"
+#include "OsmConverter.h"
+#include "GeoWriterBackend.h"
+
+namespace Marble
+{
+
+class GeoDataPlacemark;
+class GeoDataLineString;
+
+class O5mWriter: public GeoWriterBackend
+{
+public:
+ bool write(QIODevice *device, const GeoDataDocument &document) override;
+
+private:
+ typedef QPair<QString, QString> StringPair;
+ typedef QHash<StringPair, qint32> StringTable;
+
+ void writeHeader(QDataStream& stream) const;
+ void writeNodes(const OsmConverter::Nodes &nodes, QDataStream& stream) const;
+ void writeWays(const OsmConverter::Ways &ways, QDataStream& stream) const;
+ void writePolygons(const OsmConverter::Polygons &polygons, QDataStream& stream) const;
+ void writeTrailer(QDataStream& stream) const;
+
+ void writeRelationMembers(const GeoDataPolygon &polygon, qint64 &lastId, const OsmPlacemarkData &osmData, StringTable &stringTable, QDataStream &stream) const;
+ void writeReferences(const GeoDataLineString &lineString, qint64 &lastId, const OsmPlacemarkData &osmData, QDataStream &stream) const;
+ void writeVersion(const OsmPlacemarkData &osmData, QDataStream &stream) const;
+ void writeTags(const OsmPlacemarkData &osmData, StringTable &stringTable, QDataStream &stream) const;
+ void writeStringPair(const StringPair &pair, StringTable &stringTable, QDataStream &stream) const;
+ void writeSigned(qint32 value, QDataStream &stream) const;
+ void writeUnsigned(quint32 value, QDataStream &stream) const;
+ qint32 deltaTo(double value, double previous) const;
+};
+
+}
+
+#endif
diff --git a/src/plugins/runner/osm/translators/OsmConverter.cpp b/src/plugins/runner/osm/translators/OsmConverter.cpp
new file mode 100644
index 0000000..ff7c68a
--- /dev/null
+++ b/src/plugins/runner/osm/translators/OsmConverter.cpp
@@ -0,0 +1,108 @@
+//
+// This file is part of the Marble Virtual Globe.
+//
+// This program is free software licensed under the GNU LGPL. You can
+// find a copy of this license in LICENSE.txt in the top directory of
+// the source code.
+//
+// Copyright 2016 Dennis Nienhüser <nienhueser@kde.org>
+//
+
+//Self
+#include "OsmDocumentTagTranslator.h"
+
+//Marble
+#include "OsmNodeTagWriter.h"
+#include "OsmWayTagWriter.h"
+#include "OsmElementDictionary.h"
+#include "GeoDataDocument.h"
+#include "GeoWriter.h"
+#include "GeoDataPlacemark.h"
+#include "GeoDataGeometry.h"
+#include "GeoDataPoint.h"
+#include "GeoDataPolygon.h"
+#include "GeoDataLinearRing.h"
+#include "GeoDataTypes.h"
+#include "osm/OsmPlacemarkData.h"
+#include "osm/OsmObjectManager.h"
+#include "OsmRelationTagWriter.h"
+
+#include <QDebug>
+
+namespace Marble
+{
+
+void OsmConverter::read(const GeoDataDocument *document)
+{
+ m_nodes.clear();
+ m_ways.clear();
+ m_polygons.clear();
+
+ // Writing all the component nodes ( points, nodes of polylines, nodes of polygons )
+ foreach (GeoDataPlacemark* placemark, document->placemarkList()) {
+ // If the placemark's osmData is not complete, it is initialized by the OsmObjectManager
+ OsmObjectManager::initializeOsmData( placemark );
+ const OsmPlacemarkData osmData = placemark->osmData();
+
+ if ( placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPointType ) {
+ m_nodes << OsmConverter::Node(placemark->coordinate(), osmData);
+ } else if ( placemark->geometry()->nodeType() == GeoDataTypes::GeoDataLineStringType ) {
+ const GeoDataLineString* lineString = static_cast<const GeoDataLineString*>( placemark->geometry() );
+ foreach(const GeoDataCoordinates &coordinates, *lineString) {
+ m_nodes << OsmConverter::Node(coordinates, osmData.nodeReference(coordinates));
+ }
+ m_ways << OsmConverter::Way(lineString, osmData);
+ } else if ( placemark->geometry()->nodeType() == GeoDataTypes::GeoDataLinearRingType ) {
+ const GeoDataLinearRing* linearRing = static_cast<const GeoDataLinearRing*>( placemark->geometry() );
+ foreach(const GeoDataCoordinates &coordinates, *linearRing) {
+ m_nodes << OsmConverter::Node(coordinates, osmData.nodeReference(coordinates));
+ }
+ m_ways << OsmConverter::Way(linearRing, osmData);
+ } else if ( placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType ) {
+ const GeoDataPolygon *polygon = static_cast<const GeoDataPolygon*>( placemark->geometry() );
+ int index = -1;
+
+ // Writing all the outerRing's nodes
+ const GeoDataLinearRing &outerRing = polygon->outerBoundary();
+ const OsmPlacemarkData outerRingOsmData = osmData.memberReference( index );
+ foreach(const GeoDataCoordinates &coordinates, outerRing) {
+ m_nodes << OsmConverter::Node(coordinates, osmData.nodeReference(coordinates));
+ }
+ m_ways << OsmConverter::Way(&outerRing, outerRingOsmData);
+
+ // Writing all nodes for each innerRing
+ foreach ( const GeoDataLinearRing &innerRing, polygon->innerBoundaries() ) {
+ ++index;
+ const OsmPlacemarkData innerRingOsmData = osmData.memberReference( index );
+ foreach(const GeoDataCoordinates &coordinates, innerRing) {
+ m_nodes << OsmConverter::Node(coordinates, osmData.nodeReference(coordinates));
+ }
+ m_ways << OsmConverter::Way(&innerRing, innerRingOsmData);
+ }
+ m_polygons.append(OsmConverter::Polygon(polygon, osmData));
+ }
+ }
+
+ // Sort by id ascending since some external tools rely on that
+ qSort(m_nodes.begin(), m_nodes.end(), [] (const Node &a, const Node &b) { return a.second.id() < b.second.id(); });
+ qSort(m_ways.begin(), m_ways.end(), [] (const Way &a, const Way &b) { return a.second.id() < b.second.id(); });
+ qSort(m_polygons.begin(), m_polygons.end(), [] (const Polygon &a, const Polygon &b) { return a.second.id() < b.second.id(); });
+}
+
+const OsmConverter::Nodes &OsmConverter::nodes() const
+{
+ return m_nodes;
+}
+
+const OsmConverter::Ways &OsmConverter::ways() const
+{
+ return m_ways;
+}
+
+const OsmConverter::Polygons &OsmConverter::polygons() const
+{
+ return m_polygons;
+}
+
+}
+
diff --git a/src/plugins/runner/osm/translators/OsmConverter.h b/src/plugins/runner/osm/translators/OsmConverter.h
new file mode 100644
index 0000000..48ce26f
--- /dev/null
+++ b/src/plugins/runner/osm/translators/OsmConverter.h
@@ -0,0 +1,52 @@
+//
+// This file is part of the Marble Virtual Globe.
+//
+// This program is free software licensed under the GNU LGPL. You can
+// find a copy of this license in LICENSE.txt in the top directory of
+// the source code.
+//
+// Copyright 2016 Dennis Nienhüser <nienhueser@kde.org>
+//
+
+#ifndef MARBLE_OSMCONVERTER_H
+#define MARBLE_OSMCONVERTER_H
+
+#include <GeoDataCoordinates.h>
+
+namespace Marble
+{
+
+class GeoDataLineString;
+class GeoDataDocument;
+class GeoDataPolygon;
+class OsmPlacemarkData;
+
+class OsmConverter
+{
+public:
+ typedef QPair<QString, QString> Tag;
+ typedef QPair<GeoDataCoordinates, OsmPlacemarkData > Node;
+ typedef QPair<const GeoDataLineString*, OsmPlacemarkData > Way;
+ typedef QPair<const GeoDataPolygon*, OsmPlacemarkData > Polygon;
+
+ typedef QVector<Node> Nodes;
+ typedef QVector<Tag> Tags;
+ typedef QVector<Way> Ways;
+ typedef QVector<Polygon> Polygons;
+
+ void read(const GeoDataDocument* document);
+
+ const Nodes & nodes() const;
+ const Ways & ways() const;
+ const Polygons & polygons() const;
+
+private:
+ Nodes m_nodes;
+ Ways m_ways;
+ Polygons m_polygons;
+};
+
+}
+
+#endif
+
diff --git a/src/plugins/runner/osm/translators/OsmDocumentTagTranslator.cpp b/src/plugins/runner/osm/translators/OsmDocumentTagTranslator.cpp
index 4b0df27..6834189 100644
--- a/src/plugins/runner/osm/translators/OsmDocumentTagTranslator.cpp
+++ b/src/plugins/runner/osm/translators/OsmDocumentTagTranslator.cpp
@@ -26,6 +26,9 @@
#include "osm/OsmPlacemarkData.h"
#include "osm/OsmObjectManager.h"
#include "OsmRelationTagWriter.h"
+#include "OsmConverter.h"
+
+#include <QDebug>
namespace Marble
{
@@ -39,55 +42,12 @@ bool OsmDocumentTagTranslator::write( const GeoNode *node, GeoWriter& writer ) c
{
const GeoDataDocument *document = static_cast<const GeoDataDocument*>(node);
- // Creating separate lists, to improve efficiency
- typedef QPair<const GeoDataPolygon*, OsmPlacemarkData > OsmPolygon;
- typedef QPair<const GeoDataLineString*, OsmPlacemarkData > OsmLineString;
- QList<OsmPlacemarkData> nodes;
- QList<OsmLineString> ways;
- QList<OsmPolygon> polygons;
-
- // Writing all the component nodes ( points, nodes of polylines, nodes of polygons )
- foreach (GeoDataPlacemark* placemark, document->placemarkList()) {
- // If the placemark's osmData is not complete, it is initialized by the OsmObjectManager
- OsmObjectManager::initializeOsmData( placemark );
- const OsmPlacemarkData osmData = placemark->osmData();
-
- if ( placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPointType ) {
- nodes << osmData;
- } else if ( placemark->geometry()->nodeType() == GeoDataTypes::GeoDataLineStringType ) {
- const GeoDataLineString* lineString = static_cast<const GeoDataLineString*>( placemark->geometry() );
- nodes << osmData;
- ways << OsmLineString(lineString, osmData);
- } else if ( placemark->geometry()->nodeType() == GeoDataTypes::GeoDataLinearRingType ) {
- const GeoDataLinearRing* linearRing = static_cast<const GeoDataLinearRing*>( placemark->geometry() );
- nodes << osmData;
- ways << OsmLineString(linearRing, osmData);
- } else if ( placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType ) {
- const GeoDataPolygon *polygon = static_cast<const GeoDataPolygon*>( placemark->geometry() );
- int index = -1;
-
- // Writing all the outerRing's nodes
- const GeoDataLinearRing &outerRing = polygon->outerBoundary();
- const OsmPlacemarkData outerRingOsmData = osmData.memberReference( index );
- nodes << outerRingOsmData;
- ways << OsmLineString(&outerRing, outerRingOsmData);
-
- // Writing all nodes for each innerRing
- foreach ( const GeoDataLinearRing &innerRing, polygon->innerBoundaries() ) {
- ++index;
- const OsmPlacemarkData innerRingOsmData = osmData.memberReference( index );
- nodes << innerRingOsmData;
- ways << OsmLineString(&innerRing, innerRingOsmData);
- }
- polygons.append(OsmPolygon(polygon, osmData));
- }
- }
-
- OsmNodeTagWriter::writeAllNodes(nodes, writer);
+ OsmConverter converter;
+ converter.read(document);
+ OsmNodeTagWriter::writeAllNodes(converter.nodes(), writer);
- qSort(ways.begin(), ways.end(), [] (const OsmLineString &a, const OsmLineString &b) { return a.second.id() < b.second.id(); });
qint64 lastId = 0;
- foreach(const OsmLineString &way, ways) {
+ foreach(const auto &way, converter.ways()) {
if (way.second.id() != lastId) {
OsmWayTagWriter::writeWay(*way.first, way.second, writer);
lastId = way.second.id();
@@ -95,8 +55,7 @@ bool OsmDocumentTagTranslator::write( const GeoNode *node, GeoWriter& writer ) c
}
// Writing polygons
- qSort(polygons.begin(), polygons.end(), [] (const OsmPolygon &a, const OsmPolygon &b) { return a.second.id() < b.second.id(); });
- foreach (const OsmPolygon& polygon, polygons) {
+ foreach (const auto& polygon, converter.polygons()) {
OsmRelationTagWriter::writeMultipolygon(*polygon.first, polygon.second, writer );
}
diff --git a/src/plugins/runner/osm/translators/OsmDocumentTagTranslator.h b/src/plugins/runner/osm/translators/OsmDocumentTagTranslator.h
index 6d7ccad..22f7f9d 100644
--- a/src/plugins/runner/osm/translators/OsmDocumentTagTranslator.h
+++ b/src/plugins/runner/osm/translators/OsmDocumentTagTranslator.h
@@ -13,6 +13,8 @@
#include "GeoTagWriter.h"
+#include <GeoDataCoordinates.h>
+
namespace Marble
{
/**
@@ -29,8 +31,6 @@ namespace Marble
See http://wiki.openstreetmap.org/wiki/OSM_XML#Contents
*/
-class GeoDataLineString;
-class OsmPlacemarkData;
class OsmDocumentTagTranslator : public GeoTagWriter
{
diff --git a/src/plugins/runner/osm/writers/OsmNodeTagWriter.cpp b/src/plugins/runner/osm/writers/OsmNodeTagWriter.cpp
index 9f55b9f..3b68f13 100644
--- a/src/plugins/runner/osm/writers/OsmNodeTagWriter.cpp
+++ b/src/plugins/runner/osm/writers/OsmNodeTagWriter.cpp
@@ -23,47 +23,32 @@
#include "osm/OsmPlacemarkData.h"
#include "osm/OsmObjectManager.h"
-
namespace Marble
{
-void OsmNodeTagWriter::writeNode( const GeoDataCoordinates& coordinates, const OsmPlacemarkData& osmData, GeoWriter& writer )
+void OsmNodeTagWriter::writeNode( const OsmConverter::Node &node, GeoWriter& writer )
{
- QString lat = QString::number( coordinates.latitude( GeoDataCoordinates::Degree ), 'f', 7 );
- QString lon = QString::number( coordinates.longitude( GeoDataCoordinates::Degree ), 'f', 7 );
+ QString lat = QString::number( node.first.latitude( GeoDataCoordinates::Degree ), 'f', 7 );
+ QString lon = QString::number( node.first.longitude( GeoDataCoordinates::Degree ), 'f', 7 );
writer.writeStartElement( osm::osmTag_node );
writer.writeAttribute( "lat", lat );
writer.writeAttribute( "lon", lon );
- OsmObjectAttributeWriter::writeAttributes( osmData, writer );
- OsmTagTagWriter::writeTags( osmData, writer );
+ OsmObjectAttributeWriter::writeAttributes( node.second, writer );
+ OsmTagTagWriter::writeTags(node.second, writer);
writer.writeEndElement();
}
-void OsmNodeTagWriter::writeAllNodes( const QList<OsmPlacemarkData>& values, GeoWriter& writer )
+void OsmNodeTagWriter::writeAllNodes( const OsmConverter::Nodes& nodes, GeoWriter& writer )
{
- typedef QPair<GeoDataCoordinates, OsmPlacemarkData> Coordinate;
- QVector<Coordinate> nodes;
-
- foreach(const OsmPlacemarkData &osmData, values) {
- QHash< GeoDataCoordinates, OsmPlacemarkData >::const_iterator it = osmData.nodeReferencesBegin();
- QHash< GeoDataCoordinates, OsmPlacemarkData >::const_iterator end = osmData.nodeReferencesEnd();
- for (; it != end; ++it) {
- nodes.push_back(Coordinate(it.key(), it.value()));
- }
- }
-
- // Sort by id ascending since some external tools rely on that
- qSort(nodes.begin(), nodes.end(), [] (const Coordinate &a, const Coordinate &b) { return a.second.id() < b.second.id(); });
-
// Writing all the component nodes
qint64 lastId = 0;
foreach(const auto &node, nodes) {
if (node.second.id() != lastId) {
- writeNode(node.first, node.second, writer);
+ writeNode(node, writer);
lastId = node.second.id();
} // else duplicate/shared node
}
diff --git a/src/plugins/runner/osm/writers/OsmNodeTagWriter.h b/src/plugins/runner/osm/writers/OsmNodeTagWriter.h
index 4c36b7c..bbaf69f 100644
--- a/src/plugins/runner/osm/writers/OsmNodeTagWriter.h
+++ b/src/plugins/runner/osm/writers/OsmNodeTagWriter.h
@@ -11,6 +11,8 @@
#ifndef MARBLE_OSMNODETAGWRITER_H
#define MARBLE_OSMNODETAGWRITER_H
+#include "translators/OsmConverter.h"
+
#include <QList>
namespace Marble
@@ -25,11 +27,10 @@ class OsmNodeTagWriter
{
public:
- static void writeAllNodes(const QList<OsmPlacemarkData> &osmData, GeoWriter& writer );
+ static void writeAllNodes(const OsmConverter::Nodes &osmData, GeoWriter& writer );
private:
- static void writeNode( const GeoDataCoordinates& coordinates,
- const OsmPlacemarkData& osmData, GeoWriter& writer );
+ static void writeNode(const OsmConverter::Node &node, GeoWriter& writer );
};
}
diff --git a/src/plugins/runner/osm/writers/OsmTagTagWriter.cpp b/src/plugins/runner/osm/writers/OsmTagTagWriter.cpp
index 5b16ff9..72e1752 100644
--- a/src/plugins/runner/osm/writers/OsmTagTagWriter.cpp
+++ b/src/plugins/runner/osm/writers/OsmTagTagWriter.cpp
@@ -21,8 +21,8 @@ namespace Marble
void OsmTagTagWriter::writeTags( const OsmPlacemarkData& osmData, GeoWriter &writer )
{
- QHash<QString, QString>::const_iterator it = osmData.tagsBegin();
- QHash<QString, QString>::const_iterator end = osmData.tagsEnd();
+ auto it = osmData.tagsBegin();
+ auto end = osmData.tagsEnd();
for ( ; it != end; ++it ) {
writer.writeStartElement( osm::osmTag_tag );