• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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