Marble

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

KDE's Doxygen guidelines are available online.