areal_areal.hpp 33 KB

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