areal_areal.hpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869
  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-2022.
  4. // Modifications copyright (c) 2013-2022 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_AREAL_AREAL_HPP
  10. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_AREAL_AREAL_HPP
  11. #include <boost/geometry/core/topological_dimension.hpp>
  12. #include <boost/geometry/util/condition.hpp>
  13. #include <boost/geometry/util/range.hpp>
  14. #include <boost/geometry/algorithms/num_interior_rings.hpp>
  15. #include <boost/geometry/algorithms/detail/point_on_border.hpp>
  16. #include <boost/geometry/algorithms/detail/sub_range.hpp>
  17. #include <boost/geometry/algorithms/detail/single_geometry.hpp>
  18. #include <boost/geometry/algorithms/detail/relate/point_geometry.hpp>
  19. #include <boost/geometry/algorithms/detail/relate/turns.hpp>
  20. #include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp>
  21. #include <boost/geometry/algorithms/detail/relate/follow_helpers.hpp>
  22. #include <boost/geometry/geometries/helper_geometry.hpp>
  23. #include <boost/geometry/util/numeric_cast.hpp>
  24. namespace boost { namespace geometry
  25. {
  26. #ifndef DOXYGEN_NO_DETAIL
  27. namespace detail { namespace relate {
  28. // WARNING!
  29. // TODO: In the worst case calling this Pred in a loop for MultiPolygon/MultiPolygon may take O(NM)
  30. // Use the rtree in this case!
  31. // may be used to set EI and EB for an Areal geometry for which no turns were generated
  32. template
  33. <
  34. typename OtherAreal,
  35. typename Result,
  36. typename PointInArealStrategy,
  37. bool TransposeResult
  38. >
  39. class no_turns_aa_pred
  40. {
  41. public:
  42. no_turns_aa_pred(OtherAreal const& other_areal,
  43. Result & res,
  44. PointInArealStrategy const& point_in_areal_strategy)
  45. : m_result(res)
  46. , m_point_in_areal_strategy(point_in_areal_strategy)
  47. , m_other_areal(other_areal)
  48. , m_flags(0)
  49. {
  50. // check which relations must be analysed
  51. if ( ! may_update<interior, interior, '2', TransposeResult>(m_result)
  52. && ! may_update<boundary, interior, '1', TransposeResult>(m_result)
  53. && ! may_update<exterior, interior, '2', TransposeResult>(m_result) )
  54. {
  55. m_flags |= 1;
  56. }
  57. if ( ! may_update<interior, exterior, '2', TransposeResult>(m_result)
  58. && ! may_update<boundary, exterior, '1', TransposeResult>(m_result) )
  59. {
  60. m_flags |= 2;
  61. }
  62. }
  63. template <typename Areal>
  64. bool operator()(Areal const& areal)
  65. {
  66. using detail::within::point_in_geometry;
  67. // if those flags are set nothing will change
  68. if ( m_flags == 3 )
  69. {
  70. return false;
  71. }
  72. using point_type = typename geometry::point_type<Areal>::type;
  73. typename helper_geometry<point_type>::type pt;
  74. bool const ok = geometry::point_on_border(pt, areal);
  75. // TODO: for now ignore, later throw an exception?
  76. if ( !ok )
  77. {
  78. return true;
  79. }
  80. // check if the areal is inside the other_areal
  81. // TODO: This is O(N)
  82. // Run in a loop O(NM) - optimize!
  83. int const pig = point_in_geometry(pt,
  84. m_other_areal,
  85. m_point_in_areal_strategy);
  86. //BOOST_GEOMETRY_ASSERT( pig != 0 );
  87. // inside
  88. if ( pig > 0 )
  89. {
  90. update<interior, interior, '2', TransposeResult>(m_result);
  91. update<boundary, interior, '1', TransposeResult>(m_result);
  92. update<exterior, interior, '2', TransposeResult>(m_result);
  93. m_flags |= 1;
  94. // TODO: OPTIMIZE!
  95. // Only the interior rings of other ONE single geometry must be checked
  96. // NOT all geometries
  97. // Check if any interior ring is outside
  98. ring_identifier ring_id(0, -1, 0);
  99. std::size_t const irings_count = geometry::num_interior_rings(areal);
  100. for ( ; static_cast<std::size_t>(ring_id.ring_index) < irings_count ;
  101. ++ring_id.ring_index )
  102. {
  103. typename detail::sub_range_return_type<Areal const>::type
  104. range_ref = detail::sub_range(areal, ring_id);
  105. if ( boost::empty(range_ref) )
  106. {
  107. // TODO: throw exception?
  108. continue; // ignore
  109. }
  110. // TODO: O(N)
  111. // Optimize!
  112. int const hpig = point_in_geometry(range::front(range_ref),
  113. m_other_areal,
  114. m_point_in_areal_strategy);
  115. // hole outside
  116. if ( hpig < 0 )
  117. {
  118. update<interior, exterior, '2', TransposeResult>(m_result);
  119. update<boundary, exterior, '1', TransposeResult>(m_result);
  120. m_flags |= 2;
  121. break;
  122. }
  123. }
  124. }
  125. // outside
  126. else
  127. {
  128. update<interior, exterior, '2', TransposeResult>(m_result);
  129. update<boundary, exterior, '1', TransposeResult>(m_result);
  130. m_flags |= 2;
  131. // Check if any interior ring is inside
  132. ring_identifier ring_id(0, -1, 0);
  133. std::size_t const irings_count = geometry::num_interior_rings(areal);
  134. for ( ; static_cast<std::size_t>(ring_id.ring_index) < irings_count ;
  135. ++ring_id.ring_index )
  136. {
  137. typename detail::sub_range_return_type<Areal const>::type
  138. range_ref = detail::sub_range(areal, ring_id);
  139. if ( boost::empty(range_ref) )
  140. {
  141. // TODO: throw exception?
  142. continue; // ignore
  143. }
  144. // TODO: O(N)
  145. // Optimize!
  146. int const hpig = point_in_geometry(range::front(range_ref),
  147. m_other_areal,
  148. m_point_in_areal_strategy);
  149. // hole inside
  150. if ( hpig > 0 )
  151. {
  152. update<interior, interior, '2', TransposeResult>(m_result);
  153. update<boundary, interior, '1', TransposeResult>(m_result);
  154. update<exterior, interior, '2', TransposeResult>(m_result);
  155. m_flags |= 1;
  156. break;
  157. }
  158. }
  159. }
  160. return m_flags != 3 && !m_result.interrupt;
  161. }
  162. private:
  163. Result & m_result;
  164. PointInArealStrategy const& m_point_in_areal_strategy;
  165. OtherAreal const& m_other_areal;
  166. int m_flags;
  167. };
  168. // The implementation of an algorithm calculating relate() for A/A
  169. template <typename Geometry1, typename Geometry2>
  170. struct areal_areal
  171. {
  172. // check Linear / Areal
  173. BOOST_STATIC_ASSERT(topological_dimension<Geometry1>::value == 2
  174. && topological_dimension<Geometry2>::value == 2);
  175. static const bool interruption_enabled = true;
  176. template <typename Result, typename Strategy>
  177. static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
  178. Result & result,
  179. Strategy const& strategy)
  180. {
  181. // TODO: If Areal geometry may have infinite size, change the following line:
  182. update<exterior, exterior, result_dimension<Geometry2>::value>(result);// FFFFFFFFd, d in [1,9] or T
  183. if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
  184. return;
  185. // get and analyse turns
  186. using turn_type = typename turns::get_turns
  187. <
  188. Geometry1, Geometry2
  189. >::template turn_info_type<Strategy>::type;
  190. std::vector<turn_type> turns;
  191. interrupt_policy_areal_areal<Result> interrupt_policy(geometry1, geometry2, result);
  192. turns::get_turns<Geometry1, Geometry2>::apply(turns, geometry1, geometry2, interrupt_policy, strategy);
  193. if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
  194. return;
  195. no_turns_aa_pred<Geometry2, Result, Strategy, false>
  196. pred1(geometry2, result, strategy);
  197. for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1);
  198. if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
  199. return;
  200. no_turns_aa_pred<Geometry1, Result, Strategy, true>
  201. pred2(geometry1, result, strategy);
  202. for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2);
  203. if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
  204. return;
  205. if ( turns.empty() )
  206. return;
  207. if ( may_update<interior, interior, '2'>(result)
  208. || may_update<interior, exterior, '2'>(result)
  209. || may_update<boundary, interior, '1'>(result)
  210. || may_update<boundary, exterior, '1'>(result)
  211. || may_update<exterior, interior, '2'>(result) )
  212. {
  213. // sort turns
  214. using less_t = turns::less<0, turns::less_op_areal_areal<0>, Strategy>;
  215. std::sort(turns.begin(), turns.end(), less_t());
  216. /*if ( may_update<interior, exterior, '2'>(result)
  217. || may_update<boundary, exterior, '1'>(result)
  218. || may_update<boundary, interior, '1'>(result)
  219. || may_update<exterior, interior, '2'>(result) )*/
  220. {
  221. // analyse sorted turns
  222. turns_analyser<turn_type, 0> analyser;
  223. analyse_each_turn(result, analyser, turns.begin(), turns.end(), strategy);
  224. if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
  225. return;
  226. }
  227. if ( may_update<interior, interior, '2'>(result)
  228. || may_update<interior, exterior, '2'>(result)
  229. || may_update<boundary, interior, '1'>(result)
  230. || may_update<boundary, exterior, '1'>(result)
  231. || may_update<exterior, interior, '2'>(result) )
  232. {
  233. // analyse rings for which turns were not generated
  234. // or only i/i or u/u was generated
  235. uncertain_rings_analyser<0, Result, Geometry1, Geometry2, Strategy>
  236. rings_analyser(result, geometry1, geometry2, strategy);
  237. analyse_uncertain_rings<0>::apply(rings_analyser, turns.begin(), turns.end());
  238. if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
  239. return;
  240. }
  241. }
  242. if ( may_update<interior, interior, '2', true>(result)
  243. || may_update<interior, exterior, '2', true>(result)
  244. || may_update<boundary, interior, '1', true>(result)
  245. || may_update<boundary, exterior, '1', true>(result)
  246. || may_update<exterior, interior, '2', true>(result) )
  247. {
  248. // sort turns
  249. using less_t = turns::less<1, turns::less_op_areal_areal<1>, Strategy>;
  250. std::sort(turns.begin(), turns.end(), less_t());
  251. /*if ( may_update<interior, exterior, '2', true>(result)
  252. || may_update<boundary, exterior, '1', true>(result)
  253. || may_update<boundary, interior, '1', true>(result)
  254. || may_update<exterior, interior, '2', true>(result) )*/
  255. {
  256. // analyse sorted turns
  257. turns_analyser<turn_type, 1> analyser;
  258. analyse_each_turn(result, analyser, turns.begin(), turns.end(), strategy);
  259. if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
  260. return;
  261. }
  262. if ( may_update<interior, interior, '2', true>(result)
  263. || may_update<interior, exterior, '2', true>(result)
  264. || may_update<boundary, interior, '1', true>(result)
  265. || may_update<boundary, exterior, '1', true>(result)
  266. || may_update<exterior, interior, '2', true>(result) )
  267. {
  268. // analyse rings for which turns were not generated
  269. // or only i/i or u/u was generated
  270. uncertain_rings_analyser<1, Result, Geometry2, Geometry1, Strategy>
  271. rings_analyser(result, geometry2, geometry1, strategy);
  272. analyse_uncertain_rings<1>::apply(rings_analyser, turns.begin(), turns.end());
  273. //if ( result.interrupt )
  274. // return;
  275. }
  276. }
  277. }
  278. // interrupt policy which may be passed to get_turns to interrupt the analysis
  279. // based on the info in the passed result/mask
  280. template <typename Result>
  281. class interrupt_policy_areal_areal
  282. {
  283. public:
  284. static bool const enabled = true;
  285. interrupt_policy_areal_areal(Geometry1 const& geometry1,
  286. Geometry2 const& geometry2,
  287. Result & result)
  288. : m_result(result)
  289. , m_geometry1(geometry1)
  290. , m_geometry2(geometry2)
  291. {}
  292. template <typename Range>
  293. inline bool apply(Range const& turns)
  294. {
  295. for (auto it = boost::begin(turns) ; it != boost::end(turns) ; ++it)
  296. {
  297. per_turn<0>(*it);
  298. per_turn<1>(*it);
  299. }
  300. return m_result.interrupt;
  301. }
  302. private:
  303. template <std::size_t OpId, typename Turn>
  304. inline void per_turn(Turn const& turn)
  305. {
  306. //static const std::size_t other_op_id = (OpId + 1) % 2;
  307. static const bool transpose_result = OpId != 0;
  308. overlay::operation_type const op = turn.operations[OpId].operation;
  309. if ( op == overlay::operation_union )
  310. {
  311. // ignore u/u
  312. /*if ( turn.operations[other_op_id].operation != overlay::operation_union )
  313. {
  314. update<interior, exterior, '2', transpose_result>(m_result);
  315. update<boundary, exterior, '1', transpose_result>(m_result);
  316. }*/
  317. update<boundary, boundary, '0', transpose_result>(m_result);
  318. }
  319. else if ( op == overlay::operation_intersection )
  320. {
  321. // ignore i/i
  322. /*if ( turn.operations[other_op_id].operation != overlay::operation_intersection )
  323. {
  324. // not correct e.g. for G1 touching G2 in a point where a hole is touching the exterior ring
  325. // in this case 2 turns i/... and u/u will be generated for this IP
  326. //update<interior, interior, '2', transpose_result>(m_result);
  327. //update<boundary, interior, '1', transpose_result>(m_result);
  328. }*/
  329. update<boundary, boundary, '0', transpose_result>(m_result);
  330. }
  331. else if ( op == overlay::operation_continue )
  332. {
  333. update<boundary, boundary, '1', transpose_result>(m_result);
  334. update<interior, interior, '2', transpose_result>(m_result);
  335. }
  336. else if ( op == overlay::operation_blocked )
  337. {
  338. update<boundary, boundary, '1', transpose_result>(m_result);
  339. update<interior, exterior, '2', transpose_result>(m_result);
  340. }
  341. }
  342. Result & m_result;
  343. Geometry1 const& m_geometry1;
  344. Geometry2 const& m_geometry2;
  345. };
  346. // This analyser should be used like Input or SinglePass Iterator
  347. // IMPORTANT! It should be called also for the end iterator - last
  348. template <typename TurnInfo, std::size_t OpId>
  349. class turns_analyser
  350. {
  351. typedef typename TurnInfo::point_type turn_point_type;
  352. static const std::size_t op_id = OpId;
  353. static const std::size_t other_op_id = (OpId + 1) % 2;
  354. static const bool transpose_result = OpId != 0;
  355. public:
  356. turns_analyser()
  357. : m_previous_turn_ptr(0)
  358. , m_previous_operation(overlay::operation_none)
  359. , m_enter_detected(false)
  360. , m_exit_detected(false)
  361. {}
  362. template <typename Result, typename TurnIt, typename EqPPStrategy>
  363. void apply(Result & result, TurnIt it, EqPPStrategy const& strategy)
  364. {
  365. //BOOST_GEOMETRY_ASSERT( it != last );
  366. overlay::operation_type const op = it->operations[op_id].operation;
  367. if ( op != overlay::operation_union
  368. && op != overlay::operation_intersection
  369. && op != overlay::operation_blocked
  370. && op != overlay::operation_continue )
  371. {
  372. return;
  373. }
  374. segment_identifier const& seg_id = it->operations[op_id].seg_id;
  375. //segment_identifier const& other_id = it->operations[other_op_id].seg_id;
  376. const bool first_in_range = m_seg_watcher.update(seg_id);
  377. if ( m_previous_turn_ptr )
  378. {
  379. if ( m_exit_detected /*m_previous_operation == overlay::operation_union*/ )
  380. {
  381. // real exit point - may be multiple
  382. if ( first_in_range
  383. || ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it, strategy) )
  384. {
  385. update_exit(result);
  386. m_exit_detected = false;
  387. }
  388. // fake exit point, reset state
  389. else if ( op != overlay::operation_union )
  390. {
  391. m_exit_detected = false;
  392. }
  393. }
  394. /*else*/
  395. if ( m_enter_detected /*m_previous_operation == overlay::operation_intersection*/ )
  396. {
  397. // real entry point
  398. if ( first_in_range
  399. || ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it, strategy) )
  400. {
  401. update_enter(result);
  402. m_enter_detected = false;
  403. }
  404. // fake entry point, reset state
  405. else if ( op != overlay::operation_intersection )
  406. {
  407. m_enter_detected = false;
  408. }
  409. }
  410. }
  411. if ( op == overlay::operation_union )
  412. {
  413. // already set in interrupt policy
  414. //update<boundary, boundary, '0', transpose_result>(m_result);
  415. // ignore u/u
  416. //if ( it->operations[other_op_id].operation != overlay::operation_union )
  417. {
  418. m_exit_detected = true;
  419. }
  420. }
  421. else if ( op == overlay::operation_intersection )
  422. {
  423. // ignore i/i
  424. if ( it->operations[other_op_id].operation != overlay::operation_intersection )
  425. {
  426. // this was set in the interrupt policy but it was wrong
  427. // also here it's wrong since it may be a fake entry point
  428. //update<interior, interior, '2', transpose_result>(result);
  429. // already set in interrupt policy
  430. //update<boundary, boundary, '0', transpose_result>(result);
  431. m_enter_detected = true;
  432. }
  433. }
  434. else if ( op == overlay::operation_blocked )
  435. {
  436. // already set in interrupt policy
  437. }
  438. else // if ( op == overlay::operation_continue )
  439. {
  440. // already set in interrupt policy
  441. }
  442. // store ref to previously analysed (valid) turn
  443. m_previous_turn_ptr = boost::addressof(*it);
  444. // and previously analysed (valid) operation
  445. m_previous_operation = op;
  446. }
  447. // it == last
  448. template <typename Result>
  449. void apply(Result & result)
  450. {
  451. //BOOST_GEOMETRY_ASSERT( first != last );
  452. if ( m_exit_detected /*m_previous_operation == overlay::operation_union*/ )
  453. {
  454. update_exit(result);
  455. m_exit_detected = false;
  456. }
  457. if ( m_enter_detected /*m_previous_operation == overlay::operation_intersection*/ )
  458. {
  459. update_enter(result);
  460. m_enter_detected = false;
  461. }
  462. }
  463. template <typename Result>
  464. static inline void update_exit(Result & result)
  465. {
  466. update<interior, exterior, '2', transpose_result>(result);
  467. update<boundary, exterior, '1', transpose_result>(result);
  468. }
  469. template <typename Result>
  470. static inline void update_enter(Result & result)
  471. {
  472. update<interior, interior, '2', transpose_result>(result);
  473. update<boundary, interior, '1', transpose_result>(result);
  474. update<exterior, interior, '2', transpose_result>(result);
  475. }
  476. private:
  477. segment_watcher<same_ring> m_seg_watcher;
  478. TurnInfo * m_previous_turn_ptr;
  479. overlay::operation_type m_previous_operation;
  480. bool m_enter_detected;
  481. bool m_exit_detected;
  482. };
  483. // call analyser.apply() for each turn in range
  484. // IMPORTANT! The analyser is also called for the end iterator - last
  485. template
  486. <
  487. typename Result,
  488. typename Analyser,
  489. typename TurnIt,
  490. typename EqPPStrategy
  491. >
  492. static inline void analyse_each_turn(Result & res,
  493. Analyser & analyser,
  494. TurnIt first, TurnIt last,
  495. EqPPStrategy const& strategy)
  496. {
  497. if ( first == last )
  498. return;
  499. for ( TurnIt it = first ; it != last ; ++it )
  500. {
  501. analyser.apply(res, it, strategy);
  502. if ( BOOST_GEOMETRY_CONDITION(res.interrupt) )
  503. return;
  504. }
  505. analyser.apply(res);
  506. }
  507. template
  508. <
  509. std::size_t OpId,
  510. typename Result,
  511. typename Geometry,
  512. typename OtherGeometry,
  513. typename PointInArealStrategy
  514. >
  515. class uncertain_rings_analyser
  516. {
  517. static const bool transpose_result = OpId != 0;
  518. static const int other_id = (OpId + 1) % 2;
  519. public:
  520. inline uncertain_rings_analyser(Result & result,
  521. Geometry const& geom,
  522. OtherGeometry const& other_geom,
  523. PointInArealStrategy const& point_in_areal_strategy)
  524. : geometry(geom)
  525. , other_geometry(other_geom)
  526. , interrupt(result.interrupt) // just in case, could be false as well
  527. , m_result(result)
  528. , m_point_in_areal_strategy(point_in_areal_strategy)
  529. , m_flags(0)
  530. {
  531. // check which relations must be analysed
  532. // NOTE: 1 and 4 could probably be connected
  533. if ( ! may_update<interior, interior, '2', transpose_result>(m_result) )
  534. {
  535. m_flags |= 1;
  536. }
  537. if ( ! may_update<interior, exterior, '2', transpose_result>(m_result)
  538. && ! may_update<boundary, exterior, '1', transpose_result>(m_result) )
  539. {
  540. m_flags |= 2;
  541. }
  542. if ( ! may_update<boundary, interior, '1', transpose_result>(m_result)
  543. && ! may_update<exterior, interior, '2', transpose_result>(m_result) )
  544. {
  545. m_flags |= 4;
  546. }
  547. }
  548. inline void no_turns(segment_identifier const& seg_id)
  549. {
  550. // if those flags are set nothing will change
  551. if ( m_flags == 7 )
  552. {
  553. return;
  554. }
  555. auto const& sub_range = detail::sub_range(geometry, seg_id);
  556. if ( boost::empty(sub_range) )
  557. {
  558. // TODO: throw an exception?
  559. return; // ignore
  560. }
  561. // TODO: possible optimization
  562. // if the range is an interior ring we may use other IPs generated for this single geometry
  563. // to know which other single geometries should be checked
  564. // TODO: optimize! e.g. use spatial index
  565. // O(N) - running it in a loop gives O(NM)
  566. using detail::within::point_in_geometry;
  567. int const pig = point_in_geometry(range::front(sub_range),
  568. other_geometry,
  569. m_point_in_areal_strategy);
  570. //BOOST_GEOMETRY_ASSERT(pig != 0);
  571. if ( pig > 0 )
  572. {
  573. update<interior, interior, '2', transpose_result>(m_result);
  574. m_flags |= 1;
  575. update<boundary, interior, '1', transpose_result>(m_result);
  576. update<exterior, interior, '2', transpose_result>(m_result);
  577. m_flags |= 4;
  578. }
  579. else
  580. {
  581. update<boundary, exterior, '1', transpose_result>(m_result);
  582. update<interior, exterior, '2', transpose_result>(m_result);
  583. m_flags |= 2;
  584. }
  585. // TODO: break if all things are set
  586. // also some of them could be checked outside, before the analysis
  587. // In this case we shouldn't relay just on dummy flags
  588. // Flags should be initialized with proper values
  589. // or the result should be checked directly
  590. // THIS IS ALSO TRUE FOR OTHER ANALYSERS! in L/L and L/A
  591. interrupt = m_flags == 7 || m_result.interrupt;
  592. }
  593. template <typename TurnIt>
  594. inline void turns(TurnIt first, TurnIt last)
  595. {
  596. // if those flags are set nothing will change
  597. if ( (m_flags & 6) == 6 )
  598. {
  599. return;
  600. }
  601. bool found_ii = false;
  602. bool found_uu = false;
  603. for ( TurnIt it = first ; it != last ; ++it )
  604. {
  605. if ( it->operations[0].operation == overlay::operation_intersection
  606. && it->operations[1].operation == overlay::operation_intersection )
  607. {
  608. found_ii = true;
  609. }
  610. else if ( it->operations[0].operation == overlay::operation_union
  611. && it->operations[1].operation == overlay::operation_union )
  612. {
  613. found_uu = true;
  614. }
  615. else // ignore
  616. {
  617. return; // don't interrupt
  618. }
  619. }
  620. // only i/i was generated for this ring
  621. if ( found_ii )
  622. {
  623. update<interior, interior, '2', transpose_result>(m_result);
  624. m_flags |= 1;
  625. //update<boundary, boundary, '0', transpose_result>(m_result);
  626. update<boundary, interior, '1', transpose_result>(m_result);
  627. update<exterior, interior, '2', transpose_result>(m_result);
  628. m_flags |= 4;
  629. }
  630. // only u/u was generated for this ring
  631. if ( found_uu )
  632. {
  633. update<boundary, exterior, '1', transpose_result>(m_result);
  634. update<interior, exterior, '2', transpose_result>(m_result);
  635. m_flags |= 2;
  636. }
  637. interrupt = m_flags == 7 || m_result.interrupt; // interrupt if the result won't be changed in the future
  638. }
  639. Geometry const& geometry;
  640. OtherGeometry const& other_geometry;
  641. bool interrupt;
  642. private:
  643. Result & m_result;
  644. PointInArealStrategy const& m_point_in_areal_strategy;
  645. int m_flags;
  646. };
  647. template <std::size_t OpId>
  648. class analyse_uncertain_rings
  649. {
  650. public:
  651. template <typename Analyser, typename TurnIt>
  652. static inline void apply(Analyser & analyser, TurnIt first, TurnIt last)
  653. {
  654. if ( first == last )
  655. return;
  656. for_preceding_rings(analyser, *first);
  657. //analyser.per_turn(*first);
  658. TurnIt prev = first;
  659. for ( ++first ; first != last ; ++first, ++prev )
  660. {
  661. // same multi
  662. if ( prev->operations[OpId].seg_id.multi_index
  663. == first->operations[OpId].seg_id.multi_index )
  664. {
  665. // same ring
  666. if ( prev->operations[OpId].seg_id.ring_index
  667. == first->operations[OpId].seg_id.ring_index )
  668. {
  669. //analyser.per_turn(*first);
  670. }
  671. // same multi, next ring
  672. else
  673. {
  674. //analyser.end_ring(*prev);
  675. analyser.turns(prev, first);
  676. //if ( prev->operations[OpId].seg_id.ring_index + 1
  677. // < first->operations[OpId].seg_id.ring_index)
  678. {
  679. for_no_turns_rings(analyser,
  680. *first,
  681. prev->operations[OpId].seg_id.ring_index + 1,
  682. first->operations[OpId].seg_id.ring_index);
  683. }
  684. //analyser.per_turn(*first);
  685. }
  686. }
  687. // next multi
  688. else
  689. {
  690. //analyser.end_ring(*prev);
  691. analyser.turns(prev, first);
  692. for_following_rings(analyser, *prev);
  693. for_preceding_rings(analyser, *first);
  694. //analyser.per_turn(*first);
  695. }
  696. if ( analyser.interrupt )
  697. {
  698. return;
  699. }
  700. }
  701. //analyser.end_ring(*prev);
  702. analyser.turns(prev, first); // first == last
  703. for_following_rings(analyser, *prev);
  704. }
  705. private:
  706. template <typename Analyser, typename Turn>
  707. static inline void for_preceding_rings(Analyser & analyser, Turn const& turn)
  708. {
  709. segment_identifier const& seg_id = turn.operations[OpId].seg_id;
  710. for_no_turns_rings(analyser, turn, -1, seg_id.ring_index);
  711. }
  712. template <typename Analyser, typename Turn>
  713. static inline void for_following_rings(Analyser & analyser, Turn const& turn)
  714. {
  715. segment_identifier const& seg_id = turn.operations[OpId].seg_id;
  716. signed_size_type
  717. count = util::numeric_cast<signed_size_type>(
  718. geometry::num_interior_rings(
  719. detail::single_geometry(analyser.geometry, seg_id)));
  720. for_no_turns_rings(analyser, turn, seg_id.ring_index + 1, count);
  721. }
  722. template <typename Analyser, typename Turn>
  723. static inline void for_no_turns_rings(Analyser & analyser,
  724. Turn const& turn,
  725. signed_size_type first,
  726. signed_size_type last)
  727. {
  728. segment_identifier seg_id = turn.operations[OpId].seg_id;
  729. for ( seg_id.ring_index = first ; seg_id.ring_index < last ; ++seg_id.ring_index )
  730. {
  731. analyser.no_turns(seg_id);
  732. }
  733. }
  734. };
  735. };
  736. }} // namespace detail::relate
  737. #endif // DOXYGEN_NO_DETAIL
  738. }} // namespace boost::geometry
  739. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_AREAL_AREAL_HPP