summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Kolozsvari <[email protected]>2016-07-15 19:19:31 +0200
committerDavid Kolozsvari <[email protected]>2016-07-15 19:19:31 +0200
commita927ef05ca0e68db6b054bbecfe17e0861017f8a (patch)
tree7919cb5b7fe7fe2d38f8e0e1f5233839dd549a7f
parent725400a866e3ba59d67aa6f0c12a0d6e968ae3fa (diff)
Latest version of the osm-simplify tool. Added TinyPlanetProcessor class, which cuts to tiles .osm files.
-rw-r--r--tools/osm-simplify/BaseClipper.cpp17
-rw-r--r--tools/osm-simplify/BaseClipper.h4
-rw-r--r--tools/osm-simplify/CMakeLists.txt1
-rw-r--r--tools/osm-simplify/TinyPlanetProcessor.cpp156
-rw-r--r--tools/osm-simplify/TinyPlanetProcessor.h26
-rw-r--r--tools/osm-simplify/main.cpp220
6 files changed, 387 insertions, 37 deletions
diff --git a/tools/osm-simplify/BaseClipper.cpp b/tools/osm-simplify/BaseClipper.cpp
index c8c2a16..54f241c 100644
--- a/tools/osm-simplify/BaseClipper.cpp
+++ b/tools/osm-simplify/BaseClipper.cpp
@@ -110,14 +110,14 @@ qreal BaseClipper::_m( const QPointF & start, const QPointF & end )
{
qreal divisor = end.x() - start.x();
- // Had to add mre zeros, because what is acceptable in screen coordinates
+ // Had to add more zeros, because what is acceptable in screen coordinates
// could be meters on 10 meters in geographic coordinates.
if ( std::fabs( divisor ) < 0.00000000000000001 ) {
divisor = 0.00000000000000001 * (divisor < 0 ? -1 : 1);
}
return ( end.y() - start.y() )
- / divisor;
+ / divisor;
}
@@ -224,6 +224,7 @@ void BaseClipper::clipPolyObject ( const QPolygonF & polygon,
// sector that is located off screen to another one that
// is located off screen. In this situation the line
// can get clipped once, twice, or not at all.
+
clipMultiple( clippedPolyObject, clippedPolyObjects, isClosed );
}
@@ -234,9 +235,6 @@ void BaseClipper::clipPolyObject ( const QPolygonF & polygon,
if ( m_currentSector == 4 ) {
clippedPolyObject << m_currentPoint;
-#ifdef MARBLE_DEBUG
- ++(m_debugNodeCount);
-#endif
}
m_previousPoint = m_currentPoint;
@@ -748,11 +746,8 @@ void BaseClipper::clipOnceCorner( QPolygonF & clippedPolyObject,
QVector<QPolygonF> & clippedPolyObjects,
const QPointF& corner,
const QPointF& point,
- bool isClosed ) const
+ bool isClosed )
{
- Q_UNUSED( clippedPolyObjects )
- Q_UNUSED( isClosed )
-
if ( m_currentSector == 4) {
// Appearing
clippedPolyObject << corner;
@@ -767,7 +762,7 @@ void BaseClipper::clipOnceCorner( QPolygonF & clippedPolyObject,
void BaseClipper::clipOnceEdge( QPolygonF & clippedPolyObject,
QVector<QPolygonF> & clippedPolyObjects,
const QPointF& point,
- bool isClosed ) const
+ bool isClosed )
{
if ( m_currentSector == 4) {
// Appearing
@@ -779,8 +774,10 @@ void BaseClipper::clipOnceEdge( QPolygonF & clippedPolyObject,
else {
// Disappearing
clippedPolyObject << point;
+
if ( !isClosed ) {
clippedPolyObjects << clippedPolyObject;
+ clippedPolyObject = QPolygonF();
}
}
}
diff --git a/tools/osm-simplify/BaseClipper.h b/tools/osm-simplify/BaseClipper.h
index c5c4646..56dc14c 100644
--- a/tools/osm-simplify/BaseClipper.h
+++ b/tools/osm-simplify/BaseClipper.h
@@ -61,11 +61,11 @@ private:
QVector<QPolygonF> & clippedPolyObjects,
const QPointF& corner,
const QPointF& point,
- bool isClosed ) const;
+ bool isClosed );
inline void clipOnceEdge( QPolygonF & clippedPolyObject,
QVector<QPolygonF> & clippedPolyObjects,
const QPointF& point,
- bool isClosed ) const;
+ bool isClosed );
static inline qreal _m( const QPointF & start, const QPointF & end );
diff --git a/tools/osm-simplify/CMakeLists.txt b/tools/osm-simplify/CMakeLists.txt
index b66199f..cc43b28 100644
--- a/tools/osm-simplify/CMakeLists.txt
+++ b/tools/osm-simplify/CMakeLists.txt
@@ -25,6 +25,7 @@ BaseFilter.cpp
PlacemarkFilter.cpp
ShpCoastlineProcessor.cpp
LineStringProcessor.cpp
+ TinyPlanetProcessor.cpp
NodeReducer.cpp
)
diff --git a/tools/osm-simplify/TinyPlanetProcessor.cpp b/tools/osm-simplify/TinyPlanetProcessor.cpp
new file mode 100644
index 0000000..22cd8ed
--- /dev/null
+++ b/tools/osm-simplify/TinyPlanetProcessor.cpp
@@ -0,0 +1,156 @@
+//
+// 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 David Kolozsvari <[email protected]>
+//
+
+#include "TinyPlanetProcessor.h"
+
+#include "BaseClipper.h"
+
+#include "GeoDataPlacemark.h"
+#include "OsmPlacemarkData.h"
+
+#include <QDebug>
+#include <QPolygonF>
+
+TinyPlanetProcessor::TinyPlanetProcessor(GeoDataDocument* document) :
+ PlacemarkFilter(document)
+{
+
+}
+
+void TinyPlanetProcessor::process()
+{
+ // ?
+}
+
+GeoDataDocument *TinyPlanetProcessor::cutToTiles(unsigned int zoomLevel, unsigned int tileX, unsigned int tileY)
+{
+ unsigned int N = pow(2, zoomLevel);
+
+ GeoDataDocument* tile = new GeoDataDocument();
+ QString tileName = QString("%1/%2/%3").arg(zoomLevel).arg(tileX).arg(tileY);
+ tile->setName(tileName);
+
+ GeoDataLatLonBox tileBoundary;
+ qreal north = BaseClipper::tileY2lat(tileY, N);
+ qreal south = BaseClipper::tileY2lat(tileY+1, N);
+ qreal west = BaseClipper::tileX2lon(tileX, N);
+ qreal east = BaseClipper::tileX2lon(tileX+1, N);
+
+ tileBoundary.setBoundaries(north, south, east, west);
+
+ BaseClipper clipper;
+ clipper.initClipRect(tileBoundary);
+
+ foreach (GeoDataObject* object, m_objects) {
+ GeoDataPlacemark* placemark = static_cast<GeoDataPlacemark*>(object);
+
+ if(tileBoundary.intersects(placemark->geometry()->latLonAltBox())) {
+
+ if( placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType ||
+ placemark->visualCategory() == GeoDataFeature::Landmass) {
+
+ GeoDataLinearRing* marblePolygon;
+ if(placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType) {
+ marblePolygon = &static_cast<GeoDataPolygon*>(placemark->geometry())->outerBoundary();
+ } else if (placemark->geometry()->nodeType() == GeoDataTypes::GeoDataLinearRingType) {
+ marblePolygon = static_cast<GeoDataLinearRing*>(placemark->geometry());
+ }
+
+ QVector<QPolygonF> clippedPolygons;
+
+ QPolygonF outerBoundary = BaseClipper::linearRing2Qpolygon(*marblePolygon);
+
+ clipper.clipPolyObject(outerBoundary, clippedPolygons, true);
+
+ foreach(const QPolygonF& polygon, clippedPolygons) {
+
+ GeoDataLinearRing outerBoundary = BaseClipper::qPolygon2linearRing(polygon);
+ GeoDataPolygon* newMarblePolygon = new GeoDataPolygon();
+ newMarblePolygon->setOuterBoundary(outerBoundary);
+
+ GeoDataPlacemark* newPlacemark = new GeoDataPlacemark();
+ newPlacemark->setGeometry(newMarblePolygon);
+ newPlacemark->setVisualCategory(GeoDataFeature::Landmass);
+
+ OsmPlacemarkData marbleLand;
+ marbleLand.addTag("marble_land","landmass");
+ newPlacemark->setOsmData(marbleLand);
+
+ tile->append(newPlacemark);
+ }
+ } else if (placemark->geometry()->nodeType() == GeoDataTypes::GeoDataLineStringType) {
+ GeoDataLineString* marbleWay = static_cast<GeoDataLineString*>(placemark->geometry());
+
+ QVector<QPolygonF> clippedPolygons;
+
+ QPolygonF way = BaseClipper::lineString2Qpolygon(*marbleWay);
+
+ clipper.clipPolyObject(way, clippedPolygons, false);
+
+ foreach(const QPolygonF& polygon, clippedPolygons) {
+
+ GeoDataLineString* newMarbleWay = new GeoDataLineString(BaseClipper::qPolygon2lineString(polygon));
+
+ GeoDataPlacemark* newPlacemark = new GeoDataPlacemark();
+ newPlacemark->setGeometry(newMarbleWay);
+ newPlacemark->setVisualCategory(placemark->visualCategory());
+
+ OsmPlacemarkData osmData;
+ auto it = placemark->osmData().tagsBegin();
+ auto itEnd = placemark->osmData().tagsEnd();
+ while(it != itEnd) {
+ osmData.addTag(it.key(), it.value());
+ ++it;
+ }
+ newPlacemark->setOsmData(osmData);
+
+ tile->append(newPlacemark);
+ }
+ } else if (placemark->geometry()->nodeType() == GeoDataTypes::GeoDataLinearRingType) {
+
+ GeoDataLinearRing* marbleClosedWay = static_cast<GeoDataLinearRing*>(placemark->geometry());
+
+ QVector<QPolygonF> clippedPolygons;
+
+ QPolygonF closedWay = BaseClipper::linearRing2Qpolygon(*marbleClosedWay);
+
+ // If we cut a closed way to pieces, the results shouldn't be closed ways too
+ clipper.clipPolyObject(closedWay, clippedPolygons, false);
+
+ foreach(const QPolygonF& polygon, clippedPolygons) {
+
+ // When a linearRing is cut to pieces, the resulting geometries will be lineStrings
+ GeoDataLineString* newMarbleWay = new GeoDataLineString(BaseClipper::qPolygon2lineString(polygon));
+
+ GeoDataPlacemark* newPlacemark = new GeoDataPlacemark();
+ newPlacemark->setGeometry(newMarbleWay);
+ newPlacemark->setVisualCategory(placemark->visualCategory());
+
+ OsmPlacemarkData osmData;
+ auto it = placemark->osmData().tagsBegin();
+ auto itEnd = placemark->osmData().tagsEnd();
+ while(it != itEnd) {
+ osmData.addTag(it.key(), it.value());
+ ++it;
+ }
+ newPlacemark->setOsmData(osmData);
+
+ tile->append(newPlacemark);
+ }
+
+ } else {
+ tile->append(placemark);
+ }
+ }
+ }
+
+
+ return tile;
+}
diff --git a/tools/osm-simplify/TinyPlanetProcessor.h b/tools/osm-simplify/TinyPlanetProcessor.h
new file mode 100644
index 0000000..862f55e
--- /dev/null
+++ b/tools/osm-simplify/TinyPlanetProcessor.h
@@ -0,0 +1,26 @@
+//
+// 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 David Kolozsvari <[email protected]>
+//
+
+#ifndef TINYPLANETPROCESSOR_H
+#define TINYPLANETPROCESSOR_H
+
+#include "PlacemarkFilter.h"
+
+class TinyPlanetProcessor : public PlacemarkFilter
+{
+public:
+ TinyPlanetProcessor(GeoDataDocument* document);
+
+ virtual void process();
+
+ GeoDataDocument* cutToTiles(unsigned int zoomLevel, unsigned int tileX, unsigned int tileY);
+};
+
+#endif // TINYPLANETPROCESSOR_H
diff --git a/tools/osm-simplify/main.cpp b/tools/osm-simplify/main.cpp
index e0de41c..3c34d3e 100644
--- a/tools/osm-simplify/main.cpp
+++ b/tools/osm-simplify/main.cpp
@@ -18,11 +18,13 @@
#include <QFileInfo>
#include <QDir>
#include <QString>
+#include <QElapsedTimer>
#include <QMessageLogContext>
#include "LineStringProcessor.h"
#include "ShpCoastlineProcessor.h"
+#include "TinyPlanetProcessor.h"
#include "NodeReducer.h"
using namespace Marble;
@@ -65,12 +67,24 @@ void debugOutput( QtMsgType type, const QMessageLogContext &context, const QStri
}
}
}
+
void usage()
{
qDebug() << "Usage: osm-simplify [options] input.osm output.osm";
qDebug() << "\t--no-streets-smaller-than %f - eliminates streets which have realsize smaller than %f";
}
+GeoDataDocument* mergeDocuments(GeoDataDocument* map1, GeoDataDocument* map2)
+{
+ GeoDataDocument* mergedMap = new GeoDataDocument(*map1);
+
+ foreach (GeoDataFeature* feature, map2->featureList()) {
+ mergedMap->append(feature);
+ }
+
+ return mergedMap;
+}
+
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
@@ -91,20 +105,26 @@ int main(int argc, char *argv[])
},
{
- {"m","mute"},
+ {"s","silent"},
QCoreApplication::translate("main", "Don't output to terminal.")
},
{
+ {"m","merge"},
+ QCoreApplication::translate("main", "Merge the main document with the file <file_to_merge_with>. This works together with the -c flag."),
+ QCoreApplication::translate("main", "file_to_merge_with")
+ },
+
+ {
{"c", "cut-to-tiles"},
QCoreApplication::translate("main", "Cuts into tiles based on the zoom level passed using -z."),
- //QCoreApplication::translate("main", "number")
},
{
{"n", "node-reduce"},
QCoreApplication::translate("main", "Reduces the number of nodes for a given way based on zoom level"),
- },
+
+ },
{
{"z", "zoom-level"},
@@ -114,7 +134,7 @@ int main(int argc, char *argv[])
{
{"o", "output"},
- QCoreApplication::translate("main", "Generates an output .osmfile based on other flags. This won't work together with the cut-to-tiles flag."),
+ QCoreApplication::translate("main", "Generates an output .osmfile based on other flags. If the cut-to-tiles flag is set, then this needs to be a directory."),
QCoreApplication::translate("main", "output_file.osm")
}
});
@@ -130,25 +150,25 @@ int main(int argc, char *argv[])
// input is args.at(0), output is args.at(1)
QString inputFileName = args.at(0);
+ QString mergeFileName = parser.value("merge");
bool debug = parser.isSet("debug");
- bool mute = parser.isSet("mute");
+ bool silent = parser.isSet("silent");
unsigned int zoomLevel = parser.value("zoom-level").toInt();
qDebug()<<"Zoom level is "<<zoomLevel<<endl;
- QString outputFileName;
- if(parser.isSet("output")){
- outputFileName = parser.value("output");
- }
- else{
- outputFileName = "s_" + inputFileName;
+ QString outputName;
+ if(parser.isSet("output")) {
+ outputName = parser.value("output");
+ } else {
+ outputName = "s_" + inputFileName;
}
- qDebug()<<"Output file name is "<<outputFileName<<endl;
+ qDebug() << "Output file name is " << outputName << endl;
if(debug) {
debugLevel = Debug;
qInstallMessageHandler( debugOutput );
}
- if(mute) {
+ if(silent) {
debugLevel = Mute;
qInstallMessageHandler( debugOutput );
}
@@ -162,7 +182,23 @@ int main(int argc, char *argv[])
MarbleModel model;
ParsingRunnerManager manager(model.pluginManager());
- GeoDataDocument* map = manager.openFile(inputFileName, DocumentRole::MapDocument);
+
+ QElapsedTimer timer;
+ timer.start();
+
+ // Timeout is set to 10 min. If the file is reaaally huge, set it to something bigger.
+ GeoDataDocument* map = manager.openFile(inputFileName, DocumentRole::MapDocument, 600000);
+ if(map == nullptr) {
+ qWarning() << "File" << inputFileName << "couldn't be loaded.";
+ return -2;
+ }
+ qint64 parsingTime = timer.elapsed();
+ qDebug() << "Parsing time:" << parsingTime << "ms";
+
+ GeoDataDocument* mergeMap = nullptr;
+ if(parser.isSet("merge")) {
+ mergeMap = manager.openFile(mergeFileName, DocumentRole::MapDocument, 600000);
+ }
if(file.suffix() == "shp" && parser.isSet("cut-to-tiles")) {
ShpCoastlineProcessor processor(map);
@@ -178,19 +214,153 @@ int main(int argc, char *argv[])
GeoWriter writer;
writer.setDocumentType("0.6");
- QFile outputFile( QString("%1/%2/%3.osm").arg(zoomLevel).arg(x).arg(y) );
+ QFile outputFile;
+ if(parser.isSet("output")) {
+ outputFile.setFileName( QString("%1/%2/%3/%4.osm").arg(outputName).arg(zoomLevel).arg(x).arg(y) );
+ } else {
+ outputFile.setFileName( QString("%1/%2/%3.osm").arg(zoomLevel).arg(x).arg(y) );
+ }
+
+ QDir dir;
+ if(parser.isSet("output")) {
+ if(!dir.exists(outputName)) {
+ dir.mkdir(outputName);
+ }
+
+ if(!dir.exists(QString("%1/%2").arg(outputName).arg(zoomLevel))) {
+ dir.mkdir(QString("%1/%2").arg(outputName).arg(zoomLevel));
+ }
+
+ if(!dir.exists(QString("%1/%2/%3").arg(outputName).arg(zoomLevel).arg(x))) {
+ dir.mkdir(QString("%1/%2/%3").arg(outputName).arg(zoomLevel).arg(x));
+ }
+ } else {
+ if(!dir.exists(QString::number(zoomLevel))) {
+ dir.mkdir(QString::number(zoomLevel));
+ }
+ if(!dir.exists(QString("%1/%2").arg(zoomLevel).arg(x))) {
+ dir.mkdir(QString("%1/%2").arg(zoomLevel).arg(x));
+ }
+ }
+
+ outputFile.open( QIODevice::WriteOnly );
+ if ( !writer.write( &outputFile, tile ) ) {
+ qDebug() << "Could not write the file " << outputName;
+ return 4;
+ }
+
+ qInfo() << tile->name() << " done";
+
+ delete tile;
+ }
+ }
+ } else if (file.suffix() == "osm" && parser.isSet("cut-to-tiles") && parser.isSet("merge")) {
+ TinyPlanetProcessor processor(map);
+ processor.process();
+
+ ShpCoastlineProcessor shpProcessor(mergeMap);
+ shpProcessor.process();
+
+ unsigned int N = pow(2, zoomLevel);
+
+ for(unsigned int x = 0; x < N; ++x) {
+ for(unsigned int y = 0; y < N; ++y) {
+ GeoDataDocument* tile1 = processor.cutToTiles(zoomLevel, x, y);
+ GeoDataDocument* tile2 = shpProcessor.cutToTiles(zoomLevel, x, y);
+
+ GeoDataDocument* tile = mergeDocuments(tile1, tile2);
+
+ GeoWriter writer;
+ writer.setDocumentType("0.6");
+
+ QFile outputFile;
+ if(parser.isSet("output")) {
+ outputFile.setFileName( QString("%1/%2/%3/%4.osm").arg(outputName).arg(zoomLevel).arg(x).arg(y) );
+ } else {
+ outputFile.setFileName( QString("%1/%2/%3.osm").arg(zoomLevel).arg(x).arg(y) );
+ }
QDir dir;
- if(!dir.exists(QString::number(zoomLevel))) {
- dir.mkdir(QString::number(zoomLevel));
+ if(parser.isSet("output")) {
+ if(!dir.exists(outputName)) {
+ dir.mkdir(outputName);
+ }
+
+ if(!dir.exists(QString("%1/%2").arg(outputName).arg(zoomLevel))) {
+ dir.mkdir(QString("%1/%2").arg(outputName).arg(zoomLevel));
+ }
+
+ if(!dir.exists(QString("%1/%2/%3").arg(outputName).arg(zoomLevel).arg(x))) {
+ dir.mkdir(QString("%1/%2/%3").arg(outputName).arg(zoomLevel).arg(x));
+ }
+ } else {
+ if(!dir.exists(QString::number(zoomLevel))) {
+ dir.mkdir(QString::number(zoomLevel));
+ }
+ if(!dir.exists(QString("%1/%2").arg(zoomLevel).arg(x))) {
+ dir.mkdir(QString("%1/%2").arg(zoomLevel).arg(x));
+ }
}
- if(!dir.exists(QString("%1/%2").arg(zoomLevel).arg(x))) {
- dir.mkdir(QString("%1/%2").arg(zoomLevel).arg(x));
+
+ outputFile.open( QIODevice::WriteOnly );
+ if ( !writer.write( &outputFile, tile ) ) {
+ qDebug() << "Could not write the file " << outputName;
+ return 4;
+ }
+
+ qInfo() << tile->name() << " done";
+
+ delete tile1;
+ delete tile2;
+ delete tile;
+ }
+ }
+ } else if (file.suffix() == "osm" && parser.isSet("cut-to-tiles")) {
+ TinyPlanetProcessor processor(map);
+
+ processor.process();
+
+ unsigned int N = pow(2, zoomLevel);
+
+ for(unsigned int x = 0; x < N; ++x) {
+ for(unsigned int y = 0; y < N; ++y) {
+ GeoDataDocument* tile = processor.cutToTiles(zoomLevel, x, y);
+
+ GeoWriter writer;
+ writer.setDocumentType("0.6");
+
+ QFile outputFile;
+ if(parser.isSet("output")) {
+ outputFile.setFileName( QString("%1/%2/%3/%4.osm").arg(outputName).arg(zoomLevel).arg(x).arg(y) );
+ } else {
+ outputFile.setFileName( QString("%1/%2/%3.osm").arg(zoomLevel).arg(x).arg(y) );
+ }
+
+ QDir dir;
+ if(parser.isSet("output")) {
+ if(!dir.exists(outputName)) {
+ dir.mkdir(outputName);
+ }
+
+ if(!dir.exists(QString("%1/%2").arg(outputName).arg(zoomLevel))) {
+ dir.mkdir(QString("%1/%2").arg(outputName).arg(zoomLevel));
+ }
+
+ if(!dir.exists(QString("%1/%2/%3").arg(outputName).arg(zoomLevel).arg(x))) {
+ dir.mkdir(QString("%1/%2/%3").arg(outputName).arg(zoomLevel).arg(x));
+ }
+ } else {
+ if(!dir.exists(QString::number(zoomLevel))) {
+ dir.mkdir(QString::number(zoomLevel));
+ }
+ if(!dir.exists(QString("%1/%2").arg(zoomLevel).arg(x))) {
+ dir.mkdir(QString("%1/%2").arg(zoomLevel).arg(x));
+ }
}
outputFile.open( QIODevice::WriteOnly );
if ( !writer.write( &outputFile, tile ) ) {
- qDebug() << "Could not write the file " << outputFileName;
+ qDebug() << "Could not write the file " << outputName;
return 4;
}
@@ -208,18 +378,18 @@ int main(int argc, char *argv[])
else{
NodeReducer reducer(map, zoomLevel);
reducer.process();
- QFile outputFile(outputFileName);
+ QFile outputFile(outputName);
GeoWriter writer;
writer.setDocumentType("0.6");
-
+
outputFile.open( QIODevice::WriteOnly );
if ( !writer.write( &outputFile, map ) ) {
- qDebug() << "Could not write the file " << outputFileName;
+ qDebug() << "Could not write the file " << outputName;
return 4;
- }
+ }
}
-
+ } else {
}