comparison DEPENDENCIES/generic/include/boost/geometry/strategies/spherical/area_huiller.hpp @ 16:2665513ce2d3

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