• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdeedu API Reference
  • KDE Home
  • Contact Us
 

marble

  • kde-4.x
  • kdeedu
  • marble
  • src
  • lib
  • marble
SphericalScanlineTextureMapper.cpp
Go to the documentation of this file.
1 //
2 // This file is part of the Marble Virtual Globe.
3 //
4 // This program is free software licensed under the GNU LGPL. You can
5 // find a copy of this license in LICENSE.txt in the top directory of
6 // the source code.
7 //
8 // Copyright 2007 Torsten Rahn <[email protected]>
9 // Copyright 2011 Bernhard Beschow <[email protected]>
10 //
11 
12 
13 #include "SphericalScanlineTextureMapper.h"
14 
15 #include <cmath>
16 
17 #include <qmath.h>
18 #include <QRunnable>
19 
20 #include "MarbleGlobal.h"
21 #include "GeoPainter.h"
22 #include "GeoDataPolygon.h"
23 #include "MarbleDebug.h"
24 #include "Quaternion.h"
25 #include "ScanlineTextureMapperContext.h"
26 #include "StackedTileLoader.h"
27 #include "StackedTile.h"
28 #include "TextureColorizer.h"
29 #include "ViewportParams.h"
30 #include "MathHelper.h"
31 
32 
33 using namespace Marble;
34 
35 class SphericalScanlineTextureMapper::RenderJob : public QRunnable
36 {
37 public:
38  RenderJob( StackedTileLoader *tileLoader, int tileLevel, QImage *canvasImage, const ViewportParams *viewport, MapQuality mapQuality, int yTop, int yBottom );
39 
40  void run() override;
41 
42 private:
43  StackedTileLoader *const m_tileLoader;
44  const int m_tileLevel;
45  QImage *const m_canvasImage;
46  const ViewportParams *const m_viewport;
47  const MapQuality m_mapQuality;
48  int const m_yTop;
49  int const m_yBottom;
50 };
51 
52 SphericalScanlineTextureMapper::RenderJob::RenderJob( StackedTileLoader *tileLoader, int tileLevel, QImage *canvasImage, const ViewportParams *viewport, MapQuality mapQuality, int yTop, int yBottom )
53  : m_tileLoader( tileLoader ),
54  m_tileLevel( tileLevel ),
55  m_canvasImage( canvasImage ),
56  m_viewport( viewport ),
57  m_mapQuality( mapQuality ),
58  m_yTop( yTop ),
59  m_yBottom( yBottom )
60 {
61 }
62 
63 SphericalScanlineTextureMapper::SphericalScanlineTextureMapper( StackedTileLoader *tileLoader )
64  : TextureMapperInterface()
65  , m_tileLoader( tileLoader )
66  , m_radius( 0 )
67  , m_threadPool()
68 {
69 }
70 
71 void SphericalScanlineTextureMapper::mapTexture( GeoPainter *painter,
72  const ViewportParams *viewport,
73  int tileZoomLevel,
74  const QRect &dirtyRect,
75  TextureColorizer *texColorizer )
76 {
77  if ( m_canvasImage.size() != viewport->size() || m_radius != viewport->radius() ) {
78  const QImage::Format optimalFormat = ScanlineTextureMapperContext::optimalCanvasImageFormat( viewport );
79 
80  if ( m_canvasImage.size() != viewport->size() || m_canvasImage.format() != optimalFormat ) {
81  m_canvasImage = QImage( viewport->size(), optimalFormat );
82  }
83 
84  if ( !viewport->mapCoversViewport() ) {
85  m_canvasImage.fill( 0 );
86  }
87 
88  m_radius = viewport->radius();
89  m_repaintNeeded = true;
90  }
91 
92  if ( m_repaintNeeded ) {
93  mapTexture( viewport, tileZoomLevel, painter->mapQuality() );
94 
95  if ( texColorizer ) {
96  texColorizer->colorize( &m_canvasImage, viewport, painter->mapQuality() );
97  }
98 
99  m_repaintNeeded = false;
100  }
101 
102  const int radius = viewport->radius();
103 
104  QRect rect( viewport->width() / 2 - radius, viewport->height() / 2 - radius,
105  2 * radius, 2 * radius);
106  rect = rect.intersected( dirtyRect );
107  painter->drawImage( rect, m_canvasImage, rect );
108 }
109 
110 void SphericalScanlineTextureMapper::mapTexture( const ViewportParams *viewport, int tileZoomLevel, MapQuality mapQuality )
111 {
112  // Reset backend
113  m_tileLoader->resetTilehash();
114 
115  // Initialize needed constants:
116 
117  const int imageHeight = m_canvasImage.height();
118  const qint64 radius = viewport->radius();
119 
120  // Calculate the actual y-range of the map on the screen
121  const int skip = ( mapQuality == LowQuality ) ? 1
122  : 0;
123  const int yTop = ( imageHeight / 2 - radius >= 0 ) ? imageHeight / 2 - radius
124  : 0;
125  const int yBottom = ( yTop == 0 ) ? imageHeight - skip
126  : yTop + radius + radius - skip;
127 
128  const int numThreads = m_threadPool.maxThreadCount();
129  const int yStep = qCeil(qreal( yBottom - yTop ) / qreal(numThreads));
130  for ( int i = 0; i < numThreads; ++i ) {
131  const int yStart = yTop + i * yStep;
132  const int yEnd = qMin(yBottom, yTop + (i + 1) * yStep);
133  QRunnable *const job = new RenderJob( m_tileLoader, tileZoomLevel, &m_canvasImage, viewport, mapQuality, yStart, yEnd );
134  m_threadPool.start( job );
135  }
136 
137  m_threadPool.waitForDone();
138 
139  m_tileLoader->cleanupTilehash();
140 }
141 
142 void SphericalScanlineTextureMapper::RenderJob::run()
143 {
144  const int imageHeight = m_canvasImage->height();
145  const int imageWidth = m_canvasImage->width();
146  const qint64 radius = m_viewport->radius();
147  const qreal inverseRadius = 1.0 / (qreal)(radius);
148 
149  const bool interlaced = ( m_mapQuality == LowQuality );
150  const bool highQuality = ( m_mapQuality == HighQuality
151  || m_mapQuality == PrintQuality );
152  const bool printQuality = ( m_mapQuality == PrintQuality );
153 
154  // Evaluate the degree of interpolation
155  const int n = ScanlineTextureMapperContext::interpolationStep( m_viewport, m_mapQuality );
156 
157  // Calculate north pole position to decrease pole distortion later on
158  Quaternion northPole = Quaternion::fromSpherical( 0.0, M_PI * 0.5 );
159  northPole.rotateAroundAxis( m_viewport->planetAxis().inverse() );
160  const int northPoleX = imageWidth / 2 + (int)( radius * northPole.v[Q_X] );
161  const int northPoleY = imageHeight / 2 - (int)( radius * northPole.v[Q_Y] );
162 
163  // Calculate axis matrix to represent the planet's rotation.
164  matrix planetAxisMatrix;
165  m_viewport->planetAxis().toMatrix( planetAxisMatrix );
166 
167  // initialize needed variables that are modified during texture mapping:
168 
169  ScanlineTextureMapperContext context( m_tileLoader, m_tileLevel );
170  qreal lon = 0.0;
171  qreal lat = 0.0;
172 
173  // Scanline based algorithm to texture map a sphere
174  for ( int y = m_yTop; y < m_yBottom ; ++y ) {
175 
176  // Evaluate coordinates for the 3D position vector of the current pixel
177  const qreal qy = inverseRadius * (qreal)( imageHeight / 2 - y );
178  const qreal qr = 1.0 - qy * qy;
179 
180  // rx is the radius component in x direction
181  const int rx = (int)sqrt( (qreal)( radius * radius
182  - ( ( y - imageHeight / 2 )
183  * ( y - imageHeight / 2 ) ) ) );
184 
185  // Calculate the actual x-range of the map within the current scanline.
186  //
187  // If the circular border of the earth disk is still visible then xLeft
188  // equals the scanline position of the most left pixel that gets covered
189  // by the earth disk. In terms of math this equals the half image width minus
190  // the radius component on the current scanline in x direction ("rx").
191  //
192  // If the zoom factor is high enough then the whole screen gets covered
193  // by the earth and the border of the earth disk isn't visible anymore.
194  // In that situation xLeft equals zero.
195  // For xRight the situation is similar.
196 
197  const int xLeft = ( imageWidth / 2 - rx > 0 ) ? imageWidth / 2 - rx
198  : 0;
199  const int xRight = ( imageWidth / 2 - rx > 0 ) ? xLeft + rx + rx
200  : imageWidth;
201 
202  QRgb * scanLine = (QRgb*)( m_canvasImage->scanLine( y ) ) + xLeft;
203 
204  const int xIpLeft = ( imageWidth / 2 - rx > 0 ) ? n * (int)( xLeft / n + 1 )
205  : 1;
206  const int xIpRight = ( imageWidth / 2 - rx > 0 ) ? n * (int)( xRight / n - 1 )
207  : n * (int)( xRight / n - 1 ) + 1;
208 
209  // Decrease pole distortion due to linear approximation ( y-axis )
210  bool crossingPoleArea = false;
211  if ( northPole.v[Q_Z] > 0
212  && northPoleY - ( n * 0.75 ) <= y
213  && northPoleY + ( n * 0.75 ) >= y )
214  {
215  crossingPoleArea = true;
216  }
217 
218  int ncount = 0;
219 
220  for ( int x = xLeft; x < xRight; ++x ) {
221  // Prepare for interpolation
222 
223  const int leftInterval = xIpLeft + ncount * n;
224 
225  bool interpolate = false;
226  if ( x >= xIpLeft && x <= xIpRight ) {
227 
228  // Decrease pole distortion due to linear approximation ( x-axis )
229 // mDebug() << QString("NorthPole X: %1, LeftInterval: %2").arg( northPoleX ).arg( leftInterval );
230  if ( crossingPoleArea
231  && northPoleX >= leftInterval + n
232  && northPoleX < leftInterval + 2 * n
233  && x < leftInterval + 3 * n )
234  {
235  interpolate = false;
236  }
237  else {
238  x += n - 1;
239  interpolate = !printQuality;
240  ++ncount;
241  }
242  }
243  else
244  interpolate = false;
245 
246  // Evaluate more coordinates for the 3D position vector of
247  // the current pixel.
248  const qreal qx = (qreal)( x - imageWidth / 2 ) * inverseRadius;
249  const qreal qr2z = qr - qx * qx;
250  const qreal qz = ( qr2z > 0.0 ) ? sqrt( qr2z ) : 0.0;
251 
252  // Create Quaternion from vector coordinates and rotate it
253  // around globe axis
254  Quaternion qpos( 0.0, qx, qy, qz );
255  qpos.rotateAroundAxis( planetAxisMatrix );
256 
257  qpos.getSpherical( lon, lat );
258 // mDebug() << QString("lon: %1 lat: %2").arg(lon).arg(lat);
259  // Approx for n-1 out of n pixels within the boundary of
260  // xIpLeft to xIpRight
261 
262  if ( interpolate ) {
263  if (highQuality)
264  context.pixelValueApproxF( lon, lat, scanLine, n );
265  else
266  context.pixelValueApprox( lon, lat, scanLine, n );
267 
268  scanLine += ( n - 1 );
269  }
270 
271 // Comment out the pixelValue line and run Marble if you want
272 // to understand the interpolation:
273 
274 // Uncomment the crossingPoleArea line to check precise
275 // rendering around north pole:
276 
277 // if ( !crossingPoleArea )
278  if ( x < imageWidth ) {
279  if ( highQuality )
280  context.pixelValueF( lon, lat, scanLine );
281  else
282  context.pixelValue( lon, lat, scanLine );
283  }
284 
285  ++scanLine;
286  }
287 
288  // copy scanline to improve performance
289  if ( interlaced && y + 1 < m_yBottom ) {
290 
291  const int pixelByteSize = m_canvasImage->bytesPerLine() / imageWidth;
292 
293  memcpy( m_canvasImage->scanLine( y + 1 ) + xLeft * pixelByteSize,
294  m_canvasImage->scanLine( y ) + xLeft * pixelByteSize,
295  ( xRight - xLeft ) * pixelByteSize );
296  ++y;
297  }
298  }
299 }
Quaternion.h
interpolate
void interpolate(MarbleWidget *widget, qreal value)
Definition: examples/cpp/animation-video/main.cpp:68
Marble::matrix
xmmfloat matrix[3]
Definition: Quaternion.h:39
Marble::ViewportParams::size
QSize size() const
Definition: ViewportParams.cpp:315
GeoDataPolygon.h
Marble::GeoPainter
A painter that allows to draw geometric primitives on the map.
Definition: GeoPainter.h:93
Marble::TextureColorizer::colorize
void colorize(QImage *origimg, const ViewportParams *viewport, MapQuality mapQuality)
Definition: TextureColorizer.cpp:221
Marble::PrintQuality
Print quality.
Definition: MarbleGlobal.h:83
Marble::MapQuality
MapQuality
This enum is used to choose the map quality shown in the view.
Definition: MarbleGlobal.h:78
ScanlineTextureMapperContext.h
MarbleDebug.h
TextureColorizer.h
Marble::StackedTileLoader
Tile loading from a quad tree.
Definition: StackedTileLoader.h:59
QRunnable
Marble::ViewportParams::height
int height() const
Definition: ViewportParams.cpp:310
Marble::Quaternion::rotateAroundAxis
void rotateAroundAxis(const Quaternion &q)
Definition: Quaternion.cpp:191
Marble::LowQuality
Low resolution (e.g. interlaced)
Definition: MarbleGlobal.h:80
QRect
Marble::ViewportParams::width
int width() const
Definition: ViewportParams.cpp:305
QThreadPool::maxThreadCount
maxThreadCount
QImage::fill
void fill(uint pixelValue)
Marble::TextureMapperInterface
Definition: TextureMapperInterface.h:25
SphericalScanlineTextureMapper.h
MathHelper.h
Marble::ViewportParams::mapCoversViewport
bool mapCoversViewport() const
Definition: ViewportParams.cpp:446
Marble::Q_Z
Definition: Quaternion.h:33
Marble::ScanlineTextureMapperContext::optimalCanvasImageFormat
static QImage::Format optimalCanvasImageFormat(const ViewportParams *viewport)
Definition: ScanlineTextureMapperContext.cpp:419
Marble::radius
static qreal radius(qreal zoom)
Definition: thumbnailer.cpp:96
Marble::StackedTileLoader::cleanupTilehash
void cleanupTilehash()
Cleans up the internal tile hash.
Definition: StackedTileLoader.cpp:100
QtConcurrent::run
QFuture< T > run(Function function,...)
GeoPainter.h
MarbleGlobal.h
QRect::intersected
QRect intersected(const QRect &rectangle) const
Marble::ViewportParams
A public class that controls what is visible in the viewport of a Marble map.
Definition: ViewportParams.h:46
Marble::GeoPainter::drawImage
void drawImage(const GeoDataCoordinates &centerPosition, const QImage &image)
Draws an image at the given position. The image is placed with its center located at the given center...
Definition: GeoPainter.cpp:472
Marble::TextureColorizer
Definition: TextureColorizer.h:32
M_PI
#define M_PI
Definition: sgp4unit.h:52
ViewportParams.h
This file contains the headers for ViewportParams.
QImage
QThreadPool::waitForDone
void waitForDone()
Marble::SphericalScanlineTextureMapper::SphericalScanlineTextureMapper
SphericalScanlineTextureMapper(StackedTileLoader *tileLoader)
Definition: SphericalScanlineTextureMapper.cpp:63
Marble::TextureMapperInterface::m_repaintNeeded
bool m_repaintNeeded
Definition: TextureMapperInterface.h:40
Marble::ViewportParams::radius
int radius() const
Definition: ViewportParams.cpp:222
Marble::HighQuality
High quality (e.g. antialiasing for lines)
Definition: MarbleGlobal.h:82
Marble::ScanlineTextureMapperContext::interpolationStep
static int interpolationStep(const ViewportParams *viewport, MapQuality mapQuality)
Definition: ScanlineTextureMapperContext.cpp:391
StackedTile.h
Marble::Quaternion
Definition: Quaternion.h:42
QImage::size
QSize size() const
Marble::Quaternion::v
xmmfloat v
Definition: Quaternion.h:88
Marble::ScanlineTextureMapperContext
Definition: ScanlineTextureMapperContext.h:30
QImage::height
int height() const
Marble::GeoPainter::mapQuality
MapQuality mapQuality() const
Returns the map quality.
Definition: GeoPainter.cpp:217
Marble::SphericalScanlineTextureMapper::mapTexture
void mapTexture(GeoPainter *painter, const ViewportParams *viewport, int tileZoomLevel, const QRect &dirtyRect, TextureColorizer *texColorizer) override
Definition: SphericalScanlineTextureMapper.cpp:71
QThreadPool::start
void start(QRunnable *runnable, int priority)
Marble::Q_X
Definition: Quaternion.h:31
Marble::Q_Y
Definition: Quaternion.h:32
QImage::format
Format format() const
Marble::StackedTileLoader::resetTilehash
void resetTilehash()
Resets the internal tile hash.
Definition: StackedTileLoader.cpp:90
Marble::Quaternion::fromSpherical
static Quaternion fromSpherical(qreal lon, qreal lat)
used to generate Quaternion from longitude and latitude
Definition: Quaternion.cpp:38
StackedTileLoader.h
This file is part of the KDE documentation.
Documentation copyright © 1996-2019 The KDE developers.
Generated on Sat Dec 7 2019 02:41:22 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

marble

Skip menu "marble"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdeedu API Reference

Skip menu "kdeedu API Reference"
  • Analitza
  •     lib
  • kalgebra
  • kalzium
  •   libscience
  • kanagram
  • kig
  •   lib
  • klettres
  •   KmPlot
  • libkeduvocdocument
  •   keduvocdocument
  • marble
  • parley
  • rocs
  •   src
  •   stepcore

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal