• 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
VectorMap.cpp
Go to the documentation of this file.
1 //
2 // This file is part of the Marble Project.
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 2006-2007 Torsten Rahn <tackat@kde.org>
9 // Copyright 2007-2008 Inge Wallin <ingwa@kde.org>
10 //
11 
12 
13 #include "VectorMap.h"
14 
15 #include <cmath>
16 #include <cstdlib>
17 
18 #include <QVector>
19 #include <QColor>
20 
21 #include "MarbleDebug.h"
22 #include "MarbleGlobal.h"
23 #include "AbstractProjection.h"
24 #include "GeoPainter.h"
25 #include "GeoPolygon.h"
26 #include "ViewportParams.h"
27 #include "MathHelper.h"
28 
29 // #define VECMAP_DEBUG
30 
31 using namespace Marble;
32 
33 VectorMap::VectorMap()
34  : m_zBoundingBoxLimit( 0.0 ),
35  m_zPointLimit( 0.0 )
36  // m_debugNodeCount( 0 )
37 {
38 }
39 
40 VectorMap::~VectorMap()
41 {
42 }
43 
44 
45 void VectorMap::createFromPntMap( const PntMap* pntmap,
46  const ViewportParams* viewport )
47 {
48  switch( viewport->projection() ) {
49  case Spherical:
50  sphericalCreateFromPntMap( pntmap, viewport );
51  break;
52  case Equirectangular:
53  rectangularCreateFromPntMap( pntmap, viewport );
54  break;
55  case Mercator:
56  mercatorCreateFromPntMap( pntmap, viewport );
57  break;
58  }
59 }
60 
61 void VectorMap::sphericalCreateFromPntMap( const PntMap* pntmap,
62  const ViewportParams* viewport )
63 {
64  m_polygons.clear();
65 
66  // We must use qreal or int64 for the calculations because we
67  // square radius sometimes below, and it may cause an overflow. We
68  // choose qreal because of some sqrt() calculations.
69  qreal radius = viewport->radius();
70  qreal imgradius2 = ( viewport->width() / 2 ) * ( viewport->width() / 2 ) + ( viewport->height() / 2 ) * ( viewport->height() / 2 );
71 
72  // zlimit: describes the lowest z value of the sphere that is
73  // visible on the screen. This should happen in the
74  // corners.
75  qreal zlimit = ( ( imgradius2 < radius * radius )
76  ? sqrt( 1 - imgradius2 / ( radius * radius ) )
77  : 0.0 );
78  // mDebug() << "zlimit: " << zlimit;
79 
80  m_zBoundingBoxLimit = ( ( m_zBoundingBoxLimit >= 0.0
81  && zlimit < m_zBoundingBoxLimit )
82  || m_zBoundingBoxLimit < 0.0 )
83  ? zlimit : m_zBoundingBoxLimit;
84  m_zPointLimit = ( ( m_zPointLimit >= 0.0 && zlimit < m_zPointLimit )
85  || m_zPointLimit < 0.0 )
86  ? zlimit : m_zPointLimit;
87 
88  GeoPolygon::PtrVector::ConstIterator itPolyLine = pntmap->constBegin();
89  GeoPolygon::PtrVector::ConstIterator itEndPolyLine = pntmap->constEnd();
90 
91  // const int detail = 0;
92  const int detail = getDetailLevel( viewport->radius() );
93 
94  for (; itPolyLine != itEndPolyLine; ++itPolyLine )
95  {
96  // This sorts out polygons by bounding box which aren't visible at all.
97  GeoDataCoordinates::PtrVector boundary = (*itPolyLine)->getBoundary();
98  // rather paint an invalid line then crashing here if the boundaries are not loaded yet
99  if(boundary.size() < 5) continue;
100 
101  for ( int i = 0; i < 5; ++i ) {
102  Quaternion qbound = boundary[i]->quaternion();
103 
104  qbound.rotateAroundAxis( viewport->planetAxisMatrix() );
105  if ( qbound.v[Q_Z] > m_zBoundingBoxLimit ) {
106  // if (qbound.v[Q_Z] > 0){
107  // mDebug() << i << " Visible: YES";
108  sphericalCreatePolyLine( *itPolyLine, detail, viewport );
109 
110  break; // abort foreach test of current boundary
111  }
112  // else
113  // mDebug() << i << " Visible: NOT";
114  }
115  }
116 }
117 
118 void VectorMap::rectangularCreateFromPntMap( const PntMap* pntmap,
119  const ViewportParams* viewport )
120 {
121  m_polygons.clear();
122  int radius = viewport->radius();
123 
124  // Calculate translation of center point
125  const qreal centerLon = viewport->centerLongitude();
126  const qreal centerLat = viewport->centerLatitude();
127 
128  const qreal rad2Pixel = (float)( 2 * radius ) / M_PI;
129 
130  GeoPolygon::PtrVector::ConstIterator itPolyLine = pntmap->constBegin();
131  GeoPolygon::PtrVector::ConstIterator itEndPolyLine = pntmap->constEnd();
132 
133  const QRectF visibleArea ( 0, 0, viewport->width(), viewport->height() );
134  const int detail = getDetailLevel( radius );
135 
136  for (; itPolyLine != itEndPolyLine; ++itPolyLine )
137  {
138  const GeoDataCoordinates::PtrVector boundary = (*itPolyLine)->getBoundary();
139 
140  // Let's just use the top left and the bottom right bounding
141  // box point for this projection.
142 
143  // rather paint an invalid line then crashing here if the boundaries are not loaded yet
144  if ( boundary.size() < 3 )
145  continue;
146 
147  ScreenPolygon boundingPolygon;
148 
149  for ( int i = 1; i < 3; ++i ) {
150  qreal lon, lat;
151  boundary[i]->geoCoordinates(lon, lat);
152  const qreal x = (qreal)(viewport->width()) / 2.0 - rad2Pixel * (centerLon - lon);
153  const qreal y = (qreal)(viewport->height()) / 2.0 + rad2Pixel * (centerLat - lat);
154  boundingPolygon << QPointF( x, y );
155  }
156 
157  // This sorts out polygons by bounding box which aren't visible at all.
158  int offset = 0;
159 
160  if ( boundingPolygon.at(0).x() < 0 || boundingPolygon.at(1).x() < 0 ) {
161  boundingPolygon.translate( 4 * radius, 0 );
162  offset += 4 * radius;
163  }
164 
165  do {
166  offset -= 4 * radius;
167  boundingPolygon.translate( -4 * radius, 0 );
168  // FIXME: Get rid of this really fugly code once we have a
169  // proper LatLonBox check implemented and in place.
170  } while( ( (*itPolyLine)->getDateLine() != GeoPolygon::Even
171  && visibleArea.intersects( (QRectF)( boundingPolygon.boundingRect() ) ) )
172  || ( (*itPolyLine)->getDateLine() == GeoPolygon::Even
173  && ( visibleArea.intersects( QRectF( boundingPolygon.at(1),
174  QPointF( (qreal)(viewport->width()) / 2.0
175  - rad2Pixel * ( centerLon - M_PI )
176  + offset,
177  boundingPolygon.at(0).y() ) ) )
178  || visibleArea.intersects( QRectF( QPointF( (qreal)(viewport->width()) / 2.0
179  - rad2Pixel * ( centerLon
180  + M_PI )
181  + offset,
182  boundingPolygon.at(1).y() ),
183  boundingPolygon.at(0) ) ) ) ) );
184  offset += 4 * radius;
185  boundingPolygon.translate( 4 * radius, 0 );
186 
187  // FIXME: Get rid of this really fugly code once we will have
188  // a proper LatLonBox check implemented and in place.
189  while ( ( (*itPolyLine)->getDateLine() != GeoPolygon::Even
190  && visibleArea.intersects( (QRectF)( boundingPolygon.boundingRect() ) ) )
191  || ( (*itPolyLine)->getDateLine() == GeoPolygon::Even
192  && ( visibleArea.intersects(
193  QRectF( boundingPolygon.at(1),
194  QPointF( (qreal)(viewport->width()) / 2.0
195  - rad2Pixel * ( centerLon - M_PI )
196  + offset,
197  boundingPolygon.at(0).y() ) ) )
198  || visibleArea.intersects(
199  QRectF( QPointF( (qreal)(viewport->width()) / 2.0
200  - rad2Pixel * ( centerLon + M_PI )
201  + offset,
202  boundingPolygon.at(1).y() ),
203  boundingPolygon.at(0) ) ) ) )
204  )
205  {
206  rectangularCreatePolyLine( *itPolyLine, detail, viewport, offset );
207 
208  offset += 4 * radius;
209  boundingPolygon.translate( 4 * radius, 0 );
210  }
211  }
212 }
213 
214 void VectorMap::mercatorCreateFromPntMap( const PntMap* pntmap,
215  const ViewportParams* viewport )
216 {
217  m_polygons.clear();
218  int radius = viewport->radius();
219 
220  // Calculate translation of center point
221  const qreal centerLon = viewport->centerLongitude();
222  const qreal centerLat = viewport->centerLatitude();
223 
224  const qreal rad2Pixel = (float)( 2 * radius ) / M_PI;
225 
226  GeoPolygon::PtrVector::ConstIterator itPolyLine = pntmap->constBegin();
227  GeoPolygon::PtrVector::ConstIterator itEndPolyLine = pntmap->constEnd();
228 
229  const QRectF visibleArea ( 0, 0, viewport->width(), viewport->height() );
230  const int detail = getDetailLevel( radius );
231 
232  for (; itPolyLine != itEndPolyLine; ++itPolyLine )
233  {
234  const GeoDataCoordinates::PtrVector boundary = (*itPolyLine)->getBoundary();
235 
236  // Let's just use the top left and the bottom right bounding box point for
237  // this projection
238 
239  // rather paint an invalid line then crashing here if the boundaries are not loaded yet
240  if ( boundary.size() < 3 )
241  continue;
242 
243  ScreenPolygon boundingPolygon;
244 
245  for ( int i = 1; i < 3; ++i ) {
246  qreal lon, lat;
247  boundary[i]->geoCoordinates(lon, lat);
248  const qreal x = (qreal)(viewport->width()) / 2.0 + rad2Pixel * (lon - centerLon);
249  const qreal y = (qreal)(viewport->height()) / 2.0 - rad2Pixel * ( atanh( sin( lat ) )
250  - atanh( sin( centerLat ) ) );
251 
252  boundingPolygon << QPointF( x, y );
253  }
254 
255  // This sorts out polygons by bounding box which aren't visible at all.
256  int offset = 0;
257 
258  if ( boundingPolygon.at(0).x() < 0 || boundingPolygon.at(1).x() < 0 ) {
259  boundingPolygon.translate( 4 * radius, 0 );
260  offset += 4 * radius;
261  }
262 
263  do {
264  offset -= 4 * radius;
265  boundingPolygon.translate( -4 * radius, 0 );
266  // FIXME: Get rid of this really fugly code once we have a
267  // proper LatLonBox check implemented and in place.
268  } while( ( (*itPolyLine)->getDateLine() != GeoPolygon::Even
269  && visibleArea.intersects( (QRectF)( boundingPolygon.boundingRect() ) ) )
270  || ( (*itPolyLine)->getDateLine() == GeoPolygon::Even
271  && ( visibleArea.intersects( QRectF( boundingPolygon.at(1),
272  QPointF( (qreal)(viewport->width()) / 2.0
273  - rad2Pixel * ( centerLon
274  - M_PI )
275  + offset,
276  boundingPolygon.at(0).y() ) ) )
277  || visibleArea.intersects( QRectF( QPointF( (qreal)(viewport->width()) / 2.0
278  - rad2Pixel * ( centerLon
279  + M_PI )
280  + offset,
281  boundingPolygon.at(1).y() ),
282  boundingPolygon.at(0) ) ) ) ) );
283  offset += 4 * radius;
284  boundingPolygon.translate( 4 * radius, 0 );
285 
286  // FIXME: Get rid of this really fugly code once we will have
287  // a proper LatLonBox check implemented and in place.
288  while ( ( (*itPolyLine)->getDateLine() != GeoPolygon::Even
289  && visibleArea.intersects( (QRectF)( boundingPolygon.boundingRect() ) ) )
290  || ( (*itPolyLine)->getDateLine() == GeoPolygon::Even
291  && ( visibleArea.intersects(
292  QRectF( boundingPolygon.at(1),
293  QPointF( (qreal)(viewport->width()) / 2.0
294  - rad2Pixel * ( centerLon - M_PI )
295  + offset,
296  boundingPolygon.at(0).y() ) ) )
297  || visibleArea.intersects(
298  QRectF( QPointF( (qreal)(viewport->width()) / 2.0
299  - rad2Pixel * ( centerLon + M_PI )
300  + offset,
301  boundingPolygon.at(1).y() ),
302  boundingPolygon.at(0) ) ) ) )
303  )
304  {
305  mercatorCreatePolyLine( *itPolyLine, detail, viewport, offset );
306 
307  offset += 4 * radius;
308  boundingPolygon.translate( 4 * radius, 0 );
309  }
310  }
311 }
312 
313 void VectorMap::sphericalCreatePolyLine( const GeoPolygon *geoPolygon,
314  const int detail, const ViewportParams *viewport )
315 {
316  const int radius = viewport->radius();
317 
318  const int rLimit = (int)( ( radius * radius )
319  * (1.0 - m_zPointLimit * m_zPointLimit ) );
320 
321  ScreenPolygon polygon;
322  polygon.reserve( geoPolygon->size() );
323  polygon.setClosed( geoPolygon->getClosed() );
324 
325  GeoDataCoordinates::Vector::ConstIterator const &itStartPoint = geoPolygon->constBegin();
326  GeoDataCoordinates::Vector::ConstIterator const &itEndPoint = geoPolygon->constEnd();
327 
328  QPointF lastPoint;
329  bool firsthorizon = false;
330  bool currentlyvisible = false;
331  bool horizonpair = false;
332  QPointF firstHorizonPoint;
333  QPointF horizona;
334 
335  GeoDataCoordinates::Vector::const_iterator itPoint = itStartPoint;
336  for (; itPoint != itEndPoint; ++itPoint ) {
337  if ( itPoint->detail() < detail )
338  continue;
339 
340  // Calculate polygon nodes
341 #ifdef VECMAP_DEBUG
342  ++m_debugNodeCount;
343 #endif
344  Quaternion qpos = itPoint->quaternion();
345  qpos.rotateAroundAxis( viewport->planetAxisMatrix() );
346  const QPointF currentPoint( ( viewport->width() / 2 ) + radius * qpos.v[Q_X] + 1.0,
347  ( viewport->height() / 2 ) - radius * qpos.v[Q_Y] + 1.0 );
348 
349  // Take care of horizon crossings if horizon is visible
350  bool lastvisible = currentlyvisible;
351 
352  // Less accurate:
353  // currentlyvisible = (qpos.v[Q_Z] >= m_zPointLimit) ? true : false;
354  currentlyvisible = ( qpos.v[Q_Z] >= 0 );
355  if ( itPoint == itStartPoint ) {
356  // qDebug("Initializing scheduled new PolyLine");
357  lastvisible = currentlyvisible;
358  lastPoint = QPointF( currentPoint.x() + 1.0,
359  currentPoint.y() + 1.0 );
360  }
361 
362  if ( currentlyvisible != lastvisible ) {
363  // qDebug("Crossing horizon line");
364  // if (!currentlyvisible) qDebug("Leaving visible hemisphere");
365  // else qDebug("Entering visible hemisphere");
366 
367  if ( !horizonpair ) {
368  // qDebug("Point A");
369 
370  if ( !currentlyvisible ) {
371  horizona = horizonPoint(viewport, currentPoint, rLimit);
372  horizonpair = true;
373  }
374  else {
375  // qDebug("Orphaned");
376  firstHorizonPoint = horizonPoint(viewport, currentPoint, rLimit);
377  firsthorizon = true;
378  }
379  }
380  else {
381  // qDebug("Point B");
382  const QPointF horizonb = horizonPoint(viewport, currentPoint, rLimit);
383 
384  createArc(viewport, horizona, horizonb, rLimit, polygon);
385  horizonpair = false;
386  }
387  }
388 
389  // Take care of screencrossing crossings if horizon is visible.
390  // Filter Points which aren't on the visible Hemisphere.
391  if ( currentlyvisible && currentPoint != lastPoint ) {
392  // most recent addition: currentPoint != lastPoint
393  polygon << currentPoint;
394  }
395 #if 0
396  else {
397  // Speed burst on invisible hemisphere
398  step = 1;
399  if ( z < -0.2) step = 10;
400  if ( z < -0.4) step = 30;
401  if ( step > remain ) step = 1;
402  }
403 #endif
404 
405  lastPoint = currentPoint;
406  }
407 
408  // In case of horizon crossings, make sure that we always get a
409  // polygon closed correctly.
410  if ( firsthorizon ) {
411  const QPointF horizonb = firstHorizonPoint;
412  if (polygon.closed())
413  createArc(viewport, horizona, horizonb, rLimit, polygon);
414 
415  firsthorizon = false;
416  }
417 
418  // Avoid polygons degenerated to Points.
419  if ( polygon.size() >= 2 ) {
420  m_polygons.append(polygon);
421  }
422 }
423 
424 void VectorMap::rectangularCreatePolyLine(
425  const GeoPolygon *geoPolygon,
426  const int detail, const ViewportParams *viewport, int offset )
427 {
428  // Calculate translation of center point
429  const qreal centerLon = viewport->centerLongitude();
430  const qreal centerLat = viewport->centerLatitude();
431 
432  // Other convenience variables
433  const qreal rad2Pixel = (float)( 2 * viewport->radius() ) / M_PI;
434 
435  ScreenPolygon polygon;
436  polygon.reserve( geoPolygon->size() );
437  polygon.setClosed( geoPolygon->getClosed() );
438 
439  ScreenPolygon otherPolygon;
440  otherPolygon.setClosed ( geoPolygon->getClosed() );
441 
442  GeoDataCoordinates::Vector::ConstIterator const &itStartPoint = geoPolygon->constBegin();
443  GeoDataCoordinates::Vector::ConstIterator const &itEndPoint = geoPolygon->constEnd();
444 
445  bool CrossedDateline = false;
446  bool firstPoint = true;
447  int lastSign = 0;
448  qreal lastLon = 0.0;
449  qreal lastLat = 0.0;
450 
451  GeoDataCoordinates::Vector::const_iterator itPoint = itStartPoint;
452  for (; itPoint != itEndPoint; ++itPoint ) {
453  // remain -= step;
454  if ( itPoint->detail() < detail )
455  continue;
456 
457  // Calculate polygon nodes
458 #ifdef VECMAP_DEBUG
459  ++m_debugNodeCount;
460 #endif
461 
462  qreal lon, lat;
463  itPoint->geoCoordinates( lon, lat);
464  const qreal x = (qreal)(viewport->width()) / 2.0 - rad2Pixel * (centerLon - lon) + offset;
465  const qreal y = (qreal)(viewport->height()) / 2.0 + rad2Pixel * (centerLat - lat);
466  int currentSign = ( lon > 0.0 ) ? 1 : -1 ;
467  if ( firstPoint ) {
468  firstPoint = false;
469  lastSign = currentSign;
470  }
471 
472  const QPointF currentPoint = QPointF( x, y );
473 
474  // Correction of the Dateline
475  if ( lastSign != currentSign && fabs(lastLon) + fabs(lon) > M_PI ) {
476 
477  // X coordinate on the screen for the points on the
478  // dateline on both sides of the flat map.
479  qreal lastXAtDateLine = (qreal)(viewport->width()) / 2.0
480  + rad2Pixel * ( lastSign * M_PI - centerLon ) + offset;
481  qreal xAtDateLine = (qreal)(viewport->width()) / 2.0
482  + rad2Pixel * ( -lastSign * M_PI - centerLon ) + offset;
483  qreal lastYAtDateLine = (qreal)(viewport->height()) / 2.0
484  - ( lastLat - centerLat ) * rad2Pixel;
485  qreal yAtSouthPole = (qreal)(viewport->height()) / 2.0
486  - ( -viewport->currentProjection()->maxLat() - centerLat ) * rad2Pixel;
487 
488  //If the "jump" occurs in the Anctartica's latitudes
489 
490  if ( lat < - M_PI / 3 ) {
491  // FIXME: This should actually need to get investigated
492  // in GeoPainter. For now though we just help
493  // GeoPainter to get the clipping right.
494  if ( lastXAtDateLine > (qreal)(viewport->width()) - 1.0 )
495  lastXAtDateLine = (qreal)(viewport->width()) - 1.0;
496  if ( lastXAtDateLine < 0.0 )
497  lastXAtDateLine = 0.0;
498  if ( xAtDateLine > (qreal)(viewport->width()) - 1.0 )
499  xAtDateLine = (qreal)(viewport->width()) - 1.0;
500  if ( xAtDateLine < 0.0 )
501  xAtDateLine = 0.0;
502 
503  polygon << QPointF( lastXAtDateLine, y );
504  polygon << QPointF( lastXAtDateLine, yAtSouthPole );
505  polygon << QPointF( xAtDateLine, yAtSouthPole );
506  polygon << QPointF( xAtDateLine, y );
507  }
508  else {
509  if ( CrossedDateline ) {
510  polygon << QPointF( xAtDateLine, y );
511  otherPolygon << QPointF( lastXAtDateLine, lastYAtDateLine);
512  }
513  else {
514  polygon << QPointF( lastXAtDateLine, lastYAtDateLine );
515  otherPolygon << QPointF( xAtDateLine, y );
516  }
517  CrossedDateline = !CrossedDateline;
518  }
519  }
520 
521  if ( CrossedDateline )
522  otherPolygon << currentPoint;
523  else
524  polygon << currentPoint;
525 
526  lastLon = lon;
527  lastLat = lat;
528  lastSign = currentSign;
529  }
530 
531  // Avoid polygons degenerated to Points.
532  if ( polygon.size() >= 2 ) {
533  m_polygons.append(polygon);
534  }
535 
536  if ( otherPolygon.size() >= 2 ) {
537  m_polygons.append( otherPolygon );
538  }
539 }
540 
541 void VectorMap::mercatorCreatePolyLine( const GeoPolygon *geoPolygon,
542  const int detail, const ViewportParams *viewport, int offset )
543 {
544  // Calculate translation of center point
545  const qreal centerLon = viewport->centerLongitude();
546  const qreal centerLat = viewport->centerLatitude();
547 
548  // Other convenience variables
549  const qreal rad2Pixel = (qreal)( 2 * viewport->radius() ) / M_PI;
550 
551  ScreenPolygon polygon;
552  polygon.reserve( geoPolygon->size() );
553  polygon.setClosed( geoPolygon->getClosed() );
554 
555  ScreenPolygon otherPolygon;
556  otherPolygon.setClosed ( geoPolygon->getClosed() );
557 
558  GeoDataCoordinates::Vector::ConstIterator const &itStartPoint = geoPolygon->constBegin();
559  GeoDataCoordinates::Vector::ConstIterator const &itEndPoint = geoPolygon->constEnd();
560 
561  bool CrossedDateline = false;
562  bool firstPoint = true;
563  int lastSign = 0;
564  qreal lastLon = 0.0;
565  qreal lastLat = 0.0;
566 
567  GeoDataCoordinates::Vector::const_iterator itPoint = itStartPoint;
568  for (; itPoint != itEndPoint; ++itPoint ) {
569  // remain -= step;
570  if ( itPoint->detail() < detail )
571  continue;
572 
573  // Calculate polygon nodes
574 #ifdef VECMAP_DEBUG
575  ++m_debugNodeCount;
576 #endif
577 
578  // FIXME: Call the projection. Unfortunately there is no
579  // screenCoordinates taking qreals.
580  qreal lon, lat;
581  itPoint->geoCoordinates( lon, lat );
582 
583  // Removing all points beyond +/- 85 deg for Mercator:
584  if ( fabs( lat ) > viewport->currentProjection()->maxLat() )
585  continue;
586 
587  const qreal x = (qreal)(viewport->width()) / 2.0 + rad2Pixel * (lon - centerLon) + offset;
588  const qreal y = (qreal)(viewport->height()) / 2.0
589  - rad2Pixel * ( atanh( sin( lat ) ) - atanh( sin( centerLat ) ) );
590  int currentSign = ( lon > 0.0 ) ? 1 : -1 ;
591  if ( firstPoint ) {
592  firstPoint = false;
593  lastSign = currentSign;
594  }
595 
596  const QPointF currentPoint = QPointF( x, y );
597 
598  //correction of the Dateline
599 
600  if ( lastSign != currentSign && fabs(lastLon) + fabs(lon) > M_PI ) {
601 
602  // x coordinate on the screen for the points on the dateline on both
603  // sides of the flat map.
604  // FIXME: mercator projection here too.
605  qreal lastXAtDateLine = (qreal)(viewport->width()) / 2.0
606  + rad2Pixel * ( lastSign * M_PI - centerLon ) + offset;
607  qreal xAtDateLine = (qreal)(viewport->width()) / 2.0
608  + rad2Pixel * ( -lastSign * M_PI - centerLon ) + offset;
609  qreal lastYAtDateLine = (qreal)( viewport->height() / 2 - rad2Pixel
610  * ( atanh( sin( lastLat ) )
611  - atanh( sin( centerLat ) ) ) );
612  qreal yAtSouthPole = (qreal)( viewport->height() / 2
613  - rad2Pixel * ( atanh( sin( -viewport->currentProjection()->
614  maxLat() ) )
615  - atanh( sin( centerLat ) ) ) );
616 
617  //If the "jump" occurs in the Anctartica's latitudes
618 
619  if ( lat < - M_PI / 3 ) {
620  // FIXME: This should actually need to get investigated
621  // in GeoPainter. For now though we just help
622  // GeoPainter to get the clipping right.
623  if ( lastXAtDateLine > (qreal)(viewport->width()) - 1.0 )
624  lastXAtDateLine = (qreal)(viewport->width()) - 1.0;
625  if ( lastXAtDateLine < 0.0 )
626  lastXAtDateLine = 0.0;
627  if ( xAtDateLine > (qreal)(viewport->width()) - 1.0 )
628  xAtDateLine = (qreal)(viewport->width()) - 1.0;
629  if ( xAtDateLine < 0.0 )
630  xAtDateLine = 0.0;
631 
632  polygon << QPointF( lastXAtDateLine, y );
633  polygon << QPointF( lastXAtDateLine, yAtSouthPole );
634  polygon << QPointF( xAtDateLine, yAtSouthPole );
635  polygon << QPointF( xAtDateLine, y );
636  }
637  else {
638  if ( CrossedDateline ) {
639  polygon << QPointF( xAtDateLine, y );
640  otherPolygon << QPointF( lastXAtDateLine, lastYAtDateLine);
641  }
642  else {
643  polygon << QPointF( lastXAtDateLine, lastYAtDateLine );
644  otherPolygon << QPointF( xAtDateLine, y );
645  }
646  CrossedDateline = !CrossedDateline;
647  }
648  }
649 
650  if ( CrossedDateline )
651  otherPolygon << currentPoint;
652  else
653  polygon << currentPoint;
654 
655  lastLon = lon;
656  lastLat = lat;
657  lastSign = currentSign;
658  }
659 
660  // Avoid polygons degenerated to Points.
661  if ( polygon.size() >= 2 ) {
662  m_polygons.append(polygon);
663  }
664 
665  if ( otherPolygon.size() >= 2 ) {
666  m_polygons.append( otherPolygon );
667  }
668 }
669 
670 
671 // Paint the prepared vectors in screen coordinates.
672 
673 void VectorMap::paintMap(GeoPainter * painter)
674 {
675  ScreenPolygon::Vector::const_iterator itEndPolygon = m_polygons.constEnd();
676 
677  for ( ScreenPolygon::Vector::const_iterator itPolygon = m_polygons.constBegin();
678  itPolygon != itEndPolygon;
679  ++itPolygon )
680  {
681  if ( itPolygon->closed() )
682  painter->drawPolygon( *itPolygon );
683  else
684  painter->drawPolyline( *itPolygon );
685  }
686 }
687 
688 
689 QPointF VectorMap::horizonPoint( const ViewportParams *viewport, const QPointF &currentPoint, int rLimit ) const
690 {
691  // qDebug("Interpolating");
692  const qreal xa = currentPoint.x() - ( ( viewport->width() / 2 ) + 1 );
693 
694  // Move the currentPoint along the y-axis to match the horizon.
695  // ya = sqrt( ((qreal)m_radius + 1) * ( (qreal)m_radius + 1) - xa*xa);
696  qreal ya = ( rLimit > xa * xa )
697  ? sqrt( (qreal)(rLimit) - (qreal)( xa * xa ) ) : 0;
698  // mDebug() << " m_rlimit" << m_rlimit << " xa*xa" << xa*xa << " ya: " << ya;
699  if ( ( currentPoint.y() - ( ( viewport->height() / 2 ) + 1 ) ) < 0 )
700  ya = -ya;
701 
702  return QPointF( ( viewport->width() / 2 ) + xa + 1, ( viewport->height() / 2 ) + ya + 1 );
703 }
704 
705 
706 void VectorMap::createArc( const ViewportParams *viewport, const QPointF &horizona, const QPointF &horizonb, int rLimit, ScreenPolygon &polygon )
707 {
708 
709  qreal beta = (qreal)( RAD2DEG
710  * atan2( horizonb.y() - ( viewport->height() / 2 ) - 1,
711  horizonb.x() - ( viewport->width() / 2 ) - 1 ) );
712  qreal alpha = (qreal)( RAD2DEG
713  * atan2( horizona.y() - ( viewport->height() / 2 ) - 1,
714  horizona.x() - ( viewport->width() / 2 ) - 1 ) );
715 
716  qreal diff = beta - alpha;
717 
718  if ( diff != 0.0 && diff != 180.0 && diff != -180.0 ) {
719 
720  polygon.append( horizona );
721 
722  qreal sgndiff = diff / fabs(diff);
723 
724  if (fabs(diff) > 180.0)
725  diff = - sgndiff * (360.0 - fabs(diff));
726 
727  // Reassigning sgndiff this way seems dull
728  sgndiff = diff / fabs(diff);
729  // mDebug() << "SGN: " << sgndiff;
730 
731  // qDebug () << " beta: " << beta << " alpha " << alpha << " diff: " << diff;
732 
733  int itx;
734  int ity;
735  // mDebug() << "r: " << (m_radius+1) << "rn: " << sqrt((qreal)(m_rlimit));
736  qreal arcradius = sqrt( (qreal)( rLimit ) );
737 
738  for ( int it = 1; it < fabs(diff); ++it ) {
739  qreal angle = DEG2RAD * (qreal)( alpha + (sgndiff * it) );
740  itx = (int)( ( viewport->width() / 2 ) + arcradius * cos( angle ) + 1 );
741  ity = (int)( ( viewport->height() / 2 ) + arcradius * sin( angle ) + 1 );
742  // mDebug() << " ity: " << ity;
743  polygon.append( QPoint( itx, ity ) );
744  }
745 
746  polygon.append( horizonb );
747  }
748 }
749 
750 
751 int VectorMap::getDetailLevel( int radius ) const
752 {
753  int detail = 5;
754 
755  if ( radius > 5000 ) detail = 0;
756  else if ( radius > 2500 ) detail = 1;
757  else if ( radius > 1000 ) detail = 2;
758  else if ( radius > 600 ) detail = 3;
759  else if ( radius > 50 ) detail = 4;
760 
761  bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen;
762  return smallScreen ? qMin( 5, detail + 1 ) : detail;
763 }
Marble::RAD2DEG
const qreal RAD2DEG
Definition: MarbleGlobal.h:201
Marble::VectorMap::~VectorMap
~VectorMap()
Definition: VectorMap.cpp:40
GeoPolygon.h
Marble::GeoPainter::drawPolygon
void drawPolygon(const GeoDataLinearRing &linearRing, Qt::FillRule fillRule=Qt::OddEvenFill)
Draws a given linear ring (a "polygon without holes").
Definition: GeoPainter.cpp:560
angle
double angle(double vec1[3], double vec2[3])
Definition: sgp4ext.cpp:164
Marble::VectorMap::VectorMap
VectorMap()
Definition: VectorMap.cpp:33
Marble::GeoPainter
A painter that allows to draw geometric primitives on the map.
Definition: GeoPainter.h:98
Marble::GeoPainter::drawPolyline
void drawPolyline(const GeoDataLineString &lineString, const QString &labelText=QString(), LabelPositionFlags labelPositionFlags=LineCenter)
Draws a given line string (a "polyline").
Definition: GeoPainter.cpp:474
Marble::AbstractProjection::maxLat
qreal maxLat() const
Definition: AbstractProjection.cpp:54
Marble::ViewportParams::projection
Projection projection() const
Definition: ViewportParams.cpp:129
MarbleDebug.h
AbstractProjection.h
This file contains the headers for AbstractProjection.
Marble::ViewportParams::height
int height() const
Definition: ViewportParams.cpp:255
Marble::Quaternion::rotateAroundAxis
void rotateAroundAxis(const Quaternion &q)
Definition: Quaternion.cpp:167
Marble::ScreenPolygon::closed
bool closed() const
Definition: ScreenPolygon.h:29
Marble::Equirectangular
Flat projection ("plate carree")
Definition: MarbleGlobal.h:46
Marble::ViewportParams::width
int width() const
Definition: ViewportParams.cpp:250
Marble::PntMap
Definition: GeoPolygon.h:95
Marble::Mercator
Mercator projection.
Definition: MarbleGlobal.h:47
Marble::ScreenPolygon
Definition: ScreenPolygon.h:22
MathHelper.h
Marble::GeoPolygon
Definition: GeoPolygon.h:33
Marble::Q_Z
Definition: Quaternion.h:34
VectorMap.h
Marble::ViewportParams::currentProjection
const AbstractProjection * currentProjection() const
Definition: ViewportParams.cpp:134
Marble::GeoPolygon::Even
Definition: GeoPolygon.h:56
GeoPainter.h
MarbleGlobal.h
Marble::DEG2RAD
const qreal DEG2RAD
Definition: MarbleGlobal.h:200
Marble::ViewportParams::planetAxisMatrix
const matrix & planetAxisMatrix() const
Definition: ViewportParams.cpp:245
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::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::ViewportParams::centerLatitude
qreal centerLatitude() const
Definition: ViewportParams.cpp:294
Marble::GeoPolygon::getClosed
bool getClosed() const
Definition: GeoPolygon.h:59
Marble::GeoDataCoordinates::PtrVector
QVector< GeoDataCoordinates * > PtrVector
Definition: GeoDataCoordinates.h:103
Marble::VectorMap::paintMap
void paintMap(GeoPainter *painter)
Paint the background, i.e.
Definition: VectorMap.cpp:673
Marble::ViewportParams::radius
int radius() const
Definition: ViewportParams.cpp:195
Marble::ViewportParams::centerLongitude
qreal centerLongitude() const
Definition: ViewportParams.cpp:289
Marble::VectorMap::createFromPntMap
void createFromPntMap(const PntMap *, const ViewportParams *viewport)
Definition: VectorMap.cpp:45
Marble::Quaternion
Definition: Quaternion.h:43
Marble::MarbleGlobal::profiles
Profiles profiles() const
Definition: MarbleGlobal.cpp:48
M_PI
#define M_PI
Definition: GeoDataCoordinates.h:26
Marble::Quaternion::v
xmmfloat v
Definition: Quaternion.h:86
Marble::ScreenPolygon::setClosed
void setClosed(bool closed)
Definition: ScreenPolygon.h:30
Marble::Spherical
Spherical projection.
Definition: MarbleGlobal.h:45
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