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