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
68QT_BEGIN_NAMESPACE
69
70class Q_LOCATION_PRIVATE_EXPORT QGeoMapPolylineGeometry : public QGeoMapItemGeometry
71{
72public:
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
95public:
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
109class Q_LOCATION_PRIVATE_EXPORT VisibleNode
110{
111public:
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
124class Q_LOCATION_PRIVATE_EXPORT MapItemGeometryNode : public QSGGeometryNode, public VisibleNode
125{
126public:
127 ~MapItemGeometryNode() override;
128 bool isSubtreeBlocked() const override;
129};
130
131class Q_LOCATION_PRIVATE_EXPORT MapPolylineMaterial : public QSGFlatColorMaterial
132{
133public:
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(flags: Blending | RequiresFullMatrix | CustomCompileStep);
143 }
144
145 QSGMaterialShader *createShader() const override;
146
147 void setGeoProjection(const QMatrix4x4 &p)
148 {
149 m_geoProjection = p;
150 }
151
152 QMatrix4x4 geoProjection() const
153 {
154 return m_geoProjection;
155 }
156
157 void setCenter(const QDoubleVector3D &c)
158 {
159 m_center = c;
160 }
161
162 QDoubleVector3D center() const
163 {
164 return m_center;
165 }
166
167 void setColor(const QColor &color)
168 {
169 QSGFlatColorMaterial::setColor(color);
170 setFlag(flags: Blending, on: true); // ToDo: Needed only temporarily, can be removed after debugging
171 }
172
173 int wrapOffset() const
174 {
175 return m_wrapOffset;
176 }
177
178 void setWrapOffset(int wrapOffset)
179 {
180 m_wrapOffset = wrapOffset;
181 }
182
183 void setLineWidth(const float lw)
184 {
185 m_lineWidth = lw;
186 }
187
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
196protected:
197 QMatrix4x4 m_geoProjection;
198 QDoubleVector3D m_center;
199 int m_wrapOffset = 0;
200 float m_lineWidth = 1.0;
201};
202
203class Q_LOCATION_PRIVATE_EXPORT MapPolylineNode : public MapItemGeometryNode
204{
205public:
206 MapPolylineNode();
207 ~MapPolylineNode() override;
208
209 void update(const QColor &fillColor, const QGeoMapItemGeometry *shape);
210
211protected:
212 QSGFlatColorMaterial fill_material_;
213 QSGGeometry geometry_;
214};
215
216#if QT_CONFIG(opengl)
217class Q_LOCATION_PRIVATE_EXPORT QGeoMapItemLODGeometry
218{
219public:
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
225 QGeoMapItemLODGeometry()
226 {
227 resetLOD();
228 }
229
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
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
273class Q_LOCATION_PRIVATE_EXPORT QGeoMapPolylineGeometryOpenGL : public QGeoMapItemGeometry, public QGeoMapItemLODGeometry
274{
275public:
276 typedef struct {
277 QList<QDoubleVector2D> wrappedBboxes;
278 } WrappedPolyline;
279
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
313 bool contains(const QPointF &point) const override
314 {
315 Q_UNUSED(point)
316 return false;
317 }
318
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(t: (candidate - p).length());
331 }
332 // Note: this is also slightly incorrect on joins and in the beginning/end of the line
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(wrappedProjection: p.wrapMapProjection(projection: 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(wrappedProjection: p.wrapMapProjection(projection: m_screenVertices->at(i).toDoubleVector2D()));
345 continue;
346 }
347
348 b = p.wrappedMapProjectionToItemPosition(wrappedProjection: p.wrapMapProjection(projection: 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, p: pt) <= lineHalfWidth)
360 return true;
361
362 a = b;
363 }
364 return false;
365 }
366
367public:
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
377class Q_LOCATION_PRIVATE_EXPORT MapPolylineShaderLineStrip : public QSGMaterialShader
378{
379public:
380 MapPolylineShaderLineStrip();
381
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
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
409protected:
410 void initialize() override
411 {
412 m_matrix_id = program()->uniformLocation(name: "qt_Matrix");
413 m_color_id = program()->uniformLocation(name: "color");
414 m_mapProjection_id = program()->uniformLocation(name: "mapProjection");
415 m_center_id = program()->uniformLocation(name: "center");
416 m_center_lowpart_id = program()->uniformLocation(name: "center_lowpart");
417 m_wrapOffset_id = program()->uniformLocation(name: "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
427class Q_LOCATION_PRIVATE_EXPORT MapPolylineShaderExtruded : public QSGMaterialShader
428{
429public:
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
436 const char *vertexShader() const override
437 {
438 return vertexShaderMiteredSegments();
439 }
440
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
453protected:
454 void initialize() override
455 {
456 m_matrix_id = program()->uniformLocation(name: "qt_Matrix");
457 m_color_id = program()->uniformLocation(name: "color");
458 m_mapProjection_id = program()->uniformLocation(name: "mapProjection");
459 m_center_id = program()->uniformLocation(name: "center");
460 m_center_lowpart_id = program()->uniformLocation(name: "center_lowpart");
461 m_lineWidth_id = program()->uniformLocation(name: "lineWidth");
462 m_aspect_id = program()->uniformLocation(name: "aspect");
463 m_miter_id = program()->uniformLocation(name: "miter");
464 m_wrapOffset_id = program()->uniformLocation(name: "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
477class Q_LOCATION_PRIVATE_EXPORT MapPolylineNodeOpenGLLineStrip : public MapItemGeometryNode
478{
479public:
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
490protected:
491 MapPolylineMaterial fill_material_;
492 QSGGeometry geometry_;
493};
494
495class Q_LOCATION_PRIVATE_EXPORT MapPolylineMaterialExtruded : public MapPolylineMaterial
496{
497public:
498 MapPolylineMaterialExtruded() : MapPolylineMaterial()
499 {
500
501 }
502 QSGMaterialShader *createShader() const override;
503
504 void setMiter(const int m)
505 {
506 m_miter = m;
507 }
508
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
520class Q_LOCATION_PRIVATE_EXPORT MapPolylineNodeOpenGLExtruded : public MapItemGeometryNode
521{
522public:
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
532 static const char * const *attributeNames()
533 {
534 static char const *const attr[] = { "vertex", "previous", "next", "direction", "triangletype", "vertextype", nullptr };
535 return attr;
536 }
537 static const QSGGeometry::AttributeSet &attributes()
538 {
539 static const QSGGeometry::Attribute dataTri[] = {
540 QSGGeometry::Attribute::createWithAttributeType(pos: 0, tupleSize: 2, primitiveType: QSGGeometry::FloatType, attributeType: QSGGeometry::PositionAttribute) // pos
541 ,QSGGeometry::Attribute::createWithAttributeType(pos: 1, tupleSize: 2, primitiveType: QSGGeometry::FloatType, attributeType: QSGGeometry::UnknownAttribute) // next
542 ,QSGGeometry::Attribute::createWithAttributeType(pos: 2, tupleSize: 2, primitiveType: QSGGeometry::FloatType, attributeType: QSGGeometry::UnknownAttribute) // previous
543 ,QSGGeometry::Attribute::createWithAttributeType(pos: 3, tupleSize: 1, primitiveType: QSGGeometry::FloatType, attributeType: QSGGeometry::UnknownAttribute) // direction
544 ,QSGGeometry::Attribute::createWithAttributeType(pos: 4, tupleSize: 1, primitiveType: QSGGeometry::FloatType, attributeType: QSGGeometry::UnknownAttribute) // triangletype
545 ,QSGGeometry::Attribute::createWithAttributeType(pos: 5, tupleSize: 1, primitiveType: QSGGeometry::FloatType, attributeType: QSGGeometry::UnknownAttribute) // vertextype
546 };
547 static const QSGGeometry::AttributeSet attrsTri = { .count: 6, .stride: sizeof(MapPolylineNodeOpenGLExtruded::MapPolylineEntry), .attributes: 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
566protected:
567 MapPolylineMaterialExtruded fill_material_;
568 QSGGeometry m_geometryTriangulating;
569};
570#endif // QT_CONFIG(opengl)
571
572class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolylineMapItemPrivate
573{
574public:
575 QDeclarativePolylineMapItemPrivate(QDeclarativePolylineMapItem &poly) : m_poly(poly)
576 {
577
578 }
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
600class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolylineMapItemPrivateCPU: public QDeclarativePolylineMapItemPrivate
601{
602public:
603 QDeclarativePolylineMapItemPrivateCPU(QDeclarativePolylineMapItem &poly) : QDeclarativePolylineMapItemPrivate(poly)
604 {
605 }
606
607 QDeclarativePolylineMapItemPrivateCPU(QDeclarativePolylineMapItemPrivate &other)
608 : QDeclarativePolylineMapItemPrivate(other)
609 {
610 }
611
612 ~QDeclarativePolylineMapItemPrivateCPU() override;
613 void onLinePropertiesChanged() override
614 {
615 // mark dirty just in case we're a width change
616 markSourceDirtyAndUpdate();
617 }
618 void markSourceDirtyAndUpdate() override
619 {
620 m_geometry.markSourceDirty();
621 m_poly.polishAndUpdate();
622 }
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(alloc: m_poly.m_geopath.size());
630 for (const QGeoCoordinate &c : m_poly.m_geopath.path())
631 m_geopathProjected << p.geoToMapProjection(coordinate: c);
632 }
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(coordinate: m_poly.m_geopath.path().last());
639 }
640 void preserveGeometry()
641 {
642 m_geometry.setPreserveGeometry(value: true, geoLeftBound: m_poly.m_geopath.boundingGeoRectangle().topLeft());
643 }
644 void afterViewportChanged() override
645 {
646 // preserveGeometry is cleared in updateMapItemPaintNode
647 preserveGeometry();
648 markSourceDirtyAndUpdate();
649 }
650 void onMapSet() override
651 {
652 regenerateCache();
653 markSourceDirtyAndUpdate();
654 }
655 void onGeoGeometryChanged() override
656 {
657 regenerateCache();
658 preserveGeometry();
659 markSourceDirtyAndUpdate();
660 }
661 void onGeoGeometryUpdated() override
662 {
663 updateCache();
664 preserveGeometry();
665 markSourceDirtyAndUpdate();
666 }
667 void onItemGeometryChanged() override
668 {
669 onGeoGeometryChanged();
670 }
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: *map, path: m_geopathProjected, geoLeftBound: m_poly.m_geopath.boundingGeoRectangle().topLeft());
686 m_geometry.updateScreenPoints(map: *map, strokeWidth: 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(coordinate: m_geometry.origin(), offset: -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 }
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(fillColor: m_poly.m_line.color(), shape: &m_geometry);
709 m_geometry.setPreserveGeometry(value: false);
710 m_geometry.markClean();
711 m_poly.m_dirtyMaterial = false;
712 }
713 return m_node;
714 }
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)
726class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolylineMapItemPrivateOpenGLLineStrip: public QDeclarativePolylineMapItemPrivate
727{
728public:
729
730 QDeclarativePolylineMapItemPrivateOpenGLLineStrip(QDeclarativePolylineMapItem &poly) : QDeclarativePolylineMapItemPrivate(poly)
731 {
732 }
733
734 QDeclarativePolylineMapItemPrivateOpenGLLineStrip(QDeclarativePolylineMapItemPrivate &other)
735 : QDeclarativePolylineMapItemPrivate(other)
736 {
737 }
738
739 ~QDeclarativePolylineMapItemPrivateOpenGLLineStrip() override;
740 void onLinePropertiesChanged() override
741 {
742 afterViewportChanged();
743 }
744 void markSourceDirtyAndUpdate() override
745 {
746 m_geometry.markSourceDirty();
747 m_poly.polishAndUpdate();
748 }
749 void preserveGeometry()
750 {
751 m_geometry.setPreserveGeometry(value: true, geoLeftBound: m_poly.m_geopath.boundingGeoRectangle().topLeft());
752 }
753 void onMapSet() override
754 {
755 markSourceDirtyAndUpdate();
756 }
757 void onGeoGeometryChanged() override
758 {
759 preserveGeometry();
760 markSourceDirtyAndUpdate();
761 }
762 void onGeoGeometryUpdated() override
763 {
764 preserveGeometry();
765 markSourceDirtyAndUpdate();
766 }
767 void onItemGeometryChanged() override
768 {
769 onGeoGeometryChanged();
770 }
771 void afterViewportChanged() override
772 {
773 preserveGeometry();
774 m_poly.polishAndUpdate();
775 }
776 bool contains(const QPointF &point) const override
777 {
778 return m_geometry.contains(point: m_poly.mapToItem(item: m_poly.quickMap(), point),
779 lineWidth: m_poly.line()->width(),
780 p: static_cast<const QGeoProjectionWebMercator&>(m_poly.map()->geoProjection()));
781 }
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(map: *m_poly.map(), poly: m_poly.m_geopath);
796 m_geometry.markScreenDirty();
797 m_geometry.updateScreenPoints(map: *m_poly.map(), strokeWidth: 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 }
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(fillColor: m_poly.m_line.color(), // This updates only the material if the geometry is unchanged
820 lineWidth: m_poly.m_line.width(),
821 shape: &m_geometry,
822 geoProjection: combinedMatrix,
823 center: cameraCenter);
824 m_geometry.setPreserveGeometry(value: 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
835class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolylineMapItemPrivateOpenGLExtruded: public QDeclarativePolylineMapItemPrivateOpenGLLineStrip
836{
837public:
838
839 QDeclarativePolylineMapItemPrivateOpenGLExtruded(QDeclarativePolylineMapItem &poly)
840 : QDeclarativePolylineMapItemPrivateOpenGLLineStrip(poly)
841 {
842 }
843
844 QDeclarativePolylineMapItemPrivateOpenGLExtruded(QDeclarativePolylineMapItemPrivate &other)
845 : QDeclarativePolylineMapItemPrivateOpenGLLineStrip(other)
846 {
847 }
848
849 ~QDeclarativePolylineMapItemPrivateOpenGLExtruded() override;
850
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(fillColor: color,
873 lineWidth ,
874 shape: &m_geometry,
875 geoProjection: combinedMatrix,
876 center: cameraCenter,
877 capStyle: m_penCapStyle,
878 closed: false,
879 zoom: m_poly.zoomForLOD(zoom: int(map->cameraData().zoomLevel())));
880 m_geometry.setPreserveGeometry(value: 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)
891QT_END_NAMESPACE
892
893#endif // QDECLARATIVEPOLYLINEMAPITEM_P_P_H
894

source code of qtlocation/src/location/declarativemaps/qdeclarativepolylinemapitem_p_p.h