area.hpp 4.8 KB

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