diff options
Diffstat (limited to 'src/location/declarativemaps/qdeclarativepolylinemapitem_p_p.h')
-rw-r--r-- | src/location/declarativemaps/qdeclarativepolylinemapitem_p_p.h | 890 |
1 files changed, 890 insertions, 0 deletions
diff --git a/src/location/declarativemaps/qdeclarativepolylinemapitem_p_p.h b/src/location/declarativemaps/qdeclarativepolylinemapitem_p_p.h new file mode 100644 index 00000000..2a588222 --- /dev/null +++ b/src/location/declarativemaps/qdeclarativepolylinemapitem_p_p.h @@ -0,0 +1,890 @@ +/**************************************************************************** +** +** 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 QDECLARATIVEPOLYLINEMAPITEM_P_P_H +#define QDECLARATIVEPOLYLINEMAPITEM_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/qdeclarativepolylinemapitem_p.h> +#include <QtLocation/private/qdeclarativegeomapitemutils_p.h> +#include <QtLocation/private/qdeclarativepolylinemapitem_p.h> +#include <QtLocation/private/qgeomapitemgeometry_p.h> +#include <QSGGeometryNode> +#include <QSGFlatColorMaterial> +#include <QtPositioning/QGeoPath> +#include <QtPositioning/QGeoPolygon> +#include <QtPositioning/QGeoRectangle> +#include <QtPositioning/QGeoCircle> +#include <QtPositioning/private/qdoublevector2d_p.h> +#include <QtCore/QScopedValueRollback> +#include <QSharedPointer> +#include <array> + +QT_BEGIN_NAMESPACE + +class Q_LOCATION_PRIVATE_EXPORT QGeoMapPolylineGeometry : public QGeoMapItemGeometry +{ +public: + QGeoMapPolylineGeometry(); + + void updateSourcePoints(const QGeoMap &map, + const QList<QDoubleVector2D> &path, + const QGeoCoordinate geoLeftBound); + + void updateScreenPoints(const QGeoMap &map, + qreal strokeWidth, + bool adjustTranslation = true); + + void clearSource(); + + bool contains(const QPointF &point) const override; + + QList<QList<QDoubleVector2D> > clipPath(const QGeoMap &map, + const QList<QDoubleVector2D> &path, + QDoubleVector2D &leftBoundWrapped); + + void pathToScreen(const QGeoMap &map, + const QList<QList<QDoubleVector2D> > &clippedPaths, + const QDoubleVector2D &leftBoundWrapped); + +public: + QVector<qreal> srcPoints_; + QVector<QPainterPath::ElementType> srcPointTypes_; + +#ifdef QT_LOCATION_DEBUG + QList<QDoubleVector2D> m_wrappedPath; + QList<QList<QDoubleVector2D>> m_clippedPaths; +#endif + + friend class QDeclarativeCircleMapItem; + friend class QDeclarativePolygonMapItem; + friend class QDeclarativeRectangleMapItem; +}; + +class Q_LOCATION_PRIVATE_EXPORT VisibleNode +{ +public: + VisibleNode(); + virtual ~VisibleNode(); + + bool subtreeBlocked() const; + void setSubtreeBlocked(bool blocked); + bool visible() const; + void setVisible(bool visible); + + bool m_blocked : 1; + bool m_visible : 1; +}; + +class Q_LOCATION_PRIVATE_EXPORT MapItemGeometryNode : public QSGGeometryNode, public VisibleNode +{ +public: + ~MapItemGeometryNode() override; + bool isSubtreeBlocked() const override; +}; + +class Q_LOCATION_PRIVATE_EXPORT MapPolylineMaterial : public QSGFlatColorMaterial +{ +public: + MapPolylineMaterial() + : QSGFlatColorMaterial() + { + // Passing RequiresFullMatrix is essential in order to prevent the + // batch renderer from baking in simple, translate-only transforms into + // the vertex data. The shader will rely on the fact that + // vertexCoord.xy is the Shape-space coordinate and so no modifications + // are welcome. + setFlag(Blending | RequiresFullMatrix | CustomCompileStep); + } + + QSGMaterialShader *createShader() const override; + + void setGeoProjection(const QMatrix4x4 &p) + { + m_geoProjection = p; + } + + QMatrix4x4 geoProjection() const + { + return m_geoProjection; + } + + void setCenter(const QDoubleVector3D &c) + { + m_center = c; + } + + QDoubleVector3D center() const + { + return m_center; + } + + void setColor(const QColor &color) + { + QSGFlatColorMaterial::setColor(color); + setFlag(Blending, true); // ToDo: Needed only temporarily, can be removed after debugging + } + + int wrapOffset() const + { + return m_wrapOffset; + } + + void setWrapOffset(int wrapOffset) + { + m_wrapOffset = wrapOffset; + } + + void setLineWidth(const float lw) + { + m_lineWidth = lw; + } + + float lineWidth() const + { + return m_lineWidth; + } + + QSGMaterialType *type() const override; + int compare(const QSGMaterial *other) const override; + +protected: + QMatrix4x4 m_geoProjection; + QDoubleVector3D m_center; + int m_wrapOffset = 0; + float m_lineWidth = 1.0; +}; + +class Q_LOCATION_PRIVATE_EXPORT MapPolylineNode : public MapItemGeometryNode +{ +public: + MapPolylineNode(); + ~MapPolylineNode() override; + + void update(const QColor &fillColor, const QGeoMapItemGeometry *shape); + +protected: + QSGFlatColorMaterial fill_material_; + QSGGeometry geometry_; +}; + +class Q_LOCATION_PRIVATE_EXPORT QGeoMapItemLODGeometry +{ +public: + mutable std::array<QSharedPointer<QVector<QDeclarativeGeoMapItemUtils::vec2>>, 7> m_verticesLOD; // fix it to 7, + // do not allow simplifications beyond ZL 20. This could actually be limited even further + mutable QVector<QDeclarativeGeoMapItemUtils::vec2> *m_screenVertices; + mutable QSharedPointer<unsigned int> m_working; + + QGeoMapItemLODGeometry() + { + resetLOD(); + } + + void resetLOD() + { + // New pointer, some old LOD task might still be running and operating on the old pointers. + m_verticesLOD[0] = QSharedPointer<QVector<QDeclarativeGeoMapItemUtils::vec2>>( + new QVector<QDeclarativeGeoMapItemUtils::vec2>); + for (unsigned int i = 1; i < m_verticesLOD.size(); ++i) + m_verticesLOD[i] = nullptr; // allocate on first use + m_screenVertices = m_verticesLOD.front().data(); // resetting pointer to data to be LOD 0 + } + + static unsigned int zoomToLOD(unsigned int zoom); + + static unsigned int zoomForLOD(unsigned int zoom); + + bool isLODActive(unsigned int lod) const; + + void selectLOD(unsigned int zoom, double leftBound, bool /*closed*/); + + static QVector<QDeclarativeGeoMapItemUtils::vec2> getSimplified ( + QVector<QDeclarativeGeoMapItemUtils::vec2> &wrappedPath, + double leftBoundWrapped, + unsigned int zoom); + + static void enqueueSimplificationTask(const QSharedPointer<QVector<QDeclarativeGeoMapItemUtils::vec2> > &input, // reference as it gets copied in the nested call + const QSharedPointer<QVector<QDeclarativeGeoMapItemUtils::vec2> > &output, + double leftBound, + unsigned int zoom, + QSharedPointer<unsigned int> &working); + + void selectLODOnDataChanged(unsigned int zoom, double leftBound) const; + + bool selectLODOnLODMismatch(unsigned int zoom, double leftBound, bool closed) const + { + if (*m_working > 0) { + return false; + } + const_cast<QGeoMapItemLODGeometry *>(this)->selectLOD(zoom, + leftBound, + closed); + return true; + } +}; + +class Q_LOCATION_PRIVATE_EXPORT QGeoMapPolylineGeometryOpenGL : public QGeoMapItemGeometry, public QGeoMapItemLODGeometry +{ +public: + typedef struct { + QList<QDoubleVector2D> wrappedBboxes; + } WrappedPolyline; + + QGeoMapPolylineGeometryOpenGL() + { + m_working = QSharedPointer<unsigned int>(new unsigned int(0)); + } + + void updateSourcePoints(const QGeoMap &map, + const QGeoPolygon &poly); + + void updateSourcePoints(const QGeoMap &map, + const QGeoPath &poly); + + void updateSourcePoints(const QGeoProjectionWebMercator &p, + const QList<QDoubleVector2D> &wrappedPath, + const QGeoRectangle &boundingRectangle); + + void updateSourcePoints(const QGeoMap &map, + const QGeoRectangle &rect); + + void updateSourcePoints(const QGeoMap &map, + const QGeoCircle &circle); + + void updateScreenPoints(const QGeoMap &map, + qreal strokeWidth, + bool adjustTranslation = true); + + void updateQuickGeometry(const QGeoProjectionWebMercator &p, qreal strokeWidth = 0.0); + + bool allocateAndFillEntries(QSGGeometry *geom, + bool closed = false, + unsigned int zoom = 0) const; + void allocateAndFillLineStrip(QSGGeometry *geom, + int lod = 0) const; + + bool contains(const QPointF &point) const override + { + Q_UNUSED(point) + return false; + } + + static double distanceTo(const QDoubleVector2D &a, const QDoubleVector2D &b, const QDoubleVector2D &p) + { + double u = ((p.x() - a.x()) * (b.x() - a.x()) + (p.y() - a.y()) * (b.y() - a.y()) ) / (b - a).lengthSquared(); + QDoubleVector2D intersection(a.x() + u * (b.x() - a.x()) , a.y() + u * (b.y() - a.y()) ); + + QDoubleVector2D candidate = ( (p-a).length() < (p-b).length() ) ? a : b; + + if (u > 0 && u < 1 + && (p-intersection).length() < (p-candidate).length() ) // And it falls in the segment + candidate = intersection; + + return qAbs((candidate - p).length()); + } + // Note: this is also slightly incorrect on joins and in the beginning/end of the line + bool contains(const QPointF &point, qreal lineWidth, const QGeoProjectionWebMercator &p) const + { + const double lineHalfWidth = lineWidth * 0.5; + const QDoubleVector2D pt(point); + QDoubleVector2D a; + if (m_screenVertices->size()) + a = p.wrappedMapProjectionToItemPosition(p.wrapMapProjection(m_screenVertices->first().toDoubleVector2D())); + QDoubleVector2D b; + for (int i = 1; i < m_screenVertices->size(); ++i) + { + if (!a.isFinite()) { + a = p.wrappedMapProjectionToItemPosition(p.wrapMapProjection(m_screenVertices->at(i).toDoubleVector2D())); + continue; + } + + b = p.wrappedMapProjectionToItemPosition(p.wrapMapProjection(m_screenVertices->at(i).toDoubleVector2D())); + if (!b.isFinite()) { + a = b; + continue; + } + + if (b == a) + continue; + + // Heavily simplifying it here: if a point is not projectable, skip the segment. + // For a correct solution, the segment should be clipped instead. + if (distanceTo(a, b, pt) <= lineHalfWidth) + return true; + + a = b; + } + return false; + } + +public: + QDoubleVector2D m_bboxLeftBoundWrapped; + QVector<WrappedPolyline> m_wrappedPolygons; + int m_wrapOffset; + + friend class QDeclarativeCircleMapItem; + friend class QDeclarativePolygonMapItem; + friend class QDeclarativeRectangleMapItem; +}; + +class Q_LOCATION_PRIVATE_EXPORT MapPolylineShaderLineStrip : public QSGMaterialShader +{ +public: + MapPolylineShaderLineStrip(); + + const char *vertexShader() const override { + return + "attribute highp vec4 vertex; \n" + "uniform highp mat4 qt_Matrix; \n" + "uniform highp mat4 mapProjection; \n" + "uniform highp vec3 center; \n" + "uniform highp vec3 center_lowpart; \n" + "uniform lowp float wrapOffset; \n" + "vec4 wrapped(in vec4 v) { return vec4(v.x + wrapOffset, v.y, 0.0, 1.0); }\n" + "void main() { \n" + " vec4 vtx = wrapped(vertex) - vec4(center, 0.0); \n" + " vtx = vtx - vec4(center_lowpart, 0.0); \n" + " gl_Position = qt_Matrix * mapProjection * vtx; \n" + "}"; + } + + const char *fragmentShader() const { + return + "uniform lowp vec4 color; \n" + "void main() { \n" + " gl_FragColor = color; \n" + "}"; + } + + void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; + char const *const *attributeNames() const override; + +protected: + void initialize() override + { + m_matrix_id = program()->uniformLocation("qt_Matrix"); + m_color_id = program()->uniformLocation("color"); + m_mapProjection_id = program()->uniformLocation("mapProjection"); + m_center_id = program()->uniformLocation("center"); + m_center_lowpart_id = program()->uniformLocation("center_lowpart"); + m_wrapOffset_id = program()->uniformLocation("wrapOffset"); + } + int m_center_id; + int m_center_lowpart_id; + int m_mapProjection_id; + int m_matrix_id; + int m_color_id; + int m_wrapOffset_id; +}; + +class Q_LOCATION_PRIVATE_EXPORT MapPolylineShaderExtruded : public QSGMaterialShader +{ +public: + MapPolylineShaderExtruded(); + + // Heavily adapted from https://github.com/mattdesl/webgl-lines/blob/master/projected/vert.glsl, + // that is (c) Matt DesLauriers, and released under the MIT license. + const char *vertexShaderMiteredSegments() const; + + const char *vertexShader() const override + { + return vertexShaderMiteredSegments(); + } + + const char *fragmentShader() const override + { + return + "varying vec4 primitivecolor; \n" + "void main() { \n" + " gl_FragColor = primitivecolor; \n" + "}"; + } + + void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; + char const *const *attributeNames() const override; + +protected: + void initialize() override + { + m_matrix_id = program()->uniformLocation("qt_Matrix"); + m_color_id = program()->uniformLocation("color"); + m_mapProjection_id = program()->uniformLocation("mapProjection"); + m_center_id = program()->uniformLocation("center"); + m_center_lowpart_id = program()->uniformLocation("center_lowpart"); + m_lineWidth_id = program()->uniformLocation("lineWidth"); + m_aspect_id = program()->uniformLocation("aspect"); + m_miter_id = program()->uniformLocation("miter"); + m_wrapOffset_id = program()->uniformLocation("wrapOffset"); + } + int m_center_id; + int m_center_lowpart_id; + int m_mapProjection_id; + int m_matrix_id; + int m_color_id; + int m_lineWidth_id; + int m_aspect_id; + int m_miter_id; + int m_wrapOffset_id; +}; + +class Q_LOCATION_PRIVATE_EXPORT MapPolylineNodeOpenGLLineStrip : public MapItemGeometryNode +{ +public: + MapPolylineNodeOpenGLLineStrip(); + ~MapPolylineNodeOpenGLLineStrip() override; + + void update(const QColor &fillColor, + const qreal lineWidth, + const QGeoMapPolylineGeometryOpenGL *shape, + const QMatrix4x4 &geoProjection, + const QDoubleVector3D ¢er, + const Qt::PenCapStyle capStyle = Qt::SquareCap); + +protected: + MapPolylineMaterial fill_material_; + QSGGeometry geometry_; +}; + +class Q_LOCATION_PRIVATE_EXPORT MapPolylineMaterialExtruded : public MapPolylineMaterial +{ +public: + MapPolylineMaterialExtruded() : MapPolylineMaterial() + { + + } + QSGMaterialShader *createShader() const override; + + void setMiter(const int m) + { + m_miter = m; + } + + int miter() const + { + return m_miter; + } + + QSGMaterialType *type() const override; + int compare(const QSGMaterial *other) const override; + + int m_miter = 0; +}; + +class Q_LOCATION_PRIVATE_EXPORT MapPolylineNodeOpenGLExtruded : public MapItemGeometryNode +{ +public: + + typedef struct { + QDeclarativeGeoMapItemUtils::vec2 pos; + QDeclarativeGeoMapItemUtils::vec2 prev; + QDeclarativeGeoMapItemUtils::vec2 next; + float direction; + float triangletype; // es2 does not support int attribs + float vertextype; + + static const char * const *attributeNames() + { + static char const *const attr[] = { "vertex", "previous", "next", "direction", "triangletype", "vertextype", nullptr }; + return attr; + } + static const QSGGeometry::AttributeSet &attributes() + { + static const QSGGeometry::Attribute dataTri[] = { + QSGGeometry::Attribute::createWithAttributeType(0, 2, QSGGeometry::FloatType, QSGGeometry::PositionAttribute) // pos + ,QSGGeometry::Attribute::createWithAttributeType(1, 2, QSGGeometry::FloatType, QSGGeometry::UnknownAttribute) // next + ,QSGGeometry::Attribute::createWithAttributeType(2, 2, QSGGeometry::FloatType, QSGGeometry::UnknownAttribute) // previous + ,QSGGeometry::Attribute::createWithAttributeType(3, 1, QSGGeometry::FloatType, QSGGeometry::UnknownAttribute) // direction + ,QSGGeometry::Attribute::createWithAttributeType(4, 1, QSGGeometry::FloatType, QSGGeometry::UnknownAttribute) // triangletype + ,QSGGeometry::Attribute::createWithAttributeType(5, 1, QSGGeometry::FloatType, QSGGeometry::UnknownAttribute) // vertextype + }; + static const QSGGeometry::AttributeSet attrsTri = { 6, sizeof(MapPolylineNodeOpenGLExtruded::MapPolylineEntry), dataTri }; + return attrsTri; + } + } MapPolylineEntry; + + MapPolylineNodeOpenGLExtruded(); + ~MapPolylineNodeOpenGLExtruded() override; + + void update(const QColor &fillColor, + const float lineWidth, + const QGeoMapPolylineGeometryOpenGL *shape, + const QMatrix4x4 geoProjection, + const QDoubleVector3D center, + const Qt::PenCapStyle capStyle = Qt::FlatCap, + bool closed = false, + unsigned int zoom = 30); + + static const QSGGeometry::AttributeSet &attributesMapPolylineTriangulated(); + +protected: + MapPolylineMaterialExtruded fill_material_; + QSGGeometry m_geometryTriangulating; +}; + +class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolylineMapItemPrivate +{ +public: + QDeclarativePolylineMapItemPrivate(QDeclarativePolylineMapItem &poly) : m_poly(poly) + { + + } + QDeclarativePolylineMapItemPrivate(QDeclarativePolylineMapItemPrivate &other) : m_poly(other.m_poly) + { + } + + virtual ~QDeclarativePolylineMapItemPrivate(); + virtual void markSourceDirtyAndUpdate() = 0; + virtual void onMapSet() = 0; + virtual void onLinePropertiesChanged() = 0; + virtual void onGeoGeometryChanged() = 0; + virtual void onGeoGeometryUpdated() = 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; + + QDeclarativePolylineMapItem &m_poly; + Qt::PenStyle m_penStyle = Qt::SolidLine; + Qt::PenCapStyle m_penCapStyle = Qt::SquareCap; +}; + +class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolylineMapItemPrivateCPU: public QDeclarativePolylineMapItemPrivate +{ +public: + QDeclarativePolylineMapItemPrivateCPU(QDeclarativePolylineMapItem &poly) : QDeclarativePolylineMapItemPrivate(poly) + { + } + + QDeclarativePolylineMapItemPrivateCPU(QDeclarativePolylineMapItemPrivate &other) + : QDeclarativePolylineMapItemPrivate(other) + { + } + + ~QDeclarativePolylineMapItemPrivateCPU() override; + void onLinePropertiesChanged() override + { + // mark dirty just in case we're a width change + markSourceDirtyAndUpdate(); + } + void markSourceDirtyAndUpdate() override + { + m_geometry.markSourceDirty(); + m_poly.polishAndUpdate(); + } + void regenerateCache() + { + if (!m_poly.map() || m_poly.map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator) + return; + const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_poly.map()->geoProjection()); + m_geopathProjected.clear(); + m_geopathProjected.reserve(m_poly.m_geopath.size()); + for (const QGeoCoordinate &c : m_poly.m_geopath.path()) + m_geopathProjected << p.geoToMapProjection(c); + } + void updateCache() + { + if (!m_poly.map() || m_poly.map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator) + return; + const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_poly.map()->geoProjection()); + m_geopathProjected << p.geoToMapProjection(m_poly.m_geopath.path().last()); + } + void preserveGeometry() + { + m_geometry.setPreserveGeometry(true, m_poly.m_geopath.boundingGeoRectangle().topLeft()); + } + void afterViewportChanged() override + { + // preserveGeometry is cleared in updateMapItemPaintNode + preserveGeometry(); + markSourceDirtyAndUpdate(); + } + void onMapSet() override + { + regenerateCache(); + markSourceDirtyAndUpdate(); + } + void onGeoGeometryChanged() override + { + regenerateCache(); + preserveGeometry(); + markSourceDirtyAndUpdate(); + } + void onGeoGeometryUpdated() override + { + updateCache(); + preserveGeometry(); + markSourceDirtyAndUpdate(); + } + void onItemGeometryChanged() override + { + onGeoGeometryChanged(); + } + void updatePolish() override + { + if (m_poly.m_geopath.path().length() < 2) { // Possibly cleared + m_geometry.clear(); + m_poly.setWidth(0); + m_poly.setHeight(0); + return; + } + QScopedValueRollback<bool> rollback(m_poly.m_updatingGeometry); + m_poly.m_updatingGeometry = true; + + 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()); + m_geometry.updateScreenPoints(*map, borderWidth); + + m_poly.setWidth(m_geometry.sourceBoundingBox().width() + borderWidth); + m_poly.setHeight(m_geometry.sourceBoundingBox().height() + borderWidth); + + m_poly.setPositionOnMap(m_geometry.origin(), -1 * m_geometry.sourceBoundingBox().topLeft() + + QPointF(borderWidth, borderWidth) * 0.5 ); // it has to be shifted so that the center of the line is on the correct geocoord + } + QSGNode *updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData * /*data*/) override + { + if (!m_node || !oldNode) { + m_node = new MapPolylineNode(); + if (oldNode) { + delete oldNode; + oldNode = nullptr; + } + } else { + m_node = static_cast<MapPolylineNode *>(oldNode); + } + + //TODO: update only material + if (m_geometry.isScreenDirty() || m_poly.m_dirtyMaterial || !oldNode) { + m_node->update(m_poly.m_line.color(), &m_geometry); + m_geometry.setPreserveGeometry(false); + m_geometry.markClean(); + m_poly.m_dirtyMaterial = false; + } + return m_node; + } + bool contains(const QPointF &point) const override + { + return m_geometry.contains(point); + } + + QList<QDoubleVector2D> m_geopathProjected; + QGeoMapPolylineGeometry m_geometry; + MapPolylineNode *m_node = nullptr; +}; + +class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolylineMapItemPrivateOpenGLLineStrip: public QDeclarativePolylineMapItemPrivate +{ +public: + + QDeclarativePolylineMapItemPrivateOpenGLLineStrip(QDeclarativePolylineMapItem &poly) : QDeclarativePolylineMapItemPrivate(poly) + { + } + + QDeclarativePolylineMapItemPrivateOpenGLLineStrip(QDeclarativePolylineMapItemPrivate &other) + : QDeclarativePolylineMapItemPrivate(other) + { + } + + ~QDeclarativePolylineMapItemPrivateOpenGLLineStrip() override; + void onLinePropertiesChanged() override + { + afterViewportChanged(); + } + void markSourceDirtyAndUpdate() override + { + m_geometry.markSourceDirty(); + m_poly.polishAndUpdate(); + } + void preserveGeometry() + { + m_geometry.setPreserveGeometry(true, m_poly.m_geopath.boundingGeoRectangle().topLeft()); + } + void onMapSet() override + { + markSourceDirtyAndUpdate(); + } + void onGeoGeometryChanged() override + { + preserveGeometry(); + markSourceDirtyAndUpdate(); + } + void onGeoGeometryUpdated() override + { + preserveGeometry(); + markSourceDirtyAndUpdate(); + } + void onItemGeometryChanged() override + { + onGeoGeometryChanged(); + } + void afterViewportChanged() override + { + preserveGeometry(); + m_poly.polishAndUpdate(); + } + bool contains(const QPointF &point) const override + { + return m_geometry.contains(m_poly.mapToItem(m_poly.quickMap(), point), + m_poly.line()->width(), + static_cast<const QGeoProjectionWebMercator&>(m_poly.map()->geoProjection())); + } + void updatePolish() override + { + if (m_poly.m_geopath.path().length() == 0) { // Possibly cleared + m_geometry.clear(); + m_geometry.clear(); + m_poly.setWidth(0); + m_poly.setHeight(0); + return; + } + + QScopedValueRollback<bool> rollback(m_poly.m_updatingGeometry); + m_poly.m_updatingGeometry = true; + const qreal lineWidth = m_poly.m_line.width(); + m_geometry.updateSourcePoints(*m_poly.map(), m_poly.m_geopath); + m_geometry.markScreenDirty(); + m_geometry.updateScreenPoints(*m_poly.map(), lineWidth); + + m_poly.setWidth(m_geometry.sourceBoundingBox().width()); + m_poly.setHeight(m_geometry.sourceBoundingBox().height()); + m_poly.setPosition(1.0 * m_geometry.firstPointOffset() - QPointF(lineWidth * 0.5,lineWidth * 0.5)); + } + QSGNode * updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) override + { + Q_UNUSED(data); + + if (!m_node || !oldNode) { + m_node = new MapPolylineNodeOpenGLLineStrip(); + if (oldNode) + delete oldNode; + } else { + m_node = static_cast<MapPolylineNodeOpenGLLineStrip *>(oldNode); + } + + if (m_geometry.isScreenDirty() || m_poly.m_dirtyMaterial) { + const QGeoMap *map = m_poly.map(); + const QMatrix4x4 &combinedMatrix = map->geoProjection().qsgTransform(); + const QDoubleVector3D &cameraCenter = map->geoProjection().centerMercator(); + m_node->update(m_poly.m_line.color(), // This updates only the material if the geometry is unchanged + m_poly.m_line.width(), + &m_geometry, + combinedMatrix, + cameraCenter); + m_geometry.setPreserveGeometry(false); + m_geometry.markClean(); + m_poly.m_dirtyMaterial = false; + } + return m_node; + } + + QGeoMapPolylineGeometryOpenGL m_geometry; + MapPolylineNodeOpenGLLineStrip *m_node = nullptr; +}; + +class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolylineMapItemPrivateOpenGLExtruded: public QDeclarativePolylineMapItemPrivateOpenGLLineStrip +{ +public: + + QDeclarativePolylineMapItemPrivateOpenGLExtruded(QDeclarativePolylineMapItem &poly) + : QDeclarativePolylineMapItemPrivateOpenGLLineStrip(poly) + { + } + + QDeclarativePolylineMapItemPrivateOpenGLExtruded(QDeclarativePolylineMapItemPrivate &other) + : QDeclarativePolylineMapItemPrivateOpenGLLineStrip(other) + { + } + + ~QDeclarativePolylineMapItemPrivateOpenGLExtruded() override; + + QSGNode * updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) override + { + Q_UNUSED(data); + const QGeoMap *map = m_poly.map(); + const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map->geoProjection()); + const QMatrix4x4 &combinedMatrix = p.qsgTransform(); + const QDoubleVector3D &cameraCenter = p.centerMercator(); + const QColor &color = m_poly.m_line.color(); + const float lineWidth = m_poly.m_line.width(); + + MapPolylineNodeOpenGLExtruded *nodeTri = nullptr; + if (!m_nodeTri || !oldNode) { + if (oldNode) + delete oldNode; + nodeTri = new MapPolylineNodeOpenGLExtruded(); + } else { + nodeTri = static_cast<MapPolylineNodeOpenGLExtruded *>(oldNode); + } + + //TODO: update only material + if (m_geometry.isScreenDirty() || m_poly.m_dirtyMaterial) { + nodeTri->update(color, + lineWidth , + &m_geometry, + combinedMatrix, + cameraCenter, + m_penCapStyle, + false, + m_poly.zoomForLOD(int(map->cameraData().zoomLevel()))); + m_geometry.setPreserveGeometry(false); + m_geometry.markClean(); + m_poly.m_dirtyMaterial = false; + } + m_nodeTri = nodeTri; + return nodeTri; + } + + MapPolylineNodeOpenGLExtruded *m_nodeTri = nullptr; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVEPOLYLINEMAPITEM_P_P_H |