1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
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
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)
13 #ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AREA_HPP
14 #define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AREA_HPP
17 #include <boost/geometry/srs/spheroid.hpp>
19 #include <boost/geometry/formulas/area_formulas.hpp>
20 #include <boost/geometry/formulas/authalic_radius_sqr.hpp>
21 #include <boost/geometry/formulas/eccentricity_sqr.hpp>
23 #include <boost/geometry/strategies/geographic/parameters.hpp>
26 namespace boost { namespace geometry
29 namespace strategy { namespace area
33 \brief Geographic area calculation
35 \details Geographic area calculation by trapezoidal rule plus integral
36 approximation that gives the ellipsoidal correction
37 \tparam FormulaPolicy Formula used to calculate azimuths
38 \tparam SeriesOrder The order of approximation of the geodesic integral
39 \tparam Spheroid The spheroid model
40 \tparam CalculationType \tparam_calculation
42 - Danielsen JS, The area under the geodesic. Surv Rev 30(232): 61–66, 1989
43 - Charles F.F Karney, Algorithms for geodesics, 2011 https://arxiv.org/pdf/1109.4448.pdf
47 \* [link geometry.reference.algorithms.area.area_2_with_strategy area (with strategy)]
48 \* [link geometry.reference.srs.srs_spheroid srs::spheroid]
53 typename FormulaPolicy = strategy::andoyer,
54 std::size_t SeriesOrder = strategy::default_order<FormulaPolicy>::value,
55 typename Spheroid = srs::spheroid<double>,
56 typename CalculationType = void
60 // Switch between two kinds of approximation(series in eps and n v.s.series in k ^ 2 and e'^2)
61 static const bool ExpandEpsN = true;
62 // LongSegment Enables special handling of long segments
63 static const bool LongSegment = false;
65 //Select default types in case they are not set
68 template <typename Geometry>
70 : strategy::area::detail::result_type
78 struct spheroid_constants
80 typedef typename boost::mpl::if_c
82 boost::is_void<CalculationType>::value,
83 typename geometry::radius_type<Spheroid>::type,
88 calc_t const m_a2; // squared equatorial radius
89 calc_t const m_e2; // squared eccentricity
90 calc_t const m_ep2; // squared second eccentricity
91 calc_t const m_ep; // second eccentricity
92 calc_t const m_c2; // squared authalic radius
94 inline spheroid_constants(Spheroid const& spheroid)
95 : m_spheroid(spheroid)
96 , m_a2(math::sqr(get_radius<0>(spheroid)))
97 , m_e2(formula::eccentricity_sqr<calc_t>(spheroid))
98 , m_ep2(m_e2 / (calc_t(1.0) - m_e2))
99 , m_ep(math::sqrt(m_ep2))
100 , m_c2(formula_dispatch::authalic_radius_sqr
102 calc_t, Spheroid, srs_spheroid_tag
103 >::apply(m_a2, m_e2))
108 template <typename Geometry>
111 friend class geographic;
113 typedef typename result_type<Geometry>::type return_type;
118 , m_correction_sum(0)
119 , m_crosses_prime_meridian(0)
123 inline return_type area(spheroid_constants const& spheroid_const) const
127 return_type sum = spheroid_const.m_c2 * m_excess_sum
128 + spheroid_const.m_e2 * spheroid_const.m_a2 * m_correction_sum;
130 // If encircles some pole
131 if (m_crosses_prime_meridian % 2 == 1)
133 std::size_t times_crosses_prime_meridian
134 = 1 + (m_crosses_prime_meridian / 2);
136 result = return_type(2.0)
137 * geometry::math::pi<return_type>()
138 * spheroid_const.m_c2
139 * return_type(times_crosses_prime_meridian)
140 - geometry::math::abs(sum);
142 if (geometry::math::sign<return_type>(sum) == 1)
156 return_type m_excess_sum;
157 return_type m_correction_sum;
159 // Keep track if encircles some pole
160 std::size_t m_crosses_prime_meridian;
164 explicit inline geographic(Spheroid const& spheroid = Spheroid())
165 : m_spheroid_constants(spheroid)
168 template <typename PointOfSegment, typename Geometry>
169 inline void apply(PointOfSegment const& p1,
170 PointOfSegment const& p2,
171 state<Geometry>& st) const
173 if (! geometry::math::equals(get<0>(p1), get<0>(p2)))
175 typedef geometry::formula::area_formulas
177 typename result_type<Geometry>::type,
178 SeriesOrder, ExpandEpsN
181 typename area_formulas::return_type_ellipsoidal result =
182 area_formulas::template ellipsoidal<FormulaPolicy::template inverse>
183 (p1, p2, m_spheroid_constants);
185 st.m_excess_sum += result.spherical_term;
186 st.m_correction_sum += result.ellipsoidal_term;
188 // Keep track whenever a segment crosses the prime meridian
189 if (area_formulas::crosses_prime_meridian(p1, p2))
191 st.m_crosses_prime_meridian++;
196 template <typename Geometry>
197 inline typename result_type<Geometry>::type
198 result(state<Geometry> const& st) const
200 return st.area(m_spheroid_constants);
204 spheroid_constants m_spheroid_constants;
208 #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
215 struct default_strategy<geographic_tag>
217 typedef strategy::area::geographic<> type;
220 #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
224 }} // namespace strategy::area
229 }} // namespace boost::geometry
231 #endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AREA_HPP