diff options
Diffstat (limited to 'src/location/labs')
-rw-r--r-- | src/location/labs/qmappolygonobject.cpp | 3 | ||||
-rw-r--r-- | src/location/labs/qmappolylineobject.cpp | 6 | ||||
-rw-r--r-- | src/location/labs/qmappolylineobject_p_p.h | 3 | ||||
-rw-r--r-- | src/location/labs/qsg/qgeomapobjectqsgsupport.cpp | 2 | ||||
-rw-r--r-- | src/location/labs/qsg/qmapcircleobjectqsg.cpp | 266 | ||||
-rw-r--r-- | src/location/labs/qsg/qmapcircleobjectqsg_p_p.h | 40 | ||||
-rw-r--r-- | src/location/labs/qsg/qmappolygonobjectqsg.cpp | 186 | ||||
-rw-r--r-- | src/location/labs/qsg/qmappolygonobjectqsg_p_p.h | 11 | ||||
-rw-r--r-- | src/location/labs/qsg/qmappolylineobjectqsg.cpp | 91 | ||||
-rw-r--r-- | src/location/labs/qsg/qmappolylineobjectqsg_p_p.h | 7 |
10 files changed, 420 insertions, 195 deletions
diff --git a/src/location/labs/qmappolygonobject.cpp b/src/location/labs/qmappolygonobject.cpp index 5a8ce228..9d679f31 100644 --- a/src/location/labs/qmappolygonobject.cpp +++ b/src/location/labs/qmappolygonobject.cpp @@ -145,10 +145,9 @@ void QMapPolygonObjectPrivateDefault::setGeoShape(const QGeoShape &shape) return; const QGeoPolygon poly(shape); - setPath(poly.path()); // to handle overrides for (int i = 0; i < poly.holesCount(); i++) m_path.addHole(poly.holePath(i)); - emit static_cast<QMapPolygonObject *>(q)->pathChanged(); + setPath(poly.path()); // to handle overrides. Last as it normally emits static_cast<QMapPolygonObject *>(q)->pathChanged(); } bool QMapPolygonObjectPrivate::equals(const QGeoMapObjectPrivate &other) const diff --git a/src/location/labs/qmappolylineobject.cpp b/src/location/labs/qmappolylineobject.cpp index 81390d7c..acfe6609 100644 --- a/src/location/labs/qmappolylineobject.cpp +++ b/src/location/labs/qmappolylineobject.cpp @@ -76,7 +76,7 @@ QMapPolylineObjectPrivateDefault::QMapPolylineObjectPrivateDefault(QGeoMapObject QMapPolylineObjectPrivateDefault::QMapPolylineObjectPrivateDefault(const QMapPolylineObjectPrivate &other) : QMapPolylineObjectPrivate(other.q) { - m_path = other.path(); + m_path.setPath(other.path()); m_color = other.color(); m_width = other.width(); } @@ -88,12 +88,12 @@ QMapPolylineObjectPrivateDefault::~QMapPolylineObjectPrivateDefault() QList<QGeoCoordinate> QMapPolylineObjectPrivateDefault::path() const { - return m_path; + return m_path.path(); } void QMapPolylineObjectPrivateDefault::setPath(const QList<QGeoCoordinate> &path) { - m_path = path; + m_path.setPath(path); } QColor QMapPolylineObjectPrivateDefault::color() const diff --git a/src/location/labs/qmappolylineobject_p_p.h b/src/location/labs/qmappolylineobject_p_p.h index a0eb3711..3fdf1a1f 100644 --- a/src/location/labs/qmappolylineobject_p_p.h +++ b/src/location/labs/qmappolylineobject_p_p.h @@ -51,6 +51,7 @@ #include <QtLocation/private/qlocationglobal_p.h> #include <QtLocation/private/qgeomapobject_p_p.h> #include <QGeoCoordinate> +#include <QGeoPath> #include <QColor> QT_BEGIN_NAMESPACE @@ -95,7 +96,7 @@ public: QGeoMapObjectPrivate *clone() override; public: - QList<QGeoCoordinate> m_path; + QGeoPath m_path; // small overhead compared to plain QList<QGeoCoordinate> QColor m_color; qreal m_width = 0; diff --git a/src/location/labs/qsg/qgeomapobjectqsgsupport.cpp b/src/location/labs/qsg/qgeomapobjectqsgsupport.cpp index 6cb2c44a..f965efb7 100644 --- a/src/location/labs/qsg/qgeomapobjectqsgsupport.cpp +++ b/src/location/labs/qsg/qgeomapobjectqsgsupport.cpp @@ -152,6 +152,7 @@ void QGeoMapObjectQSGSupport::removeMapObject(QGeoMapObject *obj) } } +// called in the render thread void QGeoMapObjectQSGSupport::updateMapObjects(QSGNode *root, QQuickWindow *window) { if (!m_mapObjectsRootNode) { @@ -216,6 +217,7 @@ void QGeoMapObjectQSGSupport::updateMapObjects(QSGNode *root, QQuickWindow *wind m_mapObjectsRootNode->setSubtreeBlocked(false); } +// called in GUI thread void QGeoMapObjectQSGSupport::updateObjectsGeometry() { for (int i = 0; i < m_mapObjects.size(); ++i) { diff --git a/src/location/labs/qsg/qmapcircleobjectqsg.cpp b/src/location/labs/qsg/qmapcircleobjectqsg.cpp index 6c69ce5a..5b1f5361 100644 --- a/src/location/labs/qsg/qmapcircleobjectqsg.cpp +++ b/src/location/labs/qsg/qmapcircleobjectqsg.cpp @@ -41,16 +41,19 @@ QT_BEGIN_NAMESPACE static const int CircleSamples = 128; QMapCircleObjectPrivateQSG::QMapCircleObjectPrivateQSG(QGeoMapObject *q) - : QMapCircleObjectPrivateDefault(q) + : QMapCircleObjectPrivateDefault(q), m_dataCPU(new CircleDataCPU) { } QMapCircleObjectPrivateQSG::QMapCircleObjectPrivateQSG(const QMapCircleObjectPrivate &other) - : QMapCircleObjectPrivateDefault(other) + : QMapCircleObjectPrivateDefault(other), m_dataCPU(new CircleDataCPU) { // Data already cloned by the *Default copy constructor, but necessary // update operations triggered only by setters overrides + if (!QDeclarativeCircleMapItemPrivateCPU::crossEarthPole(center(), radius())) + switchToGL(); // this marks source dirty + updateGeometry(); if (m_map) emit m_map->sgNodeChanged(); @@ -62,47 +65,54 @@ QMapCircleObjectPrivateQSG::~QMapCircleObjectPrivateQSG() m_map->removeMapObject(q); } -void QMapCircleObjectPrivateQSG::updateCirclePath() +void QMapCircleObjectPrivateQSG::updateGeometry() +{ + if (!m_dataGL.isNull()) + updateGeometryGL(); + else + updateGeometryCPU(); +} + +void QMapCircleObjectPrivateQSG::CircleDataCPU::updateCirclePath(const QGeoCoordinate ¢er, qreal radius, const QGeoProjectionWebMercator &p) { - const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_map->geoProjection()); QList<QGeoCoordinate> path; - QDeclarativeCircleMapItemPrivateCPU::calculatePeripheralPoints(path, center(), radius(), CircleSamples, m_leftBound); + QDeclarativeCircleMapItemPrivateCPU::calculatePeripheralPoints(path, center, radius, CircleSamples, m_leftBound); m_circlePath.clear(); for (const QGeoCoordinate &c : path) m_circlePath << p.geoToMapProjection(c); } -void QMapCircleObjectPrivateQSG::updateGeometry() +void QMapCircleObjectPrivateQSG::updateGeometryCPU() { if (!m_map || m_map->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator || !qIsFinite(radius()) || !center().isValid()) return; const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_map->geoProjection()); - QScopedValueRollback<bool> rollback(m_updatingGeometry); - m_updatingGeometry = true; + QScopedValueRollback<bool> rollback(m_dataCPU->m_updatingGeometry); + m_dataCPU->m_updatingGeometry = true; - updateCirclePath(); - QList<QDoubleVector2D> circlePath = m_circlePath; + m_dataCPU->updateCirclePath(center(), radius(), p); + QList<QDoubleVector2D> circlePath = m_dataCPU->m_circlePath; int pathCount = circlePath.size(); bool preserve = QDeclarativeCircleMapItemPrivateCPU::preserveCircleGeometry(circlePath, center(), radius(), p); // using leftBound_ instead of the analytically calculated circle_.boundingGeoRectangle().topLeft()); // to fix QTBUG-62154 - m_geometry.markSourceDirty(); - m_geometry.setPreserveGeometry(true, m_leftBound); // to set the geoLeftBound_ - m_geometry.setPreserveGeometry(preserve, m_leftBound); + m_dataCPU->m_geometry.markSourceDirty(); + m_dataCPU->m_geometry.setPreserveGeometry(true, m_dataCPU->m_leftBound); // to set the geoLeftBound_ + m_dataCPU->m_geometry.setPreserveGeometry(preserve, m_dataCPU->m_leftBound); bool invertedCircle = false; if (QDeclarativeCircleMapItemPrivateCPU::crossEarthPole(center(), radius()) && circlePath.size() == pathCount) { - m_geometry.updateScreenPointsInvert(circlePath, *m_map); // invert fill area for really huge circles + m_dataCPU->m_geometry.updateScreenPointsInvert(circlePath, *m_map); // invert fill area for really huge circles invertedCircle = true; } else { - m_geometry.updateSourcePoints(*m_map, circlePath); - m_geometry.updateScreenPoints(*m_map); + m_dataCPU->m_geometry.updateSourcePoints(*m_map, circlePath); + m_dataCPU->m_geometry.updateScreenPoints(*m_map); } - m_borderGeometry.clear(); + m_dataCPU->m_borderGeometry.clear(); //if (borderColor() != Qt::transparent && borderWidth() > 0) { @@ -110,35 +120,76 @@ void QMapCircleObjectPrivateQSG::updateGeometry() closedPath << closedPath.first(); if (invertedCircle) { - closedPath = m_circlePath; + closedPath = m_dataCPU->m_circlePath; closedPath << closedPath.first(); std::reverse(closedPath.begin(), closedPath.end()); } - m_borderGeometry.markSourceDirty(); - m_borderGeometry.setPreserveGeometry(true, m_leftBound); - m_borderGeometry.setPreserveGeometry(preserve, m_leftBound); + m_dataCPU->m_borderGeometry.markSourceDirty(); + m_dataCPU->m_borderGeometry.setPreserveGeometry(true, m_dataCPU->m_leftBound); + m_dataCPU->m_borderGeometry.setPreserveGeometry(preserve, m_dataCPU->m_leftBound); // Use srcOrigin_ from fill geometry after clipping to ensure that translateToCommonOrigin won't fail. - const QGeoCoordinate &geometryOrigin = m_geometry.origin(); + const QGeoCoordinate &geometryOrigin = m_dataCPU->m_geometry.origin(); - m_borderGeometry.clearSource(); + m_dataCPU->m_borderGeometry.clearSource(); QDoubleVector2D borderLeftBoundWrapped; QList<QList<QDoubleVector2D > > clippedPaths = - m_borderGeometry.clipPath(*m_map, closedPath, borderLeftBoundWrapped); + m_dataCPU->m_borderGeometry.clipPath(*m_map, closedPath, borderLeftBoundWrapped); if (clippedPaths.size()) { borderLeftBoundWrapped = p.geoToWrappedMapProjection(geometryOrigin); - m_borderGeometry.pathToScreen(*m_map, clippedPaths, borderLeftBoundWrapped); - m_borderGeometry.updateScreenPoints(*m_map, borderWidth(), false); + m_dataCPU->m_borderGeometry.pathToScreen(*m_map, clippedPaths, borderLeftBoundWrapped); + m_dataCPU->m_borderGeometry.updateScreenPoints(*m_map, borderWidth(), false); } else { - m_borderGeometry.clear(); + m_dataCPU->m_borderGeometry.clear(); } } - QPointF origin = m_map->geoProjection().coordinateToItemPosition(m_geometry.origin(), false).toPointF(); - m_geometry.translate(origin - m_geometry.firstPointOffset()); - m_borderGeometry.translate(origin - m_borderGeometry.firstPointOffset()); + QPointF origin = m_map->geoProjection().coordinateToItemPosition(m_dataCPU->m_geometry.origin(), false).toPointF(); + m_dataCPU->m_geometry.translate(origin - m_dataCPU->m_geometry.firstPointOffset()); + m_dataCPU->m_borderGeometry.translate(origin - m_dataCPU->m_borderGeometry.firstPointOffset()); +} + +void QMapCircleObjectPrivateQSG::CircleDataGL::updateCirclePath(const QGeoCoordinate ¢er, qreal radius, const QGeoProjectionWebMercator &p) +{ + m_circlePath.clear(); + if (radius < 0.001) // 1mm is small enough, probably already way too small. + return; + QDeclarativeCircleMapItemPrivate::calculatePeripheralPoints(m_circlePath, + center, + radius, + CircleSamples, + m_leftBound); + + m_leftBoundMercator = p.geoToMapProjection(m_leftBound); + m_geometry.setPreserveGeometry(true, m_leftBound); + m_borderGeometry.setPreserveGeometry(true, m_leftBound); +} + +void QMapCircleObjectPrivateQSG::updateGeometryGL() +{ + if (!m_map || m_map->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator) + return; + + const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_map->geoProjection()); + if (m_dataGL->m_geometry.isSourceDirty() + || m_dataGL->m_borderGeometry.isSourceDirty()) { + m_dataGL->updateCirclePath(center(), radius(), p); + + if (m_dataGL->m_circlePath.length() == 0) { // Possibly cleared + m_dataGL->m_geometry.clear(); + m_dataGL->m_borderGeometry.clear(); + return; + } + m_dataGL->m_geometry.m_dataChanged = m_dataGL->m_borderGeometry.m_dataChanged = true; + m_dataGL->m_geometry.updateSourcePoints(*m_map, m_dataGL->m_circlePath); + m_dataGL->m_borderGeometry.updateSourcePoints(*m_map, QGeoCircle(center(), radius())); + m_dataGL->m_circlePath.clear(); // not needed anymore + } + m_dataGL->m_geometry.markScreenDirty(); // ToDo: this needs refactor. It's useless, remove screenDirty_ altogether. + m_dataGL->m_borderGeometry.markScreenDirty(); + m_dataGL->m_borderGeometry.m_wrapOffset = m_dataGL->m_geometry.m_wrapOffset = p.projectionWrapFactor(m_dataGL->m_leftBoundMercator) + 1; } QGeoMapObjectPrivate *QMapCircleObjectPrivateQSG::clone() @@ -146,45 +197,144 @@ QGeoMapObjectPrivate *QMapCircleObjectPrivateQSG::clone() return new QMapCircleObjectPrivateQSG(static_cast<QMapCircleObjectPrivate &>(*this)); } +void QMapCircleObjectPrivateQSG::switchToGL() +{ + if (!m_dataGL.isNull()) + return; + QScopedPointer<CircleDataGL> data(new CircleDataGL); + m_dataGL.swap(data); + m_dataGL->markSourceDirty(); + m_dataCPU.reset(nullptr); +} + +void QMapCircleObjectPrivateQSG::switchToCPU() +{ + if (!m_dataCPU.isNull()) + return; + QScopedPointer<CircleDataCPU> data(new CircleDataCPU); + m_dataCPU.swap(data); + m_dataGL.reset(nullptr); +} + QSGNode *QMapCircleObjectPrivateQSG::updateMapObjectNode(QSGNode *oldNode, VisibleNode **visibleNode, QSGNode *root, - QQuickWindow * /*window*/) + QQuickWindow * window) { -// Q_UNUSED(visibleNode); // coz of -Werror=unused-but-set-parameter - MapPolygonNode *node = static_cast<MapPolygonNode *>(oldNode); + if (!m_dataGL.isNull()) + return updateMapObjectNodeGL(oldNode, visibleNode, root, window); + else + return updateMapObjectNodeCPU(oldNode, visibleNode, root, window); +} - if (!node) { - if (!m_geometry.size() && !m_borderGeometry.size()) { - return nullptr; - } - node = new MapPolygonNode(); - *visibleNode = static_cast<VisibleNode *>(node); +QSGNode *QMapCircleObjectPrivateQSG::updateMapObjectNodeCPU(QSGNode *oldNode, + VisibleNode **visibleNode, + QSGNode *root, + QQuickWindow */*window*/) +{ + if (!m_dataCPU->m_node || !oldNode) { + m_dataCPU->m_node = new MapPolygonNode(); + *visibleNode = static_cast<VisibleNode *>(m_dataCPU->m_node); + if (oldNode) + delete oldNode; + } else { + m_dataCPU->m_node = static_cast<MapPolygonNode *>(oldNode); + } + + if (!m_dataCPU->m_geometry.size() && !m_dataCPU->m_borderGeometry.size()) { + visibleNode = nullptr; + return nullptr; } //TODO: update only material - if (m_geometry.isScreenDirty() || !m_borderGeometry.isScreenDirty() || !oldNode) { + if (m_dataCPU->m_geometry.isScreenDirty() || m_dataCPU->m_borderGeometry.isScreenDirty() || oldNode != m_dataCPU->m_node) { //QMapPolygonObject *p = static_cast<QMapPolygonObject *>(q); - node->update(color(), borderColor(), &m_geometry, &m_borderGeometry); - m_geometry.setPreserveGeometry(false); - m_borderGeometry.setPreserveGeometry(false); - m_geometry.markClean(); - m_borderGeometry.markClean(); + m_dataCPU->m_node->update(color(), borderColor(), &m_dataCPU->m_geometry, &m_dataCPU->m_borderGeometry); + m_dataCPU->m_geometry.setPreserveGeometry(false); + m_dataCPU->m_borderGeometry.setPreserveGeometry(false); + m_dataCPU->m_geometry.markClean(); + m_dataCPU->m_borderGeometry.markClean(); } - if (m_geometry.size() || m_borderGeometry.size()) { - root->appendChildNode(node); + if (m_dataCPU->m_geometry.size() || m_dataCPU->m_borderGeometry.size()) { + root->appendChildNode(m_dataCPU->m_node); } else { - delete node; + delete m_dataCPU->m_node; + m_dataCPU->m_node = nullptr; + visibleNode = nullptr; return nullptr; } - return node; + return m_dataCPU->m_node; } +QSGNode *QMapCircleObjectPrivateQSG::updateMapObjectNodeGL(QSGNode *oldNode, + VisibleNode **visibleNode, + QSGNode *root, + QQuickWindow */*window*/) +{ + if (!m_dataGL->m_rootNode || !oldNode) { + m_dataGL->m_rootNode = new QDeclarativePolygonMapItemPrivateOpenGL::RootNode(); + m_dataGL->m_node = new MapPolygonNodeGL(); + m_dataGL->m_rootNode->appendChildNode(m_dataGL->m_node); + m_dataGL->m_polylinenode = new MapPolylineNodeOpenGLExtruded(); + m_dataGL->m_rootNode->appendChildNode(m_dataGL->m_polylinenode); + m_dataGL->m_rootNode->markDirty(QSGNode::DirtyNodeAdded); + *visibleNode = static_cast<VisibleNode *>(m_dataGL->m_rootNode); + if (oldNode) + delete oldNode; + } else { + m_dataGL->m_rootNode = static_cast<QDeclarativePolygonMapItemPrivateOpenGL::RootNode *>(oldNode); + } + + const QMatrix4x4 &combinedMatrix = m_map->geoProjection().qsgTransform(); + const QDoubleVector3D &cameraCenter = m_map->geoProjection().centerMercator(); + + if (m_dataGL->m_borderGeometry.isScreenDirty()) { + /* Do the border update first */ + m_dataGL->m_polylinenode->update(borderColor(), + float(borderWidth()), + &m_dataGL->m_borderGeometry, + combinedMatrix, + cameraCenter, + Qt::SquareCap, + true); + m_dataGL->m_borderGeometry.setPreserveGeometry(false); + m_dataGL->m_borderGeometry.markClean(); + } + if (m_dataGL->m_geometry.isScreenDirty()) { + m_dataGL->m_node->update(color(), + &m_dataGL->m_geometry, + combinedMatrix, + cameraCenter); + m_dataGL->m_geometry.setPreserveGeometry(false); + m_dataGL->m_geometry.markClean(); + } + + if (!m_dataGL->m_polylinenode->isSubtreeBlocked() || !m_dataGL->m_node->isSubtreeBlocked()) { + m_dataGL->m_rootNode->setSubtreeBlocked(false); + root->appendChildNode(m_dataGL->m_rootNode); + return m_dataGL->m_rootNode; + } else { + delete m_dataGL->m_rootNode; + m_dataGL->m_rootNode = nullptr; + m_dataGL->m_node = nullptr; + m_dataGL->m_polylinenode = nullptr; + *visibleNode = nullptr; + return nullptr; + } +} void QMapCircleObjectPrivateQSG::setCenter(const QGeoCoordinate ¢er) { QMapCircleObjectPrivateDefault::setCenter(center); + if (!QDeclarativeCircleMapItemPrivate::crossEarthPole(this->center(), this->radius())) // Switching implementation for circles crossing/not crossing poles + switchToGL(); + else + switchToCPU(); + + if (!m_dataGL.isNull()) + m_dataGL->markSourceDirty(); + updateGeometry(); if (m_map) emit m_map->sgNodeChanged(); @@ -193,6 +343,14 @@ void QMapCircleObjectPrivateQSG::setCenter(const QGeoCoordinate ¢er) void QMapCircleObjectPrivateQSG::setRadius(qreal radius) { QMapCircleObjectPrivateDefault::setRadius(radius); + if (!QDeclarativeCircleMapItemPrivate::crossEarthPole(this->center(), this->radius())) // Switching implementation for circles crossing/not crossing poles + switchToGL(); + else + switchToCPU(); + + if (!m_dataGL.isNull()) + m_dataGL->markSourceDirty(); + updateGeometry(); if (m_map) emit m_map->sgNodeChanged(); @@ -201,7 +359,8 @@ void QMapCircleObjectPrivateQSG::setRadius(qreal radius) void QMapCircleObjectPrivateQSG::setColor(const QColor &color) { QMapCircleObjectPrivateDefault::setColor(color); - updateGeometry(); + if (!m_dataCPU.isNull()) + updateGeometry(); if (m_map) emit m_map->sgNodeChanged(); } @@ -209,7 +368,8 @@ void QMapCircleObjectPrivateQSG::setColor(const QColor &color) void QMapCircleObjectPrivateQSG::setBorderColor(const QColor &color) { QMapCircleObjectPrivateDefault::setBorderColor(color); - updateGeometry(); + if (!m_dataCPU.isNull()) + updateGeometry(); if (m_map) emit m_map->sgNodeChanged(); } @@ -217,10 +377,10 @@ void QMapCircleObjectPrivateQSG::setBorderColor(const QColor &color) void QMapCircleObjectPrivateQSG::setBorderWidth(qreal width) { QMapCircleObjectPrivateDefault::setBorderWidth(width); - updateGeometry(); + if (!m_dataCPU.isNull()) + updateGeometry(); if (m_map) emit m_map->sgNodeChanged(); } - QT_END_NAMESPACE diff --git a/src/location/labs/qsg/qmapcircleobjectqsg_p_p.h b/src/location/labs/qsg/qmapcircleobjectqsg_p_p.h index 6bbeb397..dc057c0b 100644 --- a/src/location/labs/qsg/qmapcircleobjectqsg_p_p.h +++ b/src/location/labs/qsg/qmapcircleobjectqsg_p_p.h @@ -68,14 +68,22 @@ public: QMapCircleObjectPrivateQSG(const QMapCircleObjectPrivate &other); ~QMapCircleObjectPrivateQSG() override; - void updateCirclePath(); - // QQSGMapObject void updateGeometry() override; + void updateGeometryCPU(); + void updateGeometryGL(); QSGNode *updateMapObjectNode(QSGNode *oldNode, VisibleNode **visibleNode, QSGNode *root, QQuickWindow *window) override; + QSGNode *updateMapObjectNodeCPU(QSGNode *oldNode, + VisibleNode **visibleNode, + QSGNode *root, + QQuickWindow *window); + QSGNode *updateMapObjectNodeGL(QSGNode *oldNode, + VisibleNode **visibleNode, + QSGNode *root, + QQuickWindow *window); // QGeoMapCirclePrivate interface void setCenter(const QGeoCoordinate ¢er) override; @@ -87,15 +95,43 @@ public: // QGeoMapObjectPrivate QGeoMapObjectPrivate *clone() override; + void switchToGL(); + void switchToCPU(); + public: // Data Members +struct CircleDataCPU { + MapPolygonNode *m_node = nullptr; QList<QDoubleVector2D> m_circlePath; QGeoCoordinate m_leftBound; QGeoMapCircleGeometry m_geometry; QGeoMapPolylineGeometry m_borderGeometry; bool m_updatingGeometry = false; + + void updateCirclePath(const QGeoCoordinate ¢er, qreal radius, const QGeoProjectionWebMercator &p); +}; +struct CircleDataGL { + QList<QGeoCoordinate> m_circlePath; + QGeoCoordinate m_leftBound; + QDoubleVector2D m_leftBoundMercator; + QGeoMapPolygonGeometryOpenGL m_geometry; + QGeoMapPolylineGeometryOpenGL m_borderGeometry; + QDeclarativePolygonMapItemPrivateOpenGL::RootNode *m_rootNode = nullptr; + MapPolygonNodeGL *m_node = nullptr; + MapPolylineNodeOpenGLExtruded *m_polylinenode = nullptr; + + void updateCirclePath(const QGeoCoordinate ¢er, qreal radius, const QGeoProjectionWebMercator &p); + void markSourceDirty() + { + m_geometry.markSourceDirty(); + m_borderGeometry.markSourceDirty(); + } +}; + QScopedPointer<CircleDataCPU> m_dataCPU; + QScopedPointer<CircleDataGL> m_dataGL; }; QT_END_NAMESPACE #endif // QMAPCIRCLEOBJECT_P_P_H + diff --git a/src/location/labs/qsg/qmappolygonobjectqsg.cpp b/src/location/labs/qsg/qmappolygonobjectqsg.cpp index 25473478..a8a1cb4b 100644 --- a/src/location/labs/qsg/qmappolygonobjectqsg.cpp +++ b/src/location/labs/qsg/qmappolygonobjectqsg.cpp @@ -52,6 +52,7 @@ QMapPolygonObjectPrivateQSG::QMapPolygonObjectPrivateQSG(const QMapPolygonObject { // Data already cloned by the *Default copy constructor, but necessary // update operations triggered only by setters overrides + markSourceDirty(); updateGeometry(); if (m_map) emit m_map->sgNodeChanged(); @@ -63,67 +64,22 @@ QMapPolygonObjectPrivateQSG::~QMapPolygonObjectPrivateQSG() m_map->removeMapObject(q); } -QList<QDoubleVector2D> QMapPolygonObjectPrivateQSG::projectPath() +void QMapPolygonObjectPrivateQSG::setPath(const QList<QGeoCoordinate> &p) { - QList<QDoubleVector2D> geopathProjected_; - if (!m_map || m_map->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator) - return geopathProjected_; - - const QGeoProjectionWebMercator &p = - static_cast<const QGeoProjectionWebMercator&>(m_map->geoProjection()); - geopathProjected_.reserve(m_path.path().size()); - for (const QGeoCoordinate &c : m_path.path()) - geopathProjected_ << p.geoToMapProjection(c); - return geopathProjected_; -} - -QSGNode *QMapPolygonObjectPrivateQSG::updateMapObjectNode(QSGNode *oldNode, - VisibleNode **visibleNode, - QSGNode *root, - QQuickWindow * /*window*/) -{ - Q_UNUSED(visibleNode); - MapPolygonNode *node = static_cast<MapPolygonNode *>(oldNode); - - if (!node) { - if (!m_geometry.size() && !m_borderGeometry.size()) { - return nullptr; - } - node = new MapPolygonNode(); - *visibleNode = static_cast<VisibleNode *>(node); - } - - //TODO: update only material - if (m_geometry.isScreenDirty() || !m_borderGeometry.isScreenDirty() || !oldNode) { - node->update(fillColor(), borderColor(), &m_geometry, &m_borderGeometry); - m_geometry.setPreserveGeometry(false); - m_borderGeometry.setPreserveGeometry(false); - m_geometry.markClean(); - m_borderGeometry.markClean(); - } - - if (m_geometry.size() || m_borderGeometry.size()) { - root->appendChildNode(node); - } else { - delete node; - return nullptr; - } - return node; -} - -void QMapPolygonObjectPrivateQSG::setPath(const QList<QGeoCoordinate> &path) -{ - QMapPolygonObjectPrivateDefault::setPath(path); + if (p == path()) + return; + QMapPolygonObjectPrivateDefault::setPath(p); + markSourceDirty(); updateGeometry(); if (m_map) emit m_map->sgNodeChanged(); + emit static_cast<QMapPolygonObject *>(q)->pathChanged(); } void QMapPolygonObjectPrivateQSG::setFillColor(const QColor &color) { QMapPolygonObjectPrivateDefault::setFillColor(color); - updateGeometry(); if (m_map) emit m_map->sgNodeChanged(); @@ -132,7 +88,6 @@ void QMapPolygonObjectPrivateQSG::setFillColor(const QColor &color) void QMapPolygonObjectPrivateQSG::setBorderColor(const QColor &color) { QMapPolygonObjectPrivateDefault::setBorderColor(color); - updateGeometry(); if (m_map) emit m_map->sgNodeChanged(); @@ -141,7 +96,6 @@ void QMapPolygonObjectPrivateQSG::setBorderColor(const QColor &color) void QMapPolygonObjectPrivateQSG::setBorderWidth(qreal width) { QMapPolygonObjectPrivateDefault::setBorderWidth(width); - updateGeometry(); if (m_map) emit m_map->sgNodeChanged(); @@ -158,59 +112,111 @@ void QMapPolygonObjectPrivateQSG::setGeoShape(const QGeoShape &shape) return; m_path = QGeoPathEager(shape); + markSourceDirty(); updateGeometry(); if (m_map) emit m_map->sgNodeChanged(); emit static_cast<QMapPolygonObject *>(q)->pathChanged(); } +// This is called both when data changes and when viewport changes. +// so handle both cases (sourceDirty, !sourceDirty) void QMapPolygonObjectPrivateQSG::updateGeometry() { - if (!m_map || m_path.path().length() == 0 - || m_map->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator) + if (!m_map || m_map->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator) return; - QScopedValueRollback<bool> rollback(m_updatingGeometry); - m_updatingGeometry = true; - - const QList<QDoubleVector2D> &geopathProjected = projectPath(); - - m_geometry.markSourceDirty(); - m_geometry.setPreserveGeometry(true, m_path.boundingGeoRectangle().topLeft()); - m_geometry.updateSourcePoints(*m_map, geopathProjected); - m_geometry.updateScreenPoints(*m_map); - - m_borderGeometry.clear(); - - //if (border_.color() != Qt::transparent && border_.width() > 0) - { - const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_map->geoProjection()); - QList<QDoubleVector2D> closedPath = geopathProjected; - closedPath << closedPath.first(); - - m_borderGeometry.markSourceDirty(); + if (m_path.path().length() == 0) { // Possibly cleared + m_geometry.clear(); + m_borderGeometry.clear(); + return; + } + const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_map->geoProjection()); + if (m_geometry.isSourceDirty() || m_borderGeometry.isSourceDirty()) { + // This works a bit differently than MapPolygon: + // the "screen bounds" aren't needed, so update only sources, + // regardless of the color, as color changes won't trigger polish(), + // and remember to flag m_dataChanged, that is in principle the same as + // sourceDirty_, but in practice is cleared in two different codepaths. + // sourceDirty_ is cleared in any case, dataChanged only if the primitive + // is effectively visible (e.g., not transparent or border not null) + m_geometry.setPreserveGeometry(true, m_path.boundingGeoRectangle().topLeft()); m_borderGeometry.setPreserveGeometry(true, m_path.boundingGeoRectangle().topLeft()); + m_geometry.m_dataChanged = m_borderGeometry.m_dataChanged = true; + m_geometry.updateSourcePoints(*m_map, m_path); + m_borderGeometry.updateSourcePoints(*m_map, m_path); + m_leftBoundMercator = p.geoToMapProjection(m_geometry.origin()); + } + m_geometry.markScreenDirty(); // ToDo: this needs refactor. It's useless, remove screenDirty_ altogether. + m_borderGeometry.markScreenDirty(); + m_borderGeometry.m_wrapOffset = m_geometry.m_wrapOffset = p.projectionWrapFactor(m_leftBoundMercator) + 1; +} - const QGeoCoordinate &geometryOrigin = m_geometry.origin(); - - m_borderGeometry.clearSource(); +QSGNode *QMapPolygonObjectPrivateQSG::updateMapObjectNode(QSGNode *oldNode, + VisibleNode **visibleNode, + QSGNode *root, + QQuickWindow * /*window*/) +{ + if (!m_rootNode || !oldNode) { + m_rootNode = new QDeclarativePolygonMapItemPrivateOpenGL::RootNode(); + m_node = new MapPolygonNodeGL(); + m_rootNode->appendChildNode(m_node); + m_polylinenode = new MapPolylineNodeOpenGLExtruded(); + m_rootNode->appendChildNode(m_polylinenode); + m_rootNode->markDirty(QSGNode::DirtyNodeAdded); + *visibleNode = static_cast<VisibleNode *>(m_rootNode); + if (oldNode) + delete oldNode; + } else { + m_rootNode = static_cast<QDeclarativePolygonMapItemPrivateOpenGL::RootNode *>(oldNode); + } - QDoubleVector2D borderLeftBoundWrapped; - QList<QList<QDoubleVector2D > > clippedPaths = - m_borderGeometry.clipPath(*m_map.data(), closedPath, borderLeftBoundWrapped); + const QMatrix4x4 &combinedMatrix = m_map->geoProjection().qsgTransform(); + const QDoubleVector3D &cameraCenter = m_map->geoProjection().centerMercator(); + + if (m_borderGeometry.isScreenDirty()) { + /* Do the border update first */ + m_polylinenode->update(borderColor(), + float(borderWidth()), + &m_borderGeometry, + combinedMatrix, + cameraCenter, + Qt::SquareCap, + true); + m_borderGeometry.setPreserveGeometry(false); + m_borderGeometry.markClean(); + } + if (m_geometry.isScreenDirty()) { + m_node->update(fillColor(), + &m_geometry, + combinedMatrix, + cameraCenter); + m_geometry.setPreserveGeometry(false); + m_geometry.markClean(); + } - if (clippedPaths.size()) { - borderLeftBoundWrapped = p.geoToWrappedMapProjection(geometryOrigin); - m_borderGeometry.pathToScreen(*m_map.data(), clippedPaths, borderLeftBoundWrapped); - m_borderGeometry.updateScreenPoints(*m_map.data(), borderWidth(), false); - } else { - m_borderGeometry.clear(); - } + if (!m_polylinenode->isSubtreeBlocked() || !m_node->isSubtreeBlocked()) { + m_rootNode->setSubtreeBlocked(false); + root->appendChildNode(m_rootNode); + return m_rootNode; + } else { + m_rootNode->setSubtreeBlocked(true); + // If the object is currently invisible, but not gone, + // it is reasonable to assume it will become visible again. + // However, better not to retain unused data. + delete m_rootNode; + m_rootNode = nullptr; + m_node = nullptr; + m_polylinenode = nullptr; + *visibleNode = nullptr; + return nullptr; } +} - QPointF origin = m_map->geoProjection().coordinateToItemPosition(m_geometry.origin(), false).toPointF(); - m_geometry.translate(origin - m_geometry.firstPointOffset()); - m_borderGeometry.translate(origin - m_borderGeometry.firstPointOffset()); +void QMapPolygonObjectPrivateQSG::markSourceDirty() +{ + m_geometry.markSourceDirty(); + m_borderGeometry.markSourceDirty(); } QT_END_NAMESPACE diff --git a/src/location/labs/qsg/qmappolygonobjectqsg_p_p.h b/src/location/labs/qsg/qmappolygonobjectqsg_p_p.h index 8e6ae8a8..9dcece74 100644 --- a/src/location/labs/qsg/qmappolygonobjectqsg_p_p.h +++ b/src/location/labs/qsg/qmappolygonobjectqsg_p_p.h @@ -67,6 +67,7 @@ public: QList<QDoubleVector2D> projectPath(); // QQSGMapObject + void markSourceDirty(); void updateGeometry() override; QSGNode *updateMapObjectNode(QSGNode *oldNode, VisibleNode **visibleNode, @@ -84,10 +85,12 @@ public: virtual void setGeoShape(const QGeoShape &shape) override; // Data Members - QGeoMapPolygonGeometry m_geometry; - QGeoMapPolylineGeometry m_borderGeometry; - - bool m_updatingGeometry = false; + QDoubleVector2D m_leftBoundMercator; + QGeoMapPolygonGeometryOpenGL m_geometry; + QGeoMapPolylineGeometryOpenGL m_borderGeometry; + QDeclarativePolygonMapItemPrivateOpenGL::RootNode *m_rootNode = nullptr; + MapPolygonNodeGL *m_node = nullptr; + MapPolylineNodeOpenGLExtruded *m_polylinenode = nullptr; }; QT_END_NAMESPACE diff --git a/src/location/labs/qsg/qmappolylineobjectqsg.cpp b/src/location/labs/qsg/qmappolylineobjectqsg.cpp index 96f66565..817d4df5 100644 --- a/src/location/labs/qsg/qmappolylineobjectqsg.cpp +++ b/src/location/labs/qsg/qmappolylineobjectqsg.cpp @@ -53,9 +53,9 @@ QMapPolylineObjectPrivateQSG::QMapPolylineObjectPrivateQSG(QGeoMapObject *q) QMapPolylineObjectPrivateQSG::QMapPolylineObjectPrivateQSG(const QMapPolylineObjectPrivate &other) : QMapPolylineObjectPrivateDefault(other) { - m_geoPath.setPath(m_path); // rest of the data already cloned by the *Default copy constructor, but necessary // update operations triggered only by setters overrides + markSourceDirty(); updateGeometry(); if (m_map) emit m_map->sgNodeChanged(); @@ -75,28 +75,31 @@ QList<QDoubleVector2D> QMapPolylineObjectPrivateQSG::projectPath() const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_map->geoProjection()); - geopathProjected_.reserve(m_geoPath.path().size()); - for (const QGeoCoordinate &c : m_geoPath.path()) + geopathProjected_.reserve(m_path.path().size()); + for (const QGeoCoordinate &c : m_path.path()) geopathProjected_ << p.geoToMapProjection(c); return geopathProjected_; } void QMapPolylineObjectPrivateQSG::updateGeometry() { - if (!m_map || m_geoPath.path().length() == 0 - || m_map->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator) + if (!m_map || m_map->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator) return; - QScopedValueRollback<bool> rollback(m_updatingGeometry); - m_updatingGeometry = true; - m_geometry.markSourceDirty(); - const QList<QDoubleVector2D> &geopathProjected = projectPath(); - m_geometry.setPreserveGeometry(true, m_geoPath.boundingGeoRectangle().topLeft()); - m_geometry.updateSourcePoints(*m_map.data(), geopathProjected, m_geoPath.boundingGeoRectangle().topLeft()); - m_geometry.updateScreenPoints(*m_map.data(), width(), false); + if (m_path.path().length() == 0) { // Possibly cleared + m_borderGeometry.clear(); + return; + } - QPointF origin = m_map->geoProjection().coordinateToItemPosition(m_geometry.origin(), false).toPointF(); - m_geometry.translate(origin - m_geometry.firstPointOffset()); + const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_map->geoProjection()); + if (m_borderGeometry.isSourceDirty()) { + m_borderGeometry.setPreserveGeometry(true, m_path.boundingGeoRectangle().topLeft()); + m_borderGeometry.m_dataChanged = true; + m_borderGeometry.updateSourcePoints(*m_map, m_path); + m_leftBoundMercator = p.geoToMapProjection(m_borderGeometry.origin()); + } + m_borderGeometry.markScreenDirty(); + m_borderGeometry.m_wrapOffset = p.projectionWrapFactor(m_leftBoundMercator) + 1; } QSGNode *QMapPolylineObjectPrivateQSG::updateMapObjectNode(QSGNode *oldNode, @@ -104,41 +107,52 @@ QSGNode *QMapPolylineObjectPrivateQSG::updateMapObjectNode(QSGNode *oldNode, QSGNode *root, QQuickWindow * /*window*/) { - Q_UNUSED(visibleNode); - MapPolylineNode *node = static_cast<MapPolylineNode *>(oldNode); - - if (!node) { - if (!m_geometry.size()) // condition to block the subtree - return nullptr; - node = new MapPolylineNode(); - *visibleNode = static_cast<VisibleNode *>(node); + if (!m_polylinenode || !oldNode) { + m_polylinenode = new MapPolylineNodeOpenGLExtruded(); + *visibleNode = static_cast<VisibleNode *>(m_polylinenode); + if (oldNode) + delete oldNode; + } else { + m_polylinenode = static_cast<MapPolylineNodeOpenGLExtruded *>(oldNode); } - //TODO: update only material - if (m_geometry.isScreenDirty() || !oldNode) { - node->update(color(), &m_geometry); - m_geometry.setPreserveGeometry(false); - m_geometry.markClean(); + const QMatrix4x4 &combinedMatrix = m_map->geoProjection().qsgTransform(); + const QDoubleVector3D &cameraCenter = m_map->geoProjection().centerMercator(); + + if (m_borderGeometry.isScreenDirty()) { + /* Do the border update first */ + m_polylinenode->update(color(), + float(width()), + &m_borderGeometry, + combinedMatrix, + cameraCenter, + Qt::SquareCap, + true); + m_borderGeometry.setPreserveGeometry(false); + m_borderGeometry.markClean(); } - if (m_geometry.size()) { - root->appendChildNode(node); + if (!m_polylinenode->isSubtreeBlocked() ) { + m_polylinenode->setSubtreeBlocked(false); + root->appendChildNode(m_polylinenode); + return m_polylinenode; } else { - delete node; + delete m_polylinenode; + m_polylinenode = nullptr; + *visibleNode = nullptr; return nullptr; } - return node; } QList<QGeoCoordinate> QMapPolylineObjectPrivateQSG::path() const { - return m_geoPath.path(); + return m_path.path(); } void QMapPolylineObjectPrivateQSG::setPath(const QList<QGeoCoordinate> &path) { - m_path = path; - m_geoPath.setPath(path); + m_path.setPath(path); + markSourceDirty(); updateGeometry(); if (m_map) emit m_map->sgNodeChanged(); @@ -147,7 +161,6 @@ void QMapPolylineObjectPrivateQSG::setPath(const QList<QGeoCoordinate> &path) void QMapPolylineObjectPrivateQSG::setColor(const QColor &color) { QMapPolylineObjectPrivateDefault::setColor(color); - updateGeometry(); if (m_map) emit m_map->sgNodeChanged(); @@ -156,7 +169,6 @@ void QMapPolylineObjectPrivateQSG::setColor(const QColor &color) void QMapPolylineObjectPrivateQSG::setWidth(qreal width) { QMapPolylineObjectPrivateDefault::setWidth(width); - updateGeometry(); if (m_map) emit m_map->sgNodeChanged(); @@ -169,7 +181,12 @@ QGeoMapObjectPrivate *QMapPolylineObjectPrivateQSG::clone() QGeoShape QMapPolylineObjectPrivateQSG::geoShape() const { - return m_geoPath; + return m_path; +} + +void QMapPolylineObjectPrivateQSG::markSourceDirty() +{ + m_borderGeometry.markSourceDirty(); } QT_END_NAMESPACE diff --git a/src/location/labs/qsg/qmappolylineobjectqsg_p_p.h b/src/location/labs/qsg/qmappolylineobjectqsg_p_p.h index e8eb5839..63ebcde9 100644 --- a/src/location/labs/qsg/qmappolylineobjectqsg_p_p.h +++ b/src/location/labs/qsg/qmappolylineobjectqsg_p_p.h @@ -68,6 +68,7 @@ public: QList<QDoubleVector2D> projectPath(); // QQSGMapObject + void markSourceDirty(); void updateGeometry() override; QSGNode *updateMapObjectNode(QSGNode *oldNode, VisibleNode **visibleNode, @@ -85,9 +86,9 @@ public: virtual QGeoShape geoShape() const override; // Data Members - QGeoPathEager m_geoPath; - QGeoMapPolylineGeometry m_geometry; - bool m_updatingGeometry = false; + QDoubleVector2D m_leftBoundMercator; + QGeoMapPolylineGeometryOpenGL m_borderGeometry; + MapPolylineNodeOpenGLExtruded *m_polylinenode = nullptr; }; QT_END_NAMESPACE |