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