@@ -431,39 +431,86 @@ def does_overlap(self, aabb, method='DFS'):
431
431
This function checks if the limits overlap any leaf nodes in the tree.
432
432
It returns true if there is an overlap.
433
433
434
+ *New in version 2.6.0*
435
+
436
+ This method also supports overlap checks with another instance of the
437
+ AABBTree class.
438
+
434
439
Args:
435
- aabb (AABB): The AABB to check.
440
+ aabb (AABB or AABBTree ): The AABB or AABBTree to check.
436
441
method (str): {'DFS'|'BFS'} Method for traversing the tree.
437
442
Setting 'DFS' performs a depth-first search and 'BFS' performs
438
443
a breadth-first search. Defaults to 'DFS'.
439
444
440
445
Returns:
441
446
bool: True if overlaps with a leaf node of tree.
442
447
"""
448
+ if isinstance (aabb , AABB ):
449
+ tree = AABBTree (aabb = aabb )
450
+ else :
451
+ tree = aabb
452
+
443
453
if method == 'DFS' :
454
+ if self .is_leaf and tree .is_leaf :
455
+ return self .aabb .overlaps (tree .aabb )
456
+
444
457
if self .is_leaf :
445
- return self .aabb .overlaps (aabb )
458
+ left_over = tree .left .aabb .overlaps (self .aabb )
459
+ right_over = tree .right .aabb .overlaps (self .aabb )
460
+
461
+ if left_over and tree .left .does_overlap (self , method ):
462
+ return True
463
+ if right_over and tree .right .does_overlap (self , method ):
464
+ return True
465
+ return False
466
+ if tree .is_leaf :
467
+ left_over = self .left .aabb .overlaps (tree .aabb )
468
+ right_over = self .right .aabb .overlaps (tree .aabb )
469
+
470
+ if left_over and self .left .does_overlap (tree , method ):
471
+ return True
472
+ if right_over and self .right .does_overlap (tree , method ):
473
+ return True
474
+ return False
475
+
476
+ # If both `self` and `tree` are trees
477
+ if not self .aabb .overlaps (tree .aabb ):
478
+ return False
446
479
447
- left_aabb_over = self .left .aabb .overlaps (aabb )
448
- right_aabb_over = self .right .aabb .overlaps (aabb )
480
+ left_left = self .left .aabb .overlaps (tree .left .aabb )
481
+ left_right = self .left .aabb .overlaps (tree .right .aabb )
482
+ right_left = self .right .aabb .overlaps (tree .left .aabb )
483
+ right_right = self .right .aabb .overlaps (tree .right .aabb )
449
484
450
- if left_aabb_over and self .left .does_overlap (aabb ):
485
+ if left_left and self .left .does_overlap (tree . left , method ):
451
486
return True
452
- if right_aabb_over and self .right .does_overlap (aabb ):
487
+ if left_right and self .left .does_overlap (tree .right , method ):
488
+ return True
489
+ if right_left and self .right .does_overlap (tree .left , method ):
490
+ return True
491
+ if right_right and self .right .does_overlap (tree .right , method ):
453
492
return True
454
493
return False
455
494
456
495
if method == 'BFS' :
457
496
q = deque ()
458
- q .append (self )
497
+ q .append (( self , tree ) )
459
498
while len (q ) > 0 :
460
- node = q .popleft ()
461
- overlaps = node .aabb .overlaps (aabb )
462
- if overlaps and node .is_leaf :
499
+ s_node , t_node = q .popleft ()
500
+ overlaps = s_node .aabb .overlaps (t_node . aabb )
501
+ if overlaps and s_node . is_leaf and t_node .is_leaf :
463
502
return True
464
- if overlaps :
465
- q .append (node .left )
466
- q .append (node .right )
503
+ if overlaps and s_node .is_leaf :
504
+ q .append ((s_node , t_node .left ))
505
+ q .append ((s_node , t_node .right ))
506
+ elif overlaps and t_node .is_leaf :
507
+ q .append ((s_node .left , t_node ))
508
+ q .append ((s_node .right , t_node ))
509
+ elif overlaps :
510
+ q .append ((s_node .left , t_node .left ))
511
+ q .append ((s_node .left , t_node .right ))
512
+ q .append ((s_node .right , t_node .left ))
513
+ q .append ((s_node .right , t_node .right ))
467
514
return False
468
515
469
516
e_str = "method should be 'DFS' or 'BFS', not " + str (method )
@@ -474,88 +521,115 @@ def overlap_aabbs(self, aabb, method='DFS'):
474
521
475
522
This function gets each overlapping AABB.
476
523
524
+ *New in version 2.6.0*
525
+
526
+ This method also supports overlap checks with another instance of the
527
+ AABBTree class.
528
+
477
529
Args:
478
- aabb (AABB): The AABB to check.
530
+ aabb (AABB or AABBTree ): The AABB or AABBTree to check.
479
531
method (str): {'DFS'|'BFS'} Method for traversing the tree.
480
532
Setting 'DFS' performs a depth-first search and 'BFS' performs
481
533
a breadth-first search. Defaults to 'DFS'.
482
534
483
535
Returns:
484
536
list: AABB objects in AABBTree that overlap with the input.
485
537
"""
486
- aabbs = []
487
-
488
- if method == 'DFS' :
489
- is_leaf = self .is_leaf
490
- if is_leaf and self .does_overlap (aabb ):
491
- aabbs .append (self .aabb )
492
- elif is_leaf :
493
- pass
494
- else :
495
- if self .left .aabb .overlaps (aabb ):
496
- aabbs .extend (self .left .overlap_aabbs (aabb ))
497
-
498
- if self .right .aabb .overlaps (aabb ):
499
- aabbs .extend (self .right .overlap_aabbs (aabb ))
500
- elif method == 'BFS' :
501
- q = deque ()
502
- q .append (self )
503
- while len (q ) > 0 :
504
- node = q .popleft ()
505
- if node .aabb .overlaps (aabb ):
506
- if node .is_leaf :
507
- aabbs .append (node .aabb )
508
- else :
509
- q .append (node .left )
510
- q .append (node .right )
511
- else :
512
- e_str = "method should be 'DFS' or 'BFS', not " + str (method )
513
- raise ValueError (e_str )
514
- return aabbs
538
+ pairs = self ._overlap_pairs (aabb , method )
539
+ if len (pairs ) == 0 :
540
+ return []
541
+ boxes , _ = zip (* pairs )
542
+ return list (boxes )
515
543
516
544
def overlap_values (self , aabb , method = 'DFS' ):
517
545
"""Get values of overlapping AABBs
518
546
519
547
This function gets the value field of each overlapping AABB.
520
548
549
+ *New in version 2.6.0*
550
+
551
+ This method also supports overlap checks with another instance of the
552
+ AABBTree class.
553
+
521
554
Args:
522
- aabb (AABB): The AABB to check.
555
+ aabb (AABB or AABBTree ): The AABB or AABBTree to check.
523
556
method (str): {'DFS'|'BFS'} Method for traversing the tree.
524
557
Setting 'DFS' performs a depth-first search and 'BFS' performs
525
558
a breadth-first search. Defaults to 'DFS'.
526
559
527
560
Returns:
528
561
list: Value fields of each node that overlaps.
529
562
"""
530
- values = []
563
+ pairs = self ._overlap_pairs (aabb , method )
564
+ if len (pairs ) == 0 :
565
+ return []
566
+ _ , values = zip (* pairs )
567
+ return list (values )
568
+
569
+ def _overlap_pairs (self , aabb , method = 'DFS' ):
570
+ """Get overlapping AABBs and values in (AABB, value) pairs
571
+
572
+ *New in version 2.6.0*
573
+
574
+ This function gets each overlapping AABB and its value.
575
+
576
+ Args:
577
+ aabb (AABB or AABBTree): The AABB or AABBTree to check.
578
+ method (str): {'DFS'|'BFS'} Method for traversing the tree.
579
+ Setting 'DFS' performs a depth-first search and 'BFS' performs
580
+ a breadth-first search. Defaults to 'DFS'.
581
+
582
+ Returns:
583
+ list: (AABB, value) pairs in AABBTree that overlap with the input.
584
+ """
585
+ if isinstance (aabb , AABB ):
586
+ tree = AABBTree (aabb = aabb )
587
+ else :
588
+ tree = aabb
589
+
590
+ pairs = []
531
591
532
592
if method == 'DFS' :
533
- is_leaf = self .is_leaf
534
- if is_leaf and self .does_overlap (aabb ):
535
- values .append (self .value )
536
- elif is_leaf :
593
+ if self .is_leaf and self .does_overlap (tree , method ):
594
+ pairs .append ((self .aabb , self .value ))
595
+ elif self .is_leaf :
537
596
pass
597
+ elif tree .is_leaf :
598
+ for branch in (self .left , self .right ):
599
+ pairs .extend (branch ._overlap_pairs (tree , method ))
538
600
else :
539
- if self .left .aabb .overlaps (aabb ):
540
- values .extend (self .left .overlap_values (aabb ))
601
+ for s_branch in (self .left , self .right ):
602
+ for t_branch in (tree .left , tree .right ):
603
+ pairs .extend (s_branch ._overlap_pairs (t_branch , method ))
541
604
542
- if self .right .aabb .overlaps (aabb ):
543
- values .extend (self .right .overlap_values (aabb ))
544
605
elif method == 'BFS' :
545
606
q = deque ()
546
- q .append (self )
607
+ q .append (( self , tree ) )
547
608
while len (q ) > 0 :
548
- node = q .popleft ()
549
- if node .aabb .overlaps (aabb ):
550
- if node .is_leaf :
551
- values .append (node .value )
609
+ s_node , t_node = q .popleft ()
610
+ if s_node .aabb .overlaps (t_node .aabb ):
611
+ if s_node .is_leaf and t_node .is_leaf :
612
+ pairs .append ((s_node .aabb , s_node .value ))
613
+ elif s_node .is_leaf :
614
+ q .append ((s_node , t_node .left ))
615
+ q .append ((s_node , t_node .right ))
616
+ elif t_node .is_leaf :
617
+ q .append ((s_node .left , t_node ))
618
+ q .append ((s_node .right , t_node ))
552
619
else :
553
- q .append (node .left )
554
- q .append (node .right )
620
+ q .append ((s_node .left , t_node .left ))
621
+ q .append ((s_node .left , t_node .right ))
622
+ q .append ((s_node .right , t_node .left ))
623
+ q .append ((s_node .right , t_node .right ))
555
624
else :
556
625
e_str = "method should be 'DFS' or 'BFS', not " + str (method )
557
626
raise ValueError (e_str )
558
- return values
627
+
628
+ if len (pairs ) < 2 :
629
+ return pairs
630
+ boxes , _ = zip (* pairs )
631
+ u_pairs = [p for i , p in enumerate (pairs ) if p [0 ] not in boxes [:i ]]
632
+ return u_pairs
559
633
560
634
561
635
def _merge (lims1 , lims2 ):
0 commit comments