get_turn_info.hpp 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589
  1. // Boost.Geometry
  2. // Copyright (c) 2007-2023 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2017-2023 Adam Wulkiewicz, Lodz, Poland.
  4. // This file was modified by Oracle on 2015-2022.
  5. // Modifications copyright (c) 2015-2022 Oracle and/or its affiliates.
  6. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  7. // Use, modification and distribution is subject to the Boost Software License,
  8. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HPP
  11. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HPP
  12. #include <boost/core/ignore_unused.hpp>
  13. #include <boost/throw_exception.hpp>
  14. #include <boost/geometry/core/access.hpp>
  15. #include <boost/geometry/core/assert.hpp>
  16. #include <boost/geometry/core/config.hpp>
  17. #include <boost/geometry/core/exception.hpp>
  18. #include <boost/geometry/algorithms/convert.hpp>
  19. #include <boost/geometry/algorithms/detail/overlay/get_distance_measure.hpp>
  20. #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
  21. #include <boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp>
  22. #include <boost/geometry/util/constexpr.hpp>
  23. namespace boost { namespace geometry
  24. {
  25. #if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
  26. class turn_info_exception : public geometry::exception
  27. {
  28. std::string message;
  29. public:
  30. // NOTE: "char" will be replaced by enum in future version
  31. inline turn_info_exception(char const method)
  32. {
  33. message = "Boost.Geometry Turn exception: ";
  34. message += method;
  35. }
  36. virtual char const* What() const noexcept
  37. {
  38. return message.c_str();
  39. }
  40. };
  41. #endif
  42. #ifndef DOXYGEN_NO_DETAIL
  43. namespace detail { namespace overlay
  44. {
  45. struct policy_verify_nothing
  46. {
  47. static bool const use_side_verification = false;
  48. static bool const use_start_turn = false;
  49. static bool const use_handle_as_touch = false;
  50. static bool const use_handle_as_equal = false;
  51. static bool const use_handle_imperfect_touch = false;
  52. };
  53. struct policy_verify_all
  54. {
  55. static bool const use_side_verification = true;
  56. static bool const use_start_turn = true;
  57. static bool const use_handle_as_touch = true;
  58. static bool const use_handle_as_equal = true;
  59. static bool const use_handle_imperfect_touch = true;
  60. };
  61. #if defined(BOOST_GEOMETRY_USE_RESCALING)
  62. using verify_policy_aa = policy_verify_nothing;
  63. #else
  64. using verify_policy_aa = policy_verify_all;
  65. #endif
  66. using verify_policy_ll = policy_verify_nothing;
  67. using verify_policy_la = policy_verify_nothing;
  68. struct base_turn_handler
  69. {
  70. // Returns true if both sides are opposite
  71. static inline bool opposite(int side1, int side2)
  72. {
  73. // We cannot state side1 == -side2, because 0 == -0
  74. // So either side1*side2==-1 or side1==-side2 && side1 != 0
  75. return side1 * side2 == -1;
  76. }
  77. // Same side of a segment (not being 0)
  78. static inline bool same(int side1, int side2)
  79. {
  80. return side1 * side2 == 1;
  81. }
  82. // Both get the same operation
  83. template <typename TurnInfo>
  84. static inline void both(TurnInfo& ti, operation_type const op)
  85. {
  86. ti.operations[0].operation = op;
  87. ti.operations[1].operation = op;
  88. }
  89. // If condition, first union/second intersection, else vice versa
  90. template <typename TurnInfo>
  91. static inline void ui_else_iu(bool condition, TurnInfo& ti)
  92. {
  93. ti.operations[0].operation = condition
  94. ? operation_union : operation_intersection;
  95. ti.operations[1].operation = condition
  96. ? operation_intersection : operation_union;
  97. }
  98. // If condition, both union, else both intersection
  99. template <typename TurnInfo>
  100. static inline void uu_else_ii(bool condition, TurnInfo& ti)
  101. {
  102. both(ti, condition ? operation_union : operation_intersection);
  103. }
  104. template <typename TurnInfo, typename IntersectionInfo>
  105. static inline void assign_point(TurnInfo& ti,
  106. method_type method,
  107. IntersectionInfo const& info, unsigned int index)
  108. {
  109. ti.method = method;
  110. BOOST_GEOMETRY_ASSERT(index < info.count);
  111. geometry::convert(info.intersections[index], ti.point);
  112. ti.operations[0].fraction = info.fractions[index].robust_ra;
  113. ti.operations[1].fraction = info.fractions[index].robust_rb;
  114. }
  115. template <typename TurnInfo, typename IntersectionInfo, typename DirInfo>
  116. static inline void assign_point_and_correct(TurnInfo& ti,
  117. method_type method,
  118. IntersectionInfo const& info, DirInfo const& dir_info)
  119. {
  120. ti.method = method;
  121. // For touch/touch interior always take the intersection point 0
  122. // (usually there is only one - but if collinear is handled as touch, both could be taken).
  123. static int const index = 0;
  124. geometry::convert(info.intersections[index], ti.point);
  125. for (int i = 0; i < 2; i++)
  126. {
  127. if (dir_info.arrival[i] == 1)
  128. {
  129. // The segment arrives at the intersection point, its fraction should be 1
  130. // (due to precision it might be nearly so, but not completely, in rare cases)
  131. ti.operations[i].fraction = {1, 1};
  132. }
  133. else if (dir_info.arrival[i] == -1)
  134. {
  135. // The segment leaves from the intersection point, likewise its fraction should be 0
  136. ti.operations[i].fraction = {0, 1};
  137. }
  138. else
  139. {
  140. ti.operations[i].fraction = i == 0 ? info.fractions[index].robust_ra
  141. : info.fractions[index].robust_rb;
  142. }
  143. }
  144. }
  145. template <typename IntersectionInfo>
  146. static inline unsigned int non_opposite_to_index(IntersectionInfo const& info)
  147. {
  148. return info.fractions[0].robust_rb < info.fractions[1].robust_rb
  149. ? 1 : 0;
  150. }
  151. };
  152. template<typename VerifyPolicy>
  153. struct turn_info_verification_functions
  154. {
  155. template <typename Point1, typename Point2>
  156. static inline
  157. typename select_coordinate_type<Point1, Point2>::type
  158. distance_measure(Point1 const& a, Point2 const& b)
  159. {
  160. // TODO: revise this using comparable distance for various
  161. // coordinate systems
  162. using coor_t = typename select_coordinate_type<Point1, Point2>::type;
  163. coor_t const dx = get<0>(a) - get<0>(b);
  164. coor_t const dy = get<1>(a) - get<1>(b);
  165. return dx * dx + dy * dy;
  166. }
  167. template
  168. <
  169. std::size_t IndexP,
  170. std::size_t IndexQ,
  171. typename UniqueSubRange1,
  172. typename UniqueSubRange2,
  173. typename UmbrellaStrategy,
  174. typename TurnInfo
  175. >
  176. static inline void set_both_verified(
  177. UniqueSubRange1 const& range_p,
  178. UniqueSubRange2 const& range_q,
  179. UmbrellaStrategy const& umbrella_strategy,
  180. std::size_t index_p, std::size_t index_q,
  181. TurnInfo& ti)
  182. {
  183. BOOST_GEOMETRY_ASSERT(IndexP + IndexQ == 1);
  184. BOOST_GEOMETRY_ASSERT(index_p > 0 && index_p <= 2);
  185. BOOST_GEOMETRY_ASSERT(index_q > 0 && index_q <= 2);
  186. using distance_measure_result_type = typename geometry::coordinate_type<decltype(ti.point)>::type;
  187. bool const p_in_range = index_p < range_p.size();
  188. bool const q_in_range = index_q < range_q.size();
  189. ti.operations[IndexP].remaining_distance
  190. = p_in_range
  191. ? distance_measure(ti.point, range_p.at(index_p))
  192. : distance_measure_result_type{0};
  193. ti.operations[IndexQ].remaining_distance
  194. = q_in_range
  195. ? distance_measure(ti.point, range_q.at(index_q))
  196. : distance_measure_result_type{0};
  197. if (p_in_range && q_in_range)
  198. {
  199. // pk/q2 is considered as collinear, but there might be
  200. // a tiny measurable difference. If so, use that.
  201. // Calculate pk // qj-qk
  202. bool const p_closer
  203. = ti.operations[IndexP].remaining_distance
  204. < ti.operations[IndexQ].remaining_distance;
  205. auto const dm
  206. = p_closer
  207. ? get_distance_measure(range_q.at(index_q - 1),
  208. range_q.at(index_q), range_p.at(index_p),
  209. umbrella_strategy)
  210. : get_distance_measure(range_p.at(index_p - 1),
  211. range_p.at(index_p), range_q.at(index_q),
  212. umbrella_strategy);
  213. if (! dm.is_zero())
  214. {
  215. // Not truely collinear, distinguish for union/intersection
  216. // If p goes left (positive), take that for a union
  217. bool const p_left
  218. = p_closer ? dm.is_positive() : dm.is_negative();
  219. ti.operations[IndexP].operation = p_left
  220. ? operation_union : operation_intersection;
  221. ti.operations[IndexQ].operation = p_left
  222. ? operation_intersection : operation_union;
  223. return;
  224. }
  225. }
  226. base_turn_handler::both(ti, operation_continue);
  227. }
  228. template
  229. <
  230. std::size_t IndexP,
  231. std::size_t IndexQ,
  232. typename UniqueSubRange1,
  233. typename UniqueSubRange2,
  234. typename UmbrellaStrategy,
  235. typename TurnInfo
  236. >
  237. static inline void both_collinear(
  238. UniqueSubRange1 const& range_p,
  239. UniqueSubRange2 const& range_q,
  240. UmbrellaStrategy const& umbrella_strategy,
  241. std::size_t index_p, std::size_t index_q,
  242. TurnInfo& ti)
  243. {
  244. if BOOST_GEOMETRY_CONSTEXPR (VerifyPolicy::use_side_verification)
  245. {
  246. set_both_verified<IndexP, IndexQ>(range_p, range_q, umbrella_strategy,
  247. index_p, index_q, ti);
  248. }
  249. else
  250. {
  251. base_turn_handler::both(ti, operation_continue);
  252. }
  253. }
  254. template
  255. <
  256. typename UniqueSubRange1,
  257. typename UniqueSubRange2,
  258. typename UmbrellaStrategy
  259. >
  260. static inline int verified_side(int side,
  261. UniqueSubRange1 const& range_p,
  262. UniqueSubRange2 const& range_q,
  263. UmbrellaStrategy const& umbrella_strategy,
  264. int index_p, int index_q)
  265. {
  266. if BOOST_GEOMETRY_CONSTEXPR (VerifyPolicy::use_side_verification)
  267. {
  268. if (side == 0)
  269. {
  270. if (index_p >= 1 && range_p.is_last_segment())
  271. {
  272. return 0;
  273. }
  274. if (index_q >= 2 && range_q.is_last_segment())
  275. {
  276. return 0;
  277. }
  278. auto const dm = get_distance_measure(range_p.at(index_p),
  279. range_p.at(index_p + 1),
  280. range_q.at(index_q),
  281. umbrella_strategy);
  282. static decltype(dm.measure) const zero = 0;
  283. return dm.measure == zero ? 0 : dm.measure > zero ? 1 : -1;
  284. }
  285. }
  286. return side;
  287. }
  288. };
  289. template
  290. <
  291. typename TurnInfo,
  292. typename VerifyPolicy
  293. >
  294. struct touch_interior : public base_turn_handler
  295. {
  296. using fun = turn_info_verification_functions<VerifyPolicy>;
  297. template
  298. <
  299. typename IntersectionInfo,
  300. typename UniqueSubRange
  301. >
  302. static bool handle_as_touch(IntersectionInfo const& info,
  303. UniqueSubRange const& non_touching_range)
  304. {
  305. if BOOST_GEOMETRY_CONSTEXPR (! VerifyPolicy::use_handle_as_touch)
  306. {
  307. return false;
  308. }
  309. else // else prevents unreachable code warning
  310. {
  311. //
  312. //
  313. // ^ Q(i) ^ P(i)
  314. // \ /
  315. // \ /
  316. // \ /
  317. // \ /
  318. // \ /
  319. // \ /
  320. // \ /
  321. // \ /
  322. // \ /
  323. // \ / it is about buffer_rt_r
  324. // P(k) v/ they touch here "in the middle", but at the intersection...
  325. // <---------------->v there is no follow up IP
  326. // /
  327. // /
  328. // /
  329. // /
  330. // /
  331. // /
  332. // v Q(k)
  333. //
  334. // Measure where the IP is located. If it is really close to the end,
  335. // then there is no space for the next IP (on P(1)/Q(2). A "from"
  336. // intersection will be generated, but those are never handled.
  337. // Therefore handle it as a normal touch (two segments arrive at the
  338. // intersection point). It currently checks for zero, but even a
  339. // distance a little bit larger would do.
  340. auto const dm = fun::distance_measure(info.intersections[0], non_touching_range.at(1));
  341. decltype(dm) const zero = 0;
  342. bool const result = math::equals(dm, zero);
  343. return result;
  344. }
  345. }
  346. // Index: 0, P is the interior, Q is touching and vice versa
  347. template
  348. <
  349. unsigned int Index,
  350. typename UniqueSubRange1,
  351. typename UniqueSubRange2,
  352. typename IntersectionInfo,
  353. typename DirInfo,
  354. typename SidePolicy,
  355. typename UmbrellaStrategy
  356. >
  357. static inline void apply(UniqueSubRange1 const& range_p,
  358. UniqueSubRange2 const& range_q,
  359. TurnInfo& ti,
  360. IntersectionInfo const& intersection_info,
  361. DirInfo const& dir_info,
  362. SidePolicy const& side,
  363. UmbrellaStrategy const& umbrella_strategy)
  364. {
  365. assign_point_and_correct(ti, method_touch_interior, intersection_info, dir_info);
  366. // Both segments of q touch segment p somewhere in its interior
  367. // 1) We know: if q comes from LEFT or RIGHT
  368. // (i.e. dir_info.sides.get<Index,0>() == 1 or -1)
  369. // 2) Important is: if q_k goes to LEFT, RIGHT, COLLINEAR
  370. // and, if LEFT/COLL, if it is lying LEFT or RIGHT w.r.t. q_i
  371. BOOST_STATIC_ASSERT(Index <= 1);
  372. static unsigned int const index_p = Index;
  373. static unsigned int const index_q = 1 - Index;
  374. bool const has_pk = ! range_p.is_last_segment();
  375. bool const has_qk = ! range_q.is_last_segment();
  376. int const side_qi_p = dir_info.sides.template get<index_q, 0>();
  377. int const side_qk_p = has_qk ? side.qk_wrt_p1() : 0;
  378. if (side_qi_p == -side_qk_p)
  379. {
  380. // Q crosses P from left->right or from right->left (test "ML1")
  381. // Union: folow P (left->right) or Q (right->left)
  382. // Intersection: other turn
  383. unsigned int index = side_qk_p == -1 ? index_p : index_q;
  384. ti.operations[index].operation = operation_union;
  385. ti.operations[1 - index].operation = operation_intersection;
  386. return;
  387. }
  388. int const side_qk_q = has_qk ? side.qk_wrt_q1() : 0;
  389. // Only necessary if rescaling is turned off:
  390. int const side_pj_q2 = has_qk ? side.pj_wrt_q2() : 0;
  391. if (side_qi_p == -1 && side_qk_p == -1 && side_qk_q == 1)
  392. {
  393. // Q turns left on the right side of P (test "MR3")
  394. // Both directions for "intersection"
  395. both(ti, operation_intersection);
  396. ti.touch_only = true;
  397. }
  398. else if (side_qi_p == 1 && side_qk_p == 1 && side_qk_q == -1)
  399. {
  400. if (has_qk && side_pj_q2 == -1)
  401. {
  402. // Q turns right on the left side of P (test "ML3")
  403. // Union: take both operations
  404. // Intersection: skip
  405. both(ti, operation_union);
  406. }
  407. else
  408. {
  409. // q2 is collinear with p1, so it does not turn back. This
  410. // can happen in floating point precision. In this case,
  411. // block one of the operations to avoid taking that path.
  412. ti.operations[index_p].operation = operation_union;
  413. ti.operations[index_q].operation = operation_blocked;
  414. }
  415. ti.touch_only = true;
  416. }
  417. else if (side_qi_p == side_qk_p && side_qi_p == side_qk_q)
  418. {
  419. // Q turns left on the left side of P (test "ML2")
  420. // or Q turns right on the right side of P (test "MR2")
  421. // Union: take left turn (Q if Q turns left, P if Q turns right)
  422. // Intersection: other turn
  423. unsigned int index = side_qk_q == 1 ? index_q : index_p;
  424. if (has_qk && side_pj_q2 == 0)
  425. {
  426. // Even though sides xk w.r.t. 1 are distinct, pj is collinear
  427. // with q. Therefore swap the path
  428. index = 1 - index;
  429. }
  430. if (has_pk && has_qk && opposite(side_pj_q2, side_qi_p))
  431. {
  432. // Without rescaling, floating point requires extra measures
  433. int const side_qj_p1 = side.qj_wrt_p1();
  434. int const side_qj_p2 = side.qj_wrt_p2();
  435. if (same(side_qj_p1, side_qj_p2))
  436. {
  437. int const side_pj_q1 = side.pj_wrt_q1();
  438. if (opposite(side_pj_q1, side_pj_q2))
  439. {
  440. index = 1 - index;
  441. }
  442. }
  443. }
  444. ti.operations[index].operation = operation_union;
  445. ti.operations[1 - index].operation = operation_intersection;
  446. ti.touch_only = true;
  447. }
  448. else if (side_qk_p == 0)
  449. {
  450. // Q intersects on interior of P and continues collinearly
  451. if (side_qk_q == side_qi_p)
  452. {
  453. fun::template both_collinear<index_p, index_q>(range_p, range_q, umbrella_strategy,
  454. 1, 2, ti);
  455. }
  456. else
  457. {
  458. // Opposite direction, which is never travelled.
  459. // If Q turns left, P continues for intersection
  460. // If Q turns right, P continues for union
  461. ti.operations[index_p].operation = side_qk_q == 1
  462. ? operation_intersection
  463. : operation_union;
  464. ti.operations[index_q].operation = operation_blocked;
  465. }
  466. }
  467. else
  468. {
  469. // Should not occur!
  470. ti.method = method_error;
  471. }
  472. }
  473. };
  474. template
  475. <
  476. typename TurnInfo,
  477. typename VerifyPolicy
  478. >
  479. struct touch : public base_turn_handler
  480. {
  481. using fun = turn_info_verification_functions<VerifyPolicy>;
  482. static inline bool between(int side1, int side2, int turn)
  483. {
  484. return side1 == side2 && ! opposite(side1, turn);
  485. }
  486. template
  487. <
  488. typename UniqueSubRange1,
  489. typename UniqueSubRange2,
  490. typename UmbrellaStrategy
  491. >
  492. static inline bool handle_imperfect_touch(UniqueSubRange1 const& range_p,
  493. UniqueSubRange2 const& range_q,
  494. int side_pk_q2,
  495. UmbrellaStrategy const& umbrella_strategy,
  496. TurnInfo& ti)
  497. {
  498. if BOOST_GEOMETRY_CONSTEXPR (! VerifyPolicy::use_handle_imperfect_touch)
  499. {
  500. return false;
  501. }
  502. else // else prevents unreachable code warning
  503. {
  504. // Q
  505. // ^
  506. // ||
  507. // ||
  508. // |^----
  509. // >----->P
  510. // * * they touch here (P/Q are (nearly) on top)
  511. //
  512. // Q continues from where P comes.
  513. // P continues from where Q comes
  514. // This is often a blocking situation,
  515. // unless there are FP issues: there might be a distance
  516. // between Pj and Qj, in that case handle it as a union.
  517. //
  518. // Exaggerated:
  519. // Q
  520. // ^ Q is nearly vertical
  521. // \ but not completely - and still ends above P
  522. // | \qj In this case it should block P and
  523. // | ^------ set Q to Union
  524. // >----->P qj is LEFT of P1 and pi is LEFT of Q2
  525. // (the other way round is also possible)
  526. auto has_distance = [&](auto const& r1, auto const& r2) -> bool
  527. {
  528. auto const d1 = get_distance_measure(r1.at(0), r1.at(1), r2.at(1), umbrella_strategy);
  529. auto const d2 = get_distance_measure(r2.at(1), r2.at(2), r1.at(0), umbrella_strategy);
  530. return d1.measure > 0 && d2.measure > 0;
  531. };
  532. if (side_pk_q2 == -1 && has_distance(range_p, range_q))
  533. {
  534. // Even though there is a touch, Q(j) is left of P1
  535. // and P(i) is still left from Q2.
  536. // Q continues to the right.
  537. // It can continue.
  538. ti.operations[0].operation = operation_blocked;
  539. // Q turns right -> union (both independent),
  540. // Q turns left -> intersection
  541. ti.operations[1].operation = operation_union;
  542. ti.touch_only = true;
  543. return true;
  544. }
  545. if (side_pk_q2 == 1 && has_distance(range_q, range_p))
  546. {
  547. // Similarly, but the other way round.
  548. // Q continues to the left.
  549. ti.operations[0].operation = operation_union;
  550. ti.operations[1].operation = operation_blocked;
  551. ti.touch_only = true;
  552. return true;
  553. }
  554. return false;
  555. }
  556. }
  557. template
  558. <
  559. typename UniqueSubRange1,
  560. typename UniqueSubRange2,
  561. typename IntersectionInfo,
  562. typename DirInfo,
  563. typename SideCalculator,
  564. typename UmbrellaStrategy
  565. >
  566. static inline void apply(UniqueSubRange1 const& range_p,
  567. UniqueSubRange2 const& range_q,
  568. TurnInfo& ti,
  569. IntersectionInfo const& intersection_info,
  570. DirInfo const& dir_info,
  571. SideCalculator const& side,
  572. UmbrellaStrategy const& umbrella_strategy)
  573. {
  574. assign_point_and_correct(ti, method_touch, intersection_info, dir_info);
  575. bool const has_pk = ! range_p.is_last_segment();
  576. bool const has_qk = ! range_q.is_last_segment();
  577. int const side_pk_q1 = has_pk ? side.pk_wrt_q1() : 0;
  578. int const side_qi_p1 = fun::verified_side(dir_info.sides.template get<1, 0>(),
  579. range_p, range_q, umbrella_strategy, 0, 0);
  580. int const side_qk_p1 = has_qk
  581. ? fun::verified_side(side.qk_wrt_p1(), range_p, range_q,
  582. umbrella_strategy, 0, 2)
  583. : 0;
  584. // If Qi and Qk are both at same side of Pi-Pj,
  585. // or collinear (so: not opposite sides)
  586. if (! opposite(side_qi_p1, side_qk_p1))
  587. {
  588. int const side_pk_q2 = has_pk && has_qk ? side.pk_wrt_q2() : 0;
  589. int const side_pk_p = has_pk ? side.pk_wrt_p1() : 0;
  590. int const side_qk_q = has_qk ? side.qk_wrt_q1() : 0;
  591. bool const q_turns_left = side_qk_q == 1;
  592. bool const block_q = side_qk_p1 == 0
  593. && ! same(side_qi_p1, side_qk_q)
  594. ;
  595. // If Pk at same side as Qi/Qk
  596. // (the "or" is for collinear case)
  597. // or Q is fully collinear && P turns not to left
  598. if (side_pk_p == side_qi_p1
  599. || side_pk_p == side_qk_p1
  600. || (side_qi_p1 == 0 && side_qk_p1 == 0 && side_pk_p != -1))
  601. {
  602. if (side_qk_p1 == 0 && side_pk_q1 == 0
  603. && has_pk && has_qk
  604. && handle_imperfect_touch(range_p, range_q, side_pk_q2, umbrella_strategy, ti))
  605. {
  606. // If q continues collinearly (opposite) with p, it should be blocked
  607. // but (FP) not if there is just a tiny space in between
  608. return;
  609. }
  610. // Collinear -> lines join, continue
  611. // (#BRL2)
  612. if (side_pk_q2 == 0 && ! block_q)
  613. {
  614. fun::template both_collinear<0, 1>(range_p, range_q, umbrella_strategy,
  615. 2, 2, ti);
  616. return;
  617. }
  618. // Collinear opposite case -> block P
  619. // (#BRL4, #BLR8)
  620. if (side_pk_q1 == 0)
  621. {
  622. ti.operations[0].operation = operation_blocked;
  623. // Q turns right -> union (both independent),
  624. // Q turns left -> intersection
  625. ti.operations[1].operation = block_q ? operation_blocked
  626. : q_turns_left ? operation_intersection
  627. : operation_union;
  628. return;
  629. }
  630. // Pk between Qi and Qk
  631. // (#BRL3, #BRL7)
  632. if (between(side_pk_q1, side_pk_q2, side_qk_q))
  633. {
  634. ui_else_iu(q_turns_left, ti);
  635. if (block_q)
  636. {
  637. ti.operations[1].operation = operation_blocked;
  638. }
  639. return;
  640. }
  641. // Pk between Qk and P, so left of Qk (if Q turns right) and vv
  642. // (#BRL1)
  643. if (side_pk_q2 == -side_qk_q)
  644. {
  645. ui_else_iu(! q_turns_left, ti);
  646. ti.touch_only = true;
  647. return;
  648. }
  649. //
  650. // (#BRL5, #BRL9)
  651. if (side_pk_q1 == -side_qk_q)
  652. {
  653. uu_else_ii(! q_turns_left, ti);
  654. if (block_q)
  655. {
  656. ti.operations[1].operation = operation_blocked;
  657. }
  658. else
  659. {
  660. ti.touch_only = true;
  661. }
  662. return;
  663. }
  664. }
  665. else
  666. {
  667. // Pk at other side than Qi/Pk
  668. ti.operations[0].operation = q_turns_left
  669. ? operation_intersection
  670. : operation_union;
  671. ti.operations[1].operation = block_q
  672. ? operation_blocked
  673. : side_qi_p1 == 1 || side_qk_p1 == 1
  674. ? operation_union
  675. : operation_intersection;
  676. if (! block_q)
  677. {
  678. ti.touch_only = true;
  679. }
  680. return;
  681. }
  682. }
  683. else
  684. {
  685. // The qi/qk are opposite to each other, w.r.t. p1
  686. // From left to right or from right to left
  687. int const side_pk_p = has_pk
  688. ? fun::verified_side(side.pk_wrt_p1(), range_p, range_p,
  689. umbrella_strategy, 0, 2)
  690. : 0;
  691. bool const right_to_left = side_qk_p1 == 1;
  692. // If p turns into direction of qi (1,2)
  693. if (side_pk_p == side_qi_p1)
  694. {
  695. // Collinear opposite case -> block P
  696. if (side_pk_q1 == 0)
  697. {
  698. ti.operations[0].operation = operation_blocked;
  699. ti.operations[1].operation = right_to_left
  700. ? operation_union : operation_intersection;
  701. return;
  702. }
  703. if (side_pk_q1 == side_qk_p1)
  704. {
  705. uu_else_ii(right_to_left, ti);
  706. ti.touch_only = true;
  707. return;
  708. }
  709. }
  710. // If p turns into direction of qk (4,5)
  711. if (side_pk_p == side_qk_p1)
  712. {
  713. int const side_pk_q2 = has_pk ? side.pk_wrt_q2() : 0;
  714. // Collinear case -> lines join, continue
  715. if (side_pk_q2 == 0)
  716. {
  717. both(ti, operation_continue);
  718. return;
  719. }
  720. if (side_pk_q2 == side_qk_p1)
  721. {
  722. ui_else_iu(right_to_left, ti);
  723. ti.touch_only = true;
  724. return;
  725. }
  726. }
  727. // otherwise (3)
  728. ui_else_iu(! right_to_left, ti);
  729. return;
  730. }
  731. }
  732. };
  733. template
  734. <
  735. typename TurnInfo,
  736. typename VerifyPolicy
  737. >
  738. struct equal : public base_turn_handler
  739. {
  740. using fun = turn_info_verification_functions<VerifyPolicy>;
  741. template
  742. <
  743. typename UniqueSubRange1,
  744. typename UniqueSubRange2,
  745. typename IntersectionInfo,
  746. typename DirInfo,
  747. typename SideCalculator,
  748. typename UmbrellaStrategy
  749. >
  750. static inline void apply(UniqueSubRange1 const& range_p,
  751. UniqueSubRange2 const& range_q,
  752. TurnInfo& ti,
  753. IntersectionInfo const& info,
  754. DirInfo const& ,
  755. SideCalculator const& side,
  756. UmbrellaStrategy const& umbrella_strategy)
  757. {
  758. // Copy the intersection point in TO direction
  759. assign_point(ti, method_equal, info, non_opposite_to_index(info));
  760. bool const has_pk = ! range_p.is_last_segment();
  761. bool const has_qk = ! range_q.is_last_segment();
  762. int const side_pk_q2 = has_pk && has_qk ? side.pk_wrt_q2() : 0;
  763. int const side_pk_p = has_pk ? side.pk_wrt_p1() : 0;
  764. int const side_qk_p = has_qk ? side.qk_wrt_p1() : 0;
  765. if (has_pk && has_qk && side_pk_p == side_qk_p)
  766. {
  767. // They turn to the same side, or continue both collinearly
  768. // To check for union/intersection, try to check side values
  769. int const side_qk_p2 = side.qk_wrt_p2();
  770. if (opposite(side_qk_p2, side_pk_q2))
  771. {
  772. ui_else_iu(side_pk_q2 == 1, ti);
  773. return;
  774. }
  775. }
  776. // If pk is collinear with qj-qk, they continue collinearly.
  777. // This can be on either side of p1 (== q1), or collinear
  778. // The second condition checks if they do not continue
  779. // oppositely
  780. if (side_pk_q2 == 0 && side_pk_p == side_qk_p)
  781. {
  782. fun::template both_collinear<0, 1>(range_p, range_q, umbrella_strategy, 2, 2, ti);
  783. return;
  784. }
  785. // If they turn to same side (not opposite sides)
  786. if (! opposite(side_pk_p, side_qk_p))
  787. {
  788. // If pk is left of q2 or collinear: p: union, q: intersection
  789. ui_else_iu(side_pk_q2 != -1, ti);
  790. }
  791. else
  792. {
  793. // They turn opposite sides. If p turns left (or collinear),
  794. // p: union, q: intersection
  795. ui_else_iu(side_pk_p != -1, ti);
  796. }
  797. }
  798. };
  799. template
  800. <
  801. typename TurnInfo,
  802. typename VerifyPolicy
  803. >
  804. struct start : public base_turn_handler
  805. {
  806. template
  807. <
  808. typename UniqueSubRange1,
  809. typename UniqueSubRange2,
  810. typename IntersectionInfo,
  811. typename DirInfo,
  812. typename SideCalculator,
  813. typename UmbrellaStrategy
  814. >
  815. static inline bool apply(UniqueSubRange1 const& /*range_p*/,
  816. UniqueSubRange2 const& /*range_q*/,
  817. TurnInfo& ti,
  818. IntersectionInfo const& info,
  819. DirInfo const& dir_info,
  820. SideCalculator const& side,
  821. UmbrellaStrategy const& )
  822. {
  823. if BOOST_GEOMETRY_CONSTEXPR (! VerifyPolicy::use_start_turn)
  824. {
  825. return false;
  826. }
  827. else // else prevents unreachable code warning
  828. {
  829. // Start turns have either how_a = -1, or how_b = -1 (either p leaves or q leaves)
  830. BOOST_GEOMETRY_ASSERT(dir_info.how_a != dir_info.how_b);
  831. BOOST_GEOMETRY_ASSERT(dir_info.how_a == -1 || dir_info.how_b == -1);
  832. BOOST_GEOMETRY_ASSERT(dir_info.how_a == 0 || dir_info.how_b == 0);
  833. if (dir_info.how_b == -1)
  834. {
  835. // p --------------->
  836. // |
  837. // | q q leaves
  838. // v
  839. //
  840. int const side_qj_p1 = side.qj_wrt_p1();
  841. ui_else_iu(side_qj_p1 == -1, ti);
  842. }
  843. else if (dir_info.how_a == -1)
  844. {
  845. // p leaves
  846. int const side_pj_q1 = side.pj_wrt_q1();
  847. ui_else_iu(side_pj_q1 == 1, ti);
  848. }
  849. // Copy intersection point
  850. assign_point_and_correct(ti, method_start, info, dir_info);
  851. return true;
  852. }
  853. }
  854. };
  855. template
  856. <
  857. typename TurnInfo,
  858. typename AssignPolicy
  859. >
  860. struct equal_opposite : public base_turn_handler
  861. {
  862. template
  863. <
  864. typename UniqueSubRange1,
  865. typename UniqueSubRange2,
  866. typename OutputIterator,
  867. typename IntersectionInfo
  868. >
  869. static inline void apply(
  870. UniqueSubRange1 const& /*range_p*/,
  871. UniqueSubRange2 const& /*range_q*/,
  872. /* by value: */ TurnInfo tp,
  873. OutputIterator& out,
  874. IntersectionInfo const& intersection_info)
  875. {
  876. // For equal-opposite segments, normally don't do anything.
  877. if BOOST_GEOMETRY_CONSTEXPR (AssignPolicy::include_opposite)
  878. {
  879. tp.method = method_equal;
  880. for (unsigned int i = 0; i < 2; i++)
  881. {
  882. tp.operations[i].operation = operation_opposite;
  883. }
  884. for (unsigned int i = 0; i < intersection_info.i_info().count; i++)
  885. {
  886. assign_point(tp, method_none, intersection_info.i_info(), i);
  887. *out++ = tp;
  888. }
  889. }
  890. }
  891. };
  892. template
  893. <
  894. typename TurnInfo,
  895. typename VerifyPolicy
  896. >
  897. struct collinear : public base_turn_handler
  898. {
  899. using fun = turn_info_verification_functions<VerifyPolicy>;
  900. template
  901. <
  902. typename IntersectionInfo,
  903. typename UniqueSubRange1,
  904. typename UniqueSubRange2,
  905. typename DirInfo
  906. >
  907. static bool handle_as_equal(IntersectionInfo const& info,
  908. UniqueSubRange1 const& range_p,
  909. UniqueSubRange2 const& range_q,
  910. DirInfo const& dir_info)
  911. {
  912. if BOOST_GEOMETRY_CONSTEXPR (! VerifyPolicy::use_handle_as_equal)
  913. {
  914. return false;
  915. }
  916. else // else prevents unreachable code warning
  917. {
  918. int const arrival_p = dir_info.arrival[0];
  919. int const arrival_q = dir_info.arrival[1];
  920. if (arrival_p * arrival_q != -1 || info.count != 2)
  921. {
  922. // Code below assumes that either p or q arrives in the other segment
  923. return false;
  924. }
  925. auto const dm = arrival_p == 1
  926. ? fun::distance_measure(info.intersections[1], range_q.at(1))
  927. : fun::distance_measure(info.intersections[1], range_p.at(1));
  928. decltype(dm) const zero = 0;
  929. return math::equals(dm, zero);
  930. }
  931. }
  932. /*
  933. Either P arrives within Q (arrival_p == -1) or Q arrives within P.
  934. Typical situation:
  935. ^q2
  936. /
  937. ^q1
  938. / ____ ip[1]
  939. //|p1 } this section of p/q is colllinear
  940. q0// | } ____ ip[0]
  941. / |
  942. / v
  943. p0 p2
  944. P arrives (at p1) in segment Q (between q0 and q1).
  945. Therefore arrival_p == 1
  946. P (p2) goes to the right (-1). Follow P for intersection, or follow Q for union.
  947. Therefore if (arrival_p==1) and side_p==-1, result = iu
  948. Complete table:
  949. arrival P pk//p1 qk//q1 product case result
  950. 1 1 1 CLL1 ui
  951. -1 1 -1 CLL2 iu
  952. 1 1 1 CLR1 ui
  953. -1 -1 1 CLR2 ui
  954. 1 -1 -1 CRL1 iu
  955. -1 1 -1 CRL2 iu
  956. 1 -1 -1 CRR1 iu
  957. -1 -1 1 CRR2 ui
  958. 1 0 0 CC1 cc
  959. -1 0 0 CC2 cc
  960. Resulting in the rule:
  961. The arrival-info multiplied by the relevant side delivers the result.
  962. product = arrival * (pk//p1 or qk//q1)
  963. Stated otherwise:
  964. - if P arrives: look at turn P
  965. - if Q arrives: look at turn Q
  966. - if P arrives and P turns left: union for P
  967. - if P arrives and P turns right: intersection for P
  968. - if Q arrives and Q turns left: union for Q (=intersection for P)
  969. - if Q arrives and Q turns right: intersection for Q (=union for P)
  970. */
  971. template
  972. <
  973. typename UniqueSubRange1,
  974. typename UniqueSubRange2,
  975. typename IntersectionInfo,
  976. typename DirInfo,
  977. typename SidePolicy
  978. >
  979. static inline void apply(
  980. UniqueSubRange1 const& range_p,
  981. UniqueSubRange2 const& range_q,
  982. TurnInfo& ti,
  983. IntersectionInfo const& info,
  984. DirInfo const& dir_info,
  985. SidePolicy const& side)
  986. {
  987. // Copy the intersection point in TO direction
  988. assign_point(ti, method_collinear, info, non_opposite_to_index(info));
  989. int const arrival_p = dir_info.arrival[0];
  990. // Should not be 0, this is checked before
  991. BOOST_GEOMETRY_ASSERT(arrival_p != 0);
  992. bool const has_pk = ! range_p.is_last_segment();
  993. bool const has_qk = ! range_q.is_last_segment();
  994. int const side_p = has_pk ? side.pk_wrt_p1() : 0;
  995. int const side_q = has_qk ? side.qk_wrt_q1() : 0;
  996. // If p arrives, use p, else use q
  997. int const side_p_or_q = arrival_p == 1
  998. ? side_p
  999. : side_q
  1000. ;
  1001. // Calculate product according to comments above.
  1002. int const product = arrival_p * side_p_or_q;
  1003. if (product == 0)
  1004. {
  1005. both(ti, operation_continue);
  1006. }
  1007. else
  1008. {
  1009. ui_else_iu(product == 1, ti);
  1010. }
  1011. // Calculate remaining distance. If it continues collinearly it is
  1012. // measured until the end of the next segment
  1013. ti.operations[0].remaining_distance
  1014. = side_p == 0 && has_pk
  1015. ? fun::distance_measure(ti.point, range_p.at(2))
  1016. : fun::distance_measure(ti.point, range_p.at(1));
  1017. ti.operations[1].remaining_distance
  1018. = side_q == 0 && has_qk
  1019. ? fun::distance_measure(ti.point, range_q.at(2))
  1020. : fun::distance_measure(ti.point, range_q.at(1));
  1021. }
  1022. };
  1023. template
  1024. <
  1025. typename TurnInfo,
  1026. typename AssignPolicy
  1027. >
  1028. struct collinear_opposite : public base_turn_handler
  1029. {
  1030. private :
  1031. /*
  1032. arrival P arrival Q pk//p1 qk//q1 case result2 result
  1033. --------------------------------------------------------------
  1034. 1 1 1 -1 CLO1 ix xu
  1035. 1 1 1 0 CLO2 ix (xx)
  1036. 1 1 1 1 CLO3 ix xi
  1037. 1 1 0 -1 CCO1 (xx) xu
  1038. 1 1 0 0 CCO2 (xx) (xx)
  1039. 1 1 0 1 CCO3 (xx) xi
  1040. 1 1 -1 -1 CRO1 ux xu
  1041. 1 1 -1 0 CRO2 ux (xx)
  1042. 1 1 -1 1 CRO3 ux xi
  1043. -1 1 -1 CXO1 xu
  1044. -1 1 0 CXO2 (xx)
  1045. -1 1 1 CXO3 xi
  1046. 1 -1 1 CXO1 ix
  1047. 1 -1 0 CXO2 (xx)
  1048. 1 -1 -1 CXO3 ux
  1049. */
  1050. template <unsigned int Index, typename IntersectionInfo>
  1051. static inline bool set_tp(int side_rk_r, TurnInfo& tp,
  1052. IntersectionInfo const& intersection_info)
  1053. {
  1054. BOOST_STATIC_ASSERT(Index <= 1);
  1055. operation_type blocked = operation_blocked;
  1056. switch(side_rk_r)
  1057. {
  1058. case 1 :
  1059. // Turning left on opposite collinear: intersection
  1060. tp.operations[Index].operation = operation_intersection;
  1061. break;
  1062. case -1 :
  1063. // Turning right on opposite collinear: union
  1064. tp.operations[Index].operation = operation_union;
  1065. break;
  1066. case 0 :
  1067. // No turn on opposite collinear: block, do not traverse
  1068. // But this "xx" is usually ignored, it is useless to include
  1069. // two operations blocked, so the whole point does not need
  1070. // to be generated.
  1071. // So return false to indicate nothing is to be done.
  1072. if BOOST_GEOMETRY_CONSTEXPR (AssignPolicy::include_opposite)
  1073. {
  1074. tp.operations[Index].operation = operation_opposite;
  1075. blocked = operation_opposite;
  1076. }
  1077. else
  1078. {
  1079. return false;
  1080. }
  1081. break;
  1082. }
  1083. // The other direction is always blocked when collinear opposite
  1084. tp.operations[1 - Index].operation = blocked;
  1085. // If P arrives within Q, set info on P (which is done above, index=0),
  1086. // this turn-info belongs to the second intersection point, index=1
  1087. // (see e.g. figure CLO1)
  1088. assign_point(tp, method_collinear, intersection_info, 1 - Index);
  1089. return true;
  1090. }
  1091. public:
  1092. static inline void empty_transformer(TurnInfo &) {}
  1093. template
  1094. <
  1095. typename UniqueSubRange1,
  1096. typename UniqueSubRange2,
  1097. typename OutputIterator,
  1098. typename IntersectionInfo,
  1099. typename SidePolicy
  1100. >
  1101. static inline void apply(
  1102. UniqueSubRange1 const& range_p,
  1103. UniqueSubRange2 const& range_q,
  1104. // Opposite collinear can deliver 2 intersection points,
  1105. TurnInfo const& tp_model,
  1106. OutputIterator& out,
  1107. IntersectionInfo const& intersection_info,
  1108. SidePolicy const& side)
  1109. {
  1110. apply(range_p, range_q,
  1111. tp_model, out, intersection_info, side, empty_transformer);
  1112. }
  1113. template
  1114. <
  1115. typename UniqueSubRange1,
  1116. typename UniqueSubRange2,
  1117. typename OutputIterator,
  1118. typename IntersectionInfo,
  1119. typename SidePolicy,
  1120. typename TurnTransformer
  1121. >
  1122. static inline void apply(
  1123. UniqueSubRange1 const& range_p,
  1124. UniqueSubRange2 const& range_q,
  1125. // Opposite collinear can deliver 2 intersection points,
  1126. TurnInfo const& tp_model,
  1127. OutputIterator& out,
  1128. IntersectionInfo const& info,
  1129. SidePolicy const& side,
  1130. TurnTransformer turn_transformer)
  1131. {
  1132. TurnInfo tp = tp_model;
  1133. int const arrival_p = info.d_info().arrival[0];
  1134. int const arrival_q = info.d_info().arrival[1];
  1135. // If P arrives within Q, there is a turn dependent on P
  1136. if ( arrival_p == 1
  1137. && ! range_p.is_last_segment()
  1138. && set_tp<0>(side.pk_wrt_p1(), tp, info.i_info()) )
  1139. {
  1140. turn_transformer(tp);
  1141. *out++ = tp;
  1142. }
  1143. // If Q arrives within P, there is a turn dependent on Q
  1144. if ( arrival_q == 1
  1145. && ! range_q.is_last_segment()
  1146. && set_tp<1>(side.qk_wrt_q1(), tp, info.i_info()) )
  1147. {
  1148. turn_transformer(tp);
  1149. *out++ = tp;
  1150. }
  1151. if BOOST_GEOMETRY_CONSTEXPR (AssignPolicy::include_opposite)
  1152. {
  1153. // Handle cases not yet handled above
  1154. if ((arrival_q == -1 && arrival_p == 0)
  1155. || (arrival_p == -1 && arrival_q == 0))
  1156. {
  1157. for (unsigned int i = 0; i < 2; i++)
  1158. {
  1159. tp.operations[i].operation = operation_opposite;
  1160. }
  1161. for (unsigned int i = 0; i < info.i_info().count; i++)
  1162. {
  1163. assign_point(tp, method_collinear, info.i_info(), i);
  1164. *out++ = tp;
  1165. }
  1166. }
  1167. }
  1168. }
  1169. };
  1170. template
  1171. <
  1172. typename TurnInfo
  1173. >
  1174. struct crosses : public base_turn_handler
  1175. {
  1176. template <typename IntersectionInfo, typename DirInfo>
  1177. static inline void apply(TurnInfo& ti,
  1178. IntersectionInfo const& intersection_info,
  1179. DirInfo const& dir_info)
  1180. {
  1181. assign_point(ti, method_crosses, intersection_info, 0);
  1182. // In all cases:
  1183. // If Q crosses P from left to right
  1184. // Union: take P
  1185. // Intersection: take Q
  1186. // Otherwise: vice versa
  1187. int const side_qi_p1 = dir_info.sides.template get<1, 0>();
  1188. unsigned int const index = side_qi_p1 == 1 ? 0 : 1;
  1189. ti.operations[index].operation = operation_union;
  1190. ti.operations[1 - index].operation = operation_intersection;
  1191. }
  1192. };
  1193. struct only_convert : public base_turn_handler
  1194. {
  1195. template<typename TurnInfo, typename IntersectionInfo>
  1196. static inline void apply(TurnInfo& ti, IntersectionInfo const& intersection_info)
  1197. {
  1198. assign_point(ti, method_none, intersection_info, 0);
  1199. ti.operations[0].operation = operation_continue;
  1200. ti.operations[1].operation = operation_continue;
  1201. }
  1202. };
  1203. /*!
  1204. \brief Policy doing nothing
  1205. \details get_turn_info can have an optional policy include extra
  1206. truns. By default it does not, and this class is that default.
  1207. */
  1208. struct assign_null_policy
  1209. {
  1210. static bool const include_no_turn = false;
  1211. static bool const include_degenerate = false;
  1212. static bool const include_opposite = false;
  1213. static bool const include_start_turn = false;
  1214. };
  1215. struct assign_policy_only_start_turns
  1216. {
  1217. static bool const include_no_turn = false;
  1218. static bool const include_degenerate = false;
  1219. static bool const include_opposite = false;
  1220. static bool const include_start_turn = true;
  1221. };
  1222. /*!
  1223. \brief Turn information: intersection point, method, and turn information
  1224. \details Information necessary for traversal phase (a phase
  1225. of the overlay process). The information is gathered during the
  1226. get_turns (segment intersection) phase.
  1227. \tparam AssignPolicy policy to assign extra info,
  1228. e.g. to calculate distance from segment's first points
  1229. to intersection points.
  1230. It also defines if a certain class of points
  1231. (degenerate, non-turns) should be included.
  1232. */
  1233. template<typename AssignPolicy>
  1234. struct get_turn_info
  1235. {
  1236. // Intersect a segment p with a segment q
  1237. // Both p and q are modelled as sub_ranges to provide more points
  1238. // to be able to give more information about the turn (left/right)
  1239. template
  1240. <
  1241. typename UniqueSubRange1,
  1242. typename UniqueSubRange2,
  1243. typename TurnInfo,
  1244. typename UmbrellaStrategy,
  1245. typename RobustPolicy,
  1246. typename OutputIterator
  1247. >
  1248. static inline OutputIterator apply(
  1249. UniqueSubRange1 const& range_p,
  1250. UniqueSubRange2 const& range_q,
  1251. TurnInfo const& tp_model,
  1252. UmbrellaStrategy const& umbrella_strategy,
  1253. RobustPolicy const& robust_policy,
  1254. OutputIterator out)
  1255. {
  1256. typedef intersection_info
  1257. <
  1258. UniqueSubRange1, UniqueSubRange2,
  1259. typename TurnInfo::point_type,
  1260. UmbrellaStrategy,
  1261. RobustPolicy
  1262. > inters_info;
  1263. inters_info inters(range_p, range_q, umbrella_strategy, robust_policy);
  1264. char const method = inters.d_info().how;
  1265. if (method == 'd')
  1266. {
  1267. // Disjoint
  1268. return out;
  1269. }
  1270. // Copy, to copy possibly extended fields
  1271. TurnInfo tp = tp_model;
  1272. bool const handle_as_touch_interior = method == 'm';
  1273. bool const handle_as_cross = method == 'i';
  1274. bool handle_as_touch = method == 't';
  1275. bool handle_as_equal = method == 'e';
  1276. bool const handle_as_collinear = method == 'c';
  1277. bool const handle_as_degenerate = method == '0';
  1278. bool const handle_as_start = method == 's';
  1279. // (angle, from)
  1280. bool do_only_convert = method == 'a' || method == 'f';
  1281. if (handle_as_start)
  1282. {
  1283. // It is in some cases necessary to handle a start turn
  1284. using handler = start<TurnInfo, verify_policy_aa>;
  1285. if (BOOST_GEOMETRY_CONDITION(AssignPolicy::include_start_turn)
  1286. && handler::apply(range_p, range_q, tp,
  1287. inters.i_info(), inters.d_info(), inters.sides(),
  1288. umbrella_strategy))
  1289. {
  1290. *out++ = tp;
  1291. }
  1292. else
  1293. {
  1294. do_only_convert = true;
  1295. }
  1296. }
  1297. if (handle_as_touch_interior)
  1298. {
  1299. using handler = touch_interior<TurnInfo, verify_policy_aa>;
  1300. if ( inters.d_info().arrival[1] == 1 )
  1301. {
  1302. // Q arrives
  1303. if (handler::handle_as_touch(inters.i_info(), range_p))
  1304. {
  1305. handle_as_touch = true;
  1306. }
  1307. else
  1308. {
  1309. handler::template apply<0>(range_p, range_q, tp, inters.i_info(), inters.d_info(),
  1310. inters.sides(), umbrella_strategy);
  1311. *out++ = tp;
  1312. }
  1313. }
  1314. else
  1315. {
  1316. // P arrives, swap p/q
  1317. if (handler::handle_as_touch(inters.i_info(), range_q))
  1318. {
  1319. handle_as_touch = true;
  1320. }
  1321. else
  1322. {
  1323. handler::template apply<1>(range_q, range_p, tp, inters.i_info(), inters.d_info(),
  1324. inters.swapped_sides(), umbrella_strategy);
  1325. *out++ = tp;
  1326. }
  1327. }
  1328. }
  1329. if (handle_as_cross)
  1330. {
  1331. crosses<TurnInfo>::apply(tp, inters.i_info(), inters.d_info());
  1332. *out++ = tp;
  1333. }
  1334. if (handle_as_touch)
  1335. {
  1336. // Touch: both segments arrive at the intersection point
  1337. using handler = touch<TurnInfo, verify_policy_aa>;
  1338. handler::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(),
  1339. umbrella_strategy);
  1340. *out++ = tp;
  1341. }
  1342. if (handle_as_collinear)
  1343. {
  1344. // Collinear
  1345. if ( ! inters.d_info().opposite )
  1346. {
  1347. using handler = collinear<TurnInfo, verify_policy_aa>;
  1348. if (inters.d_info().arrival[0] == 0
  1349. || handler::handle_as_equal(inters.i_info(), range_p, range_q, inters.d_info()))
  1350. {
  1351. // Both segments arrive at the second intersection point
  1352. handle_as_equal = true;
  1353. }
  1354. else
  1355. {
  1356. handler::apply(range_p, range_q, tp, inters.i_info(),
  1357. inters.d_info(), inters.sides());
  1358. *out++ = tp;
  1359. }
  1360. }
  1361. else
  1362. {
  1363. collinear_opposite
  1364. <
  1365. TurnInfo,
  1366. AssignPolicy
  1367. >::apply(range_p, range_q, tp, out, inters, inters.sides());
  1368. // Zero, or two, turn points are assigned to *out++
  1369. }
  1370. }
  1371. if (handle_as_equal)
  1372. {
  1373. if ( ! inters.d_info().opposite )
  1374. {
  1375. // Both equal
  1376. // or collinear-and-ending at intersection point
  1377. using handler = equal<TurnInfo, verify_policy_aa>;
  1378. handler::apply(range_p, range_q, tp,
  1379. inters.i_info(), inters.d_info(), inters.sides(),
  1380. umbrella_strategy);
  1381. if (handle_as_collinear)
  1382. {
  1383. // Keep info as collinear,
  1384. // so override already assigned method
  1385. tp.method = method_collinear;
  1386. }
  1387. *out++ = tp;
  1388. }
  1389. else
  1390. {
  1391. equal_opposite
  1392. <
  1393. TurnInfo,
  1394. AssignPolicy
  1395. >::apply(range_p, range_q, tp, out, inters);
  1396. // Zero, or two, turn points are assigned to *out++
  1397. }
  1398. }
  1399. if ((handle_as_degenerate
  1400. && BOOST_GEOMETRY_CONDITION(AssignPolicy::include_degenerate))
  1401. || (do_only_convert
  1402. && BOOST_GEOMETRY_CONDITION(AssignPolicy::include_no_turn)))
  1403. {
  1404. if (inters.i_info().count > 0)
  1405. {
  1406. only_convert::apply(tp, inters.i_info());
  1407. *out++ = tp;
  1408. }
  1409. }
  1410. return out;
  1411. }
  1412. };
  1413. }} // namespace detail::overlay
  1414. #endif //DOXYGEN_NO_DETAIL
  1415. }} // namespace boost::geometry
  1416. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HPP