diff options
Diffstat (limited to 'src/location/declarativemaps/qdeclarativerectanglemapitem_p_p.h')
-rw-r--r-- | src/location/declarativemaps/qdeclarativerectanglemapitem_p_p.h | 416 |
1 files changed, 416 insertions, 0 deletions
diff --git a/src/location/declarativemaps/qdeclarativerectanglemapitem_p_p.h b/src/location/declarativemaps/qdeclarativerectanglemapitem_p_p.h new file mode 100644 index 00000000..520abdf3 --- /dev/null +++ b/src/location/declarativemaps/qdeclarativerectanglemapitem_p_p.h @@ -0,0 +1,416 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Paolo Angelelli <paolo.angelelli@gmail.com> +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtLocation module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVERECTANGLEMAPITEM_P_P_H +#define QDECLARATIVERECTANGLEMAPITEM_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtLocation/private/qlocationglobal_p.h> +#include <QtLocation/private/qdeclarativepolygonmapitem_p_p.h> +#include <QtLocation/private/qdeclarativerectanglemapitem_p.h> +#include <QtPositioning/private/qwebmercator_p.h> + +QT_BEGIN_NAMESPACE + +class Q_LOCATION_PRIVATE_EXPORT QDeclarativeRectangleMapItemPrivate +{ +public: + QDeclarativeRectangleMapItemPrivate(QDeclarativeRectangleMapItem &rect) : m_rect(rect) + { + + } + QDeclarativeRectangleMapItemPrivate(QDeclarativeRectangleMapItemPrivate &other) : m_rect(other.m_rect) + { + } + + virtual ~QDeclarativeRectangleMapItemPrivate(); + virtual void onLinePropertiesChanged() = 0; + virtual void markSourceDirtyAndUpdate() = 0; + virtual void onMapSet() = 0; + virtual void onGeoGeometryChanged() = 0; + virtual void onItemGeometryChanged() = 0; + virtual void updatePolish() = 0; + virtual void afterViewportChanged() = 0; + virtual QSGNode * updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) = 0; + virtual bool contains(const QPointF &point) const = 0; + + QDeclarativeRectangleMapItem &m_rect; +}; + +class Q_LOCATION_PRIVATE_EXPORT QDeclarativeRectangleMapItemPrivateCPU: public QDeclarativeRectangleMapItemPrivate +{ +public: + QDeclarativeRectangleMapItemPrivateCPU(QDeclarativeRectangleMapItem &rect) : QDeclarativeRectangleMapItemPrivate(rect) + { + } + + QDeclarativeRectangleMapItemPrivateCPU(QDeclarativeRectangleMapItemPrivate &other) + : QDeclarativeRectangleMapItemPrivate(other) + { + } + + ~QDeclarativeRectangleMapItemPrivateCPU() override; + + void onLinePropertiesChanged() override + { + // mark dirty just in case we're a width change + markSourceDirtyAndUpdate(); + } + virtual void markSourceDirtyAndUpdate() override + { + m_geometry.markSourceDirty(); + m_borderGeometry.markSourceDirty(); + m_rect.polishAndUpdate(); + } + virtual void onMapSet() override + { + markSourceDirtyAndUpdate(); + } + virtual void onGeoGeometryChanged() override + { + markSourceDirtyAndUpdate(); + } + virtual void onItemGeometryChanged() override + { + m_geometry.setPreserveGeometry(true, m_rect.m_rectangle.topLeft()); + m_borderGeometry.setPreserveGeometry(true, m_rect.m_rectangle.topLeft()); + markSourceDirtyAndUpdate(); + } + virtual void afterViewportChanged() override + { + m_geometry.setPreserveGeometry(true, m_rect.m_rectangle.topLeft()); + m_borderGeometry.setPreserveGeometry(true, m_rect.m_rectangle.topLeft()); + markSourceDirtyAndUpdate(); + } + virtual void updatePolish() override + { + if (!m_rect.topLeft().isValid() || !m_rect.bottomRight().isValid()) { + m_geometry.clear(); + m_borderGeometry.clear(); + m_rect.setWidth(0); + m_rect.setHeight(0); + return; + } + + const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_rect.map()->geoProjection()); + + QScopedValueRollback<bool> rollback(m_rect.m_updatingGeometry); + m_rect.m_updatingGeometry = true; + + const QList<QGeoCoordinate> perimeter = path(m_rect.m_rectangle); + const QList<QDoubleVector2D> pathMercator_ = pathMercator(perimeter); + m_geometry.setPreserveGeometry(true, m_rect.m_rectangle.topLeft()); + m_geometry.updateSourcePoints(*m_rect.map(), pathMercator_); + m_geometry.updateScreenPoints(*m_rect.map(), m_rect.m_border.width()); + + QList<QGeoMapItemGeometry *> geoms; + geoms << &m_geometry; + m_borderGeometry.clear(); + + if (m_rect.m_border.color().alpha() != 0 && m_rect.m_border.width() > 0) { + QList<QDoubleVector2D> closedPath = pathMercator_; + closedPath << closedPath.first(); + + m_borderGeometry.setPreserveGeometry(true, m_rect.m_rectangle.topLeft()); + const QGeoCoordinate &geometryOrigin = m_geometry.origin(); + + m_borderGeometry.srcPoints_.clear(); + m_borderGeometry.srcPointTypes_.clear(); + + QDoubleVector2D borderLeftBoundWrapped; + QList<QList<QDoubleVector2D > > clippedPaths = m_borderGeometry.clipPath(*m_rect.map(), closedPath, borderLeftBoundWrapped); + if (clippedPaths.size()) { + borderLeftBoundWrapped = p.geoToWrappedMapProjection(geometryOrigin); + m_borderGeometry.pathToScreen(*m_rect.map(), clippedPaths, borderLeftBoundWrapped); + m_borderGeometry.updateScreenPoints(*m_rect.map(), m_rect.m_border.width()); + + geoms << &m_borderGeometry; + } else { + m_borderGeometry.clear(); + } + } + + QRectF combined = QGeoMapItemGeometry::translateToCommonOrigin(geoms); + m_rect.setWidth(combined.width() + 2 * m_rect.m_border.width()); // ToDo: fix this! 2 is incorrect + m_rect.setHeight(combined.height() + 2 * m_rect.m_border.width()); + + m_rect.setPositionOnMap(m_geometry.origin(), m_geometry.firstPointOffset()); + } + + virtual QSGNode * updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) override + { + Q_UNUSED(data); + if (!m_node || !oldNode) { + m_node = new MapPolygonNode(); + if (oldNode) { + delete oldNode; + oldNode = nullptr; + } + } else { + m_node = static_cast<MapPolygonNode *>(oldNode); + } + + //TODO: update only material + if (m_geometry.isScreenDirty() || m_borderGeometry.isScreenDirty() || m_rect.m_dirtyMaterial) { + m_node->update(m_rect.m_color, m_rect.m_border.color(), &m_geometry, &m_borderGeometry); + m_geometry.setPreserveGeometry(false); + m_borderGeometry.setPreserveGeometry(false); + m_geometry.markClean(); + m_borderGeometry.markClean(); + m_rect.m_dirtyMaterial = false; + } + return m_node; + } + virtual bool contains(const QPointF &point) const override + { + return (m_geometry.contains(point) || m_borderGeometry.contains(point)); + } + + static QList<QGeoCoordinate> path(const QGeoRectangle &rect) + { + QList<QGeoCoordinate> res; + res << rect.topLeft(); + res << QGeoCoordinate(rect.topLeft().latitude(), rect.bottomRight().longitude()); + res << rect.bottomRight(); + res << QGeoCoordinate(rect.bottomRight().latitude(), rect.topLeft().longitude()); + return res; + } + + static QList<QGeoCoordinate> perimeter(const QGeoRectangle &rect) + { + QList<QGeoCoordinate> res; + res << rect.topLeft(); + res << QGeoCoordinate(rect.topLeft().latitude(), rect.bottomRight().longitude()); + res << rect.bottomRight(); + res << QGeoCoordinate(rect.bottomRight().latitude(), rect.topLeft().longitude()); + res << res.first(); + return res; + } + + static QList<QDoubleVector2D> pathMercator(const QList<QGeoCoordinate> &p) + { + QList<QDoubleVector2D> res; + for (const auto &c: p) + res << QWebMercator::coordToMercator(c); + return res; + } + + QGeoMapPolygonGeometry m_geometry; + QGeoMapPolylineGeometry m_borderGeometry; + MapPolygonNode *m_node = nullptr; +}; + +class Q_LOCATION_PRIVATE_EXPORT QDeclarativeRectangleMapItemPrivateOpenGL: public QDeclarativeRectangleMapItemPrivate +{ +public: + QDeclarativeRectangleMapItemPrivateOpenGL(QDeclarativeRectangleMapItem &rect) : QDeclarativeRectangleMapItemPrivate(rect) + { + } + + QDeclarativeRectangleMapItemPrivateOpenGL(QDeclarativeRectangleMapItemPrivate &other) + : QDeclarativeRectangleMapItemPrivate(other) + { + } + + ~QDeclarativeRectangleMapItemPrivateOpenGL() override; + + void markScreenDirtyAndUpdate() + { + // preserveGeometry is cleared in updateMapItemPaintNode + m_geometry.markScreenDirty(); + m_borderGeometry.markScreenDirty(); + m_rect.polishAndUpdate(); + } + void onLinePropertiesChanged() override + { + m_rect.m_dirtyMaterial = true; + afterViewportChanged(); + } + virtual void markSourceDirtyAndUpdate() override + { + m_geometry.markSourceDirty(); + m_borderGeometry.markSourceDirty(); + m_rect.polishAndUpdate(); + } + void preserveGeometry() + { + m_geometry.setPreserveGeometry(true, m_rect.m_rectangle.topLeft()); + m_borderGeometry.setPreserveGeometry(true, m_rect.m_rectangle.topLeft()); + } + virtual void onMapSet() override + { + markSourceDirtyAndUpdate(); + } + virtual void onGeoGeometryChanged() override + { + preserveGeometry(); + markSourceDirtyAndUpdate(); + } + virtual void onItemGeometryChanged() override + { + onGeoGeometryChanged(); + } + virtual void afterViewportChanged() override + { + preserveGeometry(); + markScreenDirtyAndUpdate(); + } + virtual void updatePolish() override + { + if (!m_rect.topLeft().isValid() || !m_rect.bottomRight().isValid()) { + m_geometry.clear(); + m_borderGeometry.clear(); + m_rect.setWidth(0); + m_rect.setHeight(0); + return; + } + + QScopedValueRollback<bool> rollback(m_rect.m_updatingGeometry); + m_rect.m_updatingGeometry = true; + const qreal lineWidth = m_rect.m_border.width(); + const QColor &lineColor = m_rect.m_border.color(); + const QColor &fillColor = m_rect.color(); + if (fillColor.alpha() != 0) { + m_geometry.updateSourcePoints(*m_rect.map(), m_rect.m_rectangle); + m_geometry.markScreenDirty(); + m_geometry.updateScreenPoints(*m_rect.map(), lineWidth, lineColor); + } else { + m_geometry.clearBounds(); + } + + QGeoMapItemGeometry * geom = &m_geometry; + m_borderGeometry.clearScreen(); + if (lineColor.alpha() != 0 && lineWidth > 0) { + m_borderGeometry.updateSourcePoints(*m_rect.map(), m_rect.m_rectangle); + m_borderGeometry.markScreenDirty(); + m_borderGeometry.updateScreenPoints(*m_rect.map(), lineWidth); + geom = &m_borderGeometry; + } + m_rect.setWidth(geom->sourceBoundingBox().width()); + m_rect.setHeight(geom->sourceBoundingBox().height()); + m_rect.setPosition(1.0 * geom->firstPointOffset() - QPointF(lineWidth * 0.5,lineWidth * 0.5)); + } + + virtual QSGNode * updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) override + { + Q_UNUSED(data); + + 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); + if (oldNode) + delete oldNode; + } else { + m_rootNode = static_cast<QDeclarativePolygonMapItemPrivateOpenGL::RootNode *>(oldNode); + } + + const QGeoMap *map = m_rect.map(); + const QMatrix4x4 &combinedMatrix = map->geoProjection().qsgTransform(); + const QDoubleVector3D &cameraCenter = map->geoProjection().centerMercator(); + + if (m_borderGeometry.isScreenDirty()) { + /* Do the border update first */ + m_polylinenode->update(m_rect.m_border.color(), + float(m_rect.m_border.width()), + &m_borderGeometry, + combinedMatrix, + cameraCenter, + Qt::SquareCap, + true); + m_borderGeometry.setPreserveGeometry(false); + m_borderGeometry.markClean(); + } else { + m_polylinenode->setSubtreeBlocked(true); + } + if (m_geometry.isScreenDirty()) { + m_node->update(m_rect.m_color, + &m_geometry, + combinedMatrix, + cameraCenter); + m_geometry.setPreserveGeometry(false); + m_geometry.markClean(); + } else { + m_node->setSubtreeBlocked(true); + } + + m_rootNode->setSubtreeBlocked(false); + return m_rootNode; + } + virtual bool contains(const QPointF &point) const override + { + const qreal lineWidth = m_rect.m_border.width(); + const QColor &lineColor = m_rect.m_border.color(); + const QRectF &bounds = (lineColor.alpha() != 0 && lineWidth > 0) ? m_borderGeometry.sourceBoundingBox() : m_geometry.sourceBoundingBox(); + if (bounds.contains(point)) { + QDeclarativeGeoMap *m = m_rect.quickMap(); + if (m) { + const QGeoCoordinate crd = m->toCoordinate(m->mapFromItem(&m_rect, point)); + return m_rect.m_rectangle.contains(crd) || m_borderGeometry.contains(m_rect.mapToItem(m_rect.quickMap(), point), + m_rect.border()->width(), + static_cast<const QGeoProjectionWebMercator&>(m_rect.map()->geoProjection())); + } else { + return true; + } + } + return false; + } + + QGeoMapPolygonGeometryOpenGL m_geometry; + QGeoMapPolylineGeometryOpenGL m_borderGeometry; + QDeclarativePolygonMapItemPrivateOpenGL::RootNode *m_rootNode = nullptr; + MapPolygonNodeGL *m_node = nullptr; + MapPolylineNodeOpenGLExtruded *m_polylinenode = nullptr; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVERECTANGLEMAPITEM_P_P_H + |