area.hpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
  3. // Copyright (c) 2016-2018 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_STRATEGIES_GEOGRAPHIC_AREA_HPP
  10. #define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AREA_HPP
  11. #include <boost/geometry/srs/spheroid.hpp>
  12. #include <boost/geometry/formulas/area_formulas.hpp>
  13. #include <boost/geometry/formulas/authalic_radius_sqr.hpp>
  14. #include <boost/geometry/formulas/eccentricity_sqr.hpp>
  15. #include <boost/geometry/strategies/area.hpp>
  16. #include <boost/geometry/strategies/geographic/parameters.hpp>
  17. namespace boost { namespace geometry
  18. {
  19. namespace strategy { namespace area
  20. {
  21. /*!
  22. \brief Geographic area calculation
  23. \ingroup strategies
  24. \details Geographic area calculation by trapezoidal rule plus integral
  25. approximation that gives the ellipsoidal correction
  26. \tparam FormulaPolicy Formula used to calculate azimuths
  27. \tparam SeriesOrder The order of approximation of the geodesic integral
  28. \tparam Spheroid The spheroid model
  29. \tparam CalculationType \tparam_calculation
  30. \author See
  31. - Danielsen JS, The area under the geodesic. Surv Rev 30(232): 61–66, 1989
  32. - Charles F.F Karney, Algorithms for geodesics, 2011 https://arxiv.org/pdf/1109.4448.pdf
  33. \qbk{
  34. [heading See also]
  35. \* [link geometry.reference.algorithms.area.area_2_with_strategy area (with strategy)]
  36. \* [link geometry.reference.srs.srs_spheroid srs::spheroid]
  37. }
  38. */
  39. template
  40. <
  41. typename FormulaPolicy = strategy::andoyer,
  42. std::size_t SeriesOrder = strategy::default_order<FormulaPolicy>::value,
  43. typename Spheroid = srs::spheroid<double>,
  44. typename CalculationType = void
  45. >
  46. class geographic
  47. {
  48. // Switch between two kinds of approximation(series in eps and n v.s.series in k ^ 2 and e'^2)
  49. static const bool ExpandEpsN = true;
  50. // LongSegment Enables special handling of long segments
  51. static const bool LongSegment = false;
  52. //Select default types in case they are not set
  53. public:
  54. template <typename Geometry>
  55. struct result_type
  56. : strategy::area::detail::result_type
  57. <
  58. Geometry,
  59. CalculationType
  60. >
  61. {};
  62. protected :
  63. struct spheroid_constants
  64. {
  65. typedef typename boost::mpl::if_c
  66. <
  67. boost::is_void<CalculationType>::value,
  68. typename geometry::radius_type<Spheroid>::type,
  69. CalculationType
  70. >::type calc_t;
  71. Spheroid m_spheroid;
  72. calc_t const m_a2; // squared equatorial radius
  73. calc_t const m_e2; // squared eccentricity
  74. calc_t const m_ep2; // squared second eccentricity
  75. calc_t const m_ep; // second eccentricity
  76. calc_t const m_c2; // squared authalic radius
  77. inline spheroid_constants(Spheroid const& spheroid)
  78. : m_spheroid(spheroid)
  79. , m_a2(math::sqr(get_radius<0>(spheroid)))
  80. , m_e2(formula::eccentricity_sqr<calc_t>(spheroid))
  81. , m_ep2(m_e2 / (calc_t(1.0) - m_e2))
  82. , m_ep(math::sqrt(m_ep2))
  83. , m_c2(formula_dispatch::authalic_radius_sqr
  84. <
  85. calc_t, Spheroid, srs_spheroid_tag
  86. >::apply(m_a2, m_e2))
  87. {}
  88. };
  89. public:
  90. template <typename Geometry>
  91. class state
  92. {
  93. friend class geographic;
  94. typedef typename result_type<Geometry>::type return_type;
  95. public:
  96. inline state()
  97. : m_excess_sum(0)
  98. , m_correction_sum(0)
  99. , m_crosses_prime_meridian(0)
  100. {}
  101. private:
  102. inline return_type area(spheroid_constants const& spheroid_const) const
  103. {
  104. return_type result;
  105. return_type sum = spheroid_const.m_c2 * m_excess_sum
  106. + spheroid_const.m_e2 * spheroid_const.m_a2 * m_correction_sum;
  107. // If encircles some pole
  108. if (m_crosses_prime_meridian % 2 == 1)
  109. {
  110. std::size_t times_crosses_prime_meridian
  111. = 1 + (m_crosses_prime_meridian / 2);
  112. result = return_type(2.0)
  113. * geometry::math::pi<return_type>()
  114. * spheroid_const.m_c2
  115. * return_type(times_crosses_prime_meridian)
  116. - geometry::math::abs(sum);
  117. if (geometry::math::sign<return_type>(sum) == 1)
  118. {
  119. result = - result;
  120. }
  121. }
  122. else
  123. {
  124. result = sum;
  125. }
  126. return result;
  127. }
  128. return_type m_excess_sum;
  129. return_type m_correction_sum;
  130. // Keep track if encircles some pole
  131. std::size_t m_crosses_prime_meridian;
  132. };
  133. public :
  134. explicit inline geographic(Spheroid const& spheroid = Spheroid())
  135. : m_spheroid_constants(spheroid)
  136. {}
  137. template <typename PointOfSegment, typename Geometry>
  138. inline void apply(PointOfSegment const& p1,
  139. PointOfSegment const& p2,
  140. state<Geometry>& st) const
  141. {
  142. if (! geometry::math::equals(get<0>(p1), get<0>(p2)))
  143. {
  144. typedef geometry::formula::area_formulas
  145. <
  146. typename result_type<Geometry>::type,
  147. SeriesOrder, ExpandEpsN
  148. > area_formulas;
  149. typename area_formulas::return_type_ellipsoidal result =
  150. area_formulas::template ellipsoidal<FormulaPolicy::template inverse>
  151. (p1, p2, m_spheroid_constants);
  152. st.m_excess_sum += result.spherical_term;
  153. st.m_correction_sum += result.ellipsoidal_term;
  154. // Keep track whenever a segment crosses the prime meridian
  155. if (area_formulas::crosses_prime_meridian(p1, p2))
  156. {
  157. st.m_crosses_prime_meridian++;
  158. }
  159. }
  160. }
  161. template <typename Geometry>
  162. inline typename result_type<Geometry>::type
  163. result(state<Geometry> const& st) const
  164. {
  165. return st.area(m_spheroid_constants);
  166. }
  167. private:
  168. spheroid_constants m_spheroid_constants;
  169. };
  170. #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
  171. namespace services
  172. {
  173. template <>
  174. struct default_strategy<geographic_tag>
  175. {
  176. typedef strategy::area::geographic<> type;
  177. };
  178. #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
  179. }
  180. }} // namespace strategy::area
  181. }} // namespace boost::geometry
  182. #endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AREA_HPP