Marble

TileScalingTextureMapper.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later
2//
3// SPDX-FileCopyrightText: 2010-2012 Bernhard Beschow <bbeschow@cs.tu-berlin.de>
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
26using namespace Marble;
27
28TileScalingTextureMapper::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
41void 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
80void 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 );
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();
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
175void 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
185void TileScalingTextureMapper::clearPixmaps()
186{
187 m_cache.clear();
188}
189
190#include "moc_TileScalingTextureMapper.cpp"
This file contains the headers for ViewportParams.
A painter that allows to draw geometric primitives on the map.
Definition GeoPainter.h:89
MapQuality mapQuality() const
Returns the map quality.
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...
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...
Tile loading from a quad tree.
void cleanupTilehash()
Cleans up the internal tile hash.
void resetTilehash()
Resets the internal tile hash.
const StackedTile * loadTile(TileId const &stackedTileId)
Loads a tile and returns it.
A single tile that consists of a stack of Tile layers.
Definition StackedTile.h:51
QImage const * resultImage() const
Returns the QImage that describes the merged stack of Tiles.
A public class that controls what is visible in the viewport of a Marble map.
Binds a QML item to a specific geodetic location in screen coordinates.
@ HighQuality
High quality (e.g. antialiasing for lines)
@ PrintQuality
Print quality.
void clear()
bool insert(const Key &key, T *object, qsizetype cost)
bool remove(const Key &key)
void fill(Qt::GlobalColor color)
Format format() const const
QImage scaled(const QSize &size, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformMode) const const
QSize size() const const
T qobject_cast(QObject *object)
SmoothPixmapTransform
void restore()
void save()
void setRenderHint(RenderHint hint, bool on)
QPixmap fromImage(QImage &&image, Qt::ImageConversionFlags flags)
qreal bottom() const const
qreal left() const const
qreal right() const const
qreal top() const const
QPointF topLeft() const const
int height() const const
int width() const const
IgnoreAspectRatio
SmoothTransformation
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:18:17 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.