Marble

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

KDE's Doxygen guidelines are available online.