get_turn_info_for_endpoint.hpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
  3. // This file was modified by Oracle on 2013, 2014, 2017, 2018.
  4. // Modifications copyright (c) 2013-2018 Oracle and/or its affiliates.
  5. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  6. // Use, modification and distribution is subject to the Boost Software License,
  7. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  8. // http://www.boost.org/LICENSE_1_0.txt)
  9. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_FOR_ENDPOINT_HPP
  10. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_FOR_ENDPOINT_HPP
  11. #include <boost/core/ignore_unused.hpp>
  12. #include <boost/geometry/algorithms/detail/equals/point_point.hpp>
  13. #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
  14. #include <boost/geometry/core/assert.hpp>
  15. #include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
  16. namespace boost { namespace geometry {
  17. #ifndef DOXYGEN_NO_DETAIL
  18. namespace detail { namespace overlay {
  19. // SEGMENT_INTERSECTION RESULT
  20. // C H0 H1 A0 A1 O IP1 IP2
  21. // D0 and D1 == 0
  22. // |--------> 2 0 0 0 0 F i/i x/x
  23. // |-------->
  24. //
  25. // |--------> 2 0 0 0 0 T i/x x/i
  26. // <--------|
  27. //
  28. // |-----> 1 0 0 0 0 T x/x
  29. // <-----|
  30. //
  31. // |---------> 2 0 0 0 1 T i/x x/i
  32. // <----|
  33. //
  34. // |---------> 2 0 0 0 0 F i/i x/x
  35. // |---->
  36. //
  37. // |---------> 2 0 0 -1 1 F i/i u/x
  38. // |---->
  39. //
  40. // |---------> 2 0 0 -1 0 T i/x u/i
  41. // <----|
  42. // |-------> 2 0 0 1 -1 F and i/i x/u
  43. // |-------> 2 0 0 -1 1 F symmetric i/i u/x
  44. // |------->
  45. //
  46. // |-------> 2 0 0 -1 -1 T i/u u/i
  47. // <-------|
  48. //
  49. // |-------> 2 0 0 1 1 T i/x x/i
  50. // <-------|
  51. //
  52. // |--------> 2 0 0 -1 1 F i/i u/x
  53. // |---->
  54. //
  55. // |--------> 2 0 0 -1 1 T i/x u/i
  56. // <----|
  57. // |-----> 1 -1 -1 -1 -1 T u/u
  58. // <-----|
  59. //
  60. // |-----> 1 -1 0 -1 0 F and u/x
  61. // |-----> 1 0 -1 0 -1 F symmetric x/u
  62. // |----->
  63. // D0 or D1 != 0
  64. // ^
  65. // |
  66. // + 1 -1 1 -1 1 F and u/x (P is vertical)
  67. // |--------> 1 1 -1 1 -1 F symmetric x/u (P is horizontal)
  68. // ^
  69. // |
  70. // +
  71. //
  72. // +
  73. // |
  74. // v
  75. // |--------> 1 1 1 1 1 F x/x (P is vertical)
  76. //
  77. // ^
  78. // |
  79. // +
  80. // |--------> 1 -1 -1 -1 -1 F u/u (P is vertical)
  81. //
  82. // ^
  83. // |
  84. // +
  85. // |--------> 1 0 -1 0 -1 F u/u (P is vertical)
  86. //
  87. // +
  88. // |
  89. // v
  90. // |--------> 1 0 1 0 1 F u/x (P is vertical)
  91. //
  92. class linear_intersections
  93. {
  94. public:
  95. template <typename Point1, typename Point2, typename IntersectionResult, typename EqPPStrategy>
  96. linear_intersections(Point1 const& pi,
  97. Point2 const& qi,
  98. IntersectionResult const& result,
  99. bool is_p_last, bool is_q_last,
  100. EqPPStrategy const& strategy)
  101. {
  102. int arrival_a = result.template get<1>().arrival[0];
  103. int arrival_b = result.template get<1>().arrival[1];
  104. bool same_dirs = result.template get<1>().dir_a == 0
  105. && result.template get<1>().dir_b == 0;
  106. if ( same_dirs )
  107. {
  108. if ( result.template get<0>().count == 2 )
  109. {
  110. if ( ! result.template get<1>().opposite )
  111. {
  112. ips[0].p_operation = operation_intersection;
  113. ips[0].q_operation = operation_intersection;
  114. ips[1].p_operation = union_or_blocked_same_dirs(arrival_a, is_p_last);
  115. ips[1].q_operation = union_or_blocked_same_dirs(arrival_b, is_q_last);
  116. ips[0].is_pi
  117. = equals::equals_point_point(
  118. pi, result.template get<0>().intersections[0], strategy);
  119. ips[0].is_qi
  120. = equals::equals_point_point(
  121. qi, result.template get<0>().intersections[0], strategy);
  122. ips[1].is_pj = arrival_a != -1;
  123. ips[1].is_qj = arrival_b != -1;
  124. }
  125. else
  126. {
  127. ips[0].p_operation = operation_intersection;
  128. ips[0].q_operation = union_or_blocked_same_dirs(arrival_b, is_q_last);
  129. ips[1].p_operation = union_or_blocked_same_dirs(arrival_a, is_p_last);
  130. ips[1].q_operation = operation_intersection;
  131. ips[0].is_pi = arrival_b != 1;
  132. ips[0].is_qj = arrival_b != -1;
  133. ips[1].is_pj = arrival_a != -1;
  134. ips[1].is_qi = arrival_a != 1;
  135. }
  136. }
  137. else
  138. {
  139. BOOST_GEOMETRY_ASSERT(result.template get<0>().count == 1);
  140. ips[0].p_operation = union_or_blocked_same_dirs(arrival_a, is_p_last);
  141. ips[0].q_operation = union_or_blocked_same_dirs(arrival_b, is_q_last);
  142. ips[0].is_pi = arrival_a == -1;
  143. ips[0].is_qi = arrival_b == -1;
  144. ips[0].is_pj = arrival_a == 0;
  145. ips[0].is_qj = arrival_b == 0;
  146. }
  147. }
  148. else
  149. {
  150. ips[0].p_operation = union_or_blocked_different_dirs(arrival_a, is_p_last);
  151. ips[0].q_operation = union_or_blocked_different_dirs(arrival_b, is_q_last);
  152. ips[0].is_pi = arrival_a == -1;
  153. ips[0].is_qi = arrival_b == -1;
  154. ips[0].is_pj = arrival_a == 1;
  155. ips[0].is_qj = arrival_b == 1;
  156. }
  157. }
  158. struct ip_info
  159. {
  160. inline ip_info()
  161. : p_operation(operation_none), q_operation(operation_none)
  162. , is_pi(false), is_pj(false), is_qi(false), is_qj(false)
  163. {}
  164. operation_type p_operation, q_operation;
  165. bool is_pi, is_pj, is_qi, is_qj;
  166. };
  167. template <std::size_t I>
  168. ip_info const& get() const
  169. {
  170. BOOST_STATIC_ASSERT(I < 2);
  171. return ips[I];
  172. }
  173. private:
  174. // only if collinear (same_dirs)
  175. static inline operation_type union_or_blocked_same_dirs(int arrival, bool is_last)
  176. {
  177. if ( arrival == 1 )
  178. return operation_blocked;
  179. else if ( arrival == -1 )
  180. return operation_union;
  181. else
  182. return is_last ? operation_blocked : operation_union;
  183. //return operation_blocked;
  184. }
  185. // only if not collinear (!same_dirs)
  186. static inline operation_type union_or_blocked_different_dirs(int arrival, bool is_last)
  187. {
  188. if ( arrival == 1 )
  189. //return operation_blocked;
  190. return is_last ? operation_blocked : operation_union;
  191. else
  192. return operation_union;
  193. }
  194. ip_info ips[2];
  195. };
  196. template <bool EnableFirst, bool EnableLast>
  197. struct get_turn_info_for_endpoint
  198. {
  199. typedef std::pair<operation_type, operation_type> operations_pair;
  200. BOOST_STATIC_ASSERT(EnableFirst || EnableLast);
  201. template<typename UniqueSubRange1,
  202. typename UniqueSubRange2,
  203. typename TurnInfo,
  204. typename IntersectionInfo,
  205. typename OutputIterator,
  206. typename EqPPStrategy
  207. >
  208. static inline bool apply(UniqueSubRange1 const& range_p,
  209. UniqueSubRange2 const& range_q,
  210. TurnInfo const& tp_model,
  211. IntersectionInfo const& inters,
  212. method_type /*method*/,
  213. OutputIterator out,
  214. EqPPStrategy const& strategy)
  215. {
  216. std::size_t ip_count = inters.i_info().count;
  217. // no intersection points
  218. if (ip_count == 0)
  219. {
  220. return false;
  221. }
  222. if (! range_p.is_first_segment()
  223. && ! range_q.is_first_segment()
  224. && ! range_p.is_last_segment()
  225. && ! range_q.is_last_segment())
  226. {
  227. // Not an end-point from segment p or q
  228. return false;
  229. }
  230. linear_intersections intersections(range_p.at(0),
  231. range_q.at(0),
  232. inters.result(),
  233. range_p.is_last_segment(),
  234. range_q.is_last_segment(),
  235. strategy);
  236. bool append0_last
  237. = analyse_segment_and_assign_ip(range_p, range_q,
  238. intersections.template get<0>(),
  239. tp_model, inters, 0, out);
  240. // NOTE: opposite && ip_count == 1 may be true!
  241. bool opposite = inters.d_info().opposite;
  242. // don't ignore only for collinear opposite
  243. bool result_ignore_ip0 = append0_last && ( ip_count == 1 || !opposite );
  244. if ( intersections.template get<1>().p_operation == operation_none )
  245. return result_ignore_ip0;
  246. bool append1_last
  247. = analyse_segment_and_assign_ip(range_p, range_q,
  248. intersections.template get<1>(),
  249. tp_model, inters, 1, out);
  250. // don't ignore only for collinear opposite
  251. bool result_ignore_ip1 = append1_last && !opposite /*&& ip_count == 2*/;
  252. return result_ignore_ip0 || result_ignore_ip1;
  253. }
  254. template <typename UniqueSubRange1,
  255. typename UniqueSubRange2,
  256. typename TurnInfo,
  257. typename IntersectionInfo,
  258. typename OutputIterator>
  259. static inline
  260. bool analyse_segment_and_assign_ip(UniqueSubRange1 const& range_p,
  261. UniqueSubRange2 const& range_q,
  262. linear_intersections::ip_info const& ip_info,
  263. TurnInfo const& tp_model,
  264. IntersectionInfo const& inters,
  265. unsigned int ip_index,
  266. OutputIterator out)
  267. {
  268. // TODO - calculate first/last only if needed
  269. bool is_p_first_ip = range_p.is_first_segment() && ip_info.is_pi;
  270. bool is_p_last_ip = range_p.is_last_segment() && ip_info.is_pj;
  271. bool is_q_first_ip = range_q.is_first_segment() && ip_info.is_qi;
  272. bool is_q_last_ip = range_q.is_last_segment() && ip_info.is_qj;
  273. bool append_first = EnableFirst && (is_p_first_ip || is_q_first_ip);
  274. bool append_last = EnableLast && (is_p_last_ip || is_q_last_ip);
  275. operation_type p_operation = ip_info.p_operation;
  276. operation_type q_operation = ip_info.q_operation;
  277. if ( append_first || append_last )
  278. {
  279. bool handled = handle_internal<0>(range_p, range_q,
  280. is_p_first_ip, is_p_last_ip,
  281. is_q_first_ip, is_q_last_ip,
  282. ip_info.is_qi, ip_info.is_qj,
  283. tp_model, inters, ip_index,
  284. p_operation, q_operation);
  285. if ( !handled )
  286. {
  287. // Reverse p/q
  288. handle_internal<1>(range_q, range_p,
  289. is_q_first_ip, is_q_last_ip,
  290. is_p_first_ip, is_p_last_ip,
  291. ip_info.is_pi, ip_info.is_pj,
  292. tp_model, inters, ip_index,
  293. q_operation, p_operation);
  294. }
  295. if ( p_operation != operation_none )
  296. {
  297. method_type method = endpoint_ip_method(ip_info.is_pi, ip_info.is_pj,
  298. ip_info.is_qi, ip_info.is_qj);
  299. turn_position p_pos = ip_position(is_p_first_ip, is_p_last_ip);
  300. turn_position q_pos = ip_position(is_q_first_ip, is_q_last_ip);
  301. // handle spikes
  302. // P is spike and should be handled
  303. if (ip_info.is_pj // this check is redundant (also in is_spike_p) but faster
  304. && inters.i_info().count == 2
  305. && inters.is_spike_p() )
  306. {
  307. assign(inters.result(), ip_index, method, operation_blocked, q_operation,
  308. p_pos, q_pos, is_p_first_ip, is_q_first_ip, true, false, tp_model, out);
  309. assign(inters.result(), ip_index, method, operation_intersection, q_operation,
  310. p_pos, q_pos, is_p_first_ip, is_q_first_ip, true, false, tp_model, out);
  311. }
  312. // Q is spike and should be handled
  313. else if (ip_info.is_qj // this check is redundant (also in is_spike_q) but faster
  314. && inters.i_info().count == 2
  315. && inters.is_spike_q() )
  316. {
  317. assign(inters.result(), ip_index, method, p_operation, operation_blocked,
  318. p_pos, q_pos, is_p_first_ip, is_q_first_ip, false, true, tp_model, out);
  319. assign(inters.result(), ip_index, method, p_operation, operation_intersection,
  320. p_pos, q_pos, is_p_first_ip, is_q_first_ip, false, true, tp_model, out);
  321. }
  322. // no spikes
  323. else
  324. {
  325. assign(inters.result(), ip_index, method, p_operation, q_operation,
  326. p_pos, q_pos, is_p_first_ip, is_q_first_ip, false, false, tp_model, out);
  327. }
  328. }
  329. }
  330. return append_last;
  331. }
  332. // TODO: IT'S ALSO PROBABLE THAT ALL THIS FUNCTION COULD BE INTEGRATED WITH handle_segment
  333. // however now it's lazily calculated and then it would be always calculated
  334. template<std::size_t G1Index,
  335. typename UniqueRange1,
  336. typename UniqueRange2,
  337. typename TurnInfo,
  338. typename IntersectionInfo
  339. >
  340. static inline bool handle_internal(UniqueRange1 const& range1,
  341. UniqueRange2 const& range2,
  342. bool first1, bool last1, bool first2, bool last2,
  343. bool ip_i2, bool ip_j2, TurnInfo const& tp_model,
  344. IntersectionInfo const& inters, unsigned int ip_index,
  345. operation_type & op1, operation_type & op2)
  346. {
  347. boost::ignore_unused(ip_index, tp_model);
  348. typename IntersectionInfo::side_strategy_type const& sides
  349. = inters.get_side_strategy();
  350. if ( !first2 && !last2 )
  351. {
  352. if ( first1 )
  353. {
  354. #ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR
  355. // may this give false positives for INTs?
  356. typename IntersectionResult::point_type const&
  357. inters_pt = inters.i_info().intersections[ip_index];
  358. BOOST_GEOMETRY_ASSERT(ip_i2 == equals::equals_point_point(i2, inters_pt));
  359. BOOST_GEOMETRY_ASSERT(ip_j2 == equals::equals_point_point(j2, inters_pt));
  360. #endif
  361. if ( ip_i2 )
  362. {
  363. // don't output this IP - for the first point of other geometry segment
  364. op1 = operation_none;
  365. op2 = operation_none;
  366. return true;
  367. }
  368. else if ( ip_j2 )
  369. {
  370. int const side_pj_q2 = sides.apply(range2.at(1), range2.at(2), range1.at(1));
  371. int const side_pj_q1 = sides.apply(range2.at(0), range2.at(1), range1.at(1));
  372. int const side_qk_q1 = sides.apply(range2.at(0), range2.at(1), range2.at(2));
  373. operations_pair operations = operations_of_equal(side_pj_q2, side_pj_q1, side_qk_q1);
  374. // TODO: must the above be calculated?
  375. // wouldn't it be enough to check if segments are collinear?
  376. if ( operations_both(operations, operation_continue) )
  377. {
  378. if ( op1 != operation_union
  379. || op2 != operation_union
  380. || ! ( G1Index == 0 ? inters.is_spike_q() : inters.is_spike_p() ) )
  381. {
  382. // THIS IS WRT THE ORIGINAL SEGMENTS! NOT THE ONES ABOVE!
  383. bool opposite = inters.d_info().opposite;
  384. op1 = operation_intersection;
  385. op2 = opposite ? operation_union : operation_intersection;
  386. }
  387. }
  388. else
  389. {
  390. BOOST_GEOMETRY_ASSERT(operations_combination(operations, operation_intersection, operation_union));
  391. //op1 = operation_union;
  392. //op2 = operation_union;
  393. }
  394. return true;
  395. }
  396. // else do nothing - shouldn't be handled this way
  397. }
  398. else if ( last1 )
  399. {
  400. #ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR
  401. // may this give false positives for INTs?
  402. typename IntersectionResult::point_type const&
  403. inters_pt = inters.i_info().intersections[ip_index];
  404. BOOST_GEOMETRY_ASSERT(ip_i2 == equals::equals_point_point(i2, inters_pt));
  405. BOOST_GEOMETRY_ASSERT(ip_j2 == equals::equals_point_point(j2, inters_pt));
  406. #endif
  407. if ( ip_i2 )
  408. {
  409. // don't output this IP - for the first point of other geometry segment
  410. op1 = operation_none;
  411. op2 = operation_none;
  412. return true;
  413. }
  414. else if ( ip_j2 )
  415. {
  416. int const side_pi_q2 = sides.apply(range2.at(1), range2.at(2), range1.at(0));
  417. int const side_pi_q1 = sides.apply(range2.at(0), range2.at(1), range1.at(0));
  418. int const side_qk_q1 = sides.apply(range2.at(0), range2.at(1), range2.at(2));
  419. operations_pair operations = operations_of_equal(side_pi_q2, side_pi_q1, side_qk_q1);
  420. // TODO: must the above be calculated?
  421. // wouldn't it be enough to check if segments are collinear?
  422. if ( operations_both(operations, operation_continue) )
  423. {
  424. if ( op1 != operation_blocked
  425. || op2 != operation_union
  426. || ! ( G1Index == 0 ? inters.is_spike_q() : inters.is_spike_p() ) )
  427. {
  428. // THIS IS WRT THE ORIGINAL SEGMENTS! NOT THE ONES ABOVE!
  429. bool second_going_out = inters.i_info().count > 1;
  430. op1 = operation_blocked;
  431. op2 = second_going_out ? operation_union : operation_intersection;
  432. }
  433. }
  434. else
  435. {
  436. BOOST_GEOMETRY_ASSERT(operations_combination(operations, operation_intersection, operation_union));
  437. //op1 = operation_blocked;
  438. //op2 = operation_union;
  439. }
  440. return true;
  441. }
  442. // else do nothing - shouldn't be handled this way
  443. }
  444. // else do nothing - shouldn't be handled this way
  445. }
  446. return false;
  447. }
  448. static inline method_type endpoint_ip_method(bool ip_pi, bool ip_pj, bool ip_qi, bool ip_qj)
  449. {
  450. if ( (ip_pi || ip_pj) && (ip_qi || ip_qj) )
  451. return method_touch;
  452. else
  453. return method_touch_interior;
  454. }
  455. static inline turn_position ip_position(bool is_ip_first_i, bool is_ip_last_j)
  456. {
  457. return is_ip_first_i ? position_front :
  458. ( is_ip_last_j ? position_back : position_middle );
  459. }
  460. template <typename IntersectionResult,
  461. typename TurnInfo,
  462. typename OutputIterator>
  463. static inline void assign(IntersectionResult const& result,
  464. unsigned int ip_index,
  465. method_type method,
  466. operation_type op0, operation_type op1,
  467. turn_position pos0, turn_position pos1,
  468. bool is_p_first_ip, bool is_q_first_ip,
  469. bool is_p_spike, bool is_q_spike,
  470. TurnInfo const& tp_model,
  471. OutputIterator out)
  472. {
  473. TurnInfo tp = tp_model;
  474. //geometry::convert(ip, tp.point);
  475. //tp.method = method;
  476. base_turn_handler::assign_point(tp, method, result.template get<0>(), ip_index);
  477. tp.operations[0].operation = op0;
  478. tp.operations[1].operation = op1;
  479. tp.operations[0].position = pos0;
  480. tp.operations[1].position = pos1;
  481. if ( result.template get<0>().count > 1 )
  482. {
  483. // NOTE: is_collinear is NOT set for the first endpoint
  484. // for which there is no preceding segment
  485. //BOOST_GEOMETRY_ASSERT( result.template get<1>().dir_a == 0 && result.template get<1>().dir_b == 0 );
  486. if ( ! is_p_first_ip )
  487. {
  488. tp.operations[0].is_collinear = op0 != operation_intersection
  489. || is_p_spike;
  490. }
  491. if ( ! is_q_first_ip )
  492. {
  493. tp.operations[1].is_collinear = op1 != operation_intersection
  494. || is_q_spike;
  495. }
  496. }
  497. else //if ( result.template get<0>().count == 1 )
  498. {
  499. if ( op0 == operation_blocked && op1 == operation_intersection )
  500. {
  501. tp.operations[0].is_collinear = true;
  502. }
  503. else if ( op0 == operation_intersection && op1 == operation_blocked )
  504. {
  505. tp.operations[1].is_collinear = true;
  506. }
  507. }
  508. *out++ = tp;
  509. }
  510. static inline operations_pair operations_of_equal(int side_px_q2,
  511. int side_px_q1,
  512. int side_qk_q1)
  513. {
  514. // If px (pi or pj) is collinear with qj-qk (q2), they continue collinearly.
  515. // This can be on either side of q1, or collinear
  516. // The second condition checks if they do not continue
  517. // oppositely
  518. if (side_px_q2 == 0 && side_px_q1 == side_qk_q1)
  519. {
  520. return std::make_pair(operation_continue, operation_continue);
  521. }
  522. // If they turn to same side (not opposite sides)
  523. if ( ! base_turn_handler::opposite(side_px_q1, side_qk_q1) )
  524. {
  525. // If px is left of q2 or collinear: p: union, q: intersection
  526. if (side_px_q2 != -1 )
  527. {
  528. return std::make_pair(operation_union, operation_intersection);
  529. }
  530. else
  531. {
  532. return std::make_pair(operation_intersection, operation_union);
  533. }
  534. }
  535. else
  536. {
  537. // They turn opposite sides. If p turns left (or collinear),
  538. // p: union, q: intersection
  539. if (side_px_q1 != -1 )
  540. {
  541. return std::make_pair(operation_union, operation_intersection);
  542. }
  543. else
  544. {
  545. return std::make_pair(operation_intersection, operation_union);
  546. }
  547. }
  548. }
  549. static inline bool operations_both(operations_pair const& operations,
  550. operation_type const op)
  551. {
  552. return operations.first == op && operations.second == op;
  553. }
  554. static inline bool operations_combination(operations_pair const& operations,
  555. operation_type const op1,
  556. operation_type const op2)
  557. {
  558. return ( operations.first == op1 && operations.second == op2 )
  559. || ( operations.first == op2 && operations.second == op1 );
  560. }
  561. };
  562. }} // namespace detail::overlay
  563. #endif // DOXYGEN_NO_DETAIL
  564. }} // namespace boost::geometry
  565. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_FOR_ENDPOINT_HPP