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