1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
5 // This file was modified by Oracle on 2013-2020.
6 // Modifications copyright (c) 2013-2020 Oracle and/or its affiliates.
8 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
10 // Use, modification and distribution is subject to the Boost Software License,
11 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
12 // http://www.boost.org/LICENSE_1_0.txt)
14 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HELPERS_HPP
15 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HELPERS_HPP
17 #include <boost/geometry/algorithms/detail/direction_code.hpp>
18 #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
19 #include <boost/geometry/algorithms/detail/recalculate.hpp>
20 #include <boost/geometry/core/assert.hpp>
21 #include <boost/geometry/policies/relate/intersection_policy.hpp>
22 #include <boost/geometry/policies/robustness/rescale_policy_tags.hpp>
23 #include <boost/geometry/strategies/intersection_result.hpp>
25 namespace boost { namespace geometry {
27 #ifndef DOXYGEN_NO_DETAIL
28 namespace detail { namespace overlay {
30 enum turn_position { position_middle, position_front, position_back };
32 template <typename Point, typename SegmentRatio>
33 struct turn_operation_linear
34 : public turn_operation<Point, SegmentRatio>
36 turn_operation_linear()
37 : position(position_middle)
41 turn_position position;
42 bool is_collinear; // valid only for Linear geometry
47 typename UniqueSubRange1,
48 typename UniqueSubRange2,
51 struct side_calculator
53 typedef typename UniqueSubRange1::point_type point1_type;
54 typedef typename UniqueSubRange2::point_type point2_type;
55 typedef decltype(std::declval<Strategy>().side()) side_strategy_type;
57 inline side_calculator(UniqueSubRange1 const& range_p,
58 UniqueSubRange2 const& range_q,
59 Strategy const& strategy)
60 : m_side_strategy(strategy.side())
65 inline int pk_wrt_p1() const { return m_side_strategy.apply(get_pi(), get_pj(), get_pk()); }
66 inline int pk_wrt_q1() const { return m_side_strategy.apply(get_qi(), get_qj(), get_pk()); }
67 inline int qk_wrt_p1() const { return m_side_strategy.apply(get_pi(), get_pj(), get_qk()); }
68 inline int qk_wrt_q1() const { return m_side_strategy.apply(get_qi(), get_qj(), get_qk()); }
70 inline int pk_wrt_q2() const { return m_side_strategy.apply(get_qj(), get_qk(), get_pk()); }
71 inline int qk_wrt_p2() const { return m_side_strategy.apply(get_pj(), get_pk(), get_qk()); }
73 // Necessary when rescaling turns off:
74 inline int qj_wrt_p1() const { return m_side_strategy.apply(get_pi(), get_pj(), get_qj()); }
75 inline int qj_wrt_p2() const { return m_side_strategy.apply(get_pj(), get_pk(), get_qj()); }
76 inline int pj_wrt_q1() const { return m_side_strategy.apply(get_qi(), get_qj(), get_pj()); }
77 inline int pj_wrt_q2() const { return m_side_strategy.apply(get_qj(), get_qk(), get_pj()); }
79 inline point1_type const& get_pi() const { return m_range_p.at(0); }
80 inline point1_type const& get_pj() const { return m_range_p.at(1); }
81 inline point1_type const& get_pk() const { return m_range_p.at(2); }
83 inline point2_type const& get_qi() const { return m_range_q.at(0); }
84 inline point2_type const& get_qj() const { return m_range_q.at(1); }
85 inline point2_type const& get_qk() const { return m_range_q.at(2); }
87 // Used side-strategy, owned by the calculator
88 side_strategy_type m_side_strategy;
90 // Used ranges - owned by get_turns or (for robust points) by intersection_info_base
91 UniqueSubRange1 const& m_range_p;
92 UniqueSubRange2 const& m_range_q;
95 template<typename Point, typename UniqueSubRange, typename RobustPolicy>
96 struct robust_subrange_adapter
98 typedef Point point_type;
100 robust_subrange_adapter(UniqueSubRange const& unique_sub_range,
101 Point const& robust_point_i, Point const& robust_point_j,
102 RobustPolicy const& robust_policy)
104 : m_unique_sub_range(unique_sub_range)
105 , m_robust_policy(robust_policy)
106 , m_robust_point_i(robust_point_i)
107 , m_robust_point_j(robust_point_j)
108 , m_k_retrieved(false)
111 std::size_t size() const { return m_unique_sub_range.size(); }
113 //! Get precalculated point
114 Point const& at(std::size_t index) const
116 BOOST_GEOMETRY_ASSERT(index < size());
119 case 0 : return m_robust_point_i;
120 case 1 : return m_robust_point_j;
121 case 2 : return get_point_k();
122 default : return m_robust_point_i;
127 Point const& get_point_k() const
131 geometry::recalculate(m_robust_point_k, m_unique_sub_range.at(2), m_robust_policy);
132 m_k_retrieved = true;
134 return m_robust_point_k;
137 UniqueSubRange const& m_unique_sub_range;
138 RobustPolicy const& m_robust_policy;
140 Point const& m_robust_point_i;
141 Point const& m_robust_point_j;
142 mutable Point m_robust_point_k;
144 mutable bool m_k_retrieved;
149 typename UniqueSubRange1, typename UniqueSubRange2,
150 typename RobustPolicy
152 struct robust_point_calculator
154 typedef typename geometry::robust_point_type
156 typename UniqueSubRange1::point_type, RobustPolicy
157 >::type robust_point1_type;
158 typedef typename geometry::robust_point_type
160 typename UniqueSubRange2::point_type, RobustPolicy
161 >::type robust_point2_type;
163 inline robust_point_calculator(UniqueSubRange1 const& range_p,
164 UniqueSubRange2 const& range_q,
165 RobustPolicy const& robust_policy)
166 : m_robust_policy(robust_policy)
169 , m_pk_retrieved(false)
170 , m_qk_retrieved(false)
172 // Calculate pi,pj and qi,qj which are almost always necessary
173 // But don't calculate pk/qk yet, which is retrieved (taking
174 // more time) and not always necessary.
175 geometry::recalculate(m_rpi, range_p.at(0), robust_policy);
176 geometry::recalculate(m_rpj, range_p.at(1), robust_policy);
177 geometry::recalculate(m_rqi, range_q.at(0), robust_policy);
178 geometry::recalculate(m_rqj, range_q.at(1), robust_policy);
181 inline robust_point1_type const& get_rpk() const
183 if (! m_pk_retrieved)
185 geometry::recalculate(m_rpk, m_range_p.at(2), m_robust_policy);
186 m_pk_retrieved = true;
190 inline robust_point2_type const& get_rqk() const
192 if (! m_qk_retrieved)
194 geometry::recalculate(m_rqk, m_range_q.at(2), m_robust_policy);
195 m_qk_retrieved = true;
200 robust_point1_type m_rpi, m_rpj;
201 robust_point2_type m_rqi, m_rqj;
204 RobustPolicy const& m_robust_policy;
205 UniqueSubRange1 const& m_range_p;
206 UniqueSubRange2 const& m_range_q;
209 mutable robust_point1_type m_rpk;
210 mutable robust_point2_type m_rqk;
211 mutable bool m_pk_retrieved;
212 mutable bool m_qk_retrieved;
215 // Default version (empty - specialized below)
218 typename UniqueSubRange1, typename UniqueSubRange2,
219 typename TurnPoint, typename UmbrellaStrategy,
220 typename RobustPolicy,
221 typename Tag = typename rescale_policy_type<RobustPolicy>::type
223 class intersection_info_base {};
225 // Version with rescaling, having robust points
228 typename UniqueSubRange1, typename UniqueSubRange2,
229 typename TurnPoint, typename UmbrellaStrategy,
230 typename RobustPolicy
232 class intersection_info_base<UniqueSubRange1, UniqueSubRange2,
233 TurnPoint, UmbrellaStrategy, RobustPolicy, rescale_policy_tag>
235 typedef robust_point_calculator
237 UniqueSubRange1, UniqueSubRange2,
243 typedef segment_intersection_points
246 geometry::segment_ratio<boost::long_long_type>
247 > intersection_point_type;
248 typedef policies::relate::segments_intersection_policy
250 intersection_point_type
251 > intersection_policy_type;
253 typedef typename intersection_policy_type::return_type result_type;
255 typedef typename robust_calc_type::robust_point1_type robust_point1_type;
256 typedef typename robust_calc_type::robust_point2_type robust_point2_type;
258 typedef robust_subrange_adapter<robust_point1_type, UniqueSubRange1, RobustPolicy> robust_subrange1;
259 typedef robust_subrange_adapter<robust_point2_type, UniqueSubRange2, RobustPolicy> robust_subrange2;
261 typedef side_calculator
263 robust_subrange1, robust_subrange2, UmbrellaStrategy
264 > side_calculator_type;
266 typedef side_calculator
268 robust_subrange2, robust_subrange1, UmbrellaStrategy
269 > robust_swapped_side_calculator_type;
271 intersection_info_base(UniqueSubRange1 const& range_p,
272 UniqueSubRange2 const& range_q,
273 UmbrellaStrategy const& umbrella_strategy,
274 RobustPolicy const& robust_policy)
277 , m_robust_calc(range_p, range_q, robust_policy)
278 , m_robust_range_p(range_p, m_robust_calc.m_rpi, m_robust_calc.m_rpj, robust_policy)
279 , m_robust_range_q(range_q, m_robust_calc.m_rqi, m_robust_calc.m_rqj, robust_policy)
280 , m_side_calc(m_robust_range_p, m_robust_range_q, umbrella_strategy)
281 , m_swapped_side_calc(m_robust_range_q, m_robust_range_p, umbrella_strategy)
282 , m_result(umbrella_strategy.relate().apply(range_p, range_q,
283 intersection_policy_type(),
284 m_robust_range_p, m_robust_range_q))
287 inline bool p_is_last_segment() const { return m_range_p.is_last_segment(); }
288 inline bool q_is_last_segment() const { return m_range_q.is_last_segment(); }
290 inline robust_point1_type const& rpi() const { return m_robust_calc.m_rpi; }
291 inline robust_point1_type const& rpj() const { return m_robust_calc.m_rpj; }
292 inline robust_point1_type const& rpk() const { return m_robust_calc.get_rpk(); }
294 inline robust_point2_type const& rqi() const { return m_robust_calc.m_rqi; }
295 inline robust_point2_type const& rqj() const { return m_robust_calc.m_rqj; }
296 inline robust_point2_type const& rqk() const { return m_robust_calc.get_rqk(); }
298 inline side_calculator_type const& sides() const { return m_side_calc; }
299 inline robust_swapped_side_calculator_type const& swapped_sides() const
301 return m_swapped_side_calc;
306 // Owned by get_turns
307 UniqueSubRange1 const& m_range_p;
308 UniqueSubRange2 const& m_range_q;
310 // Owned by this class
311 robust_calc_type m_robust_calc;
312 robust_subrange1 m_robust_range_p;
313 robust_subrange2 m_robust_range_q;
314 side_calculator_type m_side_calc;
315 robust_swapped_side_calculator_type m_swapped_side_calc;
318 result_type m_result;
321 // Version without rescaling
324 typename UniqueSubRange1, typename UniqueSubRange2,
325 typename TurnPoint, typename UmbrellaStrategy,
326 typename RobustPolicy
328 class intersection_info_base<UniqueSubRange1, UniqueSubRange2,
329 TurnPoint, UmbrellaStrategy, RobustPolicy, no_rescale_policy_tag>
333 typedef segment_intersection_points<TurnPoint> intersection_point_type;
334 typedef policies::relate::segments_intersection_policy
336 intersection_point_type
337 > intersection_policy_type;
339 typedef typename intersection_policy_type::return_type result_type;
341 typedef typename UniqueSubRange1::point_type point1_type;
342 typedef typename UniqueSubRange2::point_type point2_type;
344 typedef side_calculator
346 UniqueSubRange1, UniqueSubRange2, UmbrellaStrategy
347 > side_calculator_type;
349 typedef side_calculator
351 UniqueSubRange2, UniqueSubRange1, UmbrellaStrategy
352 > swapped_side_calculator_type;
354 intersection_info_base(UniqueSubRange1 const& range_p,
355 UniqueSubRange2 const& range_q,
356 UmbrellaStrategy const& umbrella_strategy,
357 no_rescale_policy const& )
360 , m_side_calc(range_p, range_q, umbrella_strategy)
361 , m_swapped_side_calc(range_q, range_p, umbrella_strategy)
362 , m_result(umbrella_strategy.relate()
363 .apply(range_p, range_q, intersection_policy_type()))
366 inline bool p_is_last_segment() const { return m_range_p.is_last_segment(); }
367 inline bool q_is_last_segment() const { return m_range_q.is_last_segment(); }
369 inline point1_type const& rpi() const { return m_side_calc.get_pi(); }
370 inline point1_type const& rpj() const { return m_side_calc.get_pj(); }
371 inline point1_type const& rpk() const { return m_side_calc.get_pk(); }
373 inline point2_type const& rqi() const { return m_side_calc.get_qi(); }
374 inline point2_type const& rqj() const { return m_side_calc.get_qj(); }
375 inline point2_type const& rqk() const { return m_side_calc.get_qk(); }
377 inline side_calculator_type const& sides() const { return m_side_calc; }
378 inline swapped_side_calculator_type const& swapped_sides() const
380 return m_swapped_side_calc;
384 // Owned by get_turns
385 UniqueSubRange1 const& m_range_p;
386 UniqueSubRange2 const& m_range_q;
388 // Owned by this class
389 side_calculator_type m_side_calc;
390 swapped_side_calculator_type m_swapped_side_calc;
393 result_type m_result;
399 typename UniqueSubRange1, typename UniqueSubRange2,
401 typename UmbrellaStrategy,
402 typename RobustPolicy
404 class intersection_info
405 : public intersection_info_base<UniqueSubRange1, UniqueSubRange2,
406 TurnPoint, UmbrellaStrategy, RobustPolicy>
408 typedef intersection_info_base<UniqueSubRange1, UniqueSubRange2,
409 TurnPoint, UmbrellaStrategy, RobustPolicy> base;
413 typedef typename UniqueSubRange1::point_type point1_type;
414 typedef typename UniqueSubRange2::point_type point2_type;
416 typedef typename UmbrellaStrategy::cs_tag cs_tag;
418 typedef typename base::side_calculator_type side_calculator_type;
419 typedef typename base::result_type result_type;
421 typedef typename result_type::intersection_points_type i_info_type;
422 typedef typename result_type::direction_type d_info_type;
424 intersection_info(UniqueSubRange1 const& range_p,
425 UniqueSubRange2 const& range_q,
426 UmbrellaStrategy const& umbrella_strategy,
427 RobustPolicy const& robust_policy)
428 : base(range_p, range_q, umbrella_strategy, robust_policy)
429 , m_umbrella_strategy(umbrella_strategy)
430 , m_robust_policy(robust_policy)
433 inline result_type const& result() const { return base::m_result; }
434 inline i_info_type const& i_info() const { return base::m_result.intersection_points; }
435 inline d_info_type const& d_info() const { return base::m_result.direction; }
437 // TODO: it's more like is_spike_ip_p
438 inline bool is_spike_p() const
440 if (base::p_is_last_segment())
444 if (base::sides().pk_wrt_p1() == 0)
446 // p: pi--------pj--------pk
454 // TODO: why is q used to determine spike property in p?
455 bool const has_qk = ! base::q_is_last_segment();
456 int const qk_p1 = has_qk ? base::sides().qk_wrt_p1() : 0;
457 int const qk_p2 = has_qk ? base::sides().qk_wrt_p2() : 0;
463 // qk is collinear with both p1 and p2,
464 // verify if pk goes backwards w.r.t. pi/pj
465 return direction_code<cs_tag>(base::rpi(), base::rpj(), base::rpk()) == -1;
468 // qk is at opposite side of p1/p2, therefore
469 // p1/p2 (collinear) are opposite and form a spike
477 inline bool is_spike_q() const
479 if (base::q_is_last_segment())
484 // See comments at is_spike_p
485 if (base::sides().qk_wrt_q1() == 0)
492 // TODO: why is p used to determine spike property in q?
493 bool const has_pk = ! base::p_is_last_segment();
494 int const pk_q1 = has_pk ? base::sides().pk_wrt_q1() : 0;
495 int const pk_q2 = has_pk ? base::sides().pk_wrt_q2() : 0;
501 return direction_code<cs_tag>(base::rqi(), base::rqj(), base::rqk()) == -1;
511 UmbrellaStrategy const& strategy() const
513 return m_umbrella_strategy;
517 template <std::size_t OpId>
520 int arrival = d_info().arrival[OpId];
521 bool same_dirs = d_info().dir_a == 0 && d_info().dir_b == 0;
525 if (i_info().count == 2)
527 return arrival != -1;
540 UmbrellaStrategy const& m_umbrella_strategy;
541 RobustPolicy const& m_robust_policy;
544 }} // namespace detail::overlay
545 #endif // DOXYGEN_NO_DETAIL
547 }} // namespace boost::geometry
549 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HELPERS_HPP