linear_linear.hpp 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826
  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, 2015, 2017, 2018, 2019.
  4. // Modifications copyright (c) 2013-2019 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_RELATE_LINEAR_LINEAR_HPP
  10. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_LINEAR_HPP
  11. #include <algorithm>
  12. #include <boost/core/ignore_unused.hpp>
  13. #include <boost/range/size.hpp>
  14. #include <boost/geometry/core/assert.hpp>
  15. #include <boost/geometry/util/condition.hpp>
  16. #include <boost/geometry/util/range.hpp>
  17. #include <boost/geometry/algorithms/detail/sub_range.hpp>
  18. #include <boost/geometry/algorithms/detail/single_geometry.hpp>
  19. #include <boost/geometry/algorithms/detail/relate/point_geometry.hpp>
  20. #include <boost/geometry/algorithms/detail/relate/result.hpp>
  21. #include <boost/geometry/algorithms/detail/relate/turns.hpp>
  22. #include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp>
  23. #include <boost/geometry/algorithms/detail/relate/follow_helpers.hpp>
  24. namespace boost { namespace geometry
  25. {
  26. #ifndef DOXYGEN_NO_DETAIL
  27. namespace detail { namespace relate {
  28. template <typename Result, typename BoundaryChecker, bool TransposeResult>
  29. class disjoint_linestring_pred
  30. {
  31. typedef typename BoundaryChecker::equals_strategy_type equals_strategy_type;
  32. public:
  33. disjoint_linestring_pred(Result & res,
  34. BoundaryChecker const& boundary_checker)
  35. : m_result(res)
  36. , m_boundary_checker(boundary_checker)
  37. , m_flags(0)
  38. {
  39. if ( ! may_update<interior, exterior, '1', TransposeResult>(m_result) )
  40. {
  41. m_flags |= 1;
  42. }
  43. if ( ! may_update<boundary, exterior, '0', TransposeResult>(m_result) )
  44. {
  45. m_flags |= 2;
  46. }
  47. }
  48. template <typename Linestring>
  49. bool operator()(Linestring const& linestring)
  50. {
  51. if ( m_flags == 3 )
  52. {
  53. return false;
  54. }
  55. std::size_t const count = boost::size(linestring);
  56. // invalid input
  57. if ( count < 2 )
  58. {
  59. // ignore
  60. // TODO: throw an exception?
  61. return true;
  62. }
  63. // point-like linestring
  64. if ( count == 2
  65. && equals::equals_point_point(range::front(linestring),
  66. range::back(linestring),
  67. equals_strategy_type()) )
  68. {
  69. update<interior, exterior, '0', TransposeResult>(m_result);
  70. }
  71. else
  72. {
  73. update<interior, exterior, '1', TransposeResult>(m_result);
  74. m_flags |= 1;
  75. // check if there is a boundary
  76. if ( m_flags < 2
  77. && ( m_boundary_checker.template
  78. is_endpoint_boundary<boundary_front>(range::front(linestring))
  79. || m_boundary_checker.template
  80. is_endpoint_boundary<boundary_back>(range::back(linestring)) ) )
  81. {
  82. update<boundary, exterior, '0', TransposeResult>(m_result);
  83. m_flags |= 2;
  84. }
  85. }
  86. return m_flags != 3
  87. && ! m_result.interrupt;
  88. }
  89. private:
  90. Result & m_result;
  91. BoundaryChecker const& m_boundary_checker;
  92. unsigned m_flags;
  93. };
  94. template <typename Geometry1, typename Geometry2>
  95. struct linear_linear
  96. {
  97. static const bool interruption_enabled = true;
  98. typedef typename geometry::point_type<Geometry1>::type point1_type;
  99. typedef typename geometry::point_type<Geometry2>::type point2_type;
  100. template <typename Result, typename IntersectionStrategy>
  101. static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
  102. Result & result,
  103. IntersectionStrategy const& intersection_strategy)
  104. {
  105. typedef typename IntersectionStrategy::cs_tag cs_tag;
  106. // The result should be FFFFFFFFF
  107. relate::set<exterior, exterior, result_dimension<Geometry1>::value>(result);// FFFFFFFFd, d in [1,9] or T
  108. if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
  109. return;
  110. // get and analyse turns
  111. typedef typename turns::get_turns
  112. <
  113. Geometry1, Geometry2
  114. >::template turn_info_type<IntersectionStrategy>::type turn_type;
  115. std::vector<turn_type> turns;
  116. interrupt_policy_linear_linear<Result> interrupt_policy(result);
  117. turns::get_turns
  118. <
  119. Geometry1,
  120. Geometry2,
  121. detail::get_turns::get_turn_info_type<Geometry1, Geometry2, turns::assign_policy<true> >
  122. >::apply(turns, geometry1, geometry2, interrupt_policy, intersection_strategy);
  123. if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
  124. return;
  125. typedef boundary_checker
  126. <
  127. Geometry1,
  128. typename IntersectionStrategy::point_in_point_strategy_type
  129. > boundary_checker1_type;
  130. boundary_checker1_type boundary_checker1(geometry1);
  131. disjoint_linestring_pred<Result, boundary_checker1_type, false> pred1(result, boundary_checker1);
  132. for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1);
  133. if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
  134. return;
  135. typedef boundary_checker
  136. <
  137. Geometry2,
  138. typename IntersectionStrategy::point_in_point_strategy_type
  139. > boundary_checker2_type;
  140. boundary_checker2_type boundary_checker2(geometry2);
  141. disjoint_linestring_pred<Result, boundary_checker2_type, true> pred2(result, boundary_checker2);
  142. for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2);
  143. if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
  144. return;
  145. if ( turns.empty() )
  146. return;
  147. // TODO: turns must be sorted and followed only if it's possible to go out and in on the same point
  148. // for linear geometries union operation must be detected which I guess would be quite often
  149. if ( may_update<interior, interior, '1'>(result)
  150. || may_update<interior, boundary, '0'>(result)
  151. || may_update<interior, exterior, '1'>(result)
  152. || may_update<boundary, interior, '0'>(result)
  153. || may_update<boundary, boundary, '0'>(result)
  154. || may_update<boundary, exterior, '0'>(result) )
  155. {
  156. typedef turns::less<0, turns::less_op_linear_linear<0>, cs_tag> less;
  157. std::sort(turns.begin(), turns.end(), less());
  158. turns_analyser<turn_type, 0> analyser;
  159. analyse_each_turn(result, analyser,
  160. turns.begin(), turns.end(),
  161. geometry1, geometry2,
  162. boundary_checker1, boundary_checker2);
  163. }
  164. if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
  165. return;
  166. if ( may_update<interior, interior, '1', true>(result)
  167. || may_update<interior, boundary, '0', true>(result)
  168. || may_update<interior, exterior, '1', true>(result)
  169. || may_update<boundary, interior, '0', true>(result)
  170. || may_update<boundary, boundary, '0', true>(result)
  171. || may_update<boundary, exterior, '0', true>(result) )
  172. {
  173. typedef turns::less<1, turns::less_op_linear_linear<1>, cs_tag> less;
  174. std::sort(turns.begin(), turns.end(), less());
  175. turns_analyser<turn_type, 1> analyser;
  176. analyse_each_turn(result, analyser,
  177. turns.begin(), turns.end(),
  178. geometry2, geometry1,
  179. boundary_checker2, boundary_checker1);
  180. }
  181. }
  182. template <typename Result>
  183. class interrupt_policy_linear_linear
  184. {
  185. public:
  186. static bool const enabled = true;
  187. explicit interrupt_policy_linear_linear(Result & result)
  188. : m_result(result)
  189. {}
  190. // TODO: since we update result for some operations here, we may not do it in the analyser!
  191. template <typename Range>
  192. inline bool apply(Range const& turns)
  193. {
  194. typedef typename boost::range_iterator<Range const>::type iterator;
  195. for (iterator it = boost::begin(turns) ; it != boost::end(turns) ; ++it)
  196. {
  197. if ( it->operations[0].operation == overlay::operation_intersection
  198. || it->operations[1].operation == overlay::operation_intersection )
  199. {
  200. update<interior, interior, '1'>(m_result);
  201. }
  202. else if ( ( it->operations[0].operation == overlay::operation_union
  203. || it->operations[0].operation == overlay::operation_blocked
  204. || it->operations[1].operation == overlay::operation_union
  205. || it->operations[1].operation == overlay::operation_blocked )
  206. && it->operations[0].position == overlay::position_middle
  207. && it->operations[1].position == overlay::position_middle )
  208. {
  209. // TODO: here we could also check the boundaries and set IB,BI,BB at this point
  210. update<interior, interior, '0'>(m_result);
  211. }
  212. }
  213. return m_result.interrupt;
  214. }
  215. private:
  216. Result & m_result;
  217. };
  218. // This analyser should be used like Input or SinglePass Iterator
  219. template <typename TurnInfo, std::size_t OpId>
  220. class turns_analyser
  221. {
  222. typedef typename TurnInfo::point_type turn_point_type;
  223. static const std::size_t op_id = OpId;
  224. static const std::size_t other_op_id = (OpId + 1) % 2;
  225. static const bool transpose_result = OpId != 0;
  226. public:
  227. turns_analyser()
  228. : m_previous_turn_ptr(NULL)
  229. , m_previous_operation(overlay::operation_none)
  230. , m_degenerated_turn_ptr(NULL)
  231. , m_collinear_spike_exit(false)
  232. {}
  233. template <typename Result,
  234. typename TurnIt,
  235. typename Geometry,
  236. typename OtherGeometry,
  237. typename BoundaryChecker,
  238. typename OtherBoundaryChecker>
  239. void apply(Result & res, TurnIt it,
  240. Geometry const& geometry,
  241. OtherGeometry const& other_geometry,
  242. BoundaryChecker const& boundary_checker,
  243. OtherBoundaryChecker const& other_boundary_checker)
  244. {
  245. typedef typename BoundaryChecker::equals_strategy_type equals_strategy_type;
  246. overlay::operation_type const op = it->operations[op_id].operation;
  247. segment_identifier const& seg_id = it->operations[op_id].seg_id;
  248. segment_identifier const& other_id = it->operations[other_op_id].seg_id;
  249. bool const first_in_range = m_seg_watcher.update(seg_id);
  250. if ( op != overlay::operation_union
  251. && op != overlay::operation_intersection
  252. && op != overlay::operation_blocked )
  253. {
  254. // degenerated turn
  255. if ( op == overlay::operation_continue
  256. && it->method == overlay::method_none
  257. && m_exit_watcher.is_outside(*it)
  258. /*&& ( m_exit_watcher.get_exit_operation() == overlay::operation_none
  259. || ! turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it) )*/ )
  260. {
  261. // TODO: rewrite the above condition
  262. // WARNING! For spikes the above condition may be TRUE
  263. // When degenerated turns are be marked in a different way than c,c/c
  264. // different condition will be checked
  265. handle_degenerated(res, *it,
  266. geometry, other_geometry,
  267. boundary_checker, other_boundary_checker,
  268. first_in_range);
  269. // TODO: not elegant solution! should be rewritten.
  270. if ( it->operations[op_id].position == overlay::position_back )
  271. {
  272. m_previous_operation = overlay::operation_blocked;
  273. m_exit_watcher.reset_detected_exit();
  274. }
  275. }
  276. return;
  277. }
  278. // reset
  279. m_degenerated_turn_ptr = NULL;
  280. // handle possible exit
  281. bool fake_enter_detected = false;
  282. if ( m_exit_watcher.get_exit_operation() == overlay::operation_union )
  283. {
  284. // real exit point - may be multiple
  285. // we know that we entered and now we exit
  286. if ( ! turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(),
  287. *it,
  288. equals_strategy_type()) )
  289. {
  290. m_exit_watcher.reset_detected_exit();
  291. // not the last IP
  292. update<interior, exterior, '1', transpose_result>(res);
  293. }
  294. // fake exit point, reset state
  295. else if ( op == overlay::operation_intersection )
  296. {
  297. m_exit_watcher.reset_detected_exit();
  298. fake_enter_detected = true;
  299. }
  300. }
  301. else if ( m_exit_watcher.get_exit_operation() == overlay::operation_blocked )
  302. {
  303. // ignore multiple BLOCKs
  304. if ( op == overlay::operation_blocked )
  305. return;
  306. if ( op == overlay::operation_intersection
  307. && turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(),
  308. *it,
  309. equals_strategy_type()) )
  310. {
  311. fake_enter_detected = true;
  312. }
  313. m_exit_watcher.reset_detected_exit();
  314. }
  315. // i/i, i/x, i/u
  316. if ( op == overlay::operation_intersection )
  317. {
  318. bool const was_outside = m_exit_watcher.is_outside();
  319. m_exit_watcher.enter(*it);
  320. // interiors overlaps
  321. update<interior, interior, '1', transpose_result>(res);
  322. bool const this_b = it->operations[op_id].position == overlay::position_front // ignore spikes!
  323. && is_ip_on_boundary<boundary_front>(it->point,
  324. it->operations[op_id],
  325. boundary_checker,
  326. seg_id);
  327. // going inside on boundary point
  328. // may be front only
  329. if ( this_b )
  330. {
  331. // may be front and back
  332. bool const other_b = is_ip_on_boundary<boundary_any>(it->point,
  333. it->operations[other_op_id],
  334. other_boundary_checker,
  335. other_id);
  336. // it's also the boundary of the other geometry
  337. if ( other_b )
  338. {
  339. update<boundary, boundary, '0', transpose_result>(res);
  340. }
  341. else
  342. {
  343. update<boundary, interior, '0', transpose_result>(res);
  344. }
  345. }
  346. // going inside on non-boundary point
  347. else
  348. {
  349. // if we didn't enter in the past, we were outside
  350. if ( was_outside
  351. && ! fake_enter_detected
  352. && it->operations[op_id].position != overlay::position_front
  353. && ! m_collinear_spike_exit )
  354. {
  355. update<interior, exterior, '1', transpose_result>(res);
  356. // if it's the first IP then the first point is outside
  357. if ( first_in_range )
  358. {
  359. bool const front_b = is_endpoint_on_boundary<boundary_front>(
  360. range::front(sub_range(geometry, seg_id)),
  361. boundary_checker);
  362. // if there is a boundary on the first point
  363. if ( front_b )
  364. {
  365. update<boundary, exterior, '0', transpose_result>(res);
  366. }
  367. }
  368. }
  369. }
  370. m_collinear_spike_exit = false;
  371. }
  372. // u/i, u/u, u/x, x/i, x/u, x/x
  373. else if ( op == overlay::operation_union || op == overlay::operation_blocked )
  374. {
  375. // TODO: is exit watcher still needed?
  376. // couldn't is_collinear and some going inside counter be used instead?
  377. bool const is_collinear = it->operations[op_id].is_collinear;
  378. bool const was_outside = m_exit_watcher.is_outside()
  379. && m_exit_watcher.get_exit_operation() == overlay::operation_none;
  380. // TODO: move the above condition into the exit_watcher?
  381. // to exit we must be currently inside and the current segment must be collinear
  382. if ( !was_outside && is_collinear )
  383. {
  384. m_exit_watcher.exit(*it, false);
  385. // if the position is not set to back it must be a spike
  386. if ( it->operations[op_id].position != overlay::position_back )
  387. {
  388. m_collinear_spike_exit = true;
  389. }
  390. }
  391. bool const op_blocked = op == overlay::operation_blocked;
  392. // we're inside and going out from inside
  393. // possibly going out right now
  394. if ( ! was_outside && is_collinear )
  395. {
  396. if ( op_blocked
  397. && it->operations[op_id].position == overlay::position_back ) // ignore spikes!
  398. {
  399. // check if this is indeed the boundary point
  400. // NOTE: is_ip_on_boundary<>() should be called here but the result will be the same
  401. if ( is_endpoint_on_boundary<boundary_back>(it->point, boundary_checker) )
  402. {
  403. // may be front and back
  404. bool const other_b = is_ip_on_boundary<boundary_any>(it->point,
  405. it->operations[other_op_id],
  406. other_boundary_checker,
  407. other_id);
  408. // it's also the boundary of the other geometry
  409. if ( other_b )
  410. {
  411. update<boundary, boundary, '0', transpose_result>(res);
  412. }
  413. else
  414. {
  415. update<boundary, interior, '0', transpose_result>(res);
  416. }
  417. }
  418. }
  419. }
  420. // we're outside or intersects some segment from the outside
  421. else
  422. {
  423. // if we are truly outside
  424. if ( was_outside
  425. && it->operations[op_id].position != overlay::position_front
  426. && ! m_collinear_spike_exit
  427. /*&& !is_collinear*/ )
  428. {
  429. update<interior, exterior, '1', transpose_result>(res);
  430. }
  431. // boundaries don't overlap - just an optimization
  432. if ( it->method == overlay::method_crosses )
  433. {
  434. // the L1 is going from one side of the L2 to the other through the point
  435. update<interior, interior, '0', transpose_result>(res);
  436. // it's the first point in range
  437. if ( first_in_range )
  438. {
  439. bool const front_b = is_endpoint_on_boundary<boundary_front>(
  440. range::front(sub_range(geometry, seg_id)),
  441. boundary_checker);
  442. // if there is a boundary on the first point
  443. if ( front_b )
  444. {
  445. update<boundary, exterior, '0', transpose_result>(res);
  446. }
  447. }
  448. }
  449. // method other than crosses, check more conditions
  450. else
  451. {
  452. bool const this_b = is_ip_on_boundary<boundary_any>(it->point,
  453. it->operations[op_id],
  454. boundary_checker,
  455. seg_id);
  456. bool const other_b = is_ip_on_boundary<boundary_any>(it->point,
  457. it->operations[other_op_id],
  458. other_boundary_checker,
  459. other_id);
  460. // if current IP is on boundary of the geometry
  461. if ( this_b )
  462. {
  463. // it's also the boundary of the other geometry
  464. if ( other_b )
  465. {
  466. update<boundary, boundary, '0', transpose_result>(res);
  467. }
  468. else
  469. {
  470. update<boundary, interior, '0', transpose_result>(res);
  471. }
  472. }
  473. // if current IP is not on boundary of the geometry
  474. else
  475. {
  476. // it's also the boundary of the other geometry
  477. if ( other_b )
  478. {
  479. update<interior, boundary, '0', transpose_result>(res);
  480. }
  481. else
  482. {
  483. update<interior, interior, '0', transpose_result>(res);
  484. }
  485. }
  486. // first IP on the last segment point - this means that the first point is outside
  487. if ( first_in_range
  488. && ( !this_b || op_blocked )
  489. && was_outside
  490. && it->operations[op_id].position != overlay::position_front
  491. && ! m_collinear_spike_exit
  492. /*&& !is_collinear*/ )
  493. {
  494. bool const front_b = is_endpoint_on_boundary<boundary_front>(
  495. range::front(sub_range(geometry, seg_id)),
  496. boundary_checker);
  497. // if there is a boundary on the first point
  498. if ( front_b )
  499. {
  500. update<boundary, exterior, '0', transpose_result>(res);
  501. }
  502. }
  503. }
  504. }
  505. }
  506. // store ref to previously analysed (valid) turn
  507. m_previous_turn_ptr = boost::addressof(*it);
  508. // and previously analysed (valid) operation
  509. m_previous_operation = op;
  510. }
  511. // Called for last
  512. template <typename Result,
  513. typename TurnIt,
  514. typename Geometry,
  515. typename OtherGeometry,
  516. typename BoundaryChecker,
  517. typename OtherBoundaryChecker>
  518. void apply(Result & res,
  519. TurnIt first, TurnIt last,
  520. Geometry const& geometry,
  521. OtherGeometry const& /*other_geometry*/,
  522. BoundaryChecker const& boundary_checker,
  523. OtherBoundaryChecker const& /*other_boundary_checker*/)
  524. {
  525. boost::ignore_unused(first, last);
  526. //BOOST_GEOMETRY_ASSERT( first != last );
  527. // here, the possible exit is the real one
  528. // we know that we entered and now we exit
  529. if ( /*m_exit_watcher.get_exit_operation() == overlay::operation_union // THIS CHECK IS REDUNDANT
  530. ||*/ m_previous_operation == overlay::operation_union
  531. || m_degenerated_turn_ptr )
  532. {
  533. update<interior, exterior, '1', transpose_result>(res);
  534. BOOST_GEOMETRY_ASSERT(first != last);
  535. const TurnInfo * turn_ptr = NULL;
  536. if ( m_degenerated_turn_ptr )
  537. turn_ptr = m_degenerated_turn_ptr;
  538. else if ( m_previous_turn_ptr )
  539. turn_ptr = m_previous_turn_ptr;
  540. if ( turn_ptr )
  541. {
  542. segment_identifier const& prev_seg_id = turn_ptr->operations[op_id].seg_id;
  543. //BOOST_GEOMETRY_ASSERT(!boost::empty(sub_range(geometry, prev_seg_id)));
  544. bool const prev_back_b = is_endpoint_on_boundary<boundary_back>(
  545. range::back(sub_range(geometry, prev_seg_id)),
  546. boundary_checker);
  547. // if there is a boundary on the last point
  548. if ( prev_back_b )
  549. {
  550. update<boundary, exterior, '0', transpose_result>(res);
  551. }
  552. }
  553. }
  554. // Just in case,
  555. // reset exit watcher before the analysis of the next Linestring
  556. // note that if there are some enters stored there may be some error above
  557. m_exit_watcher.reset();
  558. m_previous_turn_ptr = NULL;
  559. m_previous_operation = overlay::operation_none;
  560. m_degenerated_turn_ptr = NULL;
  561. // actually if this is set to true here there is some error
  562. // in get_turns_ll or relate_ll, an assert could be checked here
  563. m_collinear_spike_exit = false;
  564. }
  565. template <typename Result,
  566. typename Turn,
  567. typename Geometry,
  568. typename OtherGeometry,
  569. typename BoundaryChecker,
  570. typename OtherBoundaryChecker>
  571. void handle_degenerated(Result & res,
  572. Turn const& turn,
  573. Geometry const& geometry,
  574. OtherGeometry const& other_geometry,
  575. BoundaryChecker const& boundary_checker,
  576. OtherBoundaryChecker const& /*other_boundary_checker*/,
  577. bool first_in_range)
  578. {
  579. typedef typename BoundaryChecker::equals_strategy_type
  580. equals_strategy1_type;
  581. typedef typename OtherBoundaryChecker::equals_strategy_type
  582. equals_strategy2_type;
  583. typename detail::single_geometry_return_type<Geometry const>::type
  584. ls1_ref = detail::single_geometry(geometry, turn.operations[op_id].seg_id);
  585. typename detail::single_geometry_return_type<OtherGeometry const>::type
  586. ls2_ref = detail::single_geometry(other_geometry, turn.operations[other_op_id].seg_id);
  587. // only one of those should be true:
  588. if ( turn.operations[op_id].position == overlay::position_front )
  589. {
  590. // valid, point-sized
  591. if ( boost::size(ls2_ref) == 2 )
  592. {
  593. bool const front_b = is_endpoint_on_boundary<boundary_front>(turn.point, boundary_checker);
  594. if ( front_b )
  595. {
  596. update<boundary, interior, '0', transpose_result>(res);
  597. }
  598. else
  599. {
  600. update<interior, interior, '0', transpose_result>(res);
  601. }
  602. // operation 'c' should be last for the same IP so we know that the next point won't be the same
  603. update<interior, exterior, '1', transpose_result>(res);
  604. m_degenerated_turn_ptr = boost::addressof(turn);
  605. }
  606. }
  607. else if ( turn.operations[op_id].position == overlay::position_back )
  608. {
  609. // valid, point-sized
  610. if ( boost::size(ls2_ref) == 2 )
  611. {
  612. update<interior, exterior, '1', transpose_result>(res);
  613. bool const back_b = is_endpoint_on_boundary<boundary_back>(turn.point, boundary_checker);
  614. if ( back_b )
  615. {
  616. update<boundary, interior, '0', transpose_result>(res);
  617. }
  618. else
  619. {
  620. update<interior, interior, '0', transpose_result>(res);
  621. }
  622. if ( first_in_range )
  623. {
  624. //BOOST_GEOMETRY_ASSERT(!boost::empty(ls1_ref));
  625. bool const front_b = is_endpoint_on_boundary<boundary_front>(
  626. range::front(ls1_ref), boundary_checker);
  627. if ( front_b )
  628. {
  629. update<boundary, exterior, '0', transpose_result>(res);
  630. }
  631. }
  632. }
  633. }
  634. else if ( turn.operations[op_id].position == overlay::position_middle
  635. && turn.operations[other_op_id].position == overlay::position_middle )
  636. {
  637. update<interior, interior, '0', transpose_result>(res);
  638. // here we don't know which one is degenerated
  639. bool const is_point1 = boost::size(ls1_ref) == 2
  640. && equals::equals_point_point(range::front(ls1_ref),
  641. range::back(ls1_ref),
  642. equals_strategy1_type());
  643. bool const is_point2 = boost::size(ls2_ref) == 2
  644. && equals::equals_point_point(range::front(ls2_ref),
  645. range::back(ls2_ref),
  646. equals_strategy2_type());
  647. // if the second one is degenerated
  648. if ( !is_point1 && is_point2 )
  649. {
  650. update<interior, exterior, '1', transpose_result>(res);
  651. if ( first_in_range )
  652. {
  653. //BOOST_GEOMETRY_ASSERT(!boost::empty(ls1_ref));
  654. bool const front_b = is_endpoint_on_boundary<boundary_front>(
  655. range::front(ls1_ref), boundary_checker);
  656. if ( front_b )
  657. {
  658. update<boundary, exterior, '0', transpose_result>(res);
  659. }
  660. }
  661. m_degenerated_turn_ptr = boost::addressof(turn);
  662. }
  663. }
  664. // NOTE: other.position == front and other.position == back
  665. // will be handled later, for the other geometry
  666. }
  667. private:
  668. exit_watcher<TurnInfo, OpId> m_exit_watcher;
  669. segment_watcher<same_single> m_seg_watcher;
  670. const TurnInfo * m_previous_turn_ptr;
  671. overlay::operation_type m_previous_operation;
  672. const TurnInfo * m_degenerated_turn_ptr;
  673. bool m_collinear_spike_exit;
  674. };
  675. template <typename Result,
  676. typename TurnIt,
  677. typename Analyser,
  678. typename Geometry,
  679. typename OtherGeometry,
  680. typename BoundaryChecker,
  681. typename OtherBoundaryChecker>
  682. static inline void analyse_each_turn(Result & res,
  683. Analyser & analyser,
  684. TurnIt first, TurnIt last,
  685. Geometry const& geometry,
  686. OtherGeometry const& other_geometry,
  687. BoundaryChecker const& boundary_checker,
  688. OtherBoundaryChecker const& other_boundary_checker)
  689. {
  690. if ( first == last )
  691. return;
  692. for ( TurnIt it = first ; it != last ; ++it )
  693. {
  694. analyser.apply(res, it,
  695. geometry, other_geometry,
  696. boundary_checker, other_boundary_checker);
  697. if ( BOOST_GEOMETRY_CONDITION( res.interrupt ) )
  698. return;
  699. }
  700. analyser.apply(res, first, last,
  701. geometry, other_geometry,
  702. boundary_checker, other_boundary_checker);
  703. }
  704. };
  705. }} // namespace detail::relate
  706. #endif // DOXYGEN_NO_DETAIL
  707. }} // namespace boost::geometry
  708. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_LINEAR_HPP