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 QDECLARATIVEPOLYGONMAPITEM_P_P_H 39 #define QDECLARATIVEPOLYGONMAPITEM_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/qgeomapitemgeometry_p.h> 54 #include <QtLocation/private/qdeclarativegeomapitembase_p.h> 55 #include <QtLocation/private/qdeclarativepolylinemapitem_p.h> 56 #include <QtLocation/private/qdeclarativegeomapitemutils_p.h> 57 #include <QtLocation/private/qdeclarativepolygonmapitem_p.h> 58 #include <QtLocation/private/qdeclarativepolylinemapitem_p_p.h> 59 #include <QSGGeometryNode> 60 #include <QSGFlatColorMaterial> 61 #include <QtPositioning/QGeoPath> 62 #include <QtPositioning/QGeoRectangle> 63 #include <QtPositioning/QGeoPolygon> 64 #include <QtPositioning/private/qdoublevector2d_p.h> 65 #include <QSGFlatColorMaterial> 66 #include <QSGSimpleMaterial> 67 #include <QtGui/QMatrix4x4> 68 #include <QColor> 69 #include <QList> 70 #include <QVector> 71 #include <QtCore/QScopedValueRollback> 72 73 QT_BEGIN_NAMESPACE 74 75 class Q_LOCATION_PRIVATE_EXPORT QGeoMapPolygonGeometry : public QGeoMapItemGeometry 76 { 77 public: 78 QGeoMapPolygonGeometry(); 79 setAssumeSimple(bool value)80 inline void setAssumeSimple(bool value) { assumeSimple_ = value; } 81 82 void updateSourcePoints(const QGeoMap &map, 83 const QList<QDoubleVector2D> &path); 84 85 void updateScreenPoints(const QGeoMap &map, qreal strokeWidth = 0.0); 86 87 protected: 88 QPainterPath srcPath_; 89 bool assumeSimple_; 90 }; 91 92 class Q_LOCATION_PRIVATE_EXPORT QGeoMapPolygonGeometryOpenGL : public QGeoMapItemGeometry 93 { 94 public: 95 typedef struct { 96 QList<QDoubleVector2D> wrappedBboxes; 97 } WrappedPolygon; 98 QGeoMapPolygonGeometryOpenGL(); ~QGeoMapPolygonGeometryOpenGL()99 ~QGeoMapPolygonGeometryOpenGL() override {} 100 101 // Temporary method for compatibility in MapCircleObject. Remove when MapObjects are ported. 102 void updateSourcePoints(const QGeoMap &map, 103 const QList<QDoubleVector2D> &path); 104 105 void updateSourcePoints(const QGeoMap &map, 106 const QList<QGeoCoordinate> &perimeter); 107 108 void updateSourcePoints(const QGeoMap &map, 109 const QGeoPolygon &poly); 110 111 void updateSourcePoints(const QGeoMap &map, 112 const QGeoRectangle &rect); 113 114 void updateScreenPoints(const QGeoMap &map, qreal strokeWidth = 0.0, const QColor &strokeColor = Qt::transparent); 115 void updateQuickGeometry(const QGeoProjectionWebMercator &p, qreal strokeWidth = 0.0); 116 allocateAndFillPolygon(QSGGeometry * geom)117 void allocateAndFillPolygon(QSGGeometry *geom) const 118 { 119 120 121 const QVector<QDeclarativeGeoMapItemUtils::vec2> &vx = m_screenVertices; 122 const QVector<quint32> &ix = m_screenIndices; 123 124 geom->allocate(vx.size(), ix.size()); 125 if (geom->indexType() == QSGGeometry::UnsignedShortType) { 126 quint16 *its = geom->indexDataAsUShort(); 127 for (int i = 0; i < ix.size(); ++i) 128 its[i] = ix[i]; 129 } else if (geom->indexType() == QSGGeometry::UnsignedIntType) { 130 quint32 *its = geom->indexDataAsUInt(); 131 for (int i = 0; i < ix.size(); ++i) 132 its[i] = ix[i]; 133 } 134 135 QSGGeometry::Point2D *pts = geom->vertexDataAsPoint2D(); 136 for (int i = 0; i < vx.size(); ++i) 137 pts[i].set(vx[i].x, vx[i].y); 138 } 139 140 QVector<QDeclarativeGeoMapItemUtils::vec2> m_screenVertices; 141 QVector<quint32> m_screenIndices; 142 QDoubleVector2D m_bboxLeftBoundWrapped; 143 QVector<WrappedPolygon> m_wrappedPolygons; 144 int m_wrapOffset; 145 }; 146 147 class Q_LOCATION_PRIVATE_EXPORT MapPolygonShader : public QSGMaterialShader 148 { 149 public: 150 MapPolygonShader(); 151 vertexShader()152 const char *vertexShader() const override { 153 return 154 "attribute highp vec4 vertex; \n" 155 "uniform highp mat4 qt_Matrix; \n" 156 "uniform highp mat4 mapProjection; \n" 157 "uniform highp vec3 center; \n" 158 "uniform highp vec3 center_lowpart; \n" 159 "uniform lowp float wrapOffset; \n" 160 "vec4 wrapped(in vec4 v) { return vec4(v.x + wrapOffset, v.y, 0.0, 1.0); }\n" 161 "void main() { \n" 162 " vec4 vtx = wrapped(vertex) - vec4(center, 0.0); \n" 163 " vtx = vtx - vec4(center_lowpart, 0.0); \n" 164 " gl_Position = qt_Matrix * mapProjection * vtx; \n" 165 "}"; 166 } 167 fragmentShader()168 const char *fragmentShader() const override { 169 return 170 "uniform lowp vec4 color; \n" 171 "void main() { \n" 172 " gl_FragColor = color; \n" 173 "}"; 174 } 175 176 void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; attributeNames()177 char const *const *attributeNames() const override 178 { 179 static char const *const attr[] = { "vertex", nullptr }; 180 return attr; 181 } 182 183 private: initialize()184 void initialize() override 185 { 186 m_matrix_id = program()->uniformLocation("qt_Matrix"); 187 m_color_id = program()->uniformLocation("color"); 188 m_mapProjection_id = program()->uniformLocation("mapProjection"); 189 m_center_id = program()->uniformLocation("center"); 190 m_center_lowpart_id = program()->uniformLocation("center_lowpart"); 191 m_wrapOffset_id = program()->uniformLocation("wrapOffset"); 192 } 193 int m_center_id; 194 int m_center_lowpart_id; 195 int m_mapProjection_id; 196 int m_matrix_id; 197 int m_color_id; 198 int m_wrapOffset_id; 199 }; 200 201 class Q_LOCATION_PRIVATE_EXPORT MapPolygonMaterial : public QSGFlatColorMaterial 202 { 203 public: MapPolygonMaterial()204 MapPolygonMaterial() 205 : QSGFlatColorMaterial() 206 { 207 // Passing RequiresFullMatrix is essential in order to prevent the 208 // batch renderer from baking in simple, translate-only transforms into 209 // the vertex data. The shader will rely on the fact that 210 // vertexCoord.xy is the Shape-space coordinate and so no modifications 211 // are welcome. 212 setFlag(Blending | RequiresFullMatrix | CustomCompileStep); 213 } 214 215 QSGMaterialShader *createShader() const override; 216 setGeoProjection(const QMatrix4x4 & p)217 void setGeoProjection(const QMatrix4x4 &p) 218 { 219 m_geoProjection = p; 220 } 221 geoProjection()222 QMatrix4x4 geoProjection() const 223 { 224 return m_geoProjection; 225 } 226 setCenter(const QDoubleVector3D & c)227 void setCenter(const QDoubleVector3D &c) 228 { 229 m_center = c; 230 } 231 center()232 QDoubleVector3D center() const 233 { 234 return m_center; 235 } 236 wrapOffset()237 int wrapOffset() const 238 { 239 return m_wrapOffset; 240 } 241 setWrapOffset(int wrapOffset)242 void setWrapOffset(int wrapOffset) 243 { 244 m_wrapOffset = wrapOffset; 245 } 246 247 int compare(const QSGMaterial *other) const override; 248 QSGMaterialType *type() const override; 249 250 protected: 251 QMatrix4x4 m_geoProjection; 252 QDoubleVector3D m_center; 253 int m_wrapOffset = 0; 254 }; 255 256 class Q_LOCATION_PRIVATE_EXPORT MapPolygonNode : public MapItemGeometryNode 257 { 258 259 public: 260 MapPolygonNode(); 261 ~MapPolygonNode() override; 262 263 void update(const QColor &fillColor, const QColor &borderColor, 264 const QGeoMapItemGeometry *fillShape, 265 const QGeoMapItemGeometry *borderShape); 266 private: 267 QSGFlatColorMaterial fill_material_; 268 MapPolylineNode *border_; 269 QSGGeometry geometry_; 270 }; 271 272 class Q_LOCATION_PRIVATE_EXPORT MapPolygonNodeGL : public MapItemGeometryNode 273 { 274 275 public: 276 MapPolygonNodeGL(); 277 ~MapPolygonNodeGL() override; 278 279 void update(const QColor &fillColor, 280 const QGeoMapPolygonGeometryOpenGL *fillShape, 281 const QMatrix4x4 &geoProjection, 282 const QDoubleVector3D ¢er); 283 284 MapPolygonMaterial fill_material_; 285 QSGGeometry geometry_; 286 }; 287 288 class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolygonMapItemPrivate 289 { 290 public: QDeclarativePolygonMapItemPrivate(QDeclarativePolygonMapItem & polygon)291 QDeclarativePolygonMapItemPrivate(QDeclarativePolygonMapItem &polygon) : m_poly(polygon) 292 { 293 294 } QDeclarativePolygonMapItemPrivate(QDeclarativePolygonMapItemPrivate & other)295 QDeclarativePolygonMapItemPrivate(QDeclarativePolygonMapItemPrivate &other) : m_poly(other.m_poly) 296 { 297 } 298 299 virtual ~QDeclarativePolygonMapItemPrivate(); 300 virtual void onLinePropertiesChanged() = 0; 301 virtual void markSourceDirtyAndUpdate() = 0; 302 virtual void onMapSet() = 0; 303 virtual void onGeoGeometryChanged() = 0; 304 virtual void onGeoGeometryUpdated() = 0; 305 virtual void onItemGeometryChanged() = 0; 306 virtual void updatePolish() = 0; 307 virtual void afterViewportChanged() = 0; 308 virtual QSGNode * updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) = 0; 309 virtual bool contains(const QPointF &point) const = 0; 310 311 QDeclarativePolygonMapItem &m_poly; 312 }; 313 314 class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolygonMapItemPrivateCPU: public QDeclarativePolygonMapItemPrivate 315 { 316 public: QDeclarativePolygonMapItemPrivateCPU(QDeclarativePolygonMapItem & polygon)317 QDeclarativePolygonMapItemPrivateCPU(QDeclarativePolygonMapItem &polygon) : QDeclarativePolygonMapItemPrivate(polygon) 318 { 319 } 320 QDeclarativePolygonMapItemPrivateCPU(QDeclarativePolygonMapItemPrivate & other)321 QDeclarativePolygonMapItemPrivateCPU(QDeclarativePolygonMapItemPrivate &other) 322 : QDeclarativePolygonMapItemPrivate(other) 323 { 324 } 325 326 ~QDeclarativePolygonMapItemPrivateCPU() override; onLinePropertiesChanged()327 void onLinePropertiesChanged() override 328 { 329 // mark dirty just in case we're a width change 330 markSourceDirtyAndUpdate(); 331 } markSourceDirtyAndUpdate()332 void markSourceDirtyAndUpdate() override 333 { 334 // preserveGeometry is cleared in updateMapItemPaintNode 335 m_geometry.markSourceDirty(); 336 m_borderGeometry.markSourceDirty(); 337 m_poly.polishAndUpdate(); 338 } regenerateCache()339 void regenerateCache() 340 { 341 if (!m_poly.map() || m_poly.map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator) 342 return; 343 const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_poly.map()->geoProjection()); 344 m_geopathProjected.clear(); 345 m_geopathProjected.reserve(m_poly.m_geopoly.size()); 346 for (const QGeoCoordinate &c : m_poly.m_geopoly.path()) 347 m_geopathProjected << p.geoToMapProjection(c); 348 } updateCache()349 void updateCache() 350 { 351 if (!m_poly.map() || m_poly.map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator) 352 return; 353 const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_poly.map()->geoProjection()); 354 m_geopathProjected << p.geoToMapProjection(m_poly.m_geopoly.path().last()); 355 } preserveGeometry()356 void preserveGeometry() 357 { 358 m_geometry.setPreserveGeometry(true, m_poly.m_geopoly.boundingGeoRectangle().topLeft()); 359 m_borderGeometry.setPreserveGeometry(true, m_poly.m_geopoly.boundingGeoRectangle().topLeft()); 360 } afterViewportChanged()361 void afterViewportChanged() override 362 { 363 // preserveGeometry is cleared in updateMapItemPaintNode 364 preserveGeometry(); 365 markSourceDirtyAndUpdate(); 366 } onMapSet()367 void onMapSet() override 368 { 369 regenerateCache(); 370 markSourceDirtyAndUpdate(); 371 } onGeoGeometryChanged()372 void onGeoGeometryChanged() override 373 { 374 regenerateCache(); 375 preserveGeometry(); 376 markSourceDirtyAndUpdate(); 377 } onGeoGeometryUpdated()378 void onGeoGeometryUpdated() override 379 { 380 updateCache(); 381 preserveGeometry(); 382 markSourceDirtyAndUpdate(); 383 } onItemGeometryChanged()384 void onItemGeometryChanged() override 385 { 386 onGeoGeometryChanged(); 387 } updatePolish()388 void updatePolish() override 389 { 390 if (m_poly.m_geopoly.path().length() == 0) { // Possibly cleared 391 m_geometry.clear(); 392 m_borderGeometry.clear(); 393 m_poly.setWidth(0); 394 m_poly.setHeight(0); 395 return; 396 } 397 const QGeoMap *map = m_poly.map(); 398 const qreal borderWidth = m_poly.m_border.width(); 399 const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map->geoProjection()); 400 QScopedValueRollback<bool> rollback(m_poly.m_updatingGeometry); 401 m_poly.m_updatingGeometry = true; 402 403 m_geometry.updateSourcePoints(*map, m_geopathProjected); 404 m_geometry.updateScreenPoints(*map, borderWidth); 405 406 QList<QGeoMapItemGeometry *> geoms; 407 geoms << &m_geometry; 408 m_borderGeometry.clear(); 409 410 if (m_poly.m_border.color().alpha() != 0 && borderWidth > 0) { 411 QList<QDoubleVector2D> closedPath = m_geopathProjected; 412 closedPath << closedPath.first(); 413 414 m_borderGeometry.setPreserveGeometry(true, m_poly.m_geopoly.boundingGeoRectangle().topLeft()); 415 416 const QGeoCoordinate &geometryOrigin = m_geometry.origin(); 417 418 m_borderGeometry.srcPoints_.clear(); 419 m_borderGeometry.srcPointTypes_.clear(); 420 421 QDoubleVector2D borderLeftBoundWrapped; 422 QList<QList<QDoubleVector2D > > clippedPaths = m_borderGeometry.clipPath(*map, closedPath, borderLeftBoundWrapped); 423 if (clippedPaths.size()) { 424 borderLeftBoundWrapped = p.geoToWrappedMapProjection(geometryOrigin); 425 m_borderGeometry.pathToScreen(*map, clippedPaths, borderLeftBoundWrapped); 426 m_borderGeometry.updateScreenPoints(*map, borderWidth); 427 428 geoms << &m_borderGeometry; 429 } else { 430 m_borderGeometry.clear(); 431 } 432 } 433 434 QRectF combined = QGeoMapItemGeometry::translateToCommonOrigin(geoms); 435 m_poly.setWidth(combined.width() + 2 * borderWidth); 436 m_poly.setHeight(combined.height() + 2 * borderWidth); 437 438 m_poly.setPositionOnMap(m_geometry.origin(), -1 * m_geometry.sourceBoundingBox().topLeft() 439 + QPointF(borderWidth, borderWidth)); 440 } updateMapItemPaintNode(QSGNode * oldNode,QQuickItem::UpdatePaintNodeData * data)441 QSGNode *updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) override 442 { 443 Q_UNUSED(data); 444 if (!m_node || !oldNode) { 445 m_node = new MapPolygonNode(); 446 if (oldNode) { 447 delete oldNode; 448 oldNode = nullptr; 449 } 450 } else { 451 m_node = static_cast<MapPolygonNode *>(oldNode); 452 } 453 454 //TODO: update only material 455 if (m_geometry.isScreenDirty() 456 || m_borderGeometry.isScreenDirty() 457 || m_poly.m_dirtyMaterial 458 || !oldNode) { 459 m_node->update(m_poly.m_color, 460 m_poly.m_border.color(), 461 &m_geometry, 462 &m_borderGeometry); 463 m_geometry.setPreserveGeometry(false); 464 m_borderGeometry.setPreserveGeometry(false); 465 m_geometry.markClean(); 466 m_borderGeometry.markClean(); 467 m_poly.m_dirtyMaterial = false; 468 } 469 return m_node; 470 } contains(const QPointF & point)471 bool contains(const QPointF &point) const override 472 { 473 return (m_geometry.contains(point) || m_borderGeometry.contains(point)); 474 } 475 476 QList<QDoubleVector2D> m_geopathProjected; 477 QGeoMapPolygonGeometry m_geometry; 478 QGeoMapPolylineGeometry m_borderGeometry; 479 MapPolygonNode *m_node = nullptr; 480 }; 481 482 class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolygonMapItemPrivateOpenGL: public QDeclarativePolygonMapItemPrivate 483 { 484 public: 485 struct RootNode : public QSGNode /*QSGTransformNode*/, public VisibleNode 486 { RootNodeRootNode487 RootNode() { } 488 isSubtreeBlockedRootNode489 bool isSubtreeBlocked() const override 490 { 491 return subtreeBlocked(); 492 } 493 }; 494 QDeclarativePolygonMapItemPrivateOpenGL(QDeclarativePolygonMapItem & polygon)495 QDeclarativePolygonMapItemPrivateOpenGL(QDeclarativePolygonMapItem &polygon) : QDeclarativePolygonMapItemPrivate(polygon) 496 { 497 } 498 QDeclarativePolygonMapItemPrivateOpenGL(QDeclarativePolygonMapItemPrivate & other)499 QDeclarativePolygonMapItemPrivateOpenGL(QDeclarativePolygonMapItemPrivate &other) 500 : QDeclarativePolygonMapItemPrivate(other) 501 { 502 } 503 504 ~QDeclarativePolygonMapItemPrivateOpenGL() override; 505 markScreenDirtyAndUpdate()506 void markScreenDirtyAndUpdate() 507 { 508 // preserveGeometry is cleared in updateMapItemPaintNode 509 m_geometry.markScreenDirty(); 510 m_borderGeometry.markScreenDirty(); 511 m_poly.polishAndUpdate(); 512 } onLinePropertiesChanged()513 void onLinePropertiesChanged() override 514 { 515 m_poly.m_dirtyMaterial = true; 516 afterViewportChanged(); 517 } markSourceDirtyAndUpdate()518 void markSourceDirtyAndUpdate() override 519 { 520 // preserveGeometry is cleared in updateMapItemPaintNode 521 m_geometry.markSourceDirty(); 522 m_borderGeometry.markSourceDirty(); 523 m_poly.polishAndUpdate(); 524 } preserveGeometry()525 void preserveGeometry() 526 { 527 m_geometry.setPreserveGeometry(true, m_poly.m_geopoly.boundingGeoRectangle().topLeft()); 528 m_borderGeometry.setPreserveGeometry(true, m_poly.m_geopoly.boundingGeoRectangle().topLeft()); 529 } afterViewportChanged()530 void afterViewportChanged() override // This is called when the camera changes, or visibleArea changes. 531 { 532 // preserveGeometry is cleared in updateMapItemPaintNode 533 preserveGeometry(); 534 markScreenDirtyAndUpdate(); 535 } onMapSet()536 void onMapSet() override 537 { 538 markSourceDirtyAndUpdate(); 539 } onGeoGeometryChanged()540 void onGeoGeometryChanged() override 541 { 542 preserveGeometry(); 543 markSourceDirtyAndUpdate(); 544 } onGeoGeometryUpdated()545 void onGeoGeometryUpdated() override 546 { 547 preserveGeometry(); 548 markSourceDirtyAndUpdate(); 549 } onItemGeometryChanged()550 void onItemGeometryChanged() override 551 { 552 onGeoGeometryChanged(); 553 } updatePolish()554 void updatePolish() override 555 { 556 if (m_poly.m_geopoly.path().length() == 0) { // Possibly cleared 557 m_geometry.clear(); 558 m_borderGeometry.clear(); 559 m_poly.setWidth(0); 560 m_poly.setHeight(0); 561 return; 562 } 563 564 QScopedValueRollback<bool> rollback(m_poly.m_updatingGeometry); 565 m_poly.m_updatingGeometry = true; 566 const qreal lineWidth = m_poly.m_border.width(); 567 const QColor &lineColor = m_poly.m_border.color(); 568 const QColor &fillColor = m_poly.color(); 569 if (fillColor.alpha() != 0) { 570 m_geometry.updateSourcePoints(*m_poly.map(), m_poly.m_geopoly); 571 m_geometry.markScreenDirty(); 572 m_geometry.updateScreenPoints(*m_poly.map(), lineWidth, lineColor); 573 } else { 574 m_geometry.clearBounds(); 575 } 576 577 QGeoMapItemGeometry * geom = &m_geometry; 578 m_borderGeometry.clearScreen(); 579 if (lineColor.alpha() != 0 && lineWidth > 0) { 580 m_borderGeometry.updateSourcePoints(*m_poly.map(), m_poly.m_geopoly); 581 m_borderGeometry.markScreenDirty(); 582 m_borderGeometry.updateScreenPoints(*m_poly.map(), lineWidth); 583 geom = &m_borderGeometry; 584 } 585 m_poly.setWidth(geom->sourceBoundingBox().width()); 586 m_poly.setHeight(geom->sourceBoundingBox().height()); 587 m_poly.setPosition(1.0 * geom->firstPointOffset() - QPointF(lineWidth * 0.5,lineWidth * 0.5)); 588 } updateMapItemPaintNode(QSGNode * oldNode,QQuickItem::UpdatePaintNodeData * data)589 QSGNode * updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) override 590 { 591 Q_UNUSED(data); 592 593 if (!m_rootNode || !oldNode) { 594 m_rootNode = new RootNode(); 595 m_node = new MapPolygonNodeGL(); 596 m_rootNode->appendChildNode(m_node); 597 m_polylinenode = new MapPolylineNodeOpenGLExtruded(); 598 m_rootNode->appendChildNode(m_polylinenode); 599 m_rootNode->markDirty(QSGNode::DirtyNodeAdded); 600 if (oldNode) 601 delete oldNode; 602 } else { 603 m_rootNode = static_cast<RootNode *>(oldNode); 604 } 605 606 const QGeoMap *map = m_poly.map(); 607 const QMatrix4x4 &combinedMatrix = map->geoProjection().qsgTransform(); 608 const QDoubleVector3D &cameraCenter = map->geoProjection().centerMercator(); 609 610 if (m_borderGeometry.isScreenDirty()) { 611 /* Do the border update first */ 612 m_polylinenode->update(m_poly.m_border.color(), 613 float(m_poly.m_border.width()), 614 &m_borderGeometry, 615 combinedMatrix, 616 cameraCenter, 617 Qt::SquareCap, 618 true, 619 30); // No LOD for polygons just yet. 620 // First figure out what to do with holes. 621 m_borderGeometry.setPreserveGeometry(false); 622 m_borderGeometry.markClean(); 623 } else { 624 m_polylinenode->setSubtreeBlocked(true); 625 } 626 if (m_geometry.isScreenDirty()) { 627 m_node->update(m_poly.m_color, 628 &m_geometry, 629 combinedMatrix, 630 cameraCenter); 631 m_geometry.setPreserveGeometry(false); 632 m_geometry.markClean(); 633 } else { 634 m_node->setSubtreeBlocked(true); 635 } 636 637 m_rootNode->setSubtreeBlocked(false); 638 return m_rootNode; 639 } contains(const QPointF & point)640 bool contains(const QPointF &point) const override 641 { 642 const qreal lineWidth = m_poly.m_border.width(); 643 const QColor &lineColor = m_poly.m_border.color(); 644 const QRectF &bounds = (lineColor.alpha() != 0 && lineWidth > 0) ? m_borderGeometry.sourceBoundingBox() : m_geometry.sourceBoundingBox(); 645 if (bounds.contains(point)) { 646 QDeclarativeGeoMap *m = m_poly.quickMap(); 647 if (m) { 648 const QGeoCoordinate crd = m->toCoordinate(m->mapFromItem(&m_poly, point)); 649 return m_poly.m_geopoly.contains(crd) || m_borderGeometry.contains(m_poly.mapToItem(m_poly.quickMap(), point), 650 m_poly.border()->width(), 651 static_cast<const QGeoProjectionWebMercator&>(m_poly.map()->geoProjection())); 652 } else { 653 return true; 654 } 655 } 656 return false; 657 } 658 659 QGeoMapPolygonGeometryOpenGL m_geometry; 660 QGeoMapPolylineGeometryOpenGL m_borderGeometry; 661 RootNode *m_rootNode = nullptr; 662 MapPolygonNodeGL *m_node = nullptr; 663 MapPolylineNodeOpenGLExtruded *m_polylinenode = nullptr; 664 }; 665 666 QT_END_NAMESPACE 667 668 #endif // QDECLARATIVEPOLYGONMAPITEM_P_P_H 669