point_in_poly_winding.hpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
  4. // This file was modified by Oracle on 2013, 2014, 2016, 2017, 2018, 2019.
  5. // Modifications copyright (c) 2013-2019 Oracle and/or its affiliates.
  6. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  7. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
  8. // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
  9. // Use, modification and distribution is subject to the Boost Software License,
  10. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  11. // http://www.boost.org/LICENSE_1_0.txt)
  12. #ifndef BOOST_GEOMETRY_STRATEGY_CARTESIAN_POINT_IN_POLY_WINDING_HPP
  13. #define BOOST_GEOMETRY_STRATEGY_CARTESIAN_POINT_IN_POLY_WINDING_HPP
  14. #include <boost/geometry/core/tags.hpp>
  15. #include <boost/geometry/util/math.hpp>
  16. #include <boost/geometry/util/select_calculation_type.hpp>
  17. #include <boost/geometry/strategies/cartesian/point_in_box.hpp>
  18. #include <boost/geometry/strategies/cartesian/disjoint_box_box.hpp>
  19. #include <boost/geometry/strategies/cartesian/side_by_triangle.hpp>
  20. #include <boost/geometry/strategies/covered_by.hpp>
  21. #include <boost/geometry/strategies/within.hpp>
  22. namespace boost { namespace geometry
  23. {
  24. namespace strategy { namespace within
  25. {
  26. /*!
  27. \brief Within detection using winding rule in cartesian coordinate system.
  28. \ingroup strategies
  29. \tparam Point_ \tparam_point
  30. \tparam PointOfSegment_ \tparam_segment_point
  31. \tparam CalculationType \tparam_calculation
  32. \author Barend Gehrels
  33. \qbk{
  34. [heading See also]
  35. [link geometry.reference.algorithms.within.within_3_with_strategy within (with strategy)]
  36. }
  37. */
  38. template
  39. <
  40. typename Point_ = void, // for backward compatibility
  41. typename PointOfSegment_ = Point_, // for backward compatibility
  42. typename CalculationType = void
  43. >
  44. class cartesian_winding
  45. {
  46. template <typename Point, typename PointOfSegment>
  47. struct calculation_type
  48. : select_calculation_type
  49. <
  50. Point,
  51. PointOfSegment,
  52. CalculationType
  53. >
  54. {};
  55. /*! subclass to keep state */
  56. class counter
  57. {
  58. int m_count;
  59. bool m_touches;
  60. inline int code() const
  61. {
  62. return m_touches ? 0 : m_count == 0 ? -1 : 1;
  63. }
  64. public :
  65. friend class cartesian_winding;
  66. inline counter()
  67. : m_count(0)
  68. , m_touches(false)
  69. {}
  70. };
  71. public:
  72. typedef cartesian_tag cs_tag;
  73. typedef side::side_by_triangle<CalculationType> side_strategy_type;
  74. static inline side_strategy_type get_side_strategy()
  75. {
  76. return side_strategy_type();
  77. }
  78. typedef expand::cartesian_point expand_point_strategy_type;
  79. typedef typename side_strategy_type::envelope_strategy_type envelope_strategy_type;
  80. static inline envelope_strategy_type get_envelope_strategy()
  81. {
  82. return side_strategy_type::get_envelope_strategy();
  83. }
  84. typedef typename side_strategy_type::disjoint_strategy_type disjoint_strategy_type;
  85. static inline disjoint_strategy_type get_disjoint_strategy()
  86. {
  87. return side_strategy_type::get_disjoint_strategy();
  88. }
  89. typedef typename side_strategy_type::equals_point_point_strategy_type equals_point_point_strategy_type;
  90. static inline equals_point_point_strategy_type get_equals_point_point_strategy()
  91. {
  92. return side_strategy_type::get_equals_point_point_strategy();
  93. }
  94. typedef disjoint::cartesian_box_box disjoint_box_box_strategy_type;
  95. static inline disjoint_box_box_strategy_type get_disjoint_box_box_strategy()
  96. {
  97. return disjoint_box_box_strategy_type();
  98. }
  99. typedef covered_by::cartesian_point_box disjoint_point_box_strategy_type;
  100. // Typedefs and static methods to fulfill the concept
  101. typedef counter state_type;
  102. template <typename Point, typename PointOfSegment>
  103. static inline bool apply(Point const& point,
  104. PointOfSegment const& s1, PointOfSegment const& s2,
  105. counter& state)
  106. {
  107. bool eq1 = false;
  108. bool eq2 = false;
  109. int count = check_segment(point, s1, s2, state, eq1, eq2);
  110. if (count != 0)
  111. {
  112. int side = 0;
  113. if (count == 1 || count == -1)
  114. {
  115. side = side_equal(point, eq1 ? s1 : s2, count);
  116. }
  117. else // count == 2 || count == -2
  118. {
  119. // 1 left, -1 right
  120. side = side_strategy_type::apply(s1, s2, point);
  121. }
  122. if (side == 0)
  123. {
  124. // Point is lying on segment
  125. state.m_touches = true;
  126. state.m_count = 0;
  127. return false;
  128. }
  129. // Side is NEG for right, POS for left.
  130. // The count is -2 for left, 2 for right (or -1/1)
  131. // Side positive thus means RIGHT and LEFTSIDE or LEFT and RIGHTSIDE
  132. // See accompagnying figure (TODO)
  133. if (side * count > 0)
  134. {
  135. state.m_count += count;
  136. }
  137. }
  138. return ! state.m_touches;
  139. }
  140. static inline int result(counter const& state)
  141. {
  142. return state.code();
  143. }
  144. private:
  145. template <typename Point, typename PointOfSegment>
  146. static inline int check_segment(Point const& point,
  147. PointOfSegment const& seg1,
  148. PointOfSegment const& seg2,
  149. counter& state,
  150. bool& eq1, bool& eq2)
  151. {
  152. if (check_touch(point, seg1, seg2, state, eq1, eq2))
  153. {
  154. return 0;
  155. }
  156. return calculate_count(point, seg1, seg2, eq1, eq2);
  157. }
  158. template <typename Point, typename PointOfSegment>
  159. static inline bool check_touch(Point const& point,
  160. PointOfSegment const& seg1,
  161. PointOfSegment const& seg2,
  162. counter& state,
  163. bool& eq1, bool& eq2)
  164. {
  165. typedef typename calculation_type<Point, PointOfSegment>::type calc_t;
  166. calc_t const px = get<0>(point);
  167. calc_t const s1x = get<0>(seg1);
  168. calc_t const s2x = get<0>(seg2);
  169. eq1 = math::equals(s1x, px);
  170. eq2 = math::equals(s2x, px);
  171. // Both equal p -> segment vertical
  172. // The only thing which has to be done is check if point is ON segment
  173. if (eq1 && eq2)
  174. {
  175. calc_t const py = get<1>(point);
  176. calc_t const s1y = get<1>(seg1);
  177. calc_t const s2y = get<1>(seg2);
  178. if ((s1y <= py && s2y >= py) || (s2y <= py && s1y >= py))
  179. {
  180. state.m_touches = true;
  181. }
  182. return true;
  183. }
  184. return false;
  185. }
  186. template <typename Point, typename PointOfSegment>
  187. static inline int calculate_count(Point const& point,
  188. PointOfSegment const& seg1,
  189. PointOfSegment const& seg2,
  190. bool eq1, bool eq2)
  191. {
  192. typedef typename calculation_type<Point, PointOfSegment>::type calc_t;
  193. calc_t const p = get<0>(point);
  194. calc_t const s1 = get<0>(seg1);
  195. calc_t const s2 = get<0>(seg2);
  196. return eq1 ? (s2 > p ? 1 : -1) // Point on level s1, E/W depending on s2
  197. : eq2 ? (s1 > p ? -1 : 1) // idem
  198. : s1 < p && s2 > p ? 2 // Point between s1 -> s2 --> E
  199. : s2 < p && s1 > p ? -2 // Point between s2 -> s1 --> W
  200. : 0;
  201. }
  202. template <typename Point, typename PointOfSegment>
  203. static inline int side_equal(Point const& point,
  204. PointOfSegment const& se,
  205. int count)
  206. {
  207. // NOTE: for D=0 the signs would be reversed
  208. return math::equals(get<1>(point), get<1>(se)) ?
  209. 0 :
  210. get<1>(point) < get<1>(se) ?
  211. // assuming count is equal to 1 or -1
  212. -count : // ( count > 0 ? -1 : 1) :
  213. count; // ( count > 0 ? 1 : -1) ;
  214. }
  215. };
  216. #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
  217. namespace services
  218. {
  219. template <typename PointLike, typename Geometry, typename AnyTag1, typename AnyTag2>
  220. struct default_strategy<PointLike, Geometry, AnyTag1, AnyTag2, pointlike_tag, polygonal_tag, cartesian_tag, cartesian_tag>
  221. {
  222. typedef cartesian_winding<> type;
  223. };
  224. template <typename PointLike, typename Geometry, typename AnyTag1, typename AnyTag2>
  225. struct default_strategy<PointLike, Geometry, AnyTag1, AnyTag2, pointlike_tag, linear_tag, cartesian_tag, cartesian_tag>
  226. {
  227. typedef cartesian_winding<> type;
  228. };
  229. } // namespace services
  230. #endif
  231. }} // namespace strategy::within
  232. #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
  233. namespace strategy { namespace covered_by { namespace services
  234. {
  235. template <typename PointLike, typename Geometry, typename AnyTag1, typename AnyTag2>
  236. struct default_strategy<PointLike, Geometry, AnyTag1, AnyTag2, pointlike_tag, polygonal_tag, cartesian_tag, cartesian_tag>
  237. {
  238. typedef within::cartesian_winding<> type;
  239. };
  240. template <typename PointLike, typename Geometry, typename AnyTag1, typename AnyTag2>
  241. struct default_strategy<PointLike, Geometry, AnyTag1, AnyTag2, pointlike_tag, linear_tag, cartesian_tag, cartesian_tag>
  242. {
  243. typedef within::cartesian_winding<> type;
  244. };
  245. }}} // namespace strategy::covered_by::services
  246. #endif
  247. }} // namespace boost::geometry
  248. #endif // BOOST_GEOMETRY_STRATEGY_CARTESIAN_POINT_IN_POLY_WINDING_HPP