• 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
  • projections
SphericalProjection.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 Inge Wallin <ingwa@kde.org>
9 // Copyright 2007-2012 Torsten Rahn <rahn@kde.org>
10 // Copyright 2012 Cezar Mocan <mocancezar@gmail.com>
11 //
12 
13 // Local
14 #include "SphericalProjection.h"
15 #include "SphericalProjection_p.h"
16 
17 #include "MarbleDebug.h"
18 
19 // Marble
20 #include "ViewportParams.h"
21 #include "GeoDataPoint.h"
22 #include "GeoDataLineString.h"
23 #include "GeoDataCoordinates.h"
24 #include "MarbleGlobal.h"
25 
26 #define SAFE_DISTANCE
27 
28 // Maximum amount of nodes that are created automatically between actual nodes.
29 static const int maxTessellationNodes = 200;
30 
31 namespace Marble
32 {
33 
34 
35 SphericalProjection::SphericalProjection()
36  : AbstractProjection( new SphericalProjectionPrivate( this ) )
37 {
38  setMinLat( minValidLat() );
39  setMaxLat( maxValidLat() );
40 }
41 
42 SphericalProjection::SphericalProjection( SphericalProjectionPrivate *dd )
43  : AbstractProjection( dd )
44 {
45  setMinLat( minValidLat() );
46  setMaxLat( maxValidLat() );
47 }
48 
49 SphericalProjection::~SphericalProjection()
50 {
51 }
52 
53 
54 SphericalProjectionPrivate::SphericalProjectionPrivate( SphericalProjection * parent )
55  : AbstractProjectionPrivate( parent )
56 {
57 
58 }
59 
60 
61 bool SphericalProjection::repeatableX() const
62 {
63  return false;
64 }
65 
66 qreal SphericalProjection::maxValidLat() const
67 {
68  return +90.0 * DEG2RAD;
69 }
70 
71 qreal SphericalProjection::minValidLat() const
72 {
73  return -90.0 * DEG2RAD;
74 }
75 
76 bool SphericalProjection::screenCoordinates( const GeoDataCoordinates &coordinates,
77  const ViewportParams *viewport,
78  qreal &x, qreal &y, bool &globeHidesPoint ) const
79 {
80  qreal absoluteAltitude = coordinates.altitude() + EARTH_RADIUS;
81  Quaternion qpos = coordinates.quaternion();
82 
83  qpos.rotateAroundAxis( viewport->planetAxisMatrix() );
84 
85  qreal pixelAltitude = ( ( viewport->radius() )
86  / EARTH_RADIUS * absoluteAltitude );
87  if ( coordinates.altitude() < 10000 ) {
88  // Skip placemarks at the other side of the earth.
89  if ( qpos.v[Q_Z] < 0 ) {
90  globeHidesPoint = true;
91  return false;
92  }
93  }
94  else {
95  qreal earthCenteredX = pixelAltitude * qpos.v[Q_X];
96  qreal earthCenteredY = pixelAltitude * qpos.v[Q_Y];
97  qreal radius = viewport->radius();
98 
99  // Don't draw high placemarks (e.g. satellites) that aren't visible.
100  if ( qpos.v[Q_Z] < 0
101  && ( ( earthCenteredX * earthCenteredX
102  + earthCenteredY * earthCenteredY )
103  < radius * radius ) ) {
104  globeHidesPoint = true;
105  return false;
106  }
107  }
108 
109  // Let (x, y) be the position on the screen of the placemark..
110  x = ((qreal)(viewport->width()) / 2 + pixelAltitude * qpos.v[Q_X]);
111  y = ((qreal)(viewport->height()) / 2 - pixelAltitude * qpos.v[Q_Y]);
112 
113  // Skip placemarks that are outside the screen area
114  if ( x < 0 || x >= viewport->width() || y < 0 || y >= viewport->height() ) {
115  globeHidesPoint = false;
116  return false;
117  }
118 
119  globeHidesPoint = false;
120  return true;
121 }
122 
123 bool SphericalProjection::screenCoordinates( const GeoDataCoordinates &coordinates,
124  const ViewportParams *viewport,
125  qreal *x, qreal &y,
126  int &pointRepeatNum,
127  const QSizeF& size,
128  bool &globeHidesPoint ) const
129 {
130  pointRepeatNum = 0;
131  bool visible = screenCoordinates( coordinates, viewport, *x, y, globeHidesPoint );
132 
133  // Skip placemarks that are outside the screen area
134  if ( *x + size.width() / 2.0 < 0.0 || *x >= viewport->width() + size.width() / 2.0
135  || y + size.height() / 2.0 < 0.0 || y >= viewport->height() + size.height() / 2.0 )
136  {
137  globeHidesPoint = false;
138  return false;
139  }
140 
141  // This projection doesn't have any repetitions,
142  // so the number of screen points referring to the geopoint is one.
143  pointRepeatNum = 1;
144  return visible;
145 }
146 
147 
148 bool SphericalProjection::geoCoordinates( const int x, const int y,
149  const ViewportParams *viewport,
150  qreal& lon, qreal& lat,
151  GeoDataCoordinates::Unit unit ) const
152 {
153  const qreal inverseRadius = 1.0 / (qreal)(viewport->radius());
154 
155  const qreal qx = +(qreal)( x - viewport->width() / 2 ) * inverseRadius;
156  const qreal qy = -(qreal)( y - viewport->height() / 2 ) * inverseRadius;
157 
158  if ( 1 <= qx * qx + qy * qy ) {
159  return false;
160  }
161 
162  const qreal qz = sqrt( 1 - qx * qx - qy * qy );
163 
164  Quaternion qpos( 0.0, qx, qy, qz );
165  qpos.rotateAroundAxis( viewport->planetAxis() );
166  qpos.getSpherical( lon, lat );
167 
168  if ( unit == GeoDataCoordinates::Degree ) {
169  lon *= RAD2DEG;
170  lat *= RAD2DEG;
171  }
172 
173  return true;
174 }
175 
176 GeoDataLatLonAltBox SphericalProjection::latLonAltBox( const QRect& screenRect,
177  const ViewportParams *viewport ) const
178 {
179  // For the case where the whole viewport gets covered there is a
180  // pretty dirty and generic detection algorithm:
181  GeoDataLatLonAltBox latLonAltBox = AbstractProjection::latLonAltBox( screenRect, viewport );
182 
183  // If the whole globe is visible we can easily calculate
184  // analytically the lon-/lat- range.
185  qreal pitch = GeoDataCoordinates::normalizeLat( viewport->planetAxis().pitch() );
186 
187  if ( 2.0 * viewport->radius() <= viewport->height()
188  && 2.0 * viewport->radius() <= viewport->width() )
189  {
190  // Unless the planetaxis is in the screen plane the allowed longitude range
191  // covers full -180 deg to +180 deg:
192  if ( pitch > 0.0 && pitch < +M_PI ) {
193  latLonAltBox.setNorth( +fabs( M_PI / 2.0 - fabs( pitch ) ) );
194  latLonAltBox.setSouth( -M_PI / 2.0 );
195  }
196  if ( pitch < 0.0 && pitch > -M_PI ) {
197  latLonAltBox.setWest( -M_PI );
198  latLonAltBox.setEast( +M_PI );
199  latLonAltBox.setNorth( +M_PI / 2.0 );
200  latLonAltBox.setSouth( -fabs( M_PI / 2.0 - fabs( pitch ) ) );
201  }
202 
203  // Last but not least we deal with the rare case where the
204  // globe is fully visible and pitch = 0.0 or pitch = -M_PI or
205  // pitch = +M_PI
206  if ( pitch == 0.0 || pitch == -M_PI || pitch == +M_PI ) {
207  qreal yaw = viewport->planetAxis().yaw();
208  latLonAltBox.setWest( GeoDataCoordinates::normalizeLon( yaw - M_PI / 2.0 ) );
209  latLonAltBox.setEast( GeoDataCoordinates::normalizeLon( yaw + M_PI / 2.0 ) );
210  latLonAltBox.setNorth( +M_PI / 2.0 );
211  latLonAltBox.setSouth( -M_PI / 2.0 );
212  }
213  }
214 
215  // Now we check whether maxLat (e.g. the north pole) gets displayed
216  // inside the viewport to get more accurate values for east and west.
217 
218  // We need a point on the screen at maxLat that definitely gets displayed:
219  qreal averageLongitude = ( latLonAltBox.west() + latLonAltBox.east() ) / 2.0;
220 
221  GeoDataCoordinates maxLatPoint( averageLongitude, maxLat(), 0.0, GeoDataCoordinates::Radian );
222  GeoDataCoordinates minLatPoint( averageLongitude, minLat(), 0.0, GeoDataCoordinates::Radian );
223 
224  qreal dummyX, dummyY; // not needed
225  bool dummyVal;
226 
227  if ( screenCoordinates( maxLatPoint, viewport, dummyX, dummyY, dummyVal ) ||
228  screenCoordinates( minLatPoint, viewport, dummyX, dummyY, dummyVal ) ) {
229  latLonAltBox.setWest( -M_PI );
230  latLonAltBox.setEast( +M_PI );
231  }
232 
233  return latLonAltBox;
234 }
235 
236 
237 bool SphericalProjection::mapCoversViewport( const ViewportParams *viewport ) const
238 {
239  qint64 radius = viewport->radius();
240  qint64 width = viewport->width();
241  qint64 height = viewport->height();
242 
243  // This first test is a quick one that will catch all really big
244  // radii and prevent overflow in the real test.
245  if ( radius > width + height )
246  return true;
247 
248  // This is the real test. The 4 is because we are really
249  // comparing to width/2 and height/2.
250  if ( 4 * radius * radius >= width * width + height * height )
251  return true;
252 
253  return false;
254 }
255 
256 QPainterPath SphericalProjection::mapShape( const ViewportParams *viewport ) const
257 {
258  int radius = viewport->radius();
259  int imgWidth = viewport->width();
260  int imgHeight = viewport->height();
261 
262  QPainterPath fullRect;
263  fullRect.addRect( 0 , 0 , imgWidth, imgHeight );
264 
265  // If the globe covers the whole image, then the projected region represents
266  // all of the image.
267  // Otherwise the active region has got the shape of the visible globe.
268 
269  if ( !viewport->mapCoversViewport() ) {
270  QPainterPath mapShape;
271  mapShape.addEllipse(
272  imgWidth / 2 - radius,
273  imgHeight / 2 - radius,
274  2 * radius,
275  2 * radius );
276  return mapShape.intersected( fullRect );
277  }
278 
279  return fullRect;
280 }
281 
282 bool SphericalProjection::screenCoordinates( const GeoDataLineString &lineString,
283  const ViewportParams *viewport,
284  QVector<QPolygonF *> &polygons ) const
285 {
286 
287  Q_D( const SphericalProjection );
288  // Compare bounding box size of the line string with the angularResolution
289  // Immediately return if the latLonAltBox is smaller.
290  if ( !viewport->resolves( lineString.latLonAltBox() ) ) {
291 // mDebug() << "Object too small to be resolved";
292  return false;
293  }
294 
295  d->lineStringToPolygon( lineString, viewport, polygons );
296  return true;
297 }
298 
299 void SphericalProjectionPrivate::tessellateLineSegment( const GeoDataCoordinates &aCoords,
300  qreal ax, qreal ay,
301  const GeoDataCoordinates &bCoords,
302  qreal bx, qreal by,
303  QVector<QPolygonF*> &polygons,
304  const ViewportParams *viewport,
305  TessellationFlags f) const
306 {
307  // We take the manhattan length as a distance approximation
308  // that can be too big by a factor of sqrt(2)
309  qreal distance = fabs((bx - ax)) + fabs((by - ay));
310 #ifdef SAFE_DISTANCE
311  // Interpolate additional nodes if the line segment that connects the
312  // current or previous nodes might cross the viewport.
313  // The latter can pretty safely be excluded for most projections if both points
314  // are located on the same side relative to the viewport boundaries and if they are
315  // located more than half the line segment distance away from the viewport.
316  const qreal safeDistance = - 0.5 * distance;
317  if ( !( bx < safeDistance && ax < safeDistance )
318  || !( by < safeDistance && ay < safeDistance )
319  || !( bx + safeDistance > viewport->width()
320  && ax + safeDistance > viewport->width() )
321  || !( by + safeDistance > viewport->height()
322  && ay + safeDistance > viewport->height() )
323  )
324  {
325 #endif
326  bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen;
327  int const finalTessellationPrecision = smallScreen ? 3 * tessellationPrecision : tessellationPrecision;
328 
329  // Let the line segment follow the spherical surface
330  // if the distance between the previous point and the current point
331  // on screen is too big
332  if ( distance > finalTessellationPrecision ) {
333  const int tessellatedNodes = qMin<int>( distance / finalTessellationPrecision, maxTessellationNodes );
334 
335  processTessellation( aCoords, bCoords,
336  tessellatedNodes,
337  polygons,
338  viewport,
339  f );
340  }
341  else {
342  crossHorizon( bCoords, polygons, viewport );
343  }
344 #ifdef SAFE_DISTANCE
345  }
346 #endif
347 }
348 
349 
350 void SphericalProjectionPrivate::processTessellation( const GeoDataCoordinates &previousCoords,
351  const GeoDataCoordinates &currentCoords,
352  int tessellatedNodes,
353  QVector<QPolygonF*> &polygons,
354  const ViewportParams *viewport,
355  TessellationFlags f) const
356 {
357 
358  const bool clampToGround = f.testFlag( FollowGround );
359  const bool followLatitudeCircle = f.testFlag( RespectLatitudeCircle )
360  && previousCoords.latitude() == currentCoords.latitude();
361 
362  // Calculate steps for tessellation: lonDiff and altDiff
363  qreal lonDiff = 0.0;
364  if ( followLatitudeCircle ) {
365  const int previousSign = previousCoords.longitude() > 0 ? 1 : -1;
366  const int currentSign = currentCoords.longitude() > 0 ? 1 : -1;
367 
368  lonDiff = currentCoords.longitude() - previousCoords.longitude();
369  if ( previousSign != currentSign
370  && fabs(previousCoords.longitude()) + fabs(currentCoords.longitude()) > M_PI ) {
371  if ( previousSign > currentSign ) {
372  // going eastwards ->
373  lonDiff += 2 * M_PI ;
374  } else {
375  // going westwards ->
376  lonDiff -= 2 * M_PI;
377  }
378  }
379  }
380 
381  const qreal altDiff = currentCoords.altitude() - previousCoords.altitude();
382 
383  // Create the tessellation nodes.
384  GeoDataCoordinates previousTessellatedCoords = previousCoords;
385  for ( int i = 1; i <= tessellatedNodes; ++i ) {
386  const qreal t = (qreal)(i) / (qreal)( tessellatedNodes + 1 );
387 
388  // interpolate the altitude, too
389  const qreal altitude = clampToGround ? 0 : altDiff * t + previousCoords.altitude();
390 
391  qreal lon = 0.0;
392  qreal lat = 0.0;
393  if ( followLatitudeCircle ) {
394  // To tessellate along latitude circles use the
395  // linear interpolation of the longitude.
396  lon = lonDiff * t + previousCoords.longitude();
397  lat = previousTessellatedCoords.latitude();
398  }
399  else {
400  // To tessellate along great circles use the
401  // normalized linear interpolation ("NLERP") for latitude and longitude.
402  const Quaternion itpos = Quaternion::nlerp( previousCoords.quaternion(), currentCoords.quaternion(), t );
403  itpos. getSpherical( lon, lat );
404  }
405 
406  const GeoDataCoordinates currentTessellatedCoords( lon, lat, altitude );
407  crossHorizon( currentTessellatedCoords, polygons, viewport );
408  previousTessellatedCoords = currentTessellatedCoords;
409  }
410 
411  // For the clampToGround case add the "current" coordinate after adding all other nodes.
412  GeoDataCoordinates currentModifiedCoords( currentCoords );
413  if ( clampToGround ) {
414  currentModifiedCoords.setAltitude( 0.0 );
415  }
416  crossHorizon( currentModifiedCoords, polygons, viewport );
417 }
418 
419 void SphericalProjectionPrivate::crossHorizon( const GeoDataCoordinates & bCoord,
420  QVector<QPolygonF*> &polygons,
421  const ViewportParams *viewport ) const
422 {
423  qreal x, y;
424  bool globeHidesPoint;
425 
426  Q_Q( const AbstractProjection );
427 
428  q->screenCoordinates( bCoord, viewport, x, y, globeHidesPoint );
429 
430  if( !globeHidesPoint ) {
431  *polygons.last() << QPointF( x, y );
432  }
433  else {
434  if ( !polygons.last()->isEmpty() ) {
435  QPolygonF *path = new QPolygonF;
436  polygons.append( path );
437  }
438  }
439 }
440 
441 bool SphericalProjectionPrivate::lineStringToPolygon( const GeoDataLineString &lineString,
442  const ViewportParams *viewport,
443  QVector<QPolygonF *> &polygons ) const
444 {
445  Q_Q( const SphericalProjection );
446 
447  const TessellationFlags f = lineString.tessellationFlags();
448 
449  qreal x = 0;
450  qreal y = 0;
451  bool globeHidesPoint = false;
452 
453  qreal previousX = -1.0;
454  qreal previousY = -1.0;
455  bool previousGlobeHidesPoint = false;
456 
457  qreal horizonX = -1.0;
458  qreal horizonY = -1.0;
459 
460  polygons.append( new QPolygonF );
461 
462  GeoDataLineString::ConstIterator itCoords = lineString.constBegin();
463  GeoDataLineString::ConstIterator itPreviousCoords = lineString.constBegin();
464 
465  // Some projections display the earth in a way so that there is a
466  // foreside and a backside.
467  // The horizon is the line (usually a circle) which separates both
468  // sides from each other and resembles the map shape.
469  GeoDataCoordinates horizonCoords;
470 
471  // A horizon pair is a pair of two subsequent horizon crossings:
472  // The first one describes the point where a line string disappears behind the horizon.
473  // and where horizonPair is set to true.
474  // The second one describes the point where the line string reappears.
475  // In this case the two points are connected and horizonPair is set to false again.
476  bool horizonPair = false;
477  GeoDataCoordinates horizonDisappearCoords;
478 
479  // If the first horizon crossing in a line string describes the appearance of
480  // a line string then we call it a "horizon orphan" and horizonOrphan is set to true.
481  // In this case once the last horizon crossing in the line string is reached
482  // it needs to be connected to the orphan.
483  bool horizonOrphan = false;
484  GeoDataCoordinates horizonOrphanCoords;
485 
486  GeoDataLineString::ConstIterator itBegin = lineString.constBegin();
487  GeoDataLineString::ConstIterator itEnd = lineString.constEnd();
488 
489  bool processingLastNode = false;
490 
491  // We use a while loop to be able to cover linestrings as well as linear rings:
492  // Linear rings require to tessellate the path from the last node to the first node
493  // which isn't really convenient to achieve with a for loop ...
494 
495  const bool isLong = lineString.size() > 50;
496  const int maximumDetail = ( viewport->radius() > 5000 ) ? 5 :
497  ( viewport->radius() > 2500 ) ? 4 :
498  ( viewport->radius() > 1000 ) ? 3 :
499  ( viewport->radius() > 600 ) ? 2 :
500  ( viewport->radius() > 50 ) ? 1 :
501  0;
502 
503  while ( itCoords != itEnd )
504  {
505 
506  // Optimization for line strings with a big amount of nodes
507  bool skipNode = itCoords != itBegin && isLong && !processingLastNode &&
508  ( (*itCoords).detail() > maximumDetail
509  || viewport->resolves( *itPreviousCoords, *itCoords ) );
510 
511  if ( !skipNode ) {
512 
513  q->screenCoordinates( *itCoords, viewport, x, y, globeHidesPoint );
514 
515  // Initializing variables that store the values of the previous iteration
516  if ( !processingLastNode && itCoords == itBegin ) {
517  previousGlobeHidesPoint = globeHidesPoint;
518  itPreviousCoords = itCoords;
519  previousX = x;
520  previousY = y;
521  }
522 
523  // Check for the "horizon case" (which is present e.g. for the spherical projection
524  const bool isAtHorizon = ( globeHidesPoint || previousGlobeHidesPoint ) &&
525  ( globeHidesPoint != previousGlobeHidesPoint );
526 
527  if ( isAtHorizon ) {
528  // Handle the "horizon case"
529  horizonCoords = findHorizon( *itPreviousCoords, *itCoords, viewport, f );
530 
531  if ( lineString.isClosed() ) {
532  if ( horizonPair ) {
533  horizonToPolygon( viewport, horizonDisappearCoords, horizonCoords, polygons.last() );
534  horizonPair = false;
535  }
536  else {
537  if ( globeHidesPoint ) {
538  horizonDisappearCoords = horizonCoords;
539  horizonPair = true;
540  }
541  else {
542  horizonOrphanCoords = horizonCoords;
543  horizonOrphan = true;
544  }
545  }
546  }
547 
548  q->screenCoordinates( horizonCoords, viewport, horizonX, horizonY );
549 
550  // If the line appears on the visible half we need
551  // to add an interpolated point at the horizon as the previous point.
552  if ( previousGlobeHidesPoint ) {
553  *polygons.last() << QPointF( horizonX, horizonY );
554  }
555  }
556 
557  // This if-clause contains the section that tessellates the line
558  // segments of a linestring. If you are about to learn how the code of
559  // this class works you can safely ignore this section for a start.
560 
561  if ( lineString.tessellate() /* && ( isVisible || previousIsVisible ) */ ) {
562 
563  if ( !isAtHorizon ) {
564 
565  tessellateLineSegment( *itPreviousCoords, previousX, previousY,
566  *itCoords, x, y,
567  polygons, viewport,
568  f );
569 
570  }
571  else {
572  // Connect the interpolated point at the horizon with the
573  // current or previous point in the line.
574  if ( previousGlobeHidesPoint ) {
575  tessellateLineSegment( horizonCoords, horizonX, horizonY,
576  *itCoords, x, y,
577  polygons, viewport,
578  f );
579  }
580  else {
581  tessellateLineSegment( *itPreviousCoords, previousX, previousY,
582  horizonCoords, horizonX, horizonY,
583  polygons, viewport,
584  f );
585  }
586  }
587  }
588  else {
589  if ( !globeHidesPoint ) {
590  *polygons.last() << QPointF( x, y );
591  }
592  else {
593  if ( !previousGlobeHidesPoint && isAtHorizon ) {
594  *polygons.last() << QPointF( horizonX, horizonY );
595  }
596  }
597  }
598 
599  if ( globeHidesPoint ) {
600  if ( !previousGlobeHidesPoint
601  && !lineString.isClosed()
602  ) {
603  polygons.append( new QPolygonF );
604  }
605  }
606 
607  previousGlobeHidesPoint = globeHidesPoint;
608  itPreviousCoords = itCoords;
609  previousX = x;
610  previousY = y;
611  }
612 
613  // Here we modify the condition to be able to process the
614  // first node after the last node in a LinearRing.
615 
616  if ( processingLastNode ) {
617  break;
618  }
619  ++itCoords;
620 
621  if ( itCoords == itEnd && lineString.isClosed() ) {
622  itCoords = itBegin;
623  processingLastNode = true;
624  }
625  }
626 
627  // In case of horizon crossings, make sure that we always get a
628  // polygon closed correctly.
629  if ( horizonOrphan && lineString.isClosed() ) {
630  horizonToPolygon( viewport, horizonCoords, horizonOrphanCoords, polygons.last() );
631  }
632 
633  if ( polygons.last()->size() <= 1 ){
634  polygons.pop_back(); // Clean up "unused" empty polygon instances
635  }
636 
637  return polygons.isEmpty();
638 }
639 
640 void SphericalProjectionPrivate::horizonToPolygon( const ViewportParams *viewport,
641  const GeoDataCoordinates & disappearCoords,
642  const GeoDataCoordinates & reappearCoords,
643  QPolygonF * polygon ) const
644 {
645  qreal x, y;
646 
647  const qreal imageHalfWidth = viewport->width() / 2;
648  const qreal imageHalfHeight = viewport->height() / 2;
649 
650  bool dummyGlobeHidesPoint = false;
651 
652  Q_Q( const SphericalProjection );
653  // Calculate the angle of the position vectors of both coordinates
654  q->screenCoordinates( disappearCoords, viewport, x, y, dummyGlobeHidesPoint );
655  qreal alpha = atan2( y - imageHalfHeight,
656  x - imageHalfWidth );
657 
658  q->screenCoordinates( reappearCoords, viewport, x, y, dummyGlobeHidesPoint );
659  qreal beta = atan2( y - imageHalfHeight,
660  x - imageHalfWidth );
661 
662  // Calculate the difference between both
663  qreal diff = GeoDataCoordinates::normalizeLon( beta - alpha );
664 
665  qreal sgndiff = diff < 0 ? -1 : 1;
666 
667  const qreal arcradius = viewport->radius();
668  const int itEnd = fabs(diff * RAD2DEG);
669 
670  // Create a polygon that resembles an arc between the two position vectors
671  for ( int it = 1; it <= itEnd; ++it ) {
672  const qreal angle = alpha + DEG2RAD * sgndiff * it;
673  const qreal itx = imageHalfWidth + arcradius * cos( angle );
674  const qreal ity = imageHalfHeight + arcradius * sin( angle );
675  *polygon << QPointF( itx, ity );
676  }
677 }
678 
679 
680 GeoDataCoordinates SphericalProjectionPrivate::findHorizon( const GeoDataCoordinates & previousCoords,
681  const GeoDataCoordinates & currentCoords,
682  const ViewportParams *viewport,
683  TessellationFlags f,
684  int recursionCounter ) const
685 {
686  bool currentHide = globeHidesPoint( currentCoords, viewport ) ;
687 
688  if ( recursionCounter > 20 ) {
689  return currentHide ? previousCoords : currentCoords;
690  }
691  ++recursionCounter;
692 
693  bool followLatitudeCircle = false;
694 
695  // Calculate steps for tessellation: lonDiff and altDiff
696  qreal lonDiff = 0.0;
697  qreal previousLongitude = 0.0;
698  qreal previousLatitude = 0.0;
699 
700  if ( f.testFlag( RespectLatitudeCircle ) ) {
701  previousCoords.geoCoordinates( previousLongitude, previousLatitude );
702  qreal previousSign = previousLongitude > 0 ? 1 : -1;
703 
704  qreal currentLongitude = 0.0;
705  qreal currentLatitude = 0.0;
706  currentCoords.geoCoordinates( currentLongitude, currentLatitude );
707  qreal currentSign = currentLongitude > 0 ? 1 : -1;
708 
709  if ( previousLatitude == currentLatitude ) {
710  followLatitudeCircle = true;
711 
712  lonDiff = currentLongitude - previousLongitude;
713  if ( previousSign != currentSign
714  && fabs(previousLongitude) + fabs(currentLongitude) > M_PI ) {
715  if ( previousSign > currentSign ) {
716  // going eastwards ->
717  lonDiff += 2 * M_PI ;
718  } else {
719  // going westwards ->
720  lonDiff -= 2 * M_PI;
721  }
722  }
723 
724  }
725  else {
726 // mDebug() << "Don't FollowLatitudeCircle";
727  }
728  }
729 
730  qreal lon = 0.0;
731  qreal lat = 0.0;
732 
733  qreal altDiff = currentCoords.altitude() - previousCoords.altitude();
734 
735  if ( followLatitudeCircle ) {
736  // To tessellate along latitude circles use the
737  // linear interpolation of the longitude.
738  lon = lonDiff * 0.5 + previousLongitude;
739  lat = previousLatitude;
740  }
741  else {
742  // To tessellate along great circles use the
743  // normalized linear interpolation ("NLERP") for latitude and longitude.
744  const Quaternion itpos = Quaternion::nlerp( previousCoords.quaternion(), currentCoords.quaternion(), 0.5 );
745  itpos. getSpherical( lon, lat );
746  }
747 
748  qreal altitude = previousCoords.altitude() + 0.5 * altDiff;
749 
750  GeoDataCoordinates horizonCoords( lon, lat, altitude );
751 
752  bool horizonHide = globeHidesPoint( horizonCoords, viewport );
753 
754  if ( horizonHide != currentHide ) {
755  return findHorizon( horizonCoords, currentCoords, viewport, f, recursionCounter );
756  }
757 
758  return findHorizon( previousCoords, horizonCoords, viewport, f, recursionCounter );
759 }
760 
761 
762 bool SphericalProjectionPrivate::globeHidesPoint( const GeoDataCoordinates &coordinates,
763  const ViewportParams *viewport ) const
764 {
765  qreal absoluteAltitude = coordinates.altitude() + EARTH_RADIUS;
766  Quaternion qpos = coordinates.quaternion();
767 
768  qpos.rotateAroundAxis( viewport->planetAxisMatrix() );
769 
770  qreal pixelAltitude = ( ( viewport->radius() )
771  / EARTH_RADIUS * absoluteAltitude );
772  if ( coordinates.altitude() < 10000 ) {
773  // Skip placemarks at the other side of the earth.
774  if ( qpos.v[Q_Z] < 0 ) {
775  return true;
776  }
777  }
778  else {
779  qreal earthCenteredX = pixelAltitude * qpos.v[Q_X];
780  qreal earthCenteredY = pixelAltitude * qpos.v[Q_Y];
781  qreal radius = viewport->radius();
782 
783  // Don't draw high placemarks (e.g. satellites) that aren't visible.
784  if ( qpos.v[Q_Z] < 0
785  && ( ( earthCenteredX * earthCenteredX
786  + earthCenteredY * earthCenteredY )
787  < radius * radius ) ) {
788  return true;
789  }
790  }
791 
792  return false;
793 }
794 
795 
796 
797 }
Marble::GeoDataCoordinates::Unit
Unit
enum used constructor to specify the units used
Definition: GeoDataCoordinates.h:64
GeoDataCoordinates.h
Marble::RAD2DEG
const qreal RAD2DEG
Definition: MarbleGlobal.h:201
Marble::SphericalProjection::screenCoordinates
virtual bool screenCoordinates(const GeoDataCoordinates &coordinates, const ViewportParams *params, qreal &x, qreal &y, bool &globeHidesPoint) const
Get the screen coordinates corresponding to geographical coordinates in the map.
Definition: SphericalProjection.cpp:76
Marble::AbstractProjectionPrivate
Definition: AbstractProjection_p.h:20
Marble::GeoDataCoordinates
A 3d point representation.
Definition: GeoDataCoordinates.h:52
Marble::SphericalProjectionPrivate
Definition: SphericalProjection_p.h:23
Marble::GeoDataCoordinates::Radian
Definition: GeoDataCoordinates.h:65
Marble::GeoDataLatLonBox::setNorth
void setNorth(const qreal north, GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian)
Definition: GeoDataLatLonBox.cpp:101
Marble::GeoDataLineString::constEnd
QVector< GeoDataCoordinates >::ConstIterator constEnd() const
Returns a const iterator that points to the end of the LineString.
Definition: GeoDataLineString.cpp:216
angle
double angle(double vec1[3], double vec2[3])
Definition: sgp4ext.cpp:164
Marble::GeoDataCoordinates::setAltitude
void setAltitude(const qreal altitude)
set the altitude of the Point in meters
Definition: GeoDataCoordinates.cpp:1191
Marble::GeoDataCoordinates::normalizeLon
static qreal normalizeLon(qreal lon, GeoDataCoordinates::Unit=GeoDataCoordinates::Radian)
normalize the longitude to always be -M_PI <= lon <= +M_PI (Radian).
Definition: GeoDataCoordinates.cpp:776
Marble::GeoDataLineString::size
int size() const
Returns the number of nodes in a LineString.
Definition: GeoDataLineString.cpp:134
Marble::SphericalProjection::minValidLat
virtual qreal minValidLat() const
Definition: SphericalProjection.cpp:71
Marble::AbstractProjection::maxLat
qreal maxLat() const
Definition: AbstractProjection.cpp:54
Marble::GeoDataLatLonBox::setSouth
void setSouth(const qreal south, GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian)
Definition: GeoDataLatLonBox.cpp:122
Marble::SphericalProjection::geoCoordinates
bool geoCoordinates(const int x, const int y, const ViewportParams *params, qreal &lon, qreal &lat, GeoDataCoordinates::Unit unit=GeoDataCoordinates::Degree) const
Get the earth coordinates corresponding to a pixel in the map.
Definition: SphericalProjection.cpp:148
Marble::AbstractProjection::latLonAltBox
virtual GeoDataLatLonAltBox latLonAltBox(const QRect &screenRect, const ViewportParams *viewport) const
Definition: AbstractProjection.cpp:111
SphericalProjection.h
This file contains the headers for SphericalProjection.
Marble::GeoDataCoordinates::latitude
qreal latitude(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
retrieves the latitude of the GeoDataCoordinates object use the unit parameter to switch between Radi...
Definition: GeoDataCoordinates.cpp:751
Marble::GeoDataLatLonBox::setWest
void setWest(const qreal west, GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian)
Definition: GeoDataLatLonBox.cpp:164
Marble::Quaternion::nlerp
static Quaternion nlerp(const Quaternion &q1, const Quaternion &q2, qreal t)
Definition: Quaternion.cpp:207
Marble::GeoDataLineString::ConstIterator
QVector< GeoDataCoordinates >::ConstIterator ConstIterator
Definition: GeoDataLineString.h:80
MarbleDebug.h
Marble::GeoDataLineString::tessellationFlags
TessellationFlags tessellationFlags() const
Returns the tessellation flags for a LineString.
Definition: GeoDataLineString.cpp:302
Marble::GeoDataCoordinates::Degree
Definition: GeoDataCoordinates.h:66
Marble::ViewportParams::height
int height() const
Definition: ViewportParams.cpp:255
Marble::Quaternion::rotateAroundAxis
void rotateAroundAxis(const Quaternion &q)
Definition: Quaternion.cpp:167
Marble::GeoDataLineString::isClosed
virtual bool isClosed() const
Returns whether a LineString is a closed polygon.
Definition: GeoDataLineString.cpp:275
Marble::GeoDataCoordinates::altitude
qreal altitude() const
return the altitude of the Point in meters
Definition: GeoDataCoordinates.cpp:1197
Marble::GeoDataLatLonBox::east
qreal east(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
Get the eastern boundary of the bounding box.
Definition: GeoDataLatLonBox.cpp:135
Marble::SphericalProjectionPrivate::processTessellation
void processTessellation(const GeoDataCoordinates &previousCoords, const GeoDataCoordinates &currentCoords, int count, QVector< QPolygonF * > &polygons, const ViewportParams *viewport, TessellationFlags f=0) const
Definition: SphericalProjection.cpp:350
Marble::SphericalProjection::~SphericalProjection
virtual ~SphericalProjection()
Definition: SphericalProjection.cpp:49
Marble::GeoDataCoordinates::geoCoordinates
void geoCoordinates(qreal &lon, qreal &lat, GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
use this function to get the longitude and latitude with one call - use the unit parameter to switch ...
Definition: GeoDataCoordinates.cpp:715
Marble::AbstractProjection::setMaxLat
void setMaxLat(qreal maxLat)
Definition: AbstractProjection.cpp:60
Marble::ViewportParams::width
int width() const
Definition: ViewportParams.cpp:250
Marble::tessellationPrecision
static const int tessellationPrecision
Definition: AbstractProjection.h:37
Marble::EARTH_RADIUS
const qreal EARTH_RADIUS
Definition: MarbleGlobal.h:238
Marble::Quaternion::yaw
qreal yaw() const
Definition: Quaternion.cpp:113
Marble::SphericalProjection::maxValidLat
virtual qreal maxValidLat() const
Definition: SphericalProjection.cpp:66
Marble::ViewportParams::mapCoversViewport
bool mapCoversViewport() const
Definition: ViewportParams.cpp:398
Marble::SphericalProjection::SphericalProjection
SphericalProjection()
Construct a new SphericalProjection.
Definition: SphericalProjection.cpp:35
Marble::SphericalProjectionPrivate::crossHorizon
void crossHorizon(const GeoDataCoordinates &bCoord, QVector< QPolygonF * > &polygons, const ViewportParams *viewport) const
Definition: SphericalProjection.cpp:419
Marble::SphericalProjection
A class to implement the spherical projection used by the "Globe" view.
Definition: SphericalProjection.h:36
GeoDataLineString.h
Marble::Q_Z
Definition: Quaternion.h:34
Marble::Quaternion::pitch
qreal pitch() const
Definition: Quaternion.cpp:107
Marble::GeoDataCoordinates::normalizeLat
static qreal normalizeLat(qreal lat, GeoDataCoordinates::Unit=GeoDataCoordinates::Radian)
normalize latitude to always be in -M_PI / 2.
Definition: GeoDataCoordinates.cpp:799
MarbleGlobal.h
Marble::DEG2RAD
const qreal DEG2RAD
Definition: MarbleGlobal.h:200
Marble::ViewportParams::planetAxisMatrix
const matrix & planetAxisMatrix() const
Definition: ViewportParams.cpp:245
Marble::GeoDataLineString
A LineString that allows to store a contiguous set of line segments.
Definition: GeoDataLineString.h:75
Marble::SphericalProjectionPrivate::SphericalProjectionPrivate
SphericalProjectionPrivate(SphericalProjection *parent)
Definition: SphericalProjection.cpp:54
Marble::ViewportParams
A public class that controls what is visible in the viewport of a Marble map.
Definition: ViewportParams.h:44
Marble::SphericalProjection::repeatableX
virtual bool repeatableX() const
Definition: SphericalProjection.cpp:61
Marble::Q_Y
Definition: Quaternion.h:33
Marble::SphericalProjection::mapShape
virtual QPainterPath mapShape(const ViewportParams *viewport) const
Definition: SphericalProjection.cpp:256
Marble::GeoDataCoordinates::longitude
qreal longitude(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
retrieves the longitude of the GeoDataCoordinates object use the unit parameter to switch between Rad...
Definition: GeoDataCoordinates.cpp:739
Marble::Q_X
Definition: Quaternion.h:32
ViewportParams.h
This file contains the headers for ViewportParams.
Marble::MarbleGlobal::SmallScreen
Definition: MarbleGlobal.h:268
Marble::MarbleGlobal::getInstance
static MarbleGlobal * getInstance()
Definition: MarbleGlobal.cpp:37
Marble::SphericalProjectionPrivate::tessellateLineSegment
void tessellateLineSegment(const GeoDataCoordinates &aCoords, qreal ax, qreal ay, const GeoDataCoordinates &bCoords, qreal bx, qreal by, QVector< QPolygonF * > &polygons, const ViewportParams *viewport, TessellationFlags f=0) const
Definition: SphericalProjection.cpp:299
Marble::SphericalProjectionPrivate::horizonToPolygon
void horizonToPolygon(const ViewportParams *viewport, const GeoDataCoordinates &disappearCoords, const GeoDataCoordinates &reappearCoords, QPolygonF *) const
Definition: SphericalProjection.cpp:640
Marble::RespectLatitudeCircle
Definition: MarbleGlobal.h:33
maxTessellationNodes
static const int maxTessellationNodes
Definition: SphericalProjection.cpp:29
Marble::GeoDataLatLonBox::west
qreal west(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
Get the western boundary of the bounding box.
Definition: GeoDataLatLonBox.cpp:156
Marble::SphericalProjectionPrivate::findHorizon
GeoDataCoordinates findHorizon(const GeoDataCoordinates &previousCoords, const GeoDataCoordinates &currentCoords, const ViewportParams *viewport, TessellationFlags f=0, int recursionCounter=0) const
Definition: SphericalProjection.cpp:680
Marble::SphericalProjectionPrivate::globeHidesPoint
bool globeHidesPoint(const GeoDataCoordinates &coordinates, const ViewportParams *viewport) const
Definition: SphericalProjection.cpp:762
GeoDataPoint.h
Marble::ViewportParams::radius
int radius() const
Definition: ViewportParams.cpp:195
Marble::GeoDataLineString::constBegin
QVector< GeoDataCoordinates >::ConstIterator constBegin() const
Returns a const iterator that points to the begin of the LineString.
Definition: GeoDataLineString.cpp:211
Marble::Quaternion
Definition: Quaternion.h:43
Marble::AbstractProjection
A base class for all projections in Marble.
Definition: AbstractProjection.h:49
Marble::ViewportParams::resolves
bool resolves(const GeoDataLatLonBox &latLonBox) const
Definition: ViewportParams.cpp:330
Marble::MarbleGlobal::profiles
Profiles profiles() const
Definition: MarbleGlobal.cpp:48
Marble::ViewportParams::planetAxis
Quaternion planetAxis() const
Definition: ViewportParams.cpp:240
M_PI
#define M_PI
Definition: GeoDataCoordinates.h:26
Marble::Quaternion::v
xmmfloat v
Definition: Quaternion.h:86
Marble::SphericalProjection::mapCoversViewport
bool mapCoversViewport(const ViewportParams *viewport) const
Definition: SphericalProjection.cpp:237
Marble::FollowGround
Definition: MarbleGlobal.h:34
Marble::Quaternion::getSpherical
void getSpherical(qreal &lon, qreal &lat) const
Definition: Quaternion.cpp:48
Marble::AbstractProjection::minLat
qreal minLat() const
Definition: AbstractProjection.cpp:76
Marble::SphericalProjectionPrivate::lineStringToPolygon
virtual bool lineStringToPolygon(const GeoDataLineString &lineString, const ViewportParams *viewport, QVector< QPolygonF * > &polygons) const
Definition: SphericalProjection.cpp:441
Marble::GeoDataLatLonAltBox
A class that defines a 3D bounding box for geographic data.
Definition: GeoDataLatLonAltBox.h:49
Marble::GeoDataLineString::latLonAltBox
virtual const GeoDataLatLonAltBox & latLonAltBox() const
Returns the smallest latLonAltBox that contains the LineString.
Definition: GeoDataLineString.cpp:545
Marble::AbstractProjection::setMinLat
void setMinLat(qreal minLat)
Definition: AbstractProjection.cpp:82
Marble::GeoDataLineString::tessellate
bool tessellate() const
Returns whether the LineString follows the earth's surface.
Definition: GeoDataLineString.cpp:280
Marble::SphericalProjection::latLonAltBox
GeoDataLatLonAltBox latLonAltBox(const QRect &screenRect, const ViewportParams *viewport) const
Definition: SphericalProjection.cpp:176
SphericalProjection_p.h
Marble::GeoDataCoordinates::quaternion
const Quaternion & quaternion() const
return a Quaternion with the used coordinates
Definition: GeoDataCoordinates.cpp:1226
Marble::GeoDataLatLonBox::setEast
void setEast(const qreal east, GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian)
Definition: GeoDataLatLonBox.cpp:143
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