Neko  0.8.1
A portable framework for high-order spectral element flow simulations
aabb_tree.f90
Go to the documentation of this file.
1 ! Copyright (c) 2024, The Neko Authors
2 ! All rights reserved.
3 !
4 ! Redistribution and use in source and binary forms, with or without
5 ! modification, are permitted provided that the following conditions
6 ! are met:
7 !
8 ! * Redistributions of source code must retain the above copyright
9 ! notice, this list of conditions and the following disclaimer.
10 !
11 ! * Redistributions in binary form must reproduce the above
12 ! copyright notice, this list of conditions and the following
13 ! disclaimer in the documentation and/or other materials provided
14 ! with the distribution.
15 !
16 ! * Neither the name of the authors nor the names of its
17 ! contributors may be used to endorse or promote products derived
18 ! from this software without specific prior written permission.
19 !
20 ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 ! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 ! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 ! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 ! COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 ! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 ! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 ! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 ! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 ! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 ! POSSIBILITY OF SUCH DAMAGE.
32 !
33 ! ============================================================================ !
34 ! Original C++ Implementation from:
35 ! https://github.com/JamesRandall/SimpleVoxelEngine/blob/master/voxelEngine/src/AABBTree.h
36 !
37 ! Translated to Fortran by:
38 ! @author Tim Felle Olsen
39 ! @date 9 Feb 2024
40 !
41 ! C++ Code License:
42 ! The MIT License (MIT)
43 !
44 ! Copyright (c) 2017 James Randall
45 !
46 ! Permission is hereby granted, free of charge, to any person obtaining a copy of
47 ! this software and associated documentation files (the "Software"), to deal in
48 ! the Software without restriction, including without limitation the rights to
49 ! use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
50 ! the Software, and to permit persons to whom the Software is furnished to do so,
51 ! subject to the following conditions:
52 !
53 ! The above copyright notice and this permission notice shall be included in all
54 ! copies or substantial portions of the Software.
55 !
56 ! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
57 ! IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
58 ! FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
59 ! COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
60 ! IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
61 ! CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
62 ! ============================================================================ !
63 
70 module aabb_tree
71  use aabb
72  use tri, only: tri_t
73  use num_types, only: rp, dp
74 
75  implicit none
76  private
77 
78  integer, parameter, public :: aabb_null_node = -1
79 
80  ! ========================================================================== !
81  ! Type definitions
82  ! ========================================================================== !
83 
85  type, public :: aabb_node_t
86  private
87  type(aabb_t), public :: aabb
88  integer :: object_index = -1
89 
90  ! tree links
91  integer :: parent_node_index = aabb_null_node
92  integer :: left_node_index = aabb_null_node
93  integer :: right_node_index = aabb_null_node
94 
95  ! node linked list link
96  integer :: next_node_index = aabb_null_node
97 
98  contains
99  procedure, pass(this), public :: init => aabb_node_init
100 
101  ! Getters
102  procedure, pass(this), public :: get_aabb => aabb_node_get_aabb
103  procedure, pass(this), public :: get_object_index => aabb_node_get_object_index
104  procedure, pass(this), public :: get_parent_index => aabb_node_get_parent_index
105  procedure, pass(this), public :: get_left_index => aabb_node_get_left_index
106  procedure, pass(this), public :: get_right_index => aabb_node_get_right_index
107 
108  ! Unary operations
109  procedure, pass(this), public :: min_distance => aabb_node_min_distance
110 
111  ! Boolean operators
112  procedure, pass(this), public :: is_leaf => aabb_node_is_leaf
113  procedure, pass(this), public :: is_valid => aabb_node_is_valid
114 
115  ! Comparison operators
116  generic :: operator(.lt.) => less
117  generic :: operator(.gt.) => greater
118 
119  procedure, pass(this) :: less => aabb_node_less
120  procedure, pass(this) :: greater => aabb_node_greater
121 
122  end type aabb_node_t
123 
125  type, public :: aabb_tree_t
126  private
127  type(aabb_node_t), allocatable :: nodes(:)
128  integer :: root_node_index = aabb_null_node
129  integer :: allocated_node_count = 0
130  integer :: next_free_node_index = aabb_null_node
131  integer :: node_capacity = 0
132  integer :: growth_size = 1
133 
134  contains
135 
136  ! Initializers
137  procedure, pass(this), public :: init => aabb_tree_init
138  procedure, pass(this), public :: build => aabb_tree_build_tree
139  procedure, pass(this), public :: insert_object => aabb_tree_insert_object
140 
141  ! Getters
142  procedure, pass(this), public :: get_size => aabb_tree_get_size
143 
144  procedure, pass(this), public :: get_root_index => aabb_tree_get_root_index
145  procedure, pass(this), public :: get_parent_index => aabb_tree_get_parent_index
146  procedure, pass(this), public :: get_left_index => aabb_tree_get_left_index
147  procedure, pass(this), public :: get_right_index => aabb_tree_get_right_index
148 
149  procedure, pass(this), public :: get_node => aabb_tree_get_node
150  procedure, pass(this), public :: get_root_node => aabb_tree_get_root_node
151  procedure, pass(this), public :: get_parent_node => aabb_tree_get_parent_node
152  procedure, pass(this), public :: get_left_node => aabb_tree_get_left_node
153  procedure, pass(this), public :: get_right_node => aabb_tree_get_right_node
154 
155  procedure, pass(this), public :: get_aabb => aabb_tree_get_aabb
156 
157  procedure, pass(this), public :: query_overlaps => aabb_tree_query_overlaps
158 
159  procedure, pass(this), public :: print => aabb_tree_print
160 
161  ! ----------------------------------------------------------------------- !
162  ! Internal methods
163 
164  procedure, pass(this) :: allocate_node => aabb_tree_allocate_node
165  procedure, pass(this) :: deallocate_node => aabb_tree_deallocate_node
166  procedure, pass(this) :: resize_node_pool => aabb_tree_resize_node_pool
167  procedure, pass(this) :: insert_leaf => aabb_tree_insert_leaf
168 
169  procedure, pass(this) :: fix_upwards_tree => aabb_tree_fix_upwards_tree
170 
171  procedure, pass(this) :: valid_tree => aabb_tree_valid_tree
172 
173  end type aabb_tree_t
174 
175 contains
176 
177  ! ========================================================================== !
178  ! Definitions of node methods
179  ! ========================================================================== !
180 
182  subroutine aabb_node_init(this)
183  class(aabb_node_t), intent(inout) :: this
184 
185  this%object_index = -1
186  this%parent_node_index = aabb_null_node
187  this%left_node_index = aabb_null_node
188  this%right_node_index = aabb_null_node
189  this%next_node_index = aabb_null_node
190  end subroutine aabb_node_init
191 
192  ! -------------------------------------------------------------------------- !
193  ! Getters
194 
196  pure function aabb_node_get_aabb(this) result(res)
197  class(aabb_node_t), intent(in) :: this
198  type(aabb_t) :: res
199 
200  res = this%aabb
201  end function aabb_node_get_aabb
202 
204  pure function aabb_node_get_object_index(this) result(object_index)
205  class(aabb_node_t), intent(in) :: this
206  integer :: object_index
207 
208  object_index = this%object_index
209  end function aabb_node_get_object_index
210 
212  pure function aabb_node_get_parent_index(this) result(parent_index)
213  class(aabb_node_t), intent(in) :: this
214  integer :: parent_index
215 
216  parent_index = this%parent_node_index
217  end function aabb_node_get_parent_index
218 
220  pure function aabb_node_get_left_index(this) result(left_index)
221  class(aabb_node_t), intent(in) :: this
222  integer :: left_index
223 
224  left_index = this%left_node_index
225  end function aabb_node_get_left_index
226 
228  pure function aabb_node_get_right_index(this) result(right_index)
229  class(aabb_node_t), intent(in) :: this
230  integer :: right_index
231 
232  right_index = this%right_node_index
233  end function aabb_node_get_right_index
234 
236  function aabb_node_min_distance(this, p) result(distance)
237  class(aabb_node_t), intent(in) :: this
238  real(kind=dp), dimension(3), intent(in) :: p
239  real(kind=dp) :: distance
240 
241  distance = 0.5_rp * this%aabb%get_diameter() &
242  - norm2(this%aabb%get_center() - p)
243  end function aabb_node_min_distance
244 
245  ! -------------------------------------------------------------------------- !
246  ! Boolean operators
247 
249  pure function aabb_node_is_leaf(this) result(res)
250  class(aabb_node_t), intent(in) :: this
251  logical :: res
252 
253  res = this%left_node_index == aabb_null_node .and. &
254  this%right_node_index == aabb_null_node
255  end function aabb_node_is_leaf
256 
258  pure function aabb_node_is_valid(this) result(valid)
259  class(aabb_node_t), intent(in) :: this
260  logical :: valid
261 
262  if (this%is_leaf()) then
263  valid = &
264  & this%left_node_index .eq. aabb_null_node .and. &
265  & this%right_node_index .eq. aabb_null_node .and. &
266  & this%object_index .gt. 0
267  else
268  valid = &
269  & this%left_node_index .ne. aabb_null_node .and. &
270  & this%right_node_index .ne. aabb_null_node .and. &
271  & this%object_index .eq. -1
272  end if
273 
274  end function aabb_node_is_valid
275 
276  ! -------------------------------------------------------------------------- !
277  ! Comparison operators
278 
280  pure function aabb_node_less(this, other) result(res)
281  class(aabb_node_t), intent(in) :: this
282  class(aabb_node_t), intent(in) :: other
283  logical :: res
284 
285  res = this%aabb .lt. other%aabb
286 
287  end function aabb_node_less
288 
290  pure function aabb_node_greater(this, other) result(res)
291  class(aabb_node_t), intent(in) :: this
292  class(aabb_node_t), intent(in) :: other
293  logical :: res
294 
295  res = this%aabb .gt. other%aabb
296 
297  end function aabb_node_greater
298 
299  ! ========================================================================== !
300  ! Definitions of tree methods
301  ! ========================================================================== !
302 
304  subroutine aabb_tree_init(this, initial_capacity)
305  class(aabb_tree_t), intent(inout) :: this
306  integer, intent(in) :: initial_capacity
307 
308  integer :: i
309 
310  this%root_node_index = aabb_null_node
311  this%allocated_node_count = 0
312  this%next_free_node_index = 1
313  this%node_capacity = initial_capacity
314  this%growth_size = initial_capacity
315 
316  if (allocated(this%nodes)) deallocate(this%nodes)
317  allocate(this%nodes(initial_capacity))
318 
319  do i = 1, initial_capacity
320  this%nodes(i)%next_node_index = i + 1
321  end do
322  this%nodes(initial_capacity)%next_node_index = aabb_null_node
323  end subroutine aabb_tree_init
324 
326  subroutine aabb_tree_build_tree(this, objects)
327  use utils, only: neko_error
328  implicit none
329 
330  class(aabb_tree_t), intent(inout) :: this
331  class(*), dimension(:), intent(in) :: objects
332 
333  integer :: i_obj, i_node, i
334  logical :: done
335 
336  integer :: start_layer, end_layer
337 
338  type(aabb_t), dimension(:), allocatable :: box_list
339  integer, dimension(:), allocatable :: sorted_indices
340 
341  call this%init(size(objects) * 2)
342 
343  ! ------------------------------------------------------------------------ !
344  ! Start by sorting the list of objects, then build a balanced binary tree
345  ! from the sorted list
346 
347  allocate(box_list(size(objects)))
348 
349  do i_obj = 1, size(objects)
350  box_list(i_obj) = get_aabb(objects(i_obj))
351  end do
352  sorted_indices = sort(box_list)
353 
354  do i = 1, size(sorted_indices)
355  i_obj = sorted_indices(i)
356  i_node = this%allocate_node()
357  this%nodes(i_node)%aabb = get_aabb(objects(i_obj))
358  this%nodes(i_node)%object_index = i_obj
359  end do
360 
361 
362  start_layer = 1
363  end_layer = size(objects)
364  done = .false.
365  do while (.not. done)
366 
367  ! build the next layer
368  do i = start_layer, end_layer - 1, 2
369  i_node = this%allocate_node()
370 
371  this%nodes(i_node)%aabb = merge(this%nodes(i)%aabb, this%nodes(i + 1)%aabb)
372 
373  this%nodes(i_node)%left_node_index = i
374  this%nodes(i_node)%right_node_index = i + 1
375 
376  this%nodes(i)%parent_node_index = i_node
377  this%nodes(i + 1)%parent_node_index = i_node
378  end do
379 
380  ! if the number of nodes is odd, we need to create a new node to hold the
381  ! last node
382  if (mod(end_layer - start_layer, 2) .eq. 0) then
383  i_node = this%allocate_node()
384  this%nodes(i_node)%aabb = this%nodes(end_layer)%aabb
385  this%nodes(i_node)%left_node_index = end_layer
386  this%nodes(i_node)%right_node_index = aabb_null_node
387 
388  this%nodes(end_layer)%parent_node_index = i_node
389  end if
390 
391  ! move to the next layer
392  start_layer = end_layer + 1
393  end_layer = this%allocated_node_count
394 
395  ! If there is only one node left, we are done
396  done = start_layer .eq. end_layer
397  end do
398 
399  ! The last node allocated is the root node
400  this%root_node_index = this%allocated_node_count
401 
402  if (this%get_size() .ne. size(objects)) then
403  print *, "this%get_size() = ", this%get_size()
404  print *, "size(objects) = ", size(objects)
405  call neko_error("Invalid tree size")
406  end if
407 
408  end subroutine aabb_tree_build_tree
409 
410  function sort(array) result(indices)
411  type(aabb_t), dimension(:), intent(in) :: array
412  integer, dimension(:), allocatable :: indices
413  logical, dimension(:), allocatable :: visited
414 
415  integer :: i, imin
416  integer :: minidx
417 
418  allocate(indices(size(array)))
419  allocate(visited(size(array)))
420 
421  visited = .false.
422  indices = 0
423  do i = 1, size(array)
424  minidx = -1
425  do imin = 1, size(array)
426  if (.not. visited(imin) .and. minidx .eq. -1) minidx = imin
427 
428  if (visited(imin) .and. array(imin) .lt. array(minidx)) minidx = imin
429  end do
430 
431  indices(i) = minidx
432  visited(minidx) = .true.
433  end do
434 
435  end function sort
436 
437  ! -------------------------------------------------------------------------- !
438  ! Getters
439 
441  function aabb_tree_get_size(this) result(size)
442  use stack, only: stack_i4_t
443  use utils, only: neko_error
444  class(aabb_tree_t), intent(in) :: this
445  integer :: size
446 
447  type(stack_i4_t) :: simple_stack
448  integer :: idx, tmp
449 
450  call simple_stack%init(this%allocated_node_count)
451  size = 0
452  tmp = this%get_root_index()
453  if (tmp .ne. aabb_null_node) then
454  call simple_stack%push(tmp)
455  end if
456 
457  do while (.not. simple_stack%is_empty())
458  idx = simple_stack%pop()
459  if (idx .eq. aabb_null_node) cycle
460 
461  if (this%nodes(idx)%is_leaf()) then
462  size = size + 1
463  else
464  tmp = this%get_left_index(idx)
465  call simple_stack%push(tmp)
466  tmp = this%get_right_index(idx)
467  call simple_stack%push(tmp)
468  end if
469  end do
470 
471  end function aabb_tree_get_size
472 
473  ! -------------------------------------------------------------------------- !
474  ! Get index of nodes
475 
477  pure function aabb_tree_get_root_index(this) result(root_index)
478  class(aabb_tree_t), intent(in) :: this
479  integer :: root_index
480 
481  root_index = this%root_node_index
482  end function aabb_tree_get_root_index
483 
485  pure function aabb_tree_get_parent_index(this, node_index) result(parent_index)
486  class(aabb_tree_t), intent(in) :: this
487  integer, intent(in) :: node_index
488  integer :: parent_index
489 
490  parent_index = this%nodes(node_index)%parent_node_index
491  end function aabb_tree_get_parent_index
492 
494  pure function aabb_tree_get_left_index(this, node_index) result(left_index)
495  class(aabb_tree_t), intent(in) :: this
496  integer, intent(in) :: node_index
497  integer :: left_index
498 
499  left_index = this%nodes(node_index)%left_node_index
500  end function aabb_tree_get_left_index
501 
503  pure function aabb_tree_get_right_index(this, node_index) result(right_index)
504  class(aabb_tree_t), intent(in) :: this
505  integer, intent(in) :: node_index
506  integer :: right_index
507 
508  right_index = this%nodes(node_index)%right_node_index
509  end function aabb_tree_get_right_index
510 
511  ! -------------------------------------------------------------------------- !
512  ! Get nodes
513 
515  pure function aabb_tree_get_node(this, node_index) result(node)
516  class(aabb_tree_t), intent(in) :: this
517  integer, intent(in) :: node_index
518  type(aabb_node_t) :: node
519 
520  node = this%nodes(node_index)
521  end function aabb_tree_get_node
522 
524  pure function aabb_tree_get_root_node(this) result(root_node)
525  class(aabb_tree_t), intent(in) :: this
526  type(aabb_node_t) :: root_node
527 
528  root_node = this%nodes(this%root_node_index)
529  end function aabb_tree_get_root_node
530 
532  pure function aabb_tree_get_parent_node(this, node_index) result(parent_node)
533  class(aabb_tree_t), intent(in) :: this
534  integer, intent(in) :: node_index
535  type(aabb_node_t) :: parent_node
536 
537  parent_node = this%nodes(this%nodes(node_index)%parent_node_index)
538  end function aabb_tree_get_parent_node
539 
541  pure function aabb_tree_get_left_node(this, node_index) result(left_node)
542  class(aabb_tree_t), intent(in) :: this
543  integer, intent(in) :: node_index
544  type(aabb_node_t) :: left_node
545 
546  left_node = this%nodes(this%nodes(node_index)%left_node_index)
547  end function aabb_tree_get_left_node
548 
550  pure function aabb_tree_get_right_node(this, node_index) result(right_node)
551  class(aabb_tree_t), intent(in) :: this
552  integer, intent(in) :: node_index
553  type(aabb_node_t) :: right_node
554 
555  right_node = this%nodes(this%nodes(node_index)%right_node_index)
556  end function aabb_tree_get_right_node
557 
558  pure function aabb_tree_get_aabb(this, node_index) result(out_box)
559  class(aabb_tree_t), intent(in) :: this
560  integer, intent(in) :: node_index
561  type(aabb_t) :: out_box
562 
563  out_box = this%nodes(node_index)%aabb
564  end function aabb_tree_get_aabb
565 
566  ! -------------------------------------------------------------------------- !
567 
569  subroutine aabb_tree_insert_object(this, object, object_index)
570  class(aabb_tree_t), intent(inout) :: this
571  class(*), intent(in) :: object
572  integer, intent(in) :: object_index
573 
574  integer :: node_index
575 
576  node_index = this%allocate_node()
577  this%nodes(node_index)%aabb = get_aabb(object)
578  this%nodes(node_index)%object_index = object_index
579 
580  call this%insert_leaf(node_index)
581  end subroutine aabb_tree_insert_object
582 
584  subroutine aabb_tree_query_overlaps(this, object, object_index, overlaps)
585  use stack, only: stack_i4_t
586  implicit none
587 
588  class(aabb_tree_t), intent(in) :: this
589  class(*), intent(in) :: object
590  integer, intent(in) :: object_index
591  integer, intent(out) :: overlaps(:)
592 
593  type(stack_i4_t) :: simple_stack
594  type(aabb_t) :: object_box
595 
596  integer :: root_index, left_index, right_index
597 
598  integer :: node_index
599 
600  object_box = get_aabb(object)
601  root_index = this%get_root_index()
602 
603  call simple_stack%push(root_index)
604 
605  do while (.not. simple_stack%is_empty())
606  node_index = simple_stack%pop()
607 
608  if (node_index == aabb_null_node) cycle
609 
610  if (this%nodes(node_index)%aabb%overlaps(object_box)) then
611  if (this%nodes(node_index)%is_leaf()) then
612  if (.not. this%nodes(node_index)%object_index == object_index) then
613  overlaps = [this%nodes(node_index)%object_index, overlaps]
614  end if
615  else
616  left_index = this%get_left_index(node_index)
617  call simple_stack%push(left_index)
618  right_index = this%get_right_index(node_index)
619  call simple_stack%push(right_index)
620  end if
621  end if
622  end do
623  end subroutine aabb_tree_query_overlaps
624 
625  ! -------------------------------------------------------------------------- !
626  ! Internal methods
627 
629  function aabb_tree_allocate_node(this) result(node_index)
630  class(aabb_tree_t), intent(inout) :: this
631  integer :: node_index
632 
633  if (this%next_free_node_index == aabb_null_node) then
634  call this%resize_node_pool(this%node_capacity + this%growth_size)
635  end if
636 
637  node_index = this%next_free_node_index
638 
639  associate(new_node => this%nodes(node_index))
640  this%next_free_node_index = new_node%next_node_index
641 
642  new_node%parent_node_index = aabb_null_node
643  new_node%left_node_index = aabb_null_node
644  new_node%right_node_index = aabb_null_node
645 
646  this%next_free_node_index = new_node%next_node_index
647  this%allocated_node_count = this%allocated_node_count + 1
648 
649  end associate
650  end function aabb_tree_allocate_node
651 
653  subroutine aabb_tree_deallocate_node(this, node_index)
654  class(aabb_tree_t), intent(inout) :: this
655  integer, intent(in) :: node_index
656 
657  this%nodes(node_index)%next_node_index = this%next_free_node_index
658  this%next_free_node_index = node_index
659  this%allocated_node_count = this%allocated_node_count - 1
660  end subroutine aabb_tree_deallocate_node
661 
663  subroutine aabb_tree_insert_leaf(this, leaf_node_index)
664  class(aabb_tree_t), intent(inout) :: this
665  integer, intent(in) :: leaf_node_index
666 
667  integer :: tree_node_index
668 
669  real(kind=rp) :: cost_left
670  real(kind=rp) :: cost_right
671 
672  type(aabb_node_t) :: leaf_node
673  type(aabb_node_t) :: tree_node
674  type(aabb_node_t) :: left_node
675  type(aabb_node_t) :: right_node
676 
677  type(aabb_t) :: combined_aabb
678  real(kind=rp) :: new_parent_node_cost
679  real(kind=rp) :: minimum_push_down_cost
680  type(aabb_t) :: new_left_aabb
681  type(aabb_t) :: new_right_aabb
682  integer :: leaf_sibling_index
683  type(aabb_node_t) :: leaf_sibling
684  integer :: old_parent_index
685  integer :: new_parent_index
686  type(aabb_node_t) :: new_parent
687  type(aabb_node_t) :: old_parent
688 
689  ! make sure were inserting a new leaf
690  leaf_node = this%nodes(leaf_node_index)
691 
692  ! if the tree is empty then we make the root the leaf
693  if (this%root_node_index .eq. aabb_null_node) then
694  this%root_node_index = leaf_node_index
695  leaf_node%parent_node_index = aabb_null_node
696  leaf_node%left_node_index = aabb_null_node
697  leaf_node%right_node_index = aabb_null_node
698 
699  return
700  end if
701 
702  ! search for the best place to put the new leaf in the tree
703  ! we use surface area and depth as search heuristics
704  tree_node_index = this%root_node_index
705  tree_node = this%get_node(tree_node_index)
706  do while (.not. tree_node%is_leaf())
707 
708  ! because of the test in the while loop above we know we are never a
709  ! leaf inside it
710  left_node = this%get_left_node(tree_node_index)
711  right_node = this%get_right_node(tree_node_index)
712 
713  ! ------------------------------------------------------------------- !
714 
715  combined_aabb = merge(tree_node%aabb, leaf_node%get_aabb())
716 
717  new_parent_node_cost = 2.0_rp * combined_aabb%get_surface_area()
718  minimum_push_down_cost = 2.0_rp * ( &
719  & combined_aabb%get_surface_area() &
720  & - tree_node%aabb%get_surface_area()&
721  & )
722 
723  ! use the costs to figure out whether to create a new parent here or
724  ! descend
725  if (left_node%is_leaf()) then
726  new_left_aabb = merge(leaf_node%aabb, left_node%get_aabb())
727  cost_left = new_left_aabb%get_surface_area() + minimum_push_down_cost
728  else
729  new_left_aabb = merge(leaf_node%aabb, left_node%get_aabb())
730  cost_left = ( &
731  & new_left_aabb%get_surface_area() &
732  & - left_node%aabb%get_surface_area()&
733  & ) + minimum_push_down_cost
734  end if
735 
736  if (right_node%is_leaf()) then
737  new_right_aabb = merge(leaf_node%aabb, right_node%aabb)
738  cost_right = new_right_aabb%get_surface_area() + minimum_push_down_cost
739  else
740  new_right_aabb = merge(leaf_node%aabb, right_node%aabb)
741  cost_right = ( &
742  & new_right_aabb%get_surface_area() &
743  & - right_node%aabb%get_surface_area() &
744  & ) + minimum_push_down_cost
745  end if
746 
747  ! if the cost of creating a new parent node here is less than descending
748  ! in either direction then we know we need to create a new parent node,
749  ! errrr, here and attach the leaf to that
750  if (new_parent_node_cost < cost_left .and. new_parent_node_cost < cost_right) then
751  exit
752  end if
753 
754  ! otherwise descend in the cheapest direction
755  if (cost_left .lt. cost_right) then
756  tree_node_index = tree_node%get_left_index()
757  else
758  tree_node_index = tree_node%get_right_index()
759  end if
760 
761  ! ------------------------------------------------------------------- !
762  ! Update the node and continue the loop
763  tree_node = this%get_node(tree_node_index)
764  end do
765 
766  ! the leafs sibling is going to be the node we found above and we are
767  ! going to create a new parent node and attach the leaf and this item
768  leaf_sibling_index = tree_node_index
769  leaf_sibling = this%nodes(leaf_sibling_index)
770  old_parent_index = this%get_parent_index(leaf_sibling_index)
771  new_parent_index = this%allocate_node()
772  new_parent = this%nodes(new_parent_index)
773  new_parent%parent_node_index = old_parent_index
774  new_parent%aabb = merge(leaf_node%aabb, leaf_sibling%aabb)
775 
776  if (leaf_node .lt. leaf_sibling) then
777  new_parent%left_node_index = leaf_node_index
778  new_parent%right_node_index = leaf_sibling_index
779  else
780  new_parent%left_node_index = leaf_sibling_index
781  new_parent%right_node_index = leaf_node_index
782  end if
783 
784  leaf_node%parent_node_index = new_parent_index
785  leaf_sibling%parent_node_index = new_parent_index
786 
787  if (old_parent_index .eq. aabb_null_node) then
788  ! the old parent was the root and so this is now the root
789  this%root_node_index = new_parent_index
790  else
791  ! the old parent was not the root and so we need to patch the left or
792  ! right index to point to the new node
793  old_parent = this%nodes(old_parent_index)
794  if (old_parent%left_node_index .eq. leaf_sibling_index) then
795  old_parent%left_node_index = new_parent_index
796  else
797  old_parent%right_node_index = new_parent_index
798  end if
799  this%nodes(old_parent_index) = old_parent
800  end if
801 
802  this%nodes(leaf_node_index) = leaf_node
803  this%nodes(leaf_sibling_index) = leaf_sibling
804  this%nodes(new_parent_index) = new_parent
805 
806  ! finally we need to walk back up the tree fixing heights and areas
807  tree_node_index = leaf_node%parent_node_index
808 
809  call this%fix_upwards_tree(tree_node_index)
810 
811  end subroutine aabb_tree_insert_leaf
812 
814  function aabb_tree_valid_tree(this) result(valid)
815  use stack, only: stack_i4_t
816  implicit none
817 
818  class(aabb_tree_t), intent(in) :: this
819  logical :: valid
820 
821  type(stack_i4_t) :: simple_stack
822  integer :: current_index
823  integer :: root_index, left_index, right_index
824 
825  valid = .true.
826  if (this%root_node_index .eq. aabb_null_node) then
827  valid = .false.
828  end if
829 
830  root_index = this%get_root_index()
831 
832  call simple_stack%init(this%node_capacity)
833  call simple_stack%push(root_index)
834 
835  do while (.not. simple_stack%is_empty())
836  current_index = simple_stack%pop()
837  if (current_index == aabb_null_node) cycle
838 
839  valid = valid .and. this%nodes(current_index)%is_valid()
840 
841  if (.not. this%nodes(current_index)%is_leaf()) then
842  left_index = this%get_left_index(current_index)
843  right_index = this%get_right_index(current_index)
844 
845  call simple_stack%push(left_index)
846  call simple_stack%push(right_index)
847  end if
848  end do
849  end function aabb_tree_valid_tree
850 
854  subroutine aabb_tree_fix_upwards_tree(this, tree_start_index)
855  class(aabb_tree_t), intent(inout) :: this
856  integer, intent(in) :: tree_start_index
857 
858  type(aabb_node_t) :: left_node
859  type(aabb_node_t) :: right_node
860  integer :: tree_node_index
861 
862  tree_node_index = tree_start_index
863  do while (tree_node_index .ne. aabb_null_node)
864  left_node = this%get_left_node(tree_node_index)
865  right_node = this%get_right_node(tree_node_index)
866 
867  this%nodes(tree_node_index)%aabb = merge(left_node%aabb, right_node%aabb)
868 
869  tree_node_index = this%get_parent_index(tree_node_index)
870  end do
871  end subroutine aabb_tree_fix_upwards_tree
872 
874  subroutine aabb_tree_print(this)
875  use stack, only: stack_i4_t
876  class(aabb_tree_t), intent(inout) :: this
877  type(stack_i4_t) :: simple_stack
878 
879  integer :: current_index
880  integer :: root_index, left_index, right_index
881 
882  root_index = this%get_root_index()
883  call simple_stack%init(this%node_capacity)
884  call simple_stack%push(root_index)
885 
886  do while (.not. simple_stack%is_empty())
887  current_index = simple_stack%pop()
888  if (current_index .eq. aabb_null_node) cycle
889 
890  left_index = this%get_left_index(current_index)
891  right_index = this%get_right_index(current_index)
892 
893  call simple_stack%push(this%nodes(current_index)%left_node_index)
894  call simple_stack%push(this%nodes(current_index)%right_node_index)
895 
896  write(*, *) "i = ", current_index
897  write(*, *) " Parent : ", this%get_parent_index(current_index)
898  write(*, *) " Children: ", this%get_left_index(current_index), this%get_right_index(current_index)
899 
900  write(*, *) " object_index = ", this%nodes(current_index)%object_index
901  end do
902 
903  end subroutine aabb_tree_print
904 
906  subroutine aabb_tree_resize_node_pool(this, new_capacity)
907  class(aabb_tree_t), intent(inout) :: this
908  integer, intent(in) :: new_capacity
909 
910  type(aabb_node_t), dimension(:), allocatable :: temp
911  integer :: i
912 
913  allocate(temp(new_capacity))
914  temp(:this%node_capacity) = this%nodes(:this%node_capacity)
915 
916  do i = this%allocated_node_count, new_capacity
917  temp(i)%next_node_index = i + 1
918  end do
919  temp(new_capacity)%next_node_index = aabb_null_node
920 
921  call move_alloc(temp, this%nodes)
922 
923  this%node_capacity = new_capacity
924  this%next_free_node_index = this%allocated_node_count + 1
925 
926  end subroutine aabb_tree_resize_node_pool
927 
928 end module aabb_tree
Merge two aabbs.
Definition: aabb.f90:93
Axis Aligned Bounding Box (aabb) Tree data structure.
Definition: aabb_tree.f90:70
pure type(aabb_t) function aabb_tree_get_aabb(this, node_index)
Definition: aabb_tree.f90:559
subroutine aabb_tree_fix_upwards_tree(this, tree_start_index)
Fixes the tree upwards.
Definition: aabb_tree.f90:855
pure logical function aabb_node_is_valid(this)
Returns true if the node is a valid node.
Definition: aabb_tree.f90:259
subroutine aabb_node_init(this)
Initializes the AABB node.
Definition: aabb_tree.f90:183
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.
Definition: aabb_tree.f90:551
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.
Definition: aabb_tree.f90:533
pure type(aabb_node_t) function aabb_tree_get_root_node(this)
Returns the root node of the tree.
Definition: aabb_tree.f90:525
subroutine aabb_tree_insert_object(this, object, object_index)
Inserts an object into the tree.
Definition: aabb_tree.f90:570
pure type(aabb_node_t) function aabb_tree_get_node(this, node_index)
Returns the node at the given index.
Definition: aabb_tree.f90:516
subroutine aabb_tree_print(this)
Prints the tree.
Definition: aabb_tree.f90:875
pure logical function aabb_node_greater(this, other)
Returns true if the node is greater than the other node.
Definition: aabb_tree.f90:291
integer function aabb_tree_allocate_node(this)
Allocates a new node in the tree.
Definition: aabb_tree.f90:630
pure type(aabb_t) function aabb_node_get_aabb(this)
Returns the Axis Aligned Bounding Box (aabb) of the node.
Definition: aabb_tree.f90:197
pure integer function aabb_tree_get_root_index(this)
Returns the index of the root node.
Definition: aabb_tree.f90:478
pure integer function aabb_node_get_right_index(this)
Returns the right index of the node.
Definition: aabb_tree.f90:229
subroutine aabb_tree_deallocate_node(this, node_index)
Deallocates a node in the tree.
Definition: aabb_tree.f90:654
pure integer function aabb_node_get_left_index(this)
Returns the left index of the node.
Definition: aabb_tree.f90:221
pure logical function aabb_node_is_leaf(this)
Returns true if the node is a leaf node.
Definition: aabb_tree.f90:250
real(kind=dp) function aabb_node_min_distance(this, p)
Get the minimum possible distance from the aabb to a point.
Definition: aabb_tree.f90:237
subroutine aabb_tree_init(this, initial_capacity)
Initializes the AABB tree.
Definition: aabb_tree.f90:305
subroutine aabb_tree_insert_leaf(this, leaf_node_index)
Inserts a leaf into the tree.
Definition: aabb_tree.f90:664
subroutine aabb_tree_query_overlaps(this, object, object_index, overlaps)
Queries the tree for overlapping objects.
Definition: aabb_tree.f90:585
subroutine aabb_tree_build_tree(this, objects)
Builds the tree.
Definition: aabb_tree.f90:327
integer function, dimension(:), allocatable sort(array)
Definition: aabb_tree.f90:411
pure logical function aabb_node_less(this, other)
Returns true if the node is less than the other node.
Definition: aabb_tree.f90:281
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.
Definition: aabb_tree.f90:486
pure integer function aabb_node_get_parent_index(this)
Returns the parent index of the node.
Definition: aabb_tree.f90:213
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.
Definition: aabb_tree.f90:495
integer, parameter, public aabb_null_node
Definition: aabb_tree.f90:78
pure integer function aabb_node_get_object_index(this)
Returns the object index of the node.
Definition: aabb_tree.f90:205
logical function aabb_tree_valid_tree(this)
Validates the tree.
Definition: aabb_tree.f90:815
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.
Definition: aabb_tree.f90:542
integer function aabb_tree_get_size(this)
Returns the size of the tree, in number of leaves.
Definition: aabb_tree.f90:442
subroutine aabb_tree_resize_node_pool(this, new_capacity)
Resizes the node pool.
Definition: aabb_tree.f90:907
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.
Definition: aabb_tree.f90:504
Axis Aligned Bounding Box (aabb) implementation in Fortran.
Definition: aabb.f90:71
type(aabb_t) function, public get_aabb(object, padding)
Construct the aabb of a predefined object.
Definition: aabb.f90:181
integer, parameter, public dp
Definition: num_types.f90:9
integer, parameter, public rp
Global precision used in computations.
Definition: num_types.f90:12
Implements a dynamic stack ADT.
Definition: stack.f90:35
Defines a triangular element.
Definition: tri.f90:34
Utilities.
Definition: utils.f90:35
Axis Aligned Bounding Box (aabb) data structure.
Definition: aabb.f90:107
Node type for the Axis Aligned Bounding Box (aabb) Tree.
Definition: aabb_tree.f90:85
Axis Aligned Bounding Box (aabb) Tree.
Definition: aabb_tree.f90:125
Integer based stack.
Definition: stack.f90:63
Triangular element.
Definition: tri.f90:60