get_turn_info_helpers.hpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  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_OVERLAY_GET_TURN_INFO_HELPERS_HPP
  10. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HELPERS_HPP
  11. #include <boost/geometry/algorithms/detail/direction_code.hpp>
  12. #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
  13. #include <boost/geometry/algorithms/detail/recalculate.hpp>
  14. #include <boost/geometry/core/assert.hpp>
  15. #include <boost/geometry/geometries/segment.hpp> // referring_segment
  16. #include <boost/geometry/policies/relate/direction.hpp>
  17. #include <boost/geometry/policies/relate/intersection_points.hpp>
  18. #include <boost/geometry/policies/relate/tupled.hpp>
  19. #include <boost/geometry/policies/robustness/rescale_policy_tags.hpp>
  20. #include <boost/geometry/strategies/intersection_result.hpp>
  21. namespace boost { namespace geometry {
  22. #ifndef DOXYGEN_NO_DETAIL
  23. namespace detail { namespace overlay {
  24. enum turn_position { position_middle, position_front, position_back };
  25. template <typename Point, typename SegmentRatio>
  26. struct turn_operation_linear
  27. : public turn_operation<Point, SegmentRatio>
  28. {
  29. turn_operation_linear()
  30. : position(position_middle)
  31. , is_collinear(false)
  32. {}
  33. turn_position position;
  34. bool is_collinear; // valid only for Linear geometry
  35. };
  36. template
  37. <
  38. typename TurnPointCSTag,
  39. typename UniqueSubRange1,
  40. typename UniqueSubRange2,
  41. typename SideStrategy
  42. >
  43. struct side_calculator
  44. {
  45. typedef typename UniqueSubRange1::point_type point1_type;
  46. typedef typename UniqueSubRange2::point_type point2_type;
  47. inline side_calculator(UniqueSubRange1 const& range_p,
  48. UniqueSubRange2 const& range_q,
  49. SideStrategy const& side_strategy)
  50. : m_side_strategy(side_strategy)
  51. , m_range_p(range_p)
  52. , m_range_q(range_q)
  53. {}
  54. inline int pk_wrt_p1() const { return m_side_strategy.apply(get_pi(), get_pj(), get_pk()); }
  55. inline int pk_wrt_q1() const { return m_side_strategy.apply(get_qi(), get_qj(), get_pk()); }
  56. inline int qk_wrt_p1() const { return m_side_strategy.apply(get_pi(), get_pj(), get_qk()); }
  57. inline int qk_wrt_q1() const { return m_side_strategy.apply(get_qi(), get_qj(), get_qk()); }
  58. inline int pk_wrt_q2() const { return m_side_strategy.apply(get_qj(), get_qk(), get_pk()); }
  59. inline int qk_wrt_p2() const { return m_side_strategy.apply(get_pj(), get_pk(), get_qk()); }
  60. // Necessary when rescaling turns off:
  61. inline int qj_wrt_p1() const { return m_side_strategy.apply(get_pi(), get_pj(), get_qj()); }
  62. inline int qj_wrt_p2() const { return m_side_strategy.apply(get_pj(), get_pk(), get_qj()); }
  63. inline int pj_wrt_q1() const { return m_side_strategy.apply(get_qi(), get_qj(), get_pj()); }
  64. inline int pj_wrt_q2() const { return m_side_strategy.apply(get_qj(), get_qk(), get_pj()); }
  65. inline point1_type const& get_pi() const { return m_range_p.at(0); }
  66. inline point1_type const& get_pj() const { return m_range_p.at(1); }
  67. inline point1_type const& get_pk() const { return m_range_p.at(2); }
  68. inline point2_type const& get_qi() const { return m_range_q.at(0); }
  69. inline point2_type const& get_qj() const { return m_range_q.at(1); }
  70. inline point2_type const& get_qk() const { return m_range_q.at(2); }
  71. // Used side-strategy, owned by the calculator,
  72. // created from .get_side_strategy()
  73. SideStrategy m_side_strategy;
  74. // Used ranges - owned by get_turns or (for robust points) by intersection_info_base
  75. UniqueSubRange1 const& m_range_p;
  76. UniqueSubRange2 const& m_range_q;
  77. };
  78. template<typename Point, typename UniqueSubRange, typename RobustPolicy>
  79. struct robust_subrange_adapter
  80. {
  81. typedef Point point_type;
  82. robust_subrange_adapter(UniqueSubRange const& unique_sub_range,
  83. Point const& robust_point_i, Point const& robust_point_j,
  84. RobustPolicy const& robust_policy)
  85. : m_unique_sub_range(unique_sub_range)
  86. , m_robust_policy(robust_policy)
  87. , m_robust_point_i(robust_point_i)
  88. , m_robust_point_j(robust_point_j)
  89. , m_k_retrieved(false)
  90. {}
  91. std::size_t size() const { return m_unique_sub_range.size(); }
  92. //! Get precalculated point
  93. Point const& at(std::size_t index) const
  94. {
  95. BOOST_GEOMETRY_ASSERT(index < size());
  96. switch (index)
  97. {
  98. case 0 : return m_robust_point_i;
  99. case 1 : return m_robust_point_j;
  100. case 2 : return get_point_k();
  101. default : return m_robust_point_i;
  102. }
  103. }
  104. private :
  105. Point const& get_point_k() const
  106. {
  107. if (! m_k_retrieved)
  108. {
  109. geometry::recalculate(m_robust_point_k, m_unique_sub_range.at(2), m_robust_policy);
  110. m_k_retrieved = true;
  111. }
  112. return m_robust_point_k;
  113. }
  114. UniqueSubRange const& m_unique_sub_range;
  115. RobustPolicy const& m_robust_policy;
  116. Point const& m_robust_point_i;
  117. Point const& m_robust_point_j;
  118. mutable Point m_robust_point_k;
  119. mutable bool m_k_retrieved;
  120. };
  121. template
  122. <
  123. typename UniqueSubRange1, typename UniqueSubRange2,
  124. typename RobustPolicy
  125. >
  126. struct robust_point_calculator
  127. {
  128. typedef typename geometry::robust_point_type
  129. <
  130. typename UniqueSubRange1::point_type, RobustPolicy
  131. >::type robust_point1_type;
  132. typedef typename geometry::robust_point_type
  133. <
  134. typename UniqueSubRange2::point_type, RobustPolicy
  135. >::type robust_point2_type;
  136. inline robust_point_calculator(UniqueSubRange1 const& range_p,
  137. UniqueSubRange2 const& range_q,
  138. RobustPolicy const& robust_policy)
  139. : m_robust_policy(robust_policy)
  140. , m_range_p(range_p)
  141. , m_range_q(range_q)
  142. , m_pk_retrieved(false)
  143. , m_qk_retrieved(false)
  144. {
  145. // Calculate pi,pj and qi,qj which are almost always necessary
  146. // But don't calculate pk/qk yet, which is retrieved (taking
  147. // more time) and not always necessary.
  148. geometry::recalculate(m_rpi, range_p.at(0), robust_policy);
  149. geometry::recalculate(m_rpj, range_p.at(1), robust_policy);
  150. geometry::recalculate(m_rqi, range_q.at(0), robust_policy);
  151. geometry::recalculate(m_rqj, range_q.at(1), robust_policy);
  152. }
  153. inline robust_point1_type const& get_rpk() const
  154. {
  155. if (! m_pk_retrieved)
  156. {
  157. geometry::recalculate(m_rpk, m_range_p.at(2), m_robust_policy);
  158. m_pk_retrieved = true;
  159. }
  160. return m_rpk;
  161. }
  162. inline robust_point2_type const& get_rqk() const
  163. {
  164. if (! m_qk_retrieved)
  165. {
  166. geometry::recalculate(m_rqk, m_range_q.at(2), m_robust_policy);
  167. m_qk_retrieved = true;
  168. }
  169. return m_rqk;
  170. }
  171. robust_point1_type m_rpi, m_rpj;
  172. robust_point2_type m_rqi, m_rqj;
  173. private :
  174. RobustPolicy const& m_robust_policy;
  175. UniqueSubRange1 const& m_range_p;
  176. UniqueSubRange2 const& m_range_q;
  177. // On retrieval
  178. mutable robust_point1_type m_rpk;
  179. mutable robust_point2_type m_rqk;
  180. mutable bool m_pk_retrieved;
  181. mutable bool m_qk_retrieved;
  182. };
  183. // Default version (empty - specialized below)
  184. template
  185. <
  186. typename UniqueSubRange1, typename UniqueSubRange2,
  187. typename TurnPoint, typename UmbrellaStrategy,
  188. typename RobustPolicy,
  189. typename Tag = typename rescale_policy_type<RobustPolicy>::type
  190. >
  191. class intersection_info_base {};
  192. // Version with rescaling, having robust points
  193. template
  194. <
  195. typename UniqueSubRange1, typename UniqueSubRange2,
  196. typename TurnPoint, typename UmbrellaStrategy,
  197. typename RobustPolicy
  198. >
  199. class intersection_info_base<UniqueSubRange1, UniqueSubRange2,
  200. TurnPoint, UmbrellaStrategy, RobustPolicy, rescale_policy_tag>
  201. {
  202. typedef robust_point_calculator
  203. <
  204. UniqueSubRange1, UniqueSubRange2,
  205. RobustPolicy
  206. >
  207. robust_calc_type;
  208. public:
  209. typedef segment_intersection_points
  210. <
  211. TurnPoint,
  212. geometry::segment_ratio<boost::long_long_type>
  213. > intersection_point_type;
  214. typedef policies::relate::segments_tupled
  215. <
  216. policies::relate::segments_intersection_points
  217. <
  218. intersection_point_type
  219. >,
  220. policies::relate::segments_direction
  221. > intersection_policy_type;
  222. typedef typename intersection_policy_type::return_type result_type;
  223. typedef typename robust_calc_type::robust_point1_type robust_point1_type;
  224. typedef typename robust_calc_type::robust_point2_type robust_point2_type;
  225. typedef robust_subrange_adapter<robust_point1_type, UniqueSubRange1, RobustPolicy> robust_subrange1;
  226. typedef robust_subrange_adapter<robust_point2_type, UniqueSubRange2, RobustPolicy> robust_subrange2;
  227. typedef typename cs_tag<TurnPoint>::type cs_tag;
  228. typedef typename UmbrellaStrategy::side_strategy_type side_strategy_type;
  229. typedef side_calculator<cs_tag, robust_subrange1, robust_subrange2,
  230. side_strategy_type> side_calculator_type;
  231. typedef side_calculator
  232. <
  233. cs_tag, robust_subrange2, robust_subrange1,
  234. side_strategy_type
  235. > robust_swapped_side_calculator_type;
  236. intersection_info_base(UniqueSubRange1 const& range_p,
  237. UniqueSubRange2 const& range_q,
  238. UmbrellaStrategy const& umbrella_strategy,
  239. RobustPolicy const& robust_policy)
  240. : m_range_p(range_p)
  241. , m_range_q(range_q)
  242. , m_robust_calc(range_p, range_q, robust_policy)
  243. , m_robust_range_p(range_p, m_robust_calc.m_rpi, m_robust_calc.m_rpj, robust_policy)
  244. , m_robust_range_q(range_q, m_robust_calc.m_rqi, m_robust_calc.m_rqj, robust_policy)
  245. , m_side_calc(m_robust_range_p, m_robust_range_q,
  246. umbrella_strategy.get_side_strategy())
  247. , m_result(umbrella_strategy.apply(range_p, range_q,
  248. intersection_policy_type(),
  249. m_robust_range_p, m_robust_range_q))
  250. {}
  251. inline bool p_is_last_segment() const { return m_range_p.is_last_segment(); }
  252. inline bool q_is_last_segment() const { return m_range_q.is_last_segment(); }
  253. inline robust_point1_type const& rpi() const { return m_robust_calc.m_rpi; }
  254. inline robust_point1_type const& rpj() const { return m_robust_calc.m_rpj; }
  255. inline robust_point1_type const& rpk() const { return m_robust_calc.get_rpk(); }
  256. inline robust_point2_type const& rqi() const { return m_robust_calc.m_rqi; }
  257. inline robust_point2_type const& rqj() const { return m_robust_calc.m_rqj; }
  258. inline robust_point2_type const& rqk() const { return m_robust_calc.get_rqk(); }
  259. inline side_calculator_type const& sides() const { return m_side_calc; }
  260. robust_swapped_side_calculator_type get_swapped_sides() const
  261. {
  262. robust_swapped_side_calculator_type result(
  263. m_robust_range_q, m_robust_range_p,
  264. m_side_calc.m_side_strategy);
  265. return result;
  266. }
  267. private :
  268. // Owned by get_turns
  269. UniqueSubRange1 const& m_range_p;
  270. UniqueSubRange2 const& m_range_q;
  271. // Owned by this class
  272. robust_calc_type m_robust_calc;
  273. robust_subrange1 m_robust_range_p;
  274. robust_subrange2 m_robust_range_q;
  275. side_calculator_type m_side_calc;
  276. protected :
  277. result_type m_result;
  278. };
  279. // Version without rescaling
  280. template
  281. <
  282. typename UniqueSubRange1, typename UniqueSubRange2,
  283. typename TurnPoint, typename UmbrellaStrategy,
  284. typename RobustPolicy
  285. >
  286. class intersection_info_base<UniqueSubRange1, UniqueSubRange2,
  287. TurnPoint, UmbrellaStrategy, RobustPolicy, no_rescale_policy_tag>
  288. {
  289. public:
  290. typedef segment_intersection_points<TurnPoint> intersection_point_type;
  291. typedef policies::relate::segments_tupled
  292. <
  293. policies::relate::segments_intersection_points
  294. <
  295. intersection_point_type
  296. >,
  297. policies::relate::segments_direction
  298. > intersection_policy_type;
  299. typedef typename intersection_policy_type::return_type result_type;
  300. typedef typename UniqueSubRange1::point_type point1_type;
  301. typedef typename UniqueSubRange2::point_type point2_type;
  302. typedef typename UmbrellaStrategy::cs_tag cs_tag;
  303. typedef typename UmbrellaStrategy::side_strategy_type side_strategy_type;
  304. typedef side_calculator<cs_tag, UniqueSubRange1, UniqueSubRange2, side_strategy_type> side_calculator_type;
  305. typedef side_calculator
  306. <
  307. cs_tag, UniqueSubRange2, UniqueSubRange1,
  308. side_strategy_type
  309. > swapped_side_calculator_type;
  310. intersection_info_base(UniqueSubRange1 const& range_p,
  311. UniqueSubRange2 const& range_q,
  312. UmbrellaStrategy const& umbrella_strategy,
  313. no_rescale_policy const& )
  314. : m_range_p(range_p)
  315. , m_range_q(range_q)
  316. , m_side_calc(range_p, range_q,
  317. umbrella_strategy.get_side_strategy())
  318. , m_result(umbrella_strategy.apply(range_p, range_q, intersection_policy_type()))
  319. {}
  320. inline bool p_is_last_segment() const { return m_range_p.is_last_segment(); }
  321. inline bool q_is_last_segment() const { return m_range_q.is_last_segment(); }
  322. inline point1_type const& rpi() const { return m_side_calc.get_pi(); }
  323. inline point1_type const& rpj() const { return m_side_calc.get_pj(); }
  324. inline point1_type const& rpk() const { return m_side_calc.get_pk(); }
  325. inline point2_type const& rqi() const { return m_side_calc.get_qi(); }
  326. inline point2_type const& rqj() const { return m_side_calc.get_qj(); }
  327. inline point2_type const& rqk() const { return m_side_calc.get_qk(); }
  328. inline side_calculator_type const& sides() const { return m_side_calc; }
  329. swapped_side_calculator_type get_swapped_sides() const
  330. {
  331. swapped_side_calculator_type result(
  332. m_range_q, m_range_p,
  333. m_side_calc.m_side_strategy);
  334. return result;
  335. }
  336. private :
  337. // Owned by get_turns
  338. UniqueSubRange1 const& m_range_p;
  339. UniqueSubRange2 const& m_range_q;
  340. // Owned by this class
  341. side_calculator_type m_side_calc;
  342. protected :
  343. result_type m_result;
  344. };
  345. template
  346. <
  347. typename UniqueSubRange1, typename UniqueSubRange2,
  348. typename TurnPoint,
  349. typename UmbrellaStrategy,
  350. typename RobustPolicy
  351. >
  352. class intersection_info
  353. : public intersection_info_base<UniqueSubRange1, UniqueSubRange2,
  354. TurnPoint, UmbrellaStrategy, RobustPolicy>
  355. {
  356. typedef intersection_info_base<UniqueSubRange1, UniqueSubRange2,
  357. TurnPoint, UmbrellaStrategy, RobustPolicy> base;
  358. public:
  359. typedef typename UniqueSubRange1::point_type point1_type;
  360. typedef typename UniqueSubRange2::point_type point2_type;
  361. typedef UmbrellaStrategy intersection_strategy_type;
  362. typedef typename UmbrellaStrategy::side_strategy_type side_strategy_type;
  363. typedef typename UmbrellaStrategy::cs_tag cs_tag;
  364. typedef typename base::side_calculator_type side_calculator_type;
  365. typedef typename base::result_type result_type;
  366. typedef typename boost::tuples::element<0, result_type>::type i_info_type; // intersection_info
  367. typedef typename boost::tuples::element<1, result_type>::type d_info_type; // dir_info
  368. intersection_info(UniqueSubRange1 const& range_p,
  369. UniqueSubRange2 const& range_q,
  370. UmbrellaStrategy const& umbrella_strategy,
  371. RobustPolicy const& robust_policy)
  372. : base(range_p, range_q,
  373. umbrella_strategy, robust_policy)
  374. , m_intersection_strategy(umbrella_strategy)
  375. , m_robust_policy(robust_policy)
  376. {}
  377. inline result_type const& result() const { return base::m_result; }
  378. inline i_info_type const& i_info() const { return base::m_result.template get<0>(); }
  379. inline d_info_type const& d_info() const { return base::m_result.template get<1>(); }
  380. inline side_strategy_type get_side_strategy() const
  381. {
  382. return m_intersection_strategy.get_side_strategy();
  383. }
  384. // TODO: it's more like is_spike_ip_p
  385. inline bool is_spike_p() const
  386. {
  387. if (base::p_is_last_segment())
  388. {
  389. return false;
  390. }
  391. if (base::sides().pk_wrt_p1() == 0)
  392. {
  393. // p: pi--------pj--------pk
  394. // or: pi----pk==pj
  395. if (! is_ip_j<0>())
  396. {
  397. return false;
  398. }
  399. // TODO: why is q used to determine spike property in p?
  400. bool const has_qk = ! base::q_is_last_segment();
  401. int const qk_p1 = has_qk ? base::sides().qk_wrt_p1() : 0;
  402. int const qk_p2 = has_qk ? base::sides().qk_wrt_p2() : 0;
  403. if (qk_p1 == -qk_p2)
  404. {
  405. if (qk_p1 == 0)
  406. {
  407. // qk is collinear with both p1 and p2,
  408. // verify if pk goes backwards w.r.t. pi/pj
  409. return direction_code<cs_tag>(base::rpi(), base::rpj(), base::rpk()) == -1;
  410. }
  411. // qk is at opposite side of p1/p2, therefore
  412. // p1/p2 (collinear) are opposite and form a spike
  413. return true;
  414. }
  415. }
  416. return false;
  417. }
  418. inline bool is_spike_q() const
  419. {
  420. if (base::q_is_last_segment())
  421. {
  422. return false;
  423. }
  424. // See comments at is_spike_p
  425. if (base::sides().qk_wrt_q1() == 0)
  426. {
  427. if (! is_ip_j<1>())
  428. {
  429. return false;
  430. }
  431. // TODO: why is p used to determine spike property in q?
  432. bool const has_pk = ! base::p_is_last_segment();
  433. int const pk_q1 = has_pk ? base::sides().pk_wrt_q1() : 0;
  434. int const pk_q2 = has_pk ? base::sides().pk_wrt_q2() : 0;
  435. if (pk_q1 == -pk_q2)
  436. {
  437. if (pk_q1 == 0)
  438. {
  439. return direction_code<cs_tag>(base::rqi(), base::rqj(), base::rqk()) == -1;
  440. }
  441. return true;
  442. }
  443. }
  444. return false;
  445. }
  446. private:
  447. template <std::size_t OpId>
  448. bool is_ip_j() const
  449. {
  450. int arrival = d_info().arrival[OpId];
  451. bool same_dirs = d_info().dir_a == 0 && d_info().dir_b == 0;
  452. if (same_dirs)
  453. {
  454. if (i_info().count == 2)
  455. {
  456. return arrival != -1;
  457. }
  458. else
  459. {
  460. return arrival == 0;
  461. }
  462. }
  463. else
  464. {
  465. return arrival == 1;
  466. }
  467. }
  468. UmbrellaStrategy const& m_intersection_strategy;
  469. RobustPolicy const& m_robust_policy;
  470. };
  471. }} // namespace detail::overlay
  472. #endif // DOXYGEN_NO_DETAIL
  473. }} // namespace boost::geometry
  474. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HELPERS_HPP