Marble

VerticalPerspectiveProjection.cpp
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 //
3 // SPDX-FileCopyrightText: 2014 Torsten Rahn <[email protected]>
4 //
5 
6 // Local
7 #include "VerticalPerspectiveProjection.h"
8 #include "AbstractProjection_p.h"
9 
10 #include "MarbleDebug.h"
11 
12 // Marble
13 #include "ViewportParams.h"
14 #include "GeoDataPoint.h"
15 #include "GeoDataLineString.h"
16 #include "GeoDataCoordinates.h"
17 #include "MarbleGlobal.h"
18 #include "AzimuthalProjection_p.h"
19 
20 #include <QIcon>
21 #include <qmath.h>
22 
23 #define SAFE_DISTANCE
24 
25 namespace Marble
26 {
27 
28 class VerticalPerspectiveProjectionPrivate : public AzimuthalProjectionPrivate
29 {
30  public:
31  explicit VerticalPerspectiveProjectionPrivate( VerticalPerspectiveProjection * parent );
32 
33  void calculateConstants(qreal radius) const;
34 
35  mutable qreal m_P; ///< Distance of the point of perspective in earth diameters
36  mutable qreal m_previousRadius;
37  mutable qreal m_altitudeToPixel;
38  mutable qreal m_perspectiveRadius;
39  mutable qreal m_pPfactor;
40 
41  Q_DECLARE_PUBLIC( VerticalPerspectiveProjection )
42 };
43 
45  : AzimuthalProjection( new VerticalPerspectiveProjectionPrivate( this ) )
46 {
47  setMinLat( minValidLat() );
48  setMaxLat( maxValidLat() );
49 }
50 
51 VerticalPerspectiveProjection::VerticalPerspectiveProjection( VerticalPerspectiveProjectionPrivate *dd )
52  : AzimuthalProjection( dd )
53 {
54  setMinLat( minValidLat() );
55  setMaxLat( maxValidLat() );
56 }
57 
58 VerticalPerspectiveProjection::~VerticalPerspectiveProjection()
59 {
60 }
61 
62 
63 VerticalPerspectiveProjectionPrivate::VerticalPerspectiveProjectionPrivate( VerticalPerspectiveProjection * parent )
64  : AzimuthalProjectionPrivate( parent ),
65  m_P(1),
66  m_previousRadius(1),
67  m_altitudeToPixel(1),
68  m_perspectiveRadius(1),
69  m_pPfactor(1)
70 {
71 }
72 
73 
75 {
76  return QObject::tr( "Vertical Perspective Projection" );
77 }
78 
80 {
81  return QObject::tr( "<p><b>Vertical Perspective Projection</b> (\"orthogonal\")</p><p> Shows the earth as it appears from a relatively short distance above the surface. Applications: Used for Virtual Globes.</p>" );
82 }
83 
85 {
86  return QIcon(QStringLiteral(":/icons/map-globe.png"));
87 }
88 
89 void VerticalPerspectiveProjectionPrivate::calculateConstants(qreal radius) const
90 {
91  if (radius == m_previousRadius) return;
92  m_previousRadius = radius;
93  m_P = 1.5 + 3 * 1000 * 0.4 / radius / qTan(0.5 * 110 * DEG2RAD);
94  m_altitudeToPixel = radius / (EARTH_RADIUS * qSqrt((m_P-1)/(m_P+1)));
95  m_perspectiveRadius = radius / qSqrt((m_P-1)/(m_P+1));
96  m_pPfactor = (m_P+1)/(m_perspectiveRadius*m_perspectiveRadius*(m_P-1));
97 }
98 
99 qreal VerticalPerspectiveProjection::clippingRadius() const
100 {
101  return 1;
102 }
103 
105  const ViewportParams *viewport,
106  qreal &x, qreal &y, bool &globeHidesPoint ) const
107 {
109  d->calculateConstants(viewport->radius());
110  const qreal P = d->m_P;
111  const qreal deltaLambda = coordinates.longitude() - viewport->centerLongitude();
112  const qreal phi = coordinates.latitude();
113  const qreal phi1 = viewport->centerLatitude();
114 
115  qreal cosC = qSin( phi1 ) * qSin( phi ) + qCos( phi1 ) * qCos( phi ) * qCos( deltaLambda );
116 
117  // Don't display placemarks that are below 10km altitude and
118  // are on the Earth's backside (where cosC < 1/P)
119  if (cosC < 1/P && coordinates.altitude() < 10000) {
120  globeHidesPoint = true;
121  return false;
122  }
123 
124  // Let (x, y) be the position on the screen of the placemark ..
125  // First determine the position in unit coordinates:
126  qreal k = (P - 1) / (P - cosC); // scale factor
127  x = ( qCos( phi ) * qSin( deltaLambda ) ) * k;
128  y = ( qCos( phi1 ) * qSin( phi ) - qSin( phi1 ) * qCos( phi ) * qCos( deltaLambda ) ) * k;
129 
130  // Transform to screen coordinates
131  qreal pixelAltitude = (coordinates.altitude() + EARTH_RADIUS) * d->m_altitudeToPixel;
132  x *= pixelAltitude;
133  y *= pixelAltitude;
134 
135 
136  // Don't display satellites that are on the Earth's backside:
137  if (cosC < 1/P && x*x+y*y < viewport->radius() * viewport->radius()) {
138  globeHidesPoint = true;
139  return false;
140  }
141  // The remaining placemarks are definitely not on the Earth's backside
142  globeHidesPoint = false;
143 
144  x += viewport->width() / 2;
145  y = viewport->height() / 2 - y;
146 
147  // Skip placemarks that are outside the screen area
148  return !(x < 0 || x >= viewport->width() || y < 0 || y >= viewport->height());
149 }
150 
152  const ViewportParams *viewport,
153  qreal *x, qreal &y,
154  int &pointRepeatNum,
155  const QSizeF& size,
156  bool &globeHidesPoint ) const
157 {
158  pointRepeatNum = 0;
159  globeHidesPoint = false;
160 
161  bool visible = screenCoordinates( coordinates, viewport, *x, y, globeHidesPoint );
162 
163  // Skip placemarks that are outside the screen area
164  if ( *x + size.width() / 2.0 < 0.0 || *x >= viewport->width() + size.width() / 2.0
165  || y + size.height() / 2.0 < 0.0 || y >= viewport->height() + size.height() / 2.0 )
166  {
167  return false;
168  }
169 
170  // This projection doesn't have any repetitions,
171  // so the number of screen points referring to the geopoint is one.
172  pointRepeatNum = 1;
173  return visible;
174 }
175 
176 
177 bool VerticalPerspectiveProjection::geoCoordinates( const int x, const int y,
178  const ViewportParams *viewport,
179  qreal& lon, qreal& lat,
180  GeoDataCoordinates::Unit unit ) const
181 {
183  d->calculateConstants(viewport->radius());
184  const qreal P = d->m_P;
185  const qreal rx = ( - viewport->width() / 2 + x );
186  const qreal ry = ( viewport->height() / 2 - y );
187  const qreal p2 = rx*rx + ry*ry;
188 
189  if (p2 == 0) {
190  lon = viewport->centerLongitude();
191  lat = viewport->centerLatitude();
192  return true;
193  }
194 
195  const qreal pP = p2*d->m_pPfactor;
196 
197  if ( pP > 1) return false;
198 
199  const qreal p = qSqrt(p2);
200  const qreal fract = d->m_perspectiveRadius*(P-1)/p;
201  const qreal c = qAsin((P-qSqrt(1-pP))/(fract+1/fract));
202  const qreal sinc = qSin(c);
203 
204  const qreal centerLon = viewport->centerLongitude();
205  const qreal centerLat = viewport->centerLatitude();
206  lon = centerLon + qAtan2(rx*sinc, (p*qCos(centerLat)*qCos(c) - ry*qSin(centerLat)*sinc));
207 
208  while ( lon < -M_PI ) lon += 2 * M_PI;
209  while ( lon > M_PI ) lon -= 2 * M_PI;
210 
211  lat = qAsin(qCos(c)*qSin(centerLat) + (ry*sinc*qCos(centerLat))/p);
212 
213  if ( unit == GeoDataCoordinates::Degree ) {
214  lon *= RAD2DEG;
215  lat *= RAD2DEG;
216  }
217 
218  return true;
219 }
220 
221 }
Unit
enum used constructor to specify the units used
A 3d point representation.
bool screenCoordinates(const GeoDataCoordinates &coordinates, const ViewportParams *params, qreal &x, qreal &y, bool &globeHidesPoint) const override
Get the screen coordinates corresponding to geographical coordinates in the map.
QString name() const override
Returns the user-visible name of the projection.
Binds a QML item to a specific geodetic location in screen coordinates.
virtual qreal minValidLat() const
Returns the minimum (southern) latitude that is mathematically defined and reasonable.
A base class for the Gnomonic and Orthographic (Globe) projections in Marble.
bool geoCoordinates(const int x, const int y, const ViewportParams *params, qreal &lon, qreal &lat, GeoDataCoordinates::Unit unit=GeoDataCoordinates::Degree) const override
Get the earth coordinates corresponding to a pixel in the map.
QString description() const override
Returns a short user description of the projection that can be used in tooltips or dialogs...
QString tr(const char *sourceText, const char *disambiguation, int n)
qreal altitude() const
return the altitude of the Point in meters
VerticalPerspectiveProjection()
Construct a new VerticalPerspectiveProjection.
virtual qreal maxValidLat() const
Returns the maximum (northern) latitude that is mathematically defined and reasonable.
A public class that controls what is visible in the viewport of a Marble map.
This file contains the headers for ViewportParams.
Q_D(Todo)
qreal longitude(GeoDataCoordinates::Unit unit) const
retrieves the longitude of the GeoDataCoordinates object use the unit parameter to switch between Rad...
QIcon icon() const override
Returns an icon for the projection.
qreal latitude(GeoDataCoordinates::Unit unit) const
retrieves the latitude of the GeoDataCoordinates object use the unit parameter to switch between Radi...
qreal height() const const
qreal width() const const
A class to implement the spherical projection used by the "Globe" view.
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Mon Jan 17 2022 23:11:29 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.