File indexing completed on 2024-04-28 07:37:59

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2006-2009 Torsten Rahn <tackat@kde.org>
0004 // SPDX-FileCopyrightText: 2007 Inge Wallin <ingwa@kde.org>
0005 // SPDX-FileCopyrightText: 2008 Carlos Licea <carlos.licea@kdemail.net>
0006 // SPDX-FileCopyrightText: 2009 Jens-Michael Hoffmann <jensmh@gmx.de>
0007 // SPDX-FileCopyrightText: 2010-2012 Bernhard Beschow <bbeschow@cs.tu-berlin.de>
0008 //
0009 
0010 
0011 // Own
0012 #include "MarbleMap.h"
0013 
0014 // Posix
0015 #include <cmath>
0016 
0017 // Qt
0018 #include <QElapsedTimer>
0019 #include <QtMath>
0020 
0021 // Marble
0022 #include "layers/FloatItemsLayer.h"
0023 #include "layers/FogLayer.h"
0024 #include "layers/FpsLayer.h"
0025 #include "layers/GeometryLayer.h"
0026 #include "layers/GroundLayer.h"
0027 #include "layers/MarbleSplashLayer.h"
0028 #include "layers/PlacemarkLayer.h"
0029 #include "layers/TextureLayer.h"
0030 #include "layers/VectorTileLayer.h"
0031 #include "AbstractFloatItem.h"
0032 #include "DgmlAuxillaryDictionary.h"
0033 #include "FileManager.h"
0034 #include "GeoDataTreeModel.h"
0035 #include "GeoPainter.h"
0036 #include "GeoSceneDocument.h"
0037 #include "GeoSceneFilter.h"
0038 #include "GeoSceneGeodata.h"
0039 #include "GeoSceneHead.h"
0040 #include "GeoSceneLayer.h"
0041 #include "GeoSceneMap.h"
0042 #include "GeoScenePalette.h"
0043 #include "GeoSceneSettings.h"
0044 #include "GeoSceneVector.h"
0045 #include "GeoSceneVectorTileDataset.h"
0046 #include "GeoSceneTextureTileDataset.h"
0047 #include "GeoSceneZoom.h"
0048 #include "GeoDataDocument.h"
0049 #include "GeoDataFeature.h"
0050 #include "GeoDataStyle.h"
0051 #include "GeoDataStyleMap.h"
0052 #include "LayerManager.h"
0053 #include "MapThemeManager.h"
0054 #include "MarbleDebug.h"
0055 #include "MarbleDirs.h"
0056 #include "MarbleModel.h"
0057 #include "PluginManager.h"
0058 #include "RenderPlugin.h"
0059 #include "StyleBuilder.h"
0060 #include "SunLocator.h"
0061 #include "TileId.h"
0062 #include "TileCoordsPyramid.h"
0063 #include "TileCreator.h"
0064 #include "TileCreatorDialog.h"
0065 #include "TileLoader.h"
0066 #include "ViewParams.h"
0067 #include "ViewportParams.h"
0068 #include "RenderState.h"
0069 #include "BookmarkManager.h"
0070 
0071 
0072 namespace Marble
0073 {
0074 
0075 
0076 class MarbleMap::CustomPaintLayer : public LayerInterface
0077 {
0078 public:
0079     explicit CustomPaintLayer( MarbleMap *map )
0080         : m_map( map )
0081     {
0082     }
0083 
0084     QStringList renderPosition() const override { return QStringList() << "USER_TOOLS"; }
0085 
0086     bool render( GeoPainter *painter, ViewportParams *viewport,
0087                          const QString &renderPos, GeoSceneLayer *layer ) override
0088     {
0089         Q_UNUSED( viewport );
0090         Q_UNUSED( renderPos );
0091         Q_UNUSED( layer );
0092 
0093         m_map->customPaint( painter );
0094 
0095         return true;
0096     }
0097 
0098     qreal zValue() const override { return 1.0e6; }
0099 
0100     RenderState renderState() const override { return RenderState(QStringLiteral("Custom Map Paint")); }
0101 
0102     QString runtimeTrace() const override { return QStringLiteral("CustomPaint"); }
0103 
0104 private:
0105     MarbleMap *const m_map;
0106 };
0107 
0108 
0109 class MarbleMapPrivate
0110 {
0111     friend class MarbleWidget;
0112 
0113 public:
0114     explicit MarbleMapPrivate( MarbleMap *parent, MarbleModel *model );
0115 
0116     void updateMapTheme();
0117 
0118     void updateProperty( const QString &, bool );
0119 
0120     void setDocument( const QString& key );
0121 
0122     void updateTileLevel();
0123 
0124     void addPlugins();
0125 
0126     MarbleMap *const q;
0127 
0128     // The model we are showing.
0129     MarbleModel     *const m_model;
0130     bool             m_modelIsOwned;
0131 
0132     // Parameters for the maps appearance.
0133     ViewParams       m_viewParams;
0134     ViewportParams   m_viewport;
0135     bool             m_showFrameRate;
0136     bool             m_showDebugPolygons;
0137     bool             m_showDebugBatchRender;
0138     GeoDataRelation::RelationTypes m_visibleRelationTypes;
0139     StyleBuilder     m_styleBuilder;
0140 
0141     QList<RenderPlugin *> m_renderPlugins;
0142 
0143     LayerManager     m_layerManager;
0144     MarbleSplashLayer m_marbleSplashLayer;
0145     MarbleMap::CustomPaintLayer m_customPaintLayer;
0146     GeometryLayer            m_geometryLayer;
0147     FloatItemsLayer          m_floatItemsLayer;
0148     FogLayer                 m_fogLayer;
0149     GroundLayer              m_groundLayer;
0150     TextureLayer     m_textureLayer;
0151     PlacemarkLayer   m_placemarkLayer;
0152     VectorTileLayer  m_vectorTileLayer;
0153 
0154     bool m_isLockedToSubSolarPoint;
0155     bool m_isSubSolarPointIconVisible;
0156     RenderState m_renderState;
0157 };
0158 
0159 MarbleMapPrivate::MarbleMapPrivate( MarbleMap *parent, MarbleModel *model ) :
0160     q( parent ),
0161     m_model( model ),
0162     m_viewParams(),
0163     m_showFrameRate( false ),
0164     m_showDebugPolygons( false ),
0165     m_showDebugBatchRender( false ),
0166     m_visibleRelationTypes(GeoDataRelation::RouteFerry),
0167     m_styleBuilder(),
0168     m_layerManager( parent ),
0169     m_customPaintLayer( parent ),
0170     m_geometryLayer(model->treeModel(), &m_styleBuilder),
0171     m_floatItemsLayer(parent),
0172     m_textureLayer( model->downloadManager(), model->pluginManager(), model->sunLocator(), model->groundOverlayModel() ),
0173     m_placemarkLayer( model->placemarkModel(), model->placemarkSelectionModel(), model->clock(), &m_styleBuilder ),
0174     m_vectorTileLayer( model->downloadManager(), model->pluginManager(), model->treeModel() ),
0175     m_isLockedToSubSolarPoint( false ),
0176     m_isSubSolarPointIconVisible( false )
0177 {
0178     m_layerManager.addLayer(&m_floatItemsLayer);
0179     m_layerManager.addLayer( &m_fogLayer );
0180     m_layerManager.addLayer( &m_groundLayer );
0181     m_layerManager.addLayer( &m_geometryLayer );
0182     m_layerManager.addLayer( &m_placemarkLayer );
0183     m_layerManager.addLayer( &m_customPaintLayer );
0184 
0185     m_model->bookmarkManager()->setStyleBuilder(&m_styleBuilder);
0186 
0187     QObject::connect( m_model, SIGNAL(themeChanged(QString)),
0188                       parent, SLOT(updateMapTheme()) );
0189     QObject::connect( m_model->fileManager(), SIGNAL(fileAdded(QString)),
0190                       parent, SLOT(setDocument(QString)) );
0191 
0192 
0193     QObject::connect( &m_placemarkLayer, SIGNAL(repaintNeeded()),
0194                       parent, SIGNAL(repaintNeeded()));
0195 
0196     QObject::connect ( &m_layerManager, SIGNAL(pluginSettingsChanged()),
0197                        parent,        SIGNAL(pluginSettingsChanged()) );
0198     QObject::connect ( &m_layerManager, SIGNAL(repaintNeeded(QRegion)),
0199                        parent,        SIGNAL(repaintNeeded(QRegion)) );
0200     QObject::connect ( &m_layerManager, SIGNAL(renderPluginInitialized(RenderPlugin*)),
0201                        parent,        SIGNAL(renderPluginInitialized(RenderPlugin*)) );
0202     QObject::connect ( &m_layerManager, SIGNAL(visibilityChanged(QString,bool)),
0203                        parent,        SLOT(setPropertyValue(QString,bool)) );
0204 
0205     QObject::connect( &m_geometryLayer, SIGNAL(repaintNeeded()),
0206                       parent, SIGNAL(repaintNeeded()));
0207 
0208     /*
0209      * Slot handleHighlight finds all placemarks
0210      * that contain the clicked point.
0211      * The placemarks under the clicked position may
0212      * have their styleUrl set to a style map which
0213      * doesn't specify any highlight styleId. Such
0214      * placemarks will be fletered out in GeoGraphicsScene
0215      * and will not be highlighted.
0216      */
0217     QObject::connect( parent, SIGNAL(highlightedPlacemarksChanged(qreal,qreal,GeoDataCoordinates::Unit)),
0218                       &m_geometryLayer, SLOT(handleHighlight(qreal,qreal,GeoDataCoordinates::Unit)) );
0219 
0220     QObject::connect(&m_floatItemsLayer, SIGNAL(repaintNeeded(QRegion)),
0221                      parent,             SIGNAL(repaintNeeded(QRegion)));
0222     QObject::connect(&m_floatItemsLayer, SIGNAL(renderPluginInitialized(RenderPlugin*)),
0223                      parent,             SIGNAL(renderPluginInitialized(RenderPlugin*)));
0224     QObject::connect(&m_floatItemsLayer, SIGNAL(visibilityChanged(QString,bool)),
0225                      parent,             SLOT(setPropertyValue(QString,bool)));
0226     QObject::connect(&m_floatItemsLayer, SIGNAL(pluginSettingsChanged()),
0227                      parent,             SIGNAL(pluginSettingsChanged()));
0228 
0229     QObject::connect( &m_textureLayer, SIGNAL(tileLevelChanged(int)),
0230                       parent, SLOT(updateTileLevel()) );
0231     QObject::connect( &m_vectorTileLayer, SIGNAL(tileLevelChanged(int)),
0232                       parent, SLOT(updateTileLevel()) );
0233     QObject::connect( parent, SIGNAL(radiusChanged(int)),
0234                       parent, SLOT(updateTileLevel()) );
0235 
0236     QObject::connect( &m_textureLayer, SIGNAL(repaintNeeded()),
0237                       parent, SIGNAL(repaintNeeded()) );
0238     QObject::connect( parent, SIGNAL(visibleLatLonAltBoxChanged(GeoDataLatLonAltBox)),
0239                       parent, SIGNAL(repaintNeeded()) );
0240 
0241     addPlugins();
0242     QObject::connect(model->pluginManager(), SIGNAL(renderPluginsChanged()),
0243                      parent, SLOT(addPlugins()));
0244 }
0245 
0246 void MarbleMapPrivate::updateProperty( const QString &name, bool show )
0247 {
0248     // earth
0249     if (name == QLatin1String("places")) {
0250         m_placemarkLayer.setShowPlaces( show );
0251     } else if (name == QLatin1String("cities")) {
0252         m_placemarkLayer.setShowCities( show );
0253     } else if (name == QLatin1String("terrain")) {
0254         m_placemarkLayer.setShowTerrain( show );
0255     } else if (name == QLatin1String("otherplaces")) {
0256         m_placemarkLayer.setShowOtherPlaces( show );
0257     }
0258 
0259     // other planets
0260     else if (name == QLatin1String("landingsites")) {
0261         m_placemarkLayer.setShowLandingSites( show );
0262     } else if (name == QLatin1String("craters")) {
0263         m_placemarkLayer.setShowCraters( show );
0264     } else if (name == QLatin1String("maria")) {
0265         m_placemarkLayer.setShowMaria( show );
0266     }
0267 
0268     else if (name == QLatin1String("relief")) {
0269         m_textureLayer.setShowRelief( show );
0270     }
0271 
0272     for(RenderPlugin *renderPlugin: m_renderPlugins) {
0273         if ( name == renderPlugin->nameId() ) {
0274             if ( renderPlugin->visible() == show ) {
0275                 break;
0276             }
0277 
0278             renderPlugin->setVisible( show );
0279 
0280             break;
0281         }
0282     }
0283 }
0284 
0285 void MarbleMapPrivate::addPlugins()
0286 {
0287     for (const RenderPlugin *factory: m_model->pluginManager()->renderPlugins()) {
0288         bool alreadyCreated = false;
0289         for(const RenderPlugin *existing: m_renderPlugins) {
0290             if (existing->nameId() == factory->nameId()) {
0291                 alreadyCreated = true;
0292                 break;
0293             }
0294         }
0295 
0296         if (alreadyCreated) {
0297             continue;
0298         }
0299 
0300         RenderPlugin *const renderPlugin = factory->newInstance(m_model);
0301         Q_ASSERT(renderPlugin && "Plugin must not return null when requesting a new instance.");
0302         m_renderPlugins << renderPlugin;
0303 
0304         if (AbstractFloatItem *const floatItem = qobject_cast<AbstractFloatItem *>(renderPlugin)) {
0305             m_floatItemsLayer.addFloatItem(floatItem);
0306         }
0307         else {
0308             m_layerManager.addRenderPlugin(renderPlugin);
0309         }
0310     }
0311 }
0312 
0313 // ----------------------------------------------------------------
0314 
0315 
0316 MarbleMap::MarbleMap()
0317     : d( new MarbleMapPrivate( this, new MarbleModel( this ) ) )
0318 {
0319     // nothing to do
0320 }
0321 
0322 MarbleMap::MarbleMap(MarbleModel *model)
0323     : d( new MarbleMapPrivate( this, model ) )
0324 {
0325     d->m_modelIsOwned = false;
0326 }
0327 
0328 MarbleMap::~MarbleMap()
0329 {
0330     MarbleModel *model = d->m_modelIsOwned ? d->m_model : nullptr;
0331 
0332     d->m_layerManager.removeLayer( &d->m_customPaintLayer );
0333     d->m_layerManager.removeLayer( &d->m_geometryLayer );
0334     d->m_layerManager.removeLayer(&d->m_floatItemsLayer);
0335     d->m_layerManager.removeLayer( &d->m_fogLayer );
0336     d->m_layerManager.removeLayer( &d->m_placemarkLayer );
0337     d->m_layerManager.removeLayer( &d->m_textureLayer );
0338     d->m_layerManager.removeLayer( &d->m_groundLayer );
0339     qDeleteAll(d->m_renderPlugins);
0340     delete d;
0341 
0342     delete model;  // delete the model after private data
0343 }
0344 
0345 MarbleModel *MarbleMap::model() const
0346 {
0347     return d->m_model;
0348 }
0349 
0350 ViewportParams *MarbleMap::viewport()
0351 {
0352     return &d->m_viewport;
0353 }
0354 
0355 const ViewportParams *MarbleMap::viewport() const
0356 {
0357     return &d->m_viewport;
0358 }
0359 
0360 
0361 void MarbleMap::setMapQualityForViewContext( MapQuality quality, ViewContext viewContext )
0362 {
0363     d->m_viewParams.setMapQualityForViewContext( quality, viewContext );
0364 
0365     // Update texture map during the repaint that follows:
0366     d->m_textureLayer.setNeedsUpdate();
0367 }
0368 
0369 MapQuality MarbleMap::mapQuality( ViewContext viewContext ) const
0370 {
0371     return d->m_viewParams.mapQuality( viewContext );
0372 }
0373 
0374 MapQuality MarbleMap::mapQuality() const
0375 {
0376     return d->m_viewParams.mapQuality();
0377 }
0378 
0379 void MarbleMap::setViewContext( ViewContext viewContext )
0380 {
0381     if ( d->m_viewParams.viewContext() == viewContext ) {
0382         return;
0383     }
0384 
0385     const MapQuality oldQuality = d->m_viewParams.mapQuality();
0386     d->m_viewParams.setViewContext( viewContext );
0387     emit viewContextChanged( viewContext );
0388 
0389     if ( d->m_viewParams.mapQuality() != oldQuality ) {
0390         // Update texture map during the repaint that follows:
0391         d->m_textureLayer.setNeedsUpdate();
0392 
0393         emit repaintNeeded();
0394     }
0395 }
0396 
0397 ViewContext MarbleMap::viewContext() const
0398 {
0399     return d->m_viewParams.viewContext();
0400 }
0401 
0402 
0403 void MarbleMap::setSize( int width, int height )
0404 {
0405     setSize( QSize( width, height ) );
0406 }
0407 
0408 void MarbleMap::setSize( const QSize& size )
0409 {
0410     d->m_viewport.setSize( size );
0411 
0412     emit visibleLatLonAltBoxChanged( d->m_viewport.viewLatLonAltBox() );
0413 }
0414 
0415 QSize MarbleMap::size() const
0416 {
0417     return QSize( d->m_viewport.width(), d->m_viewport.height() );
0418 }
0419 
0420 int  MarbleMap::width() const
0421 {
0422     return d->m_viewport.width();
0423 }
0424 
0425 int  MarbleMap::height() const
0426 {
0427     return d->m_viewport.height();
0428 }
0429 
0430 int MarbleMap::radius() const
0431 {
0432     return d->m_viewport.radius();
0433 }
0434 
0435 void MarbleMap::setRadius( int radius )
0436 {
0437     const int oldRadius = d->m_viewport.radius();
0438 
0439     d->m_viewport.setRadius( radius );
0440 
0441     if ( oldRadius != d->m_viewport.radius() ) {
0442         emit radiusChanged( radius );
0443         emit visibleLatLonAltBoxChanged( d->m_viewport.viewLatLonAltBox() );
0444     }
0445 }
0446 
0447 
0448 int MarbleMap::preferredRadiusCeil(int radius) const
0449 {
0450     return d->m_textureLayer.preferredRadiusCeil( radius );
0451 }
0452 
0453 
0454 int MarbleMap::preferredRadiusFloor(int radius) const
0455 {
0456     return d->m_textureLayer.preferredRadiusFloor( radius );
0457 }
0458 
0459 
0460 int MarbleMap::tileZoomLevel() const
0461 {
0462     auto const tileZoomLevel = qMax(d->m_textureLayer.tileZoomLevel(), d->m_vectorTileLayer.tileZoomLevel());
0463     return tileZoomLevel >= 0 ? tileZoomLevel : qMin<int>(qMax<int>(qLn(d->m_viewport.radius()*4/256)/qLn(2.0), 1), d->m_styleBuilder.maximumZoomLevel());
0464 }
0465 
0466 
0467 qreal MarbleMap::centerLatitude() const
0468 {
0469     // Calculate translation of center point
0470     const qreal centerLat = d->m_viewport.centerLatitude();
0471 
0472     return centerLat * RAD2DEG;
0473 }
0474 
0475 bool MarbleMap::hasFeatureAt(const QPoint &position) const
0476 {
0477     return d->m_placemarkLayer.hasPlacemarkAt(position) || d->m_geometryLayer.hasFeatureAt(position, viewport());
0478 }
0479 
0480 qreal MarbleMap::centerLongitude() const
0481 {
0482     // Calculate translation of center point
0483     const qreal centerLon = d->m_viewport.centerLongitude();
0484 
0485     return centerLon * RAD2DEG;
0486 }
0487 
0488 int  MarbleMap::minimumZoom() const
0489 {
0490     if ( d->m_model->mapTheme() )
0491         return d->m_model->mapTheme()->head()->zoom()->minimum();
0492 
0493     return 950;
0494 }
0495 
0496 int  MarbleMap::maximumZoom() const
0497 {
0498     if ( d->m_model->mapTheme() )
0499         return d->m_model->mapTheme()->head()->zoom()->maximum();
0500 
0501     return 2100;
0502 }
0503 
0504 bool MarbleMap::discreteZoom() const
0505 {
0506     if ( d->m_model->mapTheme() )
0507         return d->m_model->mapTheme()->head()->zoom()->discrete();
0508 
0509     return false;
0510 }
0511 
0512 QVector<const GeoDataFeature*> MarbleMap::whichFeatureAt( const QPoint& curpos ) const
0513 {
0514     return d->m_placemarkLayer.whichPlacemarkAt( curpos ) + d->m_geometryLayer.whichFeatureAt( curpos, viewport() );
0515 }
0516 
0517 void MarbleMap::reload()
0518 {
0519     d->m_textureLayer.reload();
0520     d->m_vectorTileLayer.reload();
0521 }
0522 
0523 void MarbleMap::downloadRegion( QVector<TileCoordsPyramid> const & pyramid )
0524 {
0525     Q_ASSERT( textureLayer() );
0526     Q_ASSERT( !pyramid.isEmpty() );
0527     QElapsedTimer t;
0528     t.start();
0529 
0530     // When downloading a region (the author of these lines thinks) most users probably expect
0531     // the download to begin with the low resolution tiles and then procede level-wise to
0532     // higher resolution tiles. In order to achieve this, we start requesting downloads of
0533     // high resolution tiles and request the low resolution tiles at the end because
0534     // DownloadQueueSet (silly name) is implemented as stack.
0535 
0536 
0537     int const first = 0;
0538     int tilesCount = 0;
0539 
0540     for ( int level = pyramid[first].bottomLevel(); level >= pyramid[first].topLevel(); --level ) {
0541         QSet<TileId> tileIdSet;
0542         for( int i = 0; i < pyramid.size(); ++i ) {
0543             QRect const coords = pyramid[i].coords( level );
0544             mDebug() << "MarbleMap::downloadRegion level:" << level << "tile coords:" << coords;
0545             int x1, y1, x2, y2;
0546             coords.getCoords( &x1, &y1, &x2, &y2 );
0547             for ( int x = x1; x <= x2; ++x ) {
0548                 for ( int y = y1; y <= y2; ++y ) {
0549                     TileId const stackedTileId( 0, level, x, y );
0550                     tileIdSet.insert( stackedTileId );
0551                     // FIXME: use lazy evaluation to not generate up to 100k tiles in one go
0552                     // this can take considerable time even on very fast systems
0553                     // in contrast generating the TileIds on the fly when they are needed
0554                     // does not seem to affect download speed.
0555                 }
0556             }
0557         }
0558         QSetIterator<TileId> i( tileIdSet );
0559         while( i.hasNext() ) {
0560             TileId const tileId = i.next();
0561             d->m_textureLayer.downloadStackedTile( tileId );
0562             d->m_vectorTileLayer.downloadTile(tileId);
0563             mDebug() << "TileDownload" << tileId;
0564         }
0565         tilesCount += tileIdSet.count();
0566     }
0567     // Needed for downloading unique tiles only. Much faster than if tiles for each level is downloaded separately
0568 
0569     int const elapsedMs = t.elapsed();
0570     mDebug() << "MarbleMap::downloadRegion:" << tilesCount << "tiles, " << elapsedMs << "ms";
0571 }
0572 
0573 void MarbleMap::highlightRouteRelation(qint64 osmId, bool enabled)
0574 {
0575     d->m_geometryLayer.highlightRouteRelation(osmId, enabled);
0576 }
0577 
0578 bool MarbleMap::propertyValue( const QString& name ) const
0579 {
0580     bool value;
0581     if ( d->m_model->mapTheme() ) {
0582         d->m_model->mapTheme()->settings()->propertyValue( name, value );
0583     }
0584     else {
0585         value = false;
0586         mDebug() << "WARNING: Failed to access a map theme! Property: " << name;
0587     }
0588     return value;
0589 }
0590 
0591 bool MarbleMap::showOverviewMap() const
0592 {
0593     return propertyValue(QStringLiteral("overviewmap"));
0594 }
0595 
0596 bool MarbleMap::showScaleBar() const
0597 {
0598     return propertyValue(QStringLiteral("scalebar"));
0599 }
0600 
0601 bool MarbleMap::showCompass() const
0602 {
0603     return propertyValue(QStringLiteral("compass"));
0604 }
0605 
0606 bool MarbleMap::showGrid() const
0607 {
0608     return propertyValue(QStringLiteral("coordinate-grid"));
0609 }
0610 
0611 bool MarbleMap::showClouds() const
0612 {
0613     return d->m_viewParams.showClouds();
0614 }
0615 
0616 bool MarbleMap::showSunShading() const
0617 {
0618     return d->m_textureLayer.showSunShading();
0619 }
0620 
0621 bool MarbleMap::showCityLights() const
0622 {
0623     return d->m_textureLayer.showCityLights();
0624 }
0625 
0626 bool MarbleMap::isLockedToSubSolarPoint() const
0627 {
0628     return d->m_isLockedToSubSolarPoint;
0629 }
0630 
0631 bool MarbleMap::isSubSolarPointIconVisible() const
0632 {
0633     return d->m_isSubSolarPointIconVisible;
0634 }
0635 
0636 bool MarbleMap::showAtmosphere() const
0637 {
0638     return d->m_viewParams.showAtmosphere();
0639 }
0640 
0641 bool MarbleMap::showCrosshairs() const
0642 {
0643     bool visible = false;
0644 
0645     QList<RenderPlugin *> pluginList = renderPlugins();
0646     QList<RenderPlugin *>::const_iterator i = pluginList.constBegin();
0647     QList<RenderPlugin *>::const_iterator const end = pluginList.constEnd();
0648     for (; i != end; ++i ) {
0649         if ((*i)->nameId() == QLatin1String("crosshairs")) {
0650             visible = (*i)->visible();
0651         }
0652     }
0653 
0654     return visible;
0655 }
0656 
0657 bool MarbleMap::showPlaces() const
0658 {
0659     return propertyValue(QStringLiteral("places"));
0660 }
0661 
0662 bool MarbleMap::showCities() const
0663 {
0664     return propertyValue(QStringLiteral("cities"));
0665 }
0666 
0667 bool MarbleMap::showTerrain() const
0668 {
0669     return propertyValue(QStringLiteral("terrain"));
0670 }
0671 
0672 bool MarbleMap::showOtherPlaces() const
0673 {
0674     return propertyValue(QStringLiteral("otherplaces"));
0675 }
0676 
0677 bool MarbleMap::showRelief() const
0678 {
0679     return propertyValue(QStringLiteral("relief"));
0680 }
0681 
0682 bool MarbleMap::showIceLayer() const
0683 {
0684     return propertyValue(QStringLiteral("ice"));
0685 }
0686 
0687 bool MarbleMap::showBorders() const
0688 {
0689     return propertyValue(QStringLiteral("borders"));
0690 }
0691 
0692 bool MarbleMap::showRivers() const
0693 {
0694     return propertyValue(QStringLiteral("rivers"));
0695 }
0696 
0697 bool MarbleMap::showLakes() const
0698 {
0699     return propertyValue(QStringLiteral("lakes"));
0700 }
0701 
0702 bool MarbleMap::showFrameRate() const
0703 {
0704     return d->m_showFrameRate;
0705 }
0706 
0707 bool MarbleMap::showBackground() const
0708 {
0709     return d->m_layerManager.showBackground();
0710 }
0711 
0712 GeoDataRelation::RelationTypes MarbleMap::visibleRelationTypes() const
0713 {
0714     return d->m_visibleRelationTypes;
0715 }
0716 
0717 quint64 MarbleMap::volatileTileCacheLimit() const
0718 {
0719     return d->m_textureLayer.volatileCacheLimit();
0720 }
0721 
0722 
0723 void MarbleMap::rotateBy(qreal deltaLon, qreal deltaLat)
0724 {
0725     centerOn( d->m_viewport.centerLongitude() * RAD2DEG + deltaLon,
0726               d->m_viewport.centerLatitude()  * RAD2DEG + deltaLat );
0727 }
0728 
0729 
0730 void MarbleMap::centerOn( const qreal lon, const qreal lat )
0731 {
0732     d->m_viewport.centerOn( lon * DEG2RAD, lat * DEG2RAD );
0733 
0734     emit visibleLatLonAltBoxChanged( d->m_viewport.viewLatLonAltBox() );
0735 }
0736 
0737 void MarbleMap::setCenterLatitude( qreal lat )
0738 {
0739     centerOn( centerLongitude(), lat );
0740 }
0741 
0742 void MarbleMap::setCenterLongitude( qreal lon )
0743 {
0744     centerOn( lon, centerLatitude() );
0745 }
0746 
0747 Projection MarbleMap::projection() const
0748 {
0749     return d->m_viewport.projection();
0750 }
0751 
0752 void MarbleMap::setProjection( Projection projection )
0753 {
0754     if ( d->m_viewport.projection() == projection )
0755         return;
0756 
0757     emit projectionChanged( projection );
0758 
0759     d->m_viewport.setProjection( projection );
0760 
0761     d->m_textureLayer.setProjection( projection );
0762 
0763     emit visibleLatLonAltBoxChanged( d->m_viewport.viewLatLonAltBox() );
0764 }
0765 
0766 
0767 bool MarbleMap::screenCoordinates( qreal lon, qreal lat,
0768                                    qreal& x, qreal& y ) const
0769 {
0770     return d->m_viewport.screenCoordinates( lon * DEG2RAD, lat * DEG2RAD, x, y );
0771 }
0772 
0773 bool MarbleMap::geoCoordinates( int x, int y,
0774                                 qreal& lon, qreal& lat,
0775                                 GeoDataCoordinates::Unit unit ) const
0776 {
0777     return d->m_viewport.geoCoordinates( x, y, lon, lat, unit );
0778 }
0779 
0780 void MarbleMapPrivate::setDocument( const QString& key )
0781 {
0782     if ( !m_model->mapTheme() ) {
0783         // Happens if no valid map theme is set or at application startup
0784         // if a file is passed via command line parameters and the last
0785         // map theme has not been loaded yet
0786         /**
0787          * @todo Do we need to queue the document and process it once a map
0788          * theme becomes available?
0789          */
0790         return;
0791     }
0792 
0793     GeoDataDocument* doc = m_model->fileManager()->at( key );
0794 
0795     for ( const GeoSceneLayer *layer: m_model->mapTheme()->map()->layers() ) {
0796         if ( layer->backend() != dgml::dgmlValue_geodata
0797              && layer->backend() != dgml::dgmlValue_vector )
0798             continue;
0799 
0800         // look for documents
0801         for ( const GeoSceneAbstractDataset *dataset: layer->datasets() ) {
0802             const GeoSceneGeodata *data = static_cast<const GeoSceneGeodata*>( dataset );
0803             QString containername = data->sourceFile();
0804             QString colorize = data->colorize();
0805             if( key == containername ) {
0806                 if (colorize == QLatin1String("land")) {
0807                     m_textureLayer.addLandDocument( doc );
0808                 }
0809                 if (colorize == QLatin1String("sea")) {
0810                     m_textureLayer.addSeaDocument( doc );
0811                 }
0812 
0813                 // set visibility according to theme property
0814                 if( !data->property().isEmpty() ) {
0815                     bool value;
0816                     m_model->mapTheme()->settings()->propertyValue( data->property(), value );
0817                     doc->setVisible( value );
0818                     m_model->treeModel()->updateFeature( doc );
0819                 }
0820             }
0821         }
0822     }
0823 }
0824 
0825 void MarbleMapPrivate::updateTileLevel()
0826 {
0827     auto const tileZoomLevel = q->tileZoomLevel();
0828     m_geometryLayer.setTileLevel(tileZoomLevel);
0829     m_placemarkLayer.setTileLevel(tileZoomLevel);
0830     emit q->tileLevelChanged(tileZoomLevel);
0831 }
0832 
0833 // Used to be paintEvent()
0834 void MarbleMap::paint( GeoPainter &painter, const QRect &dirtyRect )
0835 {
0836     Q_UNUSED( dirtyRect );
0837 
0838     if (d->m_showDebugPolygons ) {
0839         if (viewContext() == Animation) {
0840             painter.setDebugPolygonsLevel(1);
0841         }
0842         else {
0843             painter.setDebugPolygonsLevel(2);
0844         }
0845     }
0846     painter.setDebugBatchRender(d->m_showDebugBatchRender);
0847 
0848     if ( !d->m_model->mapTheme() ) {
0849         mDebug() << "No theme yet!";
0850         d->m_marbleSplashLayer.render( &painter, &d->m_viewport );
0851         return;
0852     }
0853 
0854     QElapsedTimer t;
0855     t.start();
0856 
0857     RenderStatus const oldRenderStatus = d->m_renderState.status();
0858     d->m_layerManager.renderLayers( &painter, &d->m_viewport );
0859     d->m_renderState = d->m_layerManager.renderState();
0860     bool const parsing = d->m_model->fileManager()->pendingFiles() > 0;
0861     d->m_renderState.addChild(RenderState(QStringLiteral("Files"), parsing ? WaitingForData : Complete));
0862     RenderStatus const newRenderStatus = d->m_renderState.status();
0863     if ( oldRenderStatus != newRenderStatus ) {
0864         emit renderStatusChanged( newRenderStatus );
0865     }
0866     emit renderStateChanged( d->m_renderState );
0867 
0868     if ( d->m_showFrameRate ) {
0869         FpsLayer fpsPainter( &t );
0870         fpsPainter.paint( &painter );
0871     }
0872 
0873     const qreal fps = 1000.0 / (qreal)( t.elapsed() );
0874     emit framesPerSecond( fps );
0875 }
0876 
0877 void MarbleMap::customPaint( GeoPainter *painter )
0878 {
0879     Q_UNUSED( painter );
0880 }
0881 
0882 QString MarbleMap::mapThemeId() const
0883 {
0884     return d->m_model->mapThemeId();
0885 }
0886 
0887 void MarbleMap::setMapThemeId( const QString& mapThemeId )
0888 {
0889     d->m_model->setMapThemeId( mapThemeId );
0890 }
0891 
0892 void MarbleMapPrivate::updateMapTheme()
0893 {
0894     m_layerManager.removeLayer( &m_textureLayer );
0895     // FIXME Find a better way to do this reset. Maybe connect to themeChanged SIGNAL?
0896     m_vectorTileLayer.reset();
0897     m_layerManager.removeLayer( &m_vectorTileLayer );
0898     m_layerManager.removeLayer( &m_groundLayer );
0899 
0900     QObject::connect( m_model->mapTheme()->settings(), SIGNAL(valueChanged(QString,bool)),
0901                       q, SLOT(updateProperty(QString,bool)) );
0902     QObject::connect( m_model->mapTheme()->settings(), SIGNAL(valueChanged(QString,bool)),
0903                       m_model, SLOT(updateProperty(QString,bool)) );
0904 
0905     q->setPropertyValue(QStringLiteral("clouds_data"), m_viewParams.showClouds());
0906 
0907     QColor backgroundColor = m_styleBuilder.effectColor(m_model->mapTheme()->map()->backgroundColor());
0908     m_groundLayer.setColor(backgroundColor);
0909 
0910     // Check whether there is a texture layer and vectortile layer available:
0911     if ( m_model->mapTheme()->map()->hasTextureLayers() ) {
0912         const GeoSceneSettings *const settings = m_model->mapTheme()->settings();
0913         const GeoSceneGroup *const textureLayerSettings = settings ? settings->group( "Texture Layers" ) : nullptr;
0914         const GeoSceneGroup *const vectorTileLayerSettings = settings ? settings->group( "VectorTile Layers" ) : nullptr;
0915 
0916         bool textureLayersOk = true;
0917         bool vectorTileLayersOk = true;
0918 
0919         // textures will contain texture layers and
0920         // vectorTiles vectortile layers
0921         QVector<const GeoSceneTextureTileDataset *> textures;
0922         QVector<const GeoSceneVectorTileDataset *> vectorTiles;
0923 
0924         for( GeoSceneLayer* layer: m_model->mapTheme()->map()->layers() ){
0925             if ( layer->backend() == dgml::dgmlValue_texture ){
0926 
0927                 for ( const GeoSceneAbstractDataset *pos: layer->datasets() ) {
0928                     const GeoSceneTextureTileDataset *const texture = dynamic_cast<GeoSceneTextureTileDataset const *>( pos );
0929                     if ( !texture )
0930                         continue;
0931 
0932                     const QString sourceDir = texture->sourceDir();
0933                     const QString installMap = texture->installMap();
0934                     const QString role = layer->role();
0935 
0936                     // If the tiles aren't already there, put up a progress dialog
0937                     // while creating them.
0938                     if ( !TileLoader::baseTilesAvailable( *texture )
0939                          && !installMap.isEmpty() )
0940                     {
0941                         mDebug() << "Base tiles not available. Creating Tiles ... \n"
0942                                  << "SourceDir: " << sourceDir << "InstallMap:" << installMap;
0943 
0944                         TileCreator *tileCreator = new TileCreator(
0945                                     sourceDir,
0946                                     installMap,
0947                                     (role == QLatin1String("dem")) ? "true" : "false" );
0948                         tileCreator->setTileFormat( texture->fileFormat().toLower() );
0949 
0950                         QPointer<TileCreatorDialog> tileCreatorDlg = new TileCreatorDialog( tileCreator, nullptr );
0951                         tileCreatorDlg->setSummary( m_model->mapTheme()->head()->name(),
0952                                                     m_model->mapTheme()->head()->description() );
0953                         tileCreatorDlg->exec();
0954                         if ( TileLoader::baseTilesAvailable( *texture ) ) {
0955                             mDebug() << "Base tiles for" << sourceDir << "successfully created.";
0956                         } else {
0957                             qWarning() << "Some or all base tiles for" << sourceDir << "could not be created.";
0958                         }
0959 
0960                         delete tileCreatorDlg;
0961                     }
0962 
0963                     if ( TileLoader::baseTilesAvailable( *texture ) ) {
0964                         textures.append( texture );
0965                     } else {
0966                         qWarning() << "Base tiles for" << sourceDir << "not available. Skipping all texture layers.";
0967                         textureLayersOk = false;
0968                     }
0969                 }
0970             }
0971             else if ( layer->backend() == dgml::dgmlValue_vectortile ){
0972 
0973                 for ( const GeoSceneAbstractDataset *pos: layer->datasets() ) {
0974                     const GeoSceneVectorTileDataset *const vectorTile = dynamic_cast<GeoSceneVectorTileDataset const *>( pos );
0975                     if ( !vectorTile )
0976                         continue;
0977 
0978                     const QString sourceDir = vectorTile->sourceDir();
0979                     const QString installMap = vectorTile->installMap();
0980                     const QString role = layer->role();
0981 
0982                     // If the tiles aren't already there, put up a progress dialog
0983                     // while creating them.
0984                     if ( !TileLoader::baseTilesAvailable( *vectorTile )
0985                          && !installMap.isEmpty() )
0986                     {
0987                         mDebug() << "Base tiles not available. Creating Tiles ... \n"
0988                                  << "SourceDir: " << sourceDir << "InstallMap:" << installMap;
0989 
0990                         TileCreator *tileCreator = new TileCreator(
0991                                     sourceDir,
0992                                     installMap,
0993                                     (role == QLatin1String("dem")) ? "true" : "false" );
0994                         tileCreator->setTileFormat( vectorTile->fileFormat().toLower() );
0995 
0996                         QPointer<TileCreatorDialog> tileCreatorDlg = new TileCreatorDialog( tileCreator, nullptr );
0997                         tileCreatorDlg->setSummary( m_model->mapTheme()->head()->name(),
0998                                                     m_model->mapTheme()->head()->description() );
0999                         tileCreatorDlg->exec();
1000                         if ( TileLoader::baseTilesAvailable( *vectorTile ) ) {
1001                             qDebug() << "Base tiles for" << sourceDir << "successfully created.";
1002                         } else {
1003                             qDebug() << "Some or all base tiles for" << sourceDir << "could not be created.";
1004                         }
1005 
1006                         delete tileCreatorDlg;
1007                     }
1008 
1009                     if ( TileLoader::baseTilesAvailable( *vectorTile ) ) {
1010                         vectorTiles.append( vectorTile );
1011                     } else {
1012                         qWarning() << "Base tiles for" << sourceDir << "not available. Skipping all texture layers.";
1013                         vectorTileLayersOk = false;
1014                     }
1015                 }
1016             }
1017         }
1018 
1019         QString seafile, landfile;
1020         if( !m_model->mapTheme()->map()->filters().isEmpty() ) {
1021             const GeoSceneFilter *filter= m_model->mapTheme()->map()->filters().first();
1022 
1023             if (filter->type() == QLatin1String("colorize")) {
1024                 //no need to look up with MarbleDirs twice so they are left null for now
1025                 QList<const GeoScenePalette*> palette = filter->palette();
1026                 for (const GeoScenePalette *curPalette: palette ) {
1027 
1028                     if (curPalette->type() == QLatin1String("sea")) {
1029                         seafile = MarbleDirs::path( curPalette->file() );
1030                     } else if (curPalette->type() == QLatin1String("land")) {
1031                         landfile = MarbleDirs::path( curPalette->file() );
1032                     }
1033                 }
1034                 //look up locations if they are empty
1035                 if( seafile.isEmpty() )
1036                     seafile = MarbleDirs::path(QStringLiteral("seacolors.leg"));
1037                 if( landfile.isEmpty() )
1038                     landfile = MarbleDirs::path(QStringLiteral("landcolors.leg"));
1039             }
1040         }
1041 
1042         m_textureLayer.setMapTheme( textures, textureLayerSettings, seafile, landfile );
1043         m_textureLayer.setProjection( m_viewport.projection() );
1044         m_textureLayer.setShowRelief( q->showRelief() );
1045 
1046         m_vectorTileLayer.setMapTheme( vectorTiles, vectorTileLayerSettings );
1047 
1048         if (m_textureLayer.layerCount() == 0) {
1049             m_layerManager.addLayer( &m_groundLayer );
1050         }
1051 
1052         if ( textureLayersOk )
1053             m_layerManager.addLayer( &m_textureLayer );
1054         if ( vectorTileLayersOk && !vectorTiles.isEmpty() )
1055             m_layerManager.addLayer( &m_vectorTileLayer );
1056     }
1057     else {
1058         m_layerManager.addLayer( &m_groundLayer );
1059         m_textureLayer.setMapTheme( QVector<const GeoSceneTextureTileDataset *>(), nullptr, "", "" );
1060         m_vectorTileLayer.setMapTheme( QVector<const GeoSceneVectorTileDataset *>(), nullptr );
1061     }
1062 
1063     // earth
1064     m_placemarkLayer.setShowPlaces( q->showPlaces() );
1065 
1066     m_placemarkLayer.setShowCities( q->showCities() );
1067     m_placemarkLayer.setShowTerrain( q->showTerrain() );
1068     m_placemarkLayer.setShowOtherPlaces( q->showOtherPlaces() );
1069     m_placemarkLayer.setShowLandingSites(q->propertyValue(QStringLiteral("landingsites")));
1070     m_placemarkLayer.setShowCraters(q->propertyValue(QStringLiteral("craters")));
1071     m_placemarkLayer.setShowMaria(q->propertyValue(QStringLiteral("maria")));
1072 
1073     m_styleBuilder.setDefaultLabelColor(m_model->mapTheme()->map()->labelColor());
1074     m_placemarkLayer.requestStyleReset();
1075 
1076     for (RenderPlugin *renderPlugin: m_renderPlugins) {
1077         bool propertyAvailable = false;
1078         m_model->mapTheme()->settings()->propertyAvailable( renderPlugin->nameId(), propertyAvailable );
1079         bool propertyValue = false;
1080         m_model->mapTheme()->settings()->propertyValue( renderPlugin->nameId(), propertyValue );
1081 
1082         if ( propertyAvailable ) {
1083             renderPlugin->setVisible( propertyValue );
1084         }
1085     }
1086 
1087     emit q->themeChanged( m_model->mapTheme()->head()->mapThemeId() );
1088 }
1089 
1090 void MarbleMap::setPropertyValue( const QString& name, bool value )
1091 {
1092     mDebug() << "In MarbleMap the property " << name << "was set to " << value;
1093     if ( d->m_model->mapTheme() ) {
1094         d->m_model->mapTheme()->settings()->setPropertyValue( name, value );
1095         d->m_textureLayer.setNeedsUpdate();
1096         emit propertyValueChanged(name, value);
1097     }
1098     else {
1099         mDebug() << "WARNING: Failed to access a map theme! Property: " << name;
1100     }
1101     if (d->m_textureLayer.layerCount() == 0) {
1102         d->m_layerManager.addLayer( &d->m_groundLayer );
1103     }
1104     else {
1105         d->m_layerManager.removeLayer( &d->m_groundLayer );
1106     }
1107 }
1108 
1109 void MarbleMap::setShowOverviewMap( bool visible )
1110 {
1111     setPropertyValue(QStringLiteral("overviewmap"), visible);
1112 }
1113 
1114 void MarbleMap::setShowScaleBar( bool visible )
1115 {
1116     setPropertyValue(QStringLiteral("scalebar"), visible);
1117 }
1118 
1119 void MarbleMap::setShowCompass( bool visible )
1120 {
1121     setPropertyValue(QStringLiteral("compass"), visible);
1122 }
1123 
1124 void MarbleMap::setShowAtmosphere( bool visible )
1125 {
1126     for ( RenderPlugin *plugin: renderPlugins() ) {
1127         if (plugin->nameId() == QLatin1String("atmosphere")) {
1128             plugin->setVisible( visible );
1129         }
1130     }
1131 
1132     d->m_viewParams.setShowAtmosphere( visible );
1133 }
1134 
1135 void MarbleMap::setShowCrosshairs( bool visible )
1136 {
1137     QList<RenderPlugin *> pluginList = renderPlugins();
1138     QList<RenderPlugin *>::const_iterator i = pluginList.constBegin();
1139     QList<RenderPlugin *>::const_iterator const end = pluginList.constEnd();
1140     for (; i != end; ++i ) {
1141         if ((*i)->nameId() == QLatin1String("crosshairs")) {
1142             (*i)->setVisible( visible );
1143         }
1144     }
1145 }
1146 
1147 void MarbleMap::setShowClouds( bool visible )
1148 {
1149     d->m_viewParams.setShowClouds( visible );
1150 
1151     setPropertyValue(QStringLiteral("clouds_data"), visible);
1152 }
1153 
1154 void MarbleMap::setShowSunShading( bool visible )
1155 {
1156     d->m_textureLayer.setShowSunShading( visible );
1157 }
1158 
1159 void MarbleMap::setShowCityLights( bool visible )
1160 {
1161     d->m_textureLayer.setShowCityLights( visible );
1162     setPropertyValue(QStringLiteral("citylights"), visible);
1163 }
1164 
1165 void MarbleMap::setLockToSubSolarPoint( bool visible )
1166 {
1167     disconnect( d->m_model->sunLocator(), SIGNAL(positionChanged(qreal,qreal)),
1168                 this,                     SLOT(centerOn(qreal,qreal)) );
1169 
1170     if( isLockedToSubSolarPoint() != visible ) {
1171         d->m_isLockedToSubSolarPoint = visible;
1172     }
1173 
1174     if ( isLockedToSubSolarPoint() ) {
1175         connect( d->m_model->sunLocator(), SIGNAL(positionChanged(qreal,qreal)),
1176                  this,                     SLOT(centerOn(qreal,qreal)) );
1177 
1178         centerOn( d->m_model->sunLocator()->getLon(), d->m_model->sunLocator()->getLat() );
1179     } else if ( visible ) {
1180         mDebug() << "Ignoring centering on sun, since the sun plugin is not loaded.";
1181     }
1182 }
1183 
1184 void MarbleMap::setSubSolarPointIconVisible( bool visible )
1185 {
1186     if ( isSubSolarPointIconVisible() != visible ) {
1187         d->m_isSubSolarPointIconVisible = visible;
1188     }
1189 }
1190 
1191 void MarbleMap::setShowTileId( bool visible )
1192 {
1193     d->m_textureLayer.setShowTileId( visible );
1194 }
1195 
1196 void MarbleMap::setShowGrid( bool visible )
1197 {
1198     setPropertyValue(QStringLiteral("coordinate-grid"), visible);
1199 }
1200 
1201 void MarbleMap::setShowPlaces( bool visible )
1202 {
1203     setPropertyValue(QStringLiteral("places"), visible);
1204 }
1205 
1206 void MarbleMap::setShowCities( bool visible )
1207 {
1208     setPropertyValue(QStringLiteral("cities"), visible);
1209 }
1210 
1211 void MarbleMap::setShowTerrain( bool visible )
1212 {
1213     setPropertyValue(QStringLiteral("terrain"), visible);
1214 }
1215 
1216 void MarbleMap::setShowOtherPlaces( bool visible )
1217 {
1218     setPropertyValue(QStringLiteral("otherplaces"), visible);
1219 }
1220 
1221 void MarbleMap::setShowRelief( bool visible )
1222 {
1223     setPropertyValue(QStringLiteral("relief"), visible);
1224 }
1225 
1226 void MarbleMap::setShowIceLayer( bool visible )
1227 {
1228     setPropertyValue(QStringLiteral("ice"), visible);
1229 }
1230 
1231 void MarbleMap::setShowBorders( bool visible )
1232 {
1233     setPropertyValue(QStringLiteral("borders"), visible);
1234 }
1235 
1236 void MarbleMap::setShowRivers( bool visible )
1237 {
1238     setPropertyValue(QStringLiteral("rivers"), visible);
1239 }
1240 
1241 void MarbleMap::setShowLakes( bool visible )
1242 {
1243     setPropertyValue(QStringLiteral("lakes"), visible);
1244 }
1245 
1246 void MarbleMap::setShowFrameRate( bool visible )
1247 {
1248     d->m_showFrameRate = visible;
1249 }
1250 
1251 void MarbleMap::setShowRuntimeTrace( bool visible )
1252 {
1253     if (visible != d->m_layerManager.showRuntimeTrace()) {
1254         d->m_layerManager.setShowRuntimeTrace(visible);
1255         emit repaintNeeded();
1256     }
1257 }
1258 
1259 bool MarbleMap::showRuntimeTrace() const
1260 {
1261     return d->m_layerManager.showRuntimeTrace();
1262 }
1263 
1264 void MarbleMap::setShowDebugPolygons( bool visible)
1265 {
1266     if (visible != d->m_showDebugPolygons) {
1267         d->m_showDebugPolygons = visible;
1268         emit repaintNeeded();
1269     }
1270 }
1271 
1272 bool MarbleMap::showDebugPolygons() const
1273 {
1274     return d->m_showDebugPolygons;
1275 }
1276 
1277 void MarbleMap::setShowDebugBatchRender( bool visible)
1278 {
1279     qDebug() << visible;
1280     if (visible != d->m_showDebugBatchRender) {
1281         d->m_showDebugBatchRender = visible;
1282         emit repaintNeeded();
1283     }
1284 }
1285 
1286 bool MarbleMap::showDebugBatchRender() const
1287 {
1288     return d->m_showDebugBatchRender;
1289 }
1290 
1291 void MarbleMap::setShowDebugPlacemarks( bool visible)
1292 {
1293     if (visible != d->m_placemarkLayer.isDebugModeEnabled()) {
1294         d->m_placemarkLayer.setDebugModeEnabled(visible);
1295         emit repaintNeeded();
1296     }
1297 }
1298 
1299 bool MarbleMap::showDebugPlacemarks() const
1300 {
1301     return d->m_placemarkLayer.isDebugModeEnabled();
1302 }
1303 
1304 void MarbleMap::setLevelTagDebugModeEnabled(bool visible)
1305 {
1306     if (visible != d->m_geometryLayer.levelTagDebugModeEnabled()) {
1307         d->m_geometryLayer.setLevelTagDebugModeEnabled(visible);
1308         d->m_placemarkLayer.setLevelTagDebugModeEnabled(visible);
1309         emit repaintNeeded();
1310     }
1311 }
1312 
1313 bool MarbleMap::levelTagDebugModeEnabled() const
1314 {
1315     return d->m_geometryLayer.levelTagDebugModeEnabled() &&
1316            d->m_placemarkLayer.levelTagDebugModeEnabled();
1317 }
1318 
1319 void MarbleMap::setDebugLevelTag(int level)
1320 {
1321     d->m_geometryLayer.setDebugLevelTag(level);
1322     d->m_placemarkLayer.setDebugLevelTag(level);
1323 }
1324 
1325 int MarbleMap::debugLevelTag() const
1326 {
1327     return d->m_geometryLayer.debugLevelTag();
1328 }
1329 
1330 void MarbleMap::setShowBackground( bool visible )
1331 {
1332     d->m_layerManager.setShowBackground( visible );
1333 }
1334 
1335 void MarbleMap::setVisibleRelationTypes(GeoDataRelation::RelationTypes relationTypes)
1336 {
1337     if (d->m_visibleRelationTypes != relationTypes) {
1338         d->m_visibleRelationTypes = relationTypes;
1339         d->m_geometryLayer.setVisibleRelationTypes(relationTypes);
1340         emit visibleRelationTypesChanged(d->m_visibleRelationTypes);
1341     }
1342 }
1343 
1344 void MarbleMap::notifyMouseClick( int x, int y )
1345 {
1346     qreal  lon   = 0;
1347     qreal  lat   = 0;
1348 
1349     const bool valid = geoCoordinates( x, y, lon, lat, GeoDataCoordinates::Radian );
1350 
1351     if ( valid ) {
1352         emit mouseClickGeoPosition( lon, lat, GeoDataCoordinates::Radian );
1353     }
1354 }
1355 
1356 void MarbleMap::clearVolatileTileCache()
1357 {
1358     d->m_vectorTileLayer.reset();
1359     d->m_textureLayer.reset();
1360     mDebug() << "Cleared Volatile Cache!";
1361 }
1362 
1363 void MarbleMap::setVolatileTileCacheLimit( quint64 kilobytes )
1364 {
1365     mDebug() << "kiloBytes" << kilobytes;
1366     d->m_textureLayer.setVolatileCacheLimit( kilobytes );
1367 }
1368 
1369 AngleUnit MarbleMap::defaultAngleUnit() const
1370 {
1371     if ( GeoDataCoordinates::defaultNotation() == GeoDataCoordinates::Decimal ) {
1372         return DecimalDegree;
1373     } else if ( GeoDataCoordinates::defaultNotation() == GeoDataCoordinates::UTM ) {
1374         return UTM;
1375     }
1376 
1377     return DMSDegree;
1378 }
1379 
1380 void MarbleMap::setDefaultAngleUnit( AngleUnit angleUnit )
1381 {
1382     if ( angleUnit == DecimalDegree ) {
1383         GeoDataCoordinates::setDefaultNotation( GeoDataCoordinates::Decimal );
1384         return;
1385     } else if ( angleUnit == UTM ) {
1386         GeoDataCoordinates::setDefaultNotation( GeoDataCoordinates::UTM );
1387         return;
1388     }
1389 
1390     GeoDataCoordinates::setDefaultNotation( GeoDataCoordinates::DMS );
1391 }
1392 
1393 QFont MarbleMap::defaultFont() const
1394 {
1395     return d->m_styleBuilder.defaultFont();
1396 }
1397 
1398 void MarbleMap::setDefaultFont( const QFont& font )
1399 {
1400     d->m_styleBuilder.setDefaultFont(font);
1401     d->m_placemarkLayer.requestStyleReset();
1402 }
1403 
1404 QList<RenderPlugin *> MarbleMap::renderPlugins() const
1405 {
1406     return d->m_renderPlugins;
1407 }
1408 
1409 QList<AbstractFloatItem *> MarbleMap::floatItems() const
1410 {
1411     return d->m_floatItemsLayer.floatItems();
1412 }
1413 
1414 AbstractFloatItem * MarbleMap::floatItem( const QString &nameId ) const
1415 {
1416     for ( AbstractFloatItem * floatItem: floatItems() ) {
1417         if ( floatItem && floatItem->nameId() == nameId ) {
1418             return floatItem;
1419         }
1420     }
1421 
1422     return nullptr; // No item found
1423 }
1424 
1425 QList<AbstractDataPlugin *> MarbleMap::dataPlugins()  const
1426 {
1427     return d->m_layerManager.dataPlugins();
1428 }
1429 
1430 QList<AbstractDataPluginItem *> MarbleMap::whichItemAt( const QPoint& curpos ) const
1431 {
1432     return d->m_layerManager.whichItemAt( curpos );
1433 }
1434 
1435 void MarbleMap::addLayer( LayerInterface *layer )
1436 {
1437     d->m_layerManager.addLayer(layer);
1438 }
1439 
1440 void MarbleMap::removeLayer( LayerInterface *layer )
1441 {
1442     d->m_layerManager.removeLayer(layer);
1443 }
1444 
1445 RenderStatus MarbleMap::renderStatus() const
1446 {
1447     return d->m_layerManager.renderState().status();
1448 }
1449 
1450 RenderState MarbleMap::renderState() const
1451 {
1452     return d->m_layerManager.renderState();
1453 }
1454 
1455 QString MarbleMap::addTextureLayer(GeoSceneTextureTileDataset *texture)
1456 {
1457     return textureLayer()->addTextureLayer(texture);
1458 }
1459 
1460 void  MarbleMap::removeTextureLayer(const QString &key)
1461 {
1462     textureLayer()->removeTextureLayer(key);
1463 }
1464 
1465 // this method will only temporarily "pollute" the MarbleModel class
1466 TextureLayer *MarbleMap::textureLayer() const
1467 {
1468     return &d->m_textureLayer;
1469 }
1470 
1471 VectorTileLayer *MarbleMap::vectorTileLayer() const
1472 {
1473     return &d->m_vectorTileLayer;
1474 }
1475 
1476 const StyleBuilder* MarbleMap::styleBuilder() const
1477 {
1478     return &d->m_styleBuilder;
1479 }
1480 
1481 qreal MarbleMap::heading() const
1482 {
1483     return d->m_viewport.heading() * RAD2DEG;
1484 }
1485 
1486 void MarbleMap::setHeading( qreal heading )
1487 {
1488     d->m_viewport.setHeading( heading * DEG2RAD );
1489     d->m_textureLayer.setNeedsUpdate();
1490 
1491     emit visibleLatLonAltBoxChanged( d->m_viewport.viewLatLonAltBox() );
1492 }
1493 
1494 }
1495 
1496 #include "moc_MarbleMap.cpp"