1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2016-2017 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
7 // Use, modification and distribution is subject to the Boost Software License,
8 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
9 // http://www.boost.org/LICENSE_1_0.txt)
11 #ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AREA_HPP
12 #define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AREA_HPP
15 #include <boost/geometry/core/srs.hpp>
17 #include <boost/geometry/formulas/area_formulas.hpp>
18 #include <boost/geometry/formulas/authalic_radius_sqr.hpp>
19 #include <boost/geometry/formulas/eccentricity_sqr.hpp>
21 #include <boost/geometry/strategies/geographic/parameters.hpp>
24 namespace boost { namespace geometry
27 namespace strategy { namespace area
31 \brief Geographic area calculation
33 \details Geographic area calculation by trapezoidal rule plus integral
34 approximation that gives the ellipsoidal correction
35 \tparam PointOfSegment \tparam_segment_point
36 \tparam FormulaPolicy Formula used to calculate azimuths
37 \tparam SeriesOrder The order of approximation of the geodesic integral
38 \tparam Spheroid The spheroid model
39 \tparam CalculationType \tparam_calculation
41 - Danielsen JS, The area under the geodesic. Surv Rev 30(232): 61–66, 1989
42 - Charles F.F Karney, Algorithms for geodesics, 2011 https://arxiv.org/pdf/1109.4448.pdf
46 [link geometry.reference.algorithms.area.area_2_with_strategy area (with strategy)]
51 typename PointOfSegment,
52 typename FormulaPolicy = strategy::andoyer,
53 std::size_t SeriesOrder = strategy::default_order<FormulaPolicy>::value,
54 typename Spheroid = srs::spheroid<double>,
55 typename CalculationType = void
59 // Switch between two kinds of approximation(series in eps and n v.s.series in k ^ 2 and e'^2)
60 static const bool ExpandEpsN = true;
61 // LongSegment Enables special handling of long segments
62 static const bool LongSegment = false;
64 //Select default types in case they are not set
66 typedef typename boost::mpl::if_c
68 boost::is_void<CalculationType>::type::value,
69 typename select_most_precise
71 typename coordinate_type<PointOfSegment>::type,
78 struct spheroid_constants
81 CT const m_a2; // squared equatorial radius
82 CT const m_e2; // squared eccentricity
83 CT const m_ep2; // squared second eccentricity
84 CT const m_ep; // second eccentricity
85 CT const m_c2; // squared authalic radius
87 inline spheroid_constants(Spheroid const& spheroid)
88 : m_spheroid(spheroid)
89 , m_a2(math::sqr(get_radius<0>(spheroid)))
90 , m_e2(formula::eccentricity_sqr<CT>(spheroid))
91 , m_ep2(m_e2 / (CT(1.0) - m_e2))
92 , m_ep(math::sqrt(m_ep2))
93 , m_c2(formula_dispatch::authalic_radius_sqr
95 CT, Spheroid, srs_spheroid_tag
105 // Keep track if encircles some pole
106 std::size_t m_crosses_prime_meridian;
110 , m_correction_sum(0)
111 , m_crosses_prime_meridian(0)
113 inline CT area(spheroid_constants spheroid_const) const
117 CT sum = spheroid_const.m_c2 * m_excess_sum
118 + spheroid_const.m_e2 * spheroid_const.m_a2 * m_correction_sum;
120 // If encircles some pole
121 if (m_crosses_prime_meridian % 2 == 1)
123 std::size_t times_crosses_prime_meridian
124 = 1 + (m_crosses_prime_meridian / 2);
127 * geometry::math::pi<CT>()
128 * spheroid_const.m_c2
129 * CT(times_crosses_prime_meridian)
130 - geometry::math::abs(sum);
132 if (geometry::math::sign<CT>(sum) == 1)
148 typedef CT return_type;
149 typedef PointOfSegment segment_point_type;
150 typedef area_sums state_type;
152 explicit inline geographic(Spheroid const& spheroid = Spheroid())
153 : m_spheroid_constants(spheroid)
156 inline void apply(PointOfSegment const& p1,
157 PointOfSegment const& p2,
158 area_sums& state) const
161 if (! geometry::math::equals(get<0>(p1), get<0>(p2)))
164 typedef geometry::formula::area_formulas
166 CT, SeriesOrder, ExpandEpsN
169 typename area_formulas::return_type_ellipsoidal result =
170 area_formulas::template ellipsoidal<FormulaPolicy::template inverse>
171 (p1, p2, m_spheroid_constants);
173 state.m_excess_sum += result.spherical_term;
174 state.m_correction_sum += result.ellipsoidal_term;
176 // Keep track whenever a segment crosses the prime meridian
177 if (area_formulas::crosses_prime_meridian(p1, p2))
179 state.m_crosses_prime_meridian++;
184 inline return_type result(area_sums const& state) const
186 return state.area(m_spheroid_constants);
190 spheroid_constants m_spheroid_constants;
194 #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
200 template <typename Point>
201 struct default_strategy<geographic_tag, Point>
203 typedef strategy::area::geographic<Point> type;
206 #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
210 }} // namespace strategy::area
215 }} // namespace boost::geometry
217 #endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AREA_HPP