1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 //
3 // SPDX-FileCopyrightText: 2007 Andrew Manson <g.real.ate@gmail.com>
4 // SPDX-FileCopyrightText: 2008 Torsten Rahn <rahn@kde.org>
5 //
6
7
8 #include "GeoDataLatLonAltBox.h"
9
10 #include "MarbleDebug.h"
11 #include "GeoDataCoordinates.h"
12 #include "GeoDataLineString.h"
13
14 #include "GeoDataTypes.h"
15
16 #include <QDataStream>
17
18 namespace Marble
19 {
20
21 class GeoDataLatLonAltBoxPrivate
22 {
23 public:
GeoDataLatLonAltBoxPrivate()24 GeoDataLatLonAltBoxPrivate()
25 : m_minAltitude( 0 ),
26 m_maxAltitude( 0 ),
27 m_altitudeMode( ClampToGround )
28 {
29 }
30
31 qreal m_minAltitude;
32 qreal m_maxAltitude;
33 AltitudeMode m_altitudeMode;
34 };
35
operator ==(GeoDataLatLonAltBox const & lhs,GeoDataLatLonAltBox const & rhs)36 bool operator==( GeoDataLatLonAltBox const& lhs, GeoDataLatLonAltBox const& rhs )
37 {
38 return lhs.west() == rhs.west() &&
39 lhs.east() == rhs.east() &&
40 lhs.north() == rhs.north() &&
41 lhs.south() == rhs.south() &&
42 lhs.rotation() == rhs.rotation() &&
43 lhs.d->m_minAltitude == rhs.d->m_minAltitude &&
44 lhs.d->m_maxAltitude == rhs.d->m_maxAltitude &&
45 lhs.d->m_altitudeMode == rhs.d->m_altitudeMode;
46 }
47
operator =(const GeoDataLatLonAltBox & other)48 GeoDataLatLonAltBox& GeoDataLatLonAltBox::operator=( const GeoDataLatLonAltBox &other )
49 {
50 GeoDataLatLonBox::operator=( other );
51
52 *d = *other.d;
53 return *this;
54 }
55
operator =(const GeoDataCoordinates & other)56 GeoDataLatLonAltBox& GeoDataLatLonAltBox::operator=( const GeoDataCoordinates &other )
57 {
58 setWest( other.longitude() );
59 setEast( other.longitude() );
60 setNorth( other.latitude() );
61 setSouth( other.latitude() );
62 setMinAltitude( other.altitude() );
63 setMaxAltitude( other.altitude() );
64 return *this;
65 }
66
GeoDataLatLonAltBox()67 GeoDataLatLonAltBox::GeoDataLatLonAltBox()
68 : GeoDataLatLonBox(),
69 d( new GeoDataLatLonAltBoxPrivate )
70 {
71 }
72
GeoDataLatLonAltBox(const GeoDataLatLonAltBox & other)73 GeoDataLatLonAltBox::GeoDataLatLonAltBox( const GeoDataLatLonAltBox & other )
74 : GeoDataLatLonBox( other ),
75 d( new GeoDataLatLonAltBoxPrivate( *other.d ))
76 {
77 }
78
GeoDataLatLonAltBox(const GeoDataLatLonBox & other,qreal minAltitude,qreal maxAltitude)79 GeoDataLatLonAltBox::GeoDataLatLonAltBox( const GeoDataLatLonBox &other, qreal minAltitude, qreal maxAltitude )
80 : GeoDataLatLonBox( other ),
81 d( new GeoDataLatLonAltBoxPrivate )
82 {
83 setWest( other.west() );
84 setEast( other.east() );
85 setNorth( other.north() );
86 setSouth( other.south() );
87 setRotation( other.rotation() );
88
89 d->m_minAltitude = minAltitude;
90 d->m_maxAltitude = maxAltitude;
91 }
92
93
GeoDataLatLonAltBox(const GeoDataCoordinates & coordinates)94 GeoDataLatLonAltBox::GeoDataLatLonAltBox( const GeoDataCoordinates & coordinates )
95 : GeoDataLatLonBox(),
96 d( new GeoDataLatLonAltBoxPrivate )
97 {
98 setWest( coordinates.longitude() );
99 setEast( coordinates.longitude() );
100 setNorth( coordinates.latitude() );
101 setSouth( coordinates.latitude() );
102
103 d->m_minAltitude = coordinates.altitude();
104 d->m_maxAltitude = coordinates.altitude();
105 }
106
107
~GeoDataLatLonAltBox()108 GeoDataLatLonAltBox::~GeoDataLatLonAltBox()
109 {
110 delete d;
111 }
112
nodeType() const113 const char* GeoDataLatLonAltBox::nodeType() const
114 {
115 return GeoDataTypes::GeoDataLatLonAltBoxType;
116 }
117
minAltitude() const118 qreal GeoDataLatLonAltBox::minAltitude() const
119 {
120 return d->m_minAltitude;
121 }
122
setMinAltitude(const qreal minAltitude)123 void GeoDataLatLonAltBox::setMinAltitude( const qreal minAltitude )
124 {
125 d->m_minAltitude = minAltitude;
126 }
127
maxAltitude() const128 qreal GeoDataLatLonAltBox::maxAltitude() const
129 {
130 return d->m_maxAltitude;
131 }
132
setMaxAltitude(const qreal maxAltitude)133 void GeoDataLatLonAltBox::setMaxAltitude( const qreal maxAltitude )
134 {
135 d->m_maxAltitude = maxAltitude;
136 }
137
altitudeMode() const138 AltitudeMode GeoDataLatLonAltBox::altitudeMode() const
139 {
140 return d->m_altitudeMode;
141 }
142
center() const143 GeoDataCoordinates GeoDataLatLonAltBox::center() const
144 {
145 if ( isEmpty() )
146 return GeoDataCoordinates();
147 if( crossesDateLine() )
148 return GeoDataCoordinates( GeoDataCoordinates::normalizeLon(east() + 2 * M_PI - (east() + 2 * M_PI - west()) / 2),
149 north() - (north() - south()) / 2,
150 d->m_maxAltitude - (d->m_maxAltitude - d->m_minAltitude) / 2);
151 else
152 return GeoDataCoordinates( east() - (east() - west()) / 2,
153 north() - (north() - south()) / 2,
154 d->m_maxAltitude - (d->m_maxAltitude - d->m_minAltitude) / 2);
155 }
156
setAltitudeMode(const AltitudeMode altitudeMode)157 void GeoDataLatLonAltBox::setAltitudeMode( const AltitudeMode altitudeMode )
158 {
159 d->m_altitudeMode = altitudeMode;
160 }
161
contains(const GeoDataCoordinates & point) const162 bool GeoDataLatLonAltBox::contains( const GeoDataCoordinates &point ) const
163 {
164 if ( !GeoDataLatLonBox::contains( point ) )
165 return false;
166
167 if ( point.altitude() < d->m_minAltitude || point.altitude() > d->m_maxAltitude ) {
168 return false;
169 }
170
171 return true;
172 }
173
contains(const GeoDataLatLonAltBox & other) const174 bool GeoDataLatLonAltBox::contains( const GeoDataLatLonAltBox &other ) const
175 {
176 // check the contain criterion for the altitude first as this is trivial:
177
178 // mDebug() << "this " << this->toString(GeoDataCoordinates::Degree);
179 // mDebug() << "other" << other.toString(GeoDataCoordinates::Degree);
180
181 if ( d->m_maxAltitude >= other.maxAltitude() && d->m_minAltitude <= other.minAltitude() ) {
182 return GeoDataLatLonBox::contains( other );
183 }
184
185 return false;
186 }
187
intersects(const GeoDataLatLonAltBox & other) const188 bool GeoDataLatLonAltBox::intersects( const GeoDataLatLonAltBox &other ) const
189 {
190 // Case 1: maximum altitude of other box intersects:
191 if ( ( d->m_maxAltitude >= other.maxAltitude() && d->m_minAltitude <= other.maxAltitude() )
192 // Case 2: maximum altitude of this box intersects:
193 || ( other.maxAltitude() >= d->m_maxAltitude && other.minAltitude() <= d->m_maxAltitude )
194 // Case 3: minimum altitude of other box intersects:
195 || ( d->m_maxAltitude >= other.minAltitude() && d->m_minAltitude <= other.minAltitude() )
196 // Case 4: minimum altitude of this box intersects:
197 || ( other.maxAltitude() >= d->m_minAltitude && other.minAltitude() <= d->m_minAltitude ) ) {
198
199 if ( GeoDataLatLonBox::intersects( other ) )
200 return true;
201
202 }
203
204 return false;
205 }
206
fromLineString(const GeoDataLineString & lineString)207 GeoDataLatLonAltBox GeoDataLatLonAltBox::fromLineString( const GeoDataLineString& lineString )
208 {
209 // If the line string is empty return a boundingbox that contains everything
210 if ( lineString.size() == 0 ) {
211 return GeoDataLatLonAltBox();
212 }
213
214 const qreal altitude = lineString.first().altitude();
215
216 GeoDataLatLonAltBox temp ( GeoDataLatLonBox::fromLineString( lineString ), altitude, altitude );
217
218 qreal maxAltitude = altitude;
219 qreal minAltitude = altitude;
220
221 // If there's only a single node stored then the boundingbox only contains that point
222 if ( lineString.size() == 1 ) {
223 temp.setMinAltitude( minAltitude );
224 temp.setMaxAltitude( maxAltitude );
225 return temp;
226 }
227
228 QVector<GeoDataCoordinates>::ConstIterator it( lineString.constBegin() );
229 QVector<GeoDataCoordinates>::ConstIterator itEnd( lineString.constEnd() );
230
231 for ( ; it != itEnd; ++it )
232 {
233 // Get coordinates and normalize them to the desired range.
234 const qreal altitude = (it)->altitude();
235
236 // Determining the maximum and minimum altitude
237 if ( altitude > maxAltitude ) {
238 maxAltitude = altitude;
239 } else if ( altitude < minAltitude ) {
240 minAltitude = altitude;
241 }
242 }
243
244 temp.setMinAltitude( minAltitude );
245 temp.setMaxAltitude( maxAltitude );
246 return temp;
247 }
248
isNull() const249 bool GeoDataLatLonAltBox::isNull() const
250 {
251 return GeoDataLatLonBox::isNull() && d->m_maxAltitude == d->m_minAltitude;
252 }
253
clear()254 void GeoDataLatLonAltBox::clear()
255 {
256 GeoDataLatLonBox::clear();
257 d->m_minAltitude = 0;
258 d->m_maxAltitude = 0;
259 d->m_altitudeMode = ClampToGround;
260 }
261
pack(QDataStream & stream) const262 void GeoDataLatLonAltBox::pack( QDataStream& stream ) const
263 {
264 GeoDataObject::pack( stream );
265
266 stream << d->m_minAltitude << d->m_maxAltitude;
267 stream << d->m_altitudeMode;
268 }
269
unpack(QDataStream & stream)270 void GeoDataLatLonAltBox::unpack( QDataStream& stream )
271 {
272 GeoDataObject::unpack( stream );
273
274 stream >> d->m_minAltitude >> d->m_maxAltitude;
275 int a;
276 stream >> a;
277 d->m_altitudeMode = static_cast<AltitudeMode>( a );
278 }
279
qHash(const GeoDataLatLonAltBox & box,uint seed)280 uint qHash(const GeoDataLatLonAltBox &box, uint seed)
281 {
282 seed = ::qHash(box.east(), seed);
283 seed = ::qHash(box.west(), seed);
284 seed = ::qHash(box.south(), seed);
285 seed = ::qHash(box.north(), seed);
286 seed = ::qHash(box.maxAltitude(), seed);
287
288 return ::qHash(box.minAltitude(), seed);
289 }
290
291 }
292