9 #include"EquirectScanlineTextureMapper.h"
18 #include "GeoPainter.h"
19 #include "MarbleDebug.h"
20 #include "ScanlineTextureMapperContext.h"
21 #include "StackedTileLoader.h"
22 #include "TextureColorizer.h"
28 class EquirectScanlineTextureMapper::RenderJob :
public QRunnable
37 const int m_tileLevel;
38 QImage *
const m_canvasImage;
41 const int m_yPaintedTop;
42 const int m_yPaintedBottom;
46 : m_tileLoader( tileLoader ),
47 m_tileLevel( tileLevel ),
48 m_canvasImage( canvasImage ),
49 m_viewport( viewport ),
50 m_mapQuality( mapQuality ),
51 m_yPaintedTop( yTop ),
52 m_yPaintedBottom( yBottom )
57 EquirectScanlineTextureMapper::EquirectScanlineTextureMapper(
StackedTileLoader *tileLoader )
58 : TextureMapperInterface(),
59 m_tileLoader( tileLoader ),
65 void EquirectScanlineTextureMapper::mapTexture(
GeoPainter *painter,
68 const QRect &dirtyRect,
69 TextureColorizer *texColorizer )
71 if ( m_canvasImage.size() != viewport->size() || m_radius != viewport->radius() ) {
72 const QImage::Format optimalFormat = ScanlineTextureMapperContext::optimalCanvasImageFormat( viewport );
74 if ( m_canvasImage.size() != viewport->size() || m_canvasImage.format() != optimalFormat ) {
75 m_canvasImage =
QImage( viewport->size(), optimalFormat );
78 if ( !viewport->mapCoversViewport() ) {
79 m_canvasImage.fill( 0 );
82 m_radius = viewport->radius();
83 m_repaintNeeded =
true;
86 if ( m_repaintNeeded ) {
87 mapTexture( viewport, tileZoomLevel, painter->
mapQuality() );
90 texColorizer->colorize( &m_canvasImage, viewport, painter->
mapQuality() );
93 m_repaintNeeded =
false;
96 painter->
drawImage( dirtyRect, m_canvasImage, dirtyRect );
99 void EquirectScanlineTextureMapper::mapTexture(
const ViewportParams *viewport,
int tileZoomLevel,
MapQuality mapQuality )
102 m_tileLoader->resetTilehash();
106 const int imageHeight = m_canvasImage.height();
111 qreal realYTop, realYBottom, dummyX;
117 const int yTop = qBound(qreal(0.0), realYTop, qreal(imageHeight));
118 int yPaintedTop = yTop;
119 int yPaintedBottom = qBound(qreal(0.0), realYBottom, qreal(imageHeight));
121 yPaintedTop = qBound(0, yPaintedTop, imageHeight);
122 yPaintedBottom = qBound(0, yPaintedBottom, imageHeight);
124 const int numThreads = m_threadPool.maxThreadCount();
125 const int yStep = ( yPaintedBottom - yPaintedTop ) / numThreads;
126 for (
int i = 0; i < numThreads; ++i ) {
127 const int yStart = yPaintedTop + i * yStep;
128 const int yEnd = (i == numThreads - 1) ? yPaintedBottom : yPaintedTop + (i + 1) * yStep;
129 QRunnable *
const job =
new RenderJob( m_tileLoader, tileZoomLevel, &m_canvasImage, viewport, mapQuality, yStart, yEnd );
130 m_threadPool.start( job );
134 const int clearStart = ( yPaintedTop - m_oldYPaintedTop <= 0 ) ? yPaintedBottom : 0;
135 const int clearStop = ( yPaintedTop - m_oldYPaintedTop <= 0 ) ? imageHeight : yTop;
137 QRgb *
const itClearBegin = (QRgb*)( m_canvasImage.scanLine( clearStart ) );
138 QRgb *
const itClearEnd = (QRgb*)( m_canvasImage.scanLine( clearStop ) );
140 for ( QRgb * it = itClearBegin; it < itClearEnd; ++it ) {
144 m_threadPool.waitForDone();
146 m_oldYPaintedTop = yPaintedTop;
148 m_tileLoader->cleanupTilehash();
151 void EquirectScanlineTextureMapper::RenderJob::run()
155 const int imageHeight = m_canvasImage->height();
156 const int imageWidth = m_canvasImage->width();
157 const qint64 radius = m_viewport->radius();
159 const qreal rad2Pixel = (qreal)( 2 * radius ) / M_PI;
160 const float pixel2Rad = 1.0/rad2Pixel;
162 const bool interlaced = ( m_mapQuality ==
LowQuality );
163 const bool highQuality = ( m_mapQuality ==
HighQuality
165 const bool printQuality = ( m_mapQuality ==
PrintQuality );
168 const int n = ScanlineTextureMapperContext::interpolationStep( m_viewport, m_mapQuality );
171 const qreal centerLon = m_viewport->centerLongitude();
172 const qreal centerLat = m_viewport->centerLatitude();
174 const int yCenterOffset = (int)( centerLat * rad2Pixel );
176 const int yTop = imageHeight / 2 - radius + yCenterOffset;
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 = M_PI/2 - (y - yTop )* pixel2Rad;
199 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 );