Marble

ViewportParams.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later
2//
3// SPDX-FileCopyrightText: 2007 Inge Wallin <ingwa@kde.org>
4// SPDX-FileCopyrightText: 2008 Jens-Michael Hoffmann <jensmh@gmx.de>
5// SPDX-FileCopyrightText: 2010-2013 Bernhard Beschow <bbeschow@cs.tu-berlin.de>
6//
7
8
9#include "ViewportParams.h"
10
11#include <QRect>
12
13#include <QPainterPath>
14#include <QRegion>
15
16#include "MarbleDebug.h"
17#include "GeoDataLatLonAltBox.h"
18#include "SphericalProjection.h"
19#include "EquirectProjection.h"
20#include "MercatorProjection.h"
21#include "GnomonicProjection.h"
22#include "LambertAzimuthalProjection.h"
23#include "AzimuthalEquidistantProjection.h"
24#include "StereographicProjection.h"
25#include "VerticalPerspectiveProjection.h"
26
27
28namespace Marble
29{
30
31class ViewportParamsPrivate
32{
33public:
34 ViewportParamsPrivate( Projection projection,
35 qreal centerLongitude, qreal centerLatitude,
36 int radius,
37 const QSize &size );
38
39 static const AbstractProjection *abstractProjection( Projection projection );
40
41 // These two go together. m_currentProjection points to one of
42 // the static Projection classes at the bottom.
43 Projection m_projection;
44 const AbstractProjection *m_currentProjection;
45
46 // Parameters that determine the painting
47 qreal m_centerLongitude;
48 qreal m_centerLatitude;
49 qreal m_heading;
50 Quaternion m_planetAxis; // Position, coded in a quaternion
51 matrix m_planetAxisMatrix;
52 int m_radius; // Zoom level (pixels / globe radius)
53 qreal m_angularResolution;
54
55 QSize m_size; // width, height
56
57
58 bool m_dirtyBox;
59 GeoDataLatLonAltBox m_viewLatLonAltBox;
60
61 static const SphericalProjection s_sphericalProjection;
62 static const EquirectProjection s_equirectProjection;
63 static const MercatorProjection s_mercatorProjection;
64 static const GnomonicProjection s_gnomonicProjection;
65 static const StereographicProjection s_stereographicProjection;
66 static const LambertAzimuthalProjection s_lambertAzimuthalProjection;
67 static const AzimuthalEquidistantProjection s_azimuthalEquidistantProjection;
68 static const VerticalPerspectiveProjection s_verticalPerspectiveProjection;
69
70 GeoDataCoordinates m_focusPoint;
71};
72
73const SphericalProjection ViewportParamsPrivate::s_sphericalProjection;
74const EquirectProjection ViewportParamsPrivate::s_equirectProjection;
75const MercatorProjection ViewportParamsPrivate::s_mercatorProjection;
76const GnomonicProjection ViewportParamsPrivate::s_gnomonicProjection;
77const StereographicProjection ViewportParamsPrivate::s_stereographicProjection;
78const LambertAzimuthalProjection ViewportParamsPrivate::s_lambertAzimuthalProjection;
79const AzimuthalEquidistantProjection ViewportParamsPrivate::s_azimuthalEquidistantProjection;
80const VerticalPerspectiveProjection ViewportParamsPrivate::s_verticalPerspectiveProjection;
81
82ViewportParamsPrivate::ViewportParamsPrivate( Projection projection,
83 qreal centerLongitude, qreal centerLatitude,
84 int radius,
85 const QSize &size )
86 : m_projection( projection ),
87 m_currentProjection( abstractProjection( projection ) ),
88 m_centerLongitude( centerLongitude ),
89 m_centerLatitude( centerLatitude ),
90 m_heading( 0 ),
91 m_planetAxis(),
92 m_planetAxisMatrix(),
93 m_radius( radius ),
94 m_angularResolution(4.0 / abs(m_radius)),
95 m_size( size ),
96 m_dirtyBox( true ),
97 m_viewLatLonAltBox()
98{
99}
100
101const AbstractProjection *ViewportParamsPrivate::abstractProjection(Projection projection)
102{
103 switch ( projection ) {
104 case Spherical:
105 return &s_sphericalProjection;
106 case Equirectangular:
107 return &s_equirectProjection;
108 case Mercator:
109 return &s_mercatorProjection;
110 case Gnomonic:
111 return &s_gnomonicProjection;
112 case Stereographic:
113 return &s_stereographicProjection;
114 case LambertAzimuthal:
115 return &s_lambertAzimuthalProjection;
117 return &s_azimuthalEquidistantProjection;
119 return &s_verticalPerspectiveProjection;
120 }
121
122 return nullptr;
123}
124
125
126ViewportParams::ViewportParams()
127 : d( new ViewportParamsPrivate( Spherical, 0, 0, 2000, QSize( 100, 100 ) ) )
128{
129 centerOn( d->m_centerLongitude, d->m_centerLatitude );
130}
131
132ViewportParams::ViewportParams( Projection projection,
133 qreal centerLongitude, qreal centerLatitude,
134 int radius,
135 const QSize &size )
136 : d( new ViewportParamsPrivate( projection, centerLongitude, centerLatitude, radius, size ) )
137{
138 centerOn( d->m_centerLongitude, d->m_centerLatitude );
139}
140
141ViewportParams::~ViewportParams()
142{
143 delete d;
144}
145
146
147// ================================================================
148// Getters and setters
149
150
151Projection ViewportParams::projection() const
152{
153 return d->m_projection;
154}
155
156const AbstractProjection *ViewportParams::currentProjection() const
157{
158 return d->m_currentProjection;
159}
160
161void ViewportParams::setProjection(Projection newProjection)
162{
163 d->m_projection = newProjection;
164 d->m_currentProjection = ViewportParamsPrivate::abstractProjection( newProjection );
165
166 // We now need to reset the planetAxis to make sure
167 // that it's a valid axis orientation!
168 // So this line is important (although it might look odd) ! :
169 centerOn( d->m_centerLongitude, d->m_centerLatitude );
170}
171
172int ViewportParams::polarity() const
173{
174 // For mercator this just gives the extreme latitudes
175 // instead of the actual poles but it works fine as well:
176 GeoDataCoordinates northPole( 0.0, +currentProjection()->maxLat() );
177 GeoDataCoordinates southPole( 0.0, -currentProjection()->maxLat() );
178
179 bool globeHidesN, globeHidesS;
180 qreal x;
181 qreal yN, yS;
182
183 currentProjection()->screenCoordinates( northPole, this,
184 x, yN, globeHidesN );
185 currentProjection()->screenCoordinates( southPole, this,
186 x, yS, globeHidesS );
187
188 int polarity = 0;
189
190 // case of the flat map:
191 if ( !globeHidesN && !globeHidesS ) {
192 if ( yN < yS ) {
193 polarity = +1;
194 }
195 if ( yS < yN ) {
196 polarity = -1;
197 }
198 }
199 else {
200 if ( !globeHidesN && yN < height() / 2 ) {
201 polarity = +1;
202 }
203 if ( !globeHidesN && yN > height() / 2 ) {
204 polarity = -1;
205 }
206 if ( !globeHidesS && yS > height() / 2 ) {
207 polarity = +1;
208 }
209 if ( !globeHidesS && yS < height() / 2 ) {
210 polarity = -1;
211 }
212 }
213
214 return polarity;
215}
216
217int ViewportParams::radius() const
218{
219 return d->m_radius;
220}
221
222void ViewportParams::setRadius(int newRadius)
223{
224 if ( newRadius > 0 ) {
225 d->m_dirtyBox = true;
226
227 d->m_radius = newRadius;
228 d->m_angularResolution = 4.0 / d->m_radius;
229 }
230}
231
232void ViewportParams::centerOn( qreal lon, qreal lat )
233{
234 if ( !d->m_currentProjection->traversablePoles() ) {
235 if ( lat > d->m_currentProjection->maxLat() )
236 lat = d->m_currentProjection->maxLat();
237
238 if ( lat < d->m_currentProjection->minLat() )
239 lat = d->m_currentProjection->minLat();
240 } else {
241 while ( lat > M_PI )
242 lat -= 2 * M_PI;
243 while ( lat < -M_PI )
244 lat += 2 * M_PI;
245 }
246
247 while ( lon > M_PI )
248 lon -= 2 * M_PI;
249 while ( lon < -M_PI )
250 lon += 2 * M_PI;
251
252 d->m_centerLongitude = lon;
253 d->m_centerLatitude = lat;
254
255 const Quaternion roll = Quaternion::fromEuler( 0, 0, d->m_heading );
256 const Quaternion quat = Quaternion::fromEuler( -lat, lon, 0.0 );
257
258 d->m_planetAxis = quat * roll;
259 d->m_planetAxis.normalize();
260
261 d->m_dirtyBox = true;
262 d->m_planetAxis.inverse().toMatrix( d->m_planetAxisMatrix );
263 d->m_planetAxis.normalize();
264}
265
266void ViewportParams::setHeading( qreal heading )
267{
268 d->m_heading = heading;
269
270 const Quaternion roll = Quaternion::fromEuler( 0, 0, heading );
271
272 const qreal centerLat = centerLatitude();
273 const qreal centerLon = centerLongitude();
274
275 const Quaternion quat = Quaternion::fromEuler( -centerLat, centerLon, 0 );
276
277 d->m_planetAxis = quat * roll;
278 d->m_planetAxis.normalize();
279
280 d->m_dirtyBox = true;
281 d->m_planetAxis.inverse().toMatrix( d->m_planetAxisMatrix );
282 d->m_planetAxis.normalize();
283}
284
285qreal ViewportParams::heading() const
286{
287 return d->m_heading;
288}
289
290Quaternion ViewportParams::planetAxis() const
291{
292 return d->m_planetAxis;
293}
294
295const matrix &ViewportParams::planetAxisMatrix() const
296{
297 return d->m_planetAxisMatrix;
298}
299
300int ViewportParams::width() const
301{
302 return d->m_size.width();
303}
304
305int ViewportParams::height() const
306{
307 return d->m_size.height();
308}
309
310QSize ViewportParams::size() const
311{
312 return d->m_size;
313}
314
315
316void ViewportParams::setWidth(int newWidth)
317{
318 setSize( QSize( newWidth, height() ) );
319}
320
321void ViewportParams::setHeight(int newHeight)
322{
323 setSize( QSize( width(), newHeight ) );
324}
325
326void ViewportParams::setSize(const QSize& newSize)
327{
328 if ( newSize == d->m_size )
329 return;
330
331 d->m_dirtyBox = true;
332
333 d->m_size = newSize;
334}
335
336// ================================================================
337// Other functions
338
339qreal ViewportParams::centerLongitude() const
340{
341 return d->m_centerLongitude;
342}
343
344qreal ViewportParams::centerLatitude() const
345{
346 return d->m_centerLatitude;
347}
348
349const GeoDataLatLonAltBox& ViewportParams::viewLatLonAltBox() const
350{
351 if (d->m_dirtyBox) {
352 d->m_viewLatLonAltBox = d->m_currentProjection->latLonAltBox( QRect( QPoint( 0, 0 ),
353 d->m_size ),
354 this );
355 d->m_dirtyBox = false;
356 }
357
358 return d->m_viewLatLonAltBox;
359}
360
361GeoDataLatLonAltBox ViewportParams::latLonAltBox( const QRect &screenRect ) const
362{
363 return d->m_currentProjection->latLonAltBox( screenRect, this );
364}
365
366qreal ViewportParams::angularResolution() const
367{
368 // We essentially divide the diameter by 180 deg and
369 // take half of the result as a guess for the angle per pixel resolution.
370 // d->m_angularResolution = 0.25 * M_PI / fabs( (qreal)(d->m_radius);
371 return d->m_angularResolution;
372}
373
374bool ViewportParams::resolves ( const GeoDataLatLonBox &latLonBox, qreal pixel ) const
375{
376 return latLonBox.width() + latLonBox.height() > pixel * d->m_angularResolution;
377}
378
379
380bool ViewportParams::resolves ( const GeoDataLatLonAltBox &latLonAltBox, qreal pixel, qreal altitude ) const
381{
382 return latLonAltBox.width() + latLonAltBox.height() > pixel * d->m_angularResolution
383 || latLonAltBox.maxAltitude() - latLonAltBox.minAltitude() > altitude;
384}
385
386bool ViewportParams::resolves ( const GeoDataCoordinates &coord1,
387 const GeoDataCoordinates &coord2 ) const
388{
389 qreal lon1, lat1;
390 coord1.geoCoordinates( lon1, lat1 );
391
392 qreal lon2, lat2;
393 coord2.geoCoordinates( lon2, lat2 );
394
395 // We take the manhattan length as an approximation for the distance
396 return ( fabs( lon2 - lon1 ) + fabs( lat2 - lat1 ) > d->m_angularResolution );
397}
398
399
400bool ViewportParams::screenCoordinates( const qreal lon, const qreal lat,
401 qreal &x, qreal &y ) const
402{
403 return d->m_currentProjection->screenCoordinates( lon, lat, this, x, y );
404}
405
406bool ViewportParams::screenCoordinates( const GeoDataCoordinates &geopoint,
407 qreal &x, qreal &y,
408 bool &globeHidesPoint ) const
409{
410 return d->m_currentProjection->screenCoordinates( geopoint, this, x, y, globeHidesPoint );
411}
412
413bool ViewportParams::screenCoordinates( const GeoDataCoordinates &geopoint,
414 qreal &x, qreal &y ) const
415{
416 return d->m_currentProjection->screenCoordinates( geopoint, this, x, y );
417}
418
419bool ViewportParams::screenCoordinates( const GeoDataCoordinates &coordinates,
420 qreal *x, qreal &y, int &pointRepeatNum,
421 const QSizeF& size,
422 bool &globeHidesPoint ) const
423{
424 return d->m_currentProjection->screenCoordinates( coordinates, this, x, y, pointRepeatNum, size, globeHidesPoint );
425}
426
427
428bool ViewportParams::screenCoordinates( const GeoDataLineString &lineString,
429 QVector<QPolygonF*> &polygons ) const
430{
431 return d->m_currentProjection->screenCoordinates( lineString, this, polygons );
432}
433
434bool ViewportParams::geoCoordinates( const int x, const int y,
435 qreal &lon, qreal &lat,
436 GeoDataCoordinates::Unit unit ) const
437{
438 return d->m_currentProjection->geoCoordinates( x, y, this, lon, lat, unit );
439}
440
441bool ViewportParams::mapCoversViewport() const
442{
443 return d->m_currentProjection->mapCoversViewport( this );
444}
445
446QPainterPath ViewportParams::mapShape() const
447{
448 return d->m_currentProjection->mapShape( this );
449}
450
451QRegion ViewportParams::mapRegion() const
452{
453 return d->m_currentProjection->mapRegion( this );
454}
455
456GeoDataCoordinates ViewportParams::focusPoint() const
457{
458 if (d->m_focusPoint.isValid()) {
459 return d->m_focusPoint;
460 }
461 else {
462 const qreal lon = d->m_centerLongitude;
463 const qreal lat = d->m_centerLatitude;
464
465 return GeoDataCoordinates(lon, lat, 0.0, GeoDataCoordinates::Radian);
466 }
467
468}
469
470void ViewportParams::setFocusPoint(const GeoDataCoordinates &focusPoint)
471{
472 d->m_focusPoint = focusPoint;
473}
474
475void ViewportParams::resetFocusPoint()
476{
477 d->m_focusPoint = GeoDataCoordinates();
478}
479
480}
This file contains the headers for EquirectProjection.
This file contains the headers for MercatorProjection.
This file contains the headers for SphericalProjection.
This file contains the headers for ViewportParams.
A 3d point representation.
Unit
enum used constructor to specify the units used
A LineString that allows to store a contiguous set of line segments.
QAction * roll(const QObject *recvr, const char *slot, QObject *parent)
Binds a QML item to a specific geodetic location in screen coordinates.
@ Mercator
Mercator projection.
@ VerticalPerspective
Vertical perspective projection.
@ AzimuthalEquidistant
Azimuthal Equidistant projection.
@ Gnomonic
Gnomonic projection.
@ LambertAzimuthal
Lambert Azimuthal Equal-Area projection.
@ Equirectangular
Flat projection ("plate carree")
@ Spherical
Spherical projection ("Orthographic")
@ Stereographic
Stereographic projection.
int width() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jun 14 2024 11:54:17 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.