diff --git a/tools/osm-simplify/BaseClipper.h b/tools/osm-simplify/BaseClipper.h new file mode 100644 --- /dev/null +++ b/tools/osm-simplify/BaseClipper.h @@ -0,0 +1,83 @@ +// +// 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 BASECLIPPER_H +#define BASECLIPPER_H + +#include + +#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 & 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 & clippedPolyObjects, + bool isClosed ); + inline void clipOnce( QPolygonF & clippedPolyObject, + QVector & clippedPolyObjects, + bool isClosed ); + inline void clipOnceCorner( QPolygonF & clippedPolyObject, + QVector & clippedPolyObjects, + const QPointF& corner, + const QPointF& point, + bool isClosed ) const; + inline void clipOnceEdge( QPolygonF & clippedPolyObject, + QVector & 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 diff --git a/tools/osm-simplify/BaseClipper.cpp b/tools/osm-simplify/BaseClipper.cpp new file mode 100644 --- /dev/null +++ b/tools/osm-simplify/BaseClipper.cpp @@ -0,0 +1,849 @@ +// +// 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 "BaseClipper.h" + +#include "MarbleMath.h" + +#include +#include + +BaseClipper::BaseClipper() : + m_left(0.0), + m_right(0.0), + m_top(0.0), + m_bottom(0.0), + m_currentSector(4), + m_previousSector(4), + m_currentPoint(QPointF()), + m_previousPoint(QPointF()) +{ + +} + + + +QPolygonF *BaseClipper::lineString2Qpolygon(const GeoDataLineString& lineString) +{ + QPolygonF* polygon = new QPolygonF(); + foreach (const GeoDataCoordinates& coord, lineString) { + // Need to flip the Y axis(latitude) + QPointF point(coord.longitude(), -coord.latitude()); + polygon->append(point); + } + + return polygon; +} + +QPolygonF *BaseClipper::linearRing2Qpolygon(const GeoDataLinearRing& linearRing) +{ + QPolygonF* polygon = new QPolygonF(); + foreach (const GeoDataCoordinates& coord, linearRing) { + // Need to flip the Y axis(latitude) + QPointF point(coord.longitude(), -coord.latitude()); + polygon->append(point); + } + + return polygon; +} + +GeoDataLineString *BaseClipper::qPolygon2lineString(const QPolygonF& polygon) +{ + GeoDataLineString* lineString = new GeoDataLineString(); + foreach (const QPointF& point, polygon) { + // Flipping back the Y axis + GeoDataCoordinates coord(point.x(), -point.y()); + lineString->append(coord); + } + + return lineString; +} + +GeoDataLinearRing *BaseClipper::qPolygon2linearRing(const QPolygonF& polygon) +{ + GeoDataLinearRing* linearRing = new GeoDataLinearRing(); + foreach (const QPointF& point, polygon) { + // Flipping back the Y axis + GeoDataCoordinates coord(point.x(), -point.y()); + linearRing->append(coord); + } + + return linearRing; +} + +qreal BaseClipper::tileX2lon( unsigned int x, unsigned int maxTileX ) +{ + return ( (2*M_PI * x) / maxTileX - M_PI ); +} + +qreal BaseClipper::tileY2lat( unsigned int y, unsigned int maxTileY ) +{ + return gd( M_PI - (2*M_PI * y) / maxTileY ) * (90.0 / 85.0511); +} + + + + +void BaseClipper::initClipRect (const GeoDataLatLonBox &clippingBox) +{ + m_left = clippingBox.west(); + m_right = clippingBox.east(); + + // Had to flip the 'Y' axis, because the origo of the coordinate system in which the + // geographics coordinates are is based in the bottom left corner, while the + // screencoordinatas on which this clipper operated are in an upper left corner based origo. + + m_top = -clippingBox.north(); + m_bottom = -clippingBox.south(); +} + +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 + // 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; +} + + +QPointF BaseClipper::clipTop( qreal m, const QPointF & point ) const +{ + return QPointF( ( m_top - point.y() ) / m + point.x(), m_top ); +} + +QPointF BaseClipper::clipLeft( qreal m, const QPointF & point ) const +{ + return QPointF( m_left, ( m_left - point.x() ) * m + point.y() ); +} + +QPointF BaseClipper::clipBottom( qreal m, const QPointF & point ) const +{ + return QPointF( ( m_bottom - point.y() ) / m + point.x(), m_bottom ); +} + +QPointF BaseClipper::clipRight( qreal m, const QPointF & point ) const +{ + return QPointF( m_right, ( m_right - point.x() ) * m + point.y() ); +} + +int BaseClipper::sector( const QPointF & point ) const +{ + // If we think of the image borders as (infinitely long) parallel + // lines then the plane is divided into 9 sectors. Each of these + // sections is identified by a unique keynumber (currentSector): + // + // 0 | 1 | 2 + // --+---+-- + // 3 | 4 | 5 <- sector number "4" represents the onscreen sector / viewport + // --+---+-- + // 6 | 7 | 8 + // + + // Figure out the section of the current point. + int xSector = 1; + if ( point.x() < m_left ) + xSector = 0; + else if ( point.x() > m_right ) + xSector = 2; + + int ySector = 3; + if ( point.y() < m_top ) + ySector = 0; + else if ( point.y() > m_bottom ) + ySector = 6; + + // By adding xSector and ySector we get a + // sector number of the values shown in the ASCII-art graph above. + return ySector + xSector; +} + +void BaseClipper::clipPolyObject ( const QPolygonF & polygon, + QVector & clippedPolyObjects, + bool isClosed ) +{ + // Only create a new polyObject as soon as we know for sure that + // the current point is on the screen. + QPolygonF clippedPolyObject = QPolygonF(); + + const QVector::const_iterator itStartPoint = polygon.constBegin(); + const QVector::const_iterator itEndPoint = polygon.constEnd(); + QVector::const_iterator itPoint = itStartPoint; + + // We use a while loop to be able to cover linestrings as well as linear rings: + // Linear rings require to tessellate the path from the last node to the first node + // which isn't really convenient to achieve with a for loop ... + + bool processingLastNode = false; + + while ( itPoint != itEndPoint ) { + m_currentPoint = (*itPoint); + // qDebug() << "m_currentPoint.x()" << m_currentPoint.x() << "m_currentPOint.y()" << m_currentPoint.y(); + + // Figure out the sector of the current point. + m_currentSector = sector( m_currentPoint ); + + // Initialize the variables related to the previous point. + if ( itPoint == itStartPoint && processingLastNode == false ) { + if ( isClosed ) { + m_previousPoint = polygon.last(); + + // Figure out the sector of the previous point. + m_previousSector = sector( m_previousPoint ); + } + else { + m_previousSector = m_currentSector; + } + } + + // If the current point reaches a new sector, take care of clipping. + if ( m_currentSector != m_previousSector ) { + if ( m_currentSector == 4 || m_previousSector == 4 ) { + // In this case the current or the previous point is visible on the + // screen but not both. Hence we only need to clip once and require + // only one interpolation for both cases. + + clipOnce( clippedPolyObject, clippedPolyObjects, isClosed ); + } + else { + // This case mostly deals with lines that reach from one + // 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 ); + } + + m_previousSector = m_currentSector; + } + + // If the current point is onscreen, just add it to our final polygon. + if ( m_currentSector == 4 ) { + + clippedPolyObject << m_currentPoint; +#ifdef MARBLE_DEBUG + ++(m_debugNodeCount); +#endif + } + + m_previousPoint = m_currentPoint; + + // Now let's handle the case where we have a (closed) polygon and where the + // last point of the polyline is outside the viewport and the start point + // is inside the viewport. This needs special treatment + if ( processingLastNode ) { + break; + } + ++itPoint; + + if ( itPoint == itEndPoint && isClosed ) { + itPoint = itStartPoint; + processingLastNode = true; + } + } + + // Only add the pointer if there's node data available. + if ( !clippedPolyObject.isEmpty() ) { + clippedPolyObjects << clippedPolyObject; + } +} + + +void BaseClipper::clipMultiple( QPolygonF & clippedPolyObject, + QVector & clippedPolyObjects, + bool isClosed ) +{ + Q_UNUSED( clippedPolyObjects ) + Q_UNUSED( isClosed ) + + // Take care of adding nodes in the image corners if the iterator + // traverses off screen sections. + + qreal m = _m( m_previousPoint, m_currentPoint ); + + switch ( m_currentSector ) { + case 0: + if ( m_previousSector == 5 ) { + QPointF pointRight = clipRight( m, m_previousPoint ); + QPointF pointTop = clipTop( m, m_currentPoint ); + QPointF pointLeft = clipLeft( m, m_currentPoint ); + + if ( pointRight.y() > m_top ) { + clippedPolyObject << pointRight; + } else { + clippedPolyObject << QPointF( m_right, m_top ); + } + if ( pointTop.x() >= m_left && pointTop.x() < m_right ) + clippedPolyObject << pointTop; + if ( pointLeft.y() > m_top ) + clippedPolyObject << pointLeft; + } + else if ( m_previousSector == 7 ) { + QPointF pointBottom = clipBottom( m, m_previousPoint ); + QPointF pointTop = clipTop( m, m_currentPoint ); + QPointF pointLeft = clipLeft( m, m_currentPoint ); + + if ( pointBottom.x() > m_left ) { + clippedPolyObject << pointBottom; + } else { + clippedPolyObject << QPointF( m_left, m_bottom ); + } + if ( pointLeft.y() >= m_top && pointLeft.y() < m_bottom ) + clippedPolyObject << pointLeft; + if ( pointTop.x() > m_left ) + clippedPolyObject << pointTop; + } + else if ( m_previousSector == 8 ) { + QPointF pointBottom = clipBottom( m, m_previousPoint ); + QPointF pointRight = clipRight( m, m_previousPoint ); + QPointF pointTop = clipTop( m, m_currentPoint ); + QPointF pointLeft = clipLeft( m, m_currentPoint ); + + if ( pointBottom.x() > m_left && pointBottom.x() < m_right ) + clippedPolyObject << pointBottom; + if ( pointRight.y() > m_top && pointRight.y() < m_bottom ) + clippedPolyObject << pointRight; + if ( pointTop.x() > m_left && pointTop.x() < m_right ) + clippedPolyObject << pointTop; + if ( pointLeft.y() > m_top && pointLeft.y() < m_bottom ) + clippedPolyObject << pointLeft; + + if ( pointBottom.x() <= m_left && pointLeft.y() >= m_bottom ) + clippedPolyObject << QPointF( m_left, m_bottom ); + if ( pointTop.x() >= m_right && pointRight.y() <= m_top ) + clippedPolyObject << QPointF( m_right, m_top ); + } + + clippedPolyObject << QPointF( m_left, m_top ); + break; + + case 1: + if ( m_previousSector == 3 ) { + QPointF pointLeft = clipLeft( m, m_previousPoint ); + QPointF pointTop = clipTop( m, m_currentPoint ); + + if ( pointLeft.y() > m_top ) { + clippedPolyObject << pointLeft; + } else { + clippedPolyObject << QPointF( m_left, m_top ); + } + if ( pointTop.x() > m_left ) + clippedPolyObject << pointTop; + } + else if ( m_previousSector == 5 ) { + QPointF pointRight = clipRight( m, m_previousPoint ); + QPointF pointTop = clipTop( m, m_currentPoint ); + + if ( pointRight.y() > m_top ) { + clippedPolyObject << pointRight; + } else { + clippedPolyObject << QPointF( m_right, m_top ); + } + if ( pointTop.x() < m_right ) + clippedPolyObject << pointTop; + } + else if ( m_previousSector == 6 ) { + QPointF pointBottom = clipBottom( m, m_previousPoint ); + QPointF pointLeft = clipLeft( m, m_previousPoint ); + QPointF pointTop = clipTop( m, m_currentPoint ); + + if ( pointBottom.x() > m_left ) + clippedPolyObject << pointBottom; + if ( pointLeft.y() > m_top && pointLeft.y() <= m_bottom ) + clippedPolyObject << pointLeft; + if ( pointTop.x() > m_left ) { + clippedPolyObject << pointTop; + } else { + clippedPolyObject << QPointF( m_left, m_top ); + } + } + else if ( m_previousSector == 7 ) { + clippedPolyObject << clipBottom( m, m_previousPoint ); + clippedPolyObject << clipTop( m, m_currentPoint ); + } + else if ( m_previousSector == 8 ) { + QPointF pointBottom = clipBottom( m, m_previousPoint ); + QPointF pointRight = clipRight( m, m_previousPoint ); + QPointF pointTop = clipTop( m, m_currentPoint ); + + if ( pointBottom.x() < m_right ) + clippedPolyObject << pointBottom; + if ( pointRight.y() > m_top && pointRight.y() <= m_bottom ) + clippedPolyObject << pointRight; + if ( pointTop.x() < m_right ) { + clippedPolyObject << pointTop; + } else { + clippedPolyObject << QPointF( m_right, m_top ); + } + } + break; + + case 2: + if ( m_previousSector == 3 ) { + QPointF pointLeft = clipLeft( m, m_previousPoint ); + QPointF pointTop = clipTop( m, m_currentPoint ); + QPointF pointRight = clipRight( m, m_currentPoint ); + + if ( pointLeft.y() > m_top ) { + clippedPolyObject << pointLeft; + } else { + clippedPolyObject << QPointF( m_left, m_top ); + } + if ( pointTop.x() > m_left && pointTop.x() <= m_right ) + clippedPolyObject << pointTop; + if ( pointRight.y() > m_top ) + clippedPolyObject << pointRight; + } + else if ( m_previousSector == 7 ) { + QPointF pointBottom = clipBottom( m, m_previousPoint ); + QPointF pointTop = clipTop( m, m_currentPoint ); + QPointF pointRight = clipRight( m, m_currentPoint ); + + if ( pointBottom.x() < m_right ) { + clippedPolyObject << pointBottom; + } else { + clippedPolyObject << QPointF( m_right, m_bottom ); + } + if ( pointRight.y() >= m_top && pointRight.y() < m_bottom ) + clippedPolyObject << pointRight; + if ( pointTop.x() < m_right ) + clippedPolyObject << pointTop; + } + else if ( m_previousSector == 6 ) { + QPointF pointBottom = clipBottom( m, m_previousPoint ); + QPointF pointLeft = clipLeft( m, m_currentPoint ); + QPointF pointTop = clipTop( m, m_currentPoint ); + QPointF pointRight = clipRight( m, m_previousPoint ); + + if ( pointBottom.x() > m_left && pointBottom.x() < m_right ) + clippedPolyObject << pointBottom; + if ( pointLeft.y() > m_top && pointLeft.y() < m_bottom ) + clippedPolyObject << pointLeft; + if ( pointTop.x() > m_left && pointTop.x() < m_right ) + clippedPolyObject << pointTop; + if ( pointRight.y() > m_top && pointRight.y() < m_bottom ) + clippedPolyObject << pointRight; + + if ( pointBottom.x() >= m_right && pointRight.y() >= m_bottom ) + clippedPolyObject << QPointF( m_right, m_bottom ); + if ( pointTop.x() <= m_left && pointLeft.y() <= m_top ) + clippedPolyObject << QPointF( m_left, m_top ); + } + + clippedPolyObject << QPointF( m_right, m_top ); + break; + + case 3: + if ( m_previousSector == 7 ) { + QPointF pointBottom = clipBottom( m, m_previousPoint ); + QPointF pointLeft = clipLeft( m, m_currentPoint ); + + if ( pointBottom.x() > m_left ) + clippedPolyObject << pointBottom; + if ( pointLeft.y() < m_bottom ) { + clippedPolyObject << pointLeft; + } else { + clippedPolyObject << QPointF( m_left, m_bottom ); + } + } + else if ( m_previousSector == 1 ) { + QPointF pointTop = clipTop( m, m_previousPoint ); + QPointF pointLeft = clipLeft( m, m_currentPoint ); + + if ( pointTop.x() > m_left ) + clippedPolyObject << pointTop; + if ( pointLeft.y() > m_top ) { + clippedPolyObject << pointLeft; + } else { + clippedPolyObject << QPointF( m_left, m_top ); + } + } + else if ( m_previousSector == 8 ) { + QPointF pointRight = clipRight( m, m_previousPoint ); + QPointF pointBottom = clipBottom( m, m_previousPoint ); + QPointF pointLeft = clipLeft( m, m_currentPoint ); + + if ( pointRight.y() < m_bottom ) + clippedPolyObject << pointRight; + if ( pointBottom.x() > m_left && pointBottom.x() <= m_right ) + clippedPolyObject << pointBottom; + if ( pointLeft.y() < m_bottom ) { + clippedPolyObject << pointLeft; + } else { + clippedPolyObject << QPointF( m_left, m_bottom ); + } + } + else if ( m_previousSector == 5 ) { + clippedPolyObject << clipRight( m, m_previousPoint ); + clippedPolyObject << clipLeft( m, m_currentPoint ); + } + else if ( m_previousSector == 2 ) { + QPointF pointRight = clipRight( m, m_previousPoint ); + QPointF pointTop = clipTop( m, m_previousPoint ); + QPointF pointLeft = clipLeft( m, m_currentPoint ); + + if ( pointRight.y() > m_top ) + clippedPolyObject << pointRight; + if ( pointTop.x() > m_left && pointTop.x() <= m_right ) + clippedPolyObject << pointTop; + if ( pointLeft.y() > m_top ) { + clippedPolyObject << pointLeft; + } else { + clippedPolyObject << QPointF( m_left, m_top ); + } + } + break; + + case 5: + if ( m_previousSector == 7 ) { + QPointF pointBottom = clipBottom( m, m_previousPoint ); + QPointF pointRight = clipRight( m, m_currentPoint ); + + if ( pointBottom.x() < m_right ) + clippedPolyObject << pointBottom; + if ( pointRight.y() < m_bottom ) { + clippedPolyObject << pointRight; + } else { + clippedPolyObject << QPointF( m_right, m_bottom ); + } + } + else if ( m_previousSector == 1 ) { + QPointF pointTop = clipTop( m, m_previousPoint ); + QPointF pointRight = clipRight( m, m_currentPoint ); + + if ( pointTop.x() < m_right ) + clippedPolyObject << pointTop; + if ( pointRight.y() > m_top ) { + clippedPolyObject << pointRight; + } else { + clippedPolyObject << QPointF( m_right, m_top ); + } + } + else if ( m_previousSector == 6 ) { + QPointF pointLeft = clipLeft( m, m_previousPoint ); + QPointF pointBottom = clipBottom( m, m_previousPoint ); + QPointF pointRight = clipRight( m, m_currentPoint ); + + if ( pointLeft.y() < m_bottom ) + clippedPolyObject << pointLeft; + if ( pointBottom.x() >= m_left && pointBottom.x() < m_right ) + clippedPolyObject << pointBottom; + if ( pointRight.y() < m_bottom ) { + clippedPolyObject << pointRight; + } else { + clippedPolyObject << QPointF( m_right, m_bottom ); + } + } + else if ( m_previousSector == 3 ) { + clippedPolyObject << clipLeft( m, m_previousPoint ); + clippedPolyObject << clipRight( m, m_currentPoint ); + } + else if ( m_previousSector == 0 ) { + QPointF pointLeft = clipLeft( m, m_previousPoint ); + QPointF pointTop = clipTop( m, m_previousPoint ); + QPointF pointRight = clipRight( m, m_currentPoint ); + + if ( pointLeft.y() > m_top ) + clippedPolyObject << pointLeft; + if ( pointTop.x() >= m_left && pointTop.x() < m_right ) + clippedPolyObject << pointTop; + if ( pointRight.y() > m_top ) { + clippedPolyObject << pointRight; + } else { + clippedPolyObject << QPointF( m_right, m_top ); + } + } + break; + + case 6: + if ( m_previousSector == 5 ) { + QPointF pointRight = clipRight( m, m_previousPoint ); + QPointF pointBottom = clipBottom( m, m_currentPoint ); + QPointF pointLeft = clipLeft( m, m_currentPoint ); + + if ( pointRight.y() < m_bottom ) { + clippedPolyObject << pointRight; + } else { + clippedPolyObject << QPointF( m_right, m_bottom ); + } + if ( pointBottom.x() >= m_left && pointBottom.x() < m_right ) + clippedPolyObject << pointBottom; + if ( pointLeft.y() < m_bottom ) + clippedPolyObject << pointLeft; + } + else if ( m_previousSector == 1 ) { + QPointF pointTop = clipTop( m, m_previousPoint ); + QPointF pointLeft = clipLeft( m, m_currentPoint ); + QPointF pointBottom = clipBottom( m, m_currentPoint ); + + if ( pointTop.x() > m_left ) { + clippedPolyObject << pointTop; + } else { + clippedPolyObject << QPointF( m_left, m_top ); + } + if ( pointLeft.y() > m_top && pointLeft.y() <= m_bottom ) + clippedPolyObject << pointLeft; + if ( pointBottom.x() > m_left ) + clippedPolyObject << pointBottom; + } + else if ( m_previousSector == 2 ) { + QPointF pointTop = clipTop( m, m_currentPoint ); + QPointF pointRight = clipRight( m, m_previousPoint ); + QPointF pointBottom = clipBottom( m, m_previousPoint ); + QPointF pointLeft = clipLeft( m, m_currentPoint ); + + if ( pointTop.x() > m_left && pointTop.x() < m_right ) + clippedPolyObject << pointTop; + if ( pointRight.y() > m_top && pointRight.y() < m_bottom ) + clippedPolyObject << pointRight; + if ( pointBottom.x() > m_left && pointBottom.x() < m_right ) + clippedPolyObject << pointBottom; + if ( pointLeft.y() > m_top && pointLeft.y() < m_bottom ) + clippedPolyObject << pointLeft; + + if ( pointBottom.x() >= m_right && pointRight.y() >= m_bottom ) + clippedPolyObject << QPointF( m_right, m_bottom ); + if ( pointTop.x() <= m_left && pointLeft.y() <= m_top ) + clippedPolyObject << QPointF( m_left, m_top ); + } + + clippedPolyObject << QPointF( m_left, m_bottom ); + break; + + case 7: + if ( m_previousSector == 3 ) { + QPointF pointLeft = clipLeft( m, m_previousPoint ); + QPointF pointBottom = clipBottom( m, m_currentPoint ); + + if ( pointLeft.y() < m_bottom ) { + clippedPolyObject << pointLeft; + } else { + clippedPolyObject << QPointF( m_left, m_bottom ); + } + if ( pointBottom.x() > m_left ) + clippedPolyObject << pointBottom; + } + else if ( m_previousSector == 5 ) { + QPointF pointRight = clipRight( m, m_previousPoint ); + QPointF pointBottom = clipBottom( m, m_currentPoint ); + + if ( pointRight.y() < m_bottom ) { + clippedPolyObject << pointRight; + } else { + clippedPolyObject << QPointF( m_right, m_bottom ); + } + if ( pointBottom.x() < m_right ) + clippedPolyObject << pointBottom; + } + else if ( m_previousSector == 0 ) { + QPointF pointTop = clipTop( m, m_previousPoint ); + QPointF pointLeft = clipLeft( m, m_previousPoint ); + QPointF pointBottom = clipBottom( m, m_currentPoint ); + + if ( pointTop.x() > m_left ) + clippedPolyObject << pointTop; + if ( pointLeft.y() >= m_top && pointLeft.y() < m_bottom ) + clippedPolyObject << pointLeft; + if ( pointBottom.x() > m_left ) { + clippedPolyObject << pointBottom; + } else { + clippedPolyObject << QPointF( m_left, m_bottom ); + } + } + else if ( m_previousSector == 1 ) { + clippedPolyObject << clipTop( m, m_previousPoint ); + clippedPolyObject << clipBottom( m, m_currentPoint ); + } + else if ( m_previousSector == 2 ) { + QPointF pointTop = clipTop( m, m_previousPoint ); + QPointF pointRight = clipRight( m, m_previousPoint ); + QPointF pointBottom = clipBottom( m, m_currentPoint ); + + if ( pointTop.x() < m_right ) + clippedPolyObject << pointTop; + if ( pointRight.y() >= m_top && pointRight.y() < m_bottom ) + clippedPolyObject << pointRight; + if ( pointBottom.x() < m_right ) { + clippedPolyObject << pointBottom; + } else { + clippedPolyObject << QPointF( m_right, m_bottom ); + } + } + break; + + case 8: + if ( m_previousSector == 3 ) { + QPointF pointLeft = clipLeft( m, m_previousPoint ); + QPointF pointBottom = clipBottom( m, m_currentPoint ); + QPointF pointRight = clipRight( m, m_currentPoint ); + + if ( pointLeft.y() < m_bottom ) { + clippedPolyObject << pointLeft; + } else { + clippedPolyObject << QPointF( m_left, m_bottom ); + } + if ( pointBottom.x() > m_left && pointBottom.x() <= m_right ) + clippedPolyObject << pointBottom; + if ( pointRight.y() < m_bottom ) + clippedPolyObject << pointRight; + } + else if ( m_previousSector == 1 ) { + QPointF pointTop = clipTop( m, m_previousPoint ); + QPointF pointRight = clipRight( m, m_currentPoint ); + QPointF pointBottom = clipBottom( m, m_currentPoint ); + + if ( pointTop.x() < m_right ) { + clippedPolyObject << pointTop; + } else { + clippedPolyObject << QPointF( m_right, m_top ); + } + if ( pointRight.y() > m_top && pointRight.y() <= m_bottom ) + clippedPolyObject << pointRight; + if ( pointBottom.x() < m_right ) + clippedPolyObject << pointBottom; + } + else if ( m_previousSector == 0 ) { + QPointF pointTop = clipTop( m, m_currentPoint ); + QPointF pointLeft = clipLeft( m, m_currentPoint ); + QPointF pointBottom = clipBottom( m, m_previousPoint ); + QPointF pointRight = clipRight( m, m_previousPoint ); + + if ( pointTop.x() > m_left && pointTop.x() < m_right ) + clippedPolyObject << pointTop; + if ( pointLeft.y() > m_top && pointLeft.y() < m_bottom ) + clippedPolyObject << pointLeft; + if ( pointBottom.x() > m_left && pointBottom.x() < m_right ) + clippedPolyObject << pointBottom; + if ( pointRight.y() > m_top && pointRight.y() < m_bottom ) + clippedPolyObject << pointRight; + + if ( pointBottom.x() <= m_left && pointLeft.y() >= m_bottom ) + clippedPolyObject << QPointF( m_left, m_bottom ); + if ( pointTop.x() >= m_right && pointRight.y() <= m_top ) + clippedPolyObject << QPointF( m_right, m_top ); + } + + clippedPolyObject << QPointF( m_right, m_bottom ); + break; + + default: + break; + } +} + +void BaseClipper::clipOnceCorner( QPolygonF & clippedPolyObject, + QVector & clippedPolyObjects, + const QPointF& corner, + const QPointF& point, + bool isClosed ) const +{ + Q_UNUSED( clippedPolyObjects ) + Q_UNUSED( isClosed ) + + if ( m_currentSector == 4) { + // Appearing + clippedPolyObject << corner; + clippedPolyObject << point; + } else { + // Disappearing + clippedPolyObject << point; + clippedPolyObject << corner; + } +} + +void BaseClipper::clipOnceEdge( QPolygonF & clippedPolyObject, + QVector & clippedPolyObjects, + const QPointF& point, + bool isClosed ) const +{ + if ( m_currentSector == 4) { + // Appearing + if ( !isClosed ) { + clippedPolyObject = QPolygonF(); + } + clippedPolyObject << point; + } + else { + // Disappearing + clippedPolyObject << point; + if ( !isClosed ) { + clippedPolyObjects << clippedPolyObject; + } + } +} + +void BaseClipper::clipOnce( QPolygonF & clippedPolyObject, + QVector & clippedPolyObjects, + bool isClosed ) +{ + // Interpolate border points (linear interpolation) + QPointF point; + + // Calculating the slope. + qreal m = _m( m_previousPoint, m_currentPoint ); + + // Calculate in which sector the end of the line is located that is off screen + int offscreenpos = ( m_currentSector == 4 ) ? m_previousSector : m_currentSector; + + // "Rise over run" for all possible situations . + switch ( offscreenpos ) { + case 0: // topleft + point = clipTop( m, m_previousPoint ); + if ( point.x() < m_left ) { + point = clipLeft( m, point ); + } + clipOnceCorner( clippedPolyObject, clippedPolyObjects, QPointF( m_left, m_top ), point, isClosed ); + break; + case 1: // top + point = clipTop( m, m_previousPoint ); + clipOnceEdge( clippedPolyObject, clippedPolyObjects, point, isClosed ); + break; + case 2: // topright + point = clipTop( m, m_previousPoint ); + if ( point.x() > m_right ) { + point = clipRight( m, point ); + } + clipOnceCorner( clippedPolyObject, clippedPolyObjects, QPointF( m_right, m_top ), point, isClosed ); + break; + case 3: // left + point = clipLeft( m, m_previousPoint ); + clipOnceEdge( clippedPolyObject, clippedPolyObjects, point, isClosed ); + break; + case 5: // right + point = clipRight( m, m_previousPoint ); + clipOnceEdge( clippedPolyObject, clippedPolyObjects, point, isClosed ); + break; + case 6: // bottomleft + point = clipBottom( m, m_previousPoint ); + if ( point.x() < m_left ) { + point = clipLeft( m, point ); + } + clipOnceCorner( clippedPolyObject, clippedPolyObjects, QPointF( m_left, m_bottom ), point, isClosed ); + break; + case 7: // bottom + point = clipBottom( m, m_previousPoint ); + clipOnceEdge( clippedPolyObject, clippedPolyObjects, point, isClosed ); + break; + case 8: // bottomright + point = clipBottom( m, m_previousPoint ); + if ( point.x() > m_right ) { + point = clipRight( m, point ); + } + clipOnceCorner( clippedPolyObject, clippedPolyObjects, QPointF( m_right, m_bottom ), point, isClosed ); + break; + default: + break; + } + +} diff --git a/tools/osm-simplify/BaseFilter.h b/tools/osm-simplify/BaseFilter.h --- a/tools/osm-simplify/BaseFilter.h +++ b/tools/osm-simplify/BaseFilter.h @@ -1,3 +1,13 @@ +// +// 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 OBJECTHANDLER_H #define OBJECTHANDLER_H diff --git a/tools/osm-simplify/BaseFilter.cpp b/tools/osm-simplify/BaseFilter.cpp --- a/tools/osm-simplify/BaseFilter.cpp +++ b/tools/osm-simplify/BaseFilter.cpp @@ -1,3 +1,13 @@ +// +// 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 "BaseFilter.h" #include "GeoDataDocument.h" 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 @@ -1,16 +1,17 @@ +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 @@ 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) diff --git a/tools/osm-simplify/LineStringProcessor.h b/tools/osm-simplify/LineStringProcessor.h --- a/tools/osm-simplify/LineStringProcessor.h +++ b/tools/osm-simplify/LineStringProcessor.h @@ -1,3 +1,13 @@ +// +// 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 LINESTRINGHANDLER_H #define LINESTRINGHANDLER_H diff --git a/tools/osm-simplify/LineStringProcessor.cpp b/tools/osm-simplify/LineStringProcessor.cpp --- a/tools/osm-simplify/LineStringProcessor.cpp +++ b/tools/osm-simplify/LineStringProcessor.cpp @@ -1,19 +1,42 @@ +// +// 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 "LineStringProcessor.h" #include "GeoDataPlacemark.h" #include "GeoDataGeometry.h" #include "GeoDataLineString.h" + LineStringProcessor::LineStringProcessor(GeoDataDocument* document) : - PlacemarkFilter(document, GeoDataTypes::GeoDataLineStringType) + PlacemarkFilter(document) { + QList toRemove; + foreach (GeoDataObject* placemark, m_objects) { + if( static_cast(placemark)->geometry()->nodeType() != GeoDataTypes::GeoDataLineStringType) { + toRemove.append(static_cast(placemark)); + } + } + foreach (GeoDataObject* placemark, toRemove) { + m_objects.removeOne(placemark); + } } void LineStringProcessor::process() { + qDebug() << "Polylines to process: " << m_objects.size(); + QList polylinesToDrop; + foreach (GeoDataObject* polyline, m_objects) { switch(static_cast(polyline)->visualCategory()) { @@ -43,4 +66,7 @@ } qDebug() << "Polylines dropped: " << removed; + + qDebug() << m_document->name(); } + diff --git a/tools/osm-simplify/PlacemarkFilter.h b/tools/osm-simplify/PlacemarkFilter.h --- a/tools/osm-simplify/PlacemarkFilter.h +++ b/tools/osm-simplify/PlacemarkFilter.h @@ -1,12 +1,22 @@ +// +// 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 PLACEMARKHANDLER_H #define PLACEMARKHANDLER_H #include "BaseFilter.h" class PlacemarkFilter : public BaseFilter { public: - PlacemarkFilter(GeoDataDocument* document, const char *type); + PlacemarkFilter(GeoDataDocument* document); }; #endif // PLACEMARKHANDLER_H diff --git a/tools/osm-simplify/PlacemarkFilter.cpp b/tools/osm-simplify/PlacemarkFilter.cpp --- a/tools/osm-simplify/PlacemarkFilter.cpp +++ b/tools/osm-simplify/PlacemarkFilter.cpp @@ -1,19 +1,20 @@ +// +// 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 "PlacemarkFilter.h" #include "GeoDataPlacemark.h" -PlacemarkFilter::PlacemarkFilter(GeoDataDocument *document, const char *type) : +PlacemarkFilter::PlacemarkFilter(GeoDataDocument *document) : BaseFilter(document, GeoDataTypes::GeoDataPlacemarkType) { - QList toRemove; - foreach (GeoDataObject* placemark, m_objects) { - if( static_cast(placemark)->geometry()->nodeType() != type) { - toRemove.append(placemark); - } - } - - foreach (GeoDataObject* placemark, toRemove) { - m_objects.removeOne(placemark); - } + qDebug() << "Placemark count:" << m_objects.size(); } diff --git a/tools/osm-simplify/ShpCoastlineProcessor.h b/tools/osm-simplify/ShpCoastlineProcessor.h new file mode 100644 --- /dev/null +++ b/tools/osm-simplify/ShpCoastlineProcessor.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 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 diff --git a/tools/osm-simplify/ShpCoastlineProcessor.cpp b/tools/osm-simplify/ShpCoastlineProcessor.cpp new file mode 100644 --- /dev/null +++ b/tools/osm-simplify/ShpCoastlineProcessor.cpp @@ -0,0 +1,107 @@ +// +// 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 "ShpCoastlineProcessor.h" + +#include "BaseClipper.h" + +#include "GeoDataPlacemark.h" +#include "OsmPlacemarkData.h" + +#include + +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(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(object); + + if(placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType) { + GeoDataPolygon* marblePolygon = static_cast(placemark->geometry()); + + if(tileBoundary.intersects(marblePolygon->latLonAltBox())) { + BaseClipper clipper; + clipper.initClipRect(tileBoundary); + + QVector 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; +} 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 @@ -8,18 +8,22 @@ // Copyright 2016 David Kolozsvari // -#include "OsmParser.h" #include "GeoWriter.h" +#include "MarbleModel.h" +#include "ParsingRunnerManager.h" -#include +#include #include #include #include #include +#include +#include #include #include "LineStringProcessor.h" +#include "ShpCoastlineProcessor.h" using namespace Marble; @@ -41,17 +45,17 @@ 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 @@ 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 @@ }, { - {"ns", "no-streets-smaller-than"}, - QCoreApplication::translate("main", "eliminates streets which have realsize smaller than "), - QCoreApplication::translate("main", "real number") + {"c", "cut-to-tiles"}, + QCoreApplication::translate("main", "Cuts into tiles based on the zoom level passed by "), + 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 @@ // 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 @@ 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; }