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
32 RenderJob(StackedTileLoader *tileLoader,
int tileLevel, QImage *canvasImage,
const ViewportParams *viewport,
MapQuality mapQuality,
int yTop,
int yBottom);
37 StackedTileLoader *
const m_tileLoader;
38 const int m_tileLevel;
39 QImage *
const m_canvasImage;
40 const ViewportParams *
const m_viewport;
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)
108 m_tileLoader->resetTilehash();
112 const int imageHeight = m_canvasImage.height();
117 qreal realYTop, realYBottom, dummyX;
118 GeoDataCoordinates yNorth(0, viewport->currentProjection()->
maxLat(), 0);
119 GeoDataCoordinates ySouth(0, viewport->currentProjection()->
minLat(), 0);
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);
130 const int numThreads = m_threadPool.maxThreadCount();
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) {
150 m_threadPool.waitForDone();
152 m_oldYPaintedTop = yPaintedTop;
154 m_tileLoader->cleanupTilehash();
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 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.
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)