diff --git a/tools/osm-simplify/BaseClipper.cpp b/tools/osm-simplify/BaseClipper.cpp --- a/tools/osm-simplify/BaseClipper.cpp +++ b/tools/osm-simplify/BaseClipper.cpp @@ -110,7 +110,7 @@ { 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); diff --git a/tools/osm-simplify/CMakeLists.txt b/tools/osm-simplify/CMakeLists.txt --- a/tools/osm-simplify/CMakeLists.txt +++ b/tools/osm-simplify/CMakeLists.txt @@ -25,10 +25,11 @@ PlacemarkFilter.cpp ShpCoastlineProcessor.cpp LineStringProcessor.cpp + TinyPlanetProcessor.cpp + NodeReducer.cpp ) add_definitions( -DMAKE_MARBLE_LIB ) add_executable( ${TARGET} ${${TARGET}_SRC} ) -target_link_libraries( ${TARGET} ) target_link_libraries( ${TARGET} Qt5::Core marblewidget-qt5) diff --git a/tools/osm-simplify/TinyPlanetProcessor.h b/tools/osm-simplify/TinyPlanetProcessor.h new file mode 100644 --- /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 +// + +#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/TinyPlanetProcessor.cpp b/tools/osm-simplify/TinyPlanetProcessor.cpp new file mode 100644 --- /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 +// + +#include "TinyPlanetProcessor.h" + +#include "BaseClipper.h" + +#include "GeoDataPlacemark.h" +#include "OsmPlacemarkData.h" + +#include +#include + +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(object); + + if(tileBoundary.intersects(placemark->geometry()->latLonAltBox())) { + + if(placemark->visualCategory() == GeoDataFeature::Landmass) { + qDebug() << "It's a landmass, but the geometry's nodetype is:" << placemark->geometry()->nodeType(); + } + + if(placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType) { + GeoDataPolygon* marblePolygon = static_cast(placemark->geometry()); + + QVector clippedPolygons; + + QPolygonF outerBoundary = BaseClipper::linearRing2Qpolygon(marblePolygon->outerBoundary()); + + clipper.clipPolyObject(outerBoundary, clippedPolygons, true); + + foreach(const QPolygonF& polygon, clippedPolygons) { + qDebug() << polygon.size(); + + 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(placemark->geometry()); + + QVector clippedPolygons; + + QPolygonF way = BaseClipper::lineString2Qpolygon(*marbleWay); + + clipper.clipPolyObject(way, clippedPolygons, false); + + foreach(const QPolygonF& polygon, clippedPolygons) { + qDebug() << polygon.size(); + + GeoDataLineString* newMarbleWay = new GeoDataLineString(BaseClipper::qPolygon2lineString(polygon)); + + if(newMarbleWay->first() == newMarbleWay->last()) { + qDebug() << "first = last, but it shouldn't. What to do?"; + qDebug() << "Visual category:" << placemark->visualCategory(); + qDebug() << "Let's delete the last node..."; + newMarbleWay->remove(newMarbleWay->size() - 1); + } + + GeoDataPlacemark* newPlacemark = new GeoDataPlacemark(); + newPlacemark->setGeometry(newMarbleWay); + newPlacemark->setVisualCategory(placemark->visualCategory()); + newPlacemark->setOsmData(placemark->osmData()); + + tile->append(newPlacemark); + } + } else if (placemark->geometry()->nodeType() == GeoDataTypes::GeoDataLinearRingType) { + + if(placemark->visualCategory() != GeoDataFeature::Landmass) { + GeoDataLinearRing* marbleClosedWay = static_cast(placemark->geometry()); + + QVector 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) { + qDebug() << polygon.size(); + + // When a linearRing is cut to pieces, the resulting geometries will be lineStrings + GeoDataLineString* newMarbleWay = new GeoDataLineString(BaseClipper::qPolygon2lineString(polygon)); + + if(newMarbleWay->first() == newMarbleWay->last()) { + qDebug() << "first = last, but it shouldn't. What to do?"; + qDebug() << "Visual category:" << placemark->visualCategory(); + qDebug() << "Let's delete the last node..."; + newMarbleWay->remove(newMarbleWay->size() - 1); + } + + GeoDataPlacemark* newPlacemark = new GeoDataPlacemark(); + newPlacemark->setGeometry(newMarbleWay); + newPlacemark->setVisualCategory(placemark->visualCategory()); + newPlacemark->setOsmData(placemark->osmData()); + + tile->append(newPlacemark); + } + + } + } else { + tile->append(placemark); + } + } + } + + + return tile; +} diff --git a/tools/osm-simplify/main.cpp b/tools/osm-simplify/main.cpp --- a/tools/osm-simplify/main.cpp +++ b/tools/osm-simplify/main.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -24,6 +23,8 @@ #include "LineStringProcessor.h" #include "ShpCoastlineProcessor.h" +#include "TinyPlanetProcessor.h" +#include "NodeReducer.h" using namespace Marble; @@ -65,12 +66,24 @@ } } } + 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,19 +104,35 @@ }, { - {"m","mute"}, + {"s","silent"}, QCoreApplication::translate("main", "Don't output to terminal.") }, { + {"m","merge"}, + QCoreApplication::translate("main", "Merge the main document with the file . 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 by "), + QCoreApplication::translate("main", "Cuts into tiles based on the zoom level passed using -z."), + }, + + { + {"n", "node-reduce"}, + QCoreApplication::translate("main", "Reduces the number of nodes for a given way based on zoom level"), + }, + + { + {"z", "zoom-level"}, + QCoreApplication::translate("main", "Zoom level according to which OSM information has to be processed."), QCoreApplication::translate("main", "number") }, { {"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") } }); @@ -119,16 +148,25 @@ // 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"); - unsigned int zoomLevel = parser.value("cut-to-tiles").toInt(); - QString outputFileName = parser.value("output"); + bool silent = parser.isSet("silent"); + unsigned int zoomLevel = parser.value("zoom-level").toInt(); + qDebug()<<"Zoom level is "<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)); + } + } + + 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) ); } - if(!dir.exists(QString("%1/%2").arg(zoomLevel).arg(x))) { - dir.mkdir(QString("%1/%2").arg(zoomLevel).arg(x)); + + 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; } @@ -179,8 +356,28 @@ delete tile; } } + } else if(parser.isSet("node-reduce")) { + qDebug()<<"Entered Node reduce"<