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 }
A 3d point representation.
qreal height() const const
QString name() const override
Returns the user-visible name of the projection.
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.
A class to implement the spherical projection used by the "Globe" view.
A base class for the Gnomonic and Orthographic (Globe) projections in Marble.
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.
qreal longitude(GeoDataCoordinates::Unit unit) const
retrieves the longitude of the GeoDataCoordinates object use the unit parameter to switch between Rad...
A public class that controls what is visible in the viewport of a Marble map.
qreal altitude() const
return the altitude of the Point in meters
qreal latitude(GeoDataCoordinates::Unit unit) const
retrieves the latitude of the GeoDataCoordinates object use the unit parameter to switch between Radi...
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.
Unit
enum used constructor to specify the units used
QIcon icon() const override
Returns an icon for the projection.
VerticalPerspectiveProjection()
Construct a new VerticalPerspectiveProjection.
virtual qreal maxValidLat() const
Returns the maximum (northern) latitude that is mathematically defined and reasonable.
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)
Q_D(Todo)
qreal width() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Dec 11 2023 04:09:41 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.