9#include "MercatorScanlineTextureMapper.h"
19#include "GeoPainter.h"
20#include "MarbleDebug.h"
21#include "MathHelper.h"
22#include "ScanlineTextureMapperContext.h"
23#include "StackedTileLoader.h"
24#include "TextureColorizer.h"
29class MercatorScanlineTextureMapper::RenderJob :
public QRunnable
38 const int m_tileLevel;
39 QImage *
const m_canvasImage;
42 const int m_yPaintedTop;
43 const int m_yPaintedBottom;
53 : m_tileLoader(tileLoader)
54 , m_tileLevel(tileLevel)
55 , m_canvasImage(canvasImage)
56 , m_viewport(viewport)
57 , m_mapQuality(mapQuality)
59 , m_yPaintedBottom(yBottom)
63MercatorScanlineTextureMapper::MercatorScanlineTextureMapper(
StackedTileLoader *tileLoader)
64 : TextureMapperInterface()
65 , m_tileLoader(tileLoader)
71void MercatorScanlineTextureMapper::mapTexture(
GeoPainter *painter,
74 const QRect &dirtyRect,
75 TextureColorizer *texColorizer)
77 if (m_canvasImage.
size() != viewport->size() || m_radius != viewport->radius()) {
78 const QImage::Format optimalFormat = ScanlineTextureMapperContext::optimalCanvasImageFormat(viewport);
80 if (m_canvasImage.
size() != viewport->size() || m_canvasImage.
format() != optimalFormat) {
81 m_canvasImage =
QImage(viewport->size(), optimalFormat);
84 if (!viewport->mapCoversViewport()) {
85 m_canvasImage.
fill(0);
88 m_radius = viewport->radius();
89 m_repaintNeeded =
true;
92 if (m_repaintNeeded) {
93 mapTexture(viewport, tileZoomLevel, painter->
mapQuality());
96 texColorizer->colorize(&m_canvasImage, viewport, painter->
mapQuality());
99 m_repaintNeeded =
false;
102 painter->
drawImage(dirtyRect, m_canvasImage, dirtyRect);
105void MercatorScanlineTextureMapper::mapTexture(
const ViewportParams *viewport,
int tileZoomLevel,
MapQuality mapQuality)
112 const int imageHeight = m_canvasImage.
height();
117 qreal realYTop, realYBottom, dummyX;
123 const int yTop = qBound(qreal(0.0), realYTop, qreal(imageHeight));
124 int yPaintedTop = yTop;
125 int yPaintedBottom = qBound(qreal(0.0), realYBottom, qreal(imageHeight));
127 yPaintedTop = qBound(0, yPaintedTop, imageHeight);
128 yPaintedBottom = qBound(0, yPaintedBottom, imageHeight);
131 const int yStep = (yPaintedBottom - yPaintedTop) / numThreads;
132 for (
int i = 0; i < numThreads; ++i) {
133 const int yStart = yPaintedTop + i * yStep;
134 const int yEnd = (i == numThreads - 1) ? yPaintedBottom : yPaintedTop + (i + 1) * yStep;
135 QRunnable *
const job =
new RenderJob(m_tileLoader, tileZoomLevel, &m_canvasImage, viewport, mapQuality, yStart, yEnd);
136 m_threadPool.
start(job);
140 const int clearStart = (yPaintedTop - m_oldYPaintedTop <= 0) ? yPaintedBottom : 0;
141 const int clearStop = (yPaintedTop - m_oldYPaintedTop <= 0) ? imageHeight : yTop;
143 QRgb *
const itClearBegin = (QRgb *)(m_canvasImage.
scanLine(clearStart));
144 QRgb *
const itClearEnd = (QRgb *)(m_canvasImage.
scanLine(clearStop));
146 for (QRgb *it = itClearBegin; it < itClearEnd; ++it) {
152 m_oldYPaintedTop = yPaintedTop;
157void MercatorScanlineTextureMapper::RenderJob::run()
161 const int imageHeight = m_canvasImage->
height();
162 const int imageWidth = m_canvasImage->
width();
163 const qint64 radius = m_viewport->radius();
165 const float rad2Pixel = (float)(2 * radius) / M_PI;
166 const qreal pixel2Rad = 1.0 / rad2Pixel;
168 const bool interlaced = (m_mapQuality ==
LowQuality);
170 const bool printQuality = (m_mapQuality ==
PrintQuality);
173 const int n = ScanlineTextureMapperContext::interpolationStep(m_viewport, m_mapQuality);
176 const qreal centerLon = m_viewport->centerLongitude();
177 const qreal centerLat = m_viewport->centerLatitude();
179 const int yCenterOffset = (int)(asinh(tan(centerLat)) * rad2Pixel);
181 qreal leftLon = +centerLon - (imageWidth / 2 * pixel2Rad);
182 while (leftLon < -M_PI)
184 while (leftLon > M_PI)
187 const int maxInterpolationPointX = n * (int)(imageWidth / n - 1) + 1;
191 ScanlineTextureMapperContext context(m_tileLoader, m_tileLevel);
195 for (
int y = m_yPaintedTop; y < m_yPaintedBottom; ++y) {
196 QRgb *scanLine = (QRgb *)(m_canvasImage->
scanLine(y));
199 const qreal lat = gd(((imageHeight / 2 + yCenterOffset) - y) * pixel2Rad);
201 for (
int x = 0; x < imageWidth; ++x) {
203 bool interpolate =
false;
204 if (x > 0 && x <= maxInterpolationPointX) {
206 lon += (n - 1) * pixel2Rad;
207 interpolate = !printQuality;
219 context.pixelValueApproxF(lon, lat, scanLine, n);
221 context.pixelValueApprox(lon, lat, scanLine, n);
226 if (x < imageWidth) {
228 context.pixelValueF(lon, lat, scanLine);
230 context.pixelValue(lon, lat, scanLine);
238 if (interlaced && y + 1 < m_yPaintedBottom) {
239 const int pixelByteSize = m_canvasImage->
bytesPerLine() / imageWidth;
241 memcpy(m_canvasImage->
scanLine(y + 1), m_canvasImage->
scanLine(y), imageWidth * pixelByteSize);
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.
MapQuality mapQuality() const
Returns the map quality.
void drawImage(const GeoDataCoordinates ¢erPosition, 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)
void start(Callable &&callableToRun, int priority)
bool waitForDone(int msecs)