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"