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 
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 
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 }
A 3d point representation.
A class that defines a 3D bounding box for geographic data.
QRect boundingRect() 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.
int right() const const
virtual bool traversablePoles() const
Returns whether the projection allows to navigate seamlessly "over" the pole.
virtual GeoDataLatLonAltBox latLonAltBox(const QRect &screenRect, const ViewportParams *viewport) const
Returns a GeoDataLatLonAltBox bounding box of the given screenrect inside the given viewport.
qreal east(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
Get the eastern boundary of the bounding box.
A base class for all projections in Marble.
QRect intersected(const QRect &rectangle) const const
qreal north(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
Get the northern boundary of the bounding box.
int left() const const
int bottom() const const
int top() 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.
const GeoDataLatLonAltBox & latLonAltBox() const override
Returns the smallest latLonAltBox that contains the LineString.
qreal west(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
Get the western boundary of the bounding box.
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.
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.
virtual bool repeatableX() const
Returns whether the projection allows for wrapping in x direction (along the longitude scale).
virtual QPainterPath mapShape(const ViewportParams *viewport) const =0
Returns the shape/outline of a map projection.
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 bool isClippedToSphere() const
Defines whether a projection is supposed to be clipped to a certain radius.
Q_D(Todo)
QDebug mDebug()
a function to replace qDebug() in Marble library code
Definition: MarbleDebug.cpp:31
AbstractProjection()
Construct a new AbstractProjection.
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon May 8 2023 03:53:20 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.