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