Marble

AbstractProjection.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later
2//
3// SPDX-FileCopyrightText: 2007 Inge Wallin <ingwa@kde.org>
4// SPDX-FileCopyrightText: 2007-2012 Torsten Rahn <rahn@kde.org>
5// SPDX-FileCopyrightText: 2012 Cezar Mocan <mocancezar@gmail.com>
6//
7
8// Local
10
11#include "AbstractProjection_p.h"
12
13#include "MarbleDebug.h"
14#include <QPainterPath>
15#include <QRegion>
16
17// Marble
18#include "GeoDataLatLonAltBox.h"
19#include "GeoDataLineString.h"
20#include "GeoDataLinearRing.h"
21#include "ViewportParams.h"
22
23using namespace Marble;
24
26 : d_ptr(new AbstractProjectionPrivate(this))
27{
28}
29
30AbstractProjection::AbstractProjection(AbstractProjectionPrivate *dd)
31 : d_ptr(dd)
32{
33}
34
35AbstractProjection::~AbstractProjection() = default;
36
37AbstractProjectionPrivate::AbstractProjectionPrivate(AbstractProjection *parent)
38 : m_maxLat(0)
39 , m_minLat(0)
40 , m_previousResolution(-1)
41 , m_level(-1)
42 , q_ptr(parent)
43{
44}
45
46int AbstractProjectionPrivate::levelForResolution(qreal resolution) const
47{
48 if (m_previousResolution == resolution)
49 return m_level;
50
51 m_previousResolution = resolution;
52
53 if (resolution < 0.0000005)
54 m_level = 17;
55 else if (resolution < 0.0000010)
56 m_level = 16;
57 else if (resolution < 0.0000020)
58 m_level = 15;
59 else if (resolution < 0.0000040)
60 m_level = 14;
61 else if (resolution < 0.0000080)
62 m_level = 13;
63 else if (resolution < 0.0000160)
64 m_level = 12;
65 else if (resolution < 0.0000320)
66 m_level = 11;
67 else if (resolution < 0.0000640)
68 m_level = 10;
69 else if (resolution < 0.0001280)
70 m_level = 9;
71 else if (resolution < 0.0002560)
72 m_level = 8;
73 else if (resolution < 0.0005120)
74 m_level = 7;
75 else if (resolution < 0.0010240)
76 m_level = 6;
77 else if (resolution < 0.0020480)
78 m_level = 5;
79 else if (resolution < 0.0040960)
80 m_level = 4;
81 else if (resolution < 0.0081920)
82 m_level = 3;
83 else if (resolution < 0.0163840)
84 m_level = 2;
85 else
86 m_level = 1;
87
88 return m_level;
89}
90
92{
93 return +90.0 * DEG2RAD;
94}
95
97{
99 return d->m_maxLat;
100}
101
102void AbstractProjection::setMaxLat(qreal maxLat)
103{
104 if (maxLat < maxValidLat()) {
105 mDebug() << "Trying to set maxLat to a value that is out of the valid range.";
106 return;
107 }
108
110 d->m_maxLat = maxLat;
111}
112
114{
115 return -90.0 * DEG2RAD;
116}
117
119{
120 Q_D(const AbstractProjection);
121 return d->m_minLat;
122}
123
124void AbstractProjection::setMinLat(qreal minLat)
125{
126 if (minLat < minValidLat()) {
127 mDebug() << "Trying to set minLat to a value that is out of the valid range.";
128 return;
129 }
130
132 d->m_minLat = minLat;
133}
134
136{
137 return false;
138}
139
141{
142 return false;
143}
144
145bool AbstractProjection::traversableDateLine() const
146{
147 return false;
148}
149
150AbstractProjection::PreservationType AbstractProjection::preservationType() const
151{
152 return NoPreservation;
153}
154
155bool AbstractProjection::isOrientedNormal() const
156{
157 return true;
158}
159
161{
162 return false;
163}
164
165qreal AbstractProjection::clippingRadius() const
166{
167 return 0;
169
170bool AbstractProjection::screenCoordinates(const qreal lon, const qreal lat, const ViewportParams *viewport, qreal &x, qreal &y) const
171{
172 bool globeHidesPoint;
173 GeoDataCoordinates geopoint(lon, lat);
174 return screenCoordinates(geopoint, viewport, x, y, globeHidesPoint);
175}
176
177bool AbstractProjection::screenCoordinates(const GeoDataCoordinates &geopoint, const ViewportParams *viewport, qreal &x, qreal &y) const
178{
179 bool globeHidesPoint;
180
181 return screenCoordinates(geopoint, viewport, x, y, globeHidesPoint);
182}
183
185{
186 // For the case where the whole viewport gets covered there is a
187 // pretty dirty and generic detection algorithm:
188
189 // Move along the screenborder and save the highest and lowest lon-lat values.
190 QRect projectedRect = mapRegion(viewport).boundingRect();
191 QRect mapRect = screenRect.intersected(projectedRect);
192
193 GeoDataLineString boundingLineString;
194
195 qreal lon, lat;
196
197 for (int x = mapRect.left(); x < mapRect.right(); x += latLonAltBoxSamplingRate) {
198 if (geoCoordinates(x, mapRect.bottom(), viewport, lon, lat, GeoDataCoordinates::Radian)) {
199 boundingLineString << GeoDataCoordinates(lon, lat);
200 }
201
202 if (geoCoordinates(x, mapRect.top(), viewport, lon, lat, GeoDataCoordinates::Radian)) {
203 boundingLineString << GeoDataCoordinates(lon, lat);
204 }
205 }
206
207 if (geoCoordinates(mapRect.right(), mapRect.top(), viewport, lon, lat, GeoDataCoordinates::Radian)) {
208 boundingLineString << GeoDataCoordinates(lon, lat);
209 }
210
211 if (geoCoordinates(mapRect.right(), mapRect.bottom(), viewport, lon, lat, GeoDataCoordinates::Radian)) {
212 boundingLineString << GeoDataCoordinates(lon, lat);
213 }
214
215 for (int y = mapRect.bottom(); y < mapRect.top(); y += latLonAltBoxSamplingRate) {
216 if (geoCoordinates(mapRect.left(), y, viewport, lon, lat, GeoDataCoordinates::Radian)) {
217 boundingLineString << GeoDataCoordinates(lon, lat);
218 }
219
220 if (geoCoordinates(mapRect.right(), y, viewport, lon, lat, GeoDataCoordinates::Radian)) {
221 boundingLineString << GeoDataCoordinates(lon, lat);
222 }
223 }
224
225 GeoDataLatLonAltBox latLonAltBox = boundingLineString.latLonAltBox();
226
227 // Now we need to check whether maxLat (e.g. the north pole) gets displayed
228 // inside the viewport.
229
230 // We need a point on the screen at maxLat that definitely gets displayed:
231
232 // FIXME: Some of the following code can be safely removed as soon as we properly handle
233 // GeoDataLinearRing::latLonAltBox().
234 qreal averageLongitude = (latLonAltBox.west() + latLonAltBox.east()) / 2.0;
235
236 GeoDataCoordinates maxLatPoint(averageLongitude, maxLat(), 0.0, GeoDataCoordinates::Radian);
237 GeoDataCoordinates minLatPoint(averageLongitude, minLat(), 0.0, GeoDataCoordinates::Radian);
238
239 qreal dummyX, dummyY; // not needed
240
241 if (latLonAltBox.north() > maxLat() || screenCoordinates(maxLatPoint, viewport, dummyX, dummyY)) {
242 latLonAltBox.setNorth(maxLat());
243 }
244 if (latLonAltBox.north() < minLat() || screenCoordinates(minLatPoint, viewport, dummyX, dummyY)) {
245 latLonAltBox.setSouth(minLat());
246 }
247
248 latLonAltBox.setMinAltitude(-100000000.0);
249 latLonAltBox.setMaxAltitude(100000000000000.0);
250
251 return latLonAltBox;
252}
253
254QRegion AbstractProjection::mapRegion(const ViewportParams *viewport) const
255{
256 return QRegion(mapShape(viewport).toFillPolygon().toPolygon());
257}
This file contains the headers for AbstractProjection.
This file contains the headers for ViewportParams.
A base class for all projections in Marble.
qreal minLat() const
Returns the arbitrarily chosen minimum (southern) latitude.
bool screenCoordinates(const qreal lon, const qreal lat, const ViewportParams *viewport, qreal &x, qreal &y) const
Get the screen coordinates corresponding to geographical coordinates in the map.
qreal maxLat() const
Returns the arbitrarily chosen maximum (northern) latitude.
virtual bool geoCoordinates(const int x, const int y, const ViewportParams *viewport, qreal &lon, qreal &lat, GeoDataCoordinates::Unit unit=GeoDataCoordinates::Degree) const =0
Get the earth coordinates corresponding to a pixel in the map.
virtual QPainterPath mapShape(const ViewportParams *viewport) const =0
Returns the shape/outline of a map projection.
virtual bool traversablePoles() const
Returns whether the projection allows to navigate seamlessly "over" the pole.
virtual qreal maxValidLat() const
Returns the maximum (northern) latitude that is mathematically defined and reasonable.
virtual bool isClippedToSphere() const
Defines whether a projection is supposed to be clipped to a certain radius.
virtual bool repeatableX() const
Returns whether the projection allows for wrapping in x direction (along the longitude scale).
virtual GeoDataLatLonAltBox latLonAltBox(const QRect &screenRect, const ViewportParams *viewport) const
Returns a GeoDataLatLonAltBox bounding box of the given screenrect inside the given viewport.
AbstractProjection()
Construct a new AbstractProjection.
virtual qreal minValidLat() const
Returns the minimum (southern) latitude that is mathematically defined and reasonable.
A 3d point representation.
A class that defines a 3D bounding box for geographic data.
qreal north(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
Get the northern boundary of the bounding box.
qreal east(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
Get the eastern boundary of the bounding box.
qreal west(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
Get the western boundary of the bounding box.
A LineString that allows to store a contiguous set of line segments.
const GeoDataLatLonAltBox & latLonAltBox() const override
Returns the smallest latLonAltBox that contains the LineString.
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.
int bottom() const const
QRect intersected(const QRect &rectangle) const const
int left() const const
int right() const const
int top() const const
QRect boundingRect() const const
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Nov 8 2024 12:02:44 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.