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// local
8#include "EquirectScanlineTextureMapper.h"
9
10// posix
11#include <cmath>
12
13// Qt
14#include <QRunnable>
15
16// Marble
17#include "AbstractProjection.h"
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
25using namespace Marble;
26
27class EquirectScanlineTextureMapper::RenderJob : public QRunnable
28{
29public:
30 RenderJob(StackedTileLoader *tileLoader,
31 int tileLevel,
32 QImage *canvasImage,
33 const ViewportParams *viewportParams,
34 MapQuality mapQuality,
35 int yTop,
36 int yBottom);
37
38 void run() override;
39
40private:
41 StackedTileLoader *const m_tileLoader;
42 const int m_tileLevel;
43 QImage *const m_canvasImage;
44 const ViewportParams *const m_viewport;
45 const MapQuality m_mapQuality;
46 const int m_yPaintedTop;
47 const int m_yPaintedBottom;
48};
49
50EquirectScanlineTextureMapper::RenderJob::RenderJob(StackedTileLoader *tileLoader,
51 int tileLevel,
52 QImage *canvasImage,
53 const ViewportParams *viewport,
54 MapQuality mapQuality,
55 int yTop,
56 int yBottom)
57 : m_tileLoader(tileLoader)
58 , m_tileLevel(tileLevel)
59 , m_canvasImage(canvasImage)
60 , m_viewport(viewport)
61 , m_mapQuality(mapQuality)
62 , m_yPaintedTop(yTop)
63 , m_yPaintedBottom(yBottom)
64{
65}
66
67EquirectScanlineTextureMapper::EquirectScanlineTextureMapper(StackedTileLoader *tileLoader)
68 : TextureMapperInterface()
69 , m_tileLoader(tileLoader)
70 , m_radius(0)
71 , m_oldYPaintedTop(0)
72{
73}
74
75void EquirectScanlineTextureMapper::mapTexture(GeoPainter *painter,
76 const ViewportParams *viewport,
77 int tileZoomLevel,
78 const QRect &dirtyRect,
79 TextureColorizer *texColorizer)
80{
81 if (m_canvasImage.size() != viewport->size() || m_radius != viewport->radius()) {
82 const QImage::Format optimalFormat = ScanlineTextureMapperContext::optimalCanvasImageFormat(viewport);
83
84 if (m_canvasImage.size() != viewport->size() || m_canvasImage.format() != optimalFormat) {
85 m_canvasImage = QImage(viewport->size(), optimalFormat);
86 }
87
88 if (!viewport->mapCoversViewport()) {
89 m_canvasImage.fill(0);
90 }
91
92 m_radius = viewport->radius();
93 m_repaintNeeded = true;
94 }
95
96 if (m_repaintNeeded) {
97 mapTexture(viewport, tileZoomLevel, painter->mapQuality());
98
99 if (texColorizer) {
100 texColorizer->colorize(&m_canvasImage, viewport, painter->mapQuality());
101 }
102
103 m_repaintNeeded = false;
104 }
105
106 painter->drawImage(dirtyRect, m_canvasImage, dirtyRect);
107}
108
109void EquirectScanlineTextureMapper::mapTexture(const ViewportParams *viewport, int tileZoomLevel, MapQuality mapQuality)
110{
111 // Reset backend
112 m_tileLoader->resetTilehash();
113
114 // Initialize needed constants:
115
116 const int imageHeight = m_canvasImage.height();
117
118 // Calculate y-range the represented by the center point, yTop and
119 // what actually can be painted
120
121 qreal realYTop, realYBottom, dummyX;
122 GeoDataCoordinates yNorth(0, viewport->currentProjection()->maxLat(), 0);
123 GeoDataCoordinates ySouth(0, viewport->currentProjection()->minLat(), 0);
124 viewport->screenCoordinates(yNorth, dummyX, realYTop);
125 viewport->screenCoordinates(ySouth, dummyX, realYBottom);
126
127 const int yTop = qBound(qreal(0.0), realYTop, qreal(imageHeight));
128 int yPaintedTop = yTop;
129 int yPaintedBottom = qBound(qreal(0.0), realYBottom, qreal(imageHeight));
130
131 yPaintedTop = qBound(0, yPaintedTop, imageHeight);
132 yPaintedBottom = qBound(0, yPaintedBottom, imageHeight);
133
134 const int numThreads = m_threadPool.maxThreadCount();
135 const int yStep = (yPaintedBottom - yPaintedTop) / numThreads;
136 for (int i = 0; i < numThreads; ++i) {
137 const int yStart = yPaintedTop + i * yStep;
138 const int yEnd = (i == numThreads - 1) ? yPaintedBottom : yPaintedTop + (i + 1) * yStep;
139 QRunnable *const job = new RenderJob(m_tileLoader, tileZoomLevel, &m_canvasImage, viewport, mapQuality, yStart, yEnd);
140 m_threadPool.start(job);
141 }
142
143 // Remove unused lines
144 const int clearStart = (yPaintedTop - m_oldYPaintedTop <= 0) ? yPaintedBottom : 0;
145 const int clearStop = (yPaintedTop - m_oldYPaintedTop <= 0) ? imageHeight : yTop;
146
147 QRgb *const itClearBegin = (QRgb *)(m_canvasImage.scanLine(clearStart));
148 QRgb *const itClearEnd = (QRgb *)(m_canvasImage.scanLine(clearStop));
149
150 for (QRgb *it = itClearBegin; it < itClearEnd; ++it) {
151 *(it) = 0;
152 }
153
154 m_threadPool.waitForDone();
155
156 m_oldYPaintedTop = yPaintedTop;
157
158 m_tileLoader->cleanupTilehash();
159}
160
161void EquirectScanlineTextureMapper::RenderJob::run()
162{
163 // Scanline based algorithm to do texture mapping
164
165 const int imageHeight = m_canvasImage->height();
166 const int imageWidth = m_canvasImage->width();
167 const qint64 radius = m_viewport->radius();
168 // Calculate how many degrees are being represented per pixel.
169 const qreal rad2Pixel = (qreal)(2 * radius) / M_PI;
170 const float pixel2Rad = 1.0 / rad2Pixel; // FIXME changing to qreal may crash Marble when the equator is visible
171
172 const bool interlaced = (m_mapQuality == LowQuality);
173 const bool highQuality = (m_mapQuality == HighQuality || m_mapQuality == PrintQuality);
174 const bool printQuality = (m_mapQuality == PrintQuality);
175
176 // Evaluate the degree of interpolation
177 const int n = ScanlineTextureMapperContext::interpolationStep(m_viewport, m_mapQuality);
178
179 // Calculate translation of center point
180 const qreal centerLon = m_viewport->centerLongitude();
181 const qreal centerLat = m_viewport->centerLatitude();
182
183 const int yCenterOffset = (int)(centerLat * rad2Pixel);
184
185 const int yTop = imageHeight / 2 - radius + yCenterOffset;
186
187 qreal leftLon = +centerLon - (imageWidth / 2 * pixel2Rad);
188 while (leftLon < -M_PI)
189 leftLon += 2 * M_PI;
190 while (leftLon > M_PI)
191 leftLon -= 2 * M_PI;
192
193 const int maxInterpolationPointX = n * (int)(imageWidth / n - 1) + 1;
194
195 // initialize needed variables that are modified during texture mapping:
196
197 ScanlineTextureMapperContext context(m_tileLoader, m_tileLevel);
198
199 // Scanline based algorithm to do texture mapping
200
201 for (int y = m_yPaintedTop; y < m_yPaintedBottom; ++y) {
202 QRgb *scanLine = (QRgb *)(m_canvasImage->scanLine(y));
203
204 qreal lon = leftLon;
205 const qreal lat = M_PI / 2 - (y - yTop) * pixel2Rad;
206
207 for (int x = 0; x < imageWidth; ++x) {
208 // Prepare for interpolation
209 bool interpolate = false;
210 if (x > 0 && x <= maxInterpolationPointX) {
211 x += n - 1;
212 lon += (n - 1) * pixel2Rad;
213 interpolate = !printQuality;
214 } else {
215 interpolate = false;
216 }
217
218 if (lon < -M_PI)
219 lon += 2 * M_PI;
220 if (lon > M_PI)
221 lon -= 2 * M_PI;
222
223 if (interpolate) {
224 if (highQuality)
225 context.pixelValueApproxF(lon, lat, scanLine, n);
226 else
227 context.pixelValueApprox(lon, lat, scanLine, n);
228
229 scanLine += (n - 1);
230 }
231
232 if (x < imageWidth) {
233 if (highQuality)
234 context.pixelValueF(lon, lat, scanLine);
235 else
236 context.pixelValue(lon, lat, scanLine);
237 }
238
239 ++scanLine;
240 lon += pixel2Rad;
241 }
242
243 // copy scanline to improve performance
244 if (interlaced && y + 1 < m_yPaintedBottom) {
245 const int pixelByteSize = m_canvasImage->bytesPerLine() / imageWidth;
246
247 memcpy(m_canvasImage->scanLine(y + 1), m_canvasImage->scanLine(y), imageWidth * pixelByteSize);
248 ++y;
249 }
250 }
251}
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: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...
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 Sat Dec 21 2024 17:04:13 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.