Marble

TileScalingTextureMapper.cpp
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 //
3 // SPDX-FileCopyrightText: 2010-2012 Bernhard Beschow <[email protected]>
4 //
5 
6 
7 // local
8 #include "TileScalingTextureMapper.h"
9 
10 // posix
11 #include <cmath>
12 
13 // Qt
14 #include <qmath.h>
15 
16 // Marble
17 #include "GeoPainter.h"
18 #include "ScanlineTextureMapperContext.h"
19 #include "StackedTileLoader.h"
20 #include "TextureColorizer.h"
21 #include "TileLoaderHelper.h"
22 #include "StackedTile.h"
23 #include "MathHelper.h"
24 #include "ViewportParams.h"
25 
26 using namespace Marble;
27 
28 TileScalingTextureMapper::TileScalingTextureMapper( StackedTileLoader *tileLoader, QObject *parent )
29  : QObject( parent ),
30  TextureMapperInterface(),
31  m_tileLoader( tileLoader ),
32  m_cache( 100 ),
33  m_radius( 0 )
34 {
35  connect( tileLoader, SIGNAL(tileLoaded(TileId)),
36  this, SLOT(removePixmap(TileId)) );
37  connect( tileLoader, SIGNAL(cleared()),
38  this, SLOT(clearPixmaps()) );
39 }
40 
41 void TileScalingTextureMapper::mapTexture( GeoPainter *painter,
42  const ViewportParams *viewport,
43  int tileZoomLevel,
44  const QRect &dirtyRect,
45  TextureColorizer *texColorizer )
46 {
47  if ( viewport->radius() <= 0 )
48  return;
49 
50  if ( texColorizer || m_radius != viewport->radius() ) {
51  if ( m_canvasImage.size() != viewport->size() || m_radius != viewport->radius() ) {
52  const QImage::Format optimalFormat = ScanlineTextureMapperContext::optimalCanvasImageFormat( viewport );
53 
54  if ( m_canvasImage.size() != viewport->size() || m_canvasImage.format() != optimalFormat ) {
55  m_canvasImage = QImage( viewport->size(), optimalFormat );
56  }
57 
58  if ( !viewport->mapCoversViewport() ) {
59  m_canvasImage.fill( 0 );
60  }
61 
62  m_repaintNeeded = true;
63  }
64 
65  if ( m_repaintNeeded ) {
66  mapTexture( painter, viewport, tileZoomLevel, texColorizer );
67 
68  m_radius = viewport->radius();
69  m_repaintNeeded = false;
70  }
71 
72  painter->drawImage( dirtyRect, m_canvasImage, dirtyRect );
73  } else {
74  mapTexture( painter, viewport, tileZoomLevel, texColorizer );
75 
76  m_radius = viewport->radius();
77  }
78 }
79 
80 void TileScalingTextureMapper::mapTexture( GeoPainter *painter, const ViewportParams *viewport, int tileZoomLevel, TextureColorizer *texColorizer )
81 {
82  const int imageHeight = viewport->height();
83  const int imageWidth = viewport->width();
84  const qint64 radius = viewport->radius();
85 
86  const bool highQuality = ( painter->mapQuality() == HighQuality
87  || painter->mapQuality() == PrintQuality );
88 
89  // Reset backend
90  m_tileLoader->resetTilehash();
91 
92  // Calculate translation of center point
93  const qreal centerLon = viewport->centerLongitude();
94  const qreal centerLat = viewport->centerLatitude();
95 
96  const int numTilesX = m_tileLoader->tileRowCount( tileZoomLevel );
97  const int numTilesY = m_tileLoader->tileColumnCount( tileZoomLevel );
98  Q_ASSERT( numTilesX > 0 );
99  Q_ASSERT( numTilesY > 0 );
100 
101  const qreal xNormalizedCenter = 0.5 + 0.5 * centerLon / M_PI;
102  const int minTileX = qFloor( numTilesX * ( xNormalizedCenter - imageWidth/( 8.0 * radius ) ) );
103  const int maxTileX = numTilesX * ( xNormalizedCenter + imageWidth/( 8.0 * radius ) );
104 
105  const qreal yNormalizedCenter = 0.5 - 0.5 * asinh( tan( centerLat ) ) / M_PI;
106  const int minTileY = qMax( qreal( numTilesY * ( yNormalizedCenter - imageHeight/( 8.0 * radius ) ) ),
107  qreal( 0.0 ) );
108  const int maxTileY = qMin( qreal( numTilesY * ( yNormalizedCenter + imageHeight/( 8.0 * radius ) ) ),
109  qreal( numTilesY - 1.0 ) );
110 
111  if ( m_radius != radius ) {
112  m_cache.clear();
113  }
114 
115  if ( texColorizer || m_radius != radius ) {
116  QPainter imagePainter( &m_canvasImage );
117  imagePainter.setRenderHint( QPainter::SmoothPixmapTransform, highQuality );
118 
119  for ( int tileY = minTileY; tileY <= maxTileY; ++tileY ) {
120  for ( int tileX = minTileX; tileX <= maxTileX; ++tileX ) {
121  const qreal xLeft = ( 4.0 * radius ) * ( ( tileX ) / (qreal)numTilesX - xNormalizedCenter ) + ( imageWidth / 2.0 );
122  const qreal xRight = ( 4.0 * radius ) * ( ( tileX + 1 ) / (qreal)numTilesX - xNormalizedCenter ) + ( imageWidth / 2.0 );
123  const qreal yTop = ( 4.0 * radius ) * ( ( tileY ) / (qreal)numTilesY - yNormalizedCenter ) + ( imageHeight / 2.0 );
124  const qreal yBottom = ( 4.0 * radius ) * ( ( tileY + 1 ) / (qreal)numTilesY - yNormalizedCenter ) + ( imageHeight / 2.0 );
125 
126  const QRectF rect = QRectF( QPointF( xLeft, yTop ), QPointF( xRight, yBottom ) );
127  const TileId stackedId = TileId( 0, tileZoomLevel, ( ( tileX % numTilesX ) + numTilesX ) % numTilesX, tileY );
128 
129  const StackedTile *const tile = m_tileLoader->loadTile( stackedId );
130 
131  imagePainter.drawImage( rect, *tile->resultImage() );
132  }
133  }
134 
135  if ( texColorizer ) {
136  texColorizer->colorize( &m_canvasImage, viewport, painter->mapQuality() );
137  }
138  } else {
139  painter->save();
140  painter->setRenderHint( QPainter::SmoothPixmapTransform, highQuality );
141 
142  for ( int tileY = minTileY; tileY <= maxTileY; ++tileY ) {
143  for ( int tileX = minTileX; tileX <= maxTileX; ++tileX ) {
144  const qreal xLeft = ( 4.0 * radius ) * ( ( tileX ) / (qreal)numTilesX - xNormalizedCenter ) + ( imageWidth / 2.0 );
145  const qreal xRight = ( 4.0 * radius ) * ( ( tileX + 1 ) / (qreal)numTilesX - xNormalizedCenter ) + ( imageWidth / 2.0 );
146  const qreal yTop = ( 4.0 * radius ) * ( ( tileY ) / (qreal)numTilesY - yNormalizedCenter ) + ( imageHeight / 2.0 );
147  const qreal yBottom = ( 4.0 * radius ) * ( ( tileY + 1 ) / (qreal)numTilesY - yNormalizedCenter ) + ( imageHeight / 2.0 );
148 
149  const QRectF rect = QRectF( QPointF( xLeft, yTop ), QPointF( xRight, yBottom ) );
150  const TileId stackedId = TileId( 0, tileZoomLevel, ( ( tileX % numTilesX ) + numTilesX ) % numTilesX, tileY );
151  const StackedTile *const tile = m_tileLoader->loadTile( stackedId ); // load tile here for every frame, otherwise cleanupTilehash() clears all visible tiles
152 
153  const QSize size = QSize( qCeil( rect.right() - rect.left() ), qCeil( rect.bottom() - rect.top() ) );
154  const int cacheHash = 2 * ( size.width() % 2 ) + ( size.height() % 2 );
155  const TileId cacheId = TileId( cacheHash, stackedId.zoomLevel(), stackedId.x(), stackedId.y() );
156 
157  const QPixmap *const im_cached = m_cache[cacheId];
158  const QPixmap *im = im_cached;
159  if ( im == nullptr ) {
161  }
162  painter->drawPixmap( rect.topLeft(), *im );
163 
164  if (im != im_cached)
165  m_cache.insert( cacheId, im );
166  }
167  }
168 
169  painter->restore();
170  }
171 
172  m_tileLoader->cleanupTilehash();
173 }
174 
175 void TileScalingTextureMapper::removePixmap( const TileId &tileId )
176 {
177  const TileId stackedTileId( 0, tileId.zoomLevel(), tileId.x(), tileId.y() );
178  for ( int i = 0; i < 4; ++i ) {
179  const TileId id = TileId( i, stackedTileId.zoomLevel(), stackedTileId.x(), stackedTileId.y() );
180 
181  m_cache.remove( id );
182  }
183 }
184 
185 void TileScalingTextureMapper::clearPixmaps()
186 {
187  m_cache.clear();
188 }
189 
190 #include "moc_TileScalingTextureMapper.cpp"
MapQuality mapQuality() const
Returns the map quality.
Definition: GeoPainter.cpp:211
SmoothPixmapTransform
qreal left() const const
A single tile that consists of a stack of Tile layers.
Definition: StackedTile.h:50
QPixmap fromImage(const QImage &image, Qt::ImageConversionFlags flags)
Tile loading from a quad tree.
QImage scaled(int width, int height, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformMode) const const
int width() const const
const QImage * resultImage() const
Returns the QImage that describes the merged stack of Tiles.
IgnoreAspectRatio
A public class that controls what is visible in the viewport of a Marble map.
int height() const const
QPointF topLeft() const const
qreal bottom() const const
Binds a QML item to a specific geodetic location in screen coordinates.
A painter that allows to draw geometric primitives on the map.
Definition: GeoPainter.h:88
qreal top() const const
qreal right() const const
@ HighQuality
High quality (e.g. antialiasing for lines)
Definition: MarbleGlobal.h:78
void drawPixmap(const GeoDataCoordinates &centerPosition, const QPixmap &pixmap)
Draws a pixmap at the given position. The pixmap is placed with its center located at the given cente...
Definition: GeoPainter.cpp:492
void restore()
void save()
@ PrintQuality
Print quality.
Definition: MarbleGlobal.h:79
void drawImage(const GeoDataCoordinates &centerPosition, const QImage &image)
Draws an image at the given position. The image is placed with its center located at the given center...
Definition: GeoPainter.cpp:466
void setRenderHint(QPainter::RenderHint hint, bool on)
SmoothTransformation
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Thu Sep 21 2023 04:12:28 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.