File indexing completed on 2024-05-12 03:50:10

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2008 Patrick Spendrin <ps_ml@gmx.de>
0004 //
0005 
0006 #ifndef MARBLE_GEODATACOORDINATES_P_H
0007 #define MARBLE_GEODATACOORDINATES_P_H
0008 
0009 #include "Quaternion.h"
0010 #include <QAtomicInt>
0011 
0012 namespace Marble
0013 {
0014 
0015 class GeoDataCoordinatesPrivate
0016 {
0017   public:
0018     /*
0019     * if this ctor is called there exists exactly one GeoDataCoordinates object
0020     * with this data.
0021     * changes will be made in the GeoDataCoordinates class
0022     * ref must be called ref as qAtomicAssign used in GeoDataCoordinates::operator=
0023     * needs this name. Maybe we can rename it to our scheme later on.
0024     */
0025     GeoDataCoordinatesPrivate()
0026         : m_q( nullptr ),
0027           m_lon( 0 ),
0028           m_lat( 0 ),
0029           m_altitude( 0 ),
0030           m_detail( 0 ),
0031           ref( 0 )
0032     {
0033     }
0034 
0035     /*
0036     * if this ctor is called there exists exactly one GeoDataCoordinates object
0037     * with this data.
0038     * changes will be made in the GeoDataCoordinates class
0039     * ref must be called ref as qAtomicAssign used in GeoDataCoordinates::operator=
0040     * needs this name. Maybe we can rename it to our scheme later on.
0041     */
0042     GeoDataCoordinatesPrivate( qreal _lon, qreal _lat, qreal _alt,
0043                         GeoDataCoordinates::Unit unit,
0044                         int _detail )
0045         : m_q( nullptr ),
0046           m_altitude( _alt ),
0047           m_detail( _detail ),
0048           ref( 0 )
0049     {
0050         switch( unit ){
0051         default:
0052         case GeoDataCoordinates::Radian:
0053             m_lon = _lon;
0054             m_lat = _lat;
0055             break;
0056         case GeoDataCoordinates::Degree:
0057             m_lon = _lon * DEG2RAD;
0058             m_lat = _lat * DEG2RAD;
0059             break;
0060         }
0061     }
0062 
0063     /*
0064     * this constructor is needed as Quaternion doesn't define a copy ctor
0065     * initialize the reference with the value of the other
0066     */
0067     GeoDataCoordinatesPrivate( const GeoDataCoordinatesPrivate &other )
0068         : m_q( nullptr ),
0069           m_lon( other.m_lon ),
0070           m_lat( other.m_lat ),
0071           m_altitude( other.m_altitude ),
0072           m_detail( other.m_detail ),
0073           ref( 0 )
0074     {
0075     }
0076 
0077     /*
0078     * return this instead of &other
0079     */
0080     GeoDataCoordinatesPrivate& operator=( const GeoDataCoordinatesPrivate &other )
0081     {
0082         m_lon = other.m_lon;
0083         m_lat = other.m_lat;
0084         m_altitude = other.m_altitude;
0085         m_detail = other.m_detail;
0086         ref = 0;
0087         delete m_q;
0088         m_q = nullptr;
0089         return *this;
0090     }
0091 
0092     bool operator==( const GeoDataCoordinatesPrivate &rhs ) const;
0093     bool operator!=( const GeoDataCoordinatesPrivate &rhs ) const;
0094 
0095     static Quaternion basePoint( const Quaternion &q1, const Quaternion &q2, const Quaternion &q3 );
0096 
0097     // Helper functions for UTM-related development.
0098     // Based on Chuck Taylor work:
0099     // http://home.hiwaay.net/~taylorc/toolbox/geography/geoutm.html
0100 
0101     /**
0102     * Computes the ellipsoidal distance from the equator to a point at a
0103     * given latitude.
0104     *
0105     * Reference: Hoffmann-Wellenhof, B., Lichtenegger, H., and Collins, J.,
0106     * GPS: Theory and Practice, 3rd ed.  New York: Springer-Verlag Wien, 1994.
0107     *
0108     * @param phi Latitude of the point, in radians.
0109     * @return The ellipsoidal distance of the point from the equator, in meters.
0110     */
0111     static qreal arcLengthOfMeridian( qreal phi );
0112 
0113     /**
0114     * Determines the central meridian for the given UTM zone.
0115     *
0116     * @param zone An integer value designating the UTM zone, range [1,60].
0117     * @return The central meridian for the given UTM zone, in radians, or zero
0118     * if the UTM zone parameter is outside the range [1,60].
0119     * Range of the central meridian is the radian equivalent of [-177,+177].
0120     */
0121     static qreal centralMeridianUTM( qreal zone );
0122 
0123 
0124     /**
0125     * Computes the footpoint latitude for use in converting transverse
0126     * Mercator coordinates to ellipsoidal coordinates.
0127     *
0128     * Reference: Hoffmann-Wellenhof, B., Lichtenegger, H., and Collins, J.,
0129     *   GPS: Theory and Practice, 3rd ed.  New York: Springer-Verlag Wien, 1994.
0130     *
0131     * @param northing The UTM northing coordinate, in meters.
0132     * @return The footpoint latitude, in radians.
0133     */
0134     static qreal footpointLatitude( qreal northing );
0135 
0136     /**
0137     * Converts a latitude/longitude pair to x and y coordinates in the
0138     * Transverse Mercator projection.  Note that Transverse Mercator is not
0139     * the same as UTM; a scale factor is required to convert between them.
0140     *
0141     * Reference: Hoffmann-Wellenhof, B., Lichtenegger, H., and Collins, J.,
0142     * GPS: Theory and Practice, 3rd ed.  New York: Springer-Verlag Wien, 1994.
0143     *
0144     * @param lambda Longitude of the point, in radians.
0145     * @param phi Latitude of the point, in radians.
0146     * @param lambda0 Longitude of the central meridian to be used, in radians.
0147     * @return The computed point with its x and y coordinates
0148     */
0149     static QPointF mapLonLatToXY( qreal lambda, qreal phi, qreal lambda0 );
0150 
0151     /**
0152      * Converts a latitude/longitude pair to x and y coordinates in the
0153      * Universal Transverse Mercator projection.
0154      *
0155      * @param lon Longitude of the point, in radians.
0156      * @param lat Latitude of the point, in radians.
0157      * @param zone UTM zone between 1 and 60 to be used for calculating
0158      * values for x and y.
0159      * @return A point with its x and y coordinates representing
0160      * easting and northing of the UTM coordinates computed.
0161      */
0162     static QPointF lonLatToUTMXY( qreal lon, qreal lat, qreal zone );
0163 
0164     /**
0165     * @brief retrieves the UTM latitude band of a longitude/latitude
0166     * pair
0167     * @param lon longitude, in radians
0168     * @param lat latitude, in radians
0169     * @return latitude band
0170     */
0171     static QString lonLatToLatitudeBand( qreal lon, qreal lat );
0172 
0173     /**
0174     * @brief retrieves the northing value of a longitude/latitude
0175     * pair
0176     * @param lon longitude, in radians
0177     * @param lat latitude, in radians
0178     * @return UTM northing value
0179     */
0180     static qreal lonLatToNorthing( qreal lon, qreal lat );
0181 
0182     /**
0183     * @brief retrieves the UTM zone number of a longitude/latitude
0184     * pair
0185     * @param lon longitude, in radians
0186     * @param lat latitude, in radians
0187     * @return UTM zone number
0188     */
0189     static int lonLatToZone( qreal lon, qreal lat );
0190 
0191     /**
0192     * @brief  retrieves the easting value of a longitude/latitude
0193     * pair
0194     * @param lon longitude, in radians
0195     * @param lat latitude, in radians
0196     * @return UTM easting value
0197     */
0198     static qreal lonLatToEasting( qreal lon, qreal lat );
0199 
0200     Quaternion * m_q;
0201     qreal      m_lon;
0202     qreal      m_lat;
0203     qreal      m_altitude;     // in meters above sea level
0204     quint8     m_detail;
0205     QAtomicInt ref;
0206 
0207     /* UTM Ellipsoid model constants (actual values here are for WGS84) */
0208     static const qreal sm_semiMajorAxis;
0209     static const qreal sm_semiMinorAxis;
0210     static const qreal sm_eccentricitySquared;
0211     static const qreal sm_utmScaleFactor;
0212 
0213 };
0214 
0215 inline bool GeoDataCoordinatesPrivate::operator==( const GeoDataCoordinatesPrivate &rhs ) const
0216 {
0217     // do not compare the m_detail member as it does not really belong to
0218     // GeoDataCoordinates and should be removed
0219     return m_lon == rhs.m_lon && m_lat == rhs.m_lat && m_altitude == rhs.m_altitude;
0220 }
0221 
0222 inline bool GeoDataCoordinatesPrivate::operator!=( const GeoDataCoordinatesPrivate &rhs ) const
0223 {
0224     // do not compare the m_detail member as it does not really belong to
0225     // GeoDataCoordinates and should be removed
0226     return ! (*this == rhs);
0227 }
0228 
0229 }
0230 
0231 #endif