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

marble

  • sources
  • kde-4.12
  • 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 <tackat@kde.org>
9 // Copyright 2011 Bernhard Beschow <bbeschow@cs.tu-berlin.de>
10 //
11 
12 
13 #include "SphericalScanlineTextureMapper.h"
14 
15 #include <cmath>
16 
17 #include <QRunnable>
18 
19 #include "MarbleGlobal.h"
20 #include "GeoPainter.h"
21 #include "GeoDataPolygon.h"
22 #include "GeoDataDocument.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  virtual void run();
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 #if QT_VERSION < 0x050000
107  rect = rect.intersect( dirtyRect );
108 #else
109  rect = rect.intersected( dirtyRect );
110 #endif
111  painter->drawImage( rect, m_canvasImage, rect );
112 }
113 
114 void SphericalScanlineTextureMapper::mapTexture( const ViewportParams *viewport, int tileZoomLevel, MapQuality mapQuality )
115 {
116  // Reset backend
117  m_tileLoader->resetTilehash();
118 
119  // Initialize needed constants:
120 
121  const int imageHeight = m_canvasImage.height();
122  const qint64 radius = viewport->radius();
123 
124  // Calculate the actual y-range of the map on the screen
125  const int skip = ( mapQuality == LowQuality ) ? 1
126  : 0;
127  const int yTop = ( imageHeight / 2 - radius >= 0 ) ? imageHeight / 2 - radius
128  : 0;
129  const int yBottom = ( yTop == 0 ) ? imageHeight - skip
130  : yTop + radius + radius - skip;
131 
132  const int numThreads = m_threadPool.maxThreadCount();
133  const int yStep = ( yBottom - yTop ) / numThreads;
134  for ( int i = 0; i < numThreads; ++i ) {
135  const int yStart = yTop + i * yStep;
136  const int yEnd = yTop + (i + 1) * yStep;
137  QRunnable *const job = new RenderJob( m_tileLoader, tileZoomLevel, &m_canvasImage, viewport, mapQuality, yStart, yEnd );
138  m_threadPool.start( job );
139  }
140 
141  m_threadPool.waitForDone();
142 
143  m_tileLoader->cleanupTilehash();
144 }
145 
146 void SphericalScanlineTextureMapper::RenderJob::run()
147 {
148  const int imageHeight = m_canvasImage->height();
149  const int imageWidth = m_canvasImage->width();
150  const qint64 radius = m_viewport->radius();
151  const qreal inverseRadius = 1.0 / (qreal)(radius);
152 
153  const bool interlaced = ( m_mapQuality == LowQuality );
154  const bool highQuality = ( m_mapQuality == HighQuality
155  || m_mapQuality == PrintQuality );
156  const bool printQuality = ( m_mapQuality == PrintQuality );
157 
158  // Evaluate the degree of interpolation
159  const int n = ScanlineTextureMapperContext::interpolationStep( m_viewport, m_mapQuality );
160 
161  // Calculate north pole position to decrease pole distortion later on
162  Quaternion northPole = Quaternion::fromSpherical( 0.0, M_PI * 0.5 );
163  northPole.rotateAroundAxis( m_viewport->planetAxis().inverse() );
164  const int northPoleX = imageWidth / 2 + (int)( radius * northPole.v[Q_X] );
165  const int northPoleY = imageHeight / 2 - (int)( radius * northPole.v[Q_Y] );
166 
167  // Calculate axis matrix to represent the planet's rotation.
168  matrix planetAxisMatrix;
169  m_viewport->planetAxis().toMatrix( planetAxisMatrix );
170 
171  // initialize needed variables that are modified during texture mapping:
172 
173  ScanlineTextureMapperContext context( m_tileLoader, m_tileLevel );
174  qreal lon = 0.0;
175  qreal lat = 0.0;
176 
177  // Scanline based algorithm to texture map a sphere
178  for ( int y = m_yTop; y < m_yBottom ; ++y ) {
179 
180  // Evaluate coordinates for the 3D position vector of the current pixel
181  const qreal qy = inverseRadius * (qreal)( imageHeight / 2 - y );
182  const qreal qr = 1.0 - qy * qy;
183 
184  // rx is the radius component in x direction
185  const int rx = (int)sqrt( (qreal)( radius * radius
186  - ( ( y - imageHeight / 2 )
187  * ( y - imageHeight / 2 ) ) ) );
188 
189  // Calculate the actual x-range of the map within the current scanline.
190  //
191  // If the circular border of the earth disk is still visible then xLeft
192  // equals the scanline position of the most left pixel that gets covered
193  // by the earth disk. In terms of math this equals the half image width minus
194  // the radius component on the current scanline in x direction ("rx").
195  //
196  // If the zoom factor is high enough then the whole screen gets covered
197  // by the earth and the border of the earth disk isn't visible anymore.
198  // In that situation xLeft equals zero.
199  // For xRight the situation is similar.
200 
201  const int xLeft = ( imageWidth / 2 - rx > 0 ) ? imageWidth / 2 - rx
202  : 0;
203  const int xRight = ( imageWidth / 2 - rx > 0 ) ? xLeft + rx + rx
204  : imageWidth;
205 
206  QRgb * scanLine = (QRgb*)( m_canvasImage->scanLine( y ) ) + xLeft;
207 
208  const int xIpLeft = ( imageWidth / 2 - rx > 0 ) ? n * (int)( xLeft / n + 1 )
209  : 1;
210  const int xIpRight = ( imageWidth / 2 - rx > 0 ) ? n * (int)( xRight / n - 1 )
211  : n * (int)( xRight / n - 1 ) + 1;
212 
213  // Decrease pole distortion due to linear approximation ( y-axis )
214  bool crossingPoleArea = false;
215  if ( northPole.v[Q_Z] > 0
216  && northPoleY - ( n * 0.75 ) <= y
217  && northPoleY + ( n * 0.75 ) >= y )
218  {
219  crossingPoleArea = true;
220  }
221 
222  int ncount = 0;
223 
224  for ( int x = xLeft; x < xRight; ++x ) {
225  // Prepare for interpolation
226 
227  const int leftInterval = xIpLeft + ncount * n;
228 
229  bool interpolate = false;
230  if ( x >= xIpLeft && x <= xIpRight ) {
231 
232  // Decrease pole distortion due to linear approximation ( x-axis )
233 // mDebug() << QString("NorthPole X: %1, LeftInterval: %2").arg( northPoleX ).arg( leftInterval );
234  if ( crossingPoleArea
235  && northPoleX >= leftInterval + n
236  && northPoleX < leftInterval + 2 * n
237  && x < leftInterval + 3 * n )
238  {
239  interpolate = false;
240  }
241  else {
242  x += n - 1;
243  interpolate = !printQuality;
244  ++ncount;
245  }
246  }
247  else
248  interpolate = false;
249 
250  // Evaluate more coordinates for the 3D position vector of
251  // the current pixel.
252  const qreal qx = (qreal)( x - imageWidth / 2 ) * inverseRadius;
253  const qreal qr2z = qr - qx * qx;
254  const qreal qz = ( qr2z > 0.0 ) ? sqrt( qr2z ) : 0.0;
255 
256  // Create Quaternion from vector coordinates and rotate it
257  // around globe axis
258  Quaternion qpos( 0.0, qx, qy, qz );
259  qpos.rotateAroundAxis( planetAxisMatrix );
260 
261  qpos.getSpherical( lon, lat );
262 // mDebug() << QString("lon: %1 lat: %2").arg(lon).arg(lat);
263  // Approx for n-1 out of n pixels within the boundary of
264  // xIpLeft to xIpRight
265 
266  if ( interpolate ) {
267  if (highQuality)
268  context.pixelValueApproxF( lon, lat, scanLine, n );
269  else
270  context.pixelValueApprox( lon, lat, scanLine, n );
271 
272  scanLine += ( n - 1 );
273  }
274 
275 // Comment out the pixelValue line and run Marble if you want
276 // to understand the interpolation:
277 
278 // Uncomment the crossingPoleArea line to check precise
279 // rendering around north pole:
280 
281 // if ( !crossingPoleArea )
282  if ( x < imageWidth ) {
283  if ( highQuality )
284  context.pixelValueF( lon, lat, scanLine );
285  else
286  context.pixelValue( lon, lat, scanLine );
287  }
288 
289  ++scanLine;
290  }
291 
292  // copy scanline to improve performance
293  if ( interlaced && y + 1 < m_yBottom ) {
294 
295  const int pixelByteSize = m_canvasImage->bytesPerLine() / imageWidth;
296 
297  memcpy( m_canvasImage->scanLine( y + 1 ) + xLeft * pixelByteSize,
298  m_canvasImage->scanLine( y ) + xLeft * pixelByteSize,
299  ( xRight - xLeft ) * pixelByteSize );
300  ++y;
301  }
302  }
303 }
GeoDataDocument.h
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:40
Marble::ViewportParams::size
QSize size() const
Definition: ViewportParams.cpp:260
GeoDataPolygon.h
Marble::GeoPainter
A painter that allows to draw geometric primitives on the map.
Definition: GeoPainter.h:98
Marble::TextureColorizer::colorize
void colorize(QImage *origimg, const ViewportParams *viewport, MapQuality mapQuality)
Definition: TextureColorizer.cpp:230
Marble::PrintQuality
Print quality.
Definition: MarbleGlobal.h:85
Marble::MapQuality
MapQuality
This enum is used to choose the map quality shown in the view.
Definition: MarbleGlobal.h:80
ScanlineTextureMapperContext.h
MarbleDebug.h
TextureColorizer.h
Marble::StackedTileLoader
Tile loading from a quad tree.
Definition: StackedTileLoader.h:59
Marble::ViewportParams::height
int height() const
Definition: ViewportParams.cpp:255
Marble::Quaternion::rotateAroundAxis
void rotateAroundAxis(const Quaternion &q)
Definition: Quaternion.cpp:167
Marble::LowQuality
Low resolution (e.g. interlaced)
Definition: MarbleGlobal.h:82
Marble::ViewportParams::width
int width() const
Definition: ViewportParams.cpp:250
Marble::TextureMapperInterface
Definition: TextureMapperInterface.h:27
SphericalScanlineTextureMapper.h
MathHelper.h
Marble::ViewportParams::mapCoversViewport
bool mapCoversViewport() const
Definition: ViewportParams.cpp:398
Marble::ScanlineTextureMapperContext::optimalCanvasImageFormat
static QImage::Format optimalCanvasImageFormat(const ViewportParams *viewport)
Definition: ScanlineTextureMapperContext.cpp:429
Marble::StackedTileLoader::cleanupTilehash
void cleanupTilehash()
Cleans up the internal tile hash.
Definition: StackedTileLoader.cpp:101
Marble::Q_Z
Definition: Quaternion.h:34
GeoPainter.h
MarbleGlobal.h
Marble::ViewportParams
A public class that controls what is visible in the viewport of a Marble map.
Definition: ViewportParams.h:44
Marble::Q_Y
Definition: Quaternion.h:33
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:428
Marble::TextureColorizer
Definition: TextureColorizer.h:34
Marble::Q_X
Definition: Quaternion.h:32
ViewportParams.h
This file contains the headers for ViewportParams.
Marble::SphericalScanlineTextureMapper::SphericalScanlineTextureMapper
SphericalScanlineTextureMapper(StackedTileLoader *tileLoader)
Definition: SphericalScanlineTextureMapper.cpp:63
Marble::TextureMapperInterface::m_repaintNeeded
bool m_repaintNeeded
Definition: TextureMapperInterface.h:42
Marble::ViewportParams::radius
int radius() const
Definition: ViewportParams.cpp:195
Marble::HighQuality
High quality (e.g. antialiasing for lines)
Definition: MarbleGlobal.h:84
Marble::ScanlineTextureMapperContext::interpolationStep
static int interpolationStep(const ViewportParams *viewport, MapQuality mapQuality)
Definition: ScanlineTextureMapperContext.cpp:401
StackedTile.h
Marble::Quaternion
Definition: Quaternion.h:43
M_PI
#define M_PI
Definition: GeoDataCoordinates.h:26
Marble::Quaternion::v
xmmfloat v
Definition: Quaternion.h:86
Marble::ScanlineTextureMapperContext
Definition: ScanlineTextureMapperContext.h:30
Marble::GeoPainter::mapQuality
MapQuality mapQuality() const
Returns the map quality.
Definition: GeoPainter.cpp:191
Marble::SphericalScanlineTextureMapper::mapTexture
virtual void mapTexture(GeoPainter *painter, const ViewportParams *viewport, int tileZoomLevel, const QRect &dirtyRect, TextureColorizer *texColorizer)
Definition: SphericalScanlineTextureMapper.cpp:71
Marble::StackedTileLoader::resetTilehash
void resetTilehash()
Resets the internal tile hash.
Definition: StackedTileLoader.cpp:91
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-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:38:53 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
  • kstars
  • libkdeedu
  •   keduvocdocument
  • marble
  • parley
  • rocs
  •   App
  •   RocsCore
  •   VisualEditor
  •   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