area.hpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  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_SPHERICAL_AREA_HPP
  10. #define BOOST_GEOMETRY_STRATEGY_SPHERICAL_AREA_HPP
  11. #include <boost/geometry/formulas/area_formulas.hpp>
  12. #include <boost/geometry/srs/sphere.hpp>
  13. #include <boost/geometry/strategy/area.hpp>
  14. #include <boost/geometry/strategies/spherical/get_radius.hpp>
  15. namespace boost { namespace geometry
  16. {
  17. namespace strategy { namespace area
  18. {
  19. /*!
  20. \brief Spherical area calculation
  21. \ingroup strategies
  22. \details Calculates area on the surface of a sphere using the trapezoidal rule
  23. \tparam RadiusTypeOrSphere \tparam_radius_or_sphere
  24. \tparam CalculationType \tparam_calculation
  25. \qbk{
  26. [heading See also]
  27. [link geometry.reference.algorithms.area.area_2_with_strategy area (with strategy)]
  28. }
  29. */
  30. template
  31. <
  32. typename RadiusTypeOrSphere = double,
  33. typename CalculationType = void
  34. >
  35. class spherical
  36. {
  37. typedef typename strategy_detail::get_radius
  38. <
  39. RadiusTypeOrSphere
  40. >::type radius_type;
  41. // Enables special handling of long segments
  42. static const bool LongSegment = false;
  43. public:
  44. template <typename Geometry>
  45. struct result_type
  46. : strategy::area::detail::result_type
  47. <
  48. Geometry,
  49. CalculationType
  50. >
  51. {};
  52. template <typename Geometry>
  53. class state
  54. {
  55. friend class spherical;
  56. typedef typename result_type<Geometry>::type return_type;
  57. public:
  58. inline state()
  59. : m_sum(0)
  60. , m_crosses_prime_meridian(0)
  61. {}
  62. private:
  63. template <typename RadiusType>
  64. inline return_type area(RadiusType const& r) const
  65. {
  66. return_type result;
  67. return_type radius = r;
  68. // Encircles pole
  69. if(m_crosses_prime_meridian % 2 == 1)
  70. {
  71. size_t times_crosses_prime_meridian
  72. = 1 + (m_crosses_prime_meridian / 2);
  73. result = return_type(2)
  74. * geometry::math::pi<return_type>()
  75. * times_crosses_prime_meridian
  76. - geometry::math::abs(m_sum);
  77. if(geometry::math::sign<return_type>(m_sum) == 1)
  78. {
  79. result = - result;
  80. }
  81. } else {
  82. result = m_sum;
  83. }
  84. result *= radius * radius;
  85. return result;
  86. }
  87. return_type m_sum;
  88. // Keep track if encircles some pole
  89. size_t m_crosses_prime_meridian;
  90. };
  91. public :
  92. // For backward compatibility reasons the radius is set to 1
  93. inline spherical()
  94. : m_radius(1.0)
  95. {}
  96. template <typename RadiusOrSphere>
  97. explicit inline spherical(RadiusOrSphere const& radius_or_sphere)
  98. : m_radius(strategy_detail::get_radius
  99. <
  100. RadiusOrSphere
  101. >::apply(radius_or_sphere))
  102. {}
  103. template <typename PointOfSegment, typename Geometry>
  104. inline void apply(PointOfSegment const& p1,
  105. PointOfSegment const& p2,
  106. state<Geometry>& st) const
  107. {
  108. if (! geometry::math::equals(get<0>(p1), get<0>(p2)))
  109. {
  110. typedef geometry::formula::area_formulas
  111. <
  112. typename result_type<Geometry>::type
  113. > area_formulas;
  114. st.m_sum += area_formulas::template spherical<LongSegment>(p1, p2);
  115. // Keep track whenever a segment crosses the prime meridian
  116. if (area_formulas::crosses_prime_meridian(p1, p2))
  117. {
  118. st.m_crosses_prime_meridian++;
  119. }
  120. }
  121. }
  122. template <typename Geometry>
  123. inline typename result_type<Geometry>::type
  124. result(state<Geometry> const& st) const
  125. {
  126. return st.area(m_radius);
  127. }
  128. srs::sphere<radius_type> model() const
  129. {
  130. return srs::sphere<radius_type>(m_radius);
  131. }
  132. private :
  133. radius_type m_radius;
  134. };
  135. #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
  136. namespace services
  137. {
  138. template <>
  139. struct default_strategy<spherical_equatorial_tag>
  140. {
  141. typedef strategy::area::spherical<> type;
  142. };
  143. // Note: spherical polar coordinate system requires "get_as_radian_equatorial"
  144. template <>
  145. struct default_strategy<spherical_polar_tag>
  146. {
  147. typedef strategy::area::spherical<> type;
  148. };
  149. } // namespace services
  150. #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
  151. }} // namespace strategy::area
  152. }} // namespace boost::geometry
  153. #endif // BOOST_GEOMETRY_STRATEGY_SPHERICAL_AREA_HPP