summaryrefslogtreecommitdiff
path: root/boost/geometry/strategies/geographic/area.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/geometry/strategies/geographic/area.hpp')
-rw-r--r--boost/geometry/strategies/geographic/area.hpp216
1 files changed, 216 insertions, 0 deletions
diff --git a/boost/geometry/strategies/geographic/area.hpp b/boost/geometry/strategies/geographic/area.hpp
new file mode 100644
index 0000000000..e1d3b09b5a
--- /dev/null
+++ b/boost/geometry/strategies/geographic/area.hpp
@@ -0,0 +1,216 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2016-2017 Oracle and/or its affiliates.
+// Contributed and/or modified by Vissarion Fisikopoulos, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AREA_HPP
+#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AREA_HPP
+
+
+#include <boost/geometry/core/srs.hpp>
+
+#include <boost/geometry/formulas/area_formulas.hpp>
+#include <boost/geometry/formulas/flattening.hpp>
+
+#include <boost/geometry/strategies/geographic/parameters.hpp>
+
+#include <boost/math/special_functions/atanh.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+namespace strategy { namespace area
+{
+
+/*!
+\brief Geographic area calculation
+\ingroup strategies
+\details Geographic area calculation by trapezoidal rule plus integral
+ approximation that gives the ellipsoidal correction
+\tparam PointOfSegment \tparam_segment_point
+\tparam FormulaPolicy Formula used to calculate azimuths
+\tparam SeriesOrder The order of approximation of the geodesic integral
+\tparam Spheroid The spheroid model
+\tparam CalculationType \tparam_calculation
+\author See
+- Danielsen JS, The area under the geodesic. Surv Rev 30(232): 61–66, 1989
+- Charles F.F Karney, Algorithms for geodesics, 2011 https://arxiv.org/pdf/1109.4448.pdf
+
+\qbk{
+[heading See also]
+[link geometry.reference.algorithms.area.area_2_with_strategy area (with strategy)]
+}
+*/
+template
+<
+ typename PointOfSegment,
+ typename FormulaPolicy = strategy::andoyer,
+ std::size_t SeriesOrder = strategy::default_order<FormulaPolicy>::value,
+ typename Spheroid = srs::spheroid<double>,
+ typename CalculationType = void
+>
+class geographic
+{
+ // Switch between two kinds of approximation(series in eps and n v.s.series in k ^ 2 and e'^2)
+ static const bool ExpandEpsN = true;
+ // LongSegment Enables special handling of long segments
+ static const bool LongSegment = false;
+
+ //Select default types in case they are not set
+
+ typedef typename boost::mpl::if_c
+ <
+ boost::is_void<CalculationType>::type::value,
+ typename select_most_precise
+ <
+ typename coordinate_type<PointOfSegment>::type,
+ double
+ >::type,
+ CalculationType
+ >::type CT;
+
+protected :
+ struct spheroid_constants
+ {
+ Spheroid m_spheroid;
+ CT const m_a2; // squared equatorial radius
+ CT const m_e2; // squared eccentricity
+ CT const m_ep2; // squared second eccentricity
+ CT const m_ep; // second eccentricity
+ CT const m_c2; // authalic radius
+
+ inline spheroid_constants(Spheroid const& spheroid)
+ : m_spheroid(spheroid)
+ , m_a2(math::sqr(get_radius<0>(spheroid)))
+ , m_e2(formula::flattening<CT>(spheroid)
+ * (CT(2.0) - CT(formula::flattening<CT>(spheroid))))
+ , m_ep2(m_e2 / (CT(1.0) - m_e2))
+ , m_ep(math::sqrt(m_ep2))
+ , m_c2((m_a2 / CT(2.0)) +
+ ((math::sqr(get_radius<2>(spheroid)) * boost::math::atanh(math::sqrt(m_e2)))
+ / (CT(2.0) * math::sqrt(m_e2))))
+ {}
+ };
+
+ struct area_sums
+ {
+ CT m_excess_sum;
+ CT m_correction_sum;
+
+ // Keep track if encircles some pole
+ std::size_t m_crosses_prime_meridian;
+
+ inline area_sums()
+ : m_excess_sum(0)
+ , m_correction_sum(0)
+ , m_crosses_prime_meridian(0)
+ {}
+ inline CT area(spheroid_constants spheroid_const) const
+ {
+ CT result;
+
+ CT sum = spheroid_const.m_c2 * m_excess_sum
+ + spheroid_const.m_e2 * spheroid_const.m_a2 * m_correction_sum;
+
+ // If encircles some pole
+ if (m_crosses_prime_meridian % 2 == 1)
+ {
+ std::size_t times_crosses_prime_meridian
+ = 1 + (m_crosses_prime_meridian / 2);
+
+ result = CT(2.0)
+ * geometry::math::pi<CT>()
+ * spheroid_const.m_c2
+ * CT(times_crosses_prime_meridian)
+ - geometry::math::abs(sum);
+
+ if (geometry::math::sign<CT>(sum) == 1)
+ {
+ result = - result;
+ }
+
+ }
+ else
+ {
+ result = sum;
+ }
+
+ return result;
+ }
+ };
+
+public :
+ typedef CT return_type;
+ typedef PointOfSegment segment_point_type;
+ typedef area_sums state_type;
+
+ explicit inline geographic(Spheroid const& spheroid = Spheroid())
+ : m_spheroid_constants(spheroid)
+ {}
+
+ inline void apply(PointOfSegment const& p1,
+ PointOfSegment const& p2,
+ area_sums& state) const
+ {
+
+ if (! geometry::math::equals(get<0>(p1), get<0>(p2)))
+ {
+
+ typedef geometry::formula::area_formulas
+ <
+ CT, SeriesOrder, ExpandEpsN
+ > area_formulas;
+
+ typename area_formulas::return_type_ellipsoidal result =
+ area_formulas::template ellipsoidal<FormulaPolicy::template inverse>
+ (p1, p2, m_spheroid_constants);
+
+ state.m_excess_sum += result.spherical_term;
+ state.m_correction_sum += result.ellipsoidal_term;
+
+ // Keep track whenever a segment crosses the prime meridian
+ geometry::formula::area_formulas<CT>
+ ::crosses_prime_meridian(p1, p2, state);
+ }
+ }
+
+ inline return_type result(area_sums const& state) const
+ {
+ return state.area(m_spheroid_constants);
+ }
+
+private:
+ spheroid_constants m_spheroid_constants;
+
+};
+
+#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
+
+namespace services
+{
+
+
+template <typename Point>
+struct default_strategy<geographic_tag, Point>
+{
+ typedef strategy::area::geographic<Point> type;
+};
+
+#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
+
+}
+
+}} // namespace strategy::area
+
+
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AREA_HPP