Marble

EquirectProjection.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later
2//
3// SPDX-FileCopyrightText: 2007-2012 Torsten Rahn <rahn@kde.org>
4// SPDX-FileCopyrightText: 2007-2008 Inge Wallin <ingwa@kde.org>
5//
6
7// Local
9
10// Marble
11#include "GeoDataLatLonAltBox.h"
12#include "ViewportParams.h"
13
14#include "MarbleDebug.h"
15
16#include <QIcon>
17
18using namespace Marble;
19
26
27EquirectProjection::~EquirectProjection() = default;
28
30{
31 return QObject::tr("Flat Map");
32}
33
35{
36 return QObject::tr(
37 "<p><b>Equirectangular Projection</b> (\"Plate carrée\")</p><p>Applications: De facto standard for global texture data sets for computer "
38 "software.</p>");
39}
40
42{
43 return QIcon(QStringLiteral(":/icons/map-flat.png"));
44}
45
46bool EquirectProjection::screenCoordinates(const GeoDataCoordinates &geopoint, const ViewportParams *viewport, qreal &x, qreal &y, bool &globeHidesPoint) const
47{
48 globeHidesPoint = false;
49
50 // Convenience variables
51 int radius = viewport->radius();
52 int width = viewport->width();
53 int height = viewport->height();
54
55 qreal lon;
56 qreal lat;
57 qreal rad2Pixel = 2.0 * viewport->radius() / M_PI;
58
59 const qreal centerLon = viewport->centerLongitude();
60 const qreal centerLat = viewport->centerLatitude();
61
62 geopoint.geoCoordinates(lon, lat);
63
64 // Let (x, y) be the position on the screen of the geopoint.
65 x = ((qreal)(viewport->width()) / 2.0 + rad2Pixel * (lon - centerLon));
66 y = ((qreal)(viewport->height()) / 2.0 - rad2Pixel * (lat - centerLat));
67
68 // Return true if the calculated point is inside the screen area,
69 // otherwise return false.
70 return ((0 <= y && y < height)
71 && ((0 <= x && x < width) || (0 <= x - 4 * radius && x - 4 * radius < width) || (0 <= x + 4 * radius && x + 4 * radius < width)));
72}
73
75 const ViewportParams *viewport,
76 qreal *x,
77 qreal &y,
78 int &pointRepeatNum,
79 const QSizeF &size,
80 bool &globeHidesPoint) const
81{
82 pointRepeatNum = 0;
83 // On flat projections the observer's view onto the point won't be
84 // obscured by the target planet itself.
85 globeHidesPoint = false;
86
87 // Convenience variables
88 int radius = viewport->radius();
89 auto width = (qreal)(viewport->width());
90 auto height = (qreal)(viewport->height());
91
92 // Let (itX, y) be the first guess for one possible position on screen.
93 qreal itX;
94 screenCoordinates(coordinates, viewport, itX, y);
95
96 // Make sure that the requested point is within the visible y range:
97 if (0 <= y + size.height() / 2.0 && y < height + size.height() / 2.0) {
98 // For the repetition case the same geopoint gets displayed on
99 // the map many times.across the longitude.
100
101 int xRepeatDistance = 4 * radius;
102
103 // Finding the leftmost positive x value
104 if (itX + size.width() > xRepeatDistance) {
105 const int repeatNum = (int)((itX + size.width()) / xRepeatDistance);
106 itX = itX - repeatNum * xRepeatDistance;
107 }
108 if (itX + size.width() / 2.0 < 0) {
109 itX += xRepeatDistance;
110 }
111 // The requested point is out of the visible x range:
112 if (itX > width + size.width() / 2.0) {
113 return false;
114 }
115
116 // Now iterate through all visible x screen coordinates for the point
117 // from left to right.
118 int itNum = 0;
119 while (itX - size.width() / 2.0 < width) {
120 *x = itX;
121 ++x;
122 ++itNum;
123 itX += xRepeatDistance;
124 }
125
126 pointRepeatNum = itNum;
127
128 return true;
129 }
130
131 // The requested point is out of the visible y range.
132 return false;
133}
134
135bool EquirectProjection::geoCoordinates(const int x, const int y, const ViewportParams *viewport, qreal &lon, qreal &lat, GeoDataCoordinates::Unit unit) const
136{
137 const int radius = viewport->radius();
138 const qreal pixel2Rad = M_PI / (2.0 * radius);
139
140 // Get the Lat and Lon of the center point of the screen.
141 const qreal centerLon = viewport->centerLongitude();
142 const qreal centerLat = viewport->centerLatitude();
143
144 {
145 const int halfImageWidth = viewport->width() / 2;
146 const int xPixels = x - halfImageWidth;
147
148 lon = +xPixels * pixel2Rad + centerLon;
149
150 while (lon > M_PI)
151 lon -= 2.0 * M_PI;
152 while (lon < -M_PI)
153 lon += 2.0 * M_PI;
154
155 if (unit == GeoDataCoordinates::Degree) {
156 lon *= RAD2DEG;
157 }
158 }
159
160 {
161 // Get yTop and yBottom, the limits of the map on the screen.
162 const int halfImageHeight = viewport->height() / 2;
163 const int yCenterOffset = (int)(centerLat * (qreal)(2 * radius) / M_PI);
164 const int yTop = halfImageHeight - radius + yCenterOffset;
165 const int yBottom = yTop + 2 * radius;
166
167 // Return here if the y coordinate is outside the map
168 if (yTop <= y && y < yBottom) {
169 const int yPixels = y - halfImageHeight;
170 lat = -yPixels * pixel2Rad + centerLat;
171
172 if (unit == GeoDataCoordinates::Degree) {
173 lat *= RAD2DEG;
174 }
175
176 return true;
177 }
178 }
179
180 return false;
181}
182
184{
185 qreal west;
186 qreal north = 90 * DEG2RAD;
187 geoCoordinates(screenRect.left(), screenRect.top(), viewport, west, north, GeoDataCoordinates::Radian);
188
189 qreal east;
190 qreal south = -90 * DEG2RAD;
191 geoCoordinates(screenRect.right(), screenRect.bottom(), viewport, east, south, GeoDataCoordinates::Radian);
192
193 // For the case where the whole viewport gets covered there is a
194 // pretty dirty and generic detection algorithm:
196 latLonAltBox.setNorth(north, GeoDataCoordinates::Radian);
197 latLonAltBox.setSouth(south, GeoDataCoordinates::Radian);
198 latLonAltBox.setWest(west, GeoDataCoordinates::Radian);
199 latLonAltBox.setEast(east, GeoDataCoordinates::Radian);
200 latLonAltBox.setMinAltitude(-100000000.0);
201 latLonAltBox.setMaxAltitude(100000000000000.0);
202
203 // Convenience variables
204 int radius = viewport->radius();
205 int width = viewport->width();
206
207 // The remaining algorithm should be pretty generic for all kinds of
208 // flat projections:
209
210 int xRepeatDistance = 4 * radius;
211 if (width >= xRepeatDistance) {
212 latLonAltBox.setWest(-M_PI);
213 latLonAltBox.setEast(+M_PI);
214 }
215
216 // Now we need to check whether maxLat (e.g. the north pole) gets displayed
217 // inside the viewport.
218
219 // We need a point on the screen at maxLat that definitely gets displayed:
220 qreal averageLongitude = latLonAltBox.east();
221
222 GeoDataCoordinates maxLatPoint(averageLongitude, maxLat(), 0.0, GeoDataCoordinates::Radian);
223 GeoDataCoordinates minLatPoint(averageLongitude, minLat(), 0.0, GeoDataCoordinates::Radian);
224
225 qreal dummyX, dummyY; // not needed
226
227 if (screenCoordinates(maxLatPoint, viewport, dummyX, dummyY)) {
228 latLonAltBox.setEast(+M_PI);
229 latLonAltBox.setWest(-M_PI);
230 }
231 if (screenCoordinates(minLatPoint, viewport, dummyX, dummyY)) {
232 latLonAltBox.setEast(+M_PI);
233 latLonAltBox.setWest(-M_PI);
234 }
235
236 return latLonAltBox;
237}
238
240{
241 // Convenience variables
242 int radius = viewport->radius();
243 // int width = viewport->width();
244 int height = viewport->height();
245 int halfImageHeight = viewport->height() / 2;
246
247 // Get the Lat and Lon of the center point of the screen.
248 const qreal centerLat = viewport->centerLatitude();
249
250 // Calculate how many pixel are being represented per radians.
251 const float rad2Pixel = (qreal)(2 * radius) / M_PI;
252
253 // Get yTop and yBottom, the limits of the map on the screen.
254 int yCenterOffset = (int)(centerLat * rad2Pixel);
255 int yTop = halfImageHeight - radius + yCenterOffset;
256 int yBottom = yTop + 2 * radius;
257
258 return !(yTop >= 0 || yBottom < height);
259}
This file contains the headers for EquirectProjection.
This file contains the headers for ViewportParams.
qreal minLat() const
Returns the arbitrarily chosen minimum (southern) latitude.
qreal maxLat() const
Returns the arbitrarily chosen maximum (northern) latitude.
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 Equirectangular and Mercator projections in Marble.
bool mapCoversViewport(const ViewportParams *viewport) const override
Returns whether the projected data fully obstructs the current viewport.
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.
GeoDataLatLonAltBox latLonAltBox(const QRect &screenRect, const ViewportParams *viewport) const override
Returns a GeoDataLatLonAltBox bounding box of the given screenrect inside the given viewport.
QIcon icon() const override
Returns an icon for the projection.
QString description() const override
Returns a short user description of the projection that can be used in tooltips or dialogs.
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.
EquirectProjection()
Construct a new EquirectProjection.
A 3d point representation.
Unit
enum used constructor to specify the units used
void geoCoordinates(qreal &lon, qreal &lat, GeoDataCoordinates::Unit unit) const
use this function to get the longitude and latitude with one call - use the unit parameter to switch ...
A class that defines a 3D bounding box for geographic data.
qreal east(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
Get the eastern boundary of the bounding box.
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)
int bottom() const const
int left() const const
int right() const const
int top() const const
qreal height() const const
qreal width() const const
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.