File indexing completed on 2024-05-12 03:50:12
0001 // SPDX-License-Identifier: LGPL-2.1-or-later 0002 // 0003 // SPDX-FileCopyrightText: 2007 Andrew Manson <g.real.ate@gmail.com> 0004 // SPDX-FileCopyrightText: 2008 Torsten Rahn <rahn@kde.org> 0005 // 0006 0007 0008 #include "GeoDataLatLonAltBox.h" 0009 0010 #include "MarbleDebug.h" 0011 #include "GeoDataCoordinates.h" 0012 #include "GeoDataLineString.h" 0013 0014 #include "GeoDataTypes.h" 0015 0016 #include <QDataStream> 0017 0018 namespace Marble 0019 { 0020 0021 class GeoDataLatLonAltBoxPrivate 0022 { 0023 public: 0024 GeoDataLatLonAltBoxPrivate() 0025 : m_minAltitude( 0 ), 0026 m_maxAltitude( 0 ), 0027 m_altitudeMode( ClampToGround ) 0028 { 0029 } 0030 0031 qreal m_minAltitude; 0032 qreal m_maxAltitude; 0033 AltitudeMode m_altitudeMode; 0034 }; 0035 0036 bool operator==( GeoDataLatLonAltBox const& lhs, GeoDataLatLonAltBox const& rhs ) 0037 { 0038 return lhs.west() == rhs.west() && 0039 lhs.east() == rhs.east() && 0040 lhs.north() == rhs.north() && 0041 lhs.south() == rhs.south() && 0042 lhs.rotation() == rhs.rotation() && 0043 lhs.d->m_minAltitude == rhs.d->m_minAltitude && 0044 lhs.d->m_maxAltitude == rhs.d->m_maxAltitude && 0045 lhs.d->m_altitudeMode == rhs.d->m_altitudeMode; 0046 } 0047 0048 GeoDataLatLonAltBox& GeoDataLatLonAltBox::operator=( const GeoDataLatLonAltBox &other ) 0049 { 0050 GeoDataLatLonBox::operator=( other ); 0051 0052 *d = *other.d; 0053 return *this; 0054 } 0055 0056 GeoDataLatLonAltBox& GeoDataLatLonAltBox::operator=( const GeoDataCoordinates &other ) 0057 { 0058 setWest( other.longitude() ); 0059 setEast( other.longitude() ); 0060 setNorth( other.latitude() ); 0061 setSouth( other.latitude() ); 0062 setMinAltitude( other.altitude() ); 0063 setMaxAltitude( other.altitude() ); 0064 return *this; 0065 } 0066 0067 GeoDataLatLonAltBox::GeoDataLatLonAltBox() 0068 : GeoDataLatLonBox(), 0069 d( new GeoDataLatLonAltBoxPrivate ) 0070 { 0071 } 0072 0073 GeoDataLatLonAltBox::GeoDataLatLonAltBox( const GeoDataLatLonAltBox & other ) 0074 : GeoDataLatLonBox( other ), 0075 d( new GeoDataLatLonAltBoxPrivate( *other.d )) 0076 { 0077 } 0078 0079 GeoDataLatLonAltBox::GeoDataLatLonAltBox( const GeoDataLatLonBox &other, qreal minAltitude, qreal maxAltitude ) 0080 : GeoDataLatLonBox( other ), 0081 d( new GeoDataLatLonAltBoxPrivate ) 0082 { 0083 setWest( other.west() ); 0084 setEast( other.east() ); 0085 setNorth( other.north() ); 0086 setSouth( other.south() ); 0087 setRotation( other.rotation() ); 0088 0089 d->m_minAltitude = minAltitude; 0090 d->m_maxAltitude = maxAltitude; 0091 } 0092 0093 0094 GeoDataLatLonAltBox::GeoDataLatLonAltBox( const GeoDataCoordinates & coordinates ) 0095 : GeoDataLatLonBox(), 0096 d( new GeoDataLatLonAltBoxPrivate ) 0097 { 0098 setWest( coordinates.longitude() ); 0099 setEast( coordinates.longitude() ); 0100 setNorth( coordinates.latitude() ); 0101 setSouth( coordinates.latitude() ); 0102 0103 d->m_minAltitude = coordinates.altitude(); 0104 d->m_maxAltitude = coordinates.altitude(); 0105 } 0106 0107 0108 GeoDataLatLonAltBox::~GeoDataLatLonAltBox() 0109 { 0110 delete d; 0111 } 0112 0113 const char* GeoDataLatLonAltBox::nodeType() const 0114 { 0115 return GeoDataTypes::GeoDataLatLonAltBoxType; 0116 } 0117 0118 qreal GeoDataLatLonAltBox::minAltitude() const 0119 { 0120 return d->m_minAltitude; 0121 } 0122 0123 void GeoDataLatLonAltBox::setMinAltitude( const qreal minAltitude ) 0124 { 0125 d->m_minAltitude = minAltitude; 0126 } 0127 0128 qreal GeoDataLatLonAltBox::maxAltitude() const 0129 { 0130 return d->m_maxAltitude; 0131 } 0132 0133 void GeoDataLatLonAltBox::setMaxAltitude( const qreal maxAltitude ) 0134 { 0135 d->m_maxAltitude = maxAltitude; 0136 } 0137 0138 AltitudeMode GeoDataLatLonAltBox::altitudeMode() const 0139 { 0140 return d->m_altitudeMode; 0141 } 0142 0143 GeoDataCoordinates GeoDataLatLonAltBox::center() const 0144 { 0145 if ( isEmpty() ) 0146 return GeoDataCoordinates(); 0147 if( crossesDateLine() ) 0148 return GeoDataCoordinates( GeoDataCoordinates::normalizeLon(east() + 2 * M_PI - (east() + 2 * M_PI - west()) / 2), 0149 north() - (north() - south()) / 2, 0150 d->m_maxAltitude - (d->m_maxAltitude - d->m_minAltitude) / 2); 0151 else 0152 return GeoDataCoordinates( east() - (east() - west()) / 2, 0153 north() - (north() - south()) / 2, 0154 d->m_maxAltitude - (d->m_maxAltitude - d->m_minAltitude) / 2); 0155 } 0156 0157 void GeoDataLatLonAltBox::setAltitudeMode( const AltitudeMode altitudeMode ) 0158 { 0159 d->m_altitudeMode = altitudeMode; 0160 } 0161 0162 bool GeoDataLatLonAltBox::contains( const GeoDataCoordinates &point ) const 0163 { 0164 if ( !GeoDataLatLonBox::contains( point ) ) 0165 return false; 0166 0167 if ( point.altitude() < d->m_minAltitude || point.altitude() > d->m_maxAltitude ) { 0168 return false; 0169 } 0170 0171 return true; 0172 } 0173 0174 bool GeoDataLatLonAltBox::contains( const GeoDataLatLonAltBox &other ) const 0175 { 0176 // check the contain criterion for the altitude first as this is trivial: 0177 0178 // mDebug() << "this " << this->toString(GeoDataCoordinates::Degree); 0179 // mDebug() << "other" << other.toString(GeoDataCoordinates::Degree); 0180 0181 if ( d->m_maxAltitude >= other.maxAltitude() && d->m_minAltitude <= other.minAltitude() ) { 0182 return GeoDataLatLonBox::contains( other ); 0183 } 0184 0185 return false; 0186 } 0187 0188 bool GeoDataLatLonAltBox::intersects( const GeoDataLatLonAltBox &other ) const 0189 { 0190 // Case 1: maximum altitude of other box intersects: 0191 if ( ( d->m_maxAltitude >= other.maxAltitude() && d->m_minAltitude <= other.maxAltitude() ) 0192 // Case 2: maximum altitude of this box intersects: 0193 || ( other.maxAltitude() >= d->m_maxAltitude && other.minAltitude() <= d->m_maxAltitude ) 0194 // Case 3: minimum altitude of other box intersects: 0195 || ( d->m_maxAltitude >= other.minAltitude() && d->m_minAltitude <= other.minAltitude() ) 0196 // Case 4: minimum altitude of this box intersects: 0197 || ( other.maxAltitude() >= d->m_minAltitude && other.minAltitude() <= d->m_minAltitude ) ) { 0198 0199 if ( GeoDataLatLonBox::intersects( other ) ) 0200 return true; 0201 0202 } 0203 0204 return false; 0205 } 0206 0207 GeoDataLatLonAltBox GeoDataLatLonAltBox::fromLineString( const GeoDataLineString& lineString ) 0208 { 0209 // If the line string is empty return a boundingbox that contains everything 0210 if ( lineString.size() == 0 ) { 0211 return GeoDataLatLonAltBox(); 0212 } 0213 0214 const qreal altitude = lineString.first().altitude(); 0215 0216 GeoDataLatLonAltBox temp ( GeoDataLatLonBox::fromLineString( lineString ), altitude, altitude ); 0217 0218 qreal maxAltitude = altitude; 0219 qreal minAltitude = altitude; 0220 0221 // If there's only a single node stored then the boundingbox only contains that point 0222 if ( lineString.size() == 1 ) { 0223 temp.setMinAltitude( minAltitude ); 0224 temp.setMaxAltitude( maxAltitude ); 0225 return temp; 0226 } 0227 0228 QVector<GeoDataCoordinates>::ConstIterator it( lineString.constBegin() ); 0229 QVector<GeoDataCoordinates>::ConstIterator itEnd( lineString.constEnd() ); 0230 0231 for ( ; it != itEnd; ++it ) 0232 { 0233 // Get coordinates and normalize them to the desired range. 0234 const qreal altitude = (it)->altitude(); 0235 0236 // Determining the maximum and minimum altitude 0237 if ( altitude > maxAltitude ) { 0238 maxAltitude = altitude; 0239 } else if ( altitude < minAltitude ) { 0240 minAltitude = altitude; 0241 } 0242 } 0243 0244 temp.setMinAltitude( minAltitude ); 0245 temp.setMaxAltitude( maxAltitude ); 0246 return temp; 0247 } 0248 0249 bool GeoDataLatLonAltBox::isNull() const 0250 { 0251 return GeoDataLatLonBox::isNull() && d->m_maxAltitude == d->m_minAltitude; 0252 } 0253 0254 void GeoDataLatLonAltBox::clear() 0255 { 0256 GeoDataLatLonBox::clear(); 0257 d->m_minAltitude = 0; 0258 d->m_maxAltitude = 0; 0259 d->m_altitudeMode = ClampToGround; 0260 } 0261 0262 void GeoDataLatLonAltBox::pack( QDataStream& stream ) const 0263 { 0264 GeoDataObject::pack( stream ); 0265 0266 stream << d->m_minAltitude << d->m_maxAltitude; 0267 stream << d->m_altitudeMode; 0268 } 0269 0270 void GeoDataLatLonAltBox::unpack( QDataStream& stream ) 0271 { 0272 GeoDataObject::unpack( stream ); 0273 0274 stream >> d->m_minAltitude >> d->m_maxAltitude; 0275 int a; 0276 stream >> a; 0277 d->m_altitudeMode = static_cast<AltitudeMode>( a ); 0278 } 0279 0280 uint qHash(const GeoDataLatLonAltBox &box, uint seed) 0281 { 0282 seed = ::qHash(box.east(), seed); 0283 seed = ::qHash(box.west(), seed); 0284 seed = ::qHash(box.south(), seed); 0285 seed = ::qHash(box.north(), seed); 0286 seed = ::qHash(box.maxAltitude(), seed); 0287 0288 return ::qHash(box.minAltitude(), seed); 0289 } 0290 0291 }