89 integer :: object_index = -1
104 procedure, pass(this),
public :: get_object_index => &
106 procedure, pass(this),
public :: get_parent_index => &
108 procedure, pass(this),
public :: get_left_index => &
110 procedure, pass(this),
public :: get_right_index => &
121 generic ::
operator(.lt.) => less
122 generic ::
operator(.gt.) => greater
134 integer :: allocated_node_count = 0
136 integer :: node_capacity = 0
137 integer :: growth_size = 1
144 procedure, pass(this),
public :: build_from_aabb => &
146 procedure, pass(this),
public :: insert_object => &
148 generic :: build => build_generic
153 procedure, pass(this),
public :: get_root_index => &
155 procedure, pass(this),
public :: get_parent_index => &
157 procedure, pass(this),
public :: get_left_index => &
159 procedure, pass(this),
public :: get_right_index => &
163 procedure, pass(this),
public :: get_root_node => &
165 procedure, pass(this),
public :: get_parent_node => &
167 procedure, pass(this),
public :: get_left_node => &
169 procedure, pass(this),
public :: get_right_node => &
174 procedure, pass(this),
public :: query_overlaps => &
203 this%object_index = -1
224 integer :: object_index
226 object_index = this%object_index
232 integer :: parent_index
234 parent_index = this%parent_node_index
240 integer :: left_index
242 left_index = this%left_node_index
248 integer :: right_index
250 right_index = this%right_node_index
256 real(kind=
dp),
dimension(3),
intent(in) :: p
257 real(kind=
dp) :: distance
259 distance = 0.5_rp * this%aabb%get_diameter() &
260 - norm2(this%aabb%get_center() - p)
280 if (this%is_leaf())
then
284 & this%object_index .gt. 0
289 & this%object_index .eq. -1
303 res = this%aabb .lt. other%aabb
313 res = this%aabb .gt. other%aabb
324 integer,
intent(in) :: initial_capacity
325 integer :: i, nonzero_capacity
327 if (initial_capacity < 1)
then
330 nonzero_capacity = initial_capacity
334 this%allocated_node_count = 0
335 this%next_free_node_index = 1
336 this%node_capacity = nonzero_capacity
337 this%growth_size = nonzero_capacity
339 if (
allocated(this%nodes))
deallocate(this%nodes)
340 allocate(this%nodes(nonzero_capacity))
342 do i = 1, nonzero_capacity
343 this%nodes(i)%next_node_index = i + 1
351 type(
aabb_t),
intent(in) :: objects(:)
352 real(kind=
dp),
optional,
intent(in) :: padding
354 integer :: i_obj, i_node, i
357 integer :: start_layer, end_layer
359 type(
aabb_t),
allocatable :: box_list(:)
360 integer,
dimension(:),
allocatable :: sorted_indices
362 real(kind=
dp) :: aabb_padding
364 if (
allocated(box_list))
deallocate(box_list)
365 allocate(box_list(
size(objects)))
367 call this%init(
size(objects) * 2)
368 if (
size(objects) .eq. 0)
then
377 if (
present(padding))
then
378 aabb_padding = padding
380 aabb_padding = 0.0_dp
383 do i_obj = 1,
size(objects)
384 box_list(i_obj) =
get_aabb(objects(i_obj), aabb_padding)
386 call sort(box_list, sorted_indices)
388 do i = 1,
size(sorted_indices)
389 i_obj = sorted_indices(i)
390 i_node = this%allocate_node()
391 this%nodes(i_node)%aabb = box_list(i_obj)
392 this%nodes(i_node)%object_index = i_obj
397 end_layer =
size(objects)
399 do while (.not. done)
402 do i = start_layer, end_layer - 1, 2
403 i_node = this%allocate_node()
405 this%nodes(i_node)%aabb =
merge(this%nodes(i)%aabb, &
406 this%nodes(i + 1)%aabb)
408 this%nodes(i_node)%left_node_index = i
409 this%nodes(i_node)%right_node_index = i + 1
411 this%nodes(i)%parent_node_index = i_node
412 this%nodes(i + 1)%parent_node_index = i_node
417 if (mod(end_layer - start_layer, 2) .eq. 0)
then
418 i_node = this%allocate_node()
419 this%nodes(i_node)%aabb = this%nodes(end_layer)%aabb
420 this%nodes(i_node)%left_node_index = end_layer
423 this%nodes(end_layer)%parent_node_index = i_node
427 start_layer = end_layer + 1
428 end_layer = this%allocated_node_count
431 done = start_layer .eq. end_layer
435 this%root_node_index = this%allocated_node_count
437 if (this%get_size() .ne.
size(objects))
then
438 print *,
"this%get_size() = ", this%get_size()
439 print *,
"size(objects) = ",
size(objects)
450 class(*),
target,
intent(in) :: objects(:)
451 real(kind=
dp),
optional,
intent(in) :: padding
453 integer :: i_obj, i_node, i
456 integer :: start_layer, end_layer
458 type(
aabb_t),
allocatable :: box_list(:)
459 integer,
dimension(:),
allocatable :: sorted_indices
461 real(kind=
dp) :: aabb_padding
463 if (
allocated(box_list))
deallocate(box_list)
464 allocate(box_list(
size(objects)))
466 call this%init(
size(objects) * 2)
467 if (
size(objects) .eq. 0)
then
476 if (
present(padding))
then
477 aabb_padding = padding
479 aabb_padding = 0.0_dp
482 do i_obj = 1,
size(objects)
483 box_list(i_obj) =
get_aabb(objects(i_obj), aabb_padding)
485 call sort(box_list, sorted_indices)
487 do i = 1,
size(sorted_indices)
488 i_obj = sorted_indices(i)
489 i_node = this%allocate_node()
490 this%nodes(i_node)%aabb = box_list(i_obj)
491 this%nodes(i_node)%object_index = i_obj
496 end_layer =
size(objects)
498 do while (.not. done)
501 do i = start_layer, end_layer - 1, 2
502 i_node = this%allocate_node()
504 this%nodes(i_node)%aabb =
merge(this%nodes(i)%aabb, &
505 this%nodes(i + 1)%aabb)
507 this%nodes(i_node)%left_node_index = i
508 this%nodes(i_node)%right_node_index = i + 1
510 this%nodes(i)%parent_node_index = i_node
511 this%nodes(i + 1)%parent_node_index = i_node
516 if (mod(end_layer - start_layer, 2) .eq. 0)
then
517 i_node = this%allocate_node()
518 this%nodes(i_node)%aabb = this%nodes(end_layer)%aabb
519 this%nodes(i_node)%left_node_index = end_layer
522 this%nodes(end_layer)%parent_node_index = i_node
526 start_layer = end_layer + 1
527 end_layer = this%allocated_node_count
530 done = start_layer .eq. end_layer
534 this%root_node_index = this%allocated_node_count
536 if (this%get_size() .ne.
size(objects))
then
537 print *,
"this%get_size() = ", this%get_size()
538 print *,
"size(objects) = ",
size(objects)
542 if (
allocated(box_list))
deallocate(box_list)
543 if (
allocated(sorted_indices))
deallocate(sorted_indices)
547 subroutine sort(array, indices)
548 type(
aabb_t),
dimension(:),
intent(in) :: array
549 integer,
intent(inout),
dimension(:),
allocatable :: indices
550 logical,
dimension(:),
allocatable :: visited
555 allocate(indices(
size(array)))
556 allocate(visited(
size(array)))
560 do i = 1,
size(array)
562 do imin = 1,
size(array)
563 if (.not. visited(imin) .and. minidx .eq. -1) minidx = imin
564 if (minidx .gt. -1)
then
565 if (visited(imin) .and. array(imin) .lt. array(minidx)) minidx = imin
570 visited(minidx) = .true.
573 if (
allocated(visited))
deallocate(visited)
587 call simple_stack%init(this%allocated_node_count)
589 tmp = this%get_root_index()
591 call simple_stack%push(tmp)
594 do while (.not. simple_stack%is_empty())
595 idx = simple_stack%pop()
598 if (this%nodes(idx)%is_leaf())
then
601 tmp = this%get_left_index(idx)
602 call simple_stack%push(tmp)
603 tmp = this%get_right_index(idx)
604 call simple_stack%push(tmp)
608 call simple_stack%free()
617 integer :: root_index
619 root_index = this%root_node_index
626 integer,
intent(in) :: node_index
627 integer :: parent_index
629 parent_index = this%nodes(node_index)%parent_node_index
636 integer,
intent(in) :: node_index
637 integer :: left_index
639 left_index = this%nodes(node_index)%left_node_index
646 integer,
intent(in) :: node_index
647 integer :: right_index
649 right_index = this%nodes(node_index)%right_node_index
658 integer,
intent(in) :: node_index
661 node = this%nodes(node_index)
669 root_node = this%nodes(this%root_node_index)
676 integer,
intent(in) :: node_index
679 parent_node = this%nodes(this%nodes(node_index)%parent_node_index)
685 integer,
intent(in) :: node_index
688 left_node = this%nodes(this%nodes(node_index)%left_node_index)
695 integer,
intent(in) :: node_index
698 right_node = this%nodes(this%nodes(node_index)%right_node_index)
703 integer,
intent(in) :: node_index
706 out_box = this%nodes(node_index)%aabb
714 class(*),
intent(in) :: object
715 integer,
intent(in) :: object_index
717 integer :: node_index
719 node_index = this%allocate_node()
720 this%nodes(node_index)%aabb =
get_aabb(object)
721 this%nodes(node_index)%object_index = object_index
723 call this%insert_leaf(node_index)
729 class(*),
intent(in) :: object
730 integer,
intent(in) :: object_index
734 type(
aabb_t) :: object_box
736 integer :: root_index, left_index, right_index
737 integer :: node_index, tmp_index
740 root_index = this%get_root_index()
742 call simple_stack%init()
743 call simple_stack%push(root_index)
745 do while (.not. simple_stack%is_empty())
746 node_index = simple_stack%pop()
750 if (this%nodes(node_index)%aabb%overlaps(object_box))
then
751 if (this%nodes(node_index)%is_leaf())
then
752 if (this%nodes(node_index)%object_index .ne. object_index)
then
753 tmp_index = this%nodes(node_index)%object_index
754 call overlaps%push(tmp_index)
757 left_index = this%get_left_index(node_index)
759 call simple_stack%push(left_index)
761 right_index = this%get_right_index(node_index)
763 call simple_stack%push(right_index)
768 call simple_stack%free()
777 integer :: node_index
780 call this%resize_node_pool(this%node_capacity + this%growth_size)
783 node_index = this%next_free_node_index
785 associate(new_node => this%nodes(node_index))
786 this%next_free_node_index = new_node%next_node_index
792 this%next_free_node_index = new_node%next_node_index
793 this%allocated_node_count = this%allocated_node_count + 1
801 integer,
intent(in) :: node_index
803 this%nodes(node_index)%next_node_index = this%next_free_node_index
804 this%next_free_node_index = node_index
805 this%allocated_node_count = this%allocated_node_count - 1
811 integer,
intent(in) :: leaf_node_index
813 integer :: tree_node_index
815 real(kind=rp) :: cost_left
816 real(kind=rp) :: cost_right
823 type(aabb_t) :: combined_aabb
824 real(kind=rp) :: new_parent_node_cost
825 real(kind=rp) :: minimum_push_down_cost
826 type(aabb_t) :: new_left_aabb
827 type(aabb_t) :: new_right_aabb
828 integer :: leaf_sibling_index
830 integer :: old_parent_index
831 integer :: new_parent_index
836 leaf_node = this%nodes(leaf_node_index)
840 this%root_node_index = leaf_node_index
850 tree_node_index = this%root_node_index
851 tree_node = this%get_node(tree_node_index)
852 do while (.not. tree_node%is_leaf())
856 left_node = this%get_left_node(tree_node_index)
857 right_node = this%get_right_node(tree_node_index)
861 combined_aabb = merge(tree_node%aabb, leaf_node%get_aabb())
863 new_parent_node_cost = 2.0_rp * combined_aabb%get_surface_area()
864 minimum_push_down_cost = 2.0_rp * ( &
865 & combined_aabb%get_surface_area() &
866 & - tree_node%aabb%get_surface_area()&
871 if (left_node%is_leaf())
then
872 new_left_aabb = merge(leaf_node%aabb, left_node%get_aabb())
873 cost_left = new_left_aabb%get_surface_area() + minimum_push_down_cost
875 new_left_aabb = merge(leaf_node%aabb, left_node%get_aabb())
877 & new_left_aabb%get_surface_area() &
878 & - left_node%aabb%get_surface_area()&
879 & ) + minimum_push_down_cost
882 if (right_node%is_leaf())
then
883 new_right_aabb = merge(leaf_node%aabb, right_node%aabb)
884 cost_right = new_right_aabb%get_surface_area() + &
885 minimum_push_down_cost
887 new_right_aabb = merge(leaf_node%aabb, right_node%aabb)
889 & new_right_aabb%get_surface_area() &
890 & - right_node%aabb%get_surface_area() &
891 & ) + minimum_push_down_cost
897 if (new_parent_node_cost < cost_left .and. &
898 new_parent_node_cost < cost_right)
then
903 if (cost_left .lt. cost_right)
then
904 tree_node_index = tree_node%get_left_index()
906 tree_node_index = tree_node%get_right_index()
911 tree_node = this%get_node(tree_node_index)
916 leaf_sibling_index = tree_node_index
917 leaf_sibling = this%nodes(leaf_sibling_index)
918 old_parent_index = this%get_parent_index(leaf_sibling_index)
919 new_parent_index = this%allocate_node()
920 new_parent = this%nodes(new_parent_index)
921 new_parent%parent_node_index = old_parent_index
922 new_parent%aabb = merge(leaf_node%aabb, leaf_sibling%aabb)
924 if (leaf_node .lt. leaf_sibling)
then
925 new_parent%left_node_index = leaf_node_index
926 new_parent%right_node_index = leaf_sibling_index
928 new_parent%left_node_index = leaf_sibling_index
929 new_parent%right_node_index = leaf_node_index
932 leaf_node%parent_node_index = new_parent_index
933 leaf_sibling%parent_node_index = new_parent_index
937 this%root_node_index = new_parent_index
941 old_parent = this%nodes(old_parent_index)
942 if (old_parent%left_node_index .eq. leaf_sibling_index)
then
943 old_parent%left_node_index = new_parent_index
945 old_parent%right_node_index = new_parent_index
947 this%nodes(old_parent_index) = old_parent
950 this%nodes(leaf_node_index) = leaf_node
951 this%nodes(leaf_sibling_index) = leaf_sibling
952 this%nodes(new_parent_index) = new_parent
955 tree_node_index = leaf_node%parent_node_index
957 call this%fix_upwards_tree(tree_node_index)
966 type(stack_i4_t) :: simple_stack
967 integer :: current_index
968 integer :: root_index, left_index, right_index
975 root_index = this%get_root_index()
977 call simple_stack%init(this%node_capacity)
978 call simple_stack%push(root_index)
980 do while (.not. simple_stack%is_empty())
981 current_index = simple_stack%pop()
984 valid = valid .and. this%nodes(current_index)%is_valid()
986 if (.not. this%nodes(current_index)%is_leaf())
then
987 left_index = this%get_left_index(current_index)
988 right_index = this%get_right_index(current_index)
990 call simple_stack%push(left_index)
991 call simple_stack%push(right_index)
1001 integer,
intent(in) :: tree_start_index
1005 integer :: tree_node_index
1007 tree_node_index = tree_start_index
1009 left_node = this%get_left_node(tree_node_index)
1010 right_node = this%get_right_node(tree_node_index)
1012 this%nodes(tree_node_index)%aabb = merge(left_node%aabb, right_node%aabb)
1014 tree_node_index = this%get_parent_index(tree_node_index)
1021 type(stack_i4_t) :: simple_stack
1023 integer :: current_index
1024 integer :: root_index, left_index, right_index
1026 root_index = this%get_root_index()
1027 call simple_stack%init(this%node_capacity)
1028 call simple_stack%push(root_index)
1030 do while (.not. simple_stack%is_empty())
1031 current_index = simple_stack%pop()
1034 left_index = this%get_left_index(current_index)
1035 right_index = this%get_right_index(current_index)
1037 call simple_stack%push(this%nodes(current_index)%left_node_index)
1038 call simple_stack%push(this%nodes(current_index)%right_node_index)
1040 write(*, *)
"i = ", current_index
1041 write(*, *)
" Parent : ", this%get_parent_index(current_index)
1042 write(*, *)
" Children: ", this%get_left_index(current_index), &
1043 this%get_right_index(current_index)
1045 write(*, *)
" object_index = ", this%nodes(current_index)%object_index
1053 integer,
intent(in) :: new_capacity
1055 type(
aabb_node_t),
dimension(:),
allocatable :: temp
1058 allocate(temp(new_capacity))
1059 temp(:this%node_capacity) = this%nodes(:this%node_capacity)
1061 do i = this%allocated_node_count, new_capacity
1062 temp(i)%next_node_index = i + 1
1066 call move_alloc(temp, this%nodes)
1068 this%node_capacity = new_capacity
1069 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.
subroutine aabb_tree_build_tree_aabb(this, objects, padding)
Builds the tree.
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 sort(array, indices)
Return a list of sorted indices of the aabb nodes.
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.
subroutine aabb_tree_build_tree(this, objects, padding)
Builds the tree.
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.