7#include "SphericalScanlineTextureMapper.h"
14#include "GeoDataPolygon.h"
15#include "GeoPainter.h"
16#include "MarbleDebug.h"
17#include "MathHelper.h"
18#include "Quaternion.h"
19#include "ScanlineTextureMapperContext.h"
20#include "StackedTile.h"
21#include "StackedTileLoader.h"
22#include "TextureColorizer.h"
27class SphericalScanlineTextureMapper::RenderJob :
public QRunnable
36 const int m_tileLevel;
37 QImage *
const m_canvasImage;
44SphericalScanlineTextureMapper::RenderJob::RenderJob(
StackedTileLoader *tileLoader,
51 : m_tileLoader(tileLoader)
52 , m_tileLevel(tileLevel)
53 , m_canvasImage(canvasImage)
54 , m_viewport(viewport)
55 , m_mapQuality(mapQuality)
61SphericalScanlineTextureMapper::SphericalScanlineTextureMapper(
StackedTileLoader *tileLoader)
62 : TextureMapperInterface()
63 , m_tileLoader(tileLoader)
69void SphericalScanlineTextureMapper::mapTexture(
GeoPainter *painter,
72 const QRect &dirtyRect,
73 TextureColorizer *texColorizer)
75 if (m_canvasImage.
size() != viewport->size() || m_radius != viewport->radius()) {
76 const QImage::Format optimalFormat = ScanlineTextureMapperContext::optimalCanvasImageFormat(viewport);
78 if (m_canvasImage.
size() != viewport->size() || m_canvasImage.
format() != optimalFormat) {
79 m_canvasImage =
QImage(viewport->size(), optimalFormat);
82 if (!viewport->mapCoversViewport()) {
83 m_canvasImage.
fill(0);
86 m_radius = viewport->radius();
87 m_repaintNeeded =
true;
90 if (m_repaintNeeded) {
91 mapTexture(viewport, tileZoomLevel, painter->
mapQuality());
94 texColorizer->colorize(&m_canvasImage, viewport, painter->
mapQuality());
97 m_repaintNeeded =
false;
100 const int radius = viewport->radius();
102 QRect rect(viewport->width() / 2 - radius, viewport->height() / 2 - radius, 2 * radius, 2 * radius);
103 rect = rect.intersected(dirtyRect);
104 painter->
drawImage(rect, m_canvasImage, rect);
107void SphericalScanlineTextureMapper::mapTexture(
const ViewportParams *viewport,
int tileZoomLevel,
MapQuality mapQuality)
114 const int imageHeight = m_canvasImage.
height();
115 const qint64 radius = viewport->radius();
118 const int skip = (mapQuality ==
LowQuality) ? 1 : 0;
119 const int yTop = (imageHeight / 2 - radius >= 0) ? imageHeight / 2 - radius : 0;
120 const int yBottom = (yTop == 0) ? imageHeight - skip : yTop + radius + radius - skip;
123 const int yStep = qCeil(qreal(yBottom - yTop) / qreal(numThreads));
124 for (
int i = 0; i < numThreads; ++i) {
125 const int yStart = yTop + i * yStep;
126 const int yEnd = qMin(yBottom, yTop + (i + 1) * yStep);
127 QRunnable *
const job =
new RenderJob(m_tileLoader, tileZoomLevel, &m_canvasImage, viewport, mapQuality, yStart, yEnd);
128 m_threadPool.
start(job);
136void SphericalScanlineTextureMapper::RenderJob::run()
138 const int imageHeight = m_canvasImage->
height();
139 const int imageWidth = m_canvasImage->
width();
140 const qint64 radius = m_viewport->radius();
141 const qreal inverseRadius = 1.0 / (qreal)(radius);
143 const bool interlaced = (m_mapQuality ==
LowQuality);
145 const bool printQuality = (m_mapQuality ==
PrintQuality);
148 const int n = ScanlineTextureMapperContext::interpolationStep(m_viewport, m_mapQuality);
151 Quaternion northPole = Quaternion::fromSpherical(0.0, M_PI * 0.5);
152 northPole.rotateAroundAxis(m_viewport->planetAxis().inverse());
153 const int northPoleX = imageWidth / 2 + (int)(radius * northPole.v[Q_X]);
154 const int northPoleY = imageHeight / 2 - (int)(radius * northPole.v[Q_Y]);
157 matrix planetAxisMatrix;
158 m_viewport->planetAxis().toMatrix(planetAxisMatrix);
162 ScanlineTextureMapperContext context(m_tileLoader, m_tileLevel);
167 for (
int y = m_yTop; y < m_yBottom; ++y) {
169 const qreal qy = inverseRadius * (qreal)(imageHeight / 2 - y);
170 const qreal qr = 1.0 - qy * qy;
173 const int rx = (int)sqrt((qreal)(radius * radius - ((y - imageHeight / 2) * (y - imageHeight / 2))));
187 const int xLeft = (imageWidth / 2 - rx > 0) ? imageWidth / 2 - rx : 0;
188 const int xRight = (imageWidth / 2 - rx > 0) ? xLeft + rx + rx : imageWidth;
190 QRgb *scanLine = (QRgb *)(m_canvasImage->
scanLine(y)) + xLeft;
192 const int xIpLeft = (imageWidth / 2 - rx > 0) ? n * (
int)(xLeft / n + 1) : 1;
193 const int xIpRight = (imageWidth / 2 - rx > 0) ? n * (
int)(xRight / n - 1) : n * (int)(xRight / n - 1) + 1;
196 bool crossingPoleArea =
false;
197 if (northPole.v[Q_Z] > 0 && northPoleY - (n * 0.75) <= y && northPoleY + (n * 0.75) >= y) {
198 crossingPoleArea = true;
203 for (
int x = xLeft; x < xRight; ++x) {
206 const int leftInterval = xIpLeft + ncount * n;
208 bool interpolate =
false;
209 if (x >= xIpLeft && x <= xIpRight) {
212 if (crossingPoleArea && northPoleX >= leftInterval + n && northPoleX < leftInterval + 2 * n && x < leftInterval + 3 * n) {
216 interpolate = !printQuality;
224 const qreal qx = (qreal)(x - imageWidth / 2) * inverseRadius;
225 const qreal qr2z = qr - qx * qx;
226 const qreal qz = (qr2z > 0.0) ? sqrt(qr2z) : 0.0;
230 Quaternion qpos(0.0, qx, qy, qz);
231 qpos.rotateAroundAxis(planetAxisMatrix);
233 qpos.getSpherical(lon, lat);
240 context.pixelValueApproxF(lon, lat, scanLine, n);
242 context.pixelValueApprox(lon, lat, scanLine, n);
254 if (x < imageWidth) {
256 context.pixelValueF(lon, lat, scanLine);
258 context.pixelValue(lon, lat, scanLine);
265 if (interlaced && y + 1 < m_yBottom) {
266 const int pixelByteSize = m_canvasImage->
bytesPerLine() / imageWidth;
268 memcpy(m_canvasImage->
scanLine(y + 1) + xLeft * pixelByteSize,
269 m_canvasImage->
scanLine(y) + xLeft * pixelByteSize,
270 (xRight - xLeft) * pixelByteSize);
This file contains the headers for ViewportParams.
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.
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)