Marble

VerticalPerspectiveProjection.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later
2//
3// SPDX-FileCopyrightText: 2014 Torsten Rahn <rahn@kde.org>
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
25namespace Marble
26{
27
28class 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
51VerticalPerspectiveProjection::VerticalPerspectiveProjection( VerticalPerspectiveProjectionPrivate *dd )
53{
54 setMinLat( minValidLat() );
55 setMaxLat( maxValidLat() );
56}
57
58VerticalPerspectiveProjection::~VerticalPerspectiveProjection()
59{
60}
61
62
63VerticalPerspectiveProjectionPrivate::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
89void 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
99qreal 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
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}
This file contains the headers for ViewportParams.
virtual qreal maxValidLat() const
Returns the maximum (northern) latitude that is mathematically defined and reasonable.
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.
A 3d point representation.
qreal altitude() const
return the altitude of the Point in meters
qreal longitude(GeoDataCoordinates::Unit unit) const
retrieves the longitude of the GeoDataCoordinates object use the unit parameter to switch between Rad...
Unit
enum used constructor to specify the units used
qreal latitude(GeoDataCoordinates::Unit unit) const
retrieves the latitude of the GeoDataCoordinates object use the unit parameter to switch between Radi...
A class to implement the spherical projection used by the "Globe" view.
QIcon icon() const override
Returns an icon for the projection.
VerticalPerspectiveProjection()
Construct a new VerticalPerspectiveProjection.
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.
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.
A public class that controls what is visible in the viewport of a Marble map.
Binds a QML item to a specific geodetic location in screen coordinates.
QString tr(const char *sourceText, const char *disambiguation, int n)
qreal height() const const
qreal width() const const
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:18:17 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.