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