8#include "TextureLayer.h"
11#include <QSortFilterProxyModel>
15#include "EquirectScanlineTextureMapper.h"
16#include "GenericScanlineTextureMapper.h"
17#include "GeoDataGroundOverlay.h"
18#include "GeoPainter.h"
19#include "GeoSceneGroup.h"
20#include "GeoSceneTextureTileDataset.h"
21#include "GeoSceneTypes.h"
22#include "MarbleDebug.h"
23#include "MarbleDirs.h"
24#include "MarblePlacemarkModel.h"
25#include "MercatorScanlineTextureMapper.h"
26#include "MergedLayerDecorator.h"
27#include "SphericalScanlineTextureMapper.h"
28#include "StackedTile.h"
29#include "StackedTileLoader.h"
30#include "SunLocator.h"
31#include "TextureColorizer.h"
32#include "TileLoader.h"
33#include "TileScalingTextureMapper.h"
39const int REPAINT_SCHEDULING_INTERVAL = 1000;
41class 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;
84TextureLayer::Private::Private(HttpDownloadManager *downloadManager,
85 PluginManager *pluginManager,
86 const SunLocator *sunLocator,
90 , m_sunLocator(sunLocator)
91 , m_loader(downloadManager, pluginManager)
92 , m_layerDecorator(&m_loader, sunLocator)
93 , m_tileLoader(&m_layerDecorator)
94 , m_centerCoordinates()
96 , m_texmapper(nullptr)
97 , m_texcolorizer(nullptr)
98 , m_textureLayerSettings(nullptr)
101 m_groundOverlayModel.setSourceModel(groundOverlayModel);
102 m_groundOverlayModel.setDynamicSortFilter(
true);
103 m_groundOverlayModel.setSortRole(MarblePlacemarkModel::PopularityIndexRole);
108 connect(&m_groundOverlayModel, SIGNAL(rowsAboutToBeRemoved(
QModelIndex,
int,
int)), m_parent, SLOT(removeGroundOverlays(
QModelIndex,
int,
int)));
112 connect(&m_groundOverlayModel, SIGNAL(modelReset()), m_parent, SLOT(resetGroundOverlaysCache()));
114 updateGroundOverlays();
117void TextureLayer::Private::requestDelayedRepaint()
120 m_texmapper->setRepaintNeeded();
123 if (!m_repaintTimer.isActive()) {
124 m_repaintTimer.start();
128void TextureLayer::Private::updateTextureLayers()
132 for (
const GeoSceneTextureTileDataset *candidate : std::as_const(m_textures)) {
134 if (m_textureLayerSettings) {
135 const bool propertyExists = m_textureLayerSettings->propertyValue(candidate->name(), enabled);
136 enabled |= !propertyExists;
140 mDebug() <<
"enabling texture" << candidate->name();
142 mDebug() <<
"disabling texture" << candidate->name();
146 updateGroundOverlays();
148 m_layerDecorator.setTextureLayers(result);
149 m_tileLoader.clear();
151 m_tileZoomLevel = -1;
152 m_parent->setNeedsUpdate();
155void TextureLayer::Private::updateTile(
const TileId &tileId,
const QImage &tileImage)
160 m_tileLoader.updateTile(tileId, tileImage);
162 requestDelayedRepaint();
165bool TextureLayer::Private::drawOrderLessThan(
const GeoDataGroundOverlay *o1,
const GeoDataGroundOverlay *o2)
167 return o1->drawOrder() < o2->drawOrder();
170void TextureLayer::Private::addGroundOverlays(
const QModelIndex &parent,
int first,
int last)
172 for (
int i = first; i <= last; ++i) {
173 QModelIndex index = m_groundOverlayModel.index(i, 0, parent);
174 const GeoDataGroundOverlay *overlay =
175 static_cast<GeoDataGroundOverlay *
>(qvariant_cast<GeoDataObject *>(index.
data(MarblePlacemarkModel::ObjectPointerRole)));
177 if (overlay->icon().isNull()) {
181 int pos = std::lower_bound(m_groundOverlayCache.begin(), m_groundOverlayCache.end(), overlay, drawOrderLessThan) - m_groundOverlayCache.begin();
182 m_groundOverlayCache.insert(pos, overlay);
185 updateGroundOverlays();
190void TextureLayer::Private::removeGroundOverlays(
const QModelIndex &parent,
int first,
int last)
192 for (
int i = first; i <= last; ++i) {
193 QModelIndex index = m_groundOverlayModel.index(i, 0, parent);
194 const GeoDataGroundOverlay *overlay =
195 static_cast<GeoDataGroundOverlay *
>(qvariant_cast<GeoDataObject *>(index.
data(MarblePlacemarkModel::ObjectPointerRole)));
197 int pos = std::lower_bound(m_groundOverlayCache.begin(), m_groundOverlayCache.end(), overlay, drawOrderLessThan) - m_groundOverlayCache.begin();
198 if (pos >= 0 && pos < m_groundOverlayCache.size()) {
199 m_groundOverlayCache.removeAt(pos);
203 updateGroundOverlays();
208void TextureLayer::Private::resetGroundOverlaysCache()
210 m_groundOverlayCache.clear();
212 updateGroundOverlays();
217void TextureLayer::Private::updateGroundOverlays()
219 if (!m_texcolorizer) {
220 m_layerDecorator.updateGroundOverlays(m_groundOverlayCache);
226void TextureLayer::Private::addCustomTextures()
228 m_textures.reserve(m_textures.size() + m_customTextures.size());
229 for (GeoSceneTextureTileDataset *t : std::as_const(m_customTextures)) {
230 m_textures.append(t);
234TextureLayer::TextureLayer(HttpDownloadManager *downloadManager,
235 PluginManager *pluginManager,
236 const SunLocator *sunLocator,
239 , d(new Private(downloadManager, pluginManager, sunLocator, groundOverlayModel, this))
241 connect(&d->m_loader, SIGNAL(tileCompleted(TileId,
QImage)),
this, SLOT(updateTile(TileId,
QImage)));
244 d->m_repaintTimer.setSingleShot(
true);
245 d->m_repaintTimer.setInterval(REPAINT_SCHEDULING_INTERVAL);
246 connect(&d->m_repaintTimer, SIGNAL(timeout()),
this, SIGNAL(repaintNeeded()));
249TextureLayer::~TextureLayer()
251 qDeleteAll(d->m_customTextures);
252 delete d->m_texmapper;
253 delete d->m_texcolorizer;
257void TextureLayer::addSeaDocument(
const GeoDataDocument *seaDocument)
259 if (d->m_texcolorizer) {
260 d->m_texcolorizer->addSeaDocument(seaDocument);
265void TextureLayer::addLandDocument(
const GeoDataDocument *landDocument)
267 if (d->m_texcolorizer) {
268 d->m_texcolorizer->addLandDocument(landDocument);
273int TextureLayer::layerCount()
const
275 return d->m_layerDecorator.textureLayersSize();
278bool TextureLayer::showSunShading()
const
280 return d->m_layerDecorator.showSunShading();
283bool TextureLayer::showCityLights()
const
285 return d->m_layerDecorator.showCityLights();
288bool TextureLayer::render(GeoPainter *painter, ViewportParams *viewport,
const QString &renderPos, GeoSceneLayer *layer)
292 d->m_runtimeTrace = QStringLiteral(
"Texture Cache: %1 ").arg(d->m_tileLoader.tileCount());
293 d->m_renderState = RenderState(QStringLiteral(
"Texture Tiles"));
298 if (d->m_repaintTimer.isActive()) {
299 d->m_repaintTimer.stop();
303 if (d->m_textures.isEmpty())
306 if (d->m_layerDecorator.textureLayersSize() == 0)
312 if (d->m_centerCoordinates.longitude() != viewport->centerLongitude() || d->m_centerCoordinates.latitude() != viewport->centerLatitude()) {
313 d->m_centerCoordinates.setLongitude(viewport->centerLongitude());
314 d->m_centerCoordinates.setLatitude(viewport->centerLatitude());
315 d->m_texmapper->setRepaintNeeded();
319 const int levelZeroWidth = d->m_layerDecorator.tileSize().width() * d->m_layerDecorator.tileColumnCount(0);
320 const int levelZeroHight = d->m_layerDecorator.tileSize().height() * d->m_layerDecorator.tileRowCount(0);
321 const int levelZeroMinDimension = qMin(levelZeroWidth, levelZeroHight);
324 const qreal linearLevel = qMax<qreal>(1.0, viewport->radius() * 4.0 / levelZeroMinDimension);
328 const qreal tileLevelF = qLn(linearLevel) / qLn(2.0) * 1.00001;
332 const int tileLevel = qMin<int>(d->m_layerDecorator.maximumTileLevel(), tileLevelF);
334 if (tileLevel != d->m_tileZoomLevel) {
335 d->m_tileZoomLevel = tileLevel;
336 Q_EMIT tileLevelChanged(d->m_tileZoomLevel);
340 d->m_texmapper->mapTexture(painter, viewport, d->m_tileZoomLevel, dirtyRect, d->m_texcolorizer);
341 d->m_renderState.addChild(d->m_tileLoader.renderState());
345QString TextureLayer::runtimeTrace()
const
347 return d->m_runtimeTrace;
350void TextureLayer::setShowRelief(
bool show)
352 if (d->m_texcolorizer) {
353 d->m_texcolorizer->setShowRelief(show);
357void TextureLayer::setShowSunShading(
bool show)
359 disconnect(d->m_sunLocator, SIGNAL(positionChanged(qreal, qreal)),
this, SLOT(
reset()));
362 connect(d->m_sunLocator, SIGNAL(positionChanged(qreal, qreal)),
this, SLOT(
reset()));
365 d->m_layerDecorator.setShowSunShading(show);
370void TextureLayer::setShowCityLights(
bool show)
372 d->m_layerDecorator.setShowCityLights(show);
377void TextureLayer::setShowTileId(
bool show)
379 d->m_layerDecorator.setShowTileId(show);
384void TextureLayer::setProjection(Projection projection)
386 if (d->m_textures.isEmpty()) {
391 delete d->m_texmapper;
393 switch (projection) {
395 d->m_texmapper =
new SphericalScanlineTextureMapper(&d->m_tileLoader);
398 d->m_texmapper =
new EquirectScanlineTextureMapper(&d->m_tileLoader);
401 if (d->m_textures.at(0)->tileProjectionType() == GeoSceneAbstractTileProjection::Mercator) {
402 d->m_texmapper =
new TileScalingTextureMapper(&d->m_tileLoader);
404 d->m_texmapper =
new MercatorScanlineTextureMapper(&d->m_tileLoader);
412 d->m_texmapper =
new GenericScanlineTextureMapper(&d->m_tileLoader);
415 d->m_texmapper =
nullptr;
417 Q_ASSERT(d->m_texmapper);
420void TextureLayer::setNeedsUpdate()
422 if (d->m_texmapper) {
423 d->m_texmapper->setRepaintNeeded();
426 Q_EMIT repaintNeeded();
429void TextureLayer::setVolatileCacheLimit(quint64 kilobytes)
431 d->m_tileLoader.setVolatileCacheLimit(kilobytes);
434void TextureLayer::reset()
436 d->m_tileLoader.clear();
440void TextureLayer::reload()
442 for (
const TileId &
id : d->m_tileLoader.visibleTiles()) {
446 d->m_layerDecorator.downloadStackedTile(
id, DownloadBrowse);
450void TextureLayer::downloadStackedTile(
const TileId &stackedTileId)
452 d->m_layerDecorator.downloadStackedTile(stackedTileId, DownloadBulk);
456 const GeoSceneGroup *textureLayerSettings,
460 delete d->m_texcolorizer;
461 d->m_texcolorizer =
nullptr;
464 d->m_texcolorizer =
new TextureColorizer(seaFile, landFile);
467 d->m_textures = textures;
468 d->addCustomTextures();
469 d->m_textureLayerSettings = textureLayerSettings;
471 if (d->m_textureLayerSettings) {
472 connect(d->m_textureLayerSettings, SIGNAL(valueChanged(
QString,
bool)),
this, SLOT(updateTextureLayers()));
475 d->updateTextureLayers();
478int TextureLayer::tileZoomLevel()
const
480 return d->m_tileZoomLevel;
483QSize TextureLayer::tileSize()
const
485 return d->m_layerDecorator.tileSize();
488const GeoSceneAbstractTileProjection *TextureLayer::tileProjection()
const
490 return d->m_layerDecorator.tileProjection();
493int TextureLayer::tileColumnCount(
int level)
const
495 return d->m_layerDecorator.tileColumnCount(level);
498int TextureLayer::tileRowCount(
int level)
const
500 return d->m_layerDecorator.tileRowCount(level);
503quint64 TextureLayer::volatileCacheLimit()
const
505 return d->m_tileLoader.volatileCacheLimit();
508int TextureLayer::preferredRadiusCeil(
int radius)
const
510 if (!d->m_layerDecorator.hasTextureLayer()) {
513 const int tileWidth = d->m_layerDecorator.tileSize().
width();
514 const int levelZeroColumns = d->m_layerDecorator.tileColumnCount(0);
515 const qreal linearLevel = 4.0 * (qreal)(radius) / (qreal)(tileWidth * levelZeroColumns);
516 const qreal tileLevelF = qLn(linearLevel) / qLn(2.0);
517 const int tileLevel = qCeil(tileLevelF);
520 return (tileWidth * levelZeroColumns / 4) >> (-tileLevel);
522 return (tileWidth * levelZeroColumns / 4) << tileLevel;
525int TextureLayer::preferredRadiusFloor(
int radius)
const
527 if (!d->m_layerDecorator.hasTextureLayer()) {
530 const int tileWidth = d->m_layerDecorator.tileSize().width();
531 const int levelZeroColumns = d->m_layerDecorator.tileColumnCount(0);
532 const qreal linearLevel = 4.0 * (qreal)(radius) / (qreal)(tileWidth * levelZeroColumns);
533 const qreal tileLevelF = qLn(linearLevel) / qLn(2.0);
534 const int tileLevel = qFloor(tileLevelF);
537 return (tileWidth * levelZeroColumns / 4) >> (-tileLevel);
539 return (tileWidth * levelZeroColumns / 4) << tileLevel;
542RenderState TextureLayer::renderState()
const
544 return d->m_renderState;
547QString TextureLayer::addTextureLayer(GeoSceneTextureTileDataset *texture)
552 QString sourceDir = texture->sourceDir();
553 if (!d->m_customTextures.contains(sourceDir)) {
554 d->m_customTextures.insert(sourceDir, texture);
555 d->m_textures.append(texture);
556 d->updateTextureLayers();
561void TextureLayer::removeTextureLayer(
const QString &key)
563 if (d->m_customTextures.contains(key)) {
564 GeoSceneTextureTileDataset *texture = d->m_customTextures.value(key);
565 d->m_customTextures.remove(key);
566 d->m_textures.remove(d->m_textures.indexOf(texture));
568 d->updateTextureLayers();
574#include "moc_TextureLayer.cpp"
This file contains the headers for ViewportParams.
Binds a QML item to a specific geodetic location in screen coordinates.
@ Mercator
Mercator projection.
@ VerticalPerspective
Vertical perspective projection.
@ AzimuthalEquidistant
Azimuthal Equidistant projection.
@ Gnomonic
Gnomonic projection.
@ LambertAzimuthal
Lambert Azimuthal Equal-Area projection.
@ Equirectangular
Flat projection ("plate carree")
@ Spherical
Spherical projection ("Orthographic")
@ Stereographic
Stereographic projection.
QCoreApplication * instance()
bool isNull() const const
void append(QList< T > &&value)
QVariant data(int role) const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QThread * currentThread()