88 integer :: object_index = -1
103 procedure, pass(this),
public :: get_object_index => &
105 procedure, pass(this),
public :: get_parent_index => &
107 procedure, pass(this),
public :: get_left_index => &
109 procedure, pass(this),
public :: get_right_index => &
120 generic ::
operator(.lt.) => less
121 generic ::
operator(.gt.) => greater
133 integer :: allocated_node_count = 0
135 integer :: node_capacity = 0
136 integer :: growth_size = 1
143 procedure, pass(this),
public :: insert_object => &
149 procedure, pass(this),
public :: get_root_index => &
151 procedure, pass(this),
public :: get_parent_index => &
153 procedure, pass(this),
public :: get_left_index => &
155 procedure, pass(this),
public :: get_right_index => &
159 procedure, pass(this),
public :: get_root_node => &
161 procedure, pass(this),
public :: get_parent_node => &
163 procedure, pass(this),
public :: get_left_node => &
165 procedure, pass(this),
public :: get_right_node => &
170 procedure, pass(this),
public :: query_overlaps => &
199 this%object_index = -1
220 integer :: object_index
222 object_index = this%object_index
228 integer :: parent_index
230 parent_index = this%parent_node_index
236 integer :: left_index
238 left_index = this%left_node_index
244 integer :: right_index
246 right_index = this%right_node_index
252 real(kind=
dp),
dimension(3),
intent(in) :: p
253 real(kind=
dp) :: distance
255 distance = 0.5_rp * this%aabb%get_diameter() &
256 - norm2(this%aabb%get_center() - p)
276 if (this%is_leaf())
then
280 & this%object_index .gt. 0
285 & this%object_index .eq. -1
299 res = this%aabb .lt. other%aabb
309 res = this%aabb .gt. other%aabb
320 integer,
intent(in) :: initial_capacity
325 this%allocated_node_count = 0
326 this%next_free_node_index = 1
327 this%node_capacity = initial_capacity
328 this%growth_size = initial_capacity
330 if (
allocated(this%nodes))
deallocate(this%nodes)
331 allocate(this%nodes(initial_capacity))
333 do i = 1, initial_capacity
334 this%nodes(i)%next_node_index = i + 1
345 class(*),
dimension(:),
intent(in) :: objects
347 integer :: i_obj, i_node, i
350 integer :: start_layer, end_layer
352 type(
aabb_t),
dimension(:),
allocatable :: box_list
353 integer,
dimension(:),
allocatable :: sorted_indices
355 call this%init(
size(objects) * 2)
361 allocate(box_list(
size(objects)))
363 do i_obj = 1,
size(objects)
364 box_list(i_obj) =
get_aabb(objects(i_obj))
366 sorted_indices =
sort(box_list)
368 do i = 1,
size(sorted_indices)
369 i_obj = sorted_indices(i)
370 i_node = this%allocate_node()
371 this%nodes(i_node)%aabb =
get_aabb(objects(i_obj))
372 this%nodes(i_node)%object_index = i_obj
377 end_layer =
size(objects)
379 do while (.not. done)
382 do i = start_layer, end_layer - 1, 2
383 i_node = this%allocate_node()
385 this%nodes(i_node)%aabb =
merge(this%nodes(i)%aabb, &
386 this%nodes(i + 1)%aabb)
388 this%nodes(i_node)%left_node_index = i
389 this%nodes(i_node)%right_node_index = i + 1
391 this%nodes(i)%parent_node_index = i_node
392 this%nodes(i + 1)%parent_node_index = i_node
397 if (mod(end_layer - start_layer, 2) .eq. 0)
then
398 i_node = this%allocate_node()
399 this%nodes(i_node)%aabb = this%nodes(end_layer)%aabb
400 this%nodes(i_node)%left_node_index = end_layer
403 this%nodes(end_layer)%parent_node_index = i_node
407 start_layer = end_layer + 1
408 end_layer = this%allocated_node_count
411 done = start_layer .eq. end_layer
415 this%root_node_index = this%allocated_node_count
417 if (this%get_size() .ne.
size(objects))
then
418 print *,
"this%get_size() = ", this%get_size()
419 print *,
"size(objects) = ",
size(objects)
425 function sort(array)
result(indices)
426 type(
aabb_t),
dimension(:),
intent(in) :: array
427 integer,
dimension(:),
allocatable :: indices
428 logical,
dimension(:),
allocatable :: visited
433 allocate(indices(
size(array)))
434 allocate(visited(
size(array)))
438 do i = 1,
size(array)
440 do imin = 1,
size(array)
441 if (.not. visited(imin) .and. minidx .eq. -1) minidx = imin
442 if (minidx .gt. -1)
then
443 if (visited(imin) .and. array(imin) .lt. array(minidx)) minidx = imin
448 visited(minidx) = .true.
466 call simple_stack%init(this%allocated_node_count)
468 tmp = this%get_root_index()
470 call simple_stack%push(tmp)
473 do while (.not. simple_stack%is_empty())
474 idx = simple_stack%pop()
477 if (this%nodes(idx)%is_leaf())
then
480 tmp = this%get_left_index(idx)
481 call simple_stack%push(tmp)
482 tmp = this%get_right_index(idx)
483 call simple_stack%push(tmp)
495 integer :: root_index
497 root_index = this%root_node_index
504 integer,
intent(in) :: node_index
505 integer :: parent_index
507 parent_index = this%nodes(node_index)%parent_node_index
514 integer,
intent(in) :: node_index
515 integer :: left_index
517 left_index = this%nodes(node_index)%left_node_index
524 integer,
intent(in) :: node_index
525 integer :: right_index
527 right_index = this%nodes(node_index)%right_node_index
536 integer,
intent(in) :: node_index
539 node = this%nodes(node_index)
547 root_node = this%nodes(this%root_node_index)
554 integer,
intent(in) :: node_index
557 parent_node = this%nodes(this%nodes(node_index)%parent_node_index)
563 integer,
intent(in) :: node_index
566 left_node = this%nodes(this%nodes(node_index)%left_node_index)
573 integer,
intent(in) :: node_index
576 right_node = this%nodes(this%nodes(node_index)%right_node_index)
581 integer,
intent(in) :: node_index
584 out_box = this%nodes(node_index)%aabb
592 class(*),
intent(in) :: object
593 integer,
intent(in) :: object_index
595 integer :: node_index
597 node_index = this%allocate_node()
598 this%nodes(node_index)%aabb =
get_aabb(object)
599 this%nodes(node_index)%object_index = object_index
601 call this%insert_leaf(node_index)
610 class(*),
intent(in) :: object
611 integer,
intent(in) :: object_index
612 integer,
intent(out) :: overlaps(:)
615 type(
aabb_t) :: object_box
617 integer :: root_index, left_index, right_index
619 integer :: node_index
622 root_index = this%get_root_index()
624 call simple_stack%init()
625 call simple_stack%push(root_index)
627 do while (.not. simple_stack%is_empty())
628 node_index = simple_stack%pop()
632 if (this%nodes(node_index)%aabb%overlaps(object_box))
then
633 if (this%nodes(node_index)%is_leaf())
then
634 if (this%nodes(node_index)%object_index .ne. object_index)
then
635 overlaps = [this%nodes(node_index)%object_index, overlaps]
638 left_index = this%get_left_index(node_index)
639 call simple_stack%push(left_index)
640 right_index = this%get_right_index(node_index)
641 call simple_stack%push(right_index)
645 call simple_stack%free()
654 integer :: node_index
657 call this%resize_node_pool(this%node_capacity + this%growth_size)
660 node_index = this%next_free_node_index
662 associate(new_node => this%nodes(node_index))
663 this%next_free_node_index = new_node%next_node_index
669 this%next_free_node_index = new_node%next_node_index
670 this%allocated_node_count = this%allocated_node_count + 1
678 integer,
intent(in) :: node_index
680 this%nodes(node_index)%next_node_index = this%next_free_node_index
681 this%next_free_node_index = node_index
682 this%allocated_node_count = this%allocated_node_count - 1
688 integer,
intent(in) :: leaf_node_index
690 integer :: tree_node_index
692 real(kind=rp) :: cost_left
693 real(kind=rp) :: cost_right
700 type(aabb_t) :: combined_aabb
701 real(kind=rp) :: new_parent_node_cost
702 real(kind=rp) :: minimum_push_down_cost
703 type(aabb_t) :: new_left_aabb
704 type(aabb_t) :: new_right_aabb
705 integer :: leaf_sibling_index
707 integer :: old_parent_index
708 integer :: new_parent_index
713 leaf_node = this%nodes(leaf_node_index)
717 this%root_node_index = leaf_node_index
727 tree_node_index = this%root_node_index
728 tree_node = this%get_node(tree_node_index)
729 do while (.not. tree_node%is_leaf())
733 left_node = this%get_left_node(tree_node_index)
734 right_node = this%get_right_node(tree_node_index)
738 combined_aabb = merge(tree_node%aabb, leaf_node%get_aabb())
740 new_parent_node_cost = 2.0_rp * combined_aabb%get_surface_area()
741 minimum_push_down_cost = 2.0_rp * ( &
742 & combined_aabb%get_surface_area() &
743 & - tree_node%aabb%get_surface_area()&
748 if (left_node%is_leaf())
then
749 new_left_aabb = merge(leaf_node%aabb, left_node%get_aabb())
750 cost_left = new_left_aabb%get_surface_area() + minimum_push_down_cost
752 new_left_aabb = merge(leaf_node%aabb, left_node%get_aabb())
754 & new_left_aabb%get_surface_area() &
755 & - left_node%aabb%get_surface_area()&
756 & ) + minimum_push_down_cost
759 if (right_node%is_leaf())
then
760 new_right_aabb = merge(leaf_node%aabb, right_node%aabb)
761 cost_right = new_right_aabb%get_surface_area() + &
762 minimum_push_down_cost
764 new_right_aabb = merge(leaf_node%aabb, right_node%aabb)
766 & new_right_aabb%get_surface_area() &
767 & - right_node%aabb%get_surface_area() &
768 & ) + minimum_push_down_cost
774 if (new_parent_node_cost < cost_left .and. &
775 new_parent_node_cost < cost_right)
then
780 if (cost_left .lt. cost_right)
then
781 tree_node_index = tree_node%get_left_index()
783 tree_node_index = tree_node%get_right_index()
788 tree_node = this%get_node(tree_node_index)
793 leaf_sibling_index = tree_node_index
794 leaf_sibling = this%nodes(leaf_sibling_index)
795 old_parent_index = this%get_parent_index(leaf_sibling_index)
796 new_parent_index = this%allocate_node()
797 new_parent = this%nodes(new_parent_index)
798 new_parent%parent_node_index = old_parent_index
799 new_parent%aabb = merge(leaf_node%aabb, leaf_sibling%aabb)
801 if (leaf_node .lt. leaf_sibling)
then
802 new_parent%left_node_index = leaf_node_index
803 new_parent%right_node_index = leaf_sibling_index
805 new_parent%left_node_index = leaf_sibling_index
806 new_parent%right_node_index = leaf_node_index
809 leaf_node%parent_node_index = new_parent_index
810 leaf_sibling%parent_node_index = new_parent_index
814 this%root_node_index = new_parent_index
818 old_parent = this%nodes(old_parent_index)
819 if (old_parent%left_node_index .eq. leaf_sibling_index)
then
820 old_parent%left_node_index = new_parent_index
822 old_parent%right_node_index = new_parent_index
824 this%nodes(old_parent_index) = old_parent
827 this%nodes(leaf_node_index) = leaf_node
828 this%nodes(leaf_sibling_index) = leaf_sibling
829 this%nodes(new_parent_index) = new_parent
832 tree_node_index = leaf_node%parent_node_index
834 call this%fix_upwards_tree(tree_node_index)
847 integer :: current_index
848 integer :: root_index, left_index, right_index
855 root_index = this%get_root_index()
857 call simple_stack%init(this%node_capacity)
858 call simple_stack%push(root_index)
860 do while (.not. simple_stack%is_empty())
861 current_index = simple_stack%pop()
864 valid = valid .and. this%nodes(current_index)%is_valid()
866 if (.not. this%nodes(current_index)%is_leaf())
then
867 left_index = this%get_left_index(current_index)
868 right_index = this%get_right_index(current_index)
870 call simple_stack%push(left_index)
871 call simple_stack%push(right_index)
881 integer,
intent(in) :: tree_start_index
885 integer :: tree_node_index
887 tree_node_index = tree_start_index
889 left_node = this%get_left_node(tree_node_index)
890 right_node = this%get_right_node(tree_node_index)
892 this%nodes(tree_node_index)%aabb = merge(left_node%aabb, right_node%aabb)
894 tree_node_index = this%get_parent_index(tree_node_index)
904 integer :: current_index
905 integer :: root_index, left_index, right_index
907 root_index = this%get_root_index()
908 call simple_stack%init(this%node_capacity)
909 call simple_stack%push(root_index)
911 do while (.not. simple_stack%is_empty())
912 current_index = simple_stack%pop()
915 left_index = this%get_left_index(current_index)
916 right_index = this%get_right_index(current_index)
918 call simple_stack%push(this%nodes(current_index)%left_node_index)
919 call simple_stack%push(this%nodes(current_index)%right_node_index)
921 write(*, *)
"i = ", current_index
922 write(*, *)
" Parent : ", this%get_parent_index(current_index)
923 write(*, *)
" Children: ", this%get_left_index(current_index), &
924 this%get_right_index(current_index)
926 write(*, *)
" object_index = ", this%nodes(current_index)%object_index
934 integer,
intent(in) :: new_capacity
936 type(
aabb_node_t),
dimension(:),
allocatable :: temp
939 allocate(temp(new_capacity))
940 temp(:this%node_capacity) = this%nodes(:this%node_capacity)
942 do i = this%allocated_node_count, new_capacity
943 temp(i)%next_node_index = i + 1
947 call move_alloc(temp, this%nodes)
949 this%node_capacity = new_capacity
950 this%next_free_node_index = this%allocated_node_count + 1
Axis Aligned Bounding Box (aabb) Tree data structure.
pure type(aabb_t) function aabb_tree_get_aabb(this, node_index)
subroutine aabb_tree_fix_upwards_tree(this, tree_start_index)
Fixes the tree upwards.
pure logical function aabb_node_is_valid(this)
Returns true if the node is a valid node.
subroutine aabb_node_init(this)
Initializes the AABB node.
pure type(aabb_node_t) function aabb_tree_get_right_node(this, node_index)
Returns the right node of the node at the given index.
pure type(aabb_node_t) function aabb_tree_get_parent_node(this, node_index)
Returns the parent node of the node at the given index.
pure type(aabb_node_t) function aabb_tree_get_root_node(this)
Returns the root node of the tree.
subroutine aabb_tree_insert_object(this, object, object_index)
Inserts an object into the tree.
pure type(aabb_node_t) function aabb_tree_get_node(this, node_index)
Returns the node at the given index.
subroutine aabb_tree_print(this)
Prints the tree.
pure logical function aabb_node_greater(this, other)
Returns true if the node is greater than the other node.
integer function aabb_tree_allocate_node(this)
Allocates a new node in the tree.
pure type(aabb_t) function aabb_node_get_aabb(this)
Returns the Axis Aligned Bounding Box (aabb) of the node.
pure integer function aabb_tree_get_root_index(this)
Returns the index of the root node.
pure integer function aabb_node_get_right_index(this)
Returns the right index of the node.
subroutine aabb_tree_deallocate_node(this, node_index)
Deallocates a node in the tree.
pure integer function aabb_node_get_left_index(this)
Returns the left index of the node.
pure logical function aabb_node_is_leaf(this)
Returns true if the node is a leaf node.
real(kind=dp) function aabb_node_min_distance(this, p)
Get the minimum possible distance from the aabb to a point.
subroutine aabb_tree_init(this, initial_capacity)
Initializes the AABB tree.
subroutine aabb_tree_insert_leaf(this, leaf_node_index)
Inserts a leaf into the tree.
subroutine aabb_tree_query_overlaps(this, object, object_index, overlaps)
Queries the tree for overlapping objects.
subroutine aabb_tree_build_tree(this, objects)
Builds the tree.
integer function, dimension(:), allocatable sort(array)
pure logical function aabb_node_less(this, other)
Returns true if the node is less than the other node.
pure integer function aabb_tree_get_parent_index(this, node_index)
Returns the index of the parent node of the node at the given index.
pure integer function aabb_node_get_parent_index(this)
Returns the parent index of the node.
pure integer function aabb_tree_get_left_index(this, node_index)
Returns the index of the left node of the node at the given index.
integer, parameter, public aabb_null_node
pure integer function aabb_node_get_object_index(this)
Returns the object index of the node.
logical function aabb_tree_valid_tree(this)
Validates the tree.
pure type(aabb_node_t) function aabb_tree_get_left_node(this, node_index)
Returns the left node of the node at the given index.
integer function aabb_tree_get_size(this)
Returns the size of the tree, in number of leaves.
subroutine aabb_tree_resize_node_pool(this, new_capacity)
Resizes the node pool.
pure integer function aabb_tree_get_right_index(this, node_index)
Returns the index of the right node of the node at the given index.
Axis Aligned Bounding Box (aabb) implementation in Fortran.
type(aabb_t) function, public get_aabb(object, padding)
Construct the aabb of a predefined object.
integer, parameter, public dp
integer, parameter, public rp
Global precision used in computations.
Implements a dynamic stack ADT.
Defines a triangular element.
Axis Aligned Bounding Box (aabb) data structure.
Node type for the Axis Aligned Bounding Box (aabb) Tree.
Axis Aligned Bounding Box (aabb) Tree.