area.hpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
  3. // Copyright (c) 2016-2020 Oracle and/or its affiliates.
  4. // Contributed and/or modified by Vissarion Fisikopoulos, on behalf of Oracle
  5. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  6. // Use, modification and distribution is subject to the Boost Software License,
  7. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  8. // http://www.boost.org/LICENSE_1_0.txt)
  9. #ifndef BOOST_GEOMETRY_STRATEGY_GEOGRAPHIC_AREA_HPP
  10. #define BOOST_GEOMETRY_STRATEGY_GEOGRAPHIC_AREA_HPP
  11. #include <type_traits>
  12. #include <boost/geometry/srs/spheroid.hpp>
  13. #include <boost/geometry/formulas/area_formulas.hpp>
  14. #include <boost/geometry/formulas/authalic_radius_sqr.hpp>
  15. #include <boost/geometry/formulas/eccentricity_sqr.hpp>
  16. #include <boost/geometry/strategy/area.hpp>
  17. #include <boost/geometry/strategies/geographic/parameters.hpp>
  18. namespace boost { namespace geometry
  19. {
  20. namespace strategy { namespace area
  21. {
  22. /*!
  23. \brief Geographic area calculation
  24. \ingroup strategies
  25. \details Geographic area calculation by trapezoidal rule plus integral
  26. approximation that gives the ellipsoidal correction
  27. \tparam FormulaPolicy Formula used to calculate azimuths
  28. \tparam SeriesOrder The order of approximation of the geodesic integral
  29. \tparam Spheroid The spheroid model
  30. \tparam CalculationType \tparam_calculation
  31. \author See
  32. - Danielsen JS, The area under the geodesic. Surv Rev 30(232): 61–66, 1989
  33. - Charles F.F Karney, Algorithms for geodesics, 2011 https://arxiv.org/pdf/1109.4448.pdf
  34. \qbk{
  35. [heading See also]
  36. \* [link geometry.reference.algorithms.area.area_2_with_strategy area (with strategy)]
  37. \* [link geometry.reference.srs.srs_spheroid srs::spheroid]
  38. }
  39. */
  40. template
  41. <
  42. typename FormulaPolicy = strategy::andoyer,
  43. std::size_t SeriesOrder = strategy::default_order<FormulaPolicy>::value,
  44. typename Spheroid = srs::spheroid<double>,
  45. typename CalculationType = void
  46. >
  47. class geographic
  48. {
  49. // Switch between two kinds of approximation(series in eps and n v.s.series in k ^ 2 and e'^2)
  50. static const bool ExpandEpsN = true;
  51. // LongSegment Enables special handling of long segments
  52. static const bool LongSegment = false;
  53. // Area formula is implemented for a maximum series order 5
  54. static constexpr auto SeriesOrderNorm = SeriesOrder > 5 ? 5 : SeriesOrder;
  55. //Select default types in case they are not set
  56. public:
  57. template <typename Geometry>
  58. struct result_type
  59. : strategy::area::detail::result_type
  60. <
  61. Geometry,
  62. CalculationType
  63. >
  64. {};
  65. protected :
  66. struct spheroid_constants
  67. {
  68. typedef std::conditional_t
  69. <
  70. std::is_void<CalculationType>::value,
  71. typename geometry::radius_type<Spheroid>::type,
  72. CalculationType
  73. > calc_t;
  74. Spheroid m_spheroid;
  75. calc_t const m_a2; // squared equatorial radius
  76. calc_t const m_e2; // squared eccentricity
  77. calc_t const m_ep2; // squared second eccentricity
  78. calc_t const m_ep; // second eccentricity
  79. calc_t const m_c2; // squared authalic radius
  80. calc_t const m_f; // the flattening
  81. calc_t m_coeffs_var[((SeriesOrderNorm+2)*(SeriesOrderNorm+1))/2];
  82. inline spheroid_constants(Spheroid const& spheroid)
  83. : m_spheroid(spheroid)
  84. , m_a2(math::sqr(get_radius<0>(spheroid)))
  85. , m_e2(formula::eccentricity_sqr<calc_t>(spheroid))
  86. , m_ep2(m_e2 / (calc_t(1.0) - m_e2))
  87. , m_ep(math::sqrt(m_ep2))
  88. , m_c2(formula_dispatch::authalic_radius_sqr
  89. <
  90. calc_t, Spheroid, srs_spheroid_tag
  91. >::apply(m_a2, m_e2))
  92. , m_f(formula::flattening<calc_t>(spheroid))
  93. {
  94. typedef geometry::formula::area_formulas
  95. <
  96. calc_t, SeriesOrderNorm, ExpandEpsN
  97. > area_formulas;
  98. calc_t const n = m_f / (calc_t(2) - m_f);
  99. // Generate and evaluate the polynomials on n
  100. // to get the series coefficients (that depend on eps)
  101. area_formulas::evaluate_coeffs_n(n, m_coeffs_var);
  102. }
  103. };
  104. public:
  105. template <typename Geometry>
  106. class state
  107. {
  108. friend class geographic;
  109. typedef typename result_type<Geometry>::type return_type;
  110. public:
  111. inline state()
  112. : m_excess_sum(0)
  113. , m_correction_sum(0)
  114. , m_crosses_prime_meridian(0)
  115. {}
  116. private:
  117. inline return_type area(spheroid_constants const& spheroid_const) const
  118. {
  119. return_type result;
  120. return_type const spherical_term = spheroid_const.m_c2 * m_excess_sum;
  121. return_type const ellipsoidal_term = spheroid_const.m_e2
  122. * spheroid_const.m_a2 * m_correction_sum;
  123. // ignore ellipsoidal term if is large (probably from an azimuth
  124. // inaccuracy)
  125. return_type sum = math::abs(ellipsoidal_term/spherical_term) > 0.01
  126. ? spherical_term : spherical_term + ellipsoidal_term;
  127. // If encircles some pole
  128. if (m_crosses_prime_meridian % 2 == 1)
  129. {
  130. std::size_t times_crosses_prime_meridian
  131. = 1 + (m_crosses_prime_meridian / 2);
  132. result = return_type(2.0)
  133. * geometry::math::pi<return_type>()
  134. * spheroid_const.m_c2
  135. * return_type(times_crosses_prime_meridian)
  136. - geometry::math::abs(sum);
  137. if (geometry::math::sign<return_type>(sum) == 1)
  138. {
  139. result = - result;
  140. }
  141. }
  142. else
  143. {
  144. result = sum;
  145. }
  146. return result;
  147. }
  148. return_type m_excess_sum;
  149. return_type m_correction_sum;
  150. // Keep track if encircles some pole
  151. std::size_t m_crosses_prime_meridian;
  152. };
  153. public :
  154. explicit inline geographic(Spheroid const& spheroid = Spheroid())
  155. : m_spheroid_constants(spheroid)
  156. {}
  157. template <typename PointOfSegment, typename Geometry>
  158. inline void apply(PointOfSegment const& p1,
  159. PointOfSegment const& p2,
  160. state<Geometry>& st) const
  161. {
  162. using CT = typename result_type<Geometry>::type;
  163. // if the segment in not on a meridian
  164. if (! geometry::math::equals(get<0>(p1), get<0>(p2)))
  165. {
  166. typedef geometry::formula::area_formulas
  167. <
  168. CT, SeriesOrderNorm, ExpandEpsN
  169. > area_formulas;
  170. // Keep track whenever a segment crosses the prime meridian
  171. if (area_formulas::crosses_prime_meridian(p1, p2))
  172. {
  173. st.m_crosses_prime_meridian++;
  174. }
  175. // if the segment in not on equator
  176. if (! (geometry::math::equals(get<1>(p1), 0)
  177. && geometry::math::equals(get<1>(p2), 0)))
  178. {
  179. auto result = area_formulas::template ellipsoidal
  180. <
  181. FormulaPolicy::template inverse
  182. >(p1, p2, m_spheroid_constants);
  183. st.m_excess_sum += result.spherical_term;
  184. st.m_correction_sum += result.ellipsoidal_term;
  185. }
  186. }
  187. }
  188. template <typename Geometry>
  189. inline typename result_type<Geometry>::type
  190. result(state<Geometry> const& st) const
  191. {
  192. return st.area(m_spheroid_constants);
  193. }
  194. Spheroid model() const
  195. {
  196. return m_spheroid_constants.m_spheroid;
  197. }
  198. private:
  199. spheroid_constants m_spheroid_constants;
  200. };
  201. #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
  202. namespace services
  203. {
  204. template <>
  205. struct default_strategy<geographic_tag>
  206. {
  207. typedef strategy::area::geographic<> type;
  208. };
  209. #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
  210. }
  211. }} // namespace strategy::area
  212. }} // namespace boost::geometry
  213. #endif // BOOST_GEOMETRY_STRATEGY_GEOGRAPHIC_AREA_HPP