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 ¢er, 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