@@ -111,6 +111,60 @@ struct base_turn_handler
111
111
both (ti, condition ? operation_union : operation_intersection);
112
112
}
113
113
114
+
115
+ #if ! defined(BOOST_GEOMETRY_USE_RESCALING)
116
+ template
117
+ <
118
+ typename UniqueSubRange1,
119
+ typename UniqueSubRange2
120
+ >
121
+ static inline int side_with_distance_measure (UniqueSubRange1 const & range_p,
122
+ UniqueSubRange2 const & range_q,
123
+ int range_index, int point_index)
124
+ {
125
+ if (range_index >= 1 && range_p.is_last_segment ())
126
+ {
127
+ return 0 ;
128
+ }
129
+ if (point_index >= 2 && range_q.is_last_segment ())
130
+ {
131
+ return 0 ;
132
+ }
133
+
134
+ typedef typename select_coordinate_type
135
+ <
136
+ typename UniqueSubRange1::point_type,
137
+ typename UniqueSubRange2::point_type
138
+ >::type coordinate_type;
139
+
140
+ typedef detail::distance_measure<coordinate_type> dm_type;
141
+
142
+ dm_type const dm = get_distance_measure (range_p.at (range_index), range_p.at (range_index + 1 ), range_q.at (point_index));
143
+ return dm.measure == 0 ? 0 : dm.measure > 0 ? 1 : -1 ;
144
+ }
145
+
146
+ template
147
+ <
148
+ typename UniqueSubRange1,
149
+ typename UniqueSubRange2
150
+ >
151
+ static inline int verified_side (int side,
152
+ UniqueSubRange1 const & range_p,
153
+ UniqueSubRange2 const & range_q,
154
+ int range_index,
155
+ int point_index)
156
+ {
157
+ return side == 0 ? side_with_distance_measure (range_p, range_q, range_index, point_index) : side;
158
+ }
159
+ #else
160
+ template <typename T1, typename T2>
161
+ static inline int verified_side (int side, T1 const & , T2 const & , int , int )
162
+ {
163
+ return side;
164
+ }
165
+ #endif
166
+
167
+
114
168
template <typename TurnInfo, typename IntersectionInfo>
115
169
static inline void assign_point (TurnInfo& ti,
116
170
method_type method,
@@ -178,7 +232,7 @@ struct base_turn_handler
178
232
<
179
233
typename UniqueSubRange1::point_type,
180
234
typename UniqueSubRange2::point_type
181
- >::type
235
+ >::type
182
236
> dm_type;
183
237
184
238
const bool p_closer =
@@ -369,14 +423,80 @@ struct touch : public base_turn_handler
369
423
return side1 == side2 && ! opposite (side1, turn);
370
424
}
371
425
372
- /* static inline void block_second(bool block, TurnInfo& ti)
426
+ #if ! defined(BOOST_GEOMETRY_USE_RESCALING)
427
+ template
428
+ <
429
+ typename UniqueSubRange1,
430
+ typename UniqueSubRange2
431
+ >
432
+ static inline bool handle_imperfect_touch (UniqueSubRange1 const & range_p,
433
+ UniqueSubRange2 const & range_q, TurnInfo& ti)
373
434
{
374
- if (block)
435
+ // Q
436
+ // ^
437
+ // ||
438
+ // ||
439
+ // |^----
440
+ // >----->P
441
+ // * * they touch here (P/Q are (nearly) on top)
442
+ //
443
+ // Q continues from where P comes.
444
+ // P continues from where Q comes
445
+ // This is often a blocking situation,
446
+ // unless there are FP issues: there might be a distance
447
+ // between Pj and Qj, in that case handle it as a union.
448
+ //
449
+ // Exaggerated:
450
+ // Q
451
+ // ^ Q is nearly vertical
452
+ // \ but not completely - and still ends above P
453
+ // | \qj In this case it should block P and
454
+ // | ^------ set Q to Union
455
+ // >----->P qj is LEFT of P1 and pi is LEFT of Q2
456
+ // (the other way round is also possible)
457
+
458
+ typedef typename select_coordinate_type
459
+ <
460
+ typename UniqueSubRange1::point_type,
461
+ typename UniqueSubRange2::point_type
462
+ >::type coordinate_type;
463
+
464
+ typedef detail::distance_measure<coordinate_type> dm_type;
465
+
466
+ dm_type const dm_qj_p1 = get_distance_measure (range_p.at (0 ), range_p.at (1 ), range_q.at (1 ));
467
+ dm_type const dm_pi_q2 = get_distance_measure (range_q.at (1 ), range_q.at (2 ), range_p.at (0 ));
468
+
469
+ if (dm_qj_p1.measure > 0 && dm_pi_q2.measure > 0 )
375
470
{
376
- ti.operations[1].operation = operation_blocked;
471
+ // Even though there is a touch, Q(j) is left of P1
472
+ // and P(i) is still left from Q2.
473
+ // It can continue.
474
+ ti.operations [0 ].operation = operation_blocked;
475
+ // Q turns right -> union (both independent),
476
+ // Q turns left -> intersection
477
+ ti.operations [1 ].operation = operation_union;
478
+ ti.touch_only = true ;
479
+ return true ;
377
480
}
378
- }*/
379
481
482
+ dm_type const dm_pj_q1 = get_distance_measure (range_q.at (0 ), range_q.at (1 ), range_p.at (1 ));
483
+ dm_type const dm_qi_p2 = get_distance_measure (range_p.at (1 ), range_p.at (2 ), range_q.at (0 ));
484
+
485
+ if (dm_pj_q1.measure > 0 && dm_qi_p2.measure > 0 )
486
+ {
487
+ // Even though there is a touch, Q(j) is left of P1
488
+ // and P(i) is still left from Q2.
489
+ // It can continue.
490
+ ti.operations [0 ].operation = operation_union;
491
+ // Q turns right -> union (both independent),
492
+ // Q turns left -> intersection
493
+ ti.operations [1 ].operation = operation_blocked;
494
+ ti.touch_only = true ;
495
+ return true ;
496
+ }
497
+ return false ;
498
+ }
499
+ #endif
380
500
381
501
template
382
502
<
@@ -400,9 +520,10 @@ struct touch : public base_turn_handler
400
520
bool const has_pk = ! range_p.is_last_segment ();
401
521
bool const has_qk = ! range_q.is_last_segment ();
402
522
403
- int const side_qi_p1 = dir_info.sides .template get <1 , 0 >();
404
- int const side_qk_p1 = has_qk ? side.qk_wrt_p1 () : 0 ;
523
+ int const side_pk_q1 = has_pk ? side.pk_wrt_q1 () : 0 ;
405
524
525
+ int const side_qi_p1 = verified_side (dir_info.sides .template get <1 , 0 >(), range_p, range_q, 0 , 0 );
526
+ int const side_qk_p1 = has_qk ? verified_side (side.qk_wrt_p1 (), range_p, range_q, 0 , 2 ) : 0 ;
406
527
407
528
// If Qi and Qk are both at same side of Pi-Pj,
408
529
// or collinear (so: not opposite sides)
@@ -413,6 +534,7 @@ struct touch : public base_turn_handler
413
534
int const side_qk_q = has_qk ? side.qk_wrt_q1 () : 0 ;
414
535
415
536
bool const q_turns_left = side_qk_q == 1 ;
537
+
416
538
bool const block_q = side_qk_p1 == 0
417
539
&& ! same (side_qi_p1, side_qk_q)
418
540
;
@@ -422,9 +544,18 @@ struct touch : public base_turn_handler
422
544
// or Q is fully collinear && P turns not to left
423
545
if (side_pk_p == side_qi_p1
424
546
|| side_pk_p == side_qk_p1
425
- || (side_qi_p1 == 0 && side_qk_p1 == 0 && side_pk_p != -1 )
426
- )
547
+ || (side_qi_p1 == 0 && side_qk_p1 == 0 && side_pk_p != -1 ))
427
548
{
549
+ #if ! defined(BOOST_GEOMETRY_USE_RESCALING)
550
+ if (side_qk_p1 == 0 && side_pk_q1 == 0
551
+ && has_qk && has_qk
552
+ && handle_imperfect_touch (range_p, range_q, ti))
553
+ {
554
+ // If q continues collinearly (opposite) with p, it should be blocked
555
+ // but (FP) not if there is just a tiny space in between
556
+ return ;
557
+ }
558
+ #endif
428
559
// Collinear -> lines join, continue
429
560
// (#BRL2)
430
561
if (side_pk_q2 == 0 && ! block_q)
@@ -433,8 +564,6 @@ struct touch : public base_turn_handler
433
564
return ;
434
565
}
435
566
436
- int const side_pk_q1 = has_pk && has_qk ? side.pk_wrt_q1 () : 0 ;
437
-
438
567
// Collinear opposite case -> block P
439
568
// (#BRL4, #BLR8)
440
569
if (side_pk_q1 == 0 )
@@ -457,7 +586,6 @@ struct touch : public base_turn_handler
457
586
{
458
587
ti.operations [1 ].operation = operation_blocked;
459
588
}
460
- // block_second(block_q, ti);
461
589
return ;
462
590
}
463
591
@@ -483,7 +611,6 @@ struct touch : public base_turn_handler
483
611
{
484
612
ti.touch_only = true ;
485
613
}
486
- // block_second(block_q, ti);
487
614
return ;
488
615
}
489
616
}
@@ -508,8 +635,9 @@ struct touch : public base_turn_handler
508
635
}
509
636
else
510
637
{
638
+ // The qi/qk are opposite to each other, w.r.t. p1
511
639
// From left to right or from right to left
512
- int const side_pk_p = has_pk ? side.pk_wrt_p1 () : 0 ;
640
+ int const side_pk_p = has_pk ? verified_side ( side.pk_wrt_p1 (), range_p, range_p, 0 , 2 ) : 0 ;
513
641
bool const right_to_left = side_qk_p1 == 1 ;
514
642
515
643
// If p turns into direction of qi (1,2)
@@ -601,23 +729,23 @@ struct equal : public base_turn_handler
601
729
// Without rescaling, to check for union/intersection,
602
730
// try to check side values (without any thresholds)
603
731
typedef typename select_coordinate_type
604
- <
605
- typename UniqueSubRange1::point_type,
606
- typename UniqueSubRange2::point_type
607
- >::type coordinate_type;
732
+ <
733
+ typename UniqueSubRange1::point_type,
734
+ typename UniqueSubRange2::point_type
735
+ >::type coordinate_type;
608
736
609
737
typedef detail::distance_measure<coordinate_type> dm_type;
610
738
611
- dm_type const dm_qk_p
739
+ dm_type const dm_pk_q2
612
740
= get_distance_measure (range_q.at (1 ), range_q.at (2 ), range_p.at (2 ));
613
- dm_type const dm_pk_q
741
+ dm_type const dm_qk_p2
614
742
= get_distance_measure (range_p.at (1 ), range_p.at (2 ), range_q.at (2 ));
615
743
616
- if (dm_pk_q .measure != dm_qk_p .measure )
744
+ if (dm_qk_p2 .measure != dm_pk_q2 .measure )
617
745
{
618
746
// A (possibly very small) difference is detected, which
619
747
// can be used to distinguish between union/intersection
620
- ui_else_iu (dm_pk_q .measure < dm_qk_p .measure , ti);
748
+ ui_else_iu (dm_qk_p2 .measure < dm_pk_q2 .measure , ti);
621
749
return ;
622
750
}
623
751
}
0 commit comments