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