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 #if QT_CONFIG(opengl)
93 class Q_LOCATION_PRIVATE_EXPORT QGeoMapPolygonGeometryOpenGL : public QGeoMapItemGeometry
94 {
95 public:
96     typedef struct {
97         QList<QDoubleVector2D> wrappedBboxes;
98     } WrappedPolygon;
99     QGeoMapPolygonGeometryOpenGL();
~QGeoMapPolygonGeometryOpenGL()100     ~QGeoMapPolygonGeometryOpenGL() override {}
101 
102     // Temporary method for compatibility in MapCircleObject. Remove when MapObjects are ported.
103     void updateSourcePoints(const QGeoMap &map,
104                             const QList<QDoubleVector2D> &path);
105 
106     void updateSourcePoints(const QGeoMap &map,
107                             const QList<QGeoCoordinate> &perimeter);
108 
109     void updateSourcePoints(const QGeoMap &map,
110                             const QGeoPolygon &poly);
111 
112     void updateSourcePoints(const QGeoMap &map,
113                             const QGeoRectangle &rect);
114 
115     void updateScreenPoints(const QGeoMap &map, qreal strokeWidth = 0.0, const QColor &strokeColor = Qt::transparent);
116     void updateQuickGeometry(const QGeoProjectionWebMercator &p, qreal strokeWidth = 0.0);
117 
allocateAndFillPolygon(QSGGeometry * geom)118     void allocateAndFillPolygon(QSGGeometry *geom) const
119     {
120 
121 
122         const QVector<QDeclarativeGeoMapItemUtils::vec2> &vx = m_screenVertices;
123         const QVector<quint32> &ix = m_screenIndices;
124 
125         geom->allocate(vx.size(), ix.size());
126         if (geom->indexType() == QSGGeometry::UnsignedShortType) {
127             quint16 *its = geom->indexDataAsUShort();
128             for (int i = 0; i < ix.size(); ++i)
129                 its[i] = ix[i];
130         } else if (geom->indexType() == QSGGeometry::UnsignedIntType) {
131             quint32 *its = geom->indexDataAsUInt();
132             for (int i = 0; i < ix.size(); ++i)
133                 its[i] = ix[i];
134         }
135 
136         QSGGeometry::Point2D *pts = geom->vertexDataAsPoint2D();
137         for (int i = 0; i < vx.size(); ++i)
138             pts[i].set(vx[i].x, vx[i].y);
139     }
140 
141     QVector<QDeclarativeGeoMapItemUtils::vec2> m_screenVertices;
142     QVector<quint32> m_screenIndices;
143     QDoubleVector2D m_bboxLeftBoundWrapped;
144     QVector<WrappedPolygon> m_wrappedPolygons;
145     int m_wrapOffset;
146 };
147 
148 class Q_LOCATION_PRIVATE_EXPORT MapPolygonShader : public QSGMaterialShader
149 {
150 public:
151     MapPolygonShader();
152 
vertexShader()153     const char *vertexShader() const override {
154         return
155         "attribute highp vec4 vertex;               \n"
156         "uniform highp mat4 qt_Matrix;              \n"
157         "uniform highp mat4 mapProjection;          \n"
158         "uniform highp vec3 center;                 \n"
159         "uniform highp vec3 center_lowpart;         \n"
160         "uniform lowp float wrapOffset;             \n"
161         "vec4 wrapped(in vec4 v) { return vec4(v.x + wrapOffset, v.y, 0.0, 1.0); }\n"
162         "void main() {                              \n"
163         "    vec4 vtx = wrapped(vertex) - vec4(center, 0.0);   \n"
164         "    vtx = vtx - vec4(center_lowpart, 0.0);   \n"
165         "    gl_Position = qt_Matrix * mapProjection * vtx;      \n"
166         "}";
167     }
168 
fragmentShader()169     const char *fragmentShader() const override {
170         return
171         "uniform lowp vec4 color;                   \n"
172         "void main() {                              \n"
173         "    gl_FragColor = color;                  \n"
174         "}";
175     }
176 
177     void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
attributeNames()178     char const *const *attributeNames() const override
179     {
180         static char const *const attr[] = { "vertex", nullptr };
181         return attr;
182     }
183 
184 private:
initialize()185     void initialize() override
186     {
187         m_matrix_id = program()->uniformLocation("qt_Matrix");
188         m_color_id = program()->uniformLocation("color");
189         m_mapProjection_id = program()->uniformLocation("mapProjection");
190         m_center_id = program()->uniformLocation("center");
191         m_center_lowpart_id = program()->uniformLocation("center_lowpart");
192         m_wrapOffset_id = program()->uniformLocation("wrapOffset");
193     }
194     int m_center_id;
195     int m_center_lowpart_id;
196     int m_mapProjection_id;
197     int m_matrix_id;
198     int m_color_id;
199     int m_wrapOffset_id;
200 };
201 #endif // QT_CONFIG(opengl)
202 
203 class Q_LOCATION_PRIVATE_EXPORT MapPolygonMaterial : public QSGFlatColorMaterial
204 {
205 public:
MapPolygonMaterial()206     MapPolygonMaterial()
207         : QSGFlatColorMaterial()
208     {
209         // Passing RequiresFullMatrix is essential in order to prevent the
210         // batch renderer from baking in simple, translate-only transforms into
211         // the vertex data. The shader will rely on the fact that
212         // vertexCoord.xy is the Shape-space coordinate and so no modifications
213         // are welcome.
214         setFlag(Blending | RequiresFullMatrix | CustomCompileStep);
215     }
216 
217     QSGMaterialShader *createShader() const override;
218 
setGeoProjection(const QMatrix4x4 & p)219     void setGeoProjection(const QMatrix4x4 &p)
220     {
221         m_geoProjection = p;
222     }
223 
geoProjection()224     QMatrix4x4 geoProjection() const
225     {
226         return m_geoProjection;
227     }
228 
setCenter(const QDoubleVector3D & c)229     void setCenter(const QDoubleVector3D &c)
230     {
231         m_center = c;
232     }
233 
center()234     QDoubleVector3D center() const
235     {
236         return m_center;
237     }
238 
wrapOffset()239     int wrapOffset() const
240     {
241         return m_wrapOffset;
242     }
243 
setWrapOffset(int wrapOffset)244     void setWrapOffset(int wrapOffset)
245     {
246         m_wrapOffset = wrapOffset;
247     }
248 
249     int compare(const QSGMaterial *other) const override;
250     QSGMaterialType *type() const override;
251 
252 protected:
253     QMatrix4x4 m_geoProjection;
254     QDoubleVector3D m_center;
255     int m_wrapOffset = 0;
256 };
257 
258 class Q_LOCATION_PRIVATE_EXPORT MapPolygonNode : public MapItemGeometryNode
259 {
260 
261 public:
262     MapPolygonNode();
263     ~MapPolygonNode() override;
264 
265     void update(const QColor &fillColor, const QColor &borderColor,
266                 const QGeoMapItemGeometry *fillShape,
267                 const QGeoMapItemGeometry *borderShape);
268 private:
269     QSGFlatColorMaterial fill_material_;
270     MapPolylineNode *border_;
271     QSGGeometry geometry_;
272 };
273 
274 #if QT_CONFIG(opengl)
275 class Q_LOCATION_PRIVATE_EXPORT MapPolygonNodeGL : public MapItemGeometryNode
276 {
277 
278 public:
279     MapPolygonNodeGL();
280     ~MapPolygonNodeGL() override;
281 
282     void update(const QColor &fillColor,
283                 const QGeoMapPolygonGeometryOpenGL *fillShape,
284                 const QMatrix4x4 &geoProjection,
285                 const QDoubleVector3D &center);
286 
287     MapPolygonMaterial fill_material_;
288     QSGGeometry geometry_;
289 };
290 #endif // QT_CONFIG(opengl)
291 
292 class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolygonMapItemPrivate
293 {
294 public:
QDeclarativePolygonMapItemPrivate(QDeclarativePolygonMapItem & polygon)295     QDeclarativePolygonMapItemPrivate(QDeclarativePolygonMapItem &polygon) : m_poly(polygon)
296     {
297 
298     }
QDeclarativePolygonMapItemPrivate(QDeclarativePolygonMapItemPrivate & other)299     QDeclarativePolygonMapItemPrivate(QDeclarativePolygonMapItemPrivate &other) : m_poly(other.m_poly)
300     {
301     }
302 
303     virtual ~QDeclarativePolygonMapItemPrivate();
304     virtual void onLinePropertiesChanged() = 0;
305     virtual void markSourceDirtyAndUpdate() = 0;
306     virtual void onMapSet() = 0;
307     virtual void onGeoGeometryChanged() = 0;
308     virtual void onGeoGeometryUpdated() = 0;
309     virtual void onItemGeometryChanged() = 0;
310     virtual void updatePolish() = 0;
311     virtual void afterViewportChanged() = 0;
312     virtual QSGNode * updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) = 0;
313     virtual bool contains(const QPointF &point) const = 0;
314 
315     QDeclarativePolygonMapItem &m_poly;
316 };
317 
318 class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolygonMapItemPrivateCPU: public QDeclarativePolygonMapItemPrivate
319 {
320 public:
QDeclarativePolygonMapItemPrivateCPU(QDeclarativePolygonMapItem & polygon)321     QDeclarativePolygonMapItemPrivateCPU(QDeclarativePolygonMapItem &polygon) : QDeclarativePolygonMapItemPrivate(polygon)
322     {
323     }
324 
QDeclarativePolygonMapItemPrivateCPU(QDeclarativePolygonMapItemPrivate & other)325     QDeclarativePolygonMapItemPrivateCPU(QDeclarativePolygonMapItemPrivate &other)
326     : QDeclarativePolygonMapItemPrivate(other)
327     {
328     }
329 
330     ~QDeclarativePolygonMapItemPrivateCPU() override;
onLinePropertiesChanged()331     void onLinePropertiesChanged() override
332     {
333         // mark dirty just in case we're a width change
334         markSourceDirtyAndUpdate();
335     }
markSourceDirtyAndUpdate()336     void markSourceDirtyAndUpdate() override
337     {
338         // preserveGeometry is cleared in updateMapItemPaintNode
339         m_geometry.markSourceDirty();
340         m_borderGeometry.markSourceDirty();
341         m_poly.polishAndUpdate();
342     }
regenerateCache()343     void regenerateCache()
344     {
345         if (!m_poly.map() || m_poly.map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator)
346             return;
347         const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_poly.map()->geoProjection());
348         m_geopathProjected.clear();
349         m_geopathProjected.reserve(m_poly.m_geopoly.size());
350         for (const QGeoCoordinate &c : m_poly.m_geopoly.path())
351             m_geopathProjected << p.geoToMapProjection(c);
352     }
updateCache()353     void updateCache()
354     {
355         if (!m_poly.map() || m_poly.map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator)
356             return;
357         const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_poly.map()->geoProjection());
358         m_geopathProjected << p.geoToMapProjection(m_poly.m_geopoly.path().last());
359     }
preserveGeometry()360     void preserveGeometry()
361     {
362         m_geometry.setPreserveGeometry(true, m_poly.m_geopoly.boundingGeoRectangle().topLeft());
363         m_borderGeometry.setPreserveGeometry(true, m_poly.m_geopoly.boundingGeoRectangle().topLeft());
364     }
afterViewportChanged()365     void afterViewportChanged() override
366     {
367         // preserveGeometry is cleared in updateMapItemPaintNode
368         preserveGeometry();
369         markSourceDirtyAndUpdate();
370     }
onMapSet()371     void onMapSet() override
372     {
373         regenerateCache();
374         markSourceDirtyAndUpdate();
375     }
onGeoGeometryChanged()376     void onGeoGeometryChanged() override
377     {
378         regenerateCache();
379         preserveGeometry();
380         markSourceDirtyAndUpdate();
381     }
onGeoGeometryUpdated()382     void onGeoGeometryUpdated() override
383     {
384         updateCache();
385         preserveGeometry();
386         markSourceDirtyAndUpdate();
387     }
onItemGeometryChanged()388     void onItemGeometryChanged() override
389     {
390         onGeoGeometryChanged();
391     }
updatePolish()392     void updatePolish() override
393     {
394         if (m_poly.m_geopoly.path().length() == 0) { // Possibly cleared
395             m_geometry.clear();
396             m_borderGeometry.clear();
397             m_poly.setWidth(0);
398             m_poly.setHeight(0);
399             return;
400         }
401         const QGeoMap *map = m_poly.map();
402         const qreal borderWidth = m_poly.m_border.width();
403         const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map->geoProjection());
404         QScopedValueRollback<bool> rollback(m_poly.m_updatingGeometry);
405         m_poly.m_updatingGeometry = true;
406 
407         m_geometry.updateSourcePoints(*map, m_geopathProjected);
408         m_geometry.updateScreenPoints(*map, borderWidth);
409 
410         QList<QGeoMapItemGeometry *> geoms;
411         geoms << &m_geometry;
412         m_borderGeometry.clear();
413 
414         if (m_poly.m_border.color().alpha() != 0 && borderWidth > 0) {
415             QList<QDoubleVector2D> closedPath = m_geopathProjected;
416             closedPath << closedPath.first();
417 
418             m_borderGeometry.setPreserveGeometry(true, m_poly.m_geopoly.boundingGeoRectangle().topLeft());
419 
420             const QGeoCoordinate &geometryOrigin = m_geometry.origin();
421 
422             m_borderGeometry.srcPoints_.clear();
423             m_borderGeometry.srcPointTypes_.clear();
424 
425             QDoubleVector2D borderLeftBoundWrapped;
426             QList<QList<QDoubleVector2D > > clippedPaths = m_borderGeometry.clipPath(*map, closedPath, borderLeftBoundWrapped);
427             if (clippedPaths.size()) {
428                 borderLeftBoundWrapped = p.geoToWrappedMapProjection(geometryOrigin);
429                 m_borderGeometry.pathToScreen(*map, clippedPaths, borderLeftBoundWrapped);
430                 m_borderGeometry.updateScreenPoints(*map, borderWidth);
431 
432                 geoms <<  &m_borderGeometry;
433             } else {
434                 m_borderGeometry.clear();
435             }
436         }
437 
438         QRectF combined = QGeoMapItemGeometry::translateToCommonOrigin(geoms);
439         m_poly.setWidth(combined.width() + 2 * borderWidth);
440         m_poly.setHeight(combined.height() + 2 * borderWidth);
441 
442         m_poly.setPositionOnMap(m_geometry.origin(), -1 * m_geometry.sourceBoundingBox().topLeft()
443                                                 + QPointF(borderWidth, borderWidth));
444     }
updateMapItemPaintNode(QSGNode * oldNode,QQuickItem::UpdatePaintNodeData * data)445     QSGNode *updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) override
446     {
447         Q_UNUSED(data);
448         if (!m_node || !oldNode) {
449             m_node = new MapPolygonNode();
450             if (oldNode) {
451                 delete oldNode;
452                 oldNode = nullptr;
453             }
454         } else {
455             m_node = static_cast<MapPolygonNode *>(oldNode);
456         }
457 
458         //TODO: update only material
459         if (m_geometry.isScreenDirty()
460                 || m_borderGeometry.isScreenDirty()
461                 || m_poly.m_dirtyMaterial
462                 || !oldNode) {
463             m_node->update(m_poly.m_color,
464                          m_poly.m_border.color(),
465                          &m_geometry,
466                          &m_borderGeometry);
467             m_geometry.setPreserveGeometry(false);
468             m_borderGeometry.setPreserveGeometry(false);
469             m_geometry.markClean();
470             m_borderGeometry.markClean();
471             m_poly.m_dirtyMaterial = false;
472         }
473         return m_node;
474     }
contains(const QPointF & point)475     bool contains(const QPointF &point) const override
476     {
477         return (m_geometry.contains(point) || m_borderGeometry.contains(point));
478     }
479 
480     QList<QDoubleVector2D> m_geopathProjected;
481     QGeoMapPolygonGeometry m_geometry;
482     QGeoMapPolylineGeometry m_borderGeometry;
483     MapPolygonNode *m_node = nullptr;
484 };
485 
486 #if QT_CONFIG(opengl)
487 class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolygonMapItemPrivateOpenGL: public QDeclarativePolygonMapItemPrivate
488 {
489 public:
490     struct RootNode : public QSGNode /*QSGTransformNode*/, public VisibleNode
491     {
RootNodeRootNode492         RootNode() { }
493 
isSubtreeBlockedRootNode494         bool isSubtreeBlocked() const override
495         {
496             return subtreeBlocked();
497         }
498     };
499 
QDeclarativePolygonMapItemPrivateOpenGL(QDeclarativePolygonMapItem & polygon)500     QDeclarativePolygonMapItemPrivateOpenGL(QDeclarativePolygonMapItem &polygon) : QDeclarativePolygonMapItemPrivate(polygon)
501     {
502     }
503 
QDeclarativePolygonMapItemPrivateOpenGL(QDeclarativePolygonMapItemPrivate & other)504     QDeclarativePolygonMapItemPrivateOpenGL(QDeclarativePolygonMapItemPrivate &other)
505     : QDeclarativePolygonMapItemPrivate(other)
506     {
507     }
508 
509     ~QDeclarativePolygonMapItemPrivateOpenGL() override;
510 
markScreenDirtyAndUpdate()511     void markScreenDirtyAndUpdate()
512     {
513         // preserveGeometry is cleared in updateMapItemPaintNode
514         m_geometry.markScreenDirty();
515         m_borderGeometry.markScreenDirty();
516         m_poly.polishAndUpdate();
517     }
onLinePropertiesChanged()518     void onLinePropertiesChanged() override
519     {
520         m_poly.m_dirtyMaterial = true;
521         afterViewportChanged();
522     }
markSourceDirtyAndUpdate()523     void markSourceDirtyAndUpdate() override
524     {
525         // preserveGeometry is cleared in updateMapItemPaintNode
526         m_geometry.markSourceDirty();
527         m_borderGeometry.markSourceDirty();
528         m_poly.polishAndUpdate();
529     }
preserveGeometry()530     void preserveGeometry()
531     {
532         m_geometry.setPreserveGeometry(true, m_poly.m_geopoly.boundingGeoRectangle().topLeft());
533         m_borderGeometry.setPreserveGeometry(true, m_poly.m_geopoly.boundingGeoRectangle().topLeft());
534     }
afterViewportChanged()535     void afterViewportChanged() override // This is called when the camera changes, or visibleArea changes.
536     {
537         // preserveGeometry is cleared in updateMapItemPaintNode
538         preserveGeometry();
539         markScreenDirtyAndUpdate();
540     }
onMapSet()541     void onMapSet() override
542     {
543         markSourceDirtyAndUpdate();
544     }
onGeoGeometryChanged()545     void onGeoGeometryChanged() override
546     {
547         preserveGeometry();
548         markSourceDirtyAndUpdate();
549     }
onGeoGeometryUpdated()550     void onGeoGeometryUpdated() override
551     {
552         preserveGeometry();
553         markSourceDirtyAndUpdate();
554     }
onItemGeometryChanged()555     void onItemGeometryChanged() override
556     {
557         onGeoGeometryChanged();
558     }
updatePolish()559     void updatePolish() override
560     {
561         if (m_poly.m_geopoly.path().length() == 0) { // Possibly cleared
562             m_geometry.clear();
563             m_borderGeometry.clear();
564             m_poly.setWidth(0);
565             m_poly.setHeight(0);
566             return;
567         }
568 
569         QScopedValueRollback<bool> rollback(m_poly.m_updatingGeometry);
570         m_poly.m_updatingGeometry = true;
571         const qreal lineWidth = m_poly.m_border.width();
572         const QColor &lineColor = m_poly.m_border.color();
573         const QColor &fillColor = m_poly.color();
574         if (fillColor.alpha() != 0) {
575             m_geometry.updateSourcePoints(*m_poly.map(), m_poly.m_geopoly);
576             m_geometry.markScreenDirty();
577             m_geometry.updateScreenPoints(*m_poly.map(), lineWidth, lineColor);
578         } else {
579             m_geometry.clearBounds();
580         }
581 
582         QGeoMapItemGeometry * geom = &m_geometry;
583         m_borderGeometry.clearScreen();
584         if (lineColor.alpha() != 0 && lineWidth > 0) {
585             m_borderGeometry.updateSourcePoints(*m_poly.map(), m_poly.m_geopoly);
586             m_borderGeometry.markScreenDirty();
587             m_borderGeometry.updateScreenPoints(*m_poly.map(), lineWidth);
588             geom = &m_borderGeometry;
589         }
590         m_poly.setWidth(geom->sourceBoundingBox().width());
591         m_poly.setHeight(geom->sourceBoundingBox().height());
592         m_poly.setPosition(1.0 * geom->firstPointOffset() - QPointF(lineWidth * 0.5,lineWidth * 0.5));
593     }
updateMapItemPaintNode(QSGNode * oldNode,QQuickItem::UpdatePaintNodeData * data)594     QSGNode * updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) override
595     {
596         Q_UNUSED(data);
597 
598         if (!m_rootNode || !oldNode) {
599             m_rootNode = new RootNode();
600             m_node = new MapPolygonNodeGL();
601             m_rootNode->appendChildNode(m_node);
602             m_polylinenode = new MapPolylineNodeOpenGLExtruded();
603             m_rootNode->appendChildNode(m_polylinenode);
604             m_rootNode->markDirty(QSGNode::DirtyNodeAdded);
605             if (oldNode)
606                 delete oldNode;
607         } else {
608             m_rootNode = static_cast<RootNode *>(oldNode);
609         }
610 
611         const QGeoMap *map = m_poly.map();
612         const QMatrix4x4 &combinedMatrix = map->geoProjection().qsgTransform();
613         const QDoubleVector3D &cameraCenter = map->geoProjection().centerMercator();
614 
615         if (m_borderGeometry.isScreenDirty()) {
616             /* Do the border update first */
617             m_polylinenode->update(m_poly.m_border.color(),
618                                    float(m_poly.m_border.width()),
619                                    &m_borderGeometry,
620                                    combinedMatrix,
621                                    cameraCenter,
622                                    Qt::SquareCap,
623                                    true,
624                                    30); // No LOD for polygons just yet.
625                                         // First figure out what to do with holes.
626             m_borderGeometry.setPreserveGeometry(false);
627             m_borderGeometry.markClean();
628         } else {
629             m_polylinenode->setSubtreeBlocked(true);
630         }
631         if (m_geometry.isScreenDirty()) {
632             m_node->update(m_poly.m_color,
633                          &m_geometry,
634                          combinedMatrix,
635                          cameraCenter);
636             m_geometry.setPreserveGeometry(false);
637             m_geometry.markClean();
638         } else {
639             m_node->setSubtreeBlocked(true);
640         }
641 
642         m_rootNode->setSubtreeBlocked(false);
643         return m_rootNode;
644     }
contains(const QPointF & point)645     bool contains(const QPointF &point) const override
646     {
647         const qreal lineWidth = m_poly.m_border.width();
648         const QColor &lineColor = m_poly.m_border.color();
649         const QRectF &bounds = (lineColor.alpha() != 0 && lineWidth > 0) ? m_borderGeometry.sourceBoundingBox() : m_geometry.sourceBoundingBox();
650         if (bounds.contains(point)) {
651             QDeclarativeGeoMap *m = m_poly.quickMap();
652             if (m) {
653                 const QGeoCoordinate crd = m->toCoordinate(m->mapFromItem(&m_poly, point));
654                 return  m_poly.m_geopoly.contains(crd) || m_borderGeometry.contains(m_poly.mapToItem(m_poly.quickMap(), point),
655                                                                               m_poly.border()->width(),
656                                                                               static_cast<const QGeoProjectionWebMercator&>(m_poly.map()->geoProjection()));
657             } else {
658                 return  true;
659             }
660         }
661         return false;
662     }
663 
664     QGeoMapPolygonGeometryOpenGL m_geometry;
665     QGeoMapPolylineGeometryOpenGL m_borderGeometry;
666     RootNode *m_rootNode = nullptr;
667     MapPolygonNodeGL *m_node = nullptr;
668     MapPolylineNodeOpenGLExtruded *m_polylinenode = nullptr;
669 };
670 #endif // QT_CONFIG(opengl)
671 
672 QT_END_NAMESPACE
673 
674 #endif // QDECLARATIVEPOLYGONMAPITEM_P_P_H
675