summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDennis Nienhüser <nienhueser@kde.org>2016-11-01 15:16:28 (GMT)
committerFriedrich W. H. Kossebau <kossebau@kde.org>2016-11-05 16:49:28 (GMT)
commitedc02a8eb9d49eada1f85b9039777e768b5ddd21 (patch)
treee6d34cfbfbef69c0de463a1875213c28706e13fa
parentdc93df25478d0b61f8d9d7d82be26e8181f809ab (diff)
Keep node meta data (id and tags) during clipping.
- Keep a GeoDataCoordinates pointer payload in IntPoint - Check validity of coordinates before returning them. Clipper might modify and reuse nodes internally, which results in an unwanted "move" of coordinates. In this case the association must be broken. - This also improves precision slightly, since the original coordinates are retained in most cases
-rw-r--r--tools/vectorosm-tilecreator/VectorClipper.cpp43
-rw-r--r--tools/vectorosm-tilecreator/VectorClipper.h24
-rw-r--r--tools/vectorosm-tilecreator/clipper/clipper.cpp24
-rw-r--r--tools/vectorosm-tilecreator/clipper/clipper.hpp11
4 files changed, 77 insertions, 25 deletions
diff --git a/tools/vectorosm-tilecreator/VectorClipper.cpp b/tools/vectorosm-tilecreator/VectorClipper.cpp
index 51da676..3b4bd69 100644
--- a/tools/vectorosm-tilecreator/VectorClipper.cpp
+++ b/tools/vectorosm-tilecreator/VectorClipper.cpp
@@ -261,30 +261,31 @@ ClipperLib::Path VectorClipper::clipPath(const GeoDataLatLonBox &box) const
using namespace ClipperLib;
Path path;
int const steps = 20;
- double x = box.west() * m_scale;
- double const horizontalStep = (box.east() * m_scale - x) / steps;
- double y = box.north() * m_scale;
- double const verticalStep = (box.south() * m_scale - y) / steps;
+ qreal const scale = IntPoint::scale;
+ double x = box.west() * scale;
+ double const horizontalStep = (box.east() * scale - x) / steps;
+ double y = box.north() * scale;
+ double const verticalStep = (box.south() * scale - y) / steps;
for (int i=0; i<steps; ++i) {
path << IntPoint(qRound64(x), qRound64(y));
x += horizontalStep;
}
- path << IntPoint(qRound64(box.east() * m_scale), qRound64(box.north() * m_scale));
+ path << IntPoint(qRound64(box.east() * scale), qRound64(box.north() * scale));
for (int i=0; i<steps; ++i) {
path << IntPoint(qRound64(x), qRound64(y));
y += verticalStep;
}
- path << IntPoint(qRound64(box.east() * m_scale), qRound64(box.south() * m_scale));
+ path << IntPoint(qRound64(box.east() * scale), qRound64(box.south() * scale));
for (int i=0; i<steps; ++i) {
path << IntPoint(qRound64(x), qRound64(y));
x -= horizontalStep;
}
- path << IntPoint(qRound64(box.west() * m_scale), qRound64(box.south() * m_scale));
+ path << IntPoint(qRound64(box.west() * scale), qRound64(box.south() * scale));
for (int i=0; i<steps; ++i) {
path << IntPoint(qRound64(x), qRound64(y));
y -= verticalStep;
}
- path << IntPoint(qRound64(box.west() * m_scale), qRound64(box.north() * m_scale));
+ path << IntPoint(qRound64(box.west() * scale), qRound64(box.north() * scale));
return path;
}
@@ -336,7 +337,7 @@ void VectorClipper::clipPolygon(const GeoDataPlacemark *placemark, const Clipper
using namespace ClipperLib;
Path path;
foreach(auto const & node, polygon->outerBoundary()) {
- path << IntPoint(qRound64(node.longitude() * m_scale), qRound64(node.latitude() * m_scale));
+ path << IntPoint(&node);
}
Clipper clipper;
@@ -346,27 +347,34 @@ void VectorClipper::clipPolygon(const GeoDataPlacemark *placemark, const Clipper
Paths paths;
clipper.Execute(ctIntersection, paths);
foreach(const auto &path, paths) {
+ GeoDataPlacemark* newPlacemark = new GeoDataPlacemark;
GeoDataLinearRing outerRing;
+ int index = -1;
+ auto const & osmData = placemark->osmData().memberReference(index);
foreach(const auto &point, path) {
- outerRing << GeoDataCoordinates(double(point.X) / m_scale, double(point.Y) / m_scale);
+ GeoDataCoordinates const coordinates = point.coordinates();
+ outerRing << coordinates;
+ auto const originalOsmData = osmData.nodeReference(coordinates);
+ if (originalOsmData.id() > 0) {
+ newPlacemark->osmData().addNodeReference(coordinates, originalOsmData);
+ }
}
- GeoDataPlacemark* newPlacemark = new GeoDataPlacemark;
GeoDataPolygon* newPolygon = new GeoDataPolygon;
newPolygon->setOuterBoundary(outerRing);
newPlacemark->setGeometry(newPolygon);
- int index = -1;
OsmObjectManager::initializeOsmData(newPlacemark);
copyTags(*placemark, *newPlacemark);
- copyTags(placemark->osmData().memberReference(index), newPlacemark->osmData().memberReference(index));
+ copyTags(osmData.memberReference(index), newPlacemark->osmData().memberReference(index));
auto const & innerBoundaries = polygon->innerBoundaries();
for (index = 0; index < innerBoundaries.size(); ++index) {
+ auto const & osmData = placemark->osmData().memberReference(index);
clipper.Clear();
clipper.AddPath(path, ptClip, true);
Path innerPath;
foreach(auto const & node, innerBoundaries.at(index)) {
- innerPath << IntPoint(qRound64(node.longitude() * m_scale), qRound64(node.latitude() * m_scale));
+ innerPath << IntPoint(&node);
}
clipper.AddPath(innerPath, ptSubject, true);
Paths innerPaths;
@@ -374,7 +382,12 @@ void VectorClipper::clipPolygon(const GeoDataPlacemark *placemark, const Clipper
foreach(auto const &innerPath, innerPaths) {
GeoDataLinearRing innerRing;
foreach(const auto &point, innerPath) {
- innerRing << GeoDataCoordinates(double(point.X) / m_scale, double(point.Y) / m_scale);
+ GeoDataCoordinates const coordinates = point.coordinates();
+ innerRing << coordinates;
+ auto const originalOsmData = osmData.nodeReference(coordinates);
+ if (originalOsmData.id() > 0) {
+ newPlacemark->osmData().addNodeReference(coordinates, originalOsmData);
+ }
}
newPolygon->appendInnerBoundary(innerRing);
OsmObjectManager::initializeOsmData(newPlacemark);
diff --git a/tools/vectorosm-tilecreator/VectorClipper.h b/tools/vectorosm-tilecreator/VectorClipper.h
index 9e93532..7b47134 100644
--- a/tools/vectorosm-tilecreator/VectorClipper.h
+++ b/tools/vectorosm-tilecreator/VectorClipper.h
@@ -19,6 +19,7 @@
#include "GeoDataLinearRing.h"
#include <TileId.h>
#include <GeoSceneMercatorTileProjection.h>
+#include <OsmObjectManager.h>
#include "clipper/clipper.hpp"
@@ -49,16 +50,17 @@ private:
if (isClosed && minArea > 0.0 && area(*static_cast<const GeoDataLinearRing*>(ring)) < minArea) {
return;
}
+ auto const & osmData = placemark->osmData();
using namespace ClipperLib;
- Path path;
+ Path subject;
foreach(auto const & node, *ring) {
- path << IntPoint(qRound64(node.longitude() * m_scale), qRound64(node.latitude() * m_scale));
+ subject << IntPoint(&node);
}
Clipper clipper;
clipper.PreserveCollinear(true);
clipper.AddPath(tileBoundary, ptClip, true);
- clipper.AddPath(path, ptSubject, isClosed);
+ clipper.AddPath(subject, ptSubject, isClosed);
PolyTree tree;
clipper.Execute(ctIntersection, tree);
Paths paths;
@@ -68,14 +70,20 @@ private:
OpenPathsFromPolyTree(tree, paths);
}
foreach(const auto &path, paths) {
- T* ring = new T;
+ GeoDataPlacemark* newPlacemark = new GeoDataPlacemark();
+ T* newRing = new T;
foreach(const auto &point, path) {
- *ring << GeoDataCoordinates(double(point.X) / m_scale, double(point.Y) / m_scale);
+ GeoDataCoordinates const coordinates = point.coordinates();
+ *newRing << coordinates;
+ auto const originalOsmData = osmData.nodeReference(coordinates);
+ if (originalOsmData.id() > 0) {
+ newPlacemark->osmData().addNodeReference(coordinates, originalOsmData);
+ }
}
- GeoDataPlacemark* newPlacemark = new GeoDataPlacemark();
- newPlacemark->setGeometry(ring);
+ newPlacemark->setGeometry(newRing);
copyTags(*placemark, *newPlacemark);
+ OsmObjectManager::initializeOsmData(newPlacemark);
document->append(newPlacemark);
}
}
@@ -85,8 +93,6 @@ private:
void copyTags(const GeoDataPlacemark &source, GeoDataPlacemark &target) const;
void copyTags(const OsmPlacemarkData &originalPlacemarkData, OsmPlacemarkData& targetOsmData) const;
- static qint64 const m_scale = 10000000000;
-
QMap<TileId, QVector<GeoDataPlacemark*> > m_items;
int m_maxZoomLevel;
GeoSceneMercatorTileProjection m_tileProjection;
diff --git a/tools/vectorosm-tilecreator/clipper/clipper.cpp b/tools/vectorosm-tilecreator/clipper/clipper.cpp
index 331ff11..a067637 100644
--- a/tools/vectorosm-tilecreator/clipper/clipper.cpp
+++ b/tools/vectorosm-tilecreator/clipper/clipper.cpp
@@ -48,6 +48,8 @@
#include <ostream>
#include <functional>
+#include <MarbleMath.h>
+
namespace ClipperLib {
static double const pi = 3.141592653589793238;
@@ -4617,6 +4619,28 @@ std::ostream& operator <<(std::ostream &s, const Paths &p)
s << "\n";
return s;
}
+
+IntPoint::IntPoint(const Marble::GeoDataCoordinates *coordinates) :
+ X(qRound64(coordinates->longitude() * scale)),
+ Y(qRound64(coordinates->latitude() * scale)),
+ m_coordinates(coordinates)
+{
+ // nothing to do
+}
+
+Marble::GeoDataCoordinates IntPoint::coordinates() const
+{
+ using namespace Marble;
+ GeoDataCoordinates const coords = GeoDataCoordinates(double(X) / scale, double(Y) / scale);
+ if (m_coordinates) {
+ bool const clipperKeptTheNode = EARTH_RADIUS * distanceSphere(coords, *m_coordinates) < 0.001;
+ if (clipperKeptTheNode) {
+ return *m_coordinates;
+ }
+ }
+ return coords;
+}
+
//------------------------------------------------------------------------------
} //ClipperLib namespace
diff --git a/tools/vectorosm-tilecreator/clipper/clipper.hpp b/tools/vectorosm-tilecreator/clipper/clipper.hpp
index 1b732ba..642a000 100644
--- a/tools/vectorosm-tilecreator/clipper/clipper.hpp
+++ b/tools/vectorosm-tilecreator/clipper/clipper.hpp
@@ -59,6 +59,8 @@
#include <functional>
#include <queue>
+#include <GeoDataCoordinates.h>
+
namespace ClipperLib {
enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor };
@@ -85,11 +87,13 @@ enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative };
struct IntPoint {
cInt X;
cInt Y;
+ constexpr static qint64 const scale = 10000000000;
#ifdef use_xyz
cInt Z;
IntPoint(cInt x = 0, cInt y = 0, cInt z = 0): X(x), Y(y), Z(z) {};
#else
- IntPoint(cInt x = 0, cInt y = 0): X(x), Y(y) {};
+ IntPoint(cInt x = 0, cInt y = 0): X(x), Y(y) {}
+ IntPoint(const Marble::GeoDataCoordinates* coordinates);
#endif
friend inline bool operator== (const IntPoint& a, const IntPoint& b)
@@ -100,6 +104,11 @@ struct IntPoint {
{
return a.X != b.X || a.Y != b.Y;
}
+
+ Marble::GeoDataCoordinates coordinates() const;
+
+private:
+ const Marble::GeoDataCoordinates * m_coordinates = nullptr;
};
//------------------------------------------------------------------------------