diff options
Diffstat (limited to 'src/location/declarativemaps/qdeclarativepolygonmapitem.cpp')
-rw-r--r-- | src/location/declarativemaps/qdeclarativepolygonmapitem.cpp | 89 |
1 files changed, 37 insertions, 52 deletions
diff --git a/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp b/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp index daa1a9fc..48f66423 100644 --- a/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp +++ b/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp @@ -53,6 +53,8 @@ /* poly2tri triangulator includes */ #include <clip2tri.h> +#include <earcut.hpp> +#include <array> QT_BEGIN_NAMESPACE @@ -185,7 +187,7 @@ void QGeoMapPolygonGeometry::updateSourcePoints(const QGeoMap &map, // 2) QList<QList<QDoubleVector2D> > clippedPaths; - const QList<QDoubleVector2D> &visibleRegion = map.geoProjection().visibleRegion(); + const QList<QDoubleVector2D> &visibleRegion = map.geoProjection().projectableRegion(); if (visibleRegion.size()) { c2t::clip2tri clipper; clipper.addSubjectPath(QClipperUtils::qListToPath(wrappedPath), true); @@ -254,16 +256,6 @@ void QGeoMapPolygonGeometry::updateScreenPoints(const QGeoMap &map) return; } - QDoubleVector2D origin = map.geoProjection().coordinateToItemPosition(srcOrigin_, false); - - // Create the viewport rect in the same coordinate system - // as the actual points - QRectF viewport(0, 0, map.viewportWidth(), map.viewportHeight()); - viewport.translate(-1 * origin.toPointF()); - - QPainterPath vpPath; - vpPath.addRect(viewport); - // The geometry has already been clipped against the visible region projection in wrapped mercator space. QPainterPath ppi = srcPath_; clear(); @@ -272,57 +264,50 @@ void QGeoMapPolygonGeometry::updateScreenPoints(const QGeoMap &map) if (ppi.elementCount() < 3) return; - // Intersection between the viewport and a concave polygon can create multiple polygons - // joined by a line at the viewport border, and poly2tri does not triangulate this very well - // so use the full src path if the resulting polygon is concave. - if (clipToViewport_) { - int changeInX = 0; - int changeInY = 0; - QPainterPath::Element e1 = ppi.elementAt(1); - QPainterPath::Element e = ppi.elementAt(0); - QVector2D edgeA(e1.x - e.x ,e1.y - e.y); - for (int i = 2; i <= ppi.elementCount(); ++i) { - e = ppi.elementAt(i % ppi.elementCount()); - if (e.x == e1.x && e.y == e1.y) - continue; - QVector2D edgeB(e.x - e1.x, e.y - e1.y); - if ((edgeA.x() < 0) == (edgeB.x() >= 0)) - changeInX++; - if ((edgeA.y() < 0) == (edgeB.y() >= 0)) - changeInY++; - edgeA = edgeB; - e1 = e; - } - if (changeInX > 2 || changeInY > 2) // polygon is concave - ppi = srcPath_; - } - // translate the path into top-left-centric coordinates QRectF bb = ppi.boundingRect(); ppi.translate(-bb.left(), -bb.top()); firstPointOffset_ = -1 * bb.topLeft(); ppi.closeSubpath(); - screenOutline_ = ppi; - QTriangleSet ts = qTriangulate(ppi); - qreal *vx = ts.vertices.data(); - - screenIndices_.reserve(ts.indices.size()); - screenVertices_.reserve(ts.vertices.size()); + using Coord = double; + using N = uint32_t; + using Point = std::array<Coord, 2>; + + std::vector<std::vector<Point>> polygon; + polygon.push_back(std::vector<Point>()); + std::vector<Point> &poly = polygon.front(); + // ... fill polygon structure with actual data + + for (int i = 0; i < ppi.elementCount(); ++i) { + const QPainterPath::Element e = ppi.elementAt(i); + if (e.isMoveTo() || i == ppi.elementCount() - 1 + || (qAbs(e.x - poly.front()[0]) < 0.1 + && qAbs(e.y - poly.front()[1]) < 0.1)) { + Point p = { e.x, e.y }; + poly.push_back( p ); + } else if (e.isLineTo()) { + Point p = { e.x, e.y }; + poly.push_back( p ); + } else { + qWarning("Unhandled element type in polygon painterpath"); + } + } - if (ts.indices.type() == QVertexIndexVector::UnsignedInt) { - const quint32 *ix = reinterpret_cast<const quint32 *>(ts.indices.data()); - for (int i = 0; i < (ts.indices.size()/3*3); ++i) - screenIndices_ << ix[i]; - } else { - const quint16 *ix = reinterpret_cast<const quint16 *>(ts.indices.data()); - for (int i = 0; i < (ts.indices.size()/3*3); ++i) - screenIndices_ << ix[i]; + if (poly.size() > 2) { + // Run tessellation + // Returns array of indices that refer to the vertices of the input polygon. + // Three subsequent indices form a triangle. + screenVertices_.clear(); + screenIndices_.clear(); + for (const auto &p : poly) + screenVertices_ << QPointF(p[0], p[1]); + std::vector<N> indices = mapbox::earcut<N>(polygon); + for (const auto &i: indices) + screenIndices_ << quint32(i); } - for (int i = 0; i < (ts.vertices.size()/2*2); i += 2) - screenVertices_ << QPointF(vx[i], vx[i + 1]); screenBounds_ = ppi.boundingRect(); } |