area.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  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-2024 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 = tag_t<Geometry>
  101. >
  102. struct area : detail::calculate_null
  103. {
  104. template <typename Strategy>
  105. static inline auto apply(Geometry const& geometry, Strategy const& strategy)
  106. {
  107. return calculate_null::apply
  108. <
  109. typename area_result<Geometry, Strategy>::type
  110. >(geometry, strategy);
  111. }
  112. };
  113. template <typename Geometry>
  114. struct area<Geometry, box_tag> : detail::area::box_area
  115. {};
  116. template <typename Ring>
  117. struct area<Ring, ring_tag>
  118. : detail::area::ring_area
  119. {};
  120. template <typename Polygon>
  121. struct area<Polygon, polygon_tag> : detail::calculate_polygon_sum
  122. {
  123. template <typename Strategy>
  124. static inline auto apply(Polygon const& polygon, Strategy const& strategy)
  125. {
  126. return calculate_polygon_sum::apply
  127. <
  128. typename area_result<Polygon, Strategy>::type,
  129. detail::area::ring_area
  130. >(polygon, strategy);
  131. }
  132. };
  133. template <typename MultiGeometry>
  134. struct area<MultiGeometry, multi_polygon_tag> : detail::multi_sum
  135. {
  136. template <typename Strategy>
  137. static inline auto apply(MultiGeometry const& multi, Strategy const& strategy)
  138. {
  139. return multi_sum::apply
  140. <
  141. typename area_result<MultiGeometry, Strategy>::type,
  142. area<typename boost::range_value<MultiGeometry>::type>
  143. >(multi, strategy);
  144. }
  145. };
  146. } // namespace dispatch
  147. #endif // DOXYGEN_NO_DISPATCH
  148. namespace resolve_strategy
  149. {
  150. template
  151. <
  152. typename Strategy,
  153. bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategy>::value
  154. >
  155. struct area
  156. {
  157. template <typename Geometry>
  158. static inline auto apply(Geometry const& geometry, Strategy const& strategy)
  159. {
  160. return dispatch::area<Geometry>::apply(geometry, strategy);
  161. }
  162. };
  163. template <typename Strategy>
  164. struct area<Strategy, false>
  165. {
  166. template <typename Geometry>
  167. static auto apply(Geometry const& geometry, Strategy const& strategy)
  168. {
  169. using strategies::area::services::strategy_converter;
  170. return dispatch::area
  171. <
  172. Geometry
  173. >::apply(geometry, strategy_converter<Strategy>::get(strategy));
  174. }
  175. };
  176. template <>
  177. struct area<default_strategy, false>
  178. {
  179. template <typename Geometry>
  180. static inline auto apply(Geometry const& geometry, default_strategy)
  181. {
  182. typedef typename strategies::area::services::default_strategy
  183. <
  184. Geometry
  185. >::type strategy_type;
  186. return dispatch::area<Geometry>::apply(geometry, strategy_type());
  187. }
  188. };
  189. } // namespace resolve_strategy
  190. namespace resolve_dynamic
  191. {
  192. template <typename Geometry, typename Tag = geometry::tag_t<Geometry>>
  193. struct area
  194. {
  195. template <typename Strategy>
  196. static inline auto apply(Geometry const& geometry, Strategy const& strategy)
  197. {
  198. return resolve_strategy::area<Strategy>::apply(geometry, strategy);
  199. }
  200. };
  201. template <typename Geometry>
  202. struct area<Geometry, dynamic_geometry_tag>
  203. {
  204. template <typename Strategy>
  205. static inline auto apply(Geometry const& geometry, Strategy const& strategy)
  206. {
  207. typename area_result<Geometry, Strategy>::type result = 0;
  208. traits::visit<Geometry>::apply([&](auto const& g)
  209. {
  210. result = area<util::remove_cref_t<decltype(g)>>::apply(g, strategy);
  211. }, geometry);
  212. return result;
  213. }
  214. };
  215. template <typename Geometry>
  216. struct area<Geometry, geometry_collection_tag>
  217. {
  218. template <typename Strategy>
  219. static inline auto apply(Geometry const& geometry, Strategy const& strategy)
  220. {
  221. typename area_result<Geometry, Strategy>::type result = 0;
  222. detail::visit_breadth_first([&](auto const& g)
  223. {
  224. result += area<util::remove_cref_t<decltype(g)>>::apply(g, strategy);
  225. return true;
  226. }, geometry);
  227. return result;
  228. }
  229. };
  230. } // namespace resolve_dynamic
  231. /*!
  232. \brief \brief_calc{area}
  233. \ingroup area
  234. \details \details_calc{area}. \details_default_strategy
  235. The area algorithm calculates the surface area of all geometries having a surface, namely
  236. box, polygon, ring, multipolygon. The units are the square of the units used for the points
  237. defining the surface. If subject geometry is defined in meters, then area is calculated
  238. in square meters.
  239. The area calculation can be done in all three common coordinate systems, Cartesian, Spherical
  240. and Geographic as well.
  241. \tparam Geometry \tparam_geometry
  242. \param geometry \param_geometry
  243. \return \return_calc{area}
  244. \qbk{[include reference/algorithms/area.qbk]}
  245. \qbk{[heading Examples]}
  246. \qbk{[area] [area_output]}
  247. */
  248. template <typename Geometry>
  249. inline auto area(Geometry const& geometry)
  250. {
  251. concepts::check<Geometry const>();
  252. // detail::throw_on_empty_input(geometry);
  253. return resolve_dynamic::area<Geometry>::apply(geometry, default_strategy());
  254. }
  255. /*!
  256. \brief \brief_calc{area} \brief_strategy
  257. \ingroup area
  258. \details \details_calc{area} \brief_strategy. \details_strategy_reasons
  259. \tparam Geometry \tparam_geometry
  260. \tparam Strategy \tparam_strategy{Area}
  261. \param geometry \param_geometry
  262. \param strategy \param_strategy{area}
  263. \return \return_calc{area}
  264. \qbk{distinguish,with strategy}
  265. \qbk{
  266. [include reference/algorithms/area.qbk]
  267. [heading Available Strategies]
  268. \* [link geometry.reference.strategies.strategy_area_cartesian Cartesian]
  269. \* [link geometry.reference.strategies.strategy_area_spherical Spherical]
  270. \* [link geometry.reference.strategies.strategy_area_geographic Geographic]
  271. [heading Example]
  272. [area_with_strategy]
  273. [area_with_strategy_output]
  274. }
  275. */
  276. template <typename Geometry, typename Strategy>
  277. inline auto area(Geometry const& geometry, Strategy const& strategy)
  278. {
  279. concepts::check<Geometry const>();
  280. // detail::throw_on_empty_input(geometry);
  281. return resolve_dynamic::area<Geometry>::apply(geometry, strategy);
  282. }
  283. }} // namespace boost::geometry
  284. #endif // BOOST_GEOMETRY_ALGORITHMS_AREA_HPP