Marble

EquirectScanlineTextureMapper.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later
2//
3// SPDX-FileCopyrightText: 2007 Carlos Licea <carlos _licea@hotmail.com>
4// SPDX-FileCopyrightText: 2011 Bernhard Beschow <bbeschow@cs.tu-berlin.de>
5//
6
7
8// local
9#include"EquirectScanlineTextureMapper.h"
10
11// posix
12#include <cmath>
13
14// Qt
15#include <QRunnable>
16
17// Marble
18#include "GeoPainter.h"
19#include "MarbleDebug.h"
20#include "ScanlineTextureMapperContext.h"
21#include "StackedTileLoader.h"
22#include "TextureColorizer.h"
23#include "ViewportParams.h"
24#include "AbstractProjection.h"
25
26using namespace Marble;
27
28class EquirectScanlineTextureMapper::RenderJob : public QRunnable
29{
30public:
31 RenderJob( StackedTileLoader *tileLoader, int tileLevel, QImage *canvasImage, const ViewportParams *viewportParams, MapQuality mapQuality, int yTop, int yBottom );
32
33 void run() override;
34
35private:
36 StackedTileLoader *const m_tileLoader;
37 const int m_tileLevel;
38 QImage *const m_canvasImage;
39 const ViewportParams *const m_viewport;
40 const MapQuality m_mapQuality;
41 const int m_yPaintedTop;
42 const int m_yPaintedBottom;
43};
44
45EquirectScanlineTextureMapper::RenderJob::RenderJob( StackedTileLoader *tileLoader, int tileLevel, QImage *canvasImage, const ViewportParams *viewport, MapQuality mapQuality, int yTop, int yBottom )
46 : m_tileLoader( tileLoader ),
47 m_tileLevel( tileLevel ),
48 m_canvasImage( canvasImage ),
49 m_viewport( viewport ),
50 m_mapQuality( mapQuality ),
51 m_yPaintedTop( yTop ),
52 m_yPaintedBottom( yBottom )
53{
54}
55
56
57EquirectScanlineTextureMapper::EquirectScanlineTextureMapper( StackedTileLoader *tileLoader )
58 : TextureMapperInterface(),
59 m_tileLoader( tileLoader ),
60 m_radius( 0 ),
61 m_oldYPaintedTop( 0 )
62{
63}
64
65void EquirectScanlineTextureMapper::mapTexture( GeoPainter *painter,
66 const ViewportParams *viewport,
67 int tileZoomLevel,
68 const QRect &dirtyRect,
69 TextureColorizer *texColorizer )
70{
71 if ( m_canvasImage.size() != viewport->size() || m_radius != viewport->radius() ) {
72 const QImage::Format optimalFormat = ScanlineTextureMapperContext::optimalCanvasImageFormat( viewport );
73
74 if ( m_canvasImage.size() != viewport->size() || m_canvasImage.format() != optimalFormat ) {
75 m_canvasImage = QImage( viewport->size(), optimalFormat );
76 }
77
78 if ( !viewport->mapCoversViewport() ) {
79 m_canvasImage.fill( 0 );
80 }
81
82 m_radius = viewport->radius();
83 m_repaintNeeded = true;
84 }
85
86 if ( m_repaintNeeded ) {
87 mapTexture( viewport, tileZoomLevel, painter->mapQuality() );
88
89 if ( texColorizer ) {
90 texColorizer->colorize( &m_canvasImage, viewport, painter->mapQuality() );
91 }
92
93 m_repaintNeeded = false;
94 }
95
96 painter->drawImage( dirtyRect, m_canvasImage, dirtyRect );
97}
98
99void EquirectScanlineTextureMapper::mapTexture( const ViewportParams *viewport, int tileZoomLevel, MapQuality mapQuality )
100{
101 // Reset backend
102 m_tileLoader->resetTilehash();
103
104 // Initialize needed constants:
105
106 const int imageHeight = m_canvasImage.height();
107
108 // Calculate y-range the represented by the center point, yTop and
109 // what actually can be painted
110
111 qreal realYTop, realYBottom, dummyX;
112 GeoDataCoordinates yNorth(0, viewport->currentProjection()->maxLat(), 0);
113 GeoDataCoordinates ySouth(0, viewport->currentProjection()->minLat(), 0);
114 viewport->screenCoordinates(yNorth, dummyX, realYTop );
115 viewport->screenCoordinates(ySouth, dummyX, realYBottom );
116
117 const int yTop = qBound(qreal(0.0), realYTop, qreal(imageHeight));
118 int yPaintedTop = yTop;
119 int yPaintedBottom = qBound(qreal(0.0), realYBottom, qreal(imageHeight));
120
121 yPaintedTop = qBound(0, yPaintedTop, imageHeight);
122 yPaintedBottom = qBound(0, yPaintedBottom, imageHeight);
123
124 const int numThreads = m_threadPool.maxThreadCount();
125 const int yStep = ( yPaintedBottom - yPaintedTop ) / numThreads;
126 for ( int i = 0; i < numThreads; ++i ) {
127 const int yStart = yPaintedTop + i * yStep;
128 const int yEnd = (i == numThreads - 1) ? yPaintedBottom : yPaintedTop + (i + 1) * yStep;
129 QRunnable *const job = new RenderJob( m_tileLoader, tileZoomLevel, &m_canvasImage, viewport, mapQuality, yStart, yEnd );
130 m_threadPool.start( job );
131 }
132
133 // Remove unused lines
134 const int clearStart = ( yPaintedTop - m_oldYPaintedTop <= 0 ) ? yPaintedBottom : 0;
135 const int clearStop = ( yPaintedTop - m_oldYPaintedTop <= 0 ) ? imageHeight : yTop;
136
137 QRgb * const itClearBegin = (QRgb*)( m_canvasImage.scanLine( clearStart ) );
138 QRgb * const itClearEnd = (QRgb*)( m_canvasImage.scanLine( clearStop ) );
139
140 for ( QRgb * it = itClearBegin; it < itClearEnd; ++it ) {
141 *(it) = 0;
142 }
143
144 m_threadPool.waitForDone();
145
146 m_oldYPaintedTop = yPaintedTop;
147
148 m_tileLoader->cleanupTilehash();
149}
150
151void EquirectScanlineTextureMapper::RenderJob::run()
152{
153 // Scanline based algorithm to do texture mapping
154
155 const int imageHeight = m_canvasImage->height();
156 const int imageWidth = m_canvasImage->width();
157 const qint64 radius = m_viewport->radius();
158 // Calculate how many degrees are being represented per pixel.
159 const qreal rad2Pixel = (qreal)( 2 * radius ) / M_PI;
160 const float pixel2Rad = 1.0/rad2Pixel; // FIXME changing to qreal may crash Marble when the equator is visible
161
162 const bool interlaced = ( m_mapQuality == LowQuality );
163 const bool highQuality = ( m_mapQuality == HighQuality
164 || m_mapQuality == PrintQuality );
165 const bool printQuality = ( m_mapQuality == PrintQuality );
166
167 // Evaluate the degree of interpolation
168 const int n = ScanlineTextureMapperContext::interpolationStep( m_viewport, m_mapQuality );
169
170 // Calculate translation of center point
171 const qreal centerLon = m_viewport->centerLongitude();
172 const qreal centerLat = m_viewport->centerLatitude();
173
174 const int yCenterOffset = (int)( centerLat * rad2Pixel );
175
176 const int yTop = imageHeight / 2 - radius + yCenterOffset;
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 = M_PI/2 - (y - yTop )* pixel2Rad;
198
199 for ( int x = 0; x < imageWidth; ++x ) {
200
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 17 2024 11:49:23 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.