area.hpp 10 KB

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