9 #include "GeometryLayer.h"
12 #include "GeoDataLatLonAltBox.h"
13 #include "GeoDataDocument.h"
14 #include "GeoDataFolder.h"
15 #include "GeoDataLineStyle.h"
16 #include "GeoDataMultiTrack.h"
17 #include "GeoDataObject.h"
18 #include "GeoDataPlacemark.h"
19 #include "GeoDataLinearRing.h"
20 #include "GeoDataMultiGeometry.h"
21 #include "GeoDataPolygon.h"
22 #include "GeoDataBuilding.h"
23 #include "GeoDataPolyStyle.h"
24 #include "GeoDataStyle.h"
25 #include "GeoDataIconStyle.h"
26 #include "GeoDataStyleMap.h"
27 #include "GeoDataTrack.h"
28 #include "GeoDataFeature.h"
29 #include "MarbleDebug.h"
30 #include "GeoPainter.h"
32 #include "RenderState.h"
33 #include "GeoGraphicsScene.h"
34 #include "GeoGraphicsItem.h"
35 #include "GeoLineStringGraphicsItem.h"
36 #include "GeoPolygonGraphicsItem.h"
37 #include "GeoTrackGraphicsItem.h"
38 #include "GeoDataPhotoOverlay.h"
39 #include "GeoDataScreenOverlay.h"
40 #include "GeoPhotoGraphicsItem.h"
41 #include "ScreenOverlayGraphicsItem.h"
43 #include "MarbleGraphicsItem.h"
44 #include "MarblePlacemarkModel.h"
45 #include "GeoDataTreeModel.h"
46 #include <OsmPlacemarkData.h>
47 #include "StyleBuilder.h"
48 #include "AbstractGeoPolygonGraphicsItem.h"
52 #include <QAbstractItemModel>
53 #include <QModelIndex>
57 class GeometryLayerPrivate
65 struct PaintFragments {
74 explicit GeometryLayerPrivate(
const QAbstractItemModel *model,
const StyleBuilder *styleBuilder);
76 void createGraphicsItems(
const GeoDataObject *
object);
77 void createGraphicsItems(
const GeoDataObject *
object, FeatureRelationHash &relations);
78 void createGraphicsItemFromGeometry(
const GeoDataGeometry *
object,
const GeoDataPlacemark *placemark,
const Relations &relations);
79 void createGraphicsItemFromOverlay(
const GeoDataOverlay *overlay);
80 void removeGraphicsItems(
const GeoDataFeature *feature);
81 void updateTiledLineStrings(
const GeoDataPlacemark *placemark, GeoLineStringGraphicsItem* lineStringItem);
82 static void updateTiledLineStrings(OsmLineStringItems &lineStringItems);
84 bool showRelation(
const GeoDataRelation* relation)
const;
85 void updateRelationVisibility();
88 const StyleBuilder *
const m_styleBuilder;
89 GeoGraphicsScene m_scene;
95 GeoGraphicsItem* m_lastFeatureAt;
98 int m_cachedItemCount;
103 GeoDataLatLonBox m_cachedLatLonBox;
105 GeoDataRelation::RelationTypes m_visibleRelationTypes;
106 bool m_levelTagDebugModeEnabled;
110 GeometryLayerPrivate::GeometryLayerPrivate(
const QAbstractItemModel *model,
const StyleBuilder *styleBuilder) :
112 m_styleBuilder(styleBuilder),
114 m_lastFeatureAt(nullptr),
116 m_cachedItemCount(0),
117 m_visibleRelationTypes(GeoDataRelation::RouteFerry),
118 m_levelTagDebugModeEnabled(false),
123 void GeometryLayerPrivate::createGraphicsItems(
const GeoDataObject *
object)
125 FeatureRelationHash noRelations;
126 createGraphicsItems(
object, noRelations);
129 GeometryLayer::GeometryLayer(
const QAbstractItemModel *model,
const StyleBuilder *styleBuilder) :
130 d(new GeometryLayerPrivate(model, styleBuilder))
132 const GeoDataObject *
object =
static_cast<GeoDataObject*
>(d->m_model->index(0, 0,
QModelIndex()).internalPointer());
133 if (
object && object->parent()) {
134 d->createGraphicsItems(object->parent());
138 this, SLOT(resetCacheData()));
142 this, SLOT(removePlacemarks(
QModelIndex,
int,
int)));
143 connect(model, SIGNAL(modelReset()),
144 this, SLOT(resetCacheData()));
147 connect(&d->m_scene, SIGNAL(repaintNeeded()),
148 this, SIGNAL(repaintNeeded()));
151 GeometryLayer::~GeometryLayer()
158 return QStringList(QStringLiteral(
"HOVERS_ABOVE_SURFACE"));
162 bool GeometryLayer::render(GeoPainter *painter, ViewportParams *viewport,
163 const QString& renderPos, GeoSceneLayer * layer)
170 auto const & box = viewport->viewLatLonAltBox();
173 if (d->m_cachedLatLonBox.isEmpty() || !isEqual) {
179 if (!d->m_cachedDateTime.isValid() || d->m_cachedDateTime.msecsTo(now) > 1000) {
186 const int maxZoomLevel = qMin(d->m_tileLevel, d->m_styleBuilder->maximumZoomLevel());
187 auto const items = d->m_scene.items(box, maxZoomLevel);
188 d->m_cachedLatLonBox = box;
189 d->m_cachedDateTime = now;
191 d->m_cachedItemCount = items.size();
192 d->m_cachedDefaultLayer.clear();
193 d->m_cachedPaintFragments.clear();
195 const QStringList &renderOrder = d->m_styleBuilder->renderOrder();
197 for (GeoGraphicsItem* item: items) {
200 mDebug() << item <<
" provides no paint layers, so I force one onto it.";
203 for (
const auto &layer: paintLayers) {
204 if (knownLayers.contains(layer)) {
205 GeometryLayerPrivate::PaintFragments &fragments = paintFragments[layer];
206 double const zValue = item->zValue();
209 fragments.null << item;
211 }
else if (zValue < 0.0) {
212 fragments.negative << item;
215 fragments.positive << item;
219 d->m_cachedDefaultLayer << GeometryLayerPrivate::LayerItem(layer, item);
221 if (!missingLayers.
contains(layer)) {
222 mDebug() <<
"Missing layer " << layer <<
", in render order, will render it on top";
223 missingLayers << layer;
229 for (
const QString &layer: d->m_styleBuilder->renderOrder()) {
230 GeometryLayerPrivate::PaintFragments & layerItems = paintFragments[layer];
231 std::sort(layerItems.negative.begin(), layerItems.negative.end(), GeoGraphicsItem::zValueLessThan);
234 std::sort(layerItems.null.begin(), layerItems.null.end(), GeoGraphicsItem::styleLessThan);
235 std::sort(layerItems.positive.begin(), layerItems.positive.end(), GeoGraphicsItem::zValueAndStyleLessThan);
236 auto const count = layerItems.negative.size() + layerItems.null.size() + layerItems.positive.size();
237 d->m_cachedPaintFragments[layer].reserve(count);
238 d->m_cachedPaintFragments[layer] << layerItems.negative;
239 d->m_cachedPaintFragments[layer] << layerItems.null;
240 d->m_cachedPaintFragments[layer] << layerItems.positive;
244 for (
const QString &layer: d->m_styleBuilder->renderOrder()) {
245 auto & layerItems = d->m_cachedPaintFragments[layer];
246 AbstractGeoPolygonGraphicsItem::s_previousStyle =
nullptr;
247 GeoLineStringGraphicsItem::s_previousStyle =
nullptr;
248 for (
auto item: layerItems) {
249 if (d->m_levelTagDebugModeEnabled) {
250 if (
const auto placemark = geodata_cast<GeoDataPlacemark>(item->feature())) {
251 if (placemark->hasOsmData()) {
253 if (tagIter != placemark->osmData().tagsEnd()) {
254 const int val = tagIter.
value().toInt();
255 if (val != d->m_debugLevelTag) {
262 item->paint(painter, viewport, layer, d->m_tileLevel);
266 for (
const auto & item: d->m_cachedDefaultLayer) {
267 item.second->paint(painter, viewport, item.first, d->m_tileLevel);
270 for (ScreenOverlayGraphicsItem* item: d->m_screenOverlays) {
271 item->paintEvent(painter, viewport);
275 d->m_runtimeTrace = QStringLiteral(
"Geometries: %1 Zoom: %2")
276 .arg(d->m_cachedItemCount)
277 .arg(d->m_tileLevel);
281 RenderState GeometryLayer::renderState()
const
283 return RenderState(QStringLiteral(
"GeoGraphicsScene"));
286 QString GeometryLayer::runtimeTrace()
const
288 return d->m_runtimeTrace;
291 bool GeometryLayer::hasFeatureAt(
const QPoint &curpos,
const ViewportParams *viewport)
293 if (d->m_lastFeatureAt && d->m_lastFeatureAt->contains(curpos, viewport)) {
297 auto const renderOrder = d->m_styleBuilder->renderOrder();
298 for (
int i = renderOrder.
size() - 1; i >= 0; --i) {
299 auto & layerItems = d->m_cachedPaintFragments[renderOrder[i]];
300 for (
auto item : layerItems) {
301 if (item->contains(curpos, viewport)) {
302 d->m_lastFeatureAt = item;
311 void GeometryLayerPrivate::createGraphicsItems(
const GeoDataObject *
object, FeatureRelationHash &relations)
314 if (
auto document = geodata_cast<GeoDataDocument>(
object)) {
315 for (
auto feature: document->featureList()) {
316 if (
auto relation = geodata_cast<GeoDataRelation>(feature)) {
317 relation->setVisible(showRelation(relation));
318 for (
auto member: relation->members()) {
319 relations[member] << relation;
324 if (
auto placemark = geodata_cast<GeoDataPlacemark>(
object)) {
325 createGraphicsItemFromGeometry(placemark->geometry(), placemark, relations.value(placemark));
326 }
else if (
const GeoDataOverlay* overlay =
dynamic_cast<const GeoDataOverlay*
>(
object)) {
327 createGraphicsItemFromOverlay(overlay);
331 if (
const GeoDataContainer *container =
dynamic_cast<const GeoDataContainer*
>(
object)) {
332 int rowCount = container->size();
333 for (
int row = 0; row < rowCount; ++row) {
334 createGraphicsItems(container->child(row), relations);
339 void GeometryLayerPrivate::updateTiledLineStrings(
const GeoDataPlacemark* placemark, GeoLineStringGraphicsItem* lineStringItem)
341 if (!placemark->hasOsmData()) {
344 qint64
const osmId = placemark->osmData().oid();
348 auto & lineStringItems = m_osmLineStringItems[osmId];
349 lineStringItems << lineStringItem;
350 updateTiledLineStrings(lineStringItems);
353 void GeometryLayerPrivate::updateTiledLineStrings(OsmLineStringItems &lineStringItems)
355 GeoDataLineString merged;
356 if (lineStringItems.size() > 1) {
358 for (
auto item : lineStringItems) {
359 lineStrings << item->lineString();
361 merged = GeoLineStringGraphicsItem::merge(lineStrings);
367 for (
auto item : lineStringItems) {
368 item->setVisible(visible);
370 item->setMergedLineString(merged);
371 visible = merged.isEmpty();
376 void GeometryLayerPrivate::clearCache()
378 m_lastFeatureAt =
nullptr;
381 m_cachedItemCount = 0;
382 m_cachedPaintFragments.clear();
383 m_cachedDefaultLayer.clear();
384 m_cachedLatLonBox = GeoDataLatLonBox();
387 inline bool GeometryLayerPrivate::showRelation(
const GeoDataRelation *relation)
const
389 return (m_visibleRelationTypes.testFlag(relation->relationType())
390 || m_highlightedRouteRelations.contains(relation->osmData().oid()));
393 void GeometryLayerPrivate::updateRelationVisibility()
395 for (
int i = 0; i < m_model->rowCount(); ++i) {
397 GeoDataObject *
object = qvariant_cast<GeoDataObject*> (data);
398 if (
auto doc = geodata_cast<GeoDataDocument>(
object)) {
399 for (
auto feature: doc->featureList()) {
400 if (
auto relation = geodata_cast<GeoDataRelation>(feature)) {
401 relation->setVisible(showRelation(relation));
406 m_scene.resetStyle();
409 void GeometryLayerPrivate::createGraphicsItemFromGeometry(
const GeoDataGeometry*
object,
const GeoDataPlacemark *placemark,
const Relations &relations)
411 if (!placemark->isGloballyVisible()) {
415 GeoGraphicsItem *item =
nullptr;
416 if (
const auto line = geodata_cast<GeoDataLineString>(
object)) {
417 auto lineStringItem =
new GeoLineStringGraphicsItem(placemark, line);
418 item = lineStringItem;
419 updateTiledLineStrings(placemark, lineStringItem);
420 }
else if (
const auto ring = geodata_cast<GeoDataLinearRing>(
object)) {
421 item = GeoPolygonGraphicsItem::createGraphicsItem(placemark, ring);
422 }
else if (
const auto poly = geodata_cast<GeoDataPolygon>(
object)) {
423 item = GeoPolygonGraphicsItem::createGraphicsItem(placemark, poly);
424 if (item->zValue() == 0) {
425 item->setZValue(poly->renderOrder());
427 }
else if (
const auto building = geodata_cast<GeoDataBuilding>(
object)) {
428 item = GeoPolygonGraphicsItem::createGraphicsItem(placemark, building);
429 }
else if (
const auto multigeo = geodata_cast<GeoDataMultiGeometry>(
object)) {
430 int rowCount = multigeo->size();
431 for (
int row = 0; row < rowCount; ++row) {
432 createGraphicsItemFromGeometry(multigeo->child(row), placemark, relations);
434 }
else if (
const auto multitrack = geodata_cast<GeoDataMultiTrack>(
object)) {
435 int rowCount = multitrack->size();
436 for (
int row = 0; row < rowCount; ++row) {
437 createGraphicsItemFromGeometry(multitrack->child(row), placemark, relations);
439 }
else if (
const auto track = geodata_cast<GeoDataTrack>(
object)) {
440 item =
new GeoTrackGraphicsItem(placemark, track);
445 item->setRelations(relations);
446 item->setStyleBuilder(m_styleBuilder);
447 item->setVisible(item->visible() && placemark->isGloballyVisible());
448 item->setMinZoomLevel(m_styleBuilder->minimumZoomLevel(*placemark));
449 m_scene.addItem(item);
452 void GeometryLayerPrivate::createGraphicsItemFromOverlay(
const GeoDataOverlay *overlay)
454 if (!overlay->isGloballyVisible()) {
458 GeoGraphicsItem* item =
nullptr;
459 if (
const auto photoOverlay = geodata_cast<GeoDataPhotoOverlay>(overlay)) {
460 GeoPhotoGraphicsItem *photoItem =
new GeoPhotoGraphicsItem(overlay);
461 photoItem->setPoint(photoOverlay->point());
463 }
else if (
const auto screenOverlay = geodata_cast<GeoDataScreenOverlay>(overlay)) {
464 ScreenOverlayGraphicsItem *screenItem =
new ScreenOverlayGraphicsItem(screenOverlay);
465 m_screenOverlays.push_back(screenItem);
469 item->setStyleBuilder(m_styleBuilder);
470 item->setVisible(overlay->isGloballyVisible());
471 m_scene.addItem(item);
475 void GeometryLayerPrivate::removeGraphicsItems(
const GeoDataFeature *feature)
478 if (
const auto placemark = geodata_cast<GeoDataPlacemark>(feature)) {
479 if (placemark->isGloballyVisible() &&
480 geodata_cast<GeoDataLineString>(placemark->geometry()) &&
481 placemark->hasOsmData() &&
482 placemark->osmData().oid() > 0) {
483 auto & items = m_osmLineStringItems[placemark->osmData().oid()];
484 bool removed =
false;
485 for (
auto item : items) {
486 if (item->feature() == feature) {
487 items.removeOne(item);
493 updateTiledLineStrings(items);
495 m_scene.removeItem(feature);
496 }
else if (
const auto container =
dynamic_cast<const GeoDataContainer*
>(feature)) {
497 for (
const GeoDataFeature *child: container->featureList()) {
498 removeGraphicsItems(child);
500 }
else if (geodata_cast<GeoDataScreenOverlay>(feature)) {
501 for (ScreenOverlayGraphicsItem *item: m_screenOverlays) {
502 if (item->screenOverlay() == feature) {
503 m_screenOverlays.removeAll(item);
509 void GeometryLayer::addPlacemarks(
const QModelIndex& parent,
int first,
int last)
511 Q_ASSERT(first < d->m_model->rowCount(parent));
512 Q_ASSERT(last < d->m_model->rowCount(parent));
513 for (
int i = first; i <= last; ++i) {
514 QModelIndex index = d->m_model->index(i, 0, parent);
518 d->createGraphicsItems(
object);
520 emit repaintNeeded();
524 void GeometryLayer::removePlacemarks(
const QModelIndex& parent,
int first,
int last)
526 Q_ASSERT(last < d->m_model->rowCount(parent));
527 bool isRepaintNeeded =
false;
528 for (
int i = first; i <= last; ++i) {
529 QModelIndex index = d->m_model->index(i, 0, parent);
532 const GeoDataFeature *feature =
dynamic_cast<const GeoDataFeature*
>(object);
533 if (feature !=
nullptr) {
534 d->removeGraphicsItems(feature);
535 isRepaintNeeded =
true;
538 if (isRepaintNeeded) {
539 emit repaintNeeded();
544 void GeometryLayer::resetCacheData()
548 qDeleteAll(d->m_screenOverlays);
549 d->m_screenOverlays.clear();
550 d->m_osmLineStringItems.clear();
552 const GeoDataObject *
object =
static_cast<GeoDataObject*
>(d->m_model->index(0, 0,
QModelIndex()).internalPointer());
553 if (
object && object->parent()) {
554 d->createGraphicsItems(object->parent());
556 emit repaintNeeded();
559 void GeometryLayer::setTileLevel(
int tileLevel)
561 d->m_tileLevel = tileLevel;
567 auto const renderOrder = d->m_styleBuilder->renderOrder();
570 for (
int i = renderOrder.
size()-1; i >= 0; --i) {
571 if (renderOrder[i].endsWith(label)) {
574 auto & layerItems = d->m_cachedPaintFragments[renderOrder[i]];
575 for (
auto j = layerItems.size()-1; j >= 0; --j) {
576 auto const & layerItem = layerItems[j];
578 if (layerItem->contains(curpos, viewport)) {
579 result << layerItem->feature();
581 checked << layerItem;
589 void GeometryLayer::highlightRouteRelation(qint64 osmId,
bool enabled)
592 d->m_highlightedRouteRelations << osmId;
594 d->m_highlightedRouteRelations.
remove(osmId);
596 d->updateRelationVisibility();
599 void GeometryLayer::setVisibleRelationTypes(GeoDataRelation::RelationTypes relationTypes)
601 if (relationTypes != d->m_visibleRelationTypes) {
602 d->m_visibleRelationTypes = relationTypes;
603 d->updateRelationVisibility();
609 GeoDataCoordinates clickedPoint(lon, lat, 0, unit);
612 for (
int i = 0; i < d->m_model->rowCount(); ++i) {
614 GeoDataObject *
object = qvariant_cast<GeoDataObject*> (data);
616 if (
const auto doc = geodata_cast<GeoDataDocument>(
object)) {
617 bool isHighlight =
false;
619 for (
const GeoDataStyleMap &styleMap: doc->styleMaps()) {
620 if (styleMap.contains(QStringLiteral(
"highlight"))) {
637 for (; iter !=
end; ++iter) {
638 if (
auto placemark = geodata_cast<GeoDataPlacemark>(*iter)) {
639 GeoDataPolygon *polygon =
dynamic_cast<GeoDataPolygon*
>(placemark->geometry());
641 polygon->contains(clickedPoint)) {
645 if (
auto linearRing = geodata_cast<GeoDataLinearRing>(placemark->geometry())) {
646 if (linearRing->contains(clickedPoint)) {
651 if (
auto multiGeometry = geodata_cast<GeoDataMultiGeometry>(placemark->geometry())) {
655 for (; multiIter != multiEnd; ++multiIter) {
656 GeoDataPolygon *poly =
dynamic_cast<GeoDataPolygon*
>(*multiIter);
659 poly->contains(clickedPoint)) {
664 if (
auto linearRing = geodata_cast<GeoDataLinearRing>(*multiIter)) {
665 if (linearRing->contains(clickedPoint)) {
678 emit highlightedPlacemarksChanged(selectedPlacemarks);
681 void GeometryLayer::setLevelTagDebugModeEnabled(
bool enabled)
683 if (d->m_levelTagDebugModeEnabled != enabled) {
684 d->m_levelTagDebugModeEnabled = enabled;
685 emit repaintNeeded();
689 bool GeometryLayer::levelTagDebugModeEnabled()
const
691 return d->m_levelTagDebugModeEnabled;
694 void GeometryLayer::setDebugLevelTag(
int level)
696 if (d->m_debugLevelTag != level) {
697 d->m_debugLevelTag =
level;
698 emit repaintNeeded();
702 int GeometryLayer::debugLevelTag()
const
704 return d->m_debugLevelTag;
709 #include "moc_GeometryLayer.cpp"