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