1 // Boost.Geometry (aka GGL, Generic Geometry Library) 2 3 // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. 4 5 // Copyright (c) 2016-2018 Oracle and/or its affiliates. 6 // Contributed and/or modified by Vissarion Fisikopoulos, on behalf of Oracle 7 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle 8 9 // Use, modification and distribution is subject to the Boost Software License, 10 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 11 // http://www.boost.org/LICENSE_1_0.txt) 12 13 #ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AREA_HPP 14 #define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AREA_HPP 15 16 17 #include <boost/geometry/formulas/area_formulas.hpp> 18 #include <boost/geometry/srs/sphere.hpp> 19 #include <boost/geometry/strategies/area.hpp> 20 #include <boost/geometry/strategies/spherical/get_radius.hpp> 21 22 23 namespace boost { namespace geometry 24 { 25 26 namespace strategy { namespace area 27 { 28 29 30 /*! 31 \brief Spherical area calculation 32 \ingroup strategies 33 \details Calculates area on the surface of a sphere using the trapezoidal rule 34 \tparam RadiusTypeOrSphere \tparam_radius_or_sphere 35 \tparam CalculationType \tparam_calculation 36 37 \qbk{ 38 [heading See also] 39 [link geometry.reference.algorithms.area.area_2_with_strategy area (with strategy)] 40 } 41 */ 42 template 43 < 44 typename RadiusTypeOrSphere = double, 45 typename CalculationType = void 46 > 47 class spherical 48 { 49 // Enables special handling of long segments 50 static const bool LongSegment = false; 51 52 public: 53 template <typename Geometry> 54 struct result_type 55 : strategy::area::detail::result_type 56 < 57 Geometry, 58 CalculationType 59 > 60 {}; 61 62 template <typename Geometry> 63 class state 64 { 65 friend class spherical; 66 67 typedef typename result_type<Geometry>::type return_type; 68 69 public: state()70 inline state() 71 : m_sum(0) 72 , m_crosses_prime_meridian(0) 73 {} 74 75 private: 76 template <typename RadiusType> area(RadiusType const & r) const77 inline return_type area(RadiusType const& r) const 78 { 79 return_type result; 80 return_type radius = r; 81 82 // Encircles pole 83 if(m_crosses_prime_meridian % 2 == 1) 84 { 85 size_t times_crosses_prime_meridian 86 = 1 + (m_crosses_prime_meridian / 2); 87 88 result = return_type(2) 89 * geometry::math::pi<return_type>() 90 * times_crosses_prime_meridian 91 - geometry::math::abs(m_sum); 92 93 if(geometry::math::sign<return_type>(m_sum) == 1) 94 { 95 result = - result; 96 } 97 98 } else { 99 result = m_sum; 100 } 101 102 result *= radius * radius; 103 104 return result; 105 } 106 107 return_type m_sum; 108 109 // Keep track if encircles some pole 110 size_t m_crosses_prime_meridian; 111 }; 112 113 public : 114 115 // For backward compatibility reasons the radius is set to 1 spherical()116 inline spherical() 117 : m_radius(1.0) 118 {} 119 120 template <typename RadiusOrSphere> spherical(RadiusOrSphere const & radius_or_sphere)121 explicit inline spherical(RadiusOrSphere const& radius_or_sphere) 122 : m_radius(strategy_detail::get_radius 123 < 124 RadiusOrSphere 125 >::apply(radius_or_sphere)) 126 {} 127 128 template <typename PointOfSegment, typename Geometry> apply(PointOfSegment const & p1,PointOfSegment const & p2,state<Geometry> & st) const129 inline void apply(PointOfSegment const& p1, 130 PointOfSegment const& p2, 131 state<Geometry>& st) const 132 { 133 if (! geometry::math::equals(get<0>(p1), get<0>(p2))) 134 { 135 typedef geometry::formula::area_formulas 136 < 137 typename result_type<Geometry>::type 138 > area_formulas; 139 140 st.m_sum += area_formulas::template spherical<LongSegment>(p1, p2); 141 142 // Keep track whenever a segment crosses the prime meridian 143 if (area_formulas::crosses_prime_meridian(p1, p2)) 144 { 145 st.m_crosses_prime_meridian++; 146 } 147 } 148 } 149 150 template <typename Geometry> 151 inline typename result_type<Geometry>::type result(state<Geometry> const & st) const152 result(state<Geometry> const& st) const 153 { 154 return st.area(m_radius); 155 } 156 157 private : 158 typename strategy_detail::get_radius 159 < 160 RadiusTypeOrSphere 161 >::type m_radius; 162 }; 163 164 #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS 165 166 namespace services 167 { 168 169 170 template <> 171 struct default_strategy<spherical_equatorial_tag> 172 { 173 typedef strategy::area::spherical<> type; 174 }; 175 176 // Note: spherical polar coordinate system requires "get_as_radian_equatorial" 177 template <> 178 struct default_strategy<spherical_polar_tag> 179 { 180 typedef strategy::area::spherical<> type; 181 }; 182 183 } // namespace services 184 185 #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS 186 187 188 }} // namespace strategy::area 189 190 191 192 193 }} // namespace boost::geometry 194 195 #endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AREA_HPP 196