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 }