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)