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// local
7#include "TileScalingTextureMapper.h"
8
9// posix
10#include <cmath>
11
12// Qt
13#include <qmath.h>
14
15// Marble
16#include "GeoPainter.h"
17#include "MathHelper.h"
18#include "ScanlineTextureMapperContext.h"
19#include "StackedTile.h"
20#include "StackedTileLoader.h"
21#include "TextureColorizer.h"
22#include "TileLoaderHelper.h"
23#include "ViewportParams.h"
24
25using namespace Marble;
26
27TileScalingTextureMapper::TileScalingTextureMapper(StackedTileLoader *tileLoader, QObject *parent)
28 : QObject(parent)
29 , TextureMapperInterface()
30 , m_tileLoader(tileLoader)
31 , m_cache(100)
32 , m_radius(0)
33{
34 connect(tileLoader, SIGNAL(tileLoaded(TileId)), this, SLOT(removePixmap(TileId)));
35 connect(tileLoader, SIGNAL(cleared()), this, SLOT(clearPixmaps()));
36}
37
38void TileScalingTextureMapper::mapTexture(GeoPainter *painter,
39 const ViewportParams *viewport,
40 int tileZoomLevel,
41 const QRect &dirtyRect,
42 TextureColorizer *texColorizer)
43{
44 if (viewport->radius() <= 0)
45 return;
46
47 if (texColorizer || m_radius != viewport->radius()) {
48 if (m_canvasImage.size() != viewport->size() || m_radius != viewport->radius()) {
49 const QImage::Format optimalFormat = ScanlineTextureMapperContext::optimalCanvasImageFormat(viewport);
50
51 if (m_canvasImage.size() != viewport->size() || m_canvasImage.format() != optimalFormat) {
52 m_canvasImage = QImage(viewport->size(), optimalFormat);
53 }
54
55 if (!viewport->mapCoversViewport()) {
56 m_canvasImage.fill(0);
57 }
58
59 m_repaintNeeded = true;
60 }
61
62 if (m_repaintNeeded) {
63 mapTexture(painter, viewport, tileZoomLevel, texColorizer);
64
65 m_radius = viewport->radius();
66 m_repaintNeeded = false;
67 }
68
69 painter->drawImage(dirtyRect, m_canvasImage, dirtyRect);
70 } else {
71 mapTexture(painter, viewport, tileZoomLevel, texColorizer);
72
73 m_radius = viewport->radius();
74 }
75}
76
77void TileScalingTextureMapper::mapTexture(GeoPainter *painter, const ViewportParams *viewport, int tileZoomLevel, TextureColorizer *texColorizer)
78{
79 const int imageHeight = viewport->height();
80 const int imageWidth = viewport->width();
81 const qint64 radius = viewport->radius();
82
83 const bool highQuality = (painter->mapQuality() == HighQuality || painter->mapQuality() == PrintQuality);
84
85 // Reset backend
86 m_tileLoader->resetTilehash();
87
88 // Calculate translation of center point
89 const qreal centerLon = viewport->centerLongitude();
90 const qreal centerLat = viewport->centerLatitude();
91
92 const int numTilesX = m_tileLoader->tileRowCount(tileZoomLevel);
93 const int numTilesY = m_tileLoader->tileColumnCount(tileZoomLevel);
94 Q_ASSERT(numTilesX > 0);
95 Q_ASSERT(numTilesY > 0);
96
97 const qreal xNormalizedCenter = 0.5 + 0.5 * centerLon / M_PI;
98 const int minTileX = qFloor(numTilesX * (xNormalizedCenter - imageWidth / (8.0 * radius)));
99 const int maxTileX = numTilesX * (xNormalizedCenter + imageWidth / (8.0 * radius));
100
101 const qreal yNormalizedCenter = 0.5 - 0.5 * asinh(tan(centerLat)) / M_PI;
102 const int minTileY = qMax(qreal(numTilesY * (yNormalizedCenter - imageHeight / (8.0 * radius))), qreal(0.0));
103 const int maxTileY = qMin(qreal(numTilesY * (yNormalizedCenter + imageHeight / (8.0 * radius))), qreal(numTilesY - 1.0));
104
105 if (m_radius != radius) {
106 m_cache.clear();
107 }
108
109 if (texColorizer || m_radius != radius) {
110 QPainter imagePainter(&m_canvasImage);
111 imagePainter.setRenderHint(QPainter::SmoothPixmapTransform, highQuality);
112
113 for (int tileY = minTileY; tileY <= maxTileY; ++tileY) {
114 for (int tileX = minTileX; tileX <= maxTileX; ++tileX) {
115 const qreal xLeft = (4.0 * radius) * ((tileX) / (qreal)numTilesX - xNormalizedCenter) + (imageWidth / 2.0);
116 const qreal xRight = (4.0 * radius) * ((tileX + 1) / (qreal)numTilesX - xNormalizedCenter) + (imageWidth / 2.0);
117 const qreal yTop = (4.0 * radius) * ((tileY) / (qreal)numTilesY - yNormalizedCenter) + (imageHeight / 2.0);
118 const qreal yBottom = (4.0 * radius) * ((tileY + 1) / (qreal)numTilesY - yNormalizedCenter) + (imageHeight / 2.0);
119
120 const QRectF rect = QRectF(QPointF(xLeft, yTop), QPointF(xRight, yBottom));
121 const TileId stackedId = TileId(0, tileZoomLevel, ((tileX % numTilesX) + numTilesX) % numTilesX, tileY);
122
123 const StackedTile *const tile = m_tileLoader->loadTile(stackedId);
124
125 imagePainter.drawImage(rect, *tile->resultImage());
126 }
127 }
128
129 if (texColorizer) {
130 texColorizer->colorize(&m_canvasImage, viewport, painter->mapQuality());
131 }
132 } else {
133 painter->save();
134 painter->setRenderHint(QPainter::SmoothPixmapTransform, highQuality);
135
136 for (int tileY = minTileY; tileY <= maxTileY; ++tileY) {
137 for (int tileX = minTileX; tileX <= maxTileX; ++tileX) {
138 const qreal xLeft = (4.0 * radius) * ((tileX) / (qreal)numTilesX - xNormalizedCenter) + (imageWidth / 2.0);
139 const qreal xRight = (4.0 * radius) * ((tileX + 1) / (qreal)numTilesX - xNormalizedCenter) + (imageWidth / 2.0);
140 const qreal yTop = (4.0 * radius) * ((tileY) / (qreal)numTilesY - yNormalizedCenter) + (imageHeight / 2.0);
141 const qreal yBottom = (4.0 * radius) * ((tileY + 1) / (qreal)numTilesY - yNormalizedCenter) + (imageHeight / 2.0);
142
143 const QRectF rect = QRectF(QPointF(xLeft, yTop), QPointF(xRight, yBottom));
144 const TileId stackedId = TileId(0, tileZoomLevel, ((tileX % numTilesX) + numTilesX) % numTilesX, tileY);
145 const StackedTile *const tile =
146 m_tileLoader->loadTile(stackedId); // load tile here for every frame, otherwise cleanupTilehash() clears all visible tiles
147
148 const QSize size = QSize(qCeil(rect.right() - rect.left()), qCeil(rect.bottom() - rect.top()));
149 const int cacheHash = 2 * (size.width() % 2) + (size.height() % 2);
150 const TileId cacheId = TileId(cacheHash, stackedId.zoomLevel(), stackedId.x(), stackedId.y());
151
152 const QPixmap *const im_cached = m_cache[cacheId];
153 const QPixmap *im = im_cached;
154 if (im == nullptr) {
156 }
157 painter->drawPixmap(rect.topLeft(), *im);
158
159 if (im != im_cached)
160 m_cache.insert(cacheId, im);
161 }
162 }
163
164 painter->restore();
165 }
166
167 m_tileLoader->cleanupTilehash();
168}
169
170void TileScalingTextureMapper::removePixmap(const TileId &tileId)
171{
172 const TileId stackedTileId(0, tileId.zoomLevel(), tileId.x(), tileId.y());
173 for (int i = 0; i < 4; ++i) {
174 const TileId id = TileId(i, stackedTileId.zoomLevel(), stackedTileId.x(), stackedTileId.y());
175
176 m_cache.remove(id);
177 }
178}
179
180void TileScalingTextureMapper::clearPixmaps()
181{
182 m_cache.clear();
183}
184
185#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:86
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
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 Mon Nov 18 2024 12:15:46 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.