diff --git a/tools/osm-simplify/BaseClipper.h b/tools/osm-simplify/BaseClipper.h --- a/tools/osm-simplify/BaseClipper.h +++ b/tools/osm-simplify/BaseClipper.h @@ -29,11 +29,11 @@ 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 QPolygonF lineString2Qpolygon(const GeoDataLineString &lineString, bool reverseOrder = false); + static QPolygonF linearRing2Qpolygon(const GeoDataLinearRing &linearRing, bool reverseOrder = false); - static GeoDataLineString qPolygon2lineString(const QPolygonF& polygon); - static GeoDataLinearRing qPolygon2linearRing(const QPolygonF& polygon); + static GeoDataLineString qPolygon2lineString(const QPolygonF& polygon, bool reverseOrder = false); + static GeoDataLinearRing qPolygon2linearRing(const QPolygonF& polygon, bool reverseOrder = false); void initClipRect(const GeoDataLatLonBox& clippingBox, int pointsToAddAtEdges); 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 @@ -104,49 +104,84 @@ -QPolygonF BaseClipper::lineString2Qpolygon(const GeoDataLineString& lineString) +QPolygonF BaseClipper::lineString2Qpolygon(const GeoDataLineString& lineString, bool reverseOrder) { QPolygonF polygon; - foreach (const GeoDataCoordinates& coord, lineString) { - // Need to flip the Y axis(latitude) - QPointF point(coord.longitude(), -coord.latitude()); - polygon.append(point); + if(!reverseOrder) { + foreach (const GeoDataCoordinates& coord, lineString) { + // Need to flip the Y axis(latitude) + QPointF point(coord.longitude(), -coord.latitude()); + polygon.append(point); + } + } else { + for(int i = lineString.size()-1; i >= 0; --i) { + // Need to flip the Y axis(latitude) + QPointF point(lineString.at(i).longitude(), -lineString.at(i).latitude()); + polygon.append(point); + } } return polygon; } -QPolygonF BaseClipper::linearRing2Qpolygon(const GeoDataLinearRing& linearRing) +QPolygonF BaseClipper::linearRing2Qpolygon(const GeoDataLinearRing& linearRing, bool reverseOrder) { QPolygonF polygon; - foreach (const GeoDataCoordinates& coord, linearRing) { - // Need to flip the Y axis(latitude) - QPointF point(coord.longitude(), -coord.latitude()); - polygon.append(point); + + if(!reverseOrder) { + foreach (const GeoDataCoordinates& coord, linearRing) { + // Need to flip the Y axis(latitude) + QPointF point(coord.longitude(), -coord.latitude()); + polygon.append(point); + } + } else { + for(int i = linearRing.size()-1; i >= 0; --i) { + // Need to flip the Y axis(latitude) + QPointF point(linearRing.at(i).longitude(), -linearRing.at(i).latitude()); + polygon.append(point); + } } return polygon; } -GeoDataLineString BaseClipper::qPolygon2lineString(const QPolygonF& polygon) +GeoDataLineString BaseClipper::qPolygon2lineString(const QPolygonF& polygon, bool reverseOrder) { GeoDataLineString lineString; - foreach (const QPointF& point, polygon) { - // Flipping back the Y axis - GeoDataCoordinates coord(point.x(), -point.y()); - lineString.append(coord); + + if(!reverseOrder) { + foreach (const QPointF& point, polygon) { + // Flipping back the Y axis + GeoDataCoordinates coord(point.x(), -point.y()); + lineString.append(coord); + } + } else { + for(int i = polygon.size()-1; i >= 0; --i) { + // Need to flip the Y axis(latitude) + GeoDataCoordinates coord(polygon.at(i).x(), -polygon.at(i).y()); + lineString.append(coord); + } } return lineString; } -GeoDataLinearRing BaseClipper::qPolygon2linearRing(const QPolygonF& polygon) +GeoDataLinearRing BaseClipper::qPolygon2linearRing(const QPolygonF& polygon, bool reverseOrder) { GeoDataLinearRing linearRing; - foreach (const QPointF& point, polygon) { - // Flipping back the Y axis - GeoDataCoordinates coord(point.x(), -point.y()); - linearRing.append(coord); + + if(!reverseOrder) { + foreach (const QPointF& point, polygon) { + // Flipping back the Y axis + GeoDataCoordinates coord(point.x(), -point.y()); + linearRing.append(coord); + } + } else { + for(int i = polygon.size()-1; i >= 0; --i) { + // Need to flip the Y axis(latitude) + GeoDataCoordinates coord(polygon.at(i).x(), -polygon.at(i).y()); + linearRing.append(coord); + } } return linearRing; @@ -485,11 +520,11 @@ if(!intersections.isEmpty()) { -// qDebug() << "intersections count:" << intersections.size(); -// qDebug() << "intersectionsTop count:" << intersectionsTop.size(); -// qDebug() << "intersectionsRight count:" << intersectionsRight.size(); -// qDebug() << "intersectionsBottom count:" << intersectionsBottom.size(); -// qDebug() << "intersectionsLeft count:" << intersectionsLeft.size(); + // qDebug() << "intersections count:" << intersections.size(); + // qDebug() << "intersectionsTop count:" << intersectionsTop.size(); + // qDebug() << "intersectionsRight count:" << intersectionsRight.size(); + // qDebug() << "intersectionsBottom count:" << intersectionsBottom.size(); + // qDebug() << "intersectionsLeft count:" << intersectionsLeft.size(); clippedPolyObjects.clear(); clippedPolyObject = QPolygonF(); @@ -562,12 +597,12 @@ } clippedPolyObject << it->point(); -// // To avoid crashes because of infinite loop. -// // Needs to be investigated -// if(clippedPolyObject.size() > basePolygon.size()) { -// qDebug() << "Something went wrong, exiting current clipping loop..."; -// break; -// } + // // To avoid crashes because of infinite loop. + // // Needs to be investigated + // if(clippedPolyObject.size() > basePolygon.size()) { + // qDebug() << "Something went wrong, exiting current clipping loop..."; + // break; + // } } while(clippedPolyObject.first() != clippedPolyObject.last()); @@ -579,15 +614,15 @@ clippedPolyObjects.clear(); clippedPolyObject = polygon.intersected(m_viewport); - if(clippedPolyObject == polygon) { - clippedPolyObjects << polygon; - } else if (clippedPolyObject == m_viewport.intersected(m_viewport)) { + if (clippedPolyObject == m_viewport.intersected(m_viewport)) { clippedPolyObject = QPolygonF(); clippedPolyObject << m_topLeft << m_topEdge << m_topRight << m_rightEdge << m_bottomRight << m_bottomEdge << m_bottomLeft << m_leftEdge; clippedPolyObjects << clippedPolyObject; + } else if(!clippedPolyObject.isEmpty()) { + clippedPolyObjects << polygon; } } } else if(!clippedPolyObject.isEmpty()) { diff --git a/tools/osm-simplify/TinyPlanetProcessor.h b/tools/osm-simplify/TinyPlanetProcessor.h --- a/tools/osm-simplify/TinyPlanetProcessor.h +++ b/tools/osm-simplify/TinyPlanetProcessor.h @@ -12,6 +12,7 @@ #define TINYPLANETPROCESSOR_H #include "PlacemarkFilter.h" +#include "OsmPlacemarkData.h" class TinyPlanetProcessor : public PlacemarkFilter { @@ -24,6 +25,7 @@ private: void copyTags(const GeoDataPlacemark &source, GeoDataPlacemark &target) const; + void copyTags(const OsmPlacemarkData &originalPlacemarkData, OsmPlacemarkData& targetOsmData) const; }; #endif // TINYPLANETPROCESSOR_H diff --git a/tools/osm-simplify/TinyPlanetProcessor.cpp b/tools/osm-simplify/TinyPlanetProcessor.cpp --- a/tools/osm-simplify/TinyPlanetProcessor.cpp +++ b/tools/osm-simplify/TinyPlanetProcessor.cpp @@ -14,9 +14,11 @@ #include "GeoDataPlacemark.h" #include "OsmPlacemarkData.h" +#include "OsmObjectManager.h" #include #include +#include TinyPlanetProcessor::TinyPlanetProcessor(GeoDataDocument* document) : PlacemarkFilter(document) @@ -52,41 +54,79 @@ if(tileBoundary.intersects(placemark->geometry()->latLonAltBox())) { - if( placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType || - placemark->visualCategory() == GeoDataFeature::Landmass) { + if( placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType) { - GeoDataLinearRing* marblePolygon; - if(placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType) { - marblePolygon = &static_cast(placemark->geometry())->outerBoundary(); - } else if (placemark->geometry()->nodeType() == GeoDataTypes::GeoDataLinearRingType) { - marblePolygon = static_cast(placemark->geometry()); + bool isClockwise = true; + + GeoDataPolygon* marblePolygon = static_cast(placemark->geometry()); + int index = -1; + + using PolygonPair = QPair; + QVector newMarblePolygons; + + isClockwise = marblePolygon->outerBoundary().isClockwise(); + QPolygonF outerBoundaryPolygon = BaseClipper::linearRing2Qpolygon(marblePolygon->outerBoundary(), !isClockwise); + + QVector outerBoundaries; + clipper.clipPolyObject(outerBoundaryPolygon, outerBoundaries, true); + +// qDebug() << "Size(s) after:"; + foreach(const QPolygonF& polygon, outerBoundaries) { + +// qDebug() << polygon.size(); + + PolygonPair newMarblePolygon = qMakePair(new GeoDataPlacemark(), polygon); + GeoDataPolygon* geometry = new GeoDataPolygon(); + geometry->setOuterBoundary(BaseClipper::qPolygon2linearRing(polygon, !isClockwise)); + newMarblePolygon.first->setGeometry(geometry); + + copyTags(*placemark, *(newMarblePolygon.first)); + OsmObjectManager::initializeOsmData(newMarblePolygon.first); + + placemark->osmData().memberReference(index); + copyTags(placemark->osmData().memberReference(index), + newMarblePolygon.first->osmData().memberReference(index)); + + newMarblePolygons.push_back(newMarblePolygon); } - QVector clippedPolygons; + foreach (const GeoDataLinearRing& innerBoundary, marblePolygon->innerBoundaries()) { + ++index; + isClockwise = innerBoundary.isClockwise(); + QPolygonF innerBoundaryPolygon = BaseClipper::linearRing2Qpolygon(innerBoundary, !isClockwise); + + QVector clippedPolygons; - QPolygonF outerBoundary = BaseClipper::linearRing2Qpolygon(*marblePolygon); + clipper.clipPolyObject(innerBoundaryPolygon, clippedPolygons, true); - clipper.clipPolyObject(outerBoundary, clippedPolygons, true); + foreach (const QPolygonF& polygon, clippedPolygons) { + bool isAdded = false; + foreach (const PolygonPair& newMarblePolygon, newMarblePolygons) { + if(!polygon.intersected(newMarblePolygon.second).isEmpty()) { + GeoDataPolygon* geometry = static_cast(newMarblePolygon.first->geometry()); + geometry->appendInnerBoundary(BaseClipper::qPolygon2linearRing(polygon, !isClockwise)); - qDebug() << "Size(s) after:"; - foreach(const QPolygonF& polygon, clippedPolygons) { + OsmObjectManager::initializeOsmData(newMarblePolygon.first); - qDebug() << polygon.size(); + OsmPlacemarkData& innerRingData = newMarblePolygon.first->osmData().memberReference(geometry->innerBoundaries().size()-1); + OsmPlacemarkData& placemarkInnerRingData = placemark->osmData().memberReference(index); - GeoDataLinearRing outerBoundary = BaseClipper::qPolygon2linearRing(polygon); - GeoDataPolygon* newMarblePolygon = new GeoDataPolygon(); - newMarblePolygon->setOuterBoundary(outerBoundary); + copyTags(placemarkInnerRingData, innerRingData); - GeoDataPlacemark* newPlacemark = new GeoDataPlacemark(); - newPlacemark->setGeometry(newMarblePolygon); - newPlacemark->setVisualCategory(GeoDataFeature::Landmass); + isAdded = true; + } + } - OsmPlacemarkData marbleLand; - marbleLand.addTag("marble_land","landmass"); - newPlacemark->setOsmData(marbleLand); + if(!isAdded) { + qDebug() << "Polygon not added. Why?"; + } + } + } - tile->append(newPlacemark); + foreach (const PolygonPair& newMarblePolygon, newMarblePolygons) { + tile->append(newMarblePolygon.first); } + } else if (placemark->geometry()->nodeType() == GeoDataTypes::GeoDataLineStringType) { GeoDataLineString* marbleWay = static_cast(placemark->geometry()); @@ -96,17 +136,16 @@ clipper.clipPolyObject(way, clippedPolygons, false); - qDebug() << "Size before:" << way.size(); - qDebug() << "Size(s) after:"; +// qDebug() << "Size before:" << way.size(); +// qDebug() << "Size(s) after:"; foreach(const QPolygonF& polygon, clippedPolygons) { - qDebug() << polygon.size(); +// qDebug() << polygon.size(); GeoDataLineString* newMarbleWay = new GeoDataLineString(BaseClipper::qPolygon2lineString(polygon)); GeoDataPlacemark* newPlacemark = new GeoDataPlacemark(); newPlacemark->setGeometry(newMarbleWay); - newPlacemark->setVisualCategory(placemark->visualCategory()); copyTags(*placemark, *newPlacemark); tile->append(newPlacemark); @@ -119,20 +158,17 @@ 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); + clipper.clipPolyObject(closedWay, clippedPolygons, true); - qDebug() << "Size(s) after:"; +// qDebug() << "Size(s) after:"; foreach(const QPolygonF& polygon, clippedPolygons) { - qDebug() << polygon.size(); +// qDebug() << polygon.size(); - // When a linearRing is cut to pieces, the resulting geometries will be lineStrings - GeoDataLineString* newMarbleWay = new GeoDataLineString(BaseClipper::qPolygon2lineString(polygon)); + GeoDataLinearRing* newMarbleWay = new GeoDataLinearRing(BaseClipper::qPolygon2linearRing(polygon)); GeoDataPlacemark* newPlacemark = new GeoDataPlacemark(); newPlacemark->setGeometry(newMarbleWay); - newPlacemark->setVisualCategory(placemark->visualCategory()); copyTags(*placemark, *newPlacemark); tile->append(newPlacemark); @@ -156,3 +192,10 @@ osmData.addTag(iter.key(), iter.value()); } } + +void TinyPlanetProcessor::copyTags(const OsmPlacemarkData &originalPlacemarkData, OsmPlacemarkData &targetOsmData) const +{ + for (auto iter=originalPlacemarkData.tagsBegin(), end=originalPlacemarkData.tagsEnd(); iter != end; ++iter) { + targetOsmData.addTag(iter.key(), iter.value()); + } +}