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