area.hpp 11 KB

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