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 QDECLARATIVEPOLYLINEMAPITEM_P_P_H
39 #define QDECLARATIVEPOLYLINEMAPITEM_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/qdeclarativepolylinemapitem_p.h>
54 #include <QtLocation/private/qdeclarativegeomapitemutils_p.h>
55 #include <QtLocation/private/qdeclarativepolylinemapitem_p.h>
56 #include <QtLocation/private/qgeomapitemgeometry_p.h>
57 #include <QSGGeometryNode>
58 #include <QSGFlatColorMaterial>
59 #include <QtPositioning/QGeoPath>
60 #include <QtPositioning/QGeoPolygon>
61 #include <QtPositioning/QGeoRectangle>
62 #include <QtPositioning/QGeoCircle>
63 #include <QtPositioning/private/qdoublevector2d_p.h>
64 #include <QtCore/QScopedValueRollback>
65 #include <QSharedPointer>
66 #include <array>
67 
68 QT_BEGIN_NAMESPACE
69 
70 class Q_LOCATION_PRIVATE_EXPORT QGeoMapPolylineGeometry : public QGeoMapItemGeometry
71 {
72 public:
73     QGeoMapPolylineGeometry();
74 
75     void updateSourcePoints(const QGeoMap &map,
76                             const QList<QDoubleVector2D> &path,
77                             const QGeoCoordinate geoLeftBound);
78 
79     void updateScreenPoints(const QGeoMap &map,
80                             qreal strokeWidth,
81                             bool adjustTranslation = true);
82 
83     void clearSource();
84 
85     bool contains(const QPointF &point) const override;
86 
87     QList<QList<QDoubleVector2D> > clipPath(const QGeoMap &map,
88                     const QList<QDoubleVector2D> &path,
89                     QDoubleVector2D &leftBoundWrapped);
90 
91     void pathToScreen(const QGeoMap &map,
92                       const QList<QList<QDoubleVector2D> > &clippedPaths,
93                       const QDoubleVector2D &leftBoundWrapped);
94 
95 public:
96     QVector<qreal> srcPoints_;
97     QVector<QPainterPath::ElementType> srcPointTypes_;
98 
99 #ifdef QT_LOCATION_DEBUG
100     QList<QDoubleVector2D> m_wrappedPath;
101     QList<QList<QDoubleVector2D>> m_clippedPaths;
102 #endif
103 
104     friend class QDeclarativeCircleMapItem;
105     friend class QDeclarativePolygonMapItem;
106     friend class QDeclarativeRectangleMapItem;
107 };
108 
109 class Q_LOCATION_PRIVATE_EXPORT VisibleNode
110 {
111 public:
112     VisibleNode();
113     virtual ~VisibleNode();
114 
115     bool subtreeBlocked() const;
116     void setSubtreeBlocked(bool blocked);
117     bool visible() const;
118     void setVisible(bool visible);
119 
120     bool m_blocked : 1;
121     bool m_visible : 1;
122 };
123 
124 class Q_LOCATION_PRIVATE_EXPORT MapItemGeometryNode : public QSGGeometryNode, public VisibleNode
125 {
126 public:
127     ~MapItemGeometryNode() override;
128     bool isSubtreeBlocked() const override;
129 };
130 
131 class Q_LOCATION_PRIVATE_EXPORT MapPolylineMaterial : public QSGFlatColorMaterial
132 {
133 public:
MapPolylineMaterial()134     MapPolylineMaterial()
135         : QSGFlatColorMaterial()
136     {
137         // Passing RequiresFullMatrix is essential in order to prevent the
138         // batch renderer from baking in simple, translate-only transforms into
139         // the vertex data. The shader will rely on the fact that
140         // vertexCoord.xy is the Shape-space coordinate and so no modifications
141         // are welcome.
142         setFlag(Blending | RequiresFullMatrix | CustomCompileStep);
143     }
144 
145     QSGMaterialShader *createShader() const override;
146 
setGeoProjection(const QMatrix4x4 & p)147     void setGeoProjection(const QMatrix4x4 &p)
148     {
149         m_geoProjection = p;
150     }
151 
geoProjection()152     QMatrix4x4 geoProjection() const
153     {
154         return m_geoProjection;
155     }
156 
setCenter(const QDoubleVector3D & c)157     void setCenter(const QDoubleVector3D &c)
158     {
159         m_center = c;
160     }
161 
center()162     QDoubleVector3D center() const
163     {
164         return m_center;
165     }
166 
setColor(const QColor & color)167     void setColor(const QColor &color)
168     {
169         QSGFlatColorMaterial::setColor(color);
170         setFlag(Blending, true); // ToDo: Needed only temporarily, can be removed after debugging
171     }
172 
wrapOffset()173     int wrapOffset() const
174     {
175         return m_wrapOffset;
176     }
177 
setWrapOffset(int wrapOffset)178     void setWrapOffset(int wrapOffset)
179     {
180         m_wrapOffset = wrapOffset;
181     }
182 
setLineWidth(const float lw)183     void setLineWidth(const float lw)
184     {
185         m_lineWidth = lw;
186     }
187 
lineWidth()188     float lineWidth() const
189     {
190         return m_lineWidth;
191     }
192 
193     QSGMaterialType *type() const override;
194     int compare(const QSGMaterial *other) const override;
195 
196 protected:
197     QMatrix4x4 m_geoProjection;
198     QDoubleVector3D m_center;
199     int m_wrapOffset = 0;
200     float m_lineWidth = 1.0;
201 };
202 
203 class Q_LOCATION_PRIVATE_EXPORT MapPolylineNode : public MapItemGeometryNode
204 {
205 public:
206     MapPolylineNode();
207     ~MapPolylineNode() override;
208 
209     void update(const QColor &fillColor, const QGeoMapItemGeometry *shape);
210 
211 protected:
212     QSGFlatColorMaterial fill_material_;
213     QSGGeometry geometry_;
214 };
215 
216 class Q_LOCATION_PRIVATE_EXPORT QGeoMapItemLODGeometry
217 {
218 public:
219     mutable std::array<QSharedPointer<QVector<QDeclarativeGeoMapItemUtils::vec2>>, 7> m_verticesLOD; // fix it to 7,
220                                                                              // do not allow simplifications beyond ZL 20. This could actually be limited even further
221     mutable QVector<QDeclarativeGeoMapItemUtils::vec2> *m_screenVertices;
222     mutable QSharedPointer<unsigned int> m_working;
223 
QGeoMapItemLODGeometry()224     QGeoMapItemLODGeometry()
225     {
226         resetLOD();
227     }
228 
resetLOD()229     void resetLOD()
230     {
231         // New pointer, some old LOD task might still be running and operating on the old pointers.
232         m_verticesLOD[0] = QSharedPointer<QVector<QDeclarativeGeoMapItemUtils::vec2>>(
233                             new QVector<QDeclarativeGeoMapItemUtils::vec2>);
234         for (unsigned int i = 1; i < m_verticesLOD.size(); ++i)
235             m_verticesLOD[i] = nullptr; // allocate on first use
236         m_screenVertices = m_verticesLOD.front().data(); // resetting pointer to data to be LOD 0
237     }
238 
239     static unsigned int zoomToLOD(unsigned int zoom);
240 
241     static unsigned int zoomForLOD(unsigned int zoom);
242 
243     bool isLODActive(unsigned int lod) const;
244 
245     void selectLOD(unsigned int zoom, double leftBound, bool /*closed*/);
246 
247     static QVector<QDeclarativeGeoMapItemUtils::vec2> getSimplified (
248             QVector<QDeclarativeGeoMapItemUtils::vec2> &wrappedPath,
249                               double leftBoundWrapped,
250                               unsigned int zoom);
251 
252     static void enqueueSimplificationTask(const QSharedPointer<QVector<QDeclarativeGeoMapItemUtils::vec2> > &input, // reference as it gets copied in the nested call
253                               const QSharedPointer<QVector<QDeclarativeGeoMapItemUtils::vec2> > &output,
254                               double leftBound,
255                               unsigned int zoom,
256                               QSharedPointer<unsigned int> &working);
257 
258     void selectLODOnDataChanged(unsigned int zoom, double leftBound) const;
259 
selectLODOnLODMismatch(unsigned int zoom,double leftBound,bool closed)260     bool selectLODOnLODMismatch(unsigned int zoom, double leftBound, bool closed) const
261     {
262         if (*m_working > 0) {
263             return false;
264         }
265         const_cast<QGeoMapItemLODGeometry *>(this)->selectLOD(zoom,
266                  leftBound,
267                  closed);
268         return true;
269     }
270 };
271 
272 class Q_LOCATION_PRIVATE_EXPORT QGeoMapPolylineGeometryOpenGL : public QGeoMapItemGeometry, public QGeoMapItemLODGeometry
273 {
274 public:
275     typedef struct {
276         QList<QDoubleVector2D> wrappedBboxes;
277     } WrappedPolyline;
278 
QGeoMapPolylineGeometryOpenGL()279     QGeoMapPolylineGeometryOpenGL()
280     {
281         m_working = QSharedPointer<unsigned int>(new unsigned int(0));
282     }
283 
284     void updateSourcePoints(const QGeoMap &map,
285                             const QGeoPolygon &poly);
286 
287     void updateSourcePoints(const QGeoMap &map,
288                             const QGeoPath &poly);
289 
290     void updateSourcePoints(const QGeoProjectionWebMercator &p,
291                             const QList<QDoubleVector2D> &wrappedPath,
292                             const QGeoRectangle &boundingRectangle);
293 
294     void updateSourcePoints(const QGeoMap &map,
295                             const QGeoRectangle &rect);
296 
297     void updateSourcePoints(const QGeoMap &map,
298                             const QGeoCircle &circle);
299 
300     void updateScreenPoints(const QGeoMap &map,
301                             qreal strokeWidth,
302                             bool adjustTranslation = true);
303 
304     void updateQuickGeometry(const QGeoProjectionWebMercator &p, qreal strokeWidth = 0.0);
305 
306     bool allocateAndFillEntries(QSGGeometry *geom,
307                                 bool closed = false,
308                                 unsigned int zoom = 0) const;
309     void allocateAndFillLineStrip(QSGGeometry *geom,
310                                   int lod = 0) const;
311 
contains(const QPointF & point)312     bool contains(const QPointF &point) const override
313     {
314         Q_UNUSED(point)
315         return false;
316     }
317 
distanceTo(const QDoubleVector2D & a,const QDoubleVector2D & b,const QDoubleVector2D & p)318     static double distanceTo(const QDoubleVector2D &a, const QDoubleVector2D &b, const QDoubleVector2D &p)
319     {
320         double u = ((p.x() - a.x()) * (b.x() - a.x()) + (p.y() - a.y()) * (b.y() - a.y()) ) / (b - a).lengthSquared();
321         QDoubleVector2D intersection(a.x() + u * (b.x() - a.x()) , a.y() + u * (b.y() - a.y()) );
322 
323         QDoubleVector2D candidate = ( (p-a).length() < (p-b).length() ) ? a : b;
324 
325         if (u > 0 && u < 1
326             && (p-intersection).length() < (p-candidate).length()  ) // And it falls in the segment
327                 candidate = intersection;
328 
329         return qAbs((candidate - p).length());
330     }
331     // Note: this is also slightly incorrect on joins and in the beginning/end of the line
contains(const QPointF & point,qreal lineWidth,const QGeoProjectionWebMercator & p)332     bool contains(const QPointF &point, qreal lineWidth, const QGeoProjectionWebMercator &p) const
333     {
334         const double lineHalfWidth = lineWidth * 0.5;
335         const QDoubleVector2D pt(point);
336         QDoubleVector2D a;
337         if (m_screenVertices->size())
338             a = p.wrappedMapProjectionToItemPosition(p.wrapMapProjection(m_screenVertices->first().toDoubleVector2D()));
339         QDoubleVector2D b;
340         for (int i = 1; i < m_screenVertices->size(); ++i)
341         {
342             if (!a.isFinite()) {
343                 a = p.wrappedMapProjectionToItemPosition(p.wrapMapProjection(m_screenVertices->at(i).toDoubleVector2D()));
344                 continue;
345             }
346 
347             b = p.wrappedMapProjectionToItemPosition(p.wrapMapProjection(m_screenVertices->at(i).toDoubleVector2D()));
348             if (!b.isFinite()) {
349                 a = b;
350                 continue;
351             }
352 
353             if (b == a)
354                 continue;
355 
356             // Heavily simplifying it here: if a point is not projectable, skip the segment.
357             // For a correct solution, the segment should be clipped instead.
358             if (distanceTo(a, b, pt) <= lineHalfWidth)
359                 return true;
360 
361             a = b;
362         }
363         return false;
364     }
365 
366 public:
367     QDoubleVector2D m_bboxLeftBoundWrapped;
368     QVector<WrappedPolyline> m_wrappedPolygons;
369     int m_wrapOffset;
370 
371     friend class QDeclarativeCircleMapItem;
372     friend class QDeclarativePolygonMapItem;
373     friend class QDeclarativeRectangleMapItem;
374 };
375 
376 class Q_LOCATION_PRIVATE_EXPORT MapPolylineShaderLineStrip : public QSGMaterialShader
377 {
378 public:
379     MapPolylineShaderLineStrip();
380 
vertexShader()381     const char *vertexShader() const override {
382         return
383         "attribute highp vec4 vertex;               \n"
384         "uniform highp mat4 qt_Matrix;              \n"
385         "uniform highp mat4 mapProjection;          \n"
386         "uniform highp vec3 center;                 \n"
387         "uniform highp vec3 center_lowpart;         \n"
388         "uniform lowp float wrapOffset;             \n"
389         "vec4 wrapped(in vec4 v) { return vec4(v.x + wrapOffset, v.y, 0.0, 1.0); }\n"
390         "void main() {                              \n"
391         "    vec4 vtx = wrapped(vertex) - vec4(center, 0.0);   \n"
392         "    vtx = vtx - vec4(center_lowpart, 0.0);   \n"
393         "    gl_Position = qt_Matrix * mapProjection * vtx;      \n"
394         "}";
395     }
396 
fragmentShader()397     const char *fragmentShader() const override {
398         return
399         "uniform lowp vec4 color;                   \n"
400         "void main() {                              \n"
401         "    gl_FragColor = color;                  \n"
402         "}";
403     }
404 
405     void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
406     char const *const *attributeNames() const override;
407 
408 protected:
initialize()409     void initialize() override
410     {
411         m_matrix_id = program()->uniformLocation("qt_Matrix");
412         m_color_id = program()->uniformLocation("color");
413         m_mapProjection_id = program()->uniformLocation("mapProjection");
414         m_center_id = program()->uniformLocation("center");
415         m_center_lowpart_id = program()->uniformLocation("center_lowpart");
416         m_wrapOffset_id = program()->uniformLocation("wrapOffset");
417     }
418     int m_center_id;
419     int m_center_lowpart_id;
420     int m_mapProjection_id;
421     int m_matrix_id;
422     int m_color_id;
423     int m_wrapOffset_id;
424 };
425 
426 class Q_LOCATION_PRIVATE_EXPORT MapPolylineShaderExtruded : public QSGMaterialShader
427 {
428 public:
429     MapPolylineShaderExtruded();
430 
431     // Heavily adapted from https://github.com/mattdesl/webgl-lines/blob/master/projected/vert.glsl,
432     // that is (c) Matt DesLauriers, and released under the MIT license.
433     const char *vertexShaderMiteredSegments() const;
434 
vertexShader()435     const char *vertexShader() const override
436     {
437         return vertexShaderMiteredSegments();
438     }
439 
fragmentShader()440     const char *fragmentShader() const override
441     {
442         return
443         "varying vec4 primitivecolor;           \n"
444         "void main() {                          \n"
445         "    gl_FragColor = primitivecolor;     \n"
446         "}";
447     }
448 
449     void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
450     char const *const *attributeNames() const override;
451 
452 protected:
initialize()453     void initialize() override
454     {
455         m_matrix_id = program()->uniformLocation("qt_Matrix");
456         m_color_id = program()->uniformLocation("color");
457         m_mapProjection_id = program()->uniformLocation("mapProjection");
458         m_center_id = program()->uniformLocation("center");
459         m_center_lowpart_id = program()->uniformLocation("center_lowpart");
460         m_lineWidth_id = program()->uniformLocation("lineWidth");
461         m_aspect_id = program()->uniformLocation("aspect");
462         m_miter_id = program()->uniformLocation("miter");
463         m_wrapOffset_id = program()->uniformLocation("wrapOffset");
464     }
465     int m_center_id;
466     int m_center_lowpart_id;
467     int m_mapProjection_id;
468     int m_matrix_id;
469     int m_color_id;
470     int m_lineWidth_id;
471     int m_aspect_id;
472     int m_miter_id;
473     int m_wrapOffset_id;
474 };
475 
476 class Q_LOCATION_PRIVATE_EXPORT MapPolylineNodeOpenGLLineStrip : public MapItemGeometryNode
477 {
478 public:
479     MapPolylineNodeOpenGLLineStrip();
480     ~MapPolylineNodeOpenGLLineStrip() override;
481 
482     void update(const QColor &fillColor,
483                 const qreal lineWidth,
484                 const QGeoMapPolylineGeometryOpenGL *shape,
485                 const QMatrix4x4 &geoProjection,
486                 const QDoubleVector3D &center,
487                 const Qt::PenCapStyle capStyle = Qt::SquareCap);
488 
489 protected:
490     MapPolylineMaterial fill_material_;
491     QSGGeometry geometry_;
492 };
493 
494 class Q_LOCATION_PRIVATE_EXPORT MapPolylineMaterialExtruded : public MapPolylineMaterial
495 {
496 public:
MapPolylineMaterialExtruded()497     MapPolylineMaterialExtruded() : MapPolylineMaterial()
498     {
499 
500     }
501     QSGMaterialShader *createShader() const override;
502 
setMiter(const int m)503     void setMiter(const int m)
504     {
505         m_miter = m;
506     }
507 
miter()508     int miter() const
509     {
510         return m_miter;
511     }
512 
513     QSGMaterialType *type() const override;
514     int compare(const QSGMaterial *other) const override;
515 
516     int m_miter = 0;
517 };
518 
519 class Q_LOCATION_PRIVATE_EXPORT MapPolylineNodeOpenGLExtruded : public MapItemGeometryNode
520 {
521 public:
522 
523     typedef struct {
524          QDeclarativeGeoMapItemUtils::vec2 pos;
525          QDeclarativeGeoMapItemUtils::vec2 prev;
526          QDeclarativeGeoMapItemUtils::vec2 next;
527          float direction;
528          float triangletype; // es2 does not support int attribs
529          float vertextype;
530 
attributeNames__anon5aab72870208531          static const char * const *attributeNames()
532          {
533              static char const *const attr[] = { "vertex", "previous", "next", "direction", "triangletype", "vertextype", nullptr };
534              return attr;
535          }
attributes__anon5aab72870208536          static const QSGGeometry::AttributeSet &attributes()
537          {
538              static const QSGGeometry::Attribute dataTri[] = {
539                  QSGGeometry::Attribute::createWithAttributeType(0, 2, QSGGeometry::FloatType, QSGGeometry::PositionAttribute) // pos
540                  ,QSGGeometry::Attribute::createWithAttributeType(1, 2, QSGGeometry::FloatType, QSGGeometry::UnknownAttribute) // next
541                  ,QSGGeometry::Attribute::createWithAttributeType(2, 2, QSGGeometry::FloatType, QSGGeometry::UnknownAttribute) // previous
542                  ,QSGGeometry::Attribute::createWithAttributeType(3, 1, QSGGeometry::FloatType, QSGGeometry::UnknownAttribute)  // direction
543                  ,QSGGeometry::Attribute::createWithAttributeType(4, 1, QSGGeometry::FloatType, QSGGeometry::UnknownAttribute)  // triangletype
544                  ,QSGGeometry::Attribute::createWithAttributeType(5, 1, QSGGeometry::FloatType, QSGGeometry::UnknownAttribute)  // vertextype
545              };
546              static const QSGGeometry::AttributeSet attrsTri = { 6, sizeof(MapPolylineNodeOpenGLExtruded::MapPolylineEntry), dataTri };
547              return attrsTri;
548          }
549     } MapPolylineEntry;
550 
551     MapPolylineNodeOpenGLExtruded();
552     ~MapPolylineNodeOpenGLExtruded() override;
553 
554     void update(const QColor &fillColor,
555                 const float lineWidth,
556                 const QGeoMapPolylineGeometryOpenGL *shape,
557                 const QMatrix4x4 geoProjection,
558                 const QDoubleVector3D center,
559                 const Qt::PenCapStyle capStyle = Qt::FlatCap,
560                 bool closed = false,
561                 unsigned int zoom = 30);
562 
563     static const QSGGeometry::AttributeSet &attributesMapPolylineTriangulated();
564 
565 protected:
566     MapPolylineMaterialExtruded fill_material_;
567     QSGGeometry m_geometryTriangulating;
568 };
569 
570 class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolylineMapItemPrivate
571 {
572 public:
QDeclarativePolylineMapItemPrivate(QDeclarativePolylineMapItem & poly)573     QDeclarativePolylineMapItemPrivate(QDeclarativePolylineMapItem &poly) : m_poly(poly)
574     {
575 
576     }
QDeclarativePolylineMapItemPrivate(QDeclarativePolylineMapItemPrivate & other)577     QDeclarativePolylineMapItemPrivate(QDeclarativePolylineMapItemPrivate &other) : m_poly(other.m_poly)
578     {
579     }
580 
581     virtual ~QDeclarativePolylineMapItemPrivate();
582     virtual void markSourceDirtyAndUpdate() = 0;
583     virtual void onMapSet() = 0;
584     virtual void onLinePropertiesChanged() = 0;
585     virtual void onGeoGeometryChanged() = 0;
586     virtual void onGeoGeometryUpdated() = 0;
587     virtual void onItemGeometryChanged() = 0;
588     virtual void updatePolish() = 0;
589     virtual void afterViewportChanged() = 0;
590     virtual QSGNode * updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) = 0;
591     virtual bool contains(const QPointF &point) const = 0;
592 
593     QDeclarativePolylineMapItem &m_poly;
594     Qt::PenStyle m_penStyle = Qt::SolidLine;
595     Qt::PenCapStyle m_penCapStyle = Qt::SquareCap;
596 };
597 
598 class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolylineMapItemPrivateCPU: public QDeclarativePolylineMapItemPrivate
599 {
600 public:
QDeclarativePolylineMapItemPrivateCPU(QDeclarativePolylineMapItem & poly)601     QDeclarativePolylineMapItemPrivateCPU(QDeclarativePolylineMapItem &poly) : QDeclarativePolylineMapItemPrivate(poly)
602     {
603     }
604 
QDeclarativePolylineMapItemPrivateCPU(QDeclarativePolylineMapItemPrivate & other)605     QDeclarativePolylineMapItemPrivateCPU(QDeclarativePolylineMapItemPrivate &other)
606     : QDeclarativePolylineMapItemPrivate(other)
607     {
608     }
609 
610     ~QDeclarativePolylineMapItemPrivateCPU() override;
onLinePropertiesChanged()611     void onLinePropertiesChanged() override
612     {
613         // mark dirty just in case we're a width change
614         markSourceDirtyAndUpdate();
615     }
markSourceDirtyAndUpdate()616     void markSourceDirtyAndUpdate() override
617     {
618         m_geometry.markSourceDirty();
619         m_poly.polishAndUpdate();
620     }
regenerateCache()621     void regenerateCache()
622     {
623         if (!m_poly.map() || m_poly.map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator)
624             return;
625         const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_poly.map()->geoProjection());
626         m_geopathProjected.clear();
627         m_geopathProjected.reserve(m_poly.m_geopath.size());
628         for (const QGeoCoordinate &c : m_poly.m_geopath.path())
629             m_geopathProjected << p.geoToMapProjection(c);
630     }
updateCache()631     void updateCache()
632     {
633         if (!m_poly.map() || m_poly.map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator)
634             return;
635         const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_poly.map()->geoProjection());
636         m_geopathProjected << p.geoToMapProjection(m_poly.m_geopath.path().last());
637     }
preserveGeometry()638     void preserveGeometry()
639     {
640         m_geometry.setPreserveGeometry(true, m_poly.m_geopath.boundingGeoRectangle().topLeft());
641     }
afterViewportChanged()642     void afterViewportChanged() override
643     {
644         // preserveGeometry is cleared in updateMapItemPaintNode
645         preserveGeometry();
646         markSourceDirtyAndUpdate();
647     }
onMapSet()648     void onMapSet() override
649     {
650         regenerateCache();
651         markSourceDirtyAndUpdate();
652     }
onGeoGeometryChanged()653     void onGeoGeometryChanged() override
654     {
655         regenerateCache();
656         preserveGeometry();
657         markSourceDirtyAndUpdate();
658     }
onGeoGeometryUpdated()659     void onGeoGeometryUpdated() override
660     {
661         updateCache();
662         preserveGeometry();
663         markSourceDirtyAndUpdate();
664     }
onItemGeometryChanged()665     void onItemGeometryChanged() override
666     {
667         onGeoGeometryChanged();
668     }
updatePolish()669     void updatePolish() override
670     {
671         if (m_poly.m_geopath.path().length() < 2) { // Possibly cleared
672             m_geometry.clear();
673             m_poly.setWidth(0);
674             m_poly.setHeight(0);
675             return;
676         }
677         QScopedValueRollback<bool> rollback(m_poly.m_updatingGeometry);
678         m_poly.m_updatingGeometry = true;
679 
680         const QGeoMap *map = m_poly.map();
681         const qreal borderWidth = m_poly.m_line.width();
682 
683         m_geometry.updateSourcePoints(*map, m_geopathProjected, m_poly.m_geopath.boundingGeoRectangle().topLeft());
684         m_geometry.updateScreenPoints(*map, borderWidth);
685 
686         m_poly.setWidth(m_geometry.sourceBoundingBox().width() + borderWidth);
687         m_poly.setHeight(m_geometry.sourceBoundingBox().height() + borderWidth);
688 
689         m_poly.setPositionOnMap(m_geometry.origin(), -1 * m_geometry.sourceBoundingBox().topLeft()
690                                 + QPointF(borderWidth, borderWidth) * 0.5 ); // it has to be shifted so that the center of the line is on the correct geocoord
691     }
updateMapItemPaintNode(QSGNode * oldNode,QQuickItem::UpdatePaintNodeData *)692     QSGNode *updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData * /*data*/) override
693     {
694         if (!m_node || !oldNode) {
695             m_node = new MapPolylineNode();
696             if (oldNode) {
697                 delete oldNode;
698                 oldNode = nullptr;
699             }
700         } else {
701             m_node = static_cast<MapPolylineNode *>(oldNode);
702         }
703 
704         //TODO: update only material
705         if (m_geometry.isScreenDirty() || m_poly.m_dirtyMaterial || !oldNode) {
706             m_node->update(m_poly.m_line.color(), &m_geometry);
707             m_geometry.setPreserveGeometry(false);
708             m_geometry.markClean();
709             m_poly.m_dirtyMaterial = false;
710         }
711         return m_node;
712     }
contains(const QPointF & point)713     bool contains(const QPointF &point) const override
714     {
715         return m_geometry.contains(point);
716     }
717 
718     QList<QDoubleVector2D> m_geopathProjected;
719     QGeoMapPolylineGeometry m_geometry;
720     MapPolylineNode *m_node = nullptr;
721 };
722 
723 class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolylineMapItemPrivateOpenGLLineStrip: public QDeclarativePolylineMapItemPrivate
724 {
725 public:
726 
QDeclarativePolylineMapItemPrivateOpenGLLineStrip(QDeclarativePolylineMapItem & poly)727     QDeclarativePolylineMapItemPrivateOpenGLLineStrip(QDeclarativePolylineMapItem &poly) : QDeclarativePolylineMapItemPrivate(poly)
728     {
729     }
730 
QDeclarativePolylineMapItemPrivateOpenGLLineStrip(QDeclarativePolylineMapItemPrivate & other)731     QDeclarativePolylineMapItemPrivateOpenGLLineStrip(QDeclarativePolylineMapItemPrivate &other)
732     : QDeclarativePolylineMapItemPrivate(other)
733     {
734     }
735 
736     ~QDeclarativePolylineMapItemPrivateOpenGLLineStrip() override;
onLinePropertiesChanged()737     void onLinePropertiesChanged() override
738     {
739         afterViewportChanged();
740     }
markSourceDirtyAndUpdate()741     void markSourceDirtyAndUpdate() override
742     {
743         m_geometry.markSourceDirty();
744         m_poly.polishAndUpdate();
745     }
preserveGeometry()746     void preserveGeometry()
747     {
748         m_geometry.setPreserveGeometry(true, m_poly.m_geopath.boundingGeoRectangle().topLeft());
749     }
onMapSet()750     void onMapSet() override
751     {
752         markSourceDirtyAndUpdate();
753     }
onGeoGeometryChanged()754     void onGeoGeometryChanged() override
755     {
756         preserveGeometry();
757         markSourceDirtyAndUpdate();
758     }
onGeoGeometryUpdated()759     void onGeoGeometryUpdated() override
760     {
761         preserveGeometry();
762         markSourceDirtyAndUpdate();
763     }
onItemGeometryChanged()764     void onItemGeometryChanged() override
765     {
766         onGeoGeometryChanged();
767     }
afterViewportChanged()768     void afterViewportChanged() override
769     {
770         preserveGeometry();
771         m_poly.polishAndUpdate();
772     }
contains(const QPointF & point)773     bool contains(const QPointF &point) const override
774     {
775         return m_geometry.contains(m_poly.mapToItem(m_poly.quickMap(), point),
776                                    m_poly.line()->width(),
777                                    static_cast<const QGeoProjectionWebMercator&>(m_poly.map()->geoProjection()));
778     }
updatePolish()779     void updatePolish() override
780     {
781         if (m_poly.m_geopath.path().length() == 0) { // Possibly cleared
782             m_geometry.clear();
783             m_geometry.clear();
784             m_poly.setWidth(0);
785             m_poly.setHeight(0);
786             return;
787         }
788 
789         QScopedValueRollback<bool> rollback(m_poly.m_updatingGeometry);
790         m_poly.m_updatingGeometry = true;
791         const qreal lineWidth = m_poly.m_line.width();
792         m_geometry.updateSourcePoints(*m_poly.map(), m_poly.m_geopath);
793         m_geometry.markScreenDirty();
794         m_geometry.updateScreenPoints(*m_poly.map(), lineWidth);
795 
796         m_poly.setWidth(m_geometry.sourceBoundingBox().width());
797         m_poly.setHeight(m_geometry.sourceBoundingBox().height());
798         m_poly.setPosition(1.0 * m_geometry.firstPointOffset() - QPointF(lineWidth * 0.5,lineWidth * 0.5));
799     }
updateMapItemPaintNode(QSGNode * oldNode,QQuickItem::UpdatePaintNodeData * data)800     QSGNode * updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) override
801     {
802         Q_UNUSED(data);
803 
804         if (!m_node || !oldNode) {
805             m_node = new MapPolylineNodeOpenGLLineStrip();
806             if (oldNode)
807                 delete oldNode;
808         } else {
809             m_node = static_cast<MapPolylineNodeOpenGLLineStrip *>(oldNode);
810         }
811 
812         if (m_geometry.isScreenDirty() || m_poly.m_dirtyMaterial) {
813             const QGeoMap *map = m_poly.map();
814             const QMatrix4x4 &combinedMatrix = map->geoProjection().qsgTransform();
815             const QDoubleVector3D &cameraCenter = map->geoProjection().centerMercator();
816             m_node->update(m_poly.m_line.color(), // This updates only the material if the geometry is unchanged
817                            m_poly.m_line.width(),
818                          &m_geometry,
819                          combinedMatrix,
820                          cameraCenter);
821             m_geometry.setPreserveGeometry(false);
822             m_geometry.markClean();
823             m_poly.m_dirtyMaterial = false;
824         }
825         return m_node;
826     }
827 
828     QGeoMapPolylineGeometryOpenGL m_geometry;
829     MapPolylineNodeOpenGLLineStrip *m_node = nullptr;
830 };
831 
832 class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolylineMapItemPrivateOpenGLExtruded: public QDeclarativePolylineMapItemPrivateOpenGLLineStrip
833 {
834 public:
835 
QDeclarativePolylineMapItemPrivateOpenGLExtruded(QDeclarativePolylineMapItem & poly)836     QDeclarativePolylineMapItemPrivateOpenGLExtruded(QDeclarativePolylineMapItem &poly)
837     : QDeclarativePolylineMapItemPrivateOpenGLLineStrip(poly)
838     {
839     }
840 
QDeclarativePolylineMapItemPrivateOpenGLExtruded(QDeclarativePolylineMapItemPrivate & other)841     QDeclarativePolylineMapItemPrivateOpenGLExtruded(QDeclarativePolylineMapItemPrivate &other)
842     : QDeclarativePolylineMapItemPrivateOpenGLLineStrip(other)
843     {
844     }
845 
846     ~QDeclarativePolylineMapItemPrivateOpenGLExtruded() override;
847 
updateMapItemPaintNode(QSGNode * oldNode,QQuickItem::UpdatePaintNodeData * data)848     QSGNode * updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) override
849     {
850         Q_UNUSED(data);
851         const QGeoMap *map = m_poly.map();
852         const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map->geoProjection());
853         const QMatrix4x4 &combinedMatrix = p.qsgTransform();
854         const QDoubleVector3D &cameraCenter = p.centerMercator();
855         const QColor &color = m_poly.m_line.color();
856         const float lineWidth = m_poly.m_line.width();
857 
858         MapPolylineNodeOpenGLExtruded *nodeTri = nullptr;
859         if (!m_nodeTri || !oldNode) {
860             if (oldNode)
861                 delete oldNode;
862             nodeTri = new MapPolylineNodeOpenGLExtruded();
863         } else {
864             nodeTri = static_cast<MapPolylineNodeOpenGLExtruded *>(oldNode);
865         }
866 
867         //TODO: update only material
868         if (m_geometry.isScreenDirty() || m_poly.m_dirtyMaterial) {
869             nodeTri->update(color,
870                          lineWidth  ,
871                          &m_geometry,
872                          combinedMatrix,
873                          cameraCenter,
874                          m_penCapStyle,
875                          false,
876                          m_poly.zoomForLOD(int(map->cameraData().zoomLevel())));
877             m_geometry.setPreserveGeometry(false);
878             m_geometry.markClean();
879             m_poly.m_dirtyMaterial = false;
880         }
881         m_nodeTri = nodeTri;
882         return nodeTri;
883     }
884 
885     MapPolylineNodeOpenGLExtruded *m_nodeTri = nullptr;
886 };
887 
888 QT_END_NAMESPACE
889 
890 #endif // QDECLARATIVEPOLYLINEMAPITEM_P_P_H
891