From 34fccf47ecf8ab2db53b23013f4f402c175ce9de Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Wed, 30 Nov 2022 12:12:03 +0100 Subject: Implement all four map items with Shape With a master switch in qdeclarativegeomapitembase_p.h, this is enabled by default. For now the old method is still available by just commenting out the define. The old path can be removed in follow-up patches; for now keeping both so one can compare and debug if further issues arise. Pick-to: 6.5 Change-Id: I01c44ee8a07d7d5f7eb018be33ac5d161ba90e2a Reviewed-by: Matthias Rauter Reviewed-by: Volker Hilsheimer --- .../quickmapitems/qdeclarativecirclemapitem.cpp | 115 ++++++++++++++++++--- 1 file changed, 98 insertions(+), 17 deletions(-) (limited to 'src/location/quickmapitems/qdeclarativecirclemapitem.cpp') diff --git a/src/location/quickmapitems/qdeclarativecirclemapitem.cpp b/src/location/quickmapitems/qdeclarativecirclemapitem.cpp index 5156b5e9..727e2eb0 100644 --- a/src/location/quickmapitems/qdeclarativecirclemapitem.cpp +++ b/src/location/quickmapitems/qdeclarativecirclemapitem.cpp @@ -16,6 +16,8 @@ #include #include +#include + QT_BEGIN_NAMESPACE /*! @@ -109,11 +111,12 @@ QGeoMapCircleGeometry::QGeoMapCircleGeometry() /*! \internal */ -void QGeoMapCircleGeometry::updateScreenPointsInvert(const QList &circlePath, const QGeoMap &map) +void QGeoMapCircleGeometry::updateSourceAndScreenPointsInvert(const QList &circlePath, const QGeoMap &map) { const QGeoProjectionWebMercator &p = static_cast(map.geoProjection()); // Not checking for !screenDirty anymore, as everything is now recalculated. clear(); + srcPath_ = QPainterPath(); if (map.viewportWidth() == 0 || map.viewportHeight() == 0 || circlePath.size() < 3) // a circle requires at least 3 points; return; @@ -187,23 +190,28 @@ void QGeoMapCircleGeometry::updateScreenPointsInvert(const QList &path: clippedPaths) { QDoubleVector2D lastAddedPoint; for (qsizetype i = 0; i < path.size(); ++i) { QDoubleVector2D point = p.wrappedMapProjectionToItemPosition(path.at(i)); //point = point - origin; // Do this using ppi.translate() + const QDoubleVector2D pt = point - origin; + if (qMax(pt.x(), pt.y()) > maxCoord_) + maxCoord_ = qMax(pt.x(), pt.y()); + if (i == 0) { - ppi.moveTo(point.toPointF()); + srcPath_.moveTo(point.toPointF()); lastAddedPoint = point; } else if ((point - lastAddedPoint).manhattanLength() > 3 || i == path.size() - 1) { - ppi.lineTo(point.toPointF()); + srcPath_.lineTo(point.toPointF()); lastAddedPoint = point; } } - ppi.closeSubpath(); + srcPath_.closeSubpath(); } + + QPainterPath ppi = srcPath_; ppi.translate(-1 * origin.toPointF()); QTriangleSet ts = qTriangulate(ppi); @@ -225,7 +233,7 @@ void QGeoMapCircleGeometry::updateScreenPointsInvert(const QListsetObjectName("_qt_map_item_shape"); + m_shape->setZ(-1); + m_shape->setContainsMode(QQuickShape::FillContains); + + m_shapePath = new QQuickShapePath(m_shape); + m_painterPath = new QDeclarativeGeoMapPainterPath(m_shapePath); + + auto pathElements = m_shapePath->pathElements(); + pathElements.append(&pathElements, m_painterPath); -QDeclarativeCircleMapItemPrivateCPU::~QDeclarativeCircleMapItemPrivateCPU() {} + auto shapePaths = m_shape->data(); + shapePaths.append(&shapePaths, m_shapePath); +#endif +} + +QDeclarativeCircleMapItemPrivateCPU::~QDeclarativeCircleMapItemPrivateCPU() +{ +#ifdef MAPITEMS_USE_SHAPES + delete m_shape; +#endif +} bool QDeclarativeCircleMapItemPrivate::preserveCircleGeometry (QList &path, const QGeoCoordinate ¢er, qreal distance, const QGeoProjectionWebMercator &p) @@ -597,9 +632,13 @@ void QDeclarativeCircleMapItemPrivateCPU::updatePolish() { if (!m_circle.m_circle.isValid()) { m_geometry.clear(); - m_borderGeometry.clear(); m_circle.setWidth(0); m_circle.setHeight(0); +#ifdef MAPITEMS_USE_SHAPES + m_shape->setVisible(false); +#else + m_borderGeometry.clear(); +#endif return; } @@ -619,16 +658,18 @@ void QDeclarativeCircleMapItemPrivateCPU::updatePolish() m_geometry.setPreserveGeometry(preserve, m_leftBound); bool invertedCircle = false; - if (crossEarthPole(m_circle.m_circle.center(), m_circle.m_circle.radius()) - && circlePath.size() == pathCount) { + if (crossEarthPole(m_circle.m_circle.center(), m_circle.m_circle.radius()) && circlePath.size() == pathCount) { // invert fill area for really huge circles - m_geometry.updateScreenPointsInvert(circlePath, *m_circle.map()); + m_geometry.updateSourceAndScreenPointsInvert(circlePath, *m_circle.map()); invertedCircle = true; } else { m_geometry.updateSourcePoints(*m_circle.map(), circlePath); - m_geometry.updateScreenPoints(*m_circle.map(), m_circle.m_border.width()); } +#ifndef MAPITEMS_USE_SHAPES + if (!invertedCircle) + m_geometry.updateScreenPoints(*m_circle.map(), m_circle.m_border.width()); + m_borderGeometry.clear(); QList geoms; geoms << &m_geometry; @@ -665,9 +706,33 @@ void QDeclarativeCircleMapItemPrivateCPU::updatePolish() m_borderGeometry.clear(); } } - - QRectF combined = QGeoMapItemGeometry::translateToCommonOrigin(geoms); - +#endif + +#ifdef MAPITEMS_USE_SHAPES + m_circle.setShapeTriangulationScale(m_shape, m_geometry.maxCoord()); + + const bool hasBorder = m_circle.m_border.color().alpha() != 0 && m_circle.m_border.width() > 0; + const float borderWidth = hasBorder ? m_circle.m_border.width() : 0.0f; + m_shapePath->setStrokeColor(hasBorder ? m_circle.m_border.color() : Qt::transparent); + m_shapePath->setStrokeWidth(hasBorder ? borderWidth : -1.0f); + m_shapePath->setFillColor(m_circle.color()); + + const QRectF bb = m_geometry.sourceBoundingBox(); + QPainterPath path = m_geometry.srcPath(); + path.translate(-bb.left() + borderWidth, -bb.top() + borderWidth); + path.closeSubpath(); + m_painterPath->setPath(path); + + m_circle.setSize(invertedCircle || !preserve + ? bb.size() + : bb.size() + QSize(2 * borderWidth, 2 * borderWidth)); + m_shape->setSize(m_circle.size()); + m_shape->setOpacity(m_circle.zoomLevelOpacity()); + m_shape->setVisible(true); + + m_circle.setPositionOnMap(m_geometry.origin(), -1 * bb.topLeft() + QPointF(borderWidth, borderWidth)); +#else + const QRectF combined = QGeoMapItemGeometry::translateToCommonOrigin(geoms); if (invertedCircle || !preserve) { m_circle.setWidth(combined.width()); m_circle.setHeight(combined.height()); @@ -675,15 +740,24 @@ void QDeclarativeCircleMapItemPrivateCPU::updatePolish() m_circle.setWidth(combined.width() + 2 * m_circle.m_border.width()); // ToDo: Fix this! m_circle.setHeight(combined.height() + 2 * m_circle.m_border.width()); } - // No offsetting here, even in normal case, because first point offset is already translated m_circle.setPositionOnMap(m_geometry.origin(), m_geometry.firstPointOffset()); +#endif } QSGNode *QDeclarativeCircleMapItemPrivateCPU::updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) { Q_UNUSED(data); +#ifdef MAPITEMS_USE_SHAPES + delete oldNode; + if (m_geometry.isScreenDirty() || m_circle.m_dirtyMaterial) { + m_geometry.setPreserveGeometry(false); + m_geometry.markClean(); + m_circle.m_dirtyMaterial = false; + } + return nullptr; +#else if (!m_node || !oldNode) { // Apparently the QSG might delete the nodes if they become invisible m_node = new MapPolygonNode(); if (oldNode) { @@ -703,11 +777,18 @@ QSGNode *QDeclarativeCircleMapItemPrivateCPU::updateMapItemPaintNode(QSGNode *ol m_borderGeometry.markClean(); m_circle.m_dirtyMaterial = false; } + return m_node; +#endif } + bool QDeclarativeCircleMapItemPrivateCPU::contains(const QPointF &point) const { +#ifdef MAPITEMS_USE_SHAPES + return m_shape->contains(m_circle.mapToItem(m_shape, point)); +#else return (m_geometry.contains(point) || m_borderGeometry.contains(point)); +#endif } QT_END_NAMESPACE -- cgit v1.2.1