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
9// Marble
10#include "AzimuthalProjection_p.h"
11#include "GeoDataCoordinates.h"
12#include "GeoDataLineString.h"
13#include "MarbleGlobal.h"
14#include "ViewportParams.h"
15
16#include <QIcon>
17#include <qmath.h>
18
19#define SAFE_DISTANCE
20
21namespace Marble
22{
23
24class VerticalPerspectiveProjectionPrivate : public AzimuthalProjectionPrivate
25{
26public:
27 explicit VerticalPerspectiveProjectionPrivate(VerticalPerspectiveProjection *parent);
28
29 void calculateConstants(qreal radius) const;
30
31 mutable qreal m_P; ///< Distance of the point of perspective in earth diameters
32 mutable qreal m_previousRadius;
33 mutable qreal m_altitudeToPixel;
34 mutable qreal m_perspectiveRadius;
35 mutable qreal m_pPfactor;
36
37 Q_DECLARE_PUBLIC(VerticalPerspectiveProjection)
38};
39
41 : AzimuthalProjection(new VerticalPerspectiveProjectionPrivate(this))
42{
43 setMinLat(minValidLat());
44 setMaxLat(maxValidLat());
45}
46
47VerticalPerspectiveProjection::VerticalPerspectiveProjection(VerticalPerspectiveProjectionPrivate *dd)
49{
50 setMinLat(minValidLat());
51 setMaxLat(maxValidLat());
52}
53
54VerticalPerspectiveProjection::~VerticalPerspectiveProjection() = default;
55
56VerticalPerspectiveProjectionPrivate::VerticalPerspectiveProjectionPrivate(VerticalPerspectiveProjection *parent)
57 : AzimuthalProjectionPrivate(parent)
58 , m_P(1)
59 , m_previousRadius(1)
60 , m_altitudeToPixel(1)
61 , m_perspectiveRadius(1)
62 , m_pPfactor(1)
63{
64}
65
67{
68 return QObject::tr("Vertical Perspective Projection");
69}
70
72{
73 return QObject::tr(
74 "<p><b>Vertical Perspective Projection</b> (\"orthogonal\")</p><p> Shows the earth as it appears from a relatively short distance above the surface. "
75 "Applications: Used for Virtual Globes.</p>");
76}
77
79{
80 return QIcon(QStringLiteral(":/icons/map-globe.png"));
81}
82
83void VerticalPerspectiveProjectionPrivate::calculateConstants(qreal radius) const
84{
85 if (radius == m_previousRadius)
86 return;
87 m_previousRadius = radius;
88 m_P = 1.5 + 3 * 1000 * 0.4 / radius / qTan(0.5 * 110 * DEG2RAD);
89 m_altitudeToPixel = radius / (EARTH_RADIUS * qSqrt((m_P - 1) / (m_P + 1)));
90 m_perspectiveRadius = radius / qSqrt((m_P - 1) / (m_P + 1));
91 m_pPfactor = (m_P + 1) / (m_perspectiveRadius * m_perspectiveRadius * (m_P - 1));
92}
93
94qreal VerticalPerspectiveProjection::clippingRadius() const
95{
96 return 1;
97}
98
100 const ViewportParams *viewport,
101 qreal &x,
102 qreal &y,
103 bool &globeHidesPoint) const
104{
106 d->calculateConstants(viewport->radius());
107 const qreal P = d->m_P;
108 const qreal deltaLambda = coordinates.longitude() - viewport->centerLongitude();
109 const qreal phi = coordinates.latitude();
110 const qreal phi1 = viewport->centerLatitude();
111
112 qreal cosC = qSin(phi1) * qSin(phi) + qCos(phi1) * qCos(phi) * qCos(deltaLambda);
113
114 // Don't display placemarks that are below 10km altitude and
115 // are on the Earth's backside (where cosC < 1/P)
116 if (cosC < 1 / P && coordinates.altitude() < 10000) {
117 globeHidesPoint = true;
118 return false;
119 }
120
121 // Let (x, y) be the position on the screen of the placemark ..
122 // First determine the position in unit coordinates:
123 qreal k = (P - 1) / (P - cosC); // scale factor
124 x = (qCos(phi) * qSin(deltaLambda)) * k;
125 y = (qCos(phi1) * qSin(phi) - qSin(phi1) * qCos(phi) * qCos(deltaLambda)) * k;
126
127 // Transform to screen coordinates
128 qreal pixelAltitude = (coordinates.altitude() + EARTH_RADIUS) * d->m_altitudeToPixel;
129 x *= pixelAltitude;
130 y *= pixelAltitude;
131
132 // Don't display satellites that are on the Earth's backside:
133 if (cosC < 1 / P && x * x + y * y < viewport->radius() * viewport->radius()) {
134 globeHidesPoint = true;
135 return false;
136 }
137 // The remaining placemarks are definitely not on the Earth's backside
138 globeHidesPoint = false;
139
140 x += viewport->width() / 2;
141 y = viewport->height() / 2 - y;
142
143 // Skip placemarks that are outside the screen area
144 return !(x < 0 || x >= viewport->width() || y < 0 || y >= viewport->height());
145}
146
148 const ViewportParams *viewport,
149 qreal *x,
150 qreal &y,
151 int &pointRepeatNum,
152 const QSizeF &size,
153 bool &globeHidesPoint) const
154{
155 pointRepeatNum = 0;
156 globeHidesPoint = false;
157
158 bool visible = screenCoordinates(coordinates, viewport, *x, y, globeHidesPoint);
159
160 // Skip placemarks that are outside the screen area
161 if (*x + size.width() / 2.0 < 0.0 || *x >= viewport->width() + size.width() / 2.0 || y + size.height() / 2.0 < 0.0
162 || y >= viewport->height() + size.height() / 2.0) {
163 return false;
164 }
165
166 // This projection doesn't have any repetitions,
167 // so the number of screen points referring to the geopoint is one.
168 pointRepeatNum = 1;
169 return visible;
170}
171
173 const int y,
174 const ViewportParams *viewport,
175 qreal &lon,
176 qreal &lat,
177 GeoDataCoordinates::Unit unit) const
178{
180 d->calculateConstants(viewport->radius());
181 const qreal P = d->m_P;
182 const qreal rx = (-viewport->width() / 2 + x);
183 const qreal ry = (viewport->height() / 2 - y);
184 const qreal p2 = rx * rx + ry * ry;
185
186 if (p2 == 0) {
187 lon = viewport->centerLongitude();
188 lat = viewport->centerLatitude();
189 return true;
190 }
191
192 const qreal pP = p2 * d->m_pPfactor;
193
194 if (pP > 1)
195 return false;
196
197 const qreal p = qSqrt(p2);
198 const qreal fract = d->m_perspectiveRadius * (P - 1) / p;
199 const qreal c = qAsin((P - qSqrt(1 - pP)) / (fract + 1 / fract));
200 const qreal sinc = qSin(c);
201
202 const qreal centerLon = viewport->centerLongitude();
203 const qreal centerLat = viewport->centerLatitude();
204 lon = centerLon + qAtan2(rx * sinc, (p * qCos(centerLat) * qCos(c) - ry * qSin(centerLat) * sinc));
205
206 while (lon < -M_PI)
207 lon += 2 * M_PI;
208 while (lon > M_PI)
209 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
Unit
enum used constructor to specify the units used
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 Mon Nov 4 2024 16:37:03 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.