area.hpp 11 KB

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