1 /****************************************************************************
2 **
3 ** Copyright (C) 2020 Paolo Angelelli <paolo.angelelli@gmail.com>
4 ** Copyright (C) 2020 The Qt Company Ltd.
5 ** Contact: http://www.qt.io/licensing/
6 **
7 ** This file is part of the QtLocation module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL3$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and The Qt Company. For licensing terms
15 ** and conditions see http://www.qt.io/terms-conditions. For further
16 ** information use the contact form at http://www.qt.io/contact-us.
17 **
18 ** GNU Lesser General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU Lesser
20 ** General Public License version 3 as published by the Free Software
21 ** Foundation and appearing in the file LICENSE.LGPLv3 included in the
22 ** packaging of this file. Please review the following information to
23 ** ensure the GNU Lesser General Public License version 3 requirements
24 ** will be met: https://www.gnu.org/licenses/lgpl.html.
25 **
26 ** GNU General Public License Usage
27 ** Alternatively, this file may be used under the terms of the GNU
28 ** General Public License version 2.0 or later as published by the Free
29 ** Software Foundation and appearing in the file LICENSE.GPL included in
30 ** the packaging of this file. Please review the following information to
31 ** ensure the GNU General Public License version 2.0 requirements will be
32 ** met: http://www.gnu.org/licenses/gpl-2.0.html.
33 **
34 ** $QT_END_LICENSE$
35 **
36 ****************************************************************************/
37 
38 #ifndef QDECLARATIVEPOLYGONMAPITEM_P_P_H
39 #define QDECLARATIVEPOLYGONMAPITEM_P_P_H
40 
41 //
42 //  W A R N I N G
43 //  -------------
44 //
45 // This file is not part of the Qt API.  It exists purely as an
46 // implementation detail.  This header file may change from version to
47 // version without notice, or even be removed.
48 //
49 // We mean it.
50 //
51 
52 #include <QtLocation/private/qlocationglobal_p.h>
53 #include <QtLocation/private/qgeomapitemgeometry_p.h>
54 #include <QtLocation/private/qdeclarativegeomapitembase_p.h>
55 #include <QtLocation/private/qdeclarativepolylinemapitem_p.h>
56 #include <QtLocation/private/qdeclarativegeomapitemutils_p.h>
57 #include <QtLocation/private/qdeclarativepolygonmapitem_p.h>
58 #include <QtLocation/private/qdeclarativepolylinemapitem_p_p.h>
59 #include <QSGGeometryNode>
60 #include <QSGFlatColorMaterial>
61 #include <QtPositioning/QGeoPath>
62 #include <QtPositioning/QGeoRectangle>
63 #include <QtPositioning/QGeoPolygon>
64 #include <QtPositioning/private/qdoublevector2d_p.h>
65 #include <QSGFlatColorMaterial>
66 #include <QSGSimpleMaterial>
67 #include <QtGui/QMatrix4x4>
68 #include <QColor>
69 #include <QList>
70 #include <QVector>
71 #include <QtCore/QScopedValueRollback>
72 
73 QT_BEGIN_NAMESPACE
74 
75 class Q_LOCATION_PRIVATE_EXPORT QGeoMapPolygonGeometry : public QGeoMapItemGeometry
76 {
77 public:
78     QGeoMapPolygonGeometry();
79 
setAssumeSimple(bool value)80     inline void setAssumeSimple(bool value) { assumeSimple_ = value; }
81 
82     void updateSourcePoints(const QGeoMap &map,
83                             const QList<QDoubleVector2D> &path);
84 
85     void updateScreenPoints(const QGeoMap &map, qreal strokeWidth = 0.0);
86 
87 protected:
88     QPainterPath srcPath_;
89     bool assumeSimple_;
90 };
91 
92 class Q_LOCATION_PRIVATE_EXPORT QGeoMapPolygonGeometryOpenGL : public QGeoMapItemGeometry
93 {
94 public:
95     typedef struct {
96         QList<QDoubleVector2D> wrappedBboxes;
97     } WrappedPolygon;
98     QGeoMapPolygonGeometryOpenGL();
~QGeoMapPolygonGeometryOpenGL()99     ~QGeoMapPolygonGeometryOpenGL() override {}
100 
101     // Temporary method for compatibility in MapCircleObject. Remove when MapObjects are ported.
102     void updateSourcePoints(const QGeoMap &map,
103                             const QList<QDoubleVector2D> &path);
104 
105     void updateSourcePoints(const QGeoMap &map,
106                             const QList<QGeoCoordinate> &perimeter);
107 
108     void updateSourcePoints(const QGeoMap &map,
109                             const QGeoPolygon &poly);
110 
111     void updateSourcePoints(const QGeoMap &map,
112                             const QGeoRectangle &rect);
113 
114     void updateScreenPoints(const QGeoMap &map, qreal strokeWidth = 0.0, const QColor &strokeColor = Qt::transparent);
115     void updateQuickGeometry(const QGeoProjectionWebMercator &p, qreal strokeWidth = 0.0);
116 
allocateAndFillPolygon(QSGGeometry * geom)117     void allocateAndFillPolygon(QSGGeometry *geom) const
118     {
119 
120 
121         const QVector<QDeclarativeGeoMapItemUtils::vec2> &vx = m_screenVertices;
122         const QVector<quint32> &ix = m_screenIndices;
123 
124         geom->allocate(vx.size(), ix.size());
125         if (geom->indexType() == QSGGeometry::UnsignedShortType) {
126             quint16 *its = geom->indexDataAsUShort();
127             for (int i = 0; i < ix.size(); ++i)
128                 its[i] = ix[i];
129         } else if (geom->indexType() == QSGGeometry::UnsignedIntType) {
130             quint32 *its = geom->indexDataAsUInt();
131             for (int i = 0; i < ix.size(); ++i)
132                 its[i] = ix[i];
133         }
134 
135         QSGGeometry::Point2D *pts = geom->vertexDataAsPoint2D();
136         for (int i = 0; i < vx.size(); ++i)
137             pts[i].set(vx[i].x, vx[i].y);
138     }
139 
140     QVector<QDeclarativeGeoMapItemUtils::vec2> m_screenVertices;
141     QVector<quint32> m_screenIndices;
142     QDoubleVector2D m_bboxLeftBoundWrapped;
143     QVector<WrappedPolygon> m_wrappedPolygons;
144     int m_wrapOffset;
145 };
146 
147 class Q_LOCATION_PRIVATE_EXPORT MapPolygonShader : public QSGMaterialShader
148 {
149 public:
150     MapPolygonShader();
151 
vertexShader()152     const char *vertexShader() const override {
153         return
154         "attribute highp vec4 vertex;               \n"
155         "uniform highp mat4 qt_Matrix;              \n"
156         "uniform highp mat4 mapProjection;          \n"
157         "uniform highp vec3 center;                 \n"
158         "uniform highp vec3 center_lowpart;         \n"
159         "uniform lowp float wrapOffset;             \n"
160         "vec4 wrapped(in vec4 v) { return vec4(v.x + wrapOffset, v.y, 0.0, 1.0); }\n"
161         "void main() {                              \n"
162         "    vec4 vtx = wrapped(vertex) - vec4(center, 0.0);   \n"
163         "    vtx = vtx - vec4(center_lowpart, 0.0);   \n"
164         "    gl_Position = qt_Matrix * mapProjection * vtx;      \n"
165         "}";
166     }
167 
fragmentShader()168     const char *fragmentShader() const override {
169         return
170         "uniform lowp vec4 color;                   \n"
171         "void main() {                              \n"
172         "    gl_FragColor = color;                  \n"
173         "}";
174     }
175 
176     void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
attributeNames()177     char const *const *attributeNames() const override
178     {
179         static char const *const attr[] = { "vertex", nullptr };
180         return attr;
181     }
182 
183 private:
initialize()184     void initialize() override
185     {
186         m_matrix_id = program()->uniformLocation("qt_Matrix");
187         m_color_id = program()->uniformLocation("color");
188         m_mapProjection_id = program()->uniformLocation("mapProjection");
189         m_center_id = program()->uniformLocation("center");
190         m_center_lowpart_id = program()->uniformLocation("center_lowpart");
191         m_wrapOffset_id = program()->uniformLocation("wrapOffset");
192     }
193     int m_center_id;
194     int m_center_lowpart_id;
195     int m_mapProjection_id;
196     int m_matrix_id;
197     int m_color_id;
198     int m_wrapOffset_id;
199 };
200 
201 class Q_LOCATION_PRIVATE_EXPORT MapPolygonMaterial : public QSGFlatColorMaterial
202 {
203 public:
MapPolygonMaterial()204     MapPolygonMaterial()
205         : QSGFlatColorMaterial()
206     {
207         // Passing RequiresFullMatrix is essential in order to prevent the
208         // batch renderer from baking in simple, translate-only transforms into
209         // the vertex data. The shader will rely on the fact that
210         // vertexCoord.xy is the Shape-space coordinate and so no modifications
211         // are welcome.
212         setFlag(Blending | RequiresFullMatrix | CustomCompileStep);
213     }
214 
215     QSGMaterialShader *createShader() const override;
216 
setGeoProjection(const QMatrix4x4 & p)217     void setGeoProjection(const QMatrix4x4 &p)
218     {
219         m_geoProjection = p;
220     }
221 
geoProjection()222     QMatrix4x4 geoProjection() const
223     {
224         return m_geoProjection;
225     }
226 
setCenter(const QDoubleVector3D & c)227     void setCenter(const QDoubleVector3D &c)
228     {
229         m_center = c;
230     }
231 
center()232     QDoubleVector3D center() const
233     {
234         return m_center;
235     }
236 
wrapOffset()237     int wrapOffset() const
238     {
239         return m_wrapOffset;
240     }
241 
setWrapOffset(int wrapOffset)242     void setWrapOffset(int wrapOffset)
243     {
244         m_wrapOffset = wrapOffset;
245     }
246 
247     int compare(const QSGMaterial *other) const override;
248     QSGMaterialType *type() const override;
249 
250 protected:
251     QMatrix4x4 m_geoProjection;
252     QDoubleVector3D m_center;
253     int m_wrapOffset = 0;
254 };
255 
256 class Q_LOCATION_PRIVATE_EXPORT MapPolygonNode : public MapItemGeometryNode
257 {
258 
259 public:
260     MapPolygonNode();
261     ~MapPolygonNode() override;
262 
263     void update(const QColor &fillColor, const QColor &borderColor,
264                 const QGeoMapItemGeometry *fillShape,
265                 const QGeoMapItemGeometry *borderShape);
266 private:
267     QSGFlatColorMaterial fill_material_;
268     MapPolylineNode *border_;
269     QSGGeometry geometry_;
270 };
271 
272 class Q_LOCATION_PRIVATE_EXPORT MapPolygonNodeGL : public MapItemGeometryNode
273 {
274 
275 public:
276     MapPolygonNodeGL();
277     ~MapPolygonNodeGL() override;
278 
279     void update(const QColor &fillColor,
280                 const QGeoMapPolygonGeometryOpenGL *fillShape,
281                 const QMatrix4x4 &geoProjection,
282                 const QDoubleVector3D &center);
283 
284     MapPolygonMaterial fill_material_;
285     QSGGeometry geometry_;
286 };
287 
288 class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolygonMapItemPrivate
289 {
290 public:
QDeclarativePolygonMapItemPrivate(QDeclarativePolygonMapItem & polygon)291     QDeclarativePolygonMapItemPrivate(QDeclarativePolygonMapItem &polygon) : m_poly(polygon)
292     {
293 
294     }
QDeclarativePolygonMapItemPrivate(QDeclarativePolygonMapItemPrivate & other)295     QDeclarativePolygonMapItemPrivate(QDeclarativePolygonMapItemPrivate &other) : m_poly(other.m_poly)
296     {
297     }
298 
299     virtual ~QDeclarativePolygonMapItemPrivate();
300     virtual void onLinePropertiesChanged() = 0;
301     virtual void markSourceDirtyAndUpdate() = 0;
302     virtual void onMapSet() = 0;
303     virtual void onGeoGeometryChanged() = 0;
304     virtual void onGeoGeometryUpdated() = 0;
305     virtual void onItemGeometryChanged() = 0;
306     virtual void updatePolish() = 0;
307     virtual void afterViewportChanged() = 0;
308     virtual QSGNode * updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) = 0;
309     virtual bool contains(const QPointF &point) const = 0;
310 
311     QDeclarativePolygonMapItem &m_poly;
312 };
313 
314 class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolygonMapItemPrivateCPU: public QDeclarativePolygonMapItemPrivate
315 {
316 public:
QDeclarativePolygonMapItemPrivateCPU(QDeclarativePolygonMapItem & polygon)317     QDeclarativePolygonMapItemPrivateCPU(QDeclarativePolygonMapItem &polygon) : QDeclarativePolygonMapItemPrivate(polygon)
318     {
319     }
320 
QDeclarativePolygonMapItemPrivateCPU(QDeclarativePolygonMapItemPrivate & other)321     QDeclarativePolygonMapItemPrivateCPU(QDeclarativePolygonMapItemPrivate &other)
322     : QDeclarativePolygonMapItemPrivate(other)
323     {
324     }
325 
326     ~QDeclarativePolygonMapItemPrivateCPU() override;
onLinePropertiesChanged()327     void onLinePropertiesChanged() override
328     {
329         // mark dirty just in case we're a width change
330         markSourceDirtyAndUpdate();
331     }
markSourceDirtyAndUpdate()332     void markSourceDirtyAndUpdate() override
333     {
334         // preserveGeometry is cleared in updateMapItemPaintNode
335         m_geometry.markSourceDirty();
336         m_borderGeometry.markSourceDirty();
337         m_poly.polishAndUpdate();
338     }
regenerateCache()339     void regenerateCache()
340     {
341         if (!m_poly.map() || m_poly.map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator)
342             return;
343         const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_poly.map()->geoProjection());
344         m_geopathProjected.clear();
345         m_geopathProjected.reserve(m_poly.m_geopoly.size());
346         for (const QGeoCoordinate &c : m_poly.m_geopoly.path())
347             m_geopathProjected << p.geoToMapProjection(c);
348     }
updateCache()349     void updateCache()
350     {
351         if (!m_poly.map() || m_poly.map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator)
352             return;
353         const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_poly.map()->geoProjection());
354         m_geopathProjected << p.geoToMapProjection(m_poly.m_geopoly.path().last());
355     }
preserveGeometry()356     void preserveGeometry()
357     {
358         m_geometry.setPreserveGeometry(true, m_poly.m_geopoly.boundingGeoRectangle().topLeft());
359         m_borderGeometry.setPreserveGeometry(true, m_poly.m_geopoly.boundingGeoRectangle().topLeft());
360     }
afterViewportChanged()361     void afterViewportChanged() override
362     {
363         // preserveGeometry is cleared in updateMapItemPaintNode
364         preserveGeometry();
365         markSourceDirtyAndUpdate();
366     }
onMapSet()367     void onMapSet() override
368     {
369         regenerateCache();
370         markSourceDirtyAndUpdate();
371     }
onGeoGeometryChanged()372     void onGeoGeometryChanged() override
373     {
374         regenerateCache();
375         preserveGeometry();
376         markSourceDirtyAndUpdate();
377     }
onGeoGeometryUpdated()378     void onGeoGeometryUpdated() override
379     {
380         updateCache();
381         preserveGeometry();
382         markSourceDirtyAndUpdate();
383     }
onItemGeometryChanged()384     void onItemGeometryChanged() override
385     {
386         onGeoGeometryChanged();
387     }
updatePolish()388     void updatePolish() override
389     {
390         if (m_poly.m_geopoly.path().length() == 0) { // Possibly cleared
391             m_geometry.clear();
392             m_borderGeometry.clear();
393             m_poly.setWidth(0);
394             m_poly.setHeight(0);
395             return;
396         }
397         const QGeoMap *map = m_poly.map();
398         const qreal borderWidth = m_poly.m_border.width();
399         const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map->geoProjection());
400         QScopedValueRollback<bool> rollback(m_poly.m_updatingGeometry);
401         m_poly.m_updatingGeometry = true;
402 
403         m_geometry.updateSourcePoints(*map, m_geopathProjected);
404         m_geometry.updateScreenPoints(*map, borderWidth);
405 
406         QList<QGeoMapItemGeometry *> geoms;
407         geoms << &m_geometry;
408         m_borderGeometry.clear();
409 
410         if (m_poly.m_border.color().alpha() != 0 && borderWidth > 0) {
411             QList<QDoubleVector2D> closedPath = m_geopathProjected;
412             closedPath << closedPath.first();
413 
414             m_borderGeometry.setPreserveGeometry(true, m_poly.m_geopoly.boundingGeoRectangle().topLeft());
415 
416             const QGeoCoordinate &geometryOrigin = m_geometry.origin();
417 
418             m_borderGeometry.srcPoints_.clear();
419             m_borderGeometry.srcPointTypes_.clear();
420 
421             QDoubleVector2D borderLeftBoundWrapped;
422             QList<QList<QDoubleVector2D > > clippedPaths = m_borderGeometry.clipPath(*map, closedPath, borderLeftBoundWrapped);
423             if (clippedPaths.size()) {
424                 borderLeftBoundWrapped = p.geoToWrappedMapProjection(geometryOrigin);
425                 m_borderGeometry.pathToScreen(*map, clippedPaths, borderLeftBoundWrapped);
426                 m_borderGeometry.updateScreenPoints(*map, borderWidth);
427 
428                 geoms <<  &m_borderGeometry;
429             } else {
430                 m_borderGeometry.clear();
431             }
432         }
433 
434         QRectF combined = QGeoMapItemGeometry::translateToCommonOrigin(geoms);
435         m_poly.setWidth(combined.width() + 2 * borderWidth);
436         m_poly.setHeight(combined.height() + 2 * borderWidth);
437 
438         m_poly.setPositionOnMap(m_geometry.origin(), -1 * m_geometry.sourceBoundingBox().topLeft()
439                                                 + QPointF(borderWidth, borderWidth));
440     }
updateMapItemPaintNode(QSGNode * oldNode,QQuickItem::UpdatePaintNodeData * data)441     QSGNode *updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) override
442     {
443         Q_UNUSED(data);
444         if (!m_node || !oldNode) {
445             m_node = new MapPolygonNode();
446             if (oldNode) {
447                 delete oldNode;
448                 oldNode = nullptr;
449             }
450         } else {
451             m_node = static_cast<MapPolygonNode *>(oldNode);
452         }
453 
454         //TODO: update only material
455         if (m_geometry.isScreenDirty()
456                 || m_borderGeometry.isScreenDirty()
457                 || m_poly.m_dirtyMaterial
458                 || !oldNode) {
459             m_node->update(m_poly.m_color,
460                          m_poly.m_border.color(),
461                          &m_geometry,
462                          &m_borderGeometry);
463             m_geometry.setPreserveGeometry(false);
464             m_borderGeometry.setPreserveGeometry(false);
465             m_geometry.markClean();
466             m_borderGeometry.markClean();
467             m_poly.m_dirtyMaterial = false;
468         }
469         return m_node;
470     }
contains(const QPointF & point)471     bool contains(const QPointF &point) const override
472     {
473         return (m_geometry.contains(point) || m_borderGeometry.contains(point));
474     }
475 
476     QList<QDoubleVector2D> m_geopathProjected;
477     QGeoMapPolygonGeometry m_geometry;
478     QGeoMapPolylineGeometry m_borderGeometry;
479     MapPolygonNode *m_node = nullptr;
480 };
481 
482 class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolygonMapItemPrivateOpenGL: public QDeclarativePolygonMapItemPrivate
483 {
484 public:
485     struct RootNode : public QSGNode /*QSGTransformNode*/, public VisibleNode
486     {
RootNodeRootNode487         RootNode() { }
488 
isSubtreeBlockedRootNode489         bool isSubtreeBlocked() const override
490         {
491             return subtreeBlocked();
492         }
493     };
494 
QDeclarativePolygonMapItemPrivateOpenGL(QDeclarativePolygonMapItem & polygon)495     QDeclarativePolygonMapItemPrivateOpenGL(QDeclarativePolygonMapItem &polygon) : QDeclarativePolygonMapItemPrivate(polygon)
496     {
497     }
498 
QDeclarativePolygonMapItemPrivateOpenGL(QDeclarativePolygonMapItemPrivate & other)499     QDeclarativePolygonMapItemPrivateOpenGL(QDeclarativePolygonMapItemPrivate &other)
500     : QDeclarativePolygonMapItemPrivate(other)
501     {
502     }
503 
504     ~QDeclarativePolygonMapItemPrivateOpenGL() override;
505 
markScreenDirtyAndUpdate()506     void markScreenDirtyAndUpdate()
507     {
508         // preserveGeometry is cleared in updateMapItemPaintNode
509         m_geometry.markScreenDirty();
510         m_borderGeometry.markScreenDirty();
511         m_poly.polishAndUpdate();
512     }
onLinePropertiesChanged()513     void onLinePropertiesChanged() override
514     {
515         m_poly.m_dirtyMaterial = true;
516         afterViewportChanged();
517     }
markSourceDirtyAndUpdate()518     void markSourceDirtyAndUpdate() override
519     {
520         // preserveGeometry is cleared in updateMapItemPaintNode
521         m_geometry.markSourceDirty();
522         m_borderGeometry.markSourceDirty();
523         m_poly.polishAndUpdate();
524     }
preserveGeometry()525     void preserveGeometry()
526     {
527         m_geometry.setPreserveGeometry(true, m_poly.m_geopoly.boundingGeoRectangle().topLeft());
528         m_borderGeometry.setPreserveGeometry(true, m_poly.m_geopoly.boundingGeoRectangle().topLeft());
529     }
afterViewportChanged()530     void afterViewportChanged() override // This is called when the camera changes, or visibleArea changes.
531     {
532         // preserveGeometry is cleared in updateMapItemPaintNode
533         preserveGeometry();
534         markScreenDirtyAndUpdate();
535     }
onMapSet()536     void onMapSet() override
537     {
538         markSourceDirtyAndUpdate();
539     }
onGeoGeometryChanged()540     void onGeoGeometryChanged() override
541     {
542         preserveGeometry();
543         markSourceDirtyAndUpdate();
544     }
onGeoGeometryUpdated()545     void onGeoGeometryUpdated() override
546     {
547         preserveGeometry();
548         markSourceDirtyAndUpdate();
549     }
onItemGeometryChanged()550     void onItemGeometryChanged() override
551     {
552         onGeoGeometryChanged();
553     }
updatePolish()554     void updatePolish() override
555     {
556         if (m_poly.m_geopoly.path().length() == 0) { // Possibly cleared
557             m_geometry.clear();
558             m_borderGeometry.clear();
559             m_poly.setWidth(0);
560             m_poly.setHeight(0);
561             return;
562         }
563 
564         QScopedValueRollback<bool> rollback(m_poly.m_updatingGeometry);
565         m_poly.m_updatingGeometry = true;
566         const qreal lineWidth = m_poly.m_border.width();
567         const QColor &lineColor = m_poly.m_border.color();
568         const QColor &fillColor = m_poly.color();
569         if (fillColor.alpha() != 0) {
570             m_geometry.updateSourcePoints(*m_poly.map(), m_poly.m_geopoly);
571             m_geometry.markScreenDirty();
572             m_geometry.updateScreenPoints(*m_poly.map(), lineWidth, lineColor);
573         } else {
574             m_geometry.clearBounds();
575         }
576 
577         QGeoMapItemGeometry * geom = &m_geometry;
578         m_borderGeometry.clearScreen();
579         if (lineColor.alpha() != 0 && lineWidth > 0) {
580             m_borderGeometry.updateSourcePoints(*m_poly.map(), m_poly.m_geopoly);
581             m_borderGeometry.markScreenDirty();
582             m_borderGeometry.updateScreenPoints(*m_poly.map(), lineWidth);
583             geom = &m_borderGeometry;
584         }
585         m_poly.setWidth(geom->sourceBoundingBox().width());
586         m_poly.setHeight(geom->sourceBoundingBox().height());
587         m_poly.setPosition(1.0 * geom->firstPointOffset() - QPointF(lineWidth * 0.5,lineWidth * 0.5));
588     }
updateMapItemPaintNode(QSGNode * oldNode,QQuickItem::UpdatePaintNodeData * data)589     QSGNode * updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) override
590     {
591         Q_UNUSED(data);
592 
593         if (!m_rootNode || !oldNode) {
594             m_rootNode = new RootNode();
595             m_node = new MapPolygonNodeGL();
596             m_rootNode->appendChildNode(m_node);
597             m_polylinenode = new MapPolylineNodeOpenGLExtruded();
598             m_rootNode->appendChildNode(m_polylinenode);
599             m_rootNode->markDirty(QSGNode::DirtyNodeAdded);
600             if (oldNode)
601                 delete oldNode;
602         } else {
603             m_rootNode = static_cast<RootNode *>(oldNode);
604         }
605 
606         const QGeoMap *map = m_poly.map();
607         const QMatrix4x4 &combinedMatrix = map->geoProjection().qsgTransform();
608         const QDoubleVector3D &cameraCenter = map->geoProjection().centerMercator();
609 
610         if (m_borderGeometry.isScreenDirty()) {
611             /* Do the border update first */
612             m_polylinenode->update(m_poly.m_border.color(),
613                                    float(m_poly.m_border.width()),
614                                    &m_borderGeometry,
615                                    combinedMatrix,
616                                    cameraCenter,
617                                    Qt::SquareCap,
618                                    true,
619                                    30); // No LOD for polygons just yet.
620                                         // First figure out what to do with holes.
621             m_borderGeometry.setPreserveGeometry(false);
622             m_borderGeometry.markClean();
623         } else {
624             m_polylinenode->setSubtreeBlocked(true);
625         }
626         if (m_geometry.isScreenDirty()) {
627             m_node->update(m_poly.m_color,
628                          &m_geometry,
629                          combinedMatrix,
630                          cameraCenter);
631             m_geometry.setPreserveGeometry(false);
632             m_geometry.markClean();
633         } else {
634             m_node->setSubtreeBlocked(true);
635         }
636 
637         m_rootNode->setSubtreeBlocked(false);
638         return m_rootNode;
639     }
contains(const QPointF & point)640     bool contains(const QPointF &point) const override
641     {
642         const qreal lineWidth = m_poly.m_border.width();
643         const QColor &lineColor = m_poly.m_border.color();
644         const QRectF &bounds = (lineColor.alpha() != 0 && lineWidth > 0) ? m_borderGeometry.sourceBoundingBox() : m_geometry.sourceBoundingBox();
645         if (bounds.contains(point)) {
646             QDeclarativeGeoMap *m = m_poly.quickMap();
647             if (m) {
648                 const QGeoCoordinate crd = m->toCoordinate(m->mapFromItem(&m_poly, point));
649                 return  m_poly.m_geopoly.contains(crd) || m_borderGeometry.contains(m_poly.mapToItem(m_poly.quickMap(), point),
650                                                                               m_poly.border()->width(),
651                                                                               static_cast<const QGeoProjectionWebMercator&>(m_poly.map()->geoProjection()));
652             } else {
653                 return  true;
654             }
655         }
656         return false;
657     }
658 
659     QGeoMapPolygonGeometryOpenGL m_geometry;
660     QGeoMapPolylineGeometryOpenGL m_borderGeometry;
661     RootNode *m_rootNode = nullptr;
662     MapPolygonNodeGL *m_node = nullptr;
663     MapPolylineNodeOpenGLExtruded *m_polylinenode = nullptr;
664 };
665 
666 QT_END_NAMESPACE
667 
668 #endif // QDECLARATIVEPOLYGONMAPITEM_P_P_H
669