00001 /** 00002 * \file Geocentric.hpp 00003 * \brief Header for GeographicLib::Geocentric class 00004 * 00005 * Copyright (c) Charles Karney (2008) <charles@karney.com> 00006 * and licensed under the LGPL. 00007 **********************************************************************/ 00008 00009 #if !defined(GEOCENTRIC_HPP) 00010 #define GEOCENTRIC_HPP "$Id: Geocentric.hpp 6559 2009-02-28 16:49:53Z ckarney $" 00011 00012 #include <cmath> 00013 00014 namespace GeographicLib { 00015 00016 /** 00017 * \brief %Geocentric coordinates 00018 * 00019 * Convert between geodetic coordinates latitude = \e lat, longitude = \e 00020 * lon, height = \e h (measured vertically from the surface of the ellipsoid) 00021 * to geocentric coordinates (\e x, \e y, \e z). The origin of geocentric 00022 * coordinates is at the center of the earth. The \e z axis goes thru the 00023 * north pole, \e lat = 90<sup>o</sup>. The \e x axis goes thru \e lat = 0, 00024 * \e lon = 0. Geocentric coordinates are also known as earth centered, 00025 * earth fixed (ECEF) coordinates. 00026 * 00027 * The conversion from geographic to geocentric coordinates is 00028 * straightforward. For the reverse transformation we use 00029 * - H. Vermeille, 00030 * <a href="http://dx.doi.org/10.1007/s00190-002-0273-6"> Direct 00031 * transformation from geocentric coordinates to geodetic coordinates</a>, 00032 * J. Geodesy 76, 451–454 (2002). 00033 * . 00034 * Several changes have been made to ensure that the method returns accurate 00035 * results for all finite inputs (even if \e h is infinite). See 00036 * \ref geocentric for details. 00037 * 00038 * The errors in these routines are close to round-off. Specifically, for 00039 * points within 5000 km of the surface of the ellipsoid (either inside or 00040 * outside the ellipsoid), the error is bounded by 7 nm for the WGS84 00041 * ellipsoid. See \ref geocentric for further information on the errors. 00042 **********************************************************************/ 00043 00044 class Geocentric { 00045 private: 00046 const double _a, _f, _e2, _e4, _e2m, _maxrad; 00047 static inline double sq(double x) throw() { return x * x; } 00048 #if defined(_MSC_VER) 00049 static inline double hypot(double x, double y) throw() 00050 { return _hypot(x, y); } 00051 static inline double cbrt(double x) throw() { 00052 double y = std::pow(std::abs(x), 1/3.0); 00053 return x < 0 ? -y : y; 00054 } 00055 #else 00056 static inline double hypot(double x, double y) throw() 00057 { return ::hypot(x, y); } 00058 static inline double cbrt(double x) throw() { return ::cbrt(x); } 00059 #endif 00060 public: 00061 00062 /** 00063 * Constructor for a ellipsoid radius \e a (meters) and inverse flattening 00064 * \e invf. Setting \e invf <= 0 implies \e invf = inf or flattening = 0 00065 * (i.e., a sphere). 00066 **********************************************************************/ 00067 Geocentric(double a, double invf) throw(); 00068 00069 /** 00070 * Convert from geodetic coordinates \e lat, \e lon (degrees), \e h 00071 * (meters) to geocentric coordinates \e x, \e y, \e z (meters). \e lat 00072 * should be in the range [-90, 90]; \e lon and \e lon0 should be in the 00073 * range [-180, 360]. 00074 **********************************************************************/ 00075 void Forward(double lat, double lon, double h, 00076 double& x, double& y, double& z) const throw(); 00077 00078 /** 00079 * Convert from geocentric coordinates \e x, \e y, \e z (meters) to 00080 * geodetic \e lat, \e lon (degrees), \e h (meters). In general there are 00081 * multiple solutions and the result which minimizes the absolute value of 00082 * \e h is returned. If there are still multiple solutions with different 00083 * latitutes (applies only if \e z = 0), then the solution with \e lat > 0 00084 * is returned. If there are still multiple solutions with different 00085 * longitudes (applies only if \e x = \e y = 0) then \e lon = 0 is 00086 * returned. The value of \e h returned satisfies \e h >= - \e a (1 - \e 00087 * e<sup>2</sup>) / sqrt(1 - \e e<sup>2</sup> sin<sup>2</sup>\e lat). The 00088 * value of \e lon returned is in the range [-180, 180). 00089 **********************************************************************/ 00090 void Reverse(double x, double y, double z, 00091 double& lat, double& lon, double& h) const throw(); 00092 00093 /** 00094 * A global instantiation of Geocentric with the parameters for the WGS84 00095 * ellipsoid. 00096 **********************************************************************/ 00097 const static Geocentric WGS84; 00098 }; 00099 00100 } //namespace GeographicLib 00101 #endif