File indexing completed on 2025-01-05 03:58:54
0001 // SPDX-License-Identifier: LGPL-2.1-or-later 0002 // 0003 // SPDX-FileCopyrightText: 2006-2007 Torsten Rahn <tackat@kde.org> 0004 // SPDX-FileCopyrightText: 2007-2008 Inge Wallin <ingwa@kde.org> 0005 // SPDX-FileCopyrightText: 2008 Patrick Spendrin <ps_ml@gmx.de> 0006 // SPDX-FileCopyrightText: 2015 Alejandro Garcia Montoro <alejandro.garciamontoro@gmail.com> 0007 // 0008 0009 0010 #ifndef MARBLE_GEODATACOORDINATES_H 0011 #define MARBLE_GEODATACOORDINATES_H 0012 0013 #include <QCoreApplication> 0014 #include <QMetaType> 0015 #include <QVector> 0016 0017 #include "digikam_export.h" 0018 #include "MarbleGlobal.h" 0019 0020 class QString; 0021 0022 namespace Marble 0023 { 0024 0025 class GeoDataCoordinatesPrivate; 0026 class Quaternion; 0027 0028 /** 0029 * @short A 3d point representation 0030 * 0031 * GeoDataCoordinates is the simple representation of a single three 0032 * dimensional point. It can be used all through out marble as the data type 0033 * for three dimensional objects. it comprises of a Quaternion for speed issues. 0034 * This class was introduced to reflect the difference between a simple 3d point 0035 * and the GeoDataGeometry object containing such a point. The latter is a 0036 * GeoDataPoint and is simply derived from GeoDataGeometry. 0037 * @see GeoDataPoint 0038 */ 0039 0040 class DIGIKAM_EXPORT GeoDataCoordinates 0041 { 0042 Q_DECLARE_TR_FUNCTIONS(GeoDataCoordinates) 0043 0044 public: 0045 /** 0046 * @brief enum used constructor to specify the units used 0047 * 0048 * Internally we always use radian for mathematical convenience. 0049 * However the Marble's interfaces to the outside should default 0050 * to degrees. 0051 */ 0052 enum Unit{ 0053 Radian, 0054 Degree 0055 }; 0056 0057 /** 0058 * @brief enum used to specify the notation / numerical system 0059 * 0060 * For degrees there exist two notations: 0061 * "Decimal" (base-10) and the "Sexagesimal DMS" (base-60) which is 0062 * traditionally used in cartography. Decimal notation 0063 * uses floating point numbers to specify parts of a degree. The 0064 * Sexagesimal DMS notation uses integer based 0065 * Degrees-(Arc)Minutes-(Arc)Seconds to describe parts of a degree. 0066 */ 0067 enum Notation{ 0068 Decimal, ///< "Decimal" notation (base-10) 0069 DMS, ///< "Sexagesimal DMS" notation (base-60) 0070 DM, ///< "Sexagesimal DM" notation (base-60) 0071 UTM, 0072 Astro /// < "RA and DEC" notation (used for astronomical sky coordinates) 0073 }; 0074 0075 /** 0076 * @brief The BearingType enum specifies where to measure the bearing 0077 * along great circle arcs 0078 * 0079 * When traveling along a great circle arc defined by the two points 0080 * A and B, the bearing varies along the arc. The "InitialBearing" bearing 0081 * corresponds to the bearing value at A, the "FinalBearing" bearing to that 0082 * at B. 0083 */ 0084 enum BearingType { 0085 InitialBearing, 0086 FinalBearing 0087 }; 0088 0089 // Type definitions 0090 using Vector = QVector<GeoDataCoordinates>; 0091 using PtrVector = QVector<GeoDataCoordinates *>; 0092 0093 GeoDataCoordinates( const GeoDataCoordinates& other ); 0094 0095 /** 0096 * @brief constructs an invalid instance 0097 * 0098 * Constructs an invalid instance such that calling isValid() 0099 * on it will return @code false @endcode. 0100 */ 0101 GeoDataCoordinates(); 0102 0103 /** 0104 * @brief create a geocoordinate from longitude and latitude 0105 * @param lon longitude 0106 * @param lat latitude 0107 * @param alt altitude in meters (default: 0) 0108 * @param unit units that lon and lat get measured in 0109 * (default for Radian: north pole at pi/2, southpole at -pi/2) 0110 * @param detail detail (default: 0) 0111 */ 0112 GeoDataCoordinates( qreal lon, qreal lat, qreal alt = 0, 0113 GeoDataCoordinates::Unit unit = GeoDataCoordinates::Radian, 0114 int detail = 0 ); 0115 0116 virtual ~GeoDataCoordinates(); 0117 0118 /** 0119 * @brief Returns @code true @endcode if the coordinate is valid, @code false @endcode otherwise. 0120 * @return whether the coordinate is valid 0121 * 0122 * A coordinate is valid, if at least one component has been set and the last 0123 * assignment was not an invalid GeoDataCoordinates object. 0124 */ 0125 bool isValid() const; 0126 0127 /** 0128 * @brief (re)set the coordinates in a GeoDataCoordinates object 0129 * @param lon longitude 0130 * @param lat latitude 0131 * @param alt altitude in meters (default: 0) 0132 * @param unit units that lon and lat get measured in 0133 * (default for Radian: north pole at pi/2, southpole at -pi/2) 0134 */ 0135 void set( qreal lon, qreal lat, qreal alt = 0, 0136 GeoDataCoordinates::Unit unit = GeoDataCoordinates::Radian ); 0137 0138 /** 0139 * @brief use this function to get the longitude and latitude with one 0140 * call - use the unit parameter to switch between Radian and DMS 0141 * @param lon longitude 0142 * @param lat latitude 0143 * @param unit units that lon and lat get measured in 0144 * (default for Radian: north pole at pi/2, southpole at -pi/2) 0145 */ 0146 void geoCoordinates(qreal& lon, qreal& lat, GeoDataCoordinates::Unit unit) const; 0147 void geoCoordinates(qreal& lon, qreal& lat) const; 0148 0149 /** 0150 * @brief use this function to get the longitude, latitude and altitude 0151 * with one call - use the unit parameter to switch between Radian and DMS 0152 * @param lon longitude 0153 * @param lat latitude 0154 * @param alt altitude in meters 0155 * @param unit units that lon and lat get measured in 0156 * (default for Radian: north pole at pi/2, southpole at -pi/2) 0157 */ 0158 void geoCoordinates(qreal& lon, qreal& lat, qreal& alt, GeoDataCoordinates::Unit unit) const; 0159 void geoCoordinates(qreal& lon, qreal& lat, qreal& alt) const; 0160 0161 /** 0162 * @brief set the longitude in a GeoDataCoordinates object 0163 * @param lon longitude 0164 * @param unit units that lon and lat get measured in 0165 * (default for Radian: north pole at pi/2, southpole at -pi/2) 0166 */ 0167 void setLongitude( qreal lon, 0168 GeoDataCoordinates::Unit unit = GeoDataCoordinates::Radian ); 0169 0170 /** 0171 * @brief retrieves the longitude of the GeoDataCoordinates object 0172 * use the unit parameter to switch between Radian and DMS 0173 * @param unit units that lon and lat get measured in 0174 * (default for Radian: north pole at pi/2, southpole at -pi/2) 0175 * @return longitude 0176 */ 0177 qreal longitude(GeoDataCoordinates::Unit unit) const; 0178 qreal longitude() const; 0179 0180 /** 0181 * @brief retrieves the latitude of the GeoDataCoordinates object 0182 * use the unit parameter to switch between Radian and DMS 0183 * @param unit units that lon and lat get measured in 0184 * (default for Radian: north pole at pi/2, southpole at -pi/2) 0185 * @return latitude 0186 */ 0187 qreal latitude( GeoDataCoordinates::Unit unit ) const; 0188 qreal latitude() const; 0189 0190 /** 0191 * @brief set the longitude in a GeoDataCoordinates object 0192 * @param lat longitude 0193 * @param unit units that lon and lat get measured in 0194 * (default for Radian: north pole at pi/2, southpole at -pi/2) 0195 */ 0196 void setLatitude( qreal lat, 0197 GeoDataCoordinates::Unit unit = GeoDataCoordinates::Radian ); 0198 0199 /** 0200 * @brief return the altitude of the Point in meters 0201 */ 0202 qreal altitude() const; 0203 /** 0204 * @brief set the altitude of the Point in meters 0205 * @param altitude altitude 0206 */ 0207 void setAltitude( const qreal altitude ); 0208 0209 /** 0210 * @brief retrieves the UTM zone of the GeoDataCoordinates object. 0211 * If the point is located on one of the poles (latitude < 80S or 0212 * latitude > 84N) there is no UTM zone associated; in this case, 0213 * 0 is returned. 0214 * @return UTM zone. 0215 */ 0216 int utmZone() const; 0217 0218 /** 0219 * @brief retrieves the UTM easting of the GeoDataCoordinates object, 0220 * in meters. 0221 * @return UTM easting 0222 */ 0223 qreal utmEasting() const; 0224 0225 /** 0226 * @brief retrieves the UTM latitude band of the GeoDataCoordinates object 0227 * @return UTM latitude band 0228 */ 0229 QString utmLatitudeBand() const; 0230 0231 /** 0232 * @brief retrieves the UTM northing of the GeoDataCoordinates object, 0233 * in meters 0234 * @return UTM northing 0235 */ 0236 qreal utmNorthing() const; 0237 0238 /** 0239 * @brief return the detail flag 0240 * detail range: 0 for most important points, 5 for least important 0241 */ 0242 quint8 detail() const; 0243 0244 /** 0245 * @brief set the detail flag 0246 * @param detail detail 0247 */ 0248 void setDetail(quint8 detail); 0249 0250 /** 0251 * @brief Rotates one coordinate around another. 0252 * @param axis The coordinate that serves as a rotation axis 0253 * @param angle Rotation angle 0254 * @param unit Unit of the result 0255 * @return The coordinate rotated in anticlockwise direction 0256 */ 0257 GeoDataCoordinates rotateAround( const GeoDataCoordinates &axis, qreal angle, Unit unit = Radian ) const; 0258 0259 GeoDataCoordinates rotateAround(const Quaternion &rotAxis) const; 0260 0261 /** 0262 * @brief Returns the bearing (true bearing, the angle between the line defined 0263 * by this point and the other and the prime meridian) 0264 * @param other The second point that, together with this point, defines a line 0265 * @param unit Unit of the result 0266 * @param type Type of the bearing 0267 * @return The true bearing in the requested unit, not range normalized, 0268 * in clockwise direction, with the value 0 corresponding to north 0269 */ 0270 qreal bearing( const GeoDataCoordinates &other, Unit unit = Radian, BearingType type = InitialBearing ) const; 0271 0272 /** 0273 * @brief Returns the coordinates of the resulting point after moving this point 0274 * according to the distance and bearing parameters 0275 * @param bearing the same as above 0276 * @param distance the distance on a unit sphere 0277 */ 0278 GeoDataCoordinates moveByBearing( qreal bearing, qreal distance ) const; 0279 0280 /** 0281 * @brief return a Quaternion with the used coordinates 0282 */ 0283 const Quaternion &quaternion() const; 0284 0285 /** 0286 * @brief slerp (spherical linear) interpolation between this coordinate and the given target coordinate 0287 * @param target Destination coordinate 0288 * @param t Fraction 0..1 to weight between this and target 0289 * @return Interpolated coordinate between this (t<=0.0) and target (t>=1.0) 0290 */ 0291 GeoDataCoordinates interpolate( const GeoDataCoordinates &target, double t ) const; 0292 0293 /** 0294 * @brief nlerp (normalized linear interpolation) between this coordinates and the given target coordinates 0295 * @param target Destination coordinates 0296 * @param t Fraction 0..1 to weight between this and target 0297 * @return Interpolated coordinate between this (t<=0.0) and target (t>=1.0) 0298 */ 0299 GeoDataCoordinates nlerp(const GeoDataCoordinates &target, double t) const; 0300 0301 /** 0302 * @brief squad (spherical and quadrangle) interpolation between b and c 0303 * @param before First base point 0304 * @param target Third base point (second interpolation point) 0305 * @param after Fourth base point 0306 * @param t Offset between b (t<=0) and c (t>=1) 0307 */ 0308 GeoDataCoordinates interpolate( const GeoDataCoordinates &before, const GeoDataCoordinates &target, const GeoDataCoordinates &after, double t ) const; 0309 0310 /** 0311 * @brief return whether our coordinates represent a pole 0312 * This method can be used to check whether the coordinate equals one of 0313 * the poles. 0314 */ 0315 bool isPole( Pole = AnyPole ) const; 0316 0317 /** 0318 * @brief This method calculates the shortest distance between two points on a sphere. 0319 * @brief See: https://en.wikipedia.org/wiki/Great-circle_distance 0320 */ 0321 qreal sphericalDistanceTo(const GeoDataCoordinates &other) const; 0322 0323 /** 0324 * @brief return Notation of string representation 0325 */ 0326 static GeoDataCoordinates::Notation defaultNotation(); 0327 0328 /** 0329 * @brief set the Notation of the string representation 0330 * @param notation Notation 0331 */ 0332 static void setDefaultNotation( GeoDataCoordinates::Notation notation ); 0333 0334 /** 0335 * @brief normalize the longitude to always be -M_PI <= lon <= +M_PI (Radian). 0336 * @param lon longitude 0337 * @param unit unit of the result 0338 */ 0339 static qreal normalizeLon( qreal lon, 0340 GeoDataCoordinates::Unit = GeoDataCoordinates::Radian ); 0341 0342 /** 0343 * @brief normalize latitude to always be in -M_PI / 2. <= lat <= +M_PI / 2 (Radian). 0344 * @param lat latitude 0345 * @param unit unit of the result 0346 */ 0347 static qreal normalizeLat( qreal lat, 0348 GeoDataCoordinates::Unit = GeoDataCoordinates::Radian ); 0349 0350 /** 0351 * @brief normalize both longitude and latitude at the same time 0352 * This method normalizes both latitude and longitude, so that the 0353 * latitude and the longitude stay within the "usual" range. 0354 * NOTE: If the latitude exceeds M_PI/2 (+90.0 deg) or -M_PI/2 (-90.0 deg) 0355 * then this will be interpreted as a pole traversion where the point will 0356 * end up on the opposite side of the globe. Therefore the longitude will 0357 * change by M_PI (180 deg). 0358 * If you don't want this behaviour use both normalizeLat() and 0359 * normalizeLon() instead. 0360 * @param lon the longitude value 0361 * @param lat the latitude value 0362 * @param unit unit of the result 0363 */ 0364 static void normalizeLonLat( qreal &lon, qreal &lat, 0365 GeoDataCoordinates::Unit = GeoDataCoordinates::Radian ); 0366 0367 /** 0368 * @brief try to parse the string into a coordinate pair 0369 * @param string the string 0370 * @param successful becomes true if the conversion succeeds 0371 * @return the geodatacoordinates 0372 */ 0373 static GeoDataCoordinates fromString( const QString &string, bool& successful ); 0374 0375 /** 0376 * @brief return a string representation of the coordinate 0377 * this is a convenience function which uses the default notation 0378 */ 0379 QString toString() const; 0380 0381 /** 0382 * @brief return a string with the notation given by notation 0383 * 0384 * @param notation set a notation different from the default one 0385 * @param precision set the number of digits below degrees. 0386 * The precision depends on the current notation: 0387 * For Decimal representation the precision is the number of 0388 * digits after the decimal point. 0389 * In DMS a precision of 1 or 2 shows the arc minutes; a precision 0390 * of 3 or 4 will show arc seconds. A precision beyond that will 0391 * increase the number of digits after the arc second decimal point. 0392 */ 0393 QString toString( GeoDataCoordinates::Notation notation, int precision = -1 ) const; 0394 0395 static QString lonToString( qreal lon, GeoDataCoordinates::Notation notation, 0396 GeoDataCoordinates::Unit unit = Radian, 0397 int precision = -1, 0398 char format = 'f' ); 0399 /** 0400 * @brief return a string representation of longitude of the coordinate 0401 * convenience function that uses the default notation 0402 */ 0403 QString lonToString() const; 0404 0405 static QString latToString( qreal lat, GeoDataCoordinates::Notation notation, 0406 GeoDataCoordinates::Unit unit = Radian, 0407 int precision = -1, 0408 char format = 'f' ); 0409 /** 0410 * @brief return a string representation of latitude of the coordinate 0411 * convenience function that uses the default notation 0412 */ 0413 QString latToString() const; 0414 0415 bool operator==(const GeoDataCoordinates &other) const; 0416 bool operator!=(const GeoDataCoordinates &other) const; 0417 0418 GeoDataCoordinates& operator=( const GeoDataCoordinates &other ); 0419 0420 /** Serialize the contents of the feature to @p stream. */ 0421 void pack(QDataStream &stream) const; 0422 /** Unserialize the contents of the feature from @p stream. */ 0423 void unpack(QDataStream &stream); 0424 0425 private: 0426 void detach(); 0427 0428 GeoDataCoordinatesPrivate *d; 0429 0430 static GeoDataCoordinates::Notation s_notation; 0431 static const GeoDataCoordinates null; 0432 }; 0433 0434 DIGIKAM_EXPORT size_t qHash(const GeoDataCoordinates& coordinates ); 0435 0436 0437 } 0438 0439 Q_DECLARE_METATYPE( Marble::GeoDataCoordinates ) 0440 0441 #endif