Commit ff044c42 authored by Dávid Kolozsvári's avatar Dávid Kolozsvári Committed by Dennis Nienhüser

Updated the osm-simplify tool to work on the coastline shapefile provided by...

Updated the osm-simplify tool to work on the coastline shapefile provided by the openstreetmap database.

Summary: The shapefile can be found at: http://openstreetmapdata.com/data/land-polygons

Test Plan: Still has some issues, like some polygons are rendered as linestrings inside Marble.

Reviewers: nienhueser, rahn

Subscribers: #marble

Tags: #marble

Differential Revision: https://phabricator.kde.org/D2007
parent 7b68c803
This diff is collapsed.
//
// 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 BASECLIPPER_H
#define BASECLIPPER_H
#include <QPointF>
#include "GeoDataLinearRing.h"
#include "GeoDataLatLonBox.h"
using namespace Marble;
class BaseClipper
{
public:
BaseClipper();
static qreal tileX2lon( unsigned int x, unsigned int maxTileX );
static qreal tileY2lat( unsigned int y, unsigned int maxTileY );
static QPolygonF* lineString2Qpolygon(const GeoDataLineString &lineString);
static QPolygonF* linearRing2Qpolygon(const GeoDataLinearRing &linearRing);
static GeoDataLineString* qPolygon2lineString(const QPolygonF& polygon);
static GeoDataLinearRing* qPolygon2linearRing(const QPolygonF& polygon);
void initClipRect(const GeoDataLatLonBox& clippingBox);
void clipPolyObject ( const QPolygonF & sourcePolygon,
QVector<QPolygonF> & clippedPolyObjects,
bool isClosed );
private:
inline int sector( const QPointF & point ) const;
inline QPointF clipTop( qreal m, const QPointF & point ) const;
inline QPointF clipLeft( qreal m, const QPointF & point ) const;
inline QPointF clipBottom( qreal m, const QPointF & point ) const;
inline QPointF clipRight( qreal m, const QPointF & point ) const;
inline void clipMultiple( QPolygonF & clippedPolyObject,
QVector<QPolygonF> & clippedPolyObjects,
bool isClosed );
inline void clipOnce( QPolygonF & clippedPolyObject,
QVector<QPolygonF> & clippedPolyObjects,
bool isClosed );
inline void clipOnceCorner( QPolygonF & clippedPolyObject,
QVector<QPolygonF> & clippedPolyObjects,
const QPointF& corner,
const QPointF& point,
bool isClosed ) const;
inline void clipOnceEdge( QPolygonF & clippedPolyObject,
QVector<QPolygonF> & clippedPolyObjects,
const QPointF& point,
bool isClosed ) const;
static inline qreal _m( const QPointF & start, const QPointF & end );
qreal m_left;
qreal m_right;
qreal m_top;
qreal m_bottom;
int m_currentSector;
int m_previousSector;
QPointF m_currentPoint;
QPointF m_previousPoint;
};
#endif // BASECLIPPER_H
//
// 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 "BaseFilter.h"
#include "GeoDataDocument.h"
......
//
// 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 OBJECTHANDLER_H
#define OBJECTHANDLER_H
......
cmake_minimum_required(VERSION 2.8.12)
SET (TARGET osm-simplify)
PROJECT (${TARGET})
find_package(Qt5Core REQUIRED)
find_package(Qt5Widgets)
find_package(Qt5Declarative)
find_package(Qt5Widgets REQUIRED)
find_package(Qt5Declarative REQUIRED)
find_package(Qt5Gui REQUIRED)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
../../src/plugins/runner/osm
../../src/plugins/runner/osm/writers
../../src/plugins/runner/osm/translators
../../src/lib/marble/osm
../../src/lib/marble/geodata/writer
../../src/lib/marble/geodata/parser
../../src/lib/marble/geodata/data
......@@ -20,30 +21,15 @@ include_directories(
set( ${TARGET}_SRC
main.cpp
BaseClipper.cpp
BaseFilter.cpp
PlacemarkFilter.cpp
ShpCoastlineProcessor.cpp
LineStringProcessor.cpp
../../src/plugins/runner/osm/OsmParser.cpp
../../src/plugins/runner/osm/o5mreader.cpp
../../src/plugins/runner/osm/OsmElementDictionary.cpp
../../src/plugins/runner/osm/OsmNode.cpp
../../src/plugins/runner/osm/OsmParser.cpp
../../src/plugins/runner/osm/OsmPlugin.cpp
../../src/plugins/runner/osm/OsmRelation.cpp
../../src/plugins/runner/osm/OsmRunner.cpp
../../src/plugins/runner/osm/OsmWay.cpp
../../src/plugins/runner/osm/translators/OsmDocumentTagTranslator.cpp
../../src/plugins/runner/osm/translators/OsmFeatureTagTranslator.cpp
../../src/plugins/runner/osm/translators/OsmPlacemarkTagTranslator.cpp
../../src/plugins/runner/osm/writers/OsmNodeTagWriter.cpp
../../src/plugins/runner/osm/writers/OsmObjectAttributeWriter.cpp
../../src/plugins/runner/osm/writers/OsmRelationTagWriter.cpp
../../src/plugins/runner/osm/writers/OsmTagTagWriter.cpp
../../src/plugins/runner/osm/writers/OsmTagWriter.cpp
../../src/plugins/runner/osm/writers/OsmWayTagWriter.cpp
)
add_definitions( -DMAKE_MARBLE_LIB )
add_executable( ${TARGET} ${${TARGET}_SRC} )
target_link_libraries( ${TARGET} )
target_link_libraries( ${TARGET} Qt5::Core marblewidget-qt5 )
target_link_libraries( ${TARGET} Qt5::Core marblewidget-qt5)
//
// 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 "LineStringProcessor.h"
#include "GeoDataPlacemark.h"
#include "GeoDataGeometry.h"
#include "GeoDataLineString.h"
LineStringProcessor::LineStringProcessor(GeoDataDocument* document) :
PlacemarkFilter(document, GeoDataTypes::GeoDataLineStringType)
PlacemarkFilter(document)
{
QList<GeoDataPlacemark*> toRemove;
foreach (GeoDataObject* placemark, m_objects) {
if( static_cast<GeoDataPlacemark*>(placemark)->geometry()->nodeType() != GeoDataTypes::GeoDataLineStringType) {
toRemove.append(static_cast<GeoDataPlacemark*>(placemark));
}
}
foreach (GeoDataObject* placemark, toRemove) {
m_objects.removeOne(placemark);
}
}
void LineStringProcessor::process()
{
qDebug() << "Polylines to process: " << m_objects.size();
QList<GeoDataObject*> polylinesToDrop;
foreach (GeoDataObject* polyline, m_objects) {
switch(static_cast<GeoDataPlacemark*>(polyline)->visualCategory())
{
......@@ -43,4 +66,7 @@ void LineStringProcessor::process()
}
qDebug() << "Polylines dropped: " << removed;
qDebug() << m_document->name();
}
//
// 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 LINESTRINGHANDLER_H
#define LINESTRINGHANDLER_H
......
//
// 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 "PlacemarkFilter.h"
#include "GeoDataPlacemark.h"
PlacemarkFilter::PlacemarkFilter(GeoDataDocument *document, const char *type) :
PlacemarkFilter::PlacemarkFilter(GeoDataDocument *document) :
BaseFilter(document, GeoDataTypes::GeoDataPlacemarkType)
{
QList<GeoDataObject*> toRemove;
foreach (GeoDataObject* placemark, m_objects) {
if( static_cast<GeoDataPlacemark*>(placemark)->geometry()->nodeType() != type) {
toRemove.append(placemark);
}
}
foreach (GeoDataObject* placemark, toRemove) {
m_objects.removeOne(placemark);
}
qDebug() << "Placemark count:" << m_objects.size();
}
//
// 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 PLACEMARKHANDLER_H
#define PLACEMARKHANDLER_H
......@@ -6,7 +16,7 @@
class PlacemarkFilter : public BaseFilter
{
public:
PlacemarkFilter(GeoDataDocument* document, const char *type);
PlacemarkFilter(GeoDataDocument* document);
};
#endif // PLACEMARKHANDLER_H
//
// 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 "ShpCoastlineProcessor.h"
#include "BaseClipper.h"
#include "GeoDataPlacemark.h"
#include "OsmPlacemarkData.h"
#include <QDebug>
ShpCoastlineProcessor::ShpCoastlineProcessor(GeoDataDocument* document) :
PlacemarkFilter(document)
{
}
void ShpCoastlineProcessor::process()
{
OsmPlacemarkData marbleLand;
marbleLand.addTag("marble_land","landmass");
foreach (GeoDataObject* object, m_objects) {
GeoDataPlacemark* placemark = static_cast<GeoDataPlacemark*>(object);
if(placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType) {
placemark->setOsmData(marbleLand);
}
}
}
GeoDataDocument *ShpCoastlineProcessor::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);
// qDebug() << tileName;
// qDebug() << "west: " << west*RAD2DEG << "\t east: " << east*RAD2DEG;
// qDebug() << "north: " << north*RAD2DEG << "\t south: " << south*RAD2DEG;
// qDebug() << "\n";
tileBoundary.setBoundaries(north, south, east, west);
foreach (GeoDataObject* object, m_objects) {
GeoDataPlacemark* placemark = static_cast<GeoDataPlacemark*>(object);
if(placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType) {
GeoDataPolygon* marblePolygon = static_cast<GeoDataPolygon*>(placemark->geometry());
if(tileBoundary.intersects(marblePolygon->latLonAltBox())) {
BaseClipper clipper;
clipper.initClipRect(tileBoundary);
QVector<QPolygonF> clippedPolygons;
QPolygonF outerBoundary = *BaseClipper::linearRing2Qpolygon(marblePolygon->outerBoundary());
qDebug() << "Size before:" << outerBoundary.size();
qDebug() << "Clipping...";
clipper.clipPolyObject(outerBoundary, clippedPolygons, true);
qDebug() << "done.";
qDebug() << "Number of polygons after clipping: " << clippedPolygons.size();
qDebug() << "Size(s) after:";
foreach(const QPolygonF& polygon, clippedPolygons) {
qDebug() << polygon.size();
// Dirty fix to close the polygons.
GeoDataLinearRing outerBoundary = *BaseClipper::qPolygon2linearRing(polygon);
if(outerBoundary.first() != outerBoundary.last()) {
outerBoundary.append(outerBoundary.first());
}
GeoDataPolygon* newMarblePolygon = new GeoDataPolygon();
newMarblePolygon->setOuterBoundary(outerBoundary);
GeoDataPlacemark* newPlacemark = new GeoDataPlacemark();
newPlacemark->setGeometry(newMarblePolygon);
newPlacemark->setVisualCategory(GeoDataFeature::Landmass);
newPlacemark->setOsmData(placemark->osmData());
tile->append(newPlacemark);
}
qDebug() << "";
}
}
}
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 COASTLINEFILTER_H
#define COASTLINEFILTER_H
#include "PlacemarkFilter.h"
class ShpCoastlineProcessor : public PlacemarkFilter
{
public:
ShpCoastlineProcessor(GeoDataDocument* document);
virtual void process();
GeoDataDocument* cutToTiles(unsigned int zoomLevel, unsigned int tileX, unsigned int tileY);
};
#endif // COASTLINEFILTER_H
......@@ -8,18 +8,22 @@
// Copyright 2016 David Kolozsvari <freedawson@gmail.com>
//
#include "OsmParser.h"
#include "GeoWriter.h"
#include "MarbleModel.h"
#include "ParsingRunnerManager.h"
#include <QCoreApplication>
#include <QApplication>
#include <QCommandLineParser>
#include <QDebug>
#include <QFileInfo>
#include <QTime>
#include <QDir>
#include <QString>
#include <QMessageLogContext>
#include "LineStringProcessor.h"
#include "ShpCoastlineProcessor.h"
using namespace Marble;
......@@ -41,17 +45,17 @@ void debugOutput( QtMsgType type, const QMessageLogContext &context, const QStri
break;
case QtInfoMsg:
if ( debugLevel < Mute ) {
qDebug() << "Debug: " << context.file << ":" << context.line << " " << msg;
qInfo() << "Info: " << context.file << ":" << context.line << " " << msg;
}
break;
case QtWarningMsg:
if ( debugLevel < Mute ) {
qDebug() << "Info: " << context.file << ":" << context.line << " " << msg;
qDebug() << "Warning: " << context.file << ":" << context.line << " " << msg;
}
break;
case QtCriticalMsg:
if ( debugLevel < Mute ) {
qDebug() << "Warning: " << context.file << ":" << context.line << " " << msg;
qDebug() << "Critical: " << context.file << ":" << context.line << " " << msg;
}
break;
case QtFatalMsg:
......@@ -69,17 +73,16 @@ void usage()
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
QApplication app(argc, argv);
QCoreApplication::setApplicationName("osm-simplify");
QCoreApplication::setApplicationVersion("0.1");
QApplication::setApplicationName("osm-simplify");
QApplication::setApplicationVersion("0.1");
QCommandLineParser parser;
parser.setApplicationDescription("A tool for Marble, which is used to reduce the details of osm maps.");
parser.addHelpOption();
parser.addVersionOption();
parser.addPositionalArgument("input.osm", "The input .osm file.");
parser.addPositionalArgument("output.osm", "The output .osm file.");
parser.addPositionalArgument("input", "The input .osm or .shp file.");
parser.addOptions({
{
......@@ -93,10 +96,16 @@ int main(int argc, char *argv[])
},
{
{"ns", "no-streets-smaller-than"},
QCoreApplication::translate("main", "eliminates streets which have realsize smaller than <real number>"),
QCoreApplication::translate("main", "real number")
{"c", "cut-to-tiles"},
QCoreApplication::translate("main", "Cuts into tiles based on the zoom level passed by <number>"),
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", "output_file.osm")
}
});
// Process the actual command line arguments given by the user
......@@ -110,11 +119,10 @@ int main(int argc, char *argv[])
// input is args.at(0), output is args.at(1)
QString inputFileName = args.at(0);
QString outputFileName = args.at(1);
bool debug = parser.isSet("debug");
bool mute = parser.isSet("mute");
QString smallStreetLimit = parser.value("no-streets-smaller-than"); // just an example
unsigned int zoomLevel = parser.value("cut-to-tiles").toInt();
QString outputFileName = parser.value("output");
if(debug) {
debugLevel = Debug;
......@@ -132,36 +140,49 @@ int main(int argc, char *argv[])
return 2;
}
GeoDataDocument* osmMap;
if ( file.suffix() == "osm") {
MarbleModel model;
ParsingRunnerManager manager(model.pluginManager());
GeoDataDocument* map = manager.openFile(inputFileName, DocumentRole::MapDocument);
QString error;
osmMap = OsmParser::parse(inputFileName, error);
if(file.suffix() == "shp" && parser.isSet("cut-to-tiles")) {
ShpCoastlineProcessor processor(map);
if(!error.isEmpty()) {
qDebug() << error;
return 3;
}
} else {
qDebug() << "Unsupported file format: " << inputFileName;
return 5;
}
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");
LineStringProcessor processor(osmMap);
QFile outputFile( QString("%1/%2/%3.osm").arg(zoomLevel).arg(x).arg(y) );
processor.process();
QDir dir;
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));
}
GeoWriter writer;
writer.setDocumentType("0.6");
outputFile.open( QIODevice::WriteOnly );
if ( !writer.write( &outputFile, tile ) ) {
qDebug() << "Could not write the file " << outputFileName;
return 4;
}
QFile outputFile( outputFileName );
outputFile.open( QIODevice::WriteOnly );
if ( !writer.write( &outputFile, osmMap ) ) {
qDebug() << "Could not write the file " << outputFileName;
return 4;
qInfo() << tile->name() << " done";
delete tile;
}
}
} else {
// future functionality
}
qInfo() << "Done.";
return 0;
}
Markdown is supported
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