Marble

MercatorScanlineTextureMapper.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later
2//
3// SPDX-FileCopyrightText: 2007 Carlos Licea <carlos _licea@hotmail.com>
4// SPDX-FileCopyrightText: 2008 Inge Wallin <inge@lysator.liu.se>
5// SPDX-FileCopyrightText: 2011 Bernhard Beschow <bbeschow@cs.tu-berlin.de>
6//
7
8
9// local
10#include"MercatorScanlineTextureMapper.h"
11
12// posix
13#include <cmath>
14
15// Qt
16#include <QRunnable>
17
18// Marble
19#include "GeoPainter.h"
20#include "MarbleDebug.h"
21#include "ScanlineTextureMapperContext.h"
22#include "StackedTileLoader.h"
23#include "TextureColorizer.h"
24#include "ViewportParams.h"
25#include "MathHelper.h"
26#include "AbstractProjection.h"
27
28using namespace Marble;
29
30class MercatorScanlineTextureMapper::RenderJob : public QRunnable
31{
32public:
33 RenderJob( StackedTileLoader *tileLoader, int tileLevel, QImage *canvasImage, const ViewportParams *viewport, MapQuality mapQuality, int yTop, int yBottom );
34
35 void run() override;
36
37private:
38 StackedTileLoader *const m_tileLoader;
39 const int m_tileLevel;
40 QImage *const m_canvasImage;
41 const ViewportParams *const m_viewport;
42 const MapQuality m_mapQuality;
43 const int m_yPaintedTop;
44 const int m_yPaintedBottom;
45};
46
47MercatorScanlineTextureMapper::RenderJob::RenderJob( StackedTileLoader *tileLoader, int tileLevel, QImage *canvasImage, const ViewportParams *viewport, MapQuality mapQuality, int yTop, int yBottom )
48 : m_tileLoader( tileLoader ),
49 m_tileLevel( tileLevel ),
50 m_canvasImage( canvasImage ),
51 m_viewport( viewport ),
52 m_mapQuality( mapQuality ),
53 m_yPaintedTop( yTop ),
54 m_yPaintedBottom( yBottom )
55{
56}
57
58MercatorScanlineTextureMapper::MercatorScanlineTextureMapper( StackedTileLoader *tileLoader )
59 : TextureMapperInterface(),
60 m_tileLoader( tileLoader ),
61 m_radius( 0 ),
62 m_oldYPaintedTop( 0 )
63{
64}
65
66void MercatorScanlineTextureMapper::mapTexture( GeoPainter *painter,
67 const ViewportParams *viewport,
68 int tileZoomLevel,
69 const QRect &dirtyRect,
70 TextureColorizer *texColorizer )
71{
72 if ( m_canvasImage.size() != viewport->size() || m_radius != viewport->radius() ) {
73 const QImage::Format optimalFormat = ScanlineTextureMapperContext::optimalCanvasImageFormat( viewport );
74
75 if ( m_canvasImage.size() != viewport->size() || m_canvasImage.format() != optimalFormat ) {
76 m_canvasImage = QImage( viewport->size(), optimalFormat );
77 }
78
79 if ( !viewport->mapCoversViewport() ) {
80 m_canvasImage.fill( 0 );
81 }
82
83 m_radius = viewport->radius();
84 m_repaintNeeded = true;
85 }
86
87 if ( m_repaintNeeded ) {
88 mapTexture( viewport, tileZoomLevel, painter->mapQuality() );
89
90 if ( texColorizer ) {
91 texColorizer->colorize( &m_canvasImage, viewport, painter->mapQuality() );
92 }
93
94 m_repaintNeeded = false;
95 }
96
97 painter->drawImage( dirtyRect, m_canvasImage, dirtyRect );
98}
99
100void MercatorScanlineTextureMapper::mapTexture( const ViewportParams *viewport, int tileZoomLevel, MapQuality mapQuality )
101{
102 // Reset backend
103 m_tileLoader->resetTilehash();
104
105 // Initialize needed constants:
106
107 const int imageHeight = m_canvasImage.height();
108
109 // Calculate y-range the represented by the center point, yTop and
110 // what actually can be painted
111
112 qreal realYTop, realYBottom, dummyX;
113 GeoDataCoordinates yNorth(0, viewport->currentProjection()->maxLat(), 0);
114 GeoDataCoordinates ySouth(0, viewport->currentProjection()->minLat(), 0);
115 viewport->screenCoordinates(yNorth, dummyX, realYTop );
116 viewport->screenCoordinates(ySouth, dummyX, realYBottom );
117
118 const int yTop = qBound(qreal(0.0), realYTop, qreal(imageHeight));
119 int yPaintedTop = yTop;
120 int yPaintedBottom = qBound(qreal(0.0), realYBottom, qreal(imageHeight));
121
122 yPaintedTop = qBound(0, yPaintedTop, imageHeight);
123 yPaintedBottom = qBound(0, yPaintedBottom, imageHeight);
124
125 const int numThreads = m_threadPool.maxThreadCount();
126 const int yStep = ( yPaintedBottom - yPaintedTop ) / numThreads;
127 for ( int i = 0; i < numThreads; ++i ) {
128 const int yStart = yPaintedTop + i * yStep;
129 const int yEnd = (i == numThreads - 1) ? yPaintedBottom : yPaintedTop + (i + 1) * yStep;
130 QRunnable *const job = new RenderJob( m_tileLoader, tileZoomLevel, &m_canvasImage, viewport, mapQuality, yStart, yEnd );
131 m_threadPool.start( job );
132 }
133
134 // Remove unused lines
135 const int clearStart = ( yPaintedTop - m_oldYPaintedTop <= 0 ) ? yPaintedBottom : 0;
136 const int clearStop = ( yPaintedTop - m_oldYPaintedTop <= 0 ) ? imageHeight : yTop;
137
138 QRgb * const itClearBegin = (QRgb*)( m_canvasImage.scanLine( clearStart ) );
139 QRgb * const itClearEnd = (QRgb*)( m_canvasImage.scanLine( clearStop ) );
140
141 for ( QRgb * it = itClearBegin; it < itClearEnd; ++it ) {
142 *(it) = 0;
143 }
144
145 m_threadPool.waitForDone();
146
147 m_oldYPaintedTop = yPaintedTop;
148
149 m_tileLoader->cleanupTilehash();
150}
151
152
153void MercatorScanlineTextureMapper::RenderJob::run()
154{
155 // Scanline based algorithm to do texture mapping
156
157 const int imageHeight = m_canvasImage->height();
158 const int imageWidth = m_canvasImage->width();
159 const qint64 radius = m_viewport->radius();
160 // Calculate how many degrees are being represented per pixel.
161 const float rad2Pixel = (float)( 2 * radius ) / M_PI;
162 const qreal pixel2Rad = 1.0/rad2Pixel;
163
164 const bool interlaced = ( m_mapQuality == LowQuality );
165 const bool highQuality = ( m_mapQuality == HighQuality
166 || m_mapQuality == PrintQuality );
167 const bool printQuality = ( m_mapQuality == PrintQuality );
168
169 // Evaluate the degree of interpolation
170 const int n = ScanlineTextureMapperContext::interpolationStep( m_viewport, m_mapQuality );
171
172 // Calculate translation of center point
173 const qreal centerLon = m_viewport->centerLongitude();
174 const qreal centerLat = m_viewport->centerLatitude();
175
176 const int yCenterOffset = (int)( asinh( tan( centerLat ) ) * rad2Pixel );
177
178 qreal leftLon = + centerLon - ( imageWidth / 2 * pixel2Rad );
179 while ( leftLon < -M_PI ) leftLon += 2 * M_PI;
180 while ( leftLon > M_PI ) leftLon -= 2 * M_PI;
181
182 const int maxInterpolationPointX = n * (int)( imageWidth / n - 1 ) + 1;
183
184
185 // initialize needed variables that are modified during texture mapping:
186
187 ScanlineTextureMapperContext context( m_tileLoader, m_tileLevel );
188
189
190 // Scanline based algorithm to do texture mapping
191
192 for ( int y = m_yPaintedTop; y < m_yPaintedBottom; ++y ) {
193
194 QRgb * scanLine = (QRgb*)( m_canvasImage->scanLine( y ) );
195
196 qreal lon = leftLon;
197 const qreal lat = gd ( ( (imageHeight / 2 + yCenterOffset) - y )
198 * pixel2Rad );
199
200 for ( int x = 0; x < imageWidth; ++x ) {
201 // Prepare for interpolation
202 bool interpolate = false;
203 if ( x > 0 && x <= maxInterpolationPointX ) {
204 x += n - 1;
205 lon += (n - 1) * pixel2Rad;
206 interpolate = !printQuality;
207 }
208 else {
209 interpolate = false;
210 }
211
212 if ( lon < -M_PI ) lon += 2 * M_PI;
213 if ( lon > M_PI ) lon -= 2 * M_PI;
214
215 if ( interpolate ) {
216 if (highQuality)
217 context.pixelValueApproxF( lon, lat, scanLine, n );
218 else
219 context.pixelValueApprox( lon, lat, scanLine, n );
220
221 scanLine += ( n - 1 );
222 }
223
224 if ( x < imageWidth ) {
225 if ( highQuality )
226 context.pixelValueF( lon, lat, scanLine );
227 else
228 context.pixelValue( lon, lat, scanLine );
229 }
230
231 ++scanLine;
232 lon += pixel2Rad;
233 }
234
235 // copy scanline to improve performance
236 if ( interlaced && y + 1 < m_yPaintedBottom ) {
237
238 const int pixelByteSize = m_canvasImage->bytesPerLine() / imageWidth;
239
240 memcpy( m_canvasImage->scanLine( y + 1 ),
241 m_canvasImage->scanLine( y ),
242 imageWidth * pixelByteSize );
243 ++y;
244 }
245 }
246}
This file contains the headers for AbstractProjection.
This file contains the headers for ViewportParams.
qreal minLat() const
Returns the arbitrarily chosen minimum (southern) latitude.
qreal maxLat() const
Returns the arbitrarily chosen maximum (northern) latitude.
A 3d point representation.
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...
Tile loading from a quad tree.
void cleanupTilehash()
Cleans up the internal tile hash.
void resetTilehash()
Resets the internal tile hash.
A public class that controls what is visible in the viewport of a Marble map.
bool screenCoordinates(const qreal lon, const qreal lat, qreal &x, qreal &y) const
Get the screen coordinates corresponding to geographical coordinates in the map.
Binds a QML item to a specific geodetic location in screen coordinates.
MapQuality
This enum is used to choose the map quality shown in the view.
@ HighQuality
High quality (e.g. antialiasing for lines)
@ PrintQuality
Print quality.
@ LowQuality
Low resolution (e.g. interlaced)
qsizetype bytesPerLine() const const
void fill(Qt::GlobalColor color)
Format format() const const
int height() const const
uchar * scanLine(int i)
QSize size() const const
int width() const const
void start(Callable &&callableToRun, int priority)
bool waitForDone(int msecs)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri May 3 2024 11:49:05 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.