10 #include"MercatorScanlineTextureMapper.h"
19 #include "GeoPainter.h"
20 #include "MarbleDebug.h"
21 #include "ScanlineTextureMapperContext.h"
22 #include "StackedTileLoader.h"
23 #include "TextureColorizer.h"
25 #include "MathHelper.h"
30 class MercatorScanlineTextureMapper::RenderJob :
public QRunnable
39 const int m_tileLevel;
40 QImage *
const m_canvasImage;
43 const int m_yPaintedTop;
44 const int m_yPaintedBottom;
48 : m_tileLoader( tileLoader ),
49 m_tileLevel( tileLevel ),
50 m_canvasImage( canvasImage ),
51 m_viewport( viewport ),
52 m_mapQuality( mapQuality ),
53 m_yPaintedTop( yTop ),
54 m_yPaintedBottom( yBottom )
58 MercatorScanlineTextureMapper::MercatorScanlineTextureMapper(
StackedTileLoader *tileLoader )
59 : TextureMapperInterface(),
60 m_tileLoader( tileLoader ),
66 void MercatorScanlineTextureMapper::mapTexture(
GeoPainter *painter,
69 const QRect &dirtyRect,
70 TextureColorizer *texColorizer )
72 if ( m_canvasImage.size() != viewport->size() || m_radius != viewport->radius() ) {
73 const QImage::Format optimalFormat = ScanlineTextureMapperContext::optimalCanvasImageFormat( viewport );
75 if ( m_canvasImage.size() != viewport->size() || m_canvasImage.format() != optimalFormat ) {
76 m_canvasImage =
QImage( viewport->size(), optimalFormat );
79 if ( !viewport->mapCoversViewport() ) {
80 m_canvasImage.fill( 0 );
83 m_radius = viewport->radius();
84 m_repaintNeeded =
true;
87 if ( m_repaintNeeded ) {
88 mapTexture( viewport, tileZoomLevel, painter->
mapQuality() );
91 texColorizer->colorize( &m_canvasImage, viewport, painter->
mapQuality() );
94 m_repaintNeeded =
false;
97 painter->
drawImage( dirtyRect, m_canvasImage, dirtyRect );
100 void MercatorScanlineTextureMapper::mapTexture(
const ViewportParams *viewport,
int tileZoomLevel,
MapQuality mapQuality )
103 m_tileLoader->resetTilehash();
107 const int imageHeight = m_canvasImage.height();
112 qreal realYTop, realYBottom, dummyX;
118 const int yTop = qBound(qreal(0.0), realYTop, qreal(imageHeight));
119 int yPaintedTop = yTop;
120 int yPaintedBottom = qBound(qreal(0.0), realYBottom, qreal(imageHeight));
122 yPaintedTop = qBound(0, yPaintedTop, imageHeight);
123 yPaintedBottom = qBound(0, yPaintedBottom, imageHeight);
125 const int numThreads = m_threadPool.maxThreadCount();
126 const int yStep = ( yPaintedBottom - yPaintedTop ) / numThreads;
127 for (
int i = 0; i < numThreads; ++i ) {
128 const int yStart = yPaintedTop + i * yStep;
129 const int yEnd = (i == numThreads - 1) ? yPaintedBottom : yPaintedTop + (i + 1) * yStep;
130 QRunnable *
const job =
new RenderJob( m_tileLoader, tileZoomLevel, &m_canvasImage, viewport, mapQuality, yStart, yEnd );
131 m_threadPool.start( job );
135 const int clearStart = ( yPaintedTop - m_oldYPaintedTop <= 0 ) ? yPaintedBottom : 0;
136 const int clearStop = ( yPaintedTop - m_oldYPaintedTop <= 0 ) ? imageHeight : yTop;
138 QRgb *
const itClearBegin = (QRgb*)( m_canvasImage.scanLine( clearStart ) );
139 QRgb *
const itClearEnd = (QRgb*)( m_canvasImage.scanLine( clearStop ) );
141 for ( QRgb * it = itClearBegin; it < itClearEnd; ++it ) {
145 m_threadPool.waitForDone();
147 m_oldYPaintedTop = yPaintedTop;
149 m_tileLoader->cleanupTilehash();
153 void MercatorScanlineTextureMapper::RenderJob::run()
157 const int imageHeight = m_canvasImage->height();
158 const int imageWidth = m_canvasImage->width();
159 const qint64 radius = m_viewport->radius();
161 const float rad2Pixel = (float)( 2 * radius ) / M_PI;
162 const qreal pixel2Rad = 1.0/rad2Pixel;
164 const bool interlaced = ( m_mapQuality ==
LowQuality );
165 const bool highQuality = ( m_mapQuality ==
HighQuality
167 const bool printQuality = ( m_mapQuality ==
PrintQuality );
170 const int n = ScanlineTextureMapperContext::interpolationStep( m_viewport, m_mapQuality );
173 const qreal centerLon = m_viewport->centerLongitude();
174 const qreal centerLat = m_viewport->centerLatitude();
176 const int yCenterOffset = (int)( asinh( tan( centerLat ) ) * rad2Pixel );
178 qreal leftLon = + centerLon - ( imageWidth / 2 * pixel2Rad );
179 while ( leftLon < -M_PI ) leftLon += 2 * M_PI;
180 while ( leftLon > M_PI ) leftLon -= 2 * M_PI;
182 const int maxInterpolationPointX = n * (int)( imageWidth / n - 1 ) + 1;
187 ScanlineTextureMapperContext context( m_tileLoader, m_tileLevel );
192 for (
int y = m_yPaintedTop; y < m_yPaintedBottom; ++y ) {
194 QRgb * scanLine = (QRgb*)( m_canvasImage->scanLine( y ) );
197 const qreal lat = gd ( ( (imageHeight / 2 + yCenterOffset) - y )
200 for (
int x = 0; x < imageWidth; ++x ) {
202 bool interpolate =
false;
203 if ( x > 0 && x <= maxInterpolationPointX ) {
205 lon += (n - 1) * pixel2Rad;
206 interpolate = !printQuality;
212 if ( lon < -M_PI ) lon += 2 * M_PI;
213 if ( lon > M_PI ) lon -= 2 * M_PI;
217 context.pixelValueApproxF( lon, lat, scanLine, n );
219 context.pixelValueApprox( lon, lat, scanLine, n );
221 scanLine += ( n - 1 );
224 if ( x < imageWidth ) {
226 context.pixelValueF( lon, lat, scanLine );
228 context.pixelValue( lon, lat, scanLine );
236 if ( interlaced && y + 1 < m_yPaintedBottom ) {
238 const int pixelByteSize = m_canvasImage->bytesPerLine() / imageWidth;
240 memcpy( m_canvasImage->scanLine( y + 1 ),
241 m_canvasImage->scanLine( y ),
242 imageWidth * pixelByteSize );