Commit a927ef05 authored by Dávid Kolozsvári's avatar Dávid Kolozsvári
Browse files

Latest version of the osm-simplify tool. Added TinyPlanetProcessor class,...

Latest version of the osm-simplify tool. Added TinyPlanetProcessor class, which cuts to tiles .osm files.
parent 725400a8
......@@ -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();
}
}
}
......
......@@ -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 );
......
......@@ -25,6 +25,7 @@ BaseFilter.cpp
PlacemarkFilter.cpp
ShpCoastlineProcessor.cpp
LineStringProcessor.cpp
TinyPlanetProcessor.cpp
NodeReducer.cpp
)
......
//
// 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 <freedawson@gmail.com>
//
#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;
}
//
// 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 <freedawson@gmail.com>
//
#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
......@@ -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 {
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment