point_in_box_by_side.hpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  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) 2023 Adam Wulkiewicz, Lodz, Poland.
  6. // This file was modified by Oracle on 2018-2020.
  7. // Modifications copyright (c) 2018-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_STRATEGIES_AGNOSTIC_POINT_IN_BOX_BY_SIDE_HPP
  15. #define BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_POINT_IN_BOX_BY_SIDE_HPP
  16. #include <array>
  17. #include <boost/core/ignore_unused.hpp>
  18. #include <boost/geometry/algorithms/assign.hpp>
  19. #include <boost/geometry/core/access.hpp>
  20. #include <boost/geometry/core/coordinate_dimension.hpp>
  21. #include <boost/geometry/strategies/covered_by.hpp>
  22. #include <boost/geometry/strategies/geographic/side.hpp>
  23. #include <boost/geometry/strategies/side.hpp>
  24. #include <boost/geometry/strategies/spherical/ssf.hpp>
  25. #include <boost/geometry/strategies/within.hpp>
  26. namespace boost { namespace geometry { namespace strategy
  27. {
  28. namespace within
  29. {
  30. #ifndef DOXYGEN_NO_DETAIL
  31. namespace detail
  32. {
  33. struct decide_within
  34. {
  35. static inline bool apply(int side, bool& result)
  36. {
  37. if (side != 1)
  38. {
  39. result = false;
  40. return false;
  41. }
  42. return true; // continue
  43. }
  44. };
  45. struct decide_covered_by
  46. {
  47. static inline bool apply(int side, bool& result)
  48. {
  49. if (side != 1)
  50. {
  51. result = side >= 0;
  52. return false;
  53. }
  54. return true; // continue
  55. }
  56. };
  57. // WARNING
  58. // This strategy is not suitable for boxes in non-cartesian CSes having edges
  59. // longer than 180deg because e.g. the SSF formula picks the side of the closer
  60. // longitude, so for long edges the side is the opposite.
  61. // Actually it is not suitable for shorter edges either because the edges of
  62. // boxes are defined by meridians and parallels, not great circles or geodesics.
  63. template <typename Decide, typename Point, typename Box, typename Strategy>
  64. inline bool point_in_box_by_side(Point const& point, Box const& box,
  65. Strategy const& strategy)
  66. {
  67. boost::ignore_unused(strategy);
  68. // Create (counterclockwise) array of points, the fifth one closes it
  69. // Every point should be on the LEFT side (=1), or ON the border (=0),
  70. // So >= 1 or >= 0
  71. std::array<typename point_type<Box>::type, 5> bp;
  72. geometry::detail::assign_box_corners_oriented<true>(box, bp);
  73. bp[4] = bp[0];
  74. bool result = true;
  75. for (int i = 1; i < 5; i++)
  76. {
  77. int const side = strategy.apply(point, bp[i - 1], bp[i]);
  78. if (! Decide::apply(side, result))
  79. {
  80. return result;
  81. }
  82. }
  83. return result;
  84. }
  85. } // namespace detail
  86. #endif // DOXYGEN_NO_DETAIL
  87. // There should probably be another category of geometry different than box,
  88. // e.g. rectangle or convex_ring. This strategy should probably be an
  89. // algorithm calling side strategy.
  90. template <typename CalculationType = void>
  91. struct cartesian_point_box_by_side
  92. {
  93. template <typename Point, typename Box>
  94. static inline bool apply(Point const& point, Box const& box)
  95. {
  96. using side_strategy_type
  97. = typename strategy::side::services::default_strategy
  98. <cartesian_tag, CalculationType>::type;
  99. return within::detail::point_in_box_by_side
  100. <
  101. within::detail::decide_within
  102. >(point, box, side_strategy_type());
  103. }
  104. };
  105. template <typename CalculationType = void>
  106. struct spherical_point_box_by_side
  107. {
  108. template <typename Point, typename Box>
  109. static inline bool apply(Point const& point, Box const& box)
  110. {
  111. return within::detail::point_in_box_by_side
  112. <
  113. within::detail::decide_within
  114. >(point, box,
  115. strategy::side::spherical_side_formula<CalculationType>());
  116. }
  117. };
  118. template
  119. <
  120. typename FormulaPolicy = strategy::andoyer,
  121. typename Spheroid = srs::spheroid<double>,
  122. typename CalculationType = void
  123. >
  124. struct geographic_point_box_by_side
  125. {
  126. geographic_point_box_by_side() = default;
  127. explicit geographic_point_box_by_side(Spheroid const& spheroid)
  128. : m_side(spheroid)
  129. {}
  130. template <typename Point, typename Box>
  131. bool apply(Point const& point, Box const& box) const
  132. {
  133. return within::detail::point_in_box_by_side
  134. <
  135. within::detail::decide_within
  136. >(point, box, m_side);
  137. }
  138. Spheroid const& model() const
  139. {
  140. return m_side.model();
  141. }
  142. private:
  143. strategy::side::geographic
  144. <
  145. FormulaPolicy, Spheroid, CalculationType
  146. > m_side;
  147. };
  148. } // namespace within
  149. namespace covered_by
  150. {
  151. template <typename CalculationType = void>
  152. struct cartesian_point_box_by_side
  153. {
  154. template <typename Point, typename Box>
  155. static bool apply(Point const& point, Box const& box)
  156. {
  157. using side_strategy_type
  158. = typename strategy::side::services::default_strategy
  159. <cartesian_tag, CalculationType>::type;
  160. return within::detail::point_in_box_by_side
  161. <
  162. within::detail::decide_covered_by
  163. >(point, box, side_strategy_type());
  164. }
  165. };
  166. template <typename CalculationType = void>
  167. struct spherical_point_box_by_side
  168. {
  169. template <typename Point, typename Box>
  170. static bool apply(Point const& point, Box const& box)
  171. {
  172. return within::detail::point_in_box_by_side
  173. <
  174. within::detail::decide_covered_by
  175. >(point, box,
  176. strategy::side::spherical_side_formula<CalculationType>());
  177. }
  178. };
  179. template
  180. <
  181. typename FormulaPolicy = strategy::andoyer,
  182. typename Spheroid = srs::spheroid<double>,
  183. typename CalculationType = void
  184. >
  185. struct geographic_point_box_by_side
  186. {
  187. geographic_point_box_by_side() = default;
  188. explicit geographic_point_box_by_side(Spheroid const& spheroid)
  189. : m_side(spheroid)
  190. {}
  191. template <typename Point, typename Box>
  192. bool apply(Point const& point, Box const& box) const
  193. {
  194. return within::detail::point_in_box_by_side
  195. <
  196. within::detail::decide_covered_by
  197. >(point, box, m_side);
  198. }
  199. Spheroid const& model() const
  200. {
  201. return m_side.model();
  202. }
  203. private:
  204. strategy::side::geographic
  205. <
  206. FormulaPolicy, Spheroid, CalculationType
  207. > m_side;
  208. };
  209. }
  210. }}} // namespace boost::geometry::strategy
  211. #endif // BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_POINT_IN_BOX_BY_SIDE_HPP