| /**************************************************************************** |
| ** |
| ** 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 QDECLARATIVEPOLYGONMAPITEM_P_P_H |
| #define QDECLARATIVEPOLYGONMAPITEM_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/qgeomapitemgeometry_p.h> |
| #include <QtLocation/private/qdeclarativegeomapitembase_p.h> |
| #include <QtLocation/private/qdeclarativepolylinemapitem_p.h> |
| #include <QtLocation/private/qdeclarativegeomapitemutils_p.h> |
| #include <QtLocation/private/qdeclarativepolygonmapitem_p.h> |
| #include <QtLocation/private/qdeclarativepolylinemapitem_p_p.h> |
| #include <QSGGeometryNode> |
| #include <QSGFlatColorMaterial> |
| #include <QtPositioning/QGeoPath> |
| #include <QtPositioning/QGeoRectangle> |
| #include <QtPositioning/QGeoPolygon> |
| #include <QtPositioning/private/qdoublevector2d_p.h> |
| #include <QSGFlatColorMaterial> |
| #include <QSGSimpleMaterial> |
| #include <QtGui/QMatrix4x4> |
| #include <QColor> |
| #include <QList> |
| #include <QVector> |
| #include <QtCore/QScopedValueRollback> |
| |
| QT_BEGIN_NAMESPACE |
| |
| class Q_LOCATION_PRIVATE_EXPORT QGeoMapPolygonGeometry : public QGeoMapItemGeometry |
| { |
| public: |
| QGeoMapPolygonGeometry(); |
| |
| inline void setAssumeSimple(bool value) { assumeSimple_ = value; } |
| |
| void updateSourcePoints(const QGeoMap &map, |
| const QList<QDoubleVector2D> &path); |
| |
| void updateScreenPoints(const QGeoMap &map, qreal strokeWidth = 0.0); |
| |
| protected: |
| QPainterPath srcPath_; |
| bool assumeSimple_; |
| }; |
| |
| class Q_LOCATION_PRIVATE_EXPORT QGeoMapPolygonGeometryOpenGL : public QGeoMapItemGeometry |
| { |
| public: |
| typedef struct { |
| QList<QDoubleVector2D> wrappedBboxes; |
| } WrappedPolygon; |
| QGeoMapPolygonGeometryOpenGL(); |
| ~QGeoMapPolygonGeometryOpenGL() override {} |
| |
| // Temporary method for compatibility in MapCircleObject. Remove when MapObjects are ported. |
| void updateSourcePoints(const QGeoMap &map, |
| const QList<QDoubleVector2D> &path); |
| |
| void updateSourcePoints(const QGeoMap &map, |
| const QList<QGeoCoordinate> &perimeter); |
| |
| void updateSourcePoints(const QGeoMap &map, |
| const QGeoPolygon &poly); |
| |
| void updateSourcePoints(const QGeoMap &map, |
| const QGeoRectangle &rect); |
| |
| void updateScreenPoints(const QGeoMap &map, qreal strokeWidth = 0.0, const QColor &strokeColor = Qt::transparent); |
| void updateQuickGeometry(const QGeoProjectionWebMercator &p, qreal strokeWidth = 0.0); |
| |
| void allocateAndFillPolygon(QSGGeometry *geom) const |
| { |
| |
| |
| const QVector<QDeclarativeGeoMapItemUtils::vec2> &vx = m_screenVertices; |
| const QVector<quint32> &ix = m_screenIndices; |
| |
| geom->allocate(vx.size(), ix.size()); |
| if (geom->indexType() == QSGGeometry::UnsignedShortType) { |
| quint16 *its = geom->indexDataAsUShort(); |
| for (int i = 0; i < ix.size(); ++i) |
| its[i] = ix[i]; |
| } else if (geom->indexType() == QSGGeometry::UnsignedIntType) { |
| quint32 *its = geom->indexDataAsUInt(); |
| for (int i = 0; i < ix.size(); ++i) |
| its[i] = ix[i]; |
| } |
| |
| QSGGeometry::Point2D *pts = geom->vertexDataAsPoint2D(); |
| for (int i = 0; i < vx.size(); ++i) |
| pts[i].set(vx[i].x, vx[i].y); |
| } |
| |
| QVector<QDeclarativeGeoMapItemUtils::vec2> m_screenVertices; |
| QVector<quint32> m_screenIndices; |
| QDoubleVector2D m_bboxLeftBoundWrapped; |
| QVector<WrappedPolygon> m_wrappedPolygons; |
| int m_wrapOffset; |
| }; |
| |
| class Q_LOCATION_PRIVATE_EXPORT MapPolygonShader : public QSGMaterialShader |
| { |
| public: |
| MapPolygonShader(); |
| |
| 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 override { |
| 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 |
| { |
| static char const *const attr[] = { "vertex", nullptr }; |
| return attr; |
| } |
| |
| private: |
| 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 MapPolygonMaterial : public QSGFlatColorMaterial |
| { |
| public: |
| MapPolygonMaterial() |
| : 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; |
| } |
| |
| int wrapOffset() const |
| { |
| return m_wrapOffset; |
| } |
| |
| void setWrapOffset(int wrapOffset) |
| { |
| m_wrapOffset = wrapOffset; |
| } |
| |
| int compare(const QSGMaterial *other) const override; |
| QSGMaterialType *type() const override; |
| |
| protected: |
| QMatrix4x4 m_geoProjection; |
| QDoubleVector3D m_center; |
| int m_wrapOffset = 0; |
| }; |
| |
| class Q_LOCATION_PRIVATE_EXPORT MapPolygonNode : public MapItemGeometryNode |
| { |
| |
| public: |
| MapPolygonNode(); |
| ~MapPolygonNode() override; |
| |
| void update(const QColor &fillColor, const QColor &borderColor, |
| const QGeoMapItemGeometry *fillShape, |
| const QGeoMapItemGeometry *borderShape); |
| private: |
| QSGFlatColorMaterial fill_material_; |
| MapPolylineNode *border_; |
| QSGGeometry geometry_; |
| }; |
| |
| class Q_LOCATION_PRIVATE_EXPORT MapPolygonNodeGL : public MapItemGeometryNode |
| { |
| |
| public: |
| MapPolygonNodeGL(); |
| ~MapPolygonNodeGL() override; |
| |
| void update(const QColor &fillColor, |
| const QGeoMapPolygonGeometryOpenGL *fillShape, |
| const QMatrix4x4 &geoProjection, |
| const QDoubleVector3D ¢er); |
| |
| MapPolygonMaterial fill_material_; |
| QSGGeometry geometry_; |
| }; |
| |
| class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolygonMapItemPrivate |
| { |
| public: |
| QDeclarativePolygonMapItemPrivate(QDeclarativePolygonMapItem &polygon) : m_poly(polygon) |
| { |
| |
| } |
| QDeclarativePolygonMapItemPrivate(QDeclarativePolygonMapItemPrivate &other) : m_poly(other.m_poly) |
| { |
| } |
| |
| virtual ~QDeclarativePolygonMapItemPrivate(); |
| virtual void onLinePropertiesChanged() = 0; |
| virtual void markSourceDirtyAndUpdate() = 0; |
| virtual void onMapSet() = 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; |
| |
| QDeclarativePolygonMapItem &m_poly; |
| }; |
| |
| class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolygonMapItemPrivateCPU: public QDeclarativePolygonMapItemPrivate |
| { |
| public: |
| QDeclarativePolygonMapItemPrivateCPU(QDeclarativePolygonMapItem &polygon) : QDeclarativePolygonMapItemPrivate(polygon) |
| { |
| } |
| |
| QDeclarativePolygonMapItemPrivateCPU(QDeclarativePolygonMapItemPrivate &other) |
| : QDeclarativePolygonMapItemPrivate(other) |
| { |
| } |
| |
| ~QDeclarativePolygonMapItemPrivateCPU() override; |
| void onLinePropertiesChanged() override |
| { |
| // mark dirty just in case we're a width change |
| markSourceDirtyAndUpdate(); |
| } |
| void markSourceDirtyAndUpdate() override |
| { |
| // preserveGeometry is cleared in updateMapItemPaintNode |
| m_geometry.markSourceDirty(); |
| m_borderGeometry.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_geopoly.size()); |
| for (const QGeoCoordinate &c : m_poly.m_geopoly.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_geopoly.path().last()); |
| } |
| void preserveGeometry() |
| { |
| m_geometry.setPreserveGeometry(true, m_poly.m_geopoly.boundingGeoRectangle().topLeft()); |
| m_borderGeometry.setPreserveGeometry(true, m_poly.m_geopoly.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_geopoly.path().length() == 0) { // Possibly cleared |
| m_geometry.clear(); |
| m_borderGeometry.clear(); |
| m_poly.setWidth(0); |
| m_poly.setHeight(0); |
| return; |
| } |
| const QGeoMap *map = m_poly.map(); |
| const qreal borderWidth = m_poly.m_border.width(); |
| const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map->geoProjection()); |
| QScopedValueRollback<bool> rollback(m_poly.m_updatingGeometry); |
| m_poly.m_updatingGeometry = true; |
| |
| m_geometry.updateSourcePoints(*map, m_geopathProjected); |
| m_geometry.updateScreenPoints(*map, borderWidth); |
| |
| QList<QGeoMapItemGeometry *> geoms; |
| geoms << &m_geometry; |
| m_borderGeometry.clear(); |
| |
| if (m_poly.m_border.color().alpha() != 0 && borderWidth > 0) { |
| QList<QDoubleVector2D> closedPath = m_geopathProjected; |
| closedPath << closedPath.first(); |
| |
| m_borderGeometry.setPreserveGeometry(true, m_poly.m_geopoly.boundingGeoRectangle().topLeft()); |
| |
| const QGeoCoordinate &geometryOrigin = m_geometry.origin(); |
| |
| m_borderGeometry.srcPoints_.clear(); |
| m_borderGeometry.srcPointTypes_.clear(); |
| |
| QDoubleVector2D borderLeftBoundWrapped; |
| QList<QList<QDoubleVector2D > > clippedPaths = m_borderGeometry.clipPath(*map, closedPath, borderLeftBoundWrapped); |
| if (clippedPaths.size()) { |
| borderLeftBoundWrapped = p.geoToWrappedMapProjection(geometryOrigin); |
| m_borderGeometry.pathToScreen(*map, clippedPaths, borderLeftBoundWrapped); |
| m_borderGeometry.updateScreenPoints(*map, borderWidth); |
| |
| geoms << &m_borderGeometry; |
| } else { |
| m_borderGeometry.clear(); |
| } |
| } |
| |
| QRectF combined = QGeoMapItemGeometry::translateToCommonOrigin(geoms); |
| m_poly.setWidth(combined.width() + 2 * borderWidth); |
| m_poly.setHeight(combined.height() + 2 * borderWidth); |
| |
| m_poly.setPositionOnMap(m_geometry.origin(), -1 * m_geometry.sourceBoundingBox().topLeft() |
| + QPointF(borderWidth, borderWidth)); |
| } |
| 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_poly.m_dirtyMaterial |
| || !oldNode) { |
| m_node->update(m_poly.m_color, |
| m_poly.m_border.color(), |
| &m_geometry, |
| &m_borderGeometry); |
| m_geometry.setPreserveGeometry(false); |
| m_borderGeometry.setPreserveGeometry(false); |
| m_geometry.markClean(); |
| m_borderGeometry.markClean(); |
| m_poly.m_dirtyMaterial = false; |
| } |
| return m_node; |
| } |
| bool contains(const QPointF &point) const override |
| { |
| return (m_geometry.contains(point) || m_borderGeometry.contains(point)); |
| } |
| |
| QList<QDoubleVector2D> m_geopathProjected; |
| QGeoMapPolygonGeometry m_geometry; |
| QGeoMapPolylineGeometry m_borderGeometry; |
| MapPolygonNode *m_node = nullptr; |
| }; |
| |
| class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolygonMapItemPrivateOpenGL: public QDeclarativePolygonMapItemPrivate |
| { |
| public: |
| struct RootNode : public QSGNode /*QSGTransformNode*/, public VisibleNode |
| { |
| RootNode() { } |
| |
| bool isSubtreeBlocked() const override |
| { |
| return subtreeBlocked(); |
| } |
| }; |
| |
| QDeclarativePolygonMapItemPrivateOpenGL(QDeclarativePolygonMapItem &polygon) : QDeclarativePolygonMapItemPrivate(polygon) |
| { |
| } |
| |
| QDeclarativePolygonMapItemPrivateOpenGL(QDeclarativePolygonMapItemPrivate &other) |
| : QDeclarativePolygonMapItemPrivate(other) |
| { |
| } |
| |
| ~QDeclarativePolygonMapItemPrivateOpenGL() override; |
| |
| void markScreenDirtyAndUpdate() |
| { |
| // preserveGeometry is cleared in updateMapItemPaintNode |
| m_geometry.markScreenDirty(); |
| m_borderGeometry.markScreenDirty(); |
| m_poly.polishAndUpdate(); |
| } |
| void onLinePropertiesChanged() override |
| { |
| m_poly.m_dirtyMaterial = true; |
| afterViewportChanged(); |
| } |
| void markSourceDirtyAndUpdate() override |
| { |
| // preserveGeometry is cleared in updateMapItemPaintNode |
| m_geometry.markSourceDirty(); |
| m_borderGeometry.markSourceDirty(); |
| m_poly.polishAndUpdate(); |
| } |
| void preserveGeometry() |
| { |
| m_geometry.setPreserveGeometry(true, m_poly.m_geopoly.boundingGeoRectangle().topLeft()); |
| m_borderGeometry.setPreserveGeometry(true, m_poly.m_geopoly.boundingGeoRectangle().topLeft()); |
| } |
| void afterViewportChanged() override // This is called when the camera changes, or visibleArea changes. |
| { |
| // preserveGeometry is cleared in updateMapItemPaintNode |
| preserveGeometry(); |
| markScreenDirtyAndUpdate(); |
| } |
| void onMapSet() override |
| { |
| markSourceDirtyAndUpdate(); |
| } |
| void onGeoGeometryChanged() override |
| { |
| preserveGeometry(); |
| markSourceDirtyAndUpdate(); |
| } |
| void onGeoGeometryUpdated() override |
| { |
| preserveGeometry(); |
| markSourceDirtyAndUpdate(); |
| } |
| void onItemGeometryChanged() override |
| { |
| onGeoGeometryChanged(); |
| } |
| void updatePolish() override |
| { |
| if (m_poly.m_geopoly.path().length() == 0) { // Possibly cleared |
| m_geometry.clear(); |
| m_borderGeometry.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_border.width(); |
| const QColor &lineColor = m_poly.m_border.color(); |
| const QColor &fillColor = m_poly.color(); |
| if (fillColor.alpha() != 0) { |
| m_geometry.updateSourcePoints(*m_poly.map(), m_poly.m_geopoly); |
| m_geometry.markScreenDirty(); |
| m_geometry.updateScreenPoints(*m_poly.map(), lineWidth, lineColor); |
| } else { |
| m_geometry.clearBounds(); |
| } |
| |
| QGeoMapItemGeometry * geom = &m_geometry; |
| m_borderGeometry.clearScreen(); |
| if (lineColor.alpha() != 0 && lineWidth > 0) { |
| m_borderGeometry.updateSourcePoints(*m_poly.map(), m_poly.m_geopoly); |
| m_borderGeometry.markScreenDirty(); |
| m_borderGeometry.updateScreenPoints(*m_poly.map(), lineWidth); |
| geom = &m_borderGeometry; |
| } |
| m_poly.setWidth(geom->sourceBoundingBox().width()); |
| m_poly.setHeight(geom->sourceBoundingBox().height()); |
| m_poly.setPosition(1.0 * geom->firstPointOffset() - QPointF(lineWidth * 0.5,lineWidth * 0.5)); |
| } |
| QSGNode * updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) override |
| { |
| Q_UNUSED(data); |
| |
| if (!m_rootNode || !oldNode) { |
| m_rootNode = new 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<RootNode *>(oldNode); |
| } |
| |
| const QGeoMap *map = m_poly.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_poly.m_border.color(), |
| float(m_poly.m_border.width()), |
| &m_borderGeometry, |
| combinedMatrix, |
| cameraCenter, |
| Qt::SquareCap, |
| true, |
| 30); // No LOD for polygons just yet. |
| // First figure out what to do with holes. |
| m_borderGeometry.setPreserveGeometry(false); |
| m_borderGeometry.markClean(); |
| } else { |
| m_polylinenode->setSubtreeBlocked(true); |
| } |
| if (m_geometry.isScreenDirty()) { |
| m_node->update(m_poly.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; |
| } |
| bool contains(const QPointF &point) const override |
| { |
| const qreal lineWidth = m_poly.m_border.width(); |
| const QColor &lineColor = m_poly.m_border.color(); |
| const QRectF &bounds = (lineColor.alpha() != 0 && lineWidth > 0) ? m_borderGeometry.sourceBoundingBox() : m_geometry.sourceBoundingBox(); |
| if (bounds.contains(point)) { |
| QDeclarativeGeoMap *m = m_poly.quickMap(); |
| if (m) { |
| const QGeoCoordinate crd = m->toCoordinate(m->mapFromItem(&m_poly, point)); |
| return m_poly.m_geopoly.contains(crd) || m_borderGeometry.contains(m_poly.mapToItem(m_poly.quickMap(), point), |
| m_poly.border()->width(), |
| static_cast<const QGeoProjectionWebMercator&>(m_poly.map()->geoProjection())); |
| } else { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| QGeoMapPolygonGeometryOpenGL m_geometry; |
| QGeoMapPolylineGeometryOpenGL m_borderGeometry; |
| RootNode *m_rootNode = nullptr; |
| MapPolygonNodeGL *m_node = nullptr; |
| MapPolylineNodeOpenGLExtruded *m_polylinenode = nullptr; |
| }; |
| |
| QT_END_NAMESPACE |
| |
| #endif // QDECLARATIVEPOLYGONMAPITEM_P_P_H |