areal_areal.hpp 32 KB

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