summaryrefslogtreecommitdiffstats
path: root/src/location/quickmapitems/qdeclarativepolylinemapitem.cpp
diff options
context:
space:
mode:
authorMatthias Rauter <matthias.rauter@qt.io>2023-01-26 17:18:50 +0100
committerMatthias Rauter <matthias.rauter@qt.io>2023-02-14 16:31:13 +0100
commit8b9ecad4bed0150adcbdf91db3f5f9507a156fd6 (patch)
tree6cd08872c366a32ed041701654d15559325fd464 /src/location/quickmapitems/qdeclarativepolylinemapitem.cpp
parentb842a6cdcce0ee43a48ec084180d9dc065b599a1 (diff)
Correct and improve the rendering of QuickMapItems
Various MapItems were not rendered correctly, especially in corner cases. This change ensures that MapItems are rendered correctly in the vast majority of cases. All MapItems are shown correctly if they wrap around the globe and appear twice on the map. Circles that span around the globe or are located near poles are shown correclty and filled all the way to the border of the map. Polygons are shown correctly including their holes. The code was simplified and some artefacts of previous implementations were removed. Fixes: QTBUG-110701 Fixes: QTBUG-110511 Pick-to: 6.5 Change-Id: I1110659989436cd5a93f6ec26f75caa06d5f2b71 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Diffstat (limited to 'src/location/quickmapitems/qdeclarativepolylinemapitem.cpp')
-rw-r--r--src/location/quickmapitems/qdeclarativepolylinemapitem.cpp490
1 files changed, 87 insertions, 403 deletions
diff --git a/src/location/quickmapitems/qdeclarativepolylinemapitem.cpp b/src/location/quickmapitems/qdeclarativepolylinemapitem.cpp
index 2477a4d8..e80afbee 100644
--- a/src/location/quickmapitems/qdeclarativepolylinemapitem.cpp
+++ b/src/location/quickmapitems/qdeclarativepolylinemapitem.cpp
@@ -3,7 +3,6 @@
#include "qdeclarativepolylinemapitem_p.h"
#include "qdeclarativepolylinemapitem_p_p.h"
-#include "qdeclarativegeomapitemutils_p.h"
#include <QtCore/QScopedValueRollback>
#include <qnumeric.h>
@@ -296,421 +295,97 @@ void QDeclarativeMapLineProperties::setWidth(qreal width)
emit widthChanged(width_);
}
-QGeoMapPolylineGeometry::QGeoMapPolylineGeometry()
-{
-}
-
-QList<QList<QDoubleVector2D> > QGeoMapPolylineGeometry::clipPath(const QGeoMap &map,
- const QList<QDoubleVector2D> &path,
- QDoubleVector2D &leftBoundWrapped)
-{
- /*
- * Approach:
- * 1) project coordinates to wrapped web mercator, and do unwrapBelowX
- * 2) if the scene is tilted, clip the geometry against the visible region (this may generate multiple polygons)
- * 2.1) recalculate the origin and geoLeftBound to prevent these parameters from ending in unprojectable areas
- * 2.2) ensure the left bound does not wrap around due to QGeoCoordinate <-> clipper conversions
- */
- const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map.geoProjection());
- srcOrigin_ = geoLeftBound_;
-
- double unwrapBelowX = 0;
- leftBoundWrapped = p.wrapMapProjection(p.geoToMapProjection(geoLeftBound_));
- if (preserveGeometry_)
- unwrapBelowX = leftBoundWrapped.x();
-
- QList<QDoubleVector2D> wrappedPath;
- wrappedPath.reserve(path.size());
- QDoubleVector2D wrappedLeftBound(qInf(), qInf());
- // 1)
- for (const auto &coord : path) {
- QDoubleVector2D wrappedProjection = p.wrapMapProjection(coord);
-
- // We can get NaN if the map isn't set up correctly, or the projection
- // is faulty -- probably best thing to do is abort
- if (!qIsFinite(wrappedProjection.x()) || !qIsFinite(wrappedProjection.y()))
- return QList<QList<QDoubleVector2D> >();
-
- const bool isPointLessThanUnwrapBelowX = (wrappedProjection.x() < leftBoundWrapped.x());
- // unwrap x to preserve geometry if moved to border of map
- if (preserveGeometry_ && isPointLessThanUnwrapBelowX) {
- double distance = wrappedProjection.x() - unwrapBelowX;
- if (distance < 0.0)
- distance += 1.0;
- wrappedProjection.setX(unwrapBelowX + distance);
- }
- if (wrappedProjection.x() < wrappedLeftBound.x() || (wrappedProjection.x() == wrappedLeftBound.x() && wrappedProjection.y() < wrappedLeftBound.y())) {
- wrappedLeftBound = wrappedProjection;
- }
- wrappedPath.append(wrappedProjection);
- }
-
-#ifdef QT_LOCATION_DEBUG
- m_wrappedPath = wrappedPath;
-#endif
-
- // 2)
- QList<QList<QDoubleVector2D> > clippedPaths;
- const QList<QDoubleVector2D> &visibleRegion = p.projectableGeometry();
- if (visibleRegion.size()) {
- clippedPaths = clipLine(wrappedPath, visibleRegion);
-
- // 2.1) update srcOrigin_ and leftBoundWrapped with the point with minimum X
- QDoubleVector2D lb(qInf(), qInf());
- for (const QList<QDoubleVector2D> &path: clippedPaths) {
- for (const QDoubleVector2D &p: path) {
- if (p == leftBoundWrapped) {
- lb = p;
- break;
- } else if (p.x() < lb.x() || (p.x() == lb.x() && p.y() < lb.y())) {
- // y-minimization needed to find the same point on polygon and border
- lb = p;
- }
- }
- }
- if (qIsInf(lb.x()))
- return QList<QList<QDoubleVector2D> >();
-
- // 2.2) Prevent the conversion to and from clipper from introducing negative offsets which
- // in turn will make the geometry wrap around.
- lb.setX(qMax(wrappedLeftBound.x(), lb.x()));
- leftBoundWrapped = lb;
- } else {
- clippedPaths.append(wrappedPath);
- }
-
-#ifdef QT_LOCATION_DEBUG
- m_clippedPaths = clippedPaths;
-#endif
-
- return clippedPaths;
-}
-
-void QGeoMapPolylineGeometry::pathToScreen(const QGeoMap &map,
- const QList<QList<QDoubleVector2D> > &clippedPaths,
- const QDoubleVector2D &leftBoundWrapped)
-{
- const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map.geoProjection());
- // 3) project the resulting geometry to screen position and calculate screen bounds
- double minX = qInf();
- double minY = qInf();
- double maxX = -qInf();
- double maxY = -qInf();
- srcOrigin_ = p.mapProjectionToGeo(p.unwrapMapProjection(leftBoundWrapped));
- QDoubleVector2D origin = p.wrappedMapProjectionToItemPosition(leftBoundWrapped);
- for (const QList<QDoubleVector2D> &path: clippedPaths) {
- QDoubleVector2D lastAddedPoint;
- for (qsizetype i = 0; i < path.size(); ++i) {
- QDoubleVector2D point = p.wrappedMapProjectionToItemPosition(path.at(i));
- point = point - origin; // (0,0) if point == geoLeftBound_
-
- minX = qMin(point.x(), minX);
- minY = qMin(point.y(), minY);
- maxX = qMax(point.x(), maxX);
- maxY = qMax(point.y(), maxY);
-
- if (i == 0) {
- srcPoints_ << point.x() << point.y();
- srcPointTypes_ << QPainterPath::MoveToElement;
- lastAddedPoint = point;
- } else {
- if ((point - lastAddedPoint).manhattanLength() > 3 ||
- i == path.size() - 1) {
- srcPoints_ << point.x() << point.y();
- srcPointTypes_ << QPainterPath::LineToElement;
- lastAddedPoint = point;
- }
- }
- }
- }
-
- sourceBounds_ = QRectF(QPointF(minX, minY), QPointF(maxX, maxY));
-}
-
/*!
\internal
*/
void QGeoMapPolylineGeometry::updateSourcePoints(const QGeoMap &map,
- const QList<QDoubleVector2D> &path,
- const QGeoCoordinate geoLeftBound)
+ const QList<QDoubleVector2D> &basePath)
{
+ // A polygon consists of mutliple paths. This is usually a perimeter and multiple holes
+ // We move all paths into a single QPainterPath. The filling rule EvenOdd will then ensure that the paths are shown correctly
if (!sourceDirty_)
return;
-
- geoLeftBound_ = geoLeftBound;
-
- // clear the old data and reserve enough memory
- srcPoints_.clear();
- srcPoints_.reserve(path.size() * 2);
- srcPointTypes_.clear();
- srcPointTypes_.reserve(path.size());
-
- /*
- * Approach:
- * 1) project coordinates to wrapped web mercator, and do unwrapBelowX
- * 2) if the scene is tilted, clip the geometry against the visible region (this may generate multiple polygons)
- * 3) project the resulting geometry to screen position and calculate screen bounds
- */
-
- QDoubleVector2D leftBoundWrapped;
- // 1, 2)
- const QList<QList<QDoubleVector2D> > &clippedPaths = clipPath(map, path, leftBoundWrapped);
-
- // 3)
- pathToScreen(map, clippedPaths, leftBoundWrapped);
-
+ const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map.geoProjection());
srcPath_ = QPainterPath();
- maxCoord_ = 0.0;
- const int elemCount = srcPointTypes_.count();
- for (int i = 0; i < elemCount; ++i) {
- switch (srcPointTypes_[i]) {
- case QPainterPath::MoveToElement:
- {
- const qreal x = srcPoints_[2 * i];
- const qreal y = srcPoints_[2 * i + 1];
- if (qMax(x, y) > maxCoord_)
- maxCoord_ = qMax(x, y);
- srcPath_.moveTo(x, y);
- }
- break;
- case QPainterPath::LineToElement:
- {
- const qreal x = srcPoints_[2 * i];
- const qreal y = srcPoints_[2 * i + 1];
- if (qMax(x, y) > maxCoord_)
- maxCoord_ = qMax(x, y);
- srcPath_.lineTo(x, y);
- }
- break;
- default:
- break;
- }
+ srcOrigin_ = p.mapProjectionToGeo(QDoubleVector2D(0, 0)); //avoid warning of NaN values if function is returned early
+
+ //0 Wrap the points around the globe if the path makes more sense that way.
+ // Ultimately, this is done if it is closer to walk around the day-border than the other direction
+ QVarLengthArray<QList<QDoubleVector2D>, 3> wrappedPaths;
+ wrappedPaths << QList<QDoubleVector2D>({basePath[0]});
+ wrappedPaths.last().reserve(basePath.size());
+ for (int i = 1; i < basePath.size(); i++) {
+ if (basePath[i].x() > wrappedPaths.last().last().x() + 0.5)
+ wrappedPaths.last() << basePath[i] - QDoubleVector2D(1.0, 0.0);
+ else if (basePath[i].x() < wrappedPaths.last().last().x() - 0.5)
+ wrappedPaths.last() << basePath[i] + QDoubleVector2D(1.0, 0.0);
+ else
+ wrappedPaths.last() << basePath[i];
}
-}
-
-// *** SCREEN CLIPPING *** //
-
-enum ClipPointType {
- InsidePoint = 0x00,
- LeftPoint = 0x01,
- RightPoint = 0x02,
- BottomPoint = 0x04,
- TopPoint = 0x08
-};
-static inline int clipPointType(qreal x, qreal y, const QRectF &rect)
-{
- int type = InsidePoint;
- if (x < rect.left())
- type |= LeftPoint;
- else if (x > rect.right())
- type |= RightPoint;
- if (y < rect.top())
- type |= TopPoint;
- else if (y > rect.bottom())
- type |= BottomPoint;
- return type;
-}
-
-static void clipSegmentToRect(qreal x0, qreal y0, qreal x1, qreal y1, const QRectF &clipRect,
- QList<qreal> &outPoints, QList<QPainterPath::ElementType> &outTypes)
-{
- int type0 = clipPointType(x0, y0, clipRect);
- int type1 = clipPointType(x1, y1, clipRect);
- bool accept = false;
-
- while (true) {
- if (!(type0 | type1)) {
- accept = true;
- break;
- } else if (type0 & type1) {
- break;
- } else {
- qreal x = 0.0;
- qreal y = 0.0;
- int outsideType = type0 ? type0 : type1;
-
- if (outsideType & BottomPoint) {
- x = x0 + (x1 - x0) * (clipRect.bottom() - y0) / (y1 - y0);
- y = clipRect.bottom() - 0.1;
- } else if (outsideType & TopPoint) {
- x = x0 + (x1 - x0) * (clipRect.top() - y0) / (y1 - y0);
- y = clipRect.top() + 0.1;
- } else if (outsideType & RightPoint) {
- y = y0 + (y1 - y0) * (clipRect.right() - x0) / (x1 - x0);
- x = clipRect.right() - 0.1;
- } else if (outsideType & LeftPoint) {
- y = y0 + (y1 - y0) * (clipRect.left() - x0) / (x1 - x0);
- x = clipRect.left() + 0.1;
- }
-
- if (outsideType == type0) {
- x0 = x;
- y0 = y;
- type0 = clipPointType(x0, y0, clipRect);
- } else {
- x1 = x;
- y1 = y;
- type1 = clipPointType(x1, y1, clipRect);
- }
- }
+ //1 The bounding rectangle of the polygon and camera view are compared to determine if the polygon is visible
+ // The viewport is periodic in x-direction in the interval [-1; 1].
+ // The polygon (maybe) has to be ploted periodically too by shifting it by -1 or +1;
+ const QRectF cameraRect = QDeclarativeGeoMapItemUtils::boundingRectangleFromList(p.visibleGeometry());
+ QRectF itemRect;
+ for (const auto &path : wrappedPaths)
+ itemRect |= QDeclarativeGeoMapItemUtils::boundingRectangleFromList(path).adjusted(-1e-6, -1e-6, 2e-6, 2e-6); //TODO: Maybe use linewidth?
+ for (double xoffset : {-1.0, 1.0}) {
+ if (!cameraRect.intersects(itemRect.translated(QPointF(xoffset,0))))
+ continue;
+ wrappedPaths.append(QList<QDoubleVector2D>());
+ QList<QDoubleVector2D> &wP = wrappedPaths.last();
+ wP.reserve(wrappedPaths.first().size());
+ for (const QDoubleVector2D &coord : wrappedPaths.first())
+ wP.append(coord + QDoubleVector2D(xoffset, 0.0));
}
+ if (wrappedPaths.isEmpty()) // the polygon boundary rectangle does not overlap with the viewport rectangle
+ return;
- if (accept) {
- if (outPoints.size() >= 2) {
- qreal lastX, lastY;
- lastY = outPoints.at(outPoints.size() - 1);
- lastX = outPoints.at(outPoints.size() - 2);
-
- if (!qFuzzyCompare(lastY, y0) || !qFuzzyCompare(lastX, x0)) {
- outTypes << QPainterPath::MoveToElement;
- outPoints << x0 << y0;
- }
+ //2 The polygons that are at least partially in the viewport are cliped to reduce their size
+ QList<QList<QDoubleVector2D>> clippedPaths;
+ const QList<QDoubleVector2D> &visibleRegion = p.visibleGeometryExpanded();
+ for (const auto &path : wrappedPaths) {
+ if (visibleRegion.size()) {
+ clippedPaths << clipLine(path, visibleRegion);
+ //TODO: Replace clipping with Clipper lib, similar to QPolygonMapItem
} else {
- outTypes << QPainterPath::MoveToElement;
- outPoints << x0 << y0;
- }
-
- outTypes << QPainterPath::LineToElement;
- outPoints << x1 << y1;
- }
-}
-
-static void clipPathToRect(const QList<qreal> &points,
- const QList<QPainterPath::ElementType> &types, const QRectF &clipRect,
- QList<qreal> &outPoints, QList<QPainterPath::ElementType> &outTypes)
-{
- outPoints.clear();
- outPoints.reserve(points.size());
- outTypes.clear();
- outTypes.reserve(types.size());
-
- qreal lastX = 0;
- qreal lastY = 0; // or else used uninitialized
- for (qsizetype i = 0; i < types.size(); ++i) {
- if (i > 0 && types[i] != QPainterPath::MoveToElement) {
- qreal x = points[i * 2], y = points[i * 2 + 1];
- clipSegmentToRect(lastX, lastY, x, y, clipRect, outPoints, outTypes);
+ clippedPaths.append(path); //Do we really need this if there are no visible regions??
}
-
- lastX = points[i * 2];
- lastY = points[i * 2 + 1];
- }
-}
-
-////////////////////////////////////////////////////////////////////////////
-
-/*!
- \internal
-*/
-void QGeoMapPolylineGeometry::updateScreenPoints(const QGeoMap &map,
- qreal strokeWidth,
- bool adjustTranslation)
-{
- if (!screenDirty_)
- return;
-
- QPointF origin = map.geoProjection().coordinateToItemPosition(srcOrigin_, false).toPointF();
-
- if (!qIsFinite(origin.x()) || !qIsFinite(origin.y()) || srcPointTypes_.size() < 2) { // the line might have been clipped away.
- clear();
- return;
- }
-
- // Create the viewport rect in the same coordinate system
- // as the actual points
- QRectF viewport(0, 0, map.viewportWidth(), map.viewportHeight());
- viewport.adjust(-strokeWidth, -strokeWidth, strokeWidth * 2, strokeWidth * 2);
- viewport.translate(-1 * origin);
-
- QList<qreal> points;
- QList<QPainterPath::ElementType> types;
-
- if (clipToViewport_) {
- // Although the geometry has already been clipped against the visible region in wrapped mercator space.
- // This is currently still needed to prevent a number of artifacts deriving from QTriangulatingStroker processing
- // very large lines (that is, polylines that span many pixels in screen space)
- clipPathToRect(srcPoints_, srcPointTypes_, viewport, points, types);
- } else {
- points = srcPoints_;
- types = srcPointTypes_;
}
-
- QVectorPath vp(points.data(), types.size(), types.data());
- QTriangulatingStroker ts;
- // As of Qt5.11, the clip argument is not actually used, in the call below.
- ts.process(vp, QPen(QBrush(Qt::black), strokeWidth), QRectF(), QPainter::Antialiasing);
-
- clear();
-
- // Nothing is on the screen
- if (ts.vertexCount() == 0)
+ if (clippedPaths.isEmpty()) //the polygon is entirely outside visibleRegion
return;
- // QTriangulatingStroker#vertexCount is actually the length of the array,
- // not the number of vertices
- screenVertices_.reserve(ts.vertexCount());
-
QRectF bb;
+ for (const auto &path: clippedPaths)
+ bb |= QDeclarativeGeoMapItemUtils::boundingRectangleFromList(path);
+ //Offset by origin, find the maximum coordinate
+ maxCoord_ = 0.0;
+ srcOrigin_ = p.mapProjectionToGeo(QDoubleVector2D(bb.left(), bb.top()));
+ QDoubleVector2D origin = p.wrappedMapProjectionToItemPosition(p.geoToWrappedMapProjection(srcOrigin_)); //save way: redo all projections
+ for (const auto &path: clippedPaths) {
+ QDoubleVector2D lastAddedPoint;
+ for (qsizetype i = 0; i < path.size(); ++i) {
+ QDoubleVector2D point = p.wrappedMapProjectionToItemPosition(path.at(i));
+ point = point - origin; // (0,0) if point == origin
- QPointF pt;
- const float *vs = ts.vertices();
- for (int i = 0; i < (ts.vertexCount()/2*2); i += 2) {
- pt = QPointF(vs[i], vs[i + 1]);
- screenVertices_ << pt;
-
- if (!qIsFinite(pt.x()) || !qIsFinite(pt.y()))
- break;
-
- if (!bb.contains(pt)) {
- if (pt.x() < bb.left())
- bb.setLeft(pt.x());
-
- if (pt.x() > bb.right())
- bb.setRight(pt.x());
-
- if (pt.y() < bb.top())
- bb.setTop(pt.y());
-
- if (pt.y() > bb.bottom())
- bb.setBottom(pt.y());
- }
- }
-
- screenBounds_ = bb;
-
- const QPointF strokeOffset = (adjustTranslation) ? QPointF(strokeWidth, strokeWidth) * 0.5: QPointF();
- const QPointF offset = -1 * sourceBounds_.topLeft() + strokeOffset;
- for (qsizetype i = 0; i < screenVertices_.size(); ++i)
- screenVertices_[i] += offset;
-
- firstPointOffset_ += offset;
- screenOutline_.translate(offset);
- screenBounds_.translate(offset);
-}
-
-void QGeoMapPolylineGeometry::clearSource()
-{
- srcPoints_.clear();
- srcPointTypes_.clear();
-}
+ if (qMax(point.x(), point.y()) > maxCoord_)
+ maxCoord_ = qMax(point.x(), point.y());
-bool QGeoMapPolylineGeometry::contains(const QPointF &point) const
-{
- // screenOutline_.contains(screenPoint) doesn't work, as, it appears, that
- // screenOutline_ for QGeoMapPolylineGeometry is empty (QRectF(0,0 0x0))
- const QList<QPointF> &verts = vertices();
- QPolygonF tri;
- for (const auto &v : verts) {
- tri << v;
- if (tri.size() == 3) {
- if (tri.containsPoint(point, Qt::OddEvenFill))
- return true;
- tri.remove(0);
+ if (i == 0) {
+ srcPath_.moveTo(point.toPointF());
+ lastAddedPoint = point;
+ } else {
+ if ((point - lastAddedPoint).manhattanLength() > 3 ||
+ i == path.size() - 1) {
+ srcPath_.lineTo(point.toPointF());
+ lastAddedPoint = point;
+ }
+ }
}
}
- return false;
+ sourceBounds_ = srcPath_.boundingRect();
}
/*
@@ -750,7 +425,7 @@ void QDeclarativePolylineMapItemPrivateCPU::regenerateCache()
return;
const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_poly.map()->geoProjection());
m_geopathProjected.clear();
- m_geopathProjected.reserve(m_poly.m_geopath.size());
+ m_geopathProjected.reserve(m_poly.m_geopath.path().size());
for (const QGeoCoordinate &c : m_poly.m_geopath.path())
m_geopathProjected << p.geoToMapProjection(c);
}
@@ -778,16 +453,14 @@ void QDeclarativePolylineMapItemPrivateCPU::updatePolish()
const QGeoMap *map = m_poly.map();
const qreal borderWidth = m_poly.m_line.width();
- m_geometry.updateSourcePoints(*map, m_geopathProjected, m_poly.m_geopath.boundingGeoRectangle().topLeft());
-
- // still needed even with Shapes, due to contains()
- m_geometry.updateScreenPoints(*map, borderWidth);
+ m_geometry.updateSourcePoints(*map, m_geopathProjected);
const QRectF bb = m_geometry.sourceBoundingBox();
m_poly.setSize(bb.size() + QSizeF(borderWidth, borderWidth));
// it has to be shifted so that the center of the line is on the correct geocoord
m_poly.setPositionOnMap(m_geometry.origin(), -1 * bb.topLeft() + QPointF(borderWidth, borderWidth) * 0.5);
+
m_poly.setShapeTriangulationScale(m_shape, m_geometry.maxCoord_);
m_shapePath->setStrokeColor(m_poly.m_line.color());
@@ -808,11 +481,8 @@ QSGNode *QDeclarativePolylineMapItemPrivateCPU::updateMapItemPaintNode(QSGNode *
{
delete oldNode;
- //TODO: update only material
- if (m_geometry.isScreenDirty() || m_poly.m_dirtyMaterial || !oldNode) {
- m_geometry.setPreserveGeometry(false);
+ if (m_geometry.isScreenDirty() || !oldNode) {
m_geometry.markClean();
- m_poly.m_dirtyMaterial = false;
}
return nullptr;
}
@@ -822,7 +492,21 @@ bool QDeclarativePolylineMapItemPrivateCPU::contains(const QPointF &point) const
// With Shapes, do not just call
// m_shape->contains(m_poly.mapToItem(m_shape, point)) because that can
// only do FillContains at best, whereas the polyline relies on stroking.
- return m_geometry.contains(point);
+
+ const QPainterPath &path = m_geometry.srcPath_;
+ const double &lineWidth = m_poly.m_line.width();
+ const QPointF p = m_poly.mapToItem(m_shape, point) - QPointF(lineWidth, lineWidth) * 0.5;
+
+ for (int i = 1; i < path.elementCount(); i++) {
+ if (path.elementAt(i).type == QPainterPath::MoveToElement)
+ continue;
+ const double dsqr = QDeclarativeGeoMapItemUtils::distanceSqrPointLine(p.x(), p.y(),
+ path.elementAt(i - 1).x, path.elementAt(i - 1).y,
+ path.elementAt(i).x, path.elementAt(i).y);
+ if (dsqr < 0.25 * lineWidth * lineWidth)
+ return true;
+ }
+ return false;
}
/*