Gnomonic.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /**
  2. * \file Gnomonic.hpp
  3. * \brief Header for GeographicLib::Gnomonic class
  4. *
  5. * Copyright (c) Charles Karney (2010-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_GNOMONIC_HPP)
  10. #define GEOGRAPHICLIB_GNOMONIC_HPP 1
  11. #include <GeographicLib/Geodesic.hpp>
  12. #include <GeographicLib/GeodesicLine.hpp>
  13. #include <GeographicLib/Constants.hpp>
  14. namespace GeographicLib {
  15. /**
  16. * \brief %Gnomonic projection
  17. *
  18. * %Gnomonic projection centered at an arbitrary position \e C on the
  19. * ellipsoid. This projection is derived in Section 8 of
  20. * - C. F. F. Karney,
  21. * <a href="https://doi.org/10.1007/s00190-012-0578-z">
  22. * Algorithms for geodesics</a>,
  23. * J. Geodesy <b>87</b>, 43--55 (2013);
  24. * DOI: <a href="https://doi.org/10.1007/s00190-012-0578-z">
  25. * 10.1007/s00190-012-0578-z</a>;
  26. * addenda:
  27. * <a href="https://geographiclib.sourceforge.io/geod-addenda.html">
  28. * geod-addenda.html</a>.
  29. * .
  30. * The projection of \e P is defined as follows: compute the geodesic line
  31. * from \e C to \e P; compute the reduced length \e m12, geodesic scale \e
  32. * M12, and &rho; = <i>m12</i>/\e M12; finally \e x = &rho; sin \e azi1; \e
  33. * y = &rho; cos \e azi1, where \e azi1 is the azimuth of the geodesic at \e
  34. * C. The Gnomonic::Forward and Gnomonic::Reverse methods also return the
  35. * azimuth \e azi of the geodesic at \e P and reciprocal scale \e rk in the
  36. * azimuthal direction. The scale in the radial direction if
  37. * 1/<i>rk</i><sup>2</sup>.
  38. *
  39. * For a sphere, &rho; is reduces to \e a tan(<i>s12</i>/<i>a</i>), where \e
  40. * s12 is the length of the geodesic from \e C to \e P, and the gnomonic
  41. * projection has the property that all geodesics appear as straight lines.
  42. * For an ellipsoid, this property holds only for geodesics interesting the
  43. * centers. However geodesic segments close to the center are approximately
  44. * straight.
  45. *
  46. * Consider a geodesic segment of length \e l. Let \e T be the point on the
  47. * geodesic (extended if necessary) closest to \e C the center of the
  48. * projection and \e t be the distance \e CT. To lowest order, the maximum
  49. * deviation (as a true distance) of the corresponding gnomonic line segment
  50. * (i.e., with the same end points) from the geodesic is<br>
  51. * <br>
  52. * (<i>K</i>(<i>T</i>) - <i>K</i>(<i>C</i>))
  53. * <i>l</i><sup>2</sup> \e t / 32.<br>
  54. * <br>
  55. * where \e K is the Gaussian curvature.
  56. *
  57. * This result applies for any surface. For an ellipsoid of revolution,
  58. * consider all geodesics whose end points are within a distance \e r of \e
  59. * C. For a given \e r, the deviation is maximum when the latitude of \e C
  60. * is 45&deg;, when endpoints are a distance \e r away, and when their
  61. * azimuths from the center are &plusmn; 45&deg; or &plusmn; 135&deg;.
  62. * To lowest order in \e r and the flattening \e f, the deviation is \e f
  63. * (<i>r</i>/2<i>a</i>)<sup>3</sup> \e r.
  64. *
  65. * The conversions all take place using a Geodesic object (by default
  66. * Geodesic::WGS84()). For more information on geodesics see \ref geodesic.
  67. *
  68. * \warning The definition of this projection for a sphere is
  69. * standard. However, there is no standard for how it should be extended to
  70. * an ellipsoid. The choices are:
  71. * - Declare that the projection is undefined for an ellipsoid.
  72. * - Project to a tangent plane from the center of the ellipsoid. This
  73. * causes great ellipses to appear as straight lines in the projection;
  74. * i.e., it generalizes the spherical great circle to a great ellipse.
  75. * This was proposed by independently by Bowring and Williams in 1997.
  76. * - Project to the conformal sphere with the constant of integration chosen
  77. * so that the values of the latitude match for the center point and
  78. * perform a central projection onto the plane tangent to the conformal
  79. * sphere at the center point. This causes normal sections through the
  80. * center point to appear as straight lines in the projection; i.e., it
  81. * generalizes the spherical great circle to a normal section. This was
  82. * proposed by I. G. Letoval'tsev, Generalization of the gnomonic
  83. * projection for a spheroid and the principal geodetic problems involved
  84. * in the alignment of surface routes, Geodesy and Aerophotography (5),
  85. * 271--274 (1963).
  86. * - The projection given here. This causes geodesics close to the center
  87. * point to appear as straight lines in the projection; i.e., it
  88. * generalizes the spherical great circle to a geodesic.
  89. *
  90. * Example of use:
  91. * \include example-Gnomonic.cpp
  92. *
  93. * <a href="GeodesicProj.1.html">GeodesicProj</a> is a command-line utility
  94. * providing access to the functionality of AzimuthalEquidistant, Gnomonic,
  95. * and CassiniSoldner.
  96. **********************************************************************/
  97. class GEOGRAPHICLIB_EXPORT Gnomonic {
  98. private:
  99. typedef Math::real real;
  100. real eps0_, eps_;
  101. Geodesic _earth;
  102. real _a, _f;
  103. // numit_ increased from 10 to 20 to fix convergence failure with high
  104. // precision (e.g., GEOGRAPHICLIB_DIGITS=2000) calculations. Reverse uses
  105. // Newton's method which converges quadratically and so numit_ = 10 would
  106. // normally be big enough. However, since the Geodesic class is based on a
  107. // series it is of limited accuracy; in particular, the derivative rules
  108. // used by Reverse only hold approximately. Consequently, after a few
  109. // iterations, the convergence in the Reverse falls back to improvements in
  110. // each step by a constant (albeit small) factor.
  111. static const int numit_ = 20;
  112. public:
  113. /**
  114. * Constructor for Gnomonic.
  115. *
  116. * @param[in] earth the Geodesic object to use for geodesic calculations.
  117. * By default this uses the WGS84 ellipsoid.
  118. **********************************************************************/
  119. explicit Gnomonic(const Geodesic& earth = Geodesic::WGS84());
  120. /**
  121. * Forward projection, from geographic to gnomonic.
  122. *
  123. * @param[in] lat0 latitude of center point of projection (degrees).
  124. * @param[in] lon0 longitude of center point of projection (degrees).
  125. * @param[in] lat latitude of point (degrees).
  126. * @param[in] lon longitude of point (degrees).
  127. * @param[out] x easting of point (meters).
  128. * @param[out] y northing of point (meters).
  129. * @param[out] azi azimuth of geodesic at point (degrees).
  130. * @param[out] rk reciprocal of azimuthal scale at point.
  131. *
  132. * \e lat0 and \e lat should be in the range [&minus;90&deg;, 90&deg;].
  133. * The scale of the projection is 1/<i>rk</i><sup>2</sup> in the "radial"
  134. * direction, \e azi clockwise from true north, and is 1/\e rk in the
  135. * direction perpendicular to this. If the point lies "over the horizon",
  136. * i.e., if \e rk &le; 0, then NaNs are returned for \e x and \e y (the
  137. * correct values are returned for \e azi and \e rk). A call to Forward
  138. * followed by a call to Reverse will return the original (\e lat, \e lon)
  139. * (to within roundoff) provided the point in not over the horizon.
  140. **********************************************************************/
  141. void Forward(real lat0, real lon0, real lat, real lon,
  142. real& x, real& y, real& azi, real& rk) const;
  143. /**
  144. * Reverse projection, from gnomonic to geographic.
  145. *
  146. * @param[in] lat0 latitude of center point of projection (degrees).
  147. * @param[in] lon0 longitude of center point of projection (degrees).
  148. * @param[in] x easting of point (meters).
  149. * @param[in] y northing of point (meters).
  150. * @param[out] lat latitude of point (degrees).
  151. * @param[out] lon longitude of point (degrees).
  152. * @param[out] azi azimuth of geodesic at point (degrees).
  153. * @param[out] rk reciprocal of azimuthal scale at point.
  154. *
  155. * \e lat0 should be in the range [&minus;90&deg;, 90&deg;]. \e lat will
  156. * be in the range [&minus;90&deg;, 90&deg;] and \e lon will be in the
  157. * range [&minus;180&deg;, 180&deg;]. The scale of the projection is
  158. * 1/<i>rk</i><sup>2</sup> in the "radial" direction, \e azi clockwise from
  159. * true north, and is 1/\e rk in the direction perpendicular to this. Even
  160. * though all inputs should return a valid \e lat and \e lon, it's possible
  161. * that the procedure fails to converge for very large \e x or \e y; in
  162. * this case NaNs are returned for all the output arguments. A call to
  163. * Reverse followed by a call to Forward will return the original (\e x, \e
  164. * y) (to roundoff).
  165. **********************************************************************/
  166. void Reverse(real lat0, real lon0, real x, real y,
  167. real& lat, real& lon, real& azi, real& rk) const;
  168. /**
  169. * Gnomonic::Forward without returning the azimuth and scale.
  170. **********************************************************************/
  171. void Forward(real lat0, real lon0, real lat, real lon,
  172. real& x, real& y) const {
  173. real azi, rk;
  174. Forward(lat0, lon0, lat, lon, x, y, azi, rk);
  175. }
  176. /**
  177. * Gnomonic::Reverse without returning the azimuth and scale.
  178. **********************************************************************/
  179. void Reverse(real lat0, real lon0, real x, real y,
  180. real& lat, real& lon) const {
  181. real azi, rk;
  182. Reverse(lat0, lon0, x, y, lat, lon, azi, rk);
  183. }
  184. /** \name Inspector functions
  185. **********************************************************************/
  186. ///@{
  187. /**
  188. * @return \e a the equatorial radius of the ellipsoid (meters). This is
  189. * the value inherited from the Geodesic object used in the constructor.
  190. **********************************************************************/
  191. Math::real EquatorialRadius() const { return _earth.EquatorialRadius(); }
  192. /**
  193. * @return \e f the flattening of the ellipsoid. This is the value
  194. * inherited from the Geodesic object used in the constructor.
  195. **********************************************************************/
  196. Math::real Flattening() const { return _earth.Flattening(); }
  197. /**
  198. * \deprecated An old name for EquatorialRadius().
  199. **********************************************************************/
  200. GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
  201. Math::real MajorRadius() const { return EquatorialRadius(); }
  202. ///@}
  203. };
  204. } // namespace GeographicLib
  205. #endif // GEOGRAPHICLIB_GNOMONIC_HPP