Geocentric.hpp
Go to the documentation of this file.
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&ndash;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