Geocentric.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /**
  2. * \file Geocentric.hpp
  3. * \brief Header for GeographicLib::Geocentric class
  4. *
  5. * Copyright (c) Charles Karney (2008-2020) <charles@karney.com> and licensed
  6. * under the MIT/X11 License. For more information, see
  7. * https://geographiclib.sourceforge.io/
  8. **********************************************************************/
  9. #if !defined(GEOGRAPHICLIB_GEOCENTRIC_HPP)
  10. #define GEOGRAPHICLIB_GEOCENTRIC_HPP 1
  11. #include <vector>
  12. #include <GeographicLib/Constants.hpp>
  13. namespace GeographicLib {
  14. /**
  15. * \brief %Geocentric coordinates
  16. *
  17. * Convert between geodetic coordinates latitude = \e lat, longitude = \e
  18. * lon, height = \e h (measured vertically from the surface of the ellipsoid)
  19. * to geocentric coordinates (\e X, \e Y, \e Z). The origin of geocentric
  20. * coordinates is at the center of the earth. The \e Z axis goes thru the
  21. * north pole, \e lat = 90&deg;. The \e X axis goes thru \e lat = 0,
  22. * \e lon = 0. %Geocentric coordinates are also known as earth centered,
  23. * earth fixed (ECEF) coordinates.
  24. *
  25. * The conversion from geographic to geocentric coordinates is
  26. * straightforward. For the reverse transformation we use
  27. * - H. Vermeille,
  28. * <a href="https://doi.org/10.1007/s00190-002-0273-6"> Direct
  29. * transformation from geocentric coordinates to geodetic coordinates</a>,
  30. * J. Geodesy 76, 451--454 (2002).
  31. * .
  32. * Several changes have been made to ensure that the method returns accurate
  33. * results for all finite inputs (even if \e h is infinite). The changes are
  34. * described in Appendix B of
  35. * - C. F. F. Karney,
  36. * <a href="https://arxiv.org/abs/1102.1215v1">Geodesics
  37. * on an ellipsoid of revolution</a>,
  38. * Feb. 2011;
  39. * preprint
  40. * <a href="https://arxiv.org/abs/1102.1215v1">arxiv:1102.1215v1</a>.
  41. * .
  42. * Vermeille similarly updated his method in
  43. * - H. Vermeille,
  44. * <a href="https://doi.org/10.1007/s00190-010-0419-x">
  45. * An analytical method to transform geocentric into
  46. * geodetic coordinates</a>, J. Geodesy 85, 105--117 (2011).
  47. * .
  48. * See \ref geocentric for more information.
  49. *
  50. * The errors in these routines are close to round-off. Specifically, for
  51. * points within 5000 km of the surface of the ellipsoid (either inside or
  52. * outside the ellipsoid), the error is bounded by 7 nm (7 nanometers) for
  53. * the WGS84 ellipsoid. See \ref geocentric for further information on the
  54. * errors.
  55. *
  56. * Example of use:
  57. * \include example-Geocentric.cpp
  58. *
  59. * <a href="CartConvert.1.html">CartConvert</a> is a command-line utility
  60. * providing access to the functionality of Geocentric and LocalCartesian.
  61. **********************************************************************/
  62. class GEOGRAPHICLIB_EXPORT Geocentric {
  63. private:
  64. typedef Math::real real;
  65. friend class LocalCartesian;
  66. friend class MagneticCircle; // MagneticCircle uses Rotation
  67. friend class MagneticModel; // MagneticModel uses IntForward
  68. friend class GravityCircle; // GravityCircle uses Rotation
  69. friend class GravityModel; // GravityModel uses IntForward
  70. friend class NormalGravity; // NormalGravity uses IntForward
  71. static const size_t dim_ = 3;
  72. static const size_t dim2_ = dim_ * dim_;
  73. real _a, _f, _e2, _e2m, _e2a, _e4a, _maxrad;
  74. static void Rotation(real sphi, real cphi, real slam, real clam,
  75. real M[dim2_]);
  76. static void Rotate(const real M[dim2_], real x, real y, real z,
  77. real& X, real& Y, real& Z) {
  78. // Perform [X,Y,Z]^t = M.[x,y,z]^t
  79. // (typically local cartesian to geocentric)
  80. X = M[0] * x + M[1] * y + M[2] * z;
  81. Y = M[3] * x + M[4] * y + M[5] * z;
  82. Z = M[6] * x + M[7] * y + M[8] * z;
  83. }
  84. static void Unrotate(const real M[dim2_], real X, real Y, real Z,
  85. real& x, real& y, real& z) {
  86. // Perform [x,y,z]^t = M^t.[X,Y,Z]^t
  87. // (typically geocentric to local cartesian)
  88. x = M[0] * X + M[3] * Y + M[6] * Z;
  89. y = M[1] * X + M[4] * Y + M[7] * Z;
  90. z = M[2] * X + M[5] * Y + M[8] * Z;
  91. }
  92. void IntForward(real lat, real lon, real h, real& X, real& Y, real& Z,
  93. real M[dim2_]) const;
  94. void IntReverse(real X, real Y, real Z, real& lat, real& lon, real& h,
  95. real M[dim2_]) const;
  96. public:
  97. /**
  98. * Constructor for a ellipsoid with
  99. *
  100. * @param[in] a equatorial radius (meters).
  101. * @param[in] f flattening of ellipsoid. Setting \e f = 0 gives a sphere.
  102. * Negative \e f gives a prolate ellipsoid.
  103. * @exception GeographicErr if \e a or (1 &minus; \e f) \e a is not
  104. * positive.
  105. **********************************************************************/
  106. Geocentric(real a, real f);
  107. /**
  108. * A default constructor (for use by NormalGravity).
  109. **********************************************************************/
  110. Geocentric() : _a(-1) {}
  111. /**
  112. * Convert from geodetic to geocentric coordinates.
  113. *
  114. * @param[in] lat latitude of point (degrees).
  115. * @param[in] lon longitude of point (degrees).
  116. * @param[in] h height of point above the ellipsoid (meters).
  117. * @param[out] X geocentric coordinate (meters).
  118. * @param[out] Y geocentric coordinate (meters).
  119. * @param[out] Z geocentric coordinate (meters).
  120. *
  121. * \e lat should be in the range [&minus;90&deg;, 90&deg;].
  122. **********************************************************************/
  123. void Forward(real lat, real lon, real h, real& X, real& Y, real& Z)
  124. const {
  125. if (Init())
  126. IntForward(lat, lon, h, X, Y, Z, NULL);
  127. }
  128. /**
  129. * Convert from geodetic to geocentric coordinates and return rotation
  130. * matrix.
  131. *
  132. * @param[in] lat latitude of point (degrees).
  133. * @param[in] lon longitude of point (degrees).
  134. * @param[in] h height of point above the ellipsoid (meters).
  135. * @param[out] X geocentric coordinate (meters).
  136. * @param[out] Y geocentric coordinate (meters).
  137. * @param[out] Z geocentric coordinate (meters).
  138. * @param[out] M if the length of the vector is 9, fill with the rotation
  139. * matrix in row-major order.
  140. *
  141. * Let \e v be a unit vector located at (\e lat, \e lon, \e h). We can
  142. * express \e v as \e column vectors in one of two ways
  143. * - in east, north, up coordinates (where the components are relative to a
  144. * local coordinate system at (\e lat, \e lon, \e h)); call this
  145. * representation \e v1.
  146. * - in geocentric \e X, \e Y, \e Z coordinates; call this representation
  147. * \e v0.
  148. * .
  149. * Then we have \e v0 = \e M &sdot; \e v1.
  150. **********************************************************************/
  151. void Forward(real lat, real lon, real h, real& X, real& Y, real& Z,
  152. std::vector<real>& M)
  153. const {
  154. if (!Init())
  155. return;
  156. if (M.end() == M.begin() + dim2_) {
  157. real t[dim2_];
  158. IntForward(lat, lon, h, X, Y, Z, t);
  159. std::copy(t, t + dim2_, M.begin());
  160. } else
  161. IntForward(lat, lon, h, X, Y, Z, NULL);
  162. }
  163. /**
  164. * Convert from geocentric to geodetic to coordinates.
  165. *
  166. * @param[in] X geocentric coordinate (meters).
  167. * @param[in] Y geocentric coordinate (meters).
  168. * @param[in] Z geocentric coordinate (meters).
  169. * @param[out] lat latitude of point (degrees).
  170. * @param[out] lon longitude of point (degrees).
  171. * @param[out] h height of point above the ellipsoid (meters).
  172. *
  173. * In general, there are multiple solutions and the result which minimizes
  174. * |<i>h</i> |is returned, i.e., (<i>lat</i>, <i>lon</i>) corresponds to
  175. * the closest point on the ellipsoid. If there are still multiple
  176. * solutions with different latitudes (applies only if \e Z = 0), then the
  177. * solution with \e lat > 0 is returned. If there are still multiple
  178. * solutions with different longitudes (applies only if \e X = \e Y = 0)
  179. * then \e lon = 0 is returned. The value of \e h returned satisfies \e h
  180. * &ge; &minus; \e a (1 &minus; <i>e</i><sup>2</sup>) / sqrt(1 &minus;
  181. * <i>e</i><sup>2</sup> sin<sup>2</sup>\e lat). The value of \e lon
  182. * returned is in the range [&minus;180&deg;, 180&deg;].
  183. **********************************************************************/
  184. void Reverse(real X, real Y, real Z, real& lat, real& lon, real& h)
  185. const {
  186. if (Init())
  187. IntReverse(X, Y, Z, lat, lon, h, NULL);
  188. }
  189. /**
  190. * Convert from geocentric to geodetic to coordinates.
  191. *
  192. * @param[in] X geocentric coordinate (meters).
  193. * @param[in] Y geocentric coordinate (meters).
  194. * @param[in] Z geocentric coordinate (meters).
  195. * @param[out] lat latitude of point (degrees).
  196. * @param[out] lon longitude of point (degrees).
  197. * @param[out] h height of point above the ellipsoid (meters).
  198. * @param[out] M if the length of the vector is 9, fill with the rotation
  199. * matrix in row-major order.
  200. *
  201. * Let \e v be a unit vector located at (\e lat, \e lon, \e h). We can
  202. * express \e v as \e column vectors in one of two ways
  203. * - in east, north, up coordinates (where the components are relative to a
  204. * local coordinate system at (\e lat, \e lon, \e h)); call this
  205. * representation \e v1.
  206. * - in geocentric \e X, \e Y, \e Z coordinates; call this representation
  207. * \e v0.
  208. * .
  209. * Then we have \e v1 = <i>M</i><sup>T</sup> &sdot; \e v0, where
  210. * <i>M</i><sup>T</sup> is the transpose of \e M.
  211. **********************************************************************/
  212. void Reverse(real X, real Y, real Z, real& lat, real& lon, real& h,
  213. std::vector<real>& M)
  214. const {
  215. if (!Init())
  216. return;
  217. if (M.end() == M.begin() + dim2_) {
  218. real t[dim2_];
  219. IntReverse(X, Y, Z, lat, lon, h, t);
  220. std::copy(t, t + dim2_, M.begin());
  221. } else
  222. IntReverse(X, Y, Z, lat, lon, h, NULL);
  223. }
  224. /** \name Inspector functions
  225. **********************************************************************/
  226. ///@{
  227. /**
  228. * @return true if the object has been initialized.
  229. **********************************************************************/
  230. bool Init() const { return _a > 0; }
  231. /**
  232. * @return \e a the equatorial radius of the ellipsoid (meters). This is
  233. * the value used in the constructor.
  234. **********************************************************************/
  235. Math::real EquatorialRadius() const
  236. { return Init() ? _a : Math::NaN(); }
  237. /**
  238. * @return \e f the flattening of the ellipsoid. This is the
  239. * value used in the constructor.
  240. **********************************************************************/
  241. Math::real Flattening() const
  242. { return Init() ? _f : Math::NaN(); }
  243. /**
  244. * \deprecated An old name for EquatorialRadius().
  245. **********************************************************************/
  246. GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
  247. Math::real MajorRadius() const { return EquatorialRadius(); }
  248. ///@}
  249. /**
  250. * A global instantiation of Geocentric with the parameters for the WGS84
  251. * ellipsoid.
  252. **********************************************************************/
  253. static const Geocentric& WGS84();
  254. };
  255. } // namespace GeographicLib
  256. #endif // GEOGRAPHICLIB_GEOCENTRIC_HPP