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.
6 // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
7 
8 // This file was modified by Oracle on 2017, 2018.
9 // Modifications copyright (c) 2017-2018 Oracle and/or its affiliates.
10 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
11 
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>
23 #include <boost/core/ignore_unused.hpp>
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>
47 #include <boost/geometry/strategies/area_result.hpp>
48 #include <boost/geometry/strategies/default_area_result.hpp>
49 #include <boost/geometry/strategies/default_strategy.hpp>
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 
62 
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
applyboost::geometry::detail::area::box_area71     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>
90     static inline typename area_result<Ring, Strategy>::type
applyboost::geometry::detail::area::ring_area91     apply(Ring const& ring, Strategy const& strategy)
92     {
93         BOOST_CONCEPT_ASSERT( (geometry::concepts::AreaStrategy<Ring, Strategy>) );
94         assert_dimension<Ring, 2>();
95 
96         // Ignore warning (because using static method sometimes) on strategy
97         boost::ignore_unused(strategy);
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         {
105             return typename area_result<Ring, Strategy>::type();
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);
117         typename Strategy::template state<Ring> state;
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>
151     static inline typename area_result<Geometry, Strategy>::type
applyboost::geometry::dispatch::area152         apply(Geometry const& geometry, Strategy const& strategy)
153     {
154         return calculate_null::apply
155             <
156                 typename area_result<Geometry, Strategy>::type
157             >(geometry, strategy);
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>
181     static inline typename area_result<Polygon, Strategy>::type
applyboost::geometry::dispatch::area182         apply(Polygon const& polygon, Strategy const& strategy)
183     {
184         return calculate_polygon_sum::apply<
185             typename area_result<Polygon, Strategy>::type,
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>
200     static inline typename area_result<MultiGeometry, Strategy>::type
applyboost::geometry::dispatch::area201     apply(MultiGeometry const& multi, Strategy const& strategy)
202     {
203         return multi_sum::apply
204                <
205                    typename area_result<MultiGeometry, Strategy>::type,
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 
216 namespace resolve_strategy
217 {
218 
219 template <typename Strategy>
220 struct area
221 {
222     template <typename Geometry>
223     static inline typename area_result<Geometry, Strategy>::type
applyboost::geometry::resolve_strategy::area224     apply(Geometry const& geometry, Strategy const& strategy)
225     {
226         return dispatch::area<Geometry>::apply(geometry, strategy);
227     }
228 };
229 
230 template <>
231 struct area<default_strategy>
232 {
233     template <typename Geometry>
234     static inline typename area_result<Geometry>::type
applyboost::geometry::resolve_strategy::area235     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 {
252 
253 template <typename Geometry>
254 struct area
255 {
256     template <typename Strategy>
257     static inline typename area_result<Geometry, Strategy>::type
applyboost::geometry::resolve_variant::area258         apply(Geometry const& geometry, Strategy const& strategy)
259     {
260         return resolve_strategy::area<Strategy>::apply(geometry, strategy);
261     }
262 };
263 
264 template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
265 struct area<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
266 {
267     typedef boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> variant_type;
268 
269     template <typename Strategy>
270     struct visitor
271         : boost::static_visitor<typename area_result<variant_type, Strategy>::type>
272     {
273         Strategy const& m_strategy;
274 
visitorboost::geometry::resolve_variant::area::visitor275         visitor(Strategy const& strategy): m_strategy(strategy) {}
276 
277         template <typename Geometry>
278         typename area_result<variant_type, Strategy>::type
operator ()boost::geometry::resolve_variant::area::visitor279         operator()(Geometry const& geometry) const
280         {
281             return area<Geometry>::apply(geometry, m_strategy);
282         }
283     };
284 
285     template <typename Strategy>
286     static inline typename area_result<variant_type, Strategy>::type
applyboost::geometry::resolve_variant::area287     apply(variant_type const& geometry,
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>
319 inline typename area_result<Geometry>::type
area(Geometry const & geometry)320 area(Geometry const& geometry)
321 {
322     concepts::check<Geometry const>();
323 
324     // detail::throw_on_empty_input(geometry);
325 
326     return resolve_variant::area<Geometry>::apply(geometry, default_strategy());
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 
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 
349 [heading Example]
350 [area_with_strategy]
351 [area_with_strategy_output]
352 }
353  */
354 template <typename Geometry, typename Strategy>
355 inline typename area_result<Geometry, Strategy>::type
area(Geometry const & geometry,Strategy const & strategy)356 area(Geometry const& geometry, Strategy const& strategy)
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
370