annotate DEPENDENCIES/generic/include/boost/geometry/strategies/spherical/area_huiller.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents c530137014c0
children
rev   line source
Chris@16 1 // Boost.Geometry (aka GGL, Generic Geometry Library)
Chris@16 2
Chris@16 3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
Chris@16 4
Chris@16 5 // Use, modification and distribution is subject to the Boost Software License,
Chris@16 6 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
Chris@16 7 // http://www.boost.org/LICENSE_1_0.txt)
Chris@16 8
Chris@16 9 #ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AREA_HUILLER_HPP
Chris@16 10 #define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AREA_HUILLER_HPP
Chris@16 11
Chris@16 12
Chris@16 13
Chris@16 14 #include <boost/geometry/strategies/spherical/distance_haversine.hpp>
Chris@16 15
Chris@16 16 #include <boost/geometry/core/radian_access.hpp>
Chris@16 17 #include <boost/geometry/util/math.hpp>
Chris@16 18
Chris@16 19
Chris@16 20 namespace boost { namespace geometry
Chris@16 21 {
Chris@16 22
Chris@16 23 namespace strategy { namespace area
Chris@16 24 {
Chris@16 25
Chris@16 26
Chris@16 27
Chris@16 28 /*!
Chris@16 29 \brief Area calculation by spherical excess / Huiller's formula
Chris@16 30 \ingroup strategies
Chris@16 31 \tparam PointOfSegment point type of segments of rings/polygons
Chris@16 32 \tparam CalculationType \tparam_calculation
Chris@16 33 \author Barend Gehrels. Adapted from:
Chris@16 34 - http://www.soe.ucsc.edu/~pang/160/f98/Gems/GemsIV/sph_poly.c
Chris@16 35 - http://williams.best.vwh.net/avform.htm
Chris@16 36 \note The version in Gems didn't account for polygons crossing the 180 meridian.
Chris@16 37 \note This version works for convex and non-convex polygons, for 180 meridian
Chris@16 38 crossing polygons and for polygons with holes. However, some cases (especially
Chris@16 39 180 meridian cases) must still be checked.
Chris@16 40 \note The version which sums angles, which is often seen, doesn't handle non-convex
Chris@16 41 polygons correctly.
Chris@16 42 \note The version which sums longitudes, see
Chris@16 43 http://trs-new.jpl.nasa.gov/dspace/bitstream/2014/40409/1/07-03.pdf, is simple
Chris@16 44 and works well in most cases but not in 180 meridian crossing cases. This probably
Chris@16 45 could be solved.
Chris@16 46
Chris@16 47 \note This version is made for spherical equatorial coordinate systems
Chris@16 48
Chris@16 49 \qbk{
Chris@16 50
Chris@16 51 [heading Example]
Chris@16 52 [area_with_strategy]
Chris@16 53 [area_with_strategy_output]
Chris@16 54
Chris@16 55
Chris@16 56 [heading See also]
Chris@16 57 [link geometry.reference.algorithms.area.area_2_with_strategy area (with strategy)]
Chris@16 58 }
Chris@16 59
Chris@16 60 */
Chris@16 61 template
Chris@16 62 <
Chris@16 63 typename PointOfSegment,
Chris@16 64 typename CalculationType = void
Chris@16 65 >
Chris@16 66 class huiller
Chris@16 67 {
Chris@16 68 typedef typename boost::mpl::if_c
Chris@16 69 <
Chris@16 70 boost::is_void<CalculationType>::type::value,
Chris@16 71 typename select_most_precise
Chris@16 72 <
Chris@16 73 typename coordinate_type<PointOfSegment>::type,
Chris@16 74 double
Chris@16 75 >::type,
Chris@16 76 CalculationType
Chris@16 77 >::type calculation_type;
Chris@16 78
Chris@16 79 protected :
Chris@16 80 struct excess_sum
Chris@16 81 {
Chris@16 82 calculation_type sum;
Chris@16 83
Chris@16 84 // Distances are calculated on unit sphere here
Chris@16 85 strategy::distance::haversine<calculation_type> distance_over_unit_sphere;
Chris@16 86
Chris@16 87
Chris@16 88 inline excess_sum()
Chris@16 89 : sum(0)
Chris@16 90 , distance_over_unit_sphere(1)
Chris@16 91 {}
Chris@16 92 inline calculation_type area(calculation_type radius) const
Chris@16 93 {
Chris@16 94 return - sum * radius * radius;
Chris@16 95 }
Chris@16 96 };
Chris@16 97
Chris@16 98 public :
Chris@16 99 typedef calculation_type return_type;
Chris@16 100 typedef PointOfSegment segment_point_type;
Chris@16 101 typedef excess_sum state_type;
Chris@16 102
Chris@16 103 inline huiller(calculation_type radius = 1.0)
Chris@16 104 : m_radius(radius)
Chris@16 105 {}
Chris@16 106
Chris@16 107 inline void apply(PointOfSegment const& p1,
Chris@16 108 PointOfSegment const& p2,
Chris@16 109 excess_sum& state) const
Chris@16 110 {
Chris@16 111 if (! geometry::math::equals(get<0>(p1), get<0>(p2)))
Chris@16 112 {
Chris@16 113 calculation_type const half = 0.5;
Chris@16 114 calculation_type const two = 2.0;
Chris@16 115 calculation_type const four = 4.0;
Chris@16 116 calculation_type const two_pi = two * geometry::math::pi<calculation_type>();
Chris@16 117 calculation_type const half_pi = half * geometry::math::pi<calculation_type>();
Chris@16 118
Chris@16 119 // Distance p1 p2
Chris@16 120 calculation_type a = state.distance_over_unit_sphere.apply(p1, p2);
Chris@16 121
Chris@16 122 // Sides on unit sphere to south pole
Chris@16 123 calculation_type b = half_pi - geometry::get_as_radian<1>(p2);
Chris@16 124 calculation_type c = half_pi - geometry::get_as_radian<1>(p1);
Chris@16 125
Chris@16 126 // Semi parameter
Chris@16 127 calculation_type s = half * (a + b + c);
Chris@16 128
Chris@16 129 // E: spherical excess, using l'Huiller's formula
Chris@16 130 // [tg(e / 4)]2 = tg[s / 2] tg[(s-a) / 2] tg[(s-b) / 2] tg[(s-c) / 2]
Chris@101 131 calculation_type E = four
Chris@101 132 * atan(geometry::math::sqrt(geometry::math::abs(tan(s / two)
Chris@16 133 * tan((s - a) / two)
Chris@16 134 * tan((s - b) / two)
Chris@16 135 * tan((s - c) / two))));
Chris@16 136
Chris@16 137 E = geometry::math::abs(E);
Chris@16 138
Chris@16 139 // In right direction: positive, add area. In left direction: negative, subtract area.
Chris@16 140 // Longitude comparisons are not so obvious. If one is negative, other is positive,
Chris@16 141 // we have to take the dateline into account.
Chris@16 142 // TODO: check this / enhance this, should be more robust. See also the "grow" for ll
Chris@16 143 // TODO: use minmax or "smaller"/"compare" strategy for this
Chris@16 144 calculation_type lon1 = geometry::get_as_radian<0>(p1) < 0
Chris@16 145 ? geometry::get_as_radian<0>(p1) + two_pi
Chris@16 146 : geometry::get_as_radian<0>(p1);
Chris@16 147
Chris@16 148 calculation_type lon2 = geometry::get_as_radian<0>(p2) < 0
Chris@16 149 ? geometry::get_as_radian<0>(p2) + two_pi
Chris@16 150 : geometry::get_as_radian<0>(p2);
Chris@16 151
Chris@16 152 if (lon2 < lon1)
Chris@16 153 {
Chris@16 154 E = -E;
Chris@16 155 }
Chris@16 156
Chris@16 157 state.sum += E;
Chris@16 158 }
Chris@16 159 }
Chris@16 160
Chris@16 161 inline return_type result(excess_sum const& state) const
Chris@16 162 {
Chris@16 163 return state.area(m_radius);
Chris@16 164 }
Chris@16 165
Chris@16 166 private :
Chris@16 167 /// Radius of the sphere
Chris@16 168 calculation_type m_radius;
Chris@16 169 };
Chris@16 170
Chris@16 171 #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
Chris@16 172
Chris@16 173 namespace services
Chris@16 174 {
Chris@16 175
Chris@16 176
Chris@16 177 template <typename Point>
Chris@16 178 struct default_strategy<spherical_equatorial_tag, Point>
Chris@16 179 {
Chris@16 180 typedef strategy::area::huiller<Point> type;
Chris@16 181 };
Chris@16 182
Chris@16 183 // Note: spherical polar coordinate system requires "get_as_radian_equatorial"
Chris@16 184 /***template <typename Point>
Chris@16 185 struct default_strategy<spherical_polar_tag, Point>
Chris@16 186 {
Chris@16 187 typedef strategy::area::huiller<Point> type;
Chris@16 188 };***/
Chris@16 189
Chris@16 190 } // namespace services
Chris@16 191
Chris@16 192 #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
Chris@16 193
Chris@16 194
Chris@16 195 }} // namespace strategy::area
Chris@16 196
Chris@16 197
Chris@16 198
Chris@16 199
Chris@16 200 }} // namespace boost::geometry
Chris@16 201
Chris@16 202 #endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AREA_HUILLER_HPP