8 #include "TextureLayer.h"
13 #include <QSortFilterProxyModel>
15 #include "SphericalScanlineTextureMapper.h"
16 #include "EquirectScanlineTextureMapper.h"
17 #include "MercatorScanlineTextureMapper.h"
18 #include "GenericScanlineTextureMapper.h"
19 #include "TileScalingTextureMapper.h"
20 #include "GeoDataGroundOverlay.h"
21 #include "GeoPainter.h"
22 #include "GeoSceneGroup.h"
23 #include "GeoSceneTextureTileDataset.h"
24 #include "GeoSceneTypes.h"
25 #include "MergedLayerDecorator.h"
26 #include "MarbleDebug.h"
27 #include "MarbleDirs.h"
28 #include "MarblePlacemarkModel.h"
29 #include "StackedTile.h"
30 #include "StackedTileLoader.h"
31 #include "SunLocator.h"
32 #include "TextureColorizer.h"
33 #include "TileLoader.h"
39 const int REPAINT_SCHEDULING_INTERVAL = 1000;
41 class Q_DECL_HIDDEN TextureLayer::Private
44 Private( HttpDownloadManager *downloadManager,
45 PluginManager* pluginManager,
46 const SunLocator *sunLocator,
48 TextureLayer *parent );
50 void requestDelayedRepaint();
51 void updateTextureLayers();
52 void updateTile(
const TileId &tileId,
const QImage &tileImage );
54 void addGroundOverlays(
const QModelIndex& parent,
int first,
int last );
55 void removeGroundOverlays(
const QModelIndex& parent,
int first,
int last );
56 void resetGroundOverlaysCache();
58 void updateGroundOverlays();
59 void addCustomTextures();
61 static bool drawOrderLessThan(
const GeoDataGroundOverlay* o1,
const GeoDataGroundOverlay* o2 );
64 TextureLayer *
const m_parent;
65 const SunLocator *
const m_sunLocator;
67 MergedLayerDecorator m_layerDecorator;
68 StackedTileLoader m_tileLoader;
69 GeoDataCoordinates m_centerCoordinates;
71 TextureMapperInterface *m_texmapper;
72 TextureColorizer *m_texcolorizer;
74 const GeoSceneGroup *m_textureLayerSettings;
81 RenderState m_renderState;
84 TextureLayer::Private::Private( HttpDownloadManager *downloadManager,
85 PluginManager* pluginManager,
86 const SunLocator *sunLocator,
88 TextureLayer *parent )
90 , m_sunLocator( sunLocator )
91 , m_loader( downloadManager, pluginManager )
92 , m_layerDecorator( &m_loader, sunLocator )
93 , m_tileLoader( &m_layerDecorator )
94 , m_centerCoordinates()
95 , m_tileZoomLevel( -1 )
96 , m_texmapper( nullptr )
97 , m_texcolorizer( nullptr )
98 , m_textureLayerSettings( nullptr )
101 m_groundOverlayModel.setSourceModel( groundOverlayModel );
102 m_groundOverlayModel.setDynamicSortFilter(
true );
106 connect( &m_groundOverlayModel, SIGNAL(rowsInserted(
QModelIndex,
int,
int)),
107 m_parent, SLOT(addGroundOverlays(
QModelIndex,
int,
int)) );
109 connect( &m_groundOverlayModel, SIGNAL(rowsAboutToBeRemoved(
QModelIndex,
int,
int)),
110 m_parent, SLOT(removeGroundOverlays(
QModelIndex,
int,
int)) );
113 m_parent, SLOT(resetGroundOverlaysCache()) );
115 connect( &m_groundOverlayModel, SIGNAL(modelReset()),
116 m_parent, SLOT(resetGroundOverlaysCache()) );
118 updateGroundOverlays();
121 void TextureLayer::Private::requestDelayedRepaint()
124 m_texmapper->setRepaintNeeded();
127 if ( !m_repaintTimer.isActive() ) {
128 m_repaintTimer.start();
132 void TextureLayer::Private::updateTextureLayers()
136 for (
const GeoSceneTextureTileDataset *candidate: m_textures ) {
138 if ( m_textureLayerSettings ) {
139 const bool propertyExists = m_textureLayerSettings->propertyValue( candidate->name(), enabled );
140 enabled |= !propertyExists;
143 result.
append( candidate );
144 mDebug() <<
"enabling texture" << candidate->name();
146 mDebug() <<
"disabling texture" << candidate->name();
150 updateGroundOverlays();
152 m_layerDecorator.setTextureLayers( result );
153 m_tileLoader.clear();
155 m_tileZoomLevel = -1;
156 m_parent->setNeedsUpdate();
159 void TextureLayer::Private::updateTile(
const TileId &tileId,
const QImage &tileImage )
164 m_tileLoader.updateTile( tileId, tileImage );
166 requestDelayedRepaint();
169 bool TextureLayer::Private::drawOrderLessThan(
const GeoDataGroundOverlay* o1,
const GeoDataGroundOverlay* o2 )
171 return o1->drawOrder() < o2->drawOrder();
174 void TextureLayer::Private::addGroundOverlays(
const QModelIndex& parent,
int first,
int last )
176 for (
int i = first; i <= last; ++i ) {
177 QModelIndex index = m_groundOverlayModel.index( i, 0, parent );
180 if ( overlay->icon().isNull() ) {
184 int pos = std::lower_bound( m_groundOverlayCache.begin(), m_groundOverlayCache.end(), overlay, drawOrderLessThan ) - m_groundOverlayCache.begin();
185 m_groundOverlayCache.insert( pos, overlay );
188 updateGroundOverlays();
193 void TextureLayer::Private::removeGroundOverlays(
const QModelIndex& parent,
int first,
int last )
195 for (
int i = first; i <= last; ++i ) {
196 QModelIndex index = m_groundOverlayModel.index( i, 0, parent );
199 int pos = std::lower_bound( m_groundOverlayCache.begin(), m_groundOverlayCache.end(), overlay, drawOrderLessThan ) - m_groundOverlayCache.begin();
200 if (pos >= 0 && pos < m_groundOverlayCache.size() ) {
201 m_groundOverlayCache.removeAt( pos );
205 updateGroundOverlays();
210 void TextureLayer::Private::resetGroundOverlaysCache()
212 m_groundOverlayCache.clear();
214 updateGroundOverlays();
219 void TextureLayer::Private::updateGroundOverlays()
221 if ( !m_texcolorizer ) {
222 m_layerDecorator.updateGroundOverlays( m_groundOverlayCache );
229 void TextureLayer::Private::addCustomTextures()
231 m_textures.reserve(m_textures.size() + m_customTextures.size());
232 for (GeoSceneTextureTileDataset *t: m_customTextures)
234 m_textures.append(t);
238 TextureLayer::TextureLayer( HttpDownloadManager *downloadManager,
239 PluginManager* pluginManager,
240 const SunLocator *sunLocator,
243 , d( new Private( downloadManager, pluginManager, sunLocator, groundOverlayModel, this ) )
245 connect( &d->m_loader, SIGNAL(tileCompleted(TileId,
QImage)),
246 this, SLOT(updateTile(TileId,
QImage)) );
249 d->m_repaintTimer.setSingleShot(
true );
250 d->m_repaintTimer.setInterval( REPAINT_SCHEDULING_INTERVAL );
251 connect( &d->m_repaintTimer, SIGNAL(timeout()),
252 this, SIGNAL(repaintNeeded()) );
255 TextureLayer::~TextureLayer()
257 qDeleteAll(d->m_customTextures);
258 delete d->m_texmapper;
259 delete d->m_texcolorizer;
263 void TextureLayer::addSeaDocument(
const GeoDataDocument *seaDocument )
265 if( d->m_texcolorizer ) {
266 d->m_texcolorizer->addSeaDocument( seaDocument );
271 void TextureLayer::addLandDocument(
const GeoDataDocument *landDocument )
273 if( d->m_texcolorizer ) {
274 d->m_texcolorizer->addLandDocument( landDocument );
279 int TextureLayer::layerCount()
const
281 return d->m_layerDecorator.textureLayersSize();
284 bool TextureLayer::showSunShading()
const
286 return d->m_layerDecorator.showSunShading();
289 bool TextureLayer::showCityLights()
const
291 return d->m_layerDecorator.showCityLights();
294 bool TextureLayer::render( GeoPainter *painter, ViewportParams *viewport,
295 const QString &renderPos, GeoSceneLayer *layer )
297 Q_UNUSED( renderPos );
299 d->m_runtimeTrace = QStringLiteral(
"Texture Cache: %1 ").arg(d->m_tileLoader.tileCount());
300 d->m_renderState = RenderState(QStringLiteral(
"Texture Tiles"));
305 if (d->m_repaintTimer.isActive()) {
306 d->m_repaintTimer.stop();
310 if ( d->m_textures.isEmpty() )
313 if ( d->m_layerDecorator.textureLayersSize() == 0 )
316 if ( !d->m_texmapper )
319 if ( d->m_centerCoordinates.longitude() != viewport->centerLongitude() ||
320 d->m_centerCoordinates.latitude() != viewport->centerLatitude() ) {
321 d->m_centerCoordinates.setLongitude( viewport->centerLongitude() );
322 d->m_centerCoordinates.setLatitude( viewport->centerLatitude() );
323 d->m_texmapper->setRepaintNeeded();
327 const int levelZeroWidth = d->m_layerDecorator.tileSize().width() * d->m_layerDecorator.tileColumnCount( 0 );
328 const int levelZeroHight = d->m_layerDecorator.tileSize().height() * d->m_layerDecorator.tileRowCount( 0 );
329 const int levelZeroMinDimension = qMin( levelZeroWidth, levelZeroHight );
332 const qreal linearLevel = qMax<qreal>( 1.0, viewport->radius() * 4.0 / levelZeroMinDimension );
336 const qreal tileLevelF = qLn( linearLevel ) / qLn( 2.0 ) * 1.00001;
340 const int tileLevel = qMin<int>( d->m_layerDecorator.maximumTileLevel(), tileLevelF );
342 if ( tileLevel != d->m_tileZoomLevel ) {
343 d->m_tileZoomLevel = tileLevel;
344 emit tileLevelChanged( d->m_tileZoomLevel );
348 d->m_texmapper->mapTexture( painter, viewport, d->m_tileZoomLevel, dirtyRect, d->m_texcolorizer );
349 d->m_renderState.addChild( d->m_tileLoader.renderState() );
353 QString TextureLayer::runtimeTrace()
const
355 return d->m_runtimeTrace;
358 void TextureLayer::setShowRelief(
bool show )
360 if ( d->m_texcolorizer ) {
361 d->m_texcolorizer->setShowRelief( show );
365 void TextureLayer::setShowSunShading(
bool show )
367 disconnect( d->m_sunLocator, SIGNAL(positionChanged(qreal,qreal)),
368 this, SLOT(
reset()) );
371 connect( d->m_sunLocator, SIGNAL(positionChanged(qreal,qreal)),
372 this, SLOT(
reset()) );
375 d->m_layerDecorator.setShowSunShading( show );
380 void TextureLayer::setShowCityLights(
bool show )
382 d->m_layerDecorator.setShowCityLights( show );
387 void TextureLayer::setShowTileId(
bool show )
389 d->m_layerDecorator.setShowTileId( show );
396 if ( d->m_textures.isEmpty() ) {
401 delete d->m_texmapper;
403 switch( projection ) {
405 d->m_texmapper =
new SphericalScanlineTextureMapper( &d->m_tileLoader );
408 d->m_texmapper =
new EquirectScanlineTextureMapper( &d->m_tileLoader );
411 if (d->m_textures.at(0)->tileProjectionType() == GeoSceneAbstractTileProjection::Mercator) {
412 d->m_texmapper =
new TileScalingTextureMapper( &d->m_tileLoader );
414 d->m_texmapper =
new MercatorScanlineTextureMapper( &d->m_tileLoader );
422 d->m_texmapper =
new GenericScanlineTextureMapper( &d->m_tileLoader );
425 d->m_texmapper =
nullptr;
427 Q_ASSERT( d->m_texmapper );
430 void TextureLayer::setNeedsUpdate()
432 if ( d->m_texmapper ) {
433 d->m_texmapper->setRepaintNeeded();
436 emit repaintNeeded();
439 void TextureLayer::setVolatileCacheLimit( quint64 kilobytes )
441 d->m_tileLoader.setVolatileCacheLimit( kilobytes );
444 void TextureLayer::reset()
446 d->m_tileLoader.clear();
450 void TextureLayer::reload()
452 for (
const TileId &
id: d->m_tileLoader.visibleTiles() ) {
460 void TextureLayer::downloadStackedTile(
const TileId &stackedTileId )
462 d->m_layerDecorator.downloadStackedTile( stackedTileId,
DownloadBulk );
467 delete d->m_texcolorizer;
468 d->m_texcolorizer =
nullptr;
471 d->m_texcolorizer =
new TextureColorizer( seaFile, landFile );
474 d->m_textures = textures;
475 d->addCustomTextures();
476 d->m_textureLayerSettings = textureLayerSettings;
478 if ( d->m_textureLayerSettings ) {
479 connect( d->m_textureLayerSettings, SIGNAL(valueChanged(
QString,
bool)),
480 this, SLOT(updateTextureLayers()) );
483 d->updateTextureLayers();
486 int TextureLayer::tileZoomLevel()
const
488 return d->m_tileZoomLevel;
491 QSize TextureLayer::tileSize()
const
493 return d->m_layerDecorator.tileSize();
496 const GeoSceneAbstractTileProjection *TextureLayer::tileProjection()
const
498 return d->m_layerDecorator.tileProjection();
501 int TextureLayer::tileColumnCount(
int level )
const
503 return d->m_layerDecorator.tileColumnCount( level );
506 int TextureLayer::tileRowCount(
int level )
const
508 return d->m_layerDecorator.tileRowCount( level );
511 quint64 TextureLayer::volatileCacheLimit()
const
513 return d->m_tileLoader.volatileCacheLimit();
516 int TextureLayer::preferredRadiusCeil(
int radius )
const
518 if (!d->m_layerDecorator.hasTextureLayer()) {
521 const int tileWidth = d->m_layerDecorator.tileSize().
width();
522 const int levelZeroColumns = d->m_layerDecorator.tileColumnCount( 0 );
523 const qreal linearLevel = 4.0 * (qreal)( radius ) / (qreal)( tileWidth * levelZeroColumns );
524 const qreal tileLevelF = qLn( linearLevel ) / qLn( 2.0 );
525 const int tileLevel = qCeil( tileLevelF );
528 return ( tileWidth * levelZeroColumns / 4 ) >> (-tileLevel);
530 return ( tileWidth * levelZeroColumns / 4 ) << tileLevel;
533 int TextureLayer::preferredRadiusFloor(
int radius )
const
535 if (!d->m_layerDecorator.hasTextureLayer()) {
538 const int tileWidth = d->m_layerDecorator.tileSize().width();
539 const int levelZeroColumns = d->m_layerDecorator.tileColumnCount( 0 );
540 const qreal linearLevel = 4.0 * (qreal)( radius ) / (qreal)( tileWidth * levelZeroColumns );
541 const qreal tileLevelF = qLn( linearLevel ) / qLn( 2.0 );
542 const int tileLevel = qFloor( tileLevelF );
545 return ( tileWidth * levelZeroColumns / 4 ) >> (-tileLevel);
547 return ( tileWidth * levelZeroColumns / 4 ) << tileLevel;
550 RenderState TextureLayer::renderState()
const
552 return d->m_renderState;
555 QString TextureLayer::addTextureLayer(GeoSceneTextureTileDataset* texture)
560 QString sourceDir = texture->sourceDir();
561 if (!d->m_customTextures.contains(sourceDir))
563 d->m_customTextures.
insert(sourceDir, texture);
564 d->m_textures.
append(texture);
565 d->updateTextureLayers();
570 void TextureLayer::removeTextureLayer(
const QString &key)
572 if (d->m_customTextures.contains(key))
574 GeoSceneTextureTileDataset *texture = d->m_customTextures.value(key);
575 d->m_customTextures.
remove(key);
576 d->m_textures.
remove(d->m_textures.indexOf(texture));
578 d->updateTextureLayers();
584 #include "moc_TextureLayer.cpp"