direction.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Use, modification and distribution is subject to the Boost Software License,
  4. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_DIRECTION_HPP
  7. #define BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_DIRECTION_HPP
  8. #include <cstddef>
  9. #include <string>
  10. #include <boost/concept_check.hpp>
  11. #include <boost/geometry/arithmetic/determinant.hpp>
  12. #include <boost/geometry/strategies/side_info.hpp>
  13. #include <boost/geometry/util/math.hpp>
  14. #include <boost/geometry/util/select_calculation_type.hpp>
  15. #include <boost/geometry/util/select_most_precise.hpp>
  16. namespace boost { namespace geometry
  17. {
  18. namespace policies { namespace relate
  19. {
  20. struct direction_type
  21. {
  22. // NOTE: "char" will be replaced by enum in future version
  23. inline direction_type(side_info const& s, char h,
  24. int ha, int hb,
  25. int da = 0, int db = 0,
  26. bool op = false)
  27. : how(h)
  28. , opposite(op)
  29. , how_a(ha)
  30. , how_b(hb)
  31. , dir_a(da)
  32. , dir_b(db)
  33. , sides(s)
  34. {
  35. arrival[0] = ha;
  36. arrival[1] = hb;
  37. }
  38. inline direction_type(char h, bool op, int ha = 0, int hb = 0)
  39. : how(h)
  40. , opposite(op)
  41. , how_a(ha)
  42. , how_b(hb)
  43. , dir_a(0)
  44. , dir_b(0)
  45. {
  46. arrival[0] = ha;
  47. arrival[1] = hb;
  48. }
  49. // TODO: replace this
  50. // NOTE: "char" will be replaced by enum in future version
  51. // "How" is the intersection formed?
  52. char how;
  53. // Is it opposite (for collinear/equal cases)
  54. bool opposite;
  55. // Information on how A arrives at intersection, how B arrives at intersection
  56. // 1: arrives at intersection
  57. // -1: starts from intersection
  58. int how_a;
  59. int how_b;
  60. // Direction: how is A positioned from B
  61. // 1: points left, seen from IP
  62. // -1: points right, seen from IP
  63. // In case of intersection: B's TO direction
  64. // In case that B's TO direction is at A: B's from direction
  65. // In collinear cases: it is 0
  66. int dir_a; // Direction of A-s TO from IP
  67. int dir_b; // Direction of B-s TO from IP
  68. // New information
  69. side_info sides;
  70. int arrival[2]; // 1=arrival, -1departure, 0=neutral; == how_a//how_b
  71. // About arrival[0] (== arrival of a2 w.r.t. b) for COLLINEAR cases
  72. // Arrival 1: a1--------->a2 (a arrives within b)
  73. // b1----->b2
  74. // Arrival 1: (a in b)
  75. //
  76. // Arrival -1: a1--------->a2 (a does not arrive within b)
  77. // b1----->b2
  78. // Arrival -1: (b in a) a_1-------------a_2
  79. // b_1---b_2
  80. // Arrival 0: a1------->a2 (a arrives at TO-border of b)
  81. // b1--->b2
  82. };
  83. template <typename S1, typename S2, typename CalculationType = void>
  84. struct segments_direction
  85. {
  86. typedef direction_type return_type;
  87. typedef S1 segment_type1;
  88. typedef S2 segment_type2;
  89. typedef typename select_calculation_type
  90. <
  91. S1, S2, CalculationType
  92. >::type coordinate_type;
  93. // Get the same type, but at least a double
  94. typedef typename select_most_precise<coordinate_type, double>::type rtype;
  95. template <typename R>
  96. static inline return_type segments_intersect(side_info const& sides,
  97. R const&,
  98. coordinate_type const& dx1, coordinate_type const& dy1,
  99. coordinate_type const& dx2, coordinate_type const& dy2,
  100. S1 const& s1, S2 const& s2)
  101. {
  102. bool const ra0 = sides.get<0,0>() == 0;
  103. bool const ra1 = sides.get<0,1>() == 0;
  104. bool const rb0 = sides.get<1,0>() == 0;
  105. bool const rb1 = sides.get<1,1>() == 0;
  106. return
  107. // opposite and same starting point (FROM)
  108. ra0 && rb0 ? calculate_side<1>(sides, dx1, dy1, s1, s2, 'f', -1, -1)
  109. // opposite and point to each other (TO)
  110. : ra1 && rb1 ? calculate_side<0>(sides, dx1, dy1, s1, s2, 't', 1, 1)
  111. // not opposite, forming an angle, first a then b,
  112. // directed either both left, or both right
  113. // Check side of B2 from A. This is not calculated before
  114. : ra1 && rb0 ? angle<1>(sides, dx1, dy1, s1, s2, 'a', 1, -1)
  115. // not opposite, forming a angle, first b then a,
  116. // directed either both left, or both right
  117. : ra0 && rb1 ? angle<0>(sides, dx1, dy1, s1, s2, 'a', -1, 1)
  118. // b starts from interior of a
  119. : rb0 ? starts_from_middle(sides, dx1, dy1, s1, s2, 'B', 0, -1)
  120. // a starts from interior of b (#39)
  121. : ra0 ? starts_from_middle(sides, dx1, dy1, s1, s2, 'A', -1, 0)
  122. // b ends at interior of a, calculate direction of A from IP
  123. : rb1 ? b_ends_at_middle(sides, dx2, dy2, s1, s2)
  124. // a ends at interior of b
  125. : ra1 ? a_ends_at_middle(sides, dx1, dy1, s1, s2)
  126. // normal intersection
  127. : calculate_side<1>(sides, dx1, dy1, s1, s2, 'i', -1, -1)
  128. ;
  129. }
  130. static inline return_type collinear_touch(
  131. coordinate_type const& ,
  132. coordinate_type const& , int arrival_a, int arrival_b)
  133. {
  134. // Though this is 'collinear', we handle it as To/From/Angle because it is the same.
  135. // It only does NOT have a direction.
  136. side_info sides;
  137. //int const arrive = how == 'T' ? 1 : -1;
  138. bool opposite = arrival_a == arrival_b;
  139. return
  140. ! opposite
  141. ? return_type(sides, 'a', arrival_a, arrival_b)
  142. : return_type(sides, arrival_a == 0 ? 't' : 'f', arrival_a, arrival_b, 0, 0, true);
  143. }
  144. template <typename S>
  145. static inline return_type collinear_interior_boundary_intersect(S const& , bool,
  146. int arrival_a, int arrival_b, bool opposite)
  147. {
  148. return_type r('c', opposite);
  149. r.arrival[0] = arrival_a;
  150. r.arrival[1] = arrival_b;
  151. return r;
  152. }
  153. static inline return_type collinear_a_in_b(S1 const& , bool opposite)
  154. {
  155. return_type r('c', opposite);
  156. r.arrival[0] = 1;
  157. r.arrival[1] = -1;
  158. return r;
  159. }
  160. static inline return_type collinear_b_in_a(S2 const& , bool opposite)
  161. {
  162. return_type r('c', opposite);
  163. r.arrival[0] = -1;
  164. r.arrival[1] = 1;
  165. return r;
  166. }
  167. static inline return_type collinear_overlaps(
  168. coordinate_type const& , coordinate_type const& ,
  169. coordinate_type const& , coordinate_type const& ,
  170. int arrival_a, int arrival_b, bool opposite)
  171. {
  172. return_type r('c', opposite);
  173. r.arrival[0] = arrival_a;
  174. r.arrival[1] = arrival_b;
  175. return r;
  176. }
  177. static inline return_type segment_equal(S1 const& , bool opposite)
  178. {
  179. return return_type('e', opposite);
  180. }
  181. static inline return_type degenerate(S1 const& , bool)
  182. {
  183. return return_type('0', false);
  184. }
  185. static inline return_type disjoint()
  186. {
  187. return return_type('d', false);
  188. }
  189. static inline return_type collinear_disjoint()
  190. {
  191. return return_type('d', false);
  192. }
  193. static inline return_type error(std::string const&)
  194. {
  195. // Return "E" to denote error
  196. // This will throw an error in get_turn_info
  197. // TODO: change to enum or similar
  198. return return_type('E', false);
  199. }
  200. private :
  201. static inline bool is_left
  202. (
  203. coordinate_type const& ux,
  204. coordinate_type const& uy,
  205. coordinate_type const& vx,
  206. coordinate_type const& vy
  207. )
  208. {
  209. // This is a "side calculation" as in the strategies, but here terms are precalculated
  210. // We might merge this with side, offering a pre-calculated term (in fact already done using cross-product)
  211. // Waiting for implementing spherical...
  212. rtype const zero = rtype();
  213. return geometry::detail::determinant<rtype>(ux, uy, vx, vy) > zero;
  214. }
  215. template <std::size_t I>
  216. static inline return_type calculate_side(side_info const& sides,
  217. coordinate_type const& dx1, coordinate_type const& dy1,
  218. S1 const& s1, S2 const& s2,
  219. char how, int how_a, int how_b)
  220. {
  221. coordinate_type dpx = get<I, 0>(s2) - get<0, 0>(s1);
  222. coordinate_type dpy = get<I, 1>(s2) - get<0, 1>(s1);
  223. return is_left(dx1, dy1, dpx, dpy)
  224. ? return_type(sides, how, how_a, how_b, -1, 1)
  225. : return_type(sides, how, how_a, how_b, 1, -1);
  226. }
  227. template <std::size_t I>
  228. static inline return_type angle(side_info const& sides,
  229. coordinate_type const& dx1, coordinate_type const& dy1,
  230. S1 const& s1, S2 const& s2,
  231. char how, int how_a, int how_b)
  232. {
  233. coordinate_type dpx = get<I, 0>(s2) - get<0, 0>(s1);
  234. coordinate_type dpy = get<I, 1>(s2) - get<0, 1>(s1);
  235. return is_left(dx1, dy1, dpx, dpy)
  236. ? return_type(sides, how, how_a, how_b, 1, 1)
  237. : return_type(sides, how, how_a, how_b, -1, -1);
  238. }
  239. static inline return_type starts_from_middle(side_info const& sides,
  240. coordinate_type const& dx1, coordinate_type const& dy1,
  241. S1 const& s1, S2 const& s2,
  242. char which,
  243. int how_a, int how_b)
  244. {
  245. // Calculate ARROW of b segment w.r.t. s1
  246. coordinate_type dpx = get<1, 0>(s2) - get<0, 0>(s1);
  247. coordinate_type dpy = get<1, 1>(s2) - get<0, 1>(s1);
  248. int dir = is_left(dx1, dy1, dpx, dpy) ? 1 : -1;
  249. // From other perspective, then reverse
  250. bool const is_a = which == 'A';
  251. if (is_a)
  252. {
  253. dir = -dir;
  254. }
  255. return return_type(sides, 's',
  256. how_a,
  257. how_b,
  258. is_a ? dir : -dir,
  259. ! is_a ? dir : -dir);
  260. }
  261. // To be harmonized
  262. static inline return_type a_ends_at_middle(side_info const& sides,
  263. coordinate_type const& dx, coordinate_type const& dy,
  264. S1 const& s1, S2 const& s2)
  265. {
  266. coordinate_type dpx = get<1, 0>(s2) - get<0, 0>(s1);
  267. coordinate_type dpy = get<1, 1>(s2) - get<0, 1>(s1);
  268. // Ending at the middle, one ARRIVES, the other one is NEUTRAL
  269. // (because it both "arrives" and "departs" there
  270. return is_left(dx, dy, dpx, dpy)
  271. ? return_type(sides, 'm', 1, 0, 1, 1)
  272. : return_type(sides, 'm', 1, 0, -1, -1);
  273. }
  274. static inline return_type b_ends_at_middle(side_info const& sides,
  275. coordinate_type const& dx, coordinate_type const& dy,
  276. S1 const& s1, S2 const& s2)
  277. {
  278. coordinate_type dpx = get<1, 0>(s1) - get<0, 0>(s2);
  279. coordinate_type dpy = get<1, 1>(s1) - get<0, 1>(s2);
  280. return is_left(dx, dy, dpx, dpy)
  281. ? return_type(sides, 'm', 0, 1, 1, 1)
  282. : return_type(sides, 'm', 0, 1, -1, -1);
  283. }
  284. };
  285. }} // namespace policies::relate
  286. }} // namespace boost::geometry
  287. #endif // BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_DIRECTION_HPP