// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Library General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // #ifndef SGGeoc_H #define SGGeoc_H #include // #define SG_GEOC_NATIVE_DEGREE /// Class representing a geocentric location class SGGeoc { public: /// Default constructor, initializes the instance to lat = lon = lat = 0 SGGeoc(void); /// Factory from angular values in radians and radius in ft static SGGeoc fromRadFt(double lon, double lat, double radius); /// Factory from angular values in degrees and radius in ft static SGGeoc fromDegFt(double lon, double lat, double radius); /// Factory from angular values in radians and radius in m static SGGeoc fromRadM(double lon, double lat, double radius); /// Factory from angular values in degrees and radius in m static SGGeoc fromDegM(double lon, double lat, double radius); /// Factory to convert position from a cartesian position assumed to be /// in wgs84 measured in meters /// Note that this conversion is relatively expensive to compute static SGGeoc fromCart(const SGVec3& cart); /// Factory to convert position from a geodetic position /// Note that this conversion is relatively expensive to compute static SGGeoc fromGeod(const SGGeod& geod); /// Return the geocentric longitude in radians double getLongitudeRad(void) const; /// Set the geocentric longitude from the argument given in radians void setLongitudeRad(double lon); /// Return the geocentric longitude in degrees double getLongitudeDeg(void) const; /// Set the geocentric longitude from the argument given in degrees void setLongitudeDeg(double lon); /// Return the geocentric latitude in radians double getLatitudeRad(void) const; /// Set the geocentric latitude from the argument given in radians void setLatitudeRad(double lat); /// Return the geocentric latitude in degrees double getLatitudeDeg(void) const; /// Set the geocentric latitude from the argument given in degrees void setLatitudeDeg(double lat); /// Return the geocentric radius in meters double getRadiusM(void) const; /// Set the geocentric radius from the argument given in meters void setRadiusM(double radius); /// Return the geocentric radius in feet double getRadiusFt(void) const; /// Set the geocentric radius from the argument given in feet void setRadiusFt(double radius); SGGeoc advanceRadM(double course, double distance) const; static double courseRad(const SGGeoc& from, const SGGeoc& to); static double courseDeg(const SGGeoc& from, const SGGeoc& to); static double distanceM(const SGGeoc& from, const SGGeoc& to); // Compare two geocentric positions for equality bool operator == ( const SGGeoc & other ) const; private: /// This one is private since construction is not unique if you do /// not know the units of the arguments, use the factory methods for /// that purpose SGGeoc(double lon, double lat, double radius); /// The actual data, angles in degree, radius in meters /// The rationale for storing the values in degrees is that most code places /// in flightgear/terragear use degrees as a nativ input and output value. /// The places where it makes sense to use radians is when we convert /// to other representations or compute rotation matrices. But both tasks /// are computionally intensive anyway and that additional 'toRadian' /// conversion does not hurt too much double _lon; double _lat; double _radius; }; inline SGGeoc::SGGeoc(void) : _lon(0), _lat(0), _radius(0) { } inline SGGeoc::SGGeoc(double lon, double lat, double radius) : _lon(lon), _lat(lat), _radius(radius) { } inline SGGeoc SGGeoc::fromRadFt(double lon, double lat, double radius) { #ifdef SG_GEOC_NATIVE_DEGREE return SGGeoc(lon*SGD_RADIANS_TO_DEGREES, lat*SGD_RADIANS_TO_DEGREES, radius*SG_FEET_TO_METER); #else return SGGeoc(lon, lat, radius*SG_FEET_TO_METER); #endif } inline SGGeoc SGGeoc::fromDegFt(double lon, double lat, double radius) { #ifdef SG_GEOC_NATIVE_DEGREE return SGGeoc(lon, lat, radius*SG_FEET_TO_METER); #else return SGGeoc(lon*SGD_DEGREES_TO_RADIANS, lat*SGD_DEGREES_TO_RADIANS, radius*SG_FEET_TO_METER); #endif } inline SGGeoc SGGeoc::fromRadM(double lon, double lat, double radius) { #ifdef SG_GEOC_NATIVE_DEGREE return SGGeoc(lon*SGD_RADIANS_TO_DEGREES, lat*SGD_RADIANS_TO_DEGREES, radius); #else return SGGeoc(lon, lat, radius); #endif } inline SGGeoc SGGeoc::fromDegM(double lon, double lat, double radius) { #ifdef SG_GEOC_NATIVE_DEGREE return SGGeoc(lon, lat, radius); #else return SGGeoc(lon*SGD_DEGREES_TO_RADIANS, lat*SGD_DEGREES_TO_RADIANS, radius); #endif } inline SGGeoc SGGeoc::fromCart(const SGVec3& cart) { SGGeoc geoc; SGGeodesy::SGCartToGeoc(cart, geoc); return geoc; } inline SGGeoc SGGeoc::fromGeod(const SGGeod& geod) { SGVec3 cart; SGGeodesy::SGGeodToCart(geod, cart); SGGeoc geoc; SGGeodesy::SGCartToGeoc(cart, geoc); return geoc; } inline double SGGeoc::getLongitudeRad(void) const { #ifdef SG_GEOC_NATIVE_DEGREE return _lon*SGD_DEGREES_TO_RADIANS; #else return _lon; #endif } inline void SGGeoc::setLongitudeRad(double lon) { #ifdef SG_GEOC_NATIVE_DEGREE _lon = lon*SGD_RADIANS_TO_DEGREES; #else _lon = lon; #endif } inline double SGGeoc::getLongitudeDeg(void) const { #ifdef SG_GEOC_NATIVE_DEGREE return _lon; #else return _lon*SGD_RADIANS_TO_DEGREES; #endif } inline void SGGeoc::setLongitudeDeg(double lon) { #ifdef SG_GEOC_NATIVE_DEGREE _lon = lon; #else _lon = lon*SGD_DEGREES_TO_RADIANS; #endif } inline double SGGeoc::getLatitudeRad(void) const { #ifdef SG_GEOC_NATIVE_DEGREE return _lat*SGD_DEGREES_TO_RADIANS; #else return _lat; #endif } inline void SGGeoc::setLatitudeRad(double lat) { #ifdef SG_GEOC_NATIVE_DEGREE _lat = lat*SGD_RADIANS_TO_DEGREES; #else _lat = lat; #endif } inline double SGGeoc::getLatitudeDeg(void) const { #ifdef SG_GEOC_NATIVE_DEGREE return _lat; #else return _lat*SGD_RADIANS_TO_DEGREES; #endif } inline void SGGeoc::setLatitudeDeg(double lat) { #ifdef SG_GEOC_NATIVE_DEGREE _lat = lat; #else _lat = lat*SGD_DEGREES_TO_RADIANS; #endif } inline double SGGeoc::getRadiusM(void) const { return _radius; } inline void SGGeoc::setRadiusM(double radius) { _radius = radius; } inline double SGGeoc::getRadiusFt(void) const { return _radius*SG_METER_TO_FEET; } inline void SGGeoc::setRadiusFt(double radius) { _radius = radius*SG_FEET_TO_METER; } inline SGGeoc SGGeoc::advanceRadM(double course, double distance) const { SGGeoc result; SGGeodesy::advanceRadM(*this, course, distance, result); return result; } inline double SGGeoc::courseRad(const SGGeoc& from, const SGGeoc& to) { return SGGeodesy::courseRad(from, to); } inline double SGGeoc::courseDeg(const SGGeoc& from, const SGGeoc& to) { return SGMiscd::rad2deg(courseRad(from, to)); } inline double SGGeoc::distanceM(const SGGeoc& from, const SGGeoc& to) { return SGGeodesy::distanceM(from, to); } inline bool SGGeoc::operator == ( const SGGeoc & other ) const { return _lon == other._lon && _lat == other._lat && _radius == other._radius; } /// Output to an ostream template inline std::basic_ostream& operator<<(std::basic_ostream& s, const SGGeoc& g) { return s << "lon = " << g.getLongitudeDeg() << ", lat = " << g.getLatitudeDeg() << ", radius = " << g.getRadiusM(); } #endif