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 // Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
|
Chris@16
|
5 // Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
|
Chris@16
|
6
|
Chris@16
|
7 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
|
Chris@16
|
8 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
|
Chris@16
|
9
|
Chris@16
|
10 // Use, modification and distribution is subject to the Boost Software License,
|
Chris@16
|
11 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
12 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
13
|
Chris@16
|
14 #ifndef BOOST_GEOMETRY_ALGORITHMS_AREA_HPP
|
Chris@16
|
15 #define BOOST_GEOMETRY_ALGORITHMS_AREA_HPP
|
Chris@16
|
16
|
Chris@16
|
17 #include <boost/concept_check.hpp>
|
Chris@16
|
18 #include <boost/mpl/if.hpp>
|
Chris@16
|
19 #include <boost/range/functions.hpp>
|
Chris@16
|
20 #include <boost/range/metafunctions.hpp>
|
Chris@101
|
21
|
Chris@101
|
22 #include <boost/variant/apply_visitor.hpp>
|
Chris@16
|
23 #include <boost/variant/static_visitor.hpp>
|
Chris@16
|
24 #include <boost/variant/variant_fwd.hpp>
|
Chris@16
|
25
|
Chris@16
|
26 #include <boost/geometry/core/closure.hpp>
|
Chris@16
|
27 #include <boost/geometry/core/exterior_ring.hpp>
|
Chris@16
|
28 #include <boost/geometry/core/interior_rings.hpp>
|
Chris@16
|
29 #include <boost/geometry/core/point_order.hpp>
|
Chris@101
|
30 #include <boost/geometry/core/point_type.hpp>
|
Chris@16
|
31 #include <boost/geometry/core/ring_type.hpp>
|
Chris@101
|
32 #include <boost/geometry/core/tags.hpp>
|
Chris@16
|
33
|
Chris@16
|
34 #include <boost/geometry/geometries/concepts/check.hpp>
|
Chris@16
|
35
|
Chris@16
|
36 #include <boost/geometry/algorithms/detail/calculate_null.hpp>
|
Chris@16
|
37 #include <boost/geometry/algorithms/detail/calculate_sum.hpp>
|
Chris@16
|
38 // #include <boost/geometry/algorithms/detail/throw_on_empty_input.hpp>
|
Chris@101
|
39 #include <boost/geometry/algorithms/detail/multi_sum.hpp>
|
Chris@16
|
40
|
Chris@16
|
41 #include <boost/geometry/strategies/area.hpp>
|
Chris@16
|
42 #include <boost/geometry/strategies/default_area_result.hpp>
|
Chris@16
|
43
|
Chris@16
|
44 #include <boost/geometry/strategies/concepts/area_concept.hpp>
|
Chris@16
|
45
|
Chris@16
|
46 #include <boost/geometry/util/math.hpp>
|
Chris@16
|
47 #include <boost/geometry/util/order_as_direction.hpp>
|
Chris@16
|
48 #include <boost/geometry/views/closeable_view.hpp>
|
Chris@16
|
49 #include <boost/geometry/views/reversible_view.hpp>
|
Chris@16
|
50
|
Chris@16
|
51
|
Chris@16
|
52 namespace boost { namespace geometry
|
Chris@16
|
53 {
|
Chris@16
|
54
|
Chris@16
|
55 #ifndef DOXYGEN_NO_DETAIL
|
Chris@16
|
56 namespace detail { namespace area
|
Chris@16
|
57 {
|
Chris@16
|
58
|
Chris@16
|
59 struct box_area
|
Chris@16
|
60 {
|
Chris@16
|
61 template <typename Box, typename Strategy>
|
Chris@16
|
62 static inline typename coordinate_type<Box>::type
|
Chris@16
|
63 apply(Box const& box, Strategy const&)
|
Chris@16
|
64 {
|
Chris@16
|
65 // Currently only works for 2D Cartesian boxes
|
Chris@16
|
66 assert_dimension<Box, 2>();
|
Chris@16
|
67
|
Chris@16
|
68 return (get<max_corner, 0>(box) - get<min_corner, 0>(box))
|
Chris@16
|
69 * (get<max_corner, 1>(box) - get<min_corner, 1>(box));
|
Chris@16
|
70 }
|
Chris@16
|
71 };
|
Chris@16
|
72
|
Chris@16
|
73
|
Chris@16
|
74 template
|
Chris@16
|
75 <
|
Chris@16
|
76 iterate_direction Direction,
|
Chris@16
|
77 closure_selector Closure
|
Chris@16
|
78 >
|
Chris@16
|
79 struct ring_area
|
Chris@16
|
80 {
|
Chris@16
|
81 template <typename Ring, typename Strategy>
|
Chris@16
|
82 static inline typename Strategy::return_type
|
Chris@16
|
83 apply(Ring const& ring, Strategy const& strategy)
|
Chris@16
|
84 {
|
Chris@16
|
85 BOOST_CONCEPT_ASSERT( (geometry::concept::AreaStrategy<Strategy>) );
|
Chris@16
|
86 assert_dimension<Ring, 2>();
|
Chris@16
|
87
|
Chris@16
|
88 // Ignore warning (because using static method sometimes) on strategy
|
Chris@16
|
89 boost::ignore_unused_variable_warning(strategy);
|
Chris@16
|
90
|
Chris@16
|
91 // An open ring has at least three points,
|
Chris@16
|
92 // A closed ring has at least four points,
|
Chris@16
|
93 // if not, there is no (zero) area
|
Chris@101
|
94 if (boost::size(ring)
|
Chris@16
|
95 < core_detail::closure::minimum_ring_size<Closure>::value)
|
Chris@16
|
96 {
|
Chris@16
|
97 return typename Strategy::return_type();
|
Chris@16
|
98 }
|
Chris@16
|
99
|
Chris@16
|
100 typedef typename reversible_view<Ring const, Direction>::type rview_type;
|
Chris@16
|
101 typedef typename closeable_view
|
Chris@16
|
102 <
|
Chris@16
|
103 rview_type const, Closure
|
Chris@16
|
104 >::type view_type;
|
Chris@16
|
105 typedef typename boost::range_iterator<view_type const>::type iterator_type;
|
Chris@16
|
106
|
Chris@16
|
107 rview_type rview(ring);
|
Chris@16
|
108 view_type view(rview);
|
Chris@16
|
109 typename Strategy::state_type state;
|
Chris@16
|
110 iterator_type it = boost::begin(view);
|
Chris@16
|
111 iterator_type end = boost::end(view);
|
Chris@16
|
112
|
Chris@16
|
113 for (iterator_type previous = it++;
|
Chris@16
|
114 it != end;
|
Chris@16
|
115 ++previous, ++it)
|
Chris@16
|
116 {
|
Chris@16
|
117 strategy.apply(*previous, *it, state);
|
Chris@16
|
118 }
|
Chris@16
|
119
|
Chris@16
|
120 return strategy.result(state);
|
Chris@16
|
121 }
|
Chris@16
|
122 };
|
Chris@16
|
123
|
Chris@16
|
124
|
Chris@16
|
125 }} // namespace detail::area
|
Chris@16
|
126
|
Chris@16
|
127
|
Chris@16
|
128 #endif // DOXYGEN_NO_DETAIL
|
Chris@16
|
129
|
Chris@16
|
130
|
Chris@16
|
131 #ifndef DOXYGEN_NO_DISPATCH
|
Chris@16
|
132 namespace dispatch
|
Chris@16
|
133 {
|
Chris@16
|
134
|
Chris@16
|
135 template
|
Chris@16
|
136 <
|
Chris@16
|
137 typename Geometry,
|
Chris@16
|
138 typename Tag = typename tag<Geometry>::type
|
Chris@16
|
139 >
|
Chris@16
|
140 struct area : detail::calculate_null
|
Chris@16
|
141 {
|
Chris@16
|
142 template <typename Strategy>
|
Chris@16
|
143 static inline typename Strategy::return_type apply(Geometry const& geometry, Strategy const& strategy)
|
Chris@16
|
144 {
|
Chris@16
|
145 return calculate_null::apply<typename Strategy::return_type>(geometry, strategy);
|
Chris@16
|
146 }
|
Chris@16
|
147 };
|
Chris@16
|
148
|
Chris@16
|
149
|
Chris@16
|
150 template <typename Geometry>
|
Chris@16
|
151 struct area<Geometry, box_tag> : detail::area::box_area
|
Chris@16
|
152 {};
|
Chris@16
|
153
|
Chris@16
|
154
|
Chris@16
|
155 template <typename Ring>
|
Chris@16
|
156 struct area<Ring, ring_tag>
|
Chris@16
|
157 : detail::area::ring_area
|
Chris@16
|
158 <
|
Chris@16
|
159 order_as_direction<geometry::point_order<Ring>::value>::value,
|
Chris@16
|
160 geometry::closure<Ring>::value
|
Chris@16
|
161 >
|
Chris@16
|
162 {};
|
Chris@16
|
163
|
Chris@16
|
164
|
Chris@16
|
165 template <typename Polygon>
|
Chris@16
|
166 struct area<Polygon, polygon_tag> : detail::calculate_polygon_sum
|
Chris@16
|
167 {
|
Chris@16
|
168 template <typename Strategy>
|
Chris@16
|
169 static inline typename Strategy::return_type apply(Polygon const& polygon, Strategy const& strategy)
|
Chris@16
|
170 {
|
Chris@16
|
171 return calculate_polygon_sum::apply<
|
Chris@16
|
172 typename Strategy::return_type,
|
Chris@16
|
173 detail::area::ring_area
|
Chris@16
|
174 <
|
Chris@16
|
175 order_as_direction<geometry::point_order<Polygon>::value>::value,
|
Chris@16
|
176 geometry::closure<Polygon>::value
|
Chris@16
|
177 >
|
Chris@16
|
178 >(polygon, strategy);
|
Chris@16
|
179 }
|
Chris@16
|
180 };
|
Chris@16
|
181
|
Chris@16
|
182
|
Chris@101
|
183 template <typename MultiGeometry>
|
Chris@101
|
184 struct area<MultiGeometry, multi_polygon_tag> : detail::multi_sum
|
Chris@101
|
185 {
|
Chris@101
|
186 template <typename Strategy>
|
Chris@101
|
187 static inline typename Strategy::return_type
|
Chris@101
|
188 apply(MultiGeometry const& multi, Strategy const& strategy)
|
Chris@101
|
189 {
|
Chris@101
|
190 return multi_sum::apply
|
Chris@101
|
191 <
|
Chris@101
|
192 typename Strategy::return_type,
|
Chris@101
|
193 area<typename boost::range_value<MultiGeometry>::type>
|
Chris@101
|
194 >(multi, strategy);
|
Chris@101
|
195 }
|
Chris@101
|
196 };
|
Chris@101
|
197
|
Chris@101
|
198
|
Chris@101
|
199 } // namespace dispatch
|
Chris@101
|
200 #endif // DOXYGEN_NO_DISPATCH
|
Chris@101
|
201
|
Chris@101
|
202
|
Chris@101
|
203 namespace resolve_variant {
|
Chris@101
|
204
|
Chris@16
|
205 template <typename Geometry>
|
Chris@101
|
206 struct area
|
Chris@16
|
207 {
|
Chris@16
|
208 template <typename Strategy>
|
Chris@16
|
209 static inline typename Strategy::return_type apply(Geometry const& geometry,
|
Chris@16
|
210 Strategy const& strategy)
|
Chris@16
|
211 {
|
Chris@101
|
212 return dispatch::area<Geometry>::apply(geometry, strategy);
|
Chris@16
|
213 }
|
Chris@16
|
214 };
|
Chris@16
|
215
|
Chris@16
|
216 template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
|
Chris@101
|
217 struct area<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
|
Chris@16
|
218 {
|
Chris@16
|
219 template <typename Strategy>
|
Chris@16
|
220 struct visitor: boost::static_visitor<typename Strategy::return_type>
|
Chris@16
|
221 {
|
Chris@16
|
222 Strategy const& m_strategy;
|
Chris@16
|
223
|
Chris@16
|
224 visitor(Strategy const& strategy): m_strategy(strategy) {}
|
Chris@16
|
225
|
Chris@16
|
226 template <typename Geometry>
|
Chris@16
|
227 typename Strategy::return_type operator()(Geometry const& geometry) const
|
Chris@16
|
228 {
|
Chris@101
|
229 return area<Geometry>::apply(geometry, m_strategy);
|
Chris@16
|
230 }
|
Chris@16
|
231 };
|
Chris@16
|
232
|
Chris@16
|
233 template <typename Strategy>
|
Chris@16
|
234 static inline typename Strategy::return_type
|
Chris@16
|
235 apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
|
Chris@16
|
236 Strategy const& strategy)
|
Chris@16
|
237 {
|
Chris@16
|
238 return boost::apply_visitor(visitor<Strategy>(strategy), geometry);
|
Chris@16
|
239 }
|
Chris@16
|
240 };
|
Chris@16
|
241
|
Chris@101
|
242 } // namespace resolve_variant
|
Chris@16
|
243
|
Chris@16
|
244
|
Chris@16
|
245 /*!
|
Chris@16
|
246 \brief \brief_calc{area}
|
Chris@16
|
247 \ingroup area
|
Chris@16
|
248 \details \details_calc{area}. \details_default_strategy
|
Chris@16
|
249
|
Chris@16
|
250 The area algorithm calculates the surface area of all geometries having a surface, namely
|
Chris@16
|
251 box, polygon, ring, multipolygon. The units are the square of the units used for the points
|
Chris@16
|
252 defining the surface. If subject geometry is defined in meters, then area is calculated
|
Chris@16
|
253 in square meters.
|
Chris@16
|
254
|
Chris@16
|
255 The area calculation can be done in all three common coordinate systems, Cartesian, Spherical
|
Chris@16
|
256 and Geographic as well.
|
Chris@16
|
257
|
Chris@16
|
258 \tparam Geometry \tparam_geometry
|
Chris@16
|
259 \param geometry \param_geometry
|
Chris@16
|
260 \return \return_calc{area}
|
Chris@16
|
261
|
Chris@16
|
262 \qbk{[include reference/algorithms/area.qbk]}
|
Chris@16
|
263 \qbk{[heading Examples]}
|
Chris@16
|
264 \qbk{[area] [area_output]}
|
Chris@16
|
265 */
|
Chris@16
|
266 template <typename Geometry>
|
Chris@16
|
267 inline typename default_area_result<Geometry>::type area(Geometry const& geometry)
|
Chris@16
|
268 {
|
Chris@16
|
269 concept::check<Geometry const>();
|
Chris@16
|
270
|
Chris@101
|
271 // TODO put this into a resolve_strategy stage
|
Chris@101
|
272 // (and take the return type from resolve_variant)
|
Chris@16
|
273 typedef typename point_type<Geometry>::type point_type;
|
Chris@16
|
274 typedef typename strategy::area::services::default_strategy
|
Chris@16
|
275 <
|
Chris@16
|
276 typename cs_tag<point_type>::type,
|
Chris@16
|
277 point_type
|
Chris@16
|
278 >::type strategy_type;
|
Chris@16
|
279
|
Chris@16
|
280 // detail::throw_on_empty_input(geometry);
|
Chris@101
|
281
|
Chris@101
|
282 return resolve_variant::area<Geometry>::apply(geometry, strategy_type());
|
Chris@16
|
283 }
|
Chris@16
|
284
|
Chris@16
|
285 /*!
|
Chris@16
|
286 \brief \brief_calc{area} \brief_strategy
|
Chris@16
|
287 \ingroup area
|
Chris@16
|
288 \details \details_calc{area} \brief_strategy. \details_strategy_reasons
|
Chris@16
|
289 \tparam Geometry \tparam_geometry
|
Chris@16
|
290 \tparam Strategy \tparam_strategy{Area}
|
Chris@16
|
291 \param geometry \param_geometry
|
Chris@16
|
292 \param strategy \param_strategy{area}
|
Chris@16
|
293 \return \return_calc{area}
|
Chris@16
|
294
|
Chris@16
|
295 \qbk{distinguish,with strategy}
|
Chris@16
|
296
|
Chris@16
|
297 \qbk{
|
Chris@16
|
298 [include reference/algorithms/area.qbk]
|
Chris@16
|
299
|
Chris@16
|
300 [heading Example]
|
Chris@16
|
301 [area_with_strategy]
|
Chris@16
|
302 [area_with_strategy_output]
|
Chris@16
|
303
|
Chris@16
|
304 [heading Available Strategies]
|
Chris@16
|
305 \* [link geometry.reference.strategies.strategy_area_surveyor Surveyor (cartesian)]
|
Chris@16
|
306 \* [link geometry.reference.strategies.strategy_area_huiller Huiller (spherical)]
|
Chris@16
|
307 }
|
Chris@16
|
308 */
|
Chris@16
|
309 template <typename Geometry, typename Strategy>
|
Chris@16
|
310 inline typename Strategy::return_type area(
|
Chris@16
|
311 Geometry const& geometry, Strategy const& strategy)
|
Chris@16
|
312 {
|
Chris@16
|
313 concept::check<Geometry const>();
|
Chris@16
|
314
|
Chris@16
|
315 // detail::throw_on_empty_input(geometry);
|
Chris@101
|
316
|
Chris@101
|
317 return resolve_variant::area<Geometry>::apply(geometry, strategy);
|
Chris@16
|
318 }
|
Chris@16
|
319
|
Chris@16
|
320
|
Chris@16
|
321 }} // namespace boost::geometry
|
Chris@16
|
322
|
Chris@16
|
323
|
Chris@16
|
324 #endif // BOOST_GEOMETRY_ALGORITHMS_AREA_HPP
|