direction.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  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. // THIS IS EQUAL TO arrival_a, arrival_b - they probably can go now we have robust fractions
  71. int arrival[2]; // 1=arrival, -1=departure, 0=neutral; == how_a//how_b
  72. // About arrival[0] (== arrival of a2 w.r.t. b) for COLLINEAR cases
  73. // Arrival 1: a1--------->a2 (a arrives within b)
  74. // b1----->b2
  75. // Arrival 1: (a in b)
  76. //
  77. // Arrival -1: a1--------->a2 (a does not arrive within b)
  78. // b1----->b2
  79. // Arrival -1: (b in a) a_1-------------a_2
  80. // b_1---b_2
  81. // Arrival 0: a1------->a2 (a arrives at TO-border of b)
  82. // b1--->b2
  83. };
  84. struct segments_direction
  85. {
  86. typedef direction_type return_type;
  87. template
  88. <
  89. typename Segment1,
  90. typename Segment2,
  91. typename SegmentIntersectionInfo
  92. >
  93. static inline return_type segments_crosses(side_info const& sides,
  94. SegmentIntersectionInfo const& ,
  95. Segment1 const& , Segment2 const& )
  96. {
  97. bool const ra0 = sides.get<0,0>() == 0;
  98. bool const ra1 = sides.get<0,1>() == 0;
  99. bool const rb0 = sides.get<1,0>() == 0;
  100. bool const rb1 = sides.get<1,1>() == 0;
  101. return
  102. // opposite and same starting point (FROM)
  103. ra0 && rb0 ? calculate_side<1>(sides, 'f', -1, -1)
  104. // opposite and point to each other (TO)
  105. : ra1 && rb1 ? calculate_side<0>(sides, 't', 1, 1)
  106. // not opposite, forming an angle, first a then b,
  107. // directed either both left, or both right
  108. // Check side of B2 from A. This is not calculated before
  109. : ra1 && rb0 ? angle<1>(sides, 'a', 1, -1)
  110. // not opposite, forming a angle, first b then a,
  111. // directed either both left, or both right
  112. : ra0 && rb1 ? angle<0>(sides, 'a', -1, 1)
  113. // b starts from interior of a
  114. : rb0 ? starts_from_middle(sides, 'B', 0, -1)
  115. // a starts from interior of b (#39)
  116. : ra0 ? starts_from_middle(sides, 'A', -1, 0)
  117. // b ends at interior of a, calculate direction of A from IP
  118. : rb1 ? b_ends_at_middle(sides)
  119. // a ends at interior of b
  120. : ra1 ? a_ends_at_middle(sides)
  121. // normal intersection
  122. : calculate_side<1>(sides, 'i', -1, -1)
  123. ;
  124. }
  125. template <typename SegmentIntersectionInfo, typename Point>
  126. static inline return_type segments_share_common_point(side_info const& sides,
  127. SegmentIntersectionInfo const& ,
  128. Point const&)
  129. {
  130. return segments_crosses(sides, sides, sides, sides);
  131. }
  132. template <typename Ratio>
  133. static inline int arrival_value(Ratio const& r_from, Ratio const& r_to)
  134. {
  135. // a1--------->a2
  136. // b1----->b2
  137. // a departs: -1
  138. // a1--------->a2
  139. // b1----->b2
  140. // a arrives: 1
  141. // a1--------->a2
  142. // b1----->b2
  143. // both arrive there -> r-to = 1/1, or 0/1 (on_segment)
  144. // First check the TO (for arrival), then FROM (for departure)
  145. return r_to.in_segment() ? 1
  146. : r_to.on_segment() ? 0
  147. : r_from.on_segment() ? -1
  148. : -1
  149. ;
  150. }
  151. template <typename Ratio>
  152. static inline void analyze(Ratio const& r,
  153. int& in_segment_count,
  154. int& on_end_count,
  155. int& outside_segment_count)
  156. {
  157. if (r.on_end())
  158. {
  159. on_end_count++;
  160. }
  161. else if (r.in_segment())
  162. {
  163. in_segment_count++;
  164. }
  165. else
  166. {
  167. outside_segment_count++;
  168. }
  169. }
  170. static inline int arrival_from_position_value(int /*v_from*/, int v_to)
  171. {
  172. return v_to == 2 ? 1
  173. : v_to == 1 || v_to == 3 ? 0
  174. //: v_from >= 1 && v_from <= 3 ? -1
  175. : -1;
  176. // NOTE: this should be an equivalent of the above for the other order
  177. /* (v_from < 3 && v_to > 3) || (v_from > 3 && v_to < 3) ? 1
  178. : v_from == 3 || v_to == 3 ? 0
  179. : -1;*/
  180. }
  181. static inline void analyse_position_value(int pos_val,
  182. int & in_segment_count,
  183. int & on_end_count,
  184. int & outside_segment_count)
  185. {
  186. if ( pos_val == 1 || pos_val == 3 )
  187. {
  188. on_end_count++;
  189. }
  190. else if ( pos_val == 2 )
  191. {
  192. in_segment_count++;
  193. }
  194. else
  195. {
  196. outside_segment_count++;
  197. }
  198. }
  199. template <typename Segment1, typename Segment2, typename Ratio>
  200. static inline return_type segments_collinear(
  201. Segment1 const& , Segment2 const& , bool opposite,
  202. int a1_wrt_b, int a2_wrt_b, int b1_wrt_a, int b2_wrt_a,
  203. Ratio const& /*ra_from_wrt_b*/, Ratio const& /*ra_to_wrt_b*/,
  204. Ratio const& /*rb_from_wrt_a*/, Ratio const& /*rb_to_wrt_a*/)
  205. {
  206. return_type r('c', opposite);
  207. // IMPORTANT: the order of conditions is different as in intersection_points.hpp
  208. // We assign A in 0 and B in 1
  209. r.arrival[0] = arrival_from_position_value(a1_wrt_b, a2_wrt_b);
  210. r.arrival[1] = arrival_from_position_value(b1_wrt_a, b2_wrt_a);
  211. // Analyse them
  212. int a_in_segment_count = 0;
  213. int a_on_end_count = 0;
  214. int a_outside_segment_count = 0;
  215. int b_in_segment_count = 0;
  216. int b_on_end_count = 0;
  217. int b_outside_segment_count = 0;
  218. analyse_position_value(a1_wrt_b,
  219. a_in_segment_count, a_on_end_count, a_outside_segment_count);
  220. analyse_position_value(a2_wrt_b,
  221. a_in_segment_count, a_on_end_count, a_outside_segment_count);
  222. analyse_position_value(b1_wrt_a,
  223. b_in_segment_count, b_on_end_count, b_outside_segment_count);
  224. analyse_position_value(b2_wrt_a,
  225. b_in_segment_count, b_on_end_count, b_outside_segment_count);
  226. if (a_on_end_count == 1
  227. && b_on_end_count == 1
  228. && a_outside_segment_count == 1
  229. && b_outside_segment_count == 1)
  230. {
  231. // This is a collinear touch
  232. // --------> A (or B)
  233. // <---------- B (or A)
  234. // We adapt the "how"
  235. // TODO: how was to be refactored anyway,
  236. if (! opposite)
  237. {
  238. r.how = 'a';
  239. }
  240. else
  241. {
  242. r.how = r.arrival[0] == 0 ? 't' : 'f';
  243. }
  244. }
  245. else if (a_on_end_count == 2
  246. && b_on_end_count == 2)
  247. {
  248. r.how = 'e';
  249. }
  250. return r;
  251. }
  252. template <typename Segment>
  253. static inline return_type degenerate(Segment const& , bool)
  254. {
  255. return return_type('0', false);
  256. }
  257. template <typename Segment, typename Ratio>
  258. static inline return_type one_degenerate(Segment const& ,
  259. Ratio const& ,
  260. bool)
  261. {
  262. // To be decided
  263. return return_type('0', false);
  264. }
  265. static inline return_type disjoint()
  266. {
  267. return return_type('d', false);
  268. }
  269. static inline return_type error(std::string const&)
  270. {
  271. // Return "E" to denote error
  272. // This will throw an error in get_turn_info
  273. // TODO: change to enum or similar
  274. return return_type('E', false);
  275. }
  276. private :
  277. template <std::size_t I>
  278. static inline return_type calculate_side(side_info const& sides,
  279. char how, int how_a, int how_b)
  280. {
  281. int const dir = sides.get<1, I>() == 1 ? 1 : -1;
  282. return return_type(sides, how, how_a, how_b, -dir, dir);
  283. }
  284. template <std::size_t I>
  285. static inline return_type angle(side_info const& sides,
  286. char how, int how_a, int how_b)
  287. {
  288. int const dir = sides.get<1, I>() == 1 ? 1 : -1;
  289. return return_type(sides, how, how_a, how_b, dir, dir);
  290. }
  291. static inline return_type starts_from_middle(side_info const& sides,
  292. char which,
  293. int how_a, int how_b)
  294. {
  295. // Calculate ARROW of b segment w.r.t. s1
  296. int dir = sides.get<1, 1>() == 1 ? 1 : -1;
  297. // From other perspective, then reverse
  298. bool const is_a = which == 'A';
  299. if (is_a)
  300. {
  301. dir = -dir;
  302. }
  303. return return_type(sides, 's',
  304. how_a,
  305. how_b,
  306. is_a ? dir : -dir,
  307. ! is_a ? dir : -dir);
  308. }
  309. // To be harmonized
  310. static inline return_type a_ends_at_middle(side_info const& sides)
  311. {
  312. // Ending at the middle, one ARRIVES, the other one is NEUTRAL
  313. // (because it both "arrives" and "departs" there)
  314. int const dir = sides.get<1, 1>() == 1 ? 1 : -1;
  315. return return_type(sides, 'm', 1, 0, dir, dir);
  316. }
  317. static inline return_type b_ends_at_middle(side_info const& sides)
  318. {
  319. int const dir = sides.get<0, 1>() == 1 ? 1 : -1;
  320. return return_type(sides, 'm', 0, 1, dir, dir);
  321. }
  322. };
  323. }} // namespace policies::relate
  324. }} // namespace boost::geometry
  325. #endif // BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_DIRECTION_HPP