File indexing completed on 2025-01-05 03:59:17
0001 // SPDX-License-Identifier: LGPL-2.1-or-later 0002 // 0003 // SPDX-FileCopyrightText: 2008-2009 Patrick Spendrin <ps_ml@gmx.de> 0004 // SPDX-FileCopyrightText: 2010 Thibaut Gridel <tgridel@free.fr> 0005 // SPDX-FileCopyrightText: 2011-2012 Bernhard Beschow <bbeschow@cs.tu-berlin.de> 0006 // SPDX-FileCopyrightText: 2014 Gábor Péterffy <peterffy95@gmail.com> 0007 // 0008 0009 #include "GeometryLayer.h" 0010 0011 // Qt 0012 #include <qmath.h> 0013 #include <QAbstractItemModel> 0014 #include <QModelIndex> 0015 0016 // Marble 0017 #include "GeoDataLatLonAltBox.h" 0018 #include "GeoDataDocument.h" 0019 #include "GeoDataFolder.h" 0020 #include "GeoDataLineStyle.h" 0021 #include "GeoDataMultiTrack.h" 0022 #include "GeoDataObject.h" 0023 #include "GeoDataPlacemark.h" 0024 #include "GeoDataLinearRing.h" 0025 #include "GeoDataMultiGeometry.h" 0026 #include "GeoDataPolygon.h" 0027 #include "GeoDataBuilding.h" 0028 #include "GeoDataPolyStyle.h" 0029 #include "GeoDataStyle.h" 0030 #include "GeoDataIconStyle.h" 0031 #include "GeoDataStyleMap.h" 0032 #include "GeoDataTrack.h" 0033 #include "GeoDataFeature.h" 0034 #include "GeoPainter.h" 0035 #include "ViewportParams.h" 0036 #include "RenderState.h" 0037 #include "GeoGraphicsScene.h" 0038 #include "GeoGraphicsItem.h" 0039 #include "GeoLineStringGraphicsItem.h" 0040 #include "GeoPolygonGraphicsItem.h" 0041 #include "GeoTrackGraphicsItem.h" 0042 #include "GeoDataPhotoOverlay.h" 0043 #include "GeoDataScreenOverlay.h" 0044 #include "GeoPhotoGraphicsItem.h" 0045 #include "ScreenOverlayGraphicsItem.h" 0046 #include "TileId.h" 0047 #include "MarbleGraphicsItem.h" 0048 #include "MarblePlacemarkModel.h" 0049 #include "GeoDataTreeModel.h" 0050 #include "OsmPlacemarkData.h" 0051 #include "StyleBuilder.h" 0052 #include "AbstractGeoPolygonGraphicsItem.h" 0053 0054 #include "digikam_debug.h" 0055 0056 namespace Marble 0057 { 0058 class GeometryLayerPrivate 0059 { 0060 public: 0061 using OsmLineStringItems = QVector<GeoLineStringGraphicsItem *>; 0062 using Relations = QSet<const GeoDataRelation *>; 0063 typedef QHash<const GeoDataFeature *, Relations> FeatureRelationHash; 0064 using GeoGraphicItems = QVector<GeoGraphicsItem *>; 0065 0066 struct PaintFragments { 0067 // Three lists for different z values 0068 // A z value of 0 is default and used by the majority of items, so sorting 0069 // can be avoided for it 0070 QVector<GeoGraphicsItem*> negative; // subways 0071 QVector<GeoGraphicsItem*> null; // areas and roads 0072 QVector<GeoGraphicsItem*> positive; // buildings 0073 }; 0074 0075 explicit GeometryLayerPrivate(const QAbstractItemModel *model, const StyleBuilder *styleBuilder); 0076 0077 void createGraphicsItems(const GeoDataObject *object); 0078 void createGraphicsItems(const GeoDataObject *object, FeatureRelationHash &relations); 0079 void createGraphicsItemFromGeometry(const GeoDataGeometry *object, const GeoDataPlacemark *placemark, const Relations &relations); 0080 void createGraphicsItemFromOverlay(const GeoDataOverlay *overlay); 0081 void removeGraphicsItems(const GeoDataFeature *feature); 0082 void updateTiledLineStrings(const GeoDataPlacemark *placemark, GeoLineStringGraphicsItem* lineStringItem); 0083 static void updateTiledLineStrings(OsmLineStringItems &lineStringItems); 0084 void clearCache(); 0085 bool showRelation(const GeoDataRelation* relation) const; 0086 void updateRelationVisibility(); 0087 0088 const QAbstractItemModel *const m_model; 0089 const StyleBuilder *const m_styleBuilder; 0090 GeoGraphicsScene m_scene; 0091 QString m_runtimeTrace; 0092 QList<ScreenOverlayGraphicsItem*> m_screenOverlays; 0093 0094 QHash<qint64, OsmLineStringItems> m_osmLineStringItems; 0095 int m_tileLevel; 0096 GeoGraphicsItem* m_lastFeatureAt; 0097 0098 bool m_dirty; 0099 int m_cachedItemCount; 0100 QHash<QString, GeoGraphicItems> m_cachedPaintFragments; 0101 typedef QPair<QString, GeoGraphicsItem*> LayerItem; 0102 QList<LayerItem> m_cachedDefaultLayer; 0103 QDateTime m_cachedDateTime; 0104 GeoDataLatLonBox m_cachedLatLonBox; 0105 QSet<qint64> m_highlightedRouteRelations; 0106 GeoDataRelation::RelationTypes m_visibleRelationTypes; 0107 bool m_levelTagDebugModeEnabled; 0108 int m_debugLevelTag; 0109 }; 0110 0111 GeometryLayerPrivate::GeometryLayerPrivate(const QAbstractItemModel *model, const StyleBuilder *styleBuilder) : 0112 m_model(model), 0113 m_styleBuilder(styleBuilder), 0114 m_tileLevel(0), 0115 m_lastFeatureAt(nullptr), 0116 m_dirty(true), 0117 m_cachedItemCount(0), 0118 m_visibleRelationTypes(GeoDataRelation::RouteFerry), 0119 m_levelTagDebugModeEnabled(false), 0120 m_debugLevelTag(0) 0121 { 0122 } 0123 0124 void GeometryLayerPrivate::createGraphicsItems(const GeoDataObject *object) 0125 { 0126 FeatureRelationHash noRelations; 0127 createGraphicsItems(object, noRelations); 0128 } 0129 0130 GeometryLayer::GeometryLayer(const QAbstractItemModel *model, const StyleBuilder *styleBuilder) : 0131 d(new GeometryLayerPrivate(model, styleBuilder)) 0132 { 0133 const GeoDataObject *object = static_cast<GeoDataObject*>(d->m_model->index(0, 0, QModelIndex()).internalPointer()); 0134 if (object && object->parent()) { 0135 d->createGraphicsItems(object->parent()); 0136 } 0137 0138 connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), 0139 this, SLOT(resetCacheData())); 0140 connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), 0141 this, SLOT(addPlacemarks(QModelIndex,int,int))); 0142 connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), 0143 this, SLOT(removePlacemarks(QModelIndex,int,int))); 0144 connect(model, SIGNAL(modelReset()), 0145 this, SLOT(resetCacheData())); 0146 connect(this, SIGNAL(highlightedPlacemarksChanged(QVector<GeoDataPlacemark*>)), 0147 &d->m_scene, SLOT(applyHighlight(QVector<GeoDataPlacemark*>))); 0148 connect(&d->m_scene, SIGNAL(repaintNeeded()), 0149 this, SIGNAL(repaintNeeded())); 0150 } 0151 0152 GeometryLayer::~GeometryLayer() 0153 { 0154 delete d; 0155 } 0156 0157 QStringList GeometryLayer::renderPosition() const 0158 { 0159 return QStringList(QStringLiteral("HOVERS_ABOVE_SURFACE")); 0160 } 0161 0162 0163 bool GeometryLayer::render(GeoPainter *painter, ViewportParams *viewport, 0164 const QString& renderPos, GeoSceneLayer * layer) 0165 { 0166 Q_UNUSED(renderPos) 0167 Q_UNUSED(layer) 0168 0169 painter->save(); 0170 0171 auto const & box = viewport->viewLatLonAltBox(); 0172 bool isEqual = GeoDataLatLonBox::fuzzyCompare(d->m_cachedLatLonBox, box, 0.05); 0173 0174 if (d->m_cachedLatLonBox.isEmpty() || !isEqual) { 0175 d->m_dirty = true; 0176 } 0177 0178 // update the items cache at least every second since the last request 0179 auto const now = QDateTime::currentDateTime(); 0180 if (!d->m_cachedDateTime.isValid() || d->m_cachedDateTime.msecsTo(now) > 1000) { 0181 d->m_dirty = true; 0182 } 0183 0184 if (d->m_dirty) { 0185 d->m_dirty = false; 0186 0187 const int maxZoomLevel = qMin(d->m_tileLevel, d->m_styleBuilder->maximumZoomLevel()); 0188 auto const items = d->m_scene.items(box, maxZoomLevel); 0189 d->m_cachedLatLonBox = box; 0190 d->m_cachedDateTime = now; 0191 0192 d->m_cachedItemCount = items.size(); 0193 d->m_cachedDefaultLayer.clear(); 0194 d->m_cachedPaintFragments.clear(); 0195 QHash<QString, GeometryLayerPrivate::PaintFragments> paintFragments; 0196 const QStringList &renderOrder = d->m_styleBuilder->renderOrder(); 0197 QSet<QString> const knownLayers(renderOrder.constBegin(), renderOrder.constEnd()); 0198 for (GeoGraphicsItem* item: items) { 0199 QStringList paintLayers = item->paintLayers(); 0200 if (paintLayers.isEmpty()) { 0201 qCDebug(DIGIKAM_MARBLE_LOG) << item << " provides no paint layers, so I force one onto it."; 0202 paintLayers << QString(); 0203 } 0204 for (const auto &layer: paintLayers) { 0205 if (knownLayers.contains(layer)) { 0206 GeometryLayerPrivate::PaintFragments &fragments = paintFragments[layer]; 0207 double const zValue = item->zValue(); 0208 // assign subway stations 0209 if (zValue == 0.0) { 0210 fragments.null << item; 0211 // assign areas and streets 0212 } else if (zValue < 0.0) { 0213 fragments.negative << item; 0214 // assign buildings 0215 } else { 0216 fragments.positive << item; 0217 } 0218 } else { 0219 // assign symbols 0220 d->m_cachedDefaultLayer << GeometryLayerPrivate::LayerItem(layer, item); 0221 static QSet<QString> missingLayers; 0222 if (!missingLayers.contains(layer)) { 0223 qCDebug(DIGIKAM_MARBLE_LOG) << "Missing layer " << layer << ", in render order, will render it on top"; 0224 missingLayers << layer; 0225 } 0226 } 0227 } 0228 } 0229 // Sort each fragment by z-level 0230 for (const QString &layer: d->m_styleBuilder->renderOrder()) { 0231 GeometryLayerPrivate::PaintFragments & layerItems = paintFragments[layer]; 0232 std::sort(layerItems.negative.begin(), layerItems.negative.end(), GeoGraphicsItem::zValueLessThan); 0233 // The idea here is that layerItems.null has most items and does not need to be sorted by z-value 0234 // since they are all equal (=0). We do sort them by style pointer though for batch rendering 0235 std::sort(layerItems.null.begin(), layerItems.null.end(), GeoGraphicsItem::styleLessThan); 0236 std::sort(layerItems.positive.begin(), layerItems.positive.end(), GeoGraphicsItem::zValueAndStyleLessThan); 0237 auto const count = layerItems.negative.size() + layerItems.null.size() + layerItems.positive.size(); 0238 d->m_cachedPaintFragments[layer].reserve(count); 0239 d->m_cachedPaintFragments[layer] << layerItems.negative; 0240 d->m_cachedPaintFragments[layer] << layerItems.null; 0241 d->m_cachedPaintFragments[layer] << layerItems.positive; 0242 } 0243 } 0244 0245 for (const QString &layer: d->m_styleBuilder->renderOrder()) { 0246 auto & layerItems = d->m_cachedPaintFragments[layer]; 0247 AbstractGeoPolygonGraphicsItem::s_previousStyle = nullptr; 0248 GeoLineStringGraphicsItem::s_previousStyle = nullptr; 0249 for (auto item: layerItems) { 0250 if (d->m_levelTagDebugModeEnabled) { 0251 if (const auto placemark = geodata_cast<GeoDataPlacemark>(item->feature())) { 0252 if (placemark->hasOsmData()) { 0253 QHash<QString, QString>::const_iterator tagIter = placemark->osmData().findTag(QStringLiteral("level")); 0254 if (tagIter != placemark->osmData().tagsEnd()) { 0255 const int val = tagIter.value().toInt(); 0256 if (val != d->m_debugLevelTag) { 0257 continue; 0258 } 0259 } 0260 } 0261 } 0262 } 0263 item->paint(painter, viewport, layer, d->m_tileLevel); 0264 } 0265 } 0266 0267 for (const auto & item: d->m_cachedDefaultLayer) { 0268 item.second->paint(painter, viewport, item.first, d->m_tileLevel); 0269 } 0270 0271 for (ScreenOverlayGraphicsItem* item: d->m_screenOverlays) { 0272 item->paintEvent(painter, viewport); 0273 } 0274 0275 painter->restore(); 0276 d->m_runtimeTrace = QStringLiteral("Geometries: %1 Zoom: %2") 0277 .arg(d->m_cachedItemCount) 0278 .arg(d->m_tileLevel); 0279 return true; 0280 } 0281 0282 RenderState GeometryLayer::renderState() const 0283 { 0284 return RenderState(QStringLiteral("GeoGraphicsScene")); 0285 } 0286 0287 QString GeometryLayer::runtimeTrace() const 0288 { 0289 return d->m_runtimeTrace; 0290 } 0291 0292 bool GeometryLayer::hasFeatureAt(const QPoint &curpos, const ViewportParams *viewport) 0293 { 0294 if (d->m_lastFeatureAt && d->m_lastFeatureAt->contains(curpos, viewport)) { 0295 return true; 0296 } 0297 0298 auto const renderOrder = d->m_styleBuilder->renderOrder(); 0299 for (int i = renderOrder.size() - 1; i >= 0; --i) { 0300 auto & layerItems = d->m_cachedPaintFragments[renderOrder[i]]; 0301 for (auto item : layerItems) { 0302 if (item->contains(curpos, viewport)) { 0303 d->m_lastFeatureAt = item; 0304 return true; 0305 } 0306 } 0307 } 0308 0309 return false; 0310 } 0311 0312 void GeometryLayerPrivate::createGraphicsItems(const GeoDataObject *object, FeatureRelationHash &relations) 0313 { 0314 clearCache(); 0315 if (auto document = geodata_cast<GeoDataDocument>(object)) { 0316 for (auto feature: document->featureList()) { 0317 if (auto relation = geodata_cast<GeoDataRelation>(feature)) { 0318 relation->setVisible(showRelation(relation)); 0319 for (auto member: relation->members()) { 0320 relations[member] << relation; 0321 } 0322 } 0323 } 0324 } 0325 if (auto placemark = geodata_cast<GeoDataPlacemark>(object)) { 0326 createGraphicsItemFromGeometry(placemark->geometry(), placemark, relations.value(placemark)); 0327 } else if (const GeoDataOverlay* overlay = dynamic_cast<const GeoDataOverlay*>(object)) { 0328 createGraphicsItemFromOverlay(overlay); 0329 } 0330 0331 // parse all child objects of the container 0332 if (const GeoDataContainer *container = dynamic_cast<const GeoDataContainer*>(object)) { 0333 int rowCount = container->size(); 0334 for (int row = 0; row < rowCount; ++row) { 0335 createGraphicsItems(container->child(row), relations); 0336 } 0337 } 0338 } 0339 0340 void GeometryLayerPrivate::updateTiledLineStrings(const GeoDataPlacemark* placemark, GeoLineStringGraphicsItem* lineStringItem) 0341 { 0342 if (!placemark->hasOsmData()) { 0343 return; 0344 } 0345 qint64 const osmId = placemark->osmData().oid(); 0346 if (osmId <= 0) { 0347 return; 0348 } 0349 auto & lineStringItems = m_osmLineStringItems[osmId]; 0350 lineStringItems << lineStringItem; 0351 updateTiledLineStrings(lineStringItems); 0352 } 0353 0354 void GeometryLayerPrivate::updateTiledLineStrings(OsmLineStringItems &lineStringItems) 0355 { 0356 GeoDataLineString merged; 0357 if (lineStringItems.size() > 1) { 0358 QVector<const GeoDataLineString*> lineStrings; 0359 for (auto item : lineStringItems) { 0360 lineStrings << item->lineString(); 0361 } 0362 merged = GeoLineStringGraphicsItem::merge(lineStrings); 0363 } 0364 0365 // If merging failed, reset all. Otherwise only the first one 0366 // gets the merge result and becomes visible. 0367 bool visible = true; 0368 for (auto item : lineStringItems) { 0369 item->setVisible(visible); 0370 if (visible) { 0371 item->setMergedLineString(merged); 0372 visible = merged.isEmpty(); 0373 } 0374 } 0375 } 0376 0377 void GeometryLayerPrivate::clearCache() 0378 { 0379 m_lastFeatureAt = nullptr; 0380 m_dirty = true; 0381 m_cachedDateTime = QDateTime(); 0382 m_cachedItemCount = 0; 0383 m_cachedPaintFragments.clear(); 0384 m_cachedDefaultLayer.clear(); 0385 m_cachedLatLonBox = GeoDataLatLonBox(); 0386 } 0387 0388 inline bool GeometryLayerPrivate::showRelation(const GeoDataRelation *relation) const 0389 { 0390 return (m_visibleRelationTypes.testFlag(relation->relationType()) 0391 || m_highlightedRouteRelations.contains(relation->osmData().oid())); 0392 } 0393 0394 void GeometryLayerPrivate::updateRelationVisibility() 0395 { 0396 for (int i = 0; i < m_model->rowCount(); ++i) { 0397 QVariant const data = m_model->data(m_model->index(i, 0), MarblePlacemarkModel::ObjectPointerRole); 0398 GeoDataObject *object = qvariant_cast<GeoDataObject*> (data); 0399 if (auto doc = geodata_cast<GeoDataDocument>(object)) { 0400 for (auto feature: doc->featureList()) { 0401 if (auto relation = geodata_cast<GeoDataRelation>(feature)) { 0402 relation->setVisible(showRelation(relation)); 0403 } 0404 } 0405 } 0406 } 0407 m_scene.resetStyle(); 0408 } 0409 0410 void GeometryLayerPrivate::createGraphicsItemFromGeometry(const GeoDataGeometry* object, const GeoDataPlacemark *placemark, const Relations &relations) 0411 { 0412 if (!placemark->isGloballyVisible()) { 0413 return; // Reconsider this when visibility can be changed dynamically 0414 } 0415 0416 GeoGraphicsItem *item = nullptr; 0417 if (const auto line = geodata_cast<GeoDataLineString>(object)) { 0418 auto lineStringItem = new GeoLineStringGraphicsItem(placemark, line); 0419 item = lineStringItem; 0420 updateTiledLineStrings(placemark, lineStringItem); 0421 } else if (const auto ring = geodata_cast<GeoDataLinearRing>(object)) { 0422 item = GeoPolygonGraphicsItem::createGraphicsItem(placemark, ring); 0423 } else if (const auto poly = geodata_cast<GeoDataPolygon>(object)) { 0424 item = GeoPolygonGraphicsItem::createGraphicsItem(placemark, poly); 0425 if (item->zValue() == 0) { 0426 item->setZValue(poly->renderOrder()); 0427 } 0428 } else if (const auto building = geodata_cast<GeoDataBuilding>(object)) { 0429 item = GeoPolygonGraphicsItem::createGraphicsItem(placemark, building); 0430 } else if (const auto multigeo = geodata_cast<GeoDataMultiGeometry>(object)) { 0431 int rowCount = multigeo->size(); 0432 for (int row = 0; row < rowCount; ++row) { 0433 createGraphicsItemFromGeometry(multigeo->child(row), placemark, relations); 0434 } 0435 } else if (const auto multitrack = geodata_cast<GeoDataMultiTrack>(object)) { 0436 int rowCount = multitrack->size(); 0437 for (int row = 0; row < rowCount; ++row) { 0438 createGraphicsItemFromGeometry(multitrack->child(row), placemark, relations); 0439 } 0440 } else if (const auto track = geodata_cast<GeoDataTrack>(object)) { 0441 item = new GeoTrackGraphicsItem(placemark, track); 0442 } 0443 if (!item) { 0444 return; 0445 } 0446 item->setRelations(relations); 0447 item->setStyleBuilder(m_styleBuilder); 0448 item->setVisible(item->visible() && placemark->isGloballyVisible()); 0449 item->setMinZoomLevel(m_styleBuilder->minimumZoomLevel(*placemark)); 0450 m_scene.addItem(item); 0451 } 0452 0453 void GeometryLayerPrivate::createGraphicsItemFromOverlay(const GeoDataOverlay *overlay) 0454 { 0455 if (!overlay->isGloballyVisible()) { 0456 return; // Reconsider this when visibility can be changed dynamically 0457 } 0458 0459 GeoGraphicsItem* item = nullptr; 0460 if (const auto photoOverlay = geodata_cast<GeoDataPhotoOverlay>(overlay)) { 0461 GeoPhotoGraphicsItem *photoItem = new GeoPhotoGraphicsItem(overlay); 0462 photoItem->setPoint(photoOverlay->point()); 0463 item = photoItem; 0464 } else if (const auto screenOverlay = geodata_cast<GeoDataScreenOverlay>(overlay)) { 0465 ScreenOverlayGraphicsItem *screenItem = new ScreenOverlayGraphicsItem(screenOverlay); 0466 m_screenOverlays.push_back(screenItem); 0467 } 0468 0469 if (item) { 0470 item->setStyleBuilder(m_styleBuilder); 0471 item->setVisible(overlay->isGloballyVisible()); 0472 m_scene.addItem(item); 0473 } 0474 } 0475 0476 void GeometryLayerPrivate::removeGraphicsItems(const GeoDataFeature *feature) 0477 { 0478 clearCache(); 0479 if (const auto placemark = geodata_cast<GeoDataPlacemark>(feature)) { 0480 if (placemark->isGloballyVisible() && 0481 geodata_cast<GeoDataLineString>(placemark->geometry()) && 0482 placemark->hasOsmData() && 0483 placemark->osmData().oid() > 0) { 0484 auto & items = m_osmLineStringItems[placemark->osmData().oid()]; 0485 bool removed = false; 0486 for (auto item : items) { 0487 if (item->feature() == feature) { 0488 items.removeOne(item); 0489 removed = true; 0490 break; 0491 } 0492 } 0493 Q_ASSERT(removed); 0494 updateTiledLineStrings(items); 0495 } 0496 m_scene.removeItem(feature); 0497 } else if (const auto container = dynamic_cast<const GeoDataContainer*>(feature)) { 0498 for (const GeoDataFeature *child: container->featureList()) { 0499 removeGraphicsItems(child); 0500 } 0501 } else if (geodata_cast<GeoDataScreenOverlay>(feature)) { 0502 for (ScreenOverlayGraphicsItem *item: m_screenOverlays) { 0503 if (item->screenOverlay() == feature) { 0504 m_screenOverlays.removeAll(item); 0505 } 0506 } 0507 } 0508 } 0509 0510 void GeometryLayer::addPlacemarks(const QModelIndex& parent, int first, int last) 0511 { 0512 Q_ASSERT(first < d->m_model->rowCount(parent)); 0513 Q_ASSERT(last < d->m_model->rowCount(parent)); 0514 for (int i = first; i <= last; ++i) { 0515 QModelIndex index = d->m_model->index(i, 0, parent); 0516 Q_ASSERT(index.isValid()); 0517 const GeoDataObject *object = qvariant_cast<GeoDataObject*>(index.data(MarblePlacemarkModel::ObjectPointerRole)); 0518 Q_ASSERT(object); 0519 d->createGraphicsItems(object); 0520 } 0521 Q_EMIT repaintNeeded(); 0522 0523 } 0524 0525 void GeometryLayer::removePlacemarks(const QModelIndex& parent, int first, int last) 0526 { 0527 Q_ASSERT(last < d->m_model->rowCount(parent)); 0528 bool isRepaintNeeded = false; 0529 for (int i = first; i <= last; ++i) { 0530 QModelIndex index = d->m_model->index(i, 0, parent); 0531 Q_ASSERT(index.isValid()); 0532 const GeoDataObject *object = qvariant_cast<GeoDataObject*>(index.data(MarblePlacemarkModel::ObjectPointerRole)); 0533 const GeoDataFeature *feature = dynamic_cast<const GeoDataFeature*>(object); 0534 if (feature != nullptr) { 0535 d->removeGraphicsItems(feature); 0536 isRepaintNeeded = true; 0537 } 0538 } 0539 if (isRepaintNeeded) { 0540 Q_EMIT repaintNeeded(); 0541 } 0542 0543 } 0544 0545 void GeometryLayer::resetCacheData() 0546 { 0547 d->clearCache(); 0548 d->m_scene.clear(); 0549 qDeleteAll(d->m_screenOverlays); 0550 d->m_screenOverlays.clear(); 0551 d->m_osmLineStringItems.clear(); 0552 0553 const GeoDataObject *object = static_cast<GeoDataObject*>(d->m_model->index(0, 0, QModelIndex()).internalPointer()); 0554 if (object && object->parent()) { 0555 d->createGraphicsItems(object->parent()); 0556 } 0557 Q_EMIT repaintNeeded(); 0558 } 0559 0560 void GeometryLayer::setTileLevel(int tileLevel) 0561 { 0562 d->m_tileLevel = tileLevel; 0563 } 0564 0565 QVector<const GeoDataFeature*> GeometryLayer::whichFeatureAt(const QPoint &curpos, const ViewportParams *viewport) 0566 { 0567 QVector<const GeoDataFeature*> result; 0568 auto const renderOrder = d->m_styleBuilder->renderOrder(); 0569 QString const label = QStringLiteral("/label"); 0570 QSet<GeoGraphicsItem*> checked; 0571 for (int i = renderOrder.size()-1; i >= 0; --i) { 0572 if (renderOrder[i].endsWith(label)) { 0573 continue; 0574 } 0575 auto & layerItems = d->m_cachedPaintFragments[renderOrder[i]]; 0576 for (auto j = layerItems.size()-1; j >= 0; --j) { 0577 auto const & layerItem = layerItems[j]; 0578 if (!checked.contains(layerItem)) { 0579 if (layerItem->contains(curpos, viewport)) { 0580 result << layerItem->feature(); 0581 } 0582 checked << layerItem; 0583 } 0584 } 0585 } 0586 0587 return result; 0588 } 0589 0590 void GeometryLayer::highlightRouteRelation(qint64 osmId, bool enabled) 0591 { 0592 if (enabled) { 0593 d->m_highlightedRouteRelations << osmId; 0594 } else { 0595 d->m_highlightedRouteRelations.remove(osmId); 0596 } 0597 d->updateRelationVisibility(); 0598 } 0599 0600 void GeometryLayer::setVisibleRelationTypes(GeoDataRelation::RelationTypes relationTypes) 0601 { 0602 if (relationTypes != d->m_visibleRelationTypes) { 0603 d->m_visibleRelationTypes = relationTypes; 0604 d->updateRelationVisibility(); 0605 } 0606 } 0607 0608 void GeometryLayer::handleHighlight(qreal lon, qreal lat, GeoDataCoordinates::Unit unit) 0609 { 0610 GeoDataCoordinates clickedPoint(lon, lat, 0, unit); 0611 QVector<GeoDataPlacemark*> selectedPlacemarks; 0612 0613 for (int i = 0; i < d->m_model->rowCount(); ++i) { 0614 QVariant const data = d->m_model->data(d->m_model->index(i, 0), MarblePlacemarkModel::ObjectPointerRole); 0615 GeoDataObject *object = qvariant_cast<GeoDataObject*> (data); 0616 Q_ASSERT(object); 0617 if (const auto doc = geodata_cast<GeoDataDocument>(object)) { 0618 bool isHighlight = false; 0619 0620 for (const GeoDataStyleMap &styleMap: doc->styleMaps()) { 0621 if (styleMap.contains(QStringLiteral("highlight"))) { 0622 isHighlight = true; 0623 break; 0624 } 0625 } 0626 0627 /* 0628 * If a document doesn't specify any highlight 0629 * styleId in its style maps then there is no need 0630 * to further check that document for placemarks 0631 * which have been clicked because we won't 0632 * highlight them. 0633 */ 0634 if (isHighlight) { 0635 QVector<GeoDataFeature*>::Iterator iter = doc->begin(); 0636 QVector<GeoDataFeature*>::Iterator const end = doc->end(); 0637 0638 for (; iter != end; ++iter) { 0639 if (auto placemark = geodata_cast<GeoDataPlacemark>(*iter)) { 0640 GeoDataPolygon *polygon = dynamic_cast<GeoDataPolygon*>(placemark->geometry()); 0641 if (polygon && 0642 polygon->contains(clickedPoint)) { 0643 selectedPlacemarks.push_back(placemark); 0644 } 0645 0646 if (auto linearRing = geodata_cast<GeoDataLinearRing>(placemark->geometry())) { 0647 if (linearRing->contains(clickedPoint)) { 0648 selectedPlacemarks.push_back(placemark); 0649 } 0650 } 0651 0652 if (auto multiGeometry = geodata_cast<GeoDataMultiGeometry>(placemark->geometry())) { 0653 QVector<GeoDataGeometry*>::Iterator multiIter = multiGeometry->begin(); 0654 QVector<GeoDataGeometry*>::Iterator const multiEnd = multiGeometry->end(); 0655 0656 for (; multiIter != multiEnd; ++multiIter) { 0657 GeoDataPolygon *poly = dynamic_cast<GeoDataPolygon*>(*multiIter); 0658 0659 if (poly && 0660 poly->contains(clickedPoint)) { 0661 selectedPlacemarks.push_back(placemark); 0662 break; 0663 } 0664 0665 if (auto linearRing = geodata_cast<GeoDataLinearRing>(*multiIter)) { 0666 if (linearRing->contains(clickedPoint)) { 0667 selectedPlacemarks.push_back(placemark); 0668 break; 0669 } 0670 } 0671 } 0672 } 0673 } 0674 } 0675 } 0676 } 0677 } 0678 0679 Q_EMIT highlightedPlacemarksChanged(selectedPlacemarks); 0680 } 0681 0682 void GeometryLayer::setLevelTagDebugModeEnabled(bool enabled) 0683 { 0684 if (d->m_levelTagDebugModeEnabled != enabled) { 0685 d->m_levelTagDebugModeEnabled = enabled; 0686 Q_EMIT repaintNeeded(); 0687 } 0688 } 0689 0690 bool GeometryLayer::levelTagDebugModeEnabled() const 0691 { 0692 return d->m_levelTagDebugModeEnabled; 0693 } 0694 0695 void GeometryLayer::setDebugLevelTag(int level) 0696 { 0697 if (d->m_debugLevelTag != level) { 0698 d->m_debugLevelTag = level; 0699 Q_EMIT repaintNeeded(); 0700 } 0701 } 0702 0703 int GeometryLayer::debugLevelTag() const 0704 { 0705 return d->m_debugLevelTag; 0706 } 0707 0708 } 0709 0710 #include "moc_GeometryLayer.cpp"