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