Neko  0.9.99
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 => &
105  procedure, pass(this), public :: get_parent_index => &
107  procedure, pass(this), public :: get_left_index => &
109  procedure, pass(this), public :: get_right_index => &
111 
112  ! Unary operations
113  procedure, pass(this), public :: min_distance => aabb_node_min_distance
114 
115  ! Boolean operators
116  procedure, pass(this), public :: is_leaf => aabb_node_is_leaf
117  procedure, pass(this), public :: is_valid => aabb_node_is_valid
118 
119  ! Comparison operators
120  generic :: operator(.lt.) => less
121  generic :: operator(.gt.) => greater
122 
123  procedure, pass(this) :: less => aabb_node_less
124  procedure, pass(this) :: greater => aabb_node_greater
125 
126  end type aabb_node_t
127 
129  type, public :: aabb_tree_t
130  private
131  type(aabb_node_t), allocatable :: nodes(:)
132  integer :: root_node_index = aabb_null_node
133  integer :: allocated_node_count = 0
134  integer :: next_free_node_index = aabb_null_node
135  integer :: node_capacity = 0
136  integer :: growth_size = 1
137 
138  contains
139 
140  ! Initializers
141  procedure, pass(this), public :: init => aabb_tree_init
142  procedure, pass(this), public :: build => aabb_tree_build_tree
143  procedure, pass(this), public :: insert_object => &
145 
146  ! Getters
147  procedure, pass(this), public :: get_size => aabb_tree_get_size
148 
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 => &
157 
158  procedure, pass(this), public :: get_node => aabb_tree_get_node
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 => &
167 
168  procedure, pass(this), public :: get_aabb => aabb_tree_get_aabb
169 
170  procedure, pass(this), public :: query_overlaps => &
172 
173  procedure, pass(this), public :: print => aabb_tree_print
174 
175  ! ----------------------------------------------------------------------- !
176  ! Internal methods
177 
178  procedure, pass(this) :: allocate_node => aabb_tree_allocate_node
179  procedure, pass(this) :: deallocate_node => aabb_tree_deallocate_node
180  procedure, pass(this) :: resize_node_pool => aabb_tree_resize_node_pool
181  procedure, pass(this) :: insert_leaf => aabb_tree_insert_leaf
182 
183  procedure, pass(this) :: fix_upwards_tree => aabb_tree_fix_upwards_tree
184 
185  procedure, pass(this) :: valid_tree => aabb_tree_valid_tree
186 
187  end type aabb_tree_t
188 
189 contains
190 
191  ! ========================================================================== !
192  ! Definitions of node methods
193  ! ========================================================================== !
194 
196  subroutine aabb_node_init(this)
197  class(aabb_node_t), intent(inout) :: this
198 
199  this%object_index = -1
200  this%parent_node_index = aabb_null_node
201  this%left_node_index = aabb_null_node
202  this%right_node_index = aabb_null_node
203  this%next_node_index = aabb_null_node
204  end subroutine aabb_node_init
205 
206  ! -------------------------------------------------------------------------- !
207  ! Getters
208 
210  pure function aabb_node_get_aabb(this) result(res)
211  class(aabb_node_t), intent(in) :: this
212  type(aabb_t) :: res
213 
214  res = this%aabb
215  end function aabb_node_get_aabb
216 
218  pure function aabb_node_get_object_index(this) result(object_index)
219  class(aabb_node_t), intent(in) :: this
220  integer :: object_index
221 
222  object_index = this%object_index
223  end function aabb_node_get_object_index
224 
226  pure function aabb_node_get_parent_index(this) result(parent_index)
227  class(aabb_node_t), intent(in) :: this
228  integer :: parent_index
229 
230  parent_index = this%parent_node_index
231  end function aabb_node_get_parent_index
232 
234  pure function aabb_node_get_left_index(this) result(left_index)
235  class(aabb_node_t), intent(in) :: this
236  integer :: left_index
237 
238  left_index = this%left_node_index
239  end function aabb_node_get_left_index
240 
242  pure function aabb_node_get_right_index(this) result(right_index)
243  class(aabb_node_t), intent(in) :: this
244  integer :: right_index
245 
246  right_index = this%right_node_index
247  end function aabb_node_get_right_index
248 
250  function aabb_node_min_distance(this, p) result(distance)
251  class(aabb_node_t), intent(in) :: this
252  real(kind=dp), dimension(3), intent(in) :: p
253  real(kind=dp) :: distance
254 
255  distance = 0.5_rp * this%aabb%get_diameter() &
256  - norm2(this%aabb%get_center() - p)
257  end function aabb_node_min_distance
258 
259  ! -------------------------------------------------------------------------- !
260  ! Boolean operators
261 
263  pure function aabb_node_is_leaf(this) result(res)
264  class(aabb_node_t), intent(in) :: this
265  logical :: res
266 
267  res = this%left_node_index == aabb_null_node .and. &
268  this%right_node_index == aabb_null_node
269  end function aabb_node_is_leaf
270 
272  pure function aabb_node_is_valid(this) result(valid)
273  class(aabb_node_t), intent(in) :: this
274  logical :: valid
275 
276  if (this%is_leaf()) then
277  valid = &
278  & this%left_node_index .eq. aabb_null_node .and. &
279  & this%right_node_index .eq. aabb_null_node .and. &
280  & this%object_index .gt. 0
281  else
282  valid = &
283  & this%left_node_index .ne. aabb_null_node .and. &
284  & this%right_node_index .ne. aabb_null_node .and. &
285  & this%object_index .eq. -1
286  end if
287 
288  end function aabb_node_is_valid
289 
290  ! -------------------------------------------------------------------------- !
291  ! Comparison operators
292 
294  pure function aabb_node_less(this, other) result(res)
295  class(aabb_node_t), intent(in) :: this
296  class(aabb_node_t), intent(in) :: other
297  logical :: res
298 
299  res = this%aabb .lt. other%aabb
300 
301  end function aabb_node_less
302 
304  pure function aabb_node_greater(this, other) result(res)
305  class(aabb_node_t), intent(in) :: this
306  class(aabb_node_t), intent(in) :: other
307  logical :: res
308 
309  res = this%aabb .gt. other%aabb
310 
311  end function aabb_node_greater
312 
313  ! ========================================================================== !
314  ! Definitions of tree methods
315  ! ========================================================================== !
316 
318  subroutine aabb_tree_init(this, initial_capacity)
319  class(aabb_tree_t), intent(inout) :: this
320  integer, intent(in) :: initial_capacity
321 
322  integer :: i
323 
324  this%root_node_index = aabb_null_node
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
329 
330  if (allocated(this%nodes)) deallocate(this%nodes)
331  allocate(this%nodes(initial_capacity))
332 
333  do i = 1, initial_capacity
334  this%nodes(i)%next_node_index = i + 1
335  end do
336  this%nodes(initial_capacity)%next_node_index = aabb_null_node
337  end subroutine aabb_tree_init
338 
340  subroutine aabb_tree_build_tree(this, objects)
341  use utils, only: neko_error
342  implicit none
343 
344  class(aabb_tree_t), intent(inout) :: this
345  class(*), dimension(:), intent(in) :: objects
346 
347  integer :: i_obj, i_node, i
348  logical :: done
349 
350  integer :: start_layer, end_layer
351 
352  type(aabb_t), dimension(:), allocatable :: box_list
353  integer, dimension(:), allocatable :: sorted_indices
354 
355  call this%init(size(objects) * 2)
356 
357  ! ------------------------------------------------------------------------ !
358  ! Start by sorting the list of objects, then build a balanced binary tree
359  ! from the sorted list
360 
361  allocate(box_list(size(objects)))
362 
363  do i_obj = 1, size(objects)
364  box_list(i_obj) = get_aabb(objects(i_obj))
365  end do
366  sorted_indices = sort(box_list)
367 
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
373  end do
374 
375 
376  start_layer = 1
377  end_layer = size(objects)
378  done = .false.
379  do while (.not. done)
380 
381  ! build the next layer
382  do i = start_layer, end_layer - 1, 2
383  i_node = this%allocate_node()
384 
385  this%nodes(i_node)%aabb = merge(this%nodes(i)%aabb, &
386  this%nodes(i + 1)%aabb)
387 
388  this%nodes(i_node)%left_node_index = i
389  this%nodes(i_node)%right_node_index = i + 1
390 
391  this%nodes(i)%parent_node_index = i_node
392  this%nodes(i + 1)%parent_node_index = i_node
393  end do
394 
395  ! if the number of nodes is odd, we need to create a new node to hold the
396  ! last 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
401  this%nodes(i_node)%right_node_index = aabb_null_node
402 
403  this%nodes(end_layer)%parent_node_index = i_node
404  end if
405 
406  ! move to the next layer
407  start_layer = end_layer + 1
408  end_layer = this%allocated_node_count
409 
410  ! If there is only one node left, we are done
411  done = start_layer .eq. end_layer
412  end do
413 
414  ! The last node allocated is the root node
415  this%root_node_index = this%allocated_node_count
416 
417  if (this%get_size() .ne. size(objects)) then
418  print *, "this%get_size() = ", this%get_size()
419  print *, "size(objects) = ", size(objects)
420  call neko_error("Invalid tree size")
421  end if
422 
423  end subroutine aabb_tree_build_tree
424 
425  function sort(array) result(indices)
426  type(aabb_t), dimension(:), intent(in) :: array
427  integer, dimension(:), allocatable :: indices
428  logical, dimension(:), allocatable :: visited
429 
430  integer :: i, imin
431  integer :: minidx
432 
433  allocate(indices(size(array)))
434  allocate(visited(size(array)))
435 
436  visited = .false.
437  indices = 0
438  do i = 1, size(array)
439  minidx = -1
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
444  end if
445  end do
446 
447  indices(i) = minidx
448  visited(minidx) = .true.
449  end do
450 
451  end function sort
452 
453  ! -------------------------------------------------------------------------- !
454  ! Getters
455 
457  function aabb_tree_get_size(this) result(size)
458  use stack, only: stack_i4_t
459  use utils, only: neko_error
460  class(aabb_tree_t), intent(in) :: this
461  integer :: size
462 
463  type(stack_i4_t) :: simple_stack
464  integer :: idx, tmp
465 
466  call simple_stack%init(this%allocated_node_count)
467  size = 0
468  tmp = this%get_root_index()
469  if (tmp .ne. aabb_null_node) then
470  call simple_stack%push(tmp)
471  end if
472 
473  do while (.not. simple_stack%is_empty())
474  idx = simple_stack%pop()
475  if (idx .eq. aabb_null_node) cycle
476 
477  if (this%nodes(idx)%is_leaf()) then
478  size = size + 1
479  else
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)
484  end if
485  end do
486 
487  end function aabb_tree_get_size
488 
489  ! -------------------------------------------------------------------------- !
490  ! Get index of nodes
491 
493  pure function aabb_tree_get_root_index(this) result(root_index)
494  class(aabb_tree_t), intent(in) :: this
495  integer :: root_index
496 
497  root_index = this%root_node_index
498  end function aabb_tree_get_root_index
499 
501  pure function aabb_tree_get_parent_index(this, node_index) &
502  result(parent_index)
503  class(aabb_tree_t), intent(in) :: this
504  integer, intent(in) :: node_index
505  integer :: parent_index
506 
507  parent_index = this%nodes(node_index)%parent_node_index
508  end function aabb_tree_get_parent_index
509 
511  pure function aabb_tree_get_left_index(this, node_index) &
512  result(left_index)
513  class(aabb_tree_t), intent(in) :: this
514  integer, intent(in) :: node_index
515  integer :: left_index
516 
517  left_index = this%nodes(node_index)%left_node_index
518  end function aabb_tree_get_left_index
519 
521  pure function aabb_tree_get_right_index(this, node_index) &
522  result(right_index)
523  class(aabb_tree_t), intent(in) :: this
524  integer, intent(in) :: node_index
525  integer :: right_index
526 
527  right_index = this%nodes(node_index)%right_node_index
528  end function aabb_tree_get_right_index
529 
530  ! -------------------------------------------------------------------------- !
531  ! Get nodes
532 
534  pure function aabb_tree_get_node(this, node_index) result(node)
535  class(aabb_tree_t), intent(in) :: this
536  integer, intent(in) :: node_index
537  type(aabb_node_t) :: node
538 
539  node = this%nodes(node_index)
540  end function aabb_tree_get_node
541 
543  pure function aabb_tree_get_root_node(this) result(root_node)
544  class(aabb_tree_t), intent(in) :: this
545  type(aabb_node_t) :: root_node
546 
547  root_node = this%nodes(this%root_node_index)
548  end function aabb_tree_get_root_node
549 
551  pure function aabb_tree_get_parent_node(this, node_index) &
552  result(parent_node)
553  class(aabb_tree_t), intent(in) :: this
554  integer, intent(in) :: node_index
555  type(aabb_node_t) :: parent_node
556 
557  parent_node = this%nodes(this%nodes(node_index)%parent_node_index)
558  end function aabb_tree_get_parent_node
559 
561  pure function aabb_tree_get_left_node(this, node_index) result(left_node)
562  class(aabb_tree_t), intent(in) :: this
563  integer, intent(in) :: node_index
564  type(aabb_node_t) :: left_node
565 
566  left_node = this%nodes(this%nodes(node_index)%left_node_index)
567  end function aabb_tree_get_left_node
568 
570  pure function aabb_tree_get_right_node(this, node_index) &
571  result(right_node)
572  class(aabb_tree_t), intent(in) :: this
573  integer, intent(in) :: node_index
574  type(aabb_node_t) :: right_node
575 
576  right_node = this%nodes(this%nodes(node_index)%right_node_index)
577  end function aabb_tree_get_right_node
578 
579  pure function aabb_tree_get_aabb(this, node_index) result(out_box)
580  class(aabb_tree_t), intent(in) :: this
581  integer, intent(in) :: node_index
582  type(aabb_t) :: out_box
583 
584  out_box = this%nodes(node_index)%aabb
585  end function aabb_tree_get_aabb
586 
587  ! -------------------------------------------------------------------------- !
588 
590  subroutine aabb_tree_insert_object(this, object, object_index)
591  class(aabb_tree_t), intent(inout) :: this
592  class(*), intent(in) :: object
593  integer, intent(in) :: object_index
594 
595  integer :: node_index
596 
597  node_index = this%allocate_node()
598  this%nodes(node_index)%aabb = get_aabb(object)
599  this%nodes(node_index)%object_index = object_index
600 
601  call this%insert_leaf(node_index)
602  end subroutine aabb_tree_insert_object
603 
605  subroutine aabb_tree_query_overlaps(this, object, object_index, overlaps)
606  use stack, only: stack_i4_t
607  implicit none
608 
609  class(aabb_tree_t), intent(in) :: this
610  class(*), intent(in) :: object
611  integer, intent(in) :: object_index
612  integer, intent(out) :: overlaps(:)
613 
614  type(stack_i4_t) :: simple_stack
615  type(aabb_t) :: object_box
616 
617  integer :: root_index, left_index, right_index
618 
619  integer :: node_index
620 
621  object_box = get_aabb(object)
622  root_index = this%get_root_index()
623 
624  call simple_stack%init()
625  call simple_stack%push(root_index)
626 
627  do while (.not. simple_stack%is_empty())
628  node_index = simple_stack%pop()
629 
630  if (node_index == aabb_null_node) cycle
631 
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]
636  end if
637  else
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)
642  end if
643  end if
644  end do
645  call simple_stack%free()
646  end subroutine aabb_tree_query_overlaps
647 
648  ! -------------------------------------------------------------------------- !
649  ! Internal methods
650 
652  function aabb_tree_allocate_node(this) result(node_index)
653  class(aabb_tree_t), intent(inout) :: this
654  integer :: node_index
655 
656  if (this%next_free_node_index == aabb_null_node) then
657  call this%resize_node_pool(this%node_capacity + this%growth_size)
658  end if
659 
660  node_index = this%next_free_node_index
661 
662  associate(new_node => this%nodes(node_index))
663  this%next_free_node_index = new_node%next_node_index
664 
665  new_node%parent_node_index = aabb_null_node
666  new_node%left_node_index = aabb_null_node
667  new_node%right_node_index = aabb_null_node
668 
669  this%next_free_node_index = new_node%next_node_index
670  this%allocated_node_count = this%allocated_node_count + 1
671 
672  end associate
673  end function aabb_tree_allocate_node
674 
676  subroutine aabb_tree_deallocate_node(this, node_index)
677  class(aabb_tree_t), intent(inout) :: this
678  integer, intent(in) :: node_index
679 
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
683  end subroutine aabb_tree_deallocate_node
684 
686  subroutine aabb_tree_insert_leaf(this, leaf_node_index)
687  class(aabb_tree_t), intent(inout) :: this
688  integer, intent(in) :: leaf_node_index
689 
690  integer :: tree_node_index
691 
692  real(kind=rp) :: cost_left
693  real(kind=rp) :: cost_right
694 
695  type(aabb_node_t) :: leaf_node
696  type(aabb_node_t) :: tree_node
697  type(aabb_node_t) :: left_node
698  type(aabb_node_t) :: right_node
699 
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
706  type(aabb_node_t) :: leaf_sibling
707  integer :: old_parent_index
708  integer :: new_parent_index
709  type(aabb_node_t) :: new_parent
710  type(aabb_node_t) :: old_parent
711 
712  ! make sure were inserting a new leaf
713  leaf_node = this%nodes(leaf_node_index)
714 
715  ! if the tree is empty then we make the root the leaf
716  if (this%root_node_index .eq. aabb_null_node) then
717  this%root_node_index = leaf_node_index
718  leaf_node%parent_node_index = aabb_null_node
719  leaf_node%left_node_index = aabb_null_node
720  leaf_node%right_node_index = aabb_null_node
721 
722  return
723  end if
724 
725  ! search for the best place to put the new leaf in the tree
726  ! we use surface area and depth as search heuristics
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())
730 
731  ! because of the test in the while loop above we know we are never a
732  ! leaf inside it
733  left_node = this%get_left_node(tree_node_index)
734  right_node = this%get_right_node(tree_node_index)
735 
736  ! ------------------------------------------------------------------- !
737 
738  combined_aabb = merge(tree_node%aabb, leaf_node%get_aabb())
739 
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()&
744  & )
745 
746  ! use the costs to figure out whether to create a new parent here or
747  ! descend
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
751  else
752  new_left_aabb = merge(leaf_node%aabb, left_node%get_aabb())
753  cost_left = ( &
754  & new_left_aabb%get_surface_area() &
755  & - left_node%aabb%get_surface_area()&
756  & ) + minimum_push_down_cost
757  end if
758 
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
763  else
764  new_right_aabb = merge(leaf_node%aabb, right_node%aabb)
765  cost_right = ( &
766  & new_right_aabb%get_surface_area() &
767  & - right_node%aabb%get_surface_area() &
768  & ) + minimum_push_down_cost
769  end if
770 
771  ! if the cost of creating a new parent node here is less than descending
772  ! in either direction then we know we need to create a new parent node,
773  ! errrr, here and attach the leaf to that
774  if (new_parent_node_cost < cost_left .and. &
775  new_parent_node_cost < cost_right) then
776  exit
777  end if
778 
779  ! otherwise descend in the cheapest direction
780  if (cost_left .lt. cost_right) then
781  tree_node_index = tree_node%get_left_index()
782  else
783  tree_node_index = tree_node%get_right_index()
784  end if
785 
786  ! ------------------------------------------------------------------- !
787  ! Update the node and continue the loop
788  tree_node = this%get_node(tree_node_index)
789  end do
790 
791  ! the leafs sibling is going to be the node we found above and we are
792  ! going to create a new parent node and attach the leaf and this item
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)
800 
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
804  else
805  new_parent%left_node_index = leaf_sibling_index
806  new_parent%right_node_index = leaf_node_index
807  end if
808 
809  leaf_node%parent_node_index = new_parent_index
810  leaf_sibling%parent_node_index = new_parent_index
811 
812  if (old_parent_index .eq. aabb_null_node) then
813  ! the old parent was the root and so this is now the root
814  this%root_node_index = new_parent_index
815  else
816  ! the old parent was not the root and so we need to patch the left or
817  ! right index to point to the new node
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
821  else
822  old_parent%right_node_index = new_parent_index
823  end if
824  this%nodes(old_parent_index) = old_parent
825  end if
826 
827  this%nodes(leaf_node_index) = leaf_node
828  this%nodes(leaf_sibling_index) = leaf_sibling
829  this%nodes(new_parent_index) = new_parent
830 
831  ! finally we need to walk back up the tree fixing heights and areas
832  tree_node_index = leaf_node%parent_node_index
833 
834  call this%fix_upwards_tree(tree_node_index)
835 
836  end subroutine aabb_tree_insert_leaf
837 
839  function aabb_tree_valid_tree(this) result(valid)
840  use stack, only: stack_i4_t
841  implicit none
842 
843  class(aabb_tree_t), intent(in) :: this
844  logical :: valid
845 
846  type(stack_i4_t) :: simple_stack
847  integer :: current_index
848  integer :: root_index, left_index, right_index
849 
850  valid = .true.
851  if (this%root_node_index .eq. aabb_null_node) then
852  valid = .false.
853  end if
854 
855  root_index = this%get_root_index()
856 
857  call simple_stack%init(this%node_capacity)
858  call simple_stack%push(root_index)
859 
860  do while (.not. simple_stack%is_empty())
861  current_index = simple_stack%pop()
862  if (current_index == aabb_null_node) cycle
863 
864  valid = valid .and. this%nodes(current_index)%is_valid()
865 
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)
869 
870  call simple_stack%push(left_index)
871  call simple_stack%push(right_index)
872  end if
873  end do
874  end function aabb_tree_valid_tree
875 
879  subroutine aabb_tree_fix_upwards_tree(this, tree_start_index)
880  class(aabb_tree_t), intent(inout) :: this
881  integer, intent(in) :: tree_start_index
882 
883  type(aabb_node_t) :: left_node
884  type(aabb_node_t) :: right_node
885  integer :: tree_node_index
886 
887  tree_node_index = tree_start_index
888  do while (tree_node_index .ne. aabb_null_node)
889  left_node = this%get_left_node(tree_node_index)
890  right_node = this%get_right_node(tree_node_index)
891 
892  this%nodes(tree_node_index)%aabb = merge(left_node%aabb, right_node%aabb)
893 
894  tree_node_index = this%get_parent_index(tree_node_index)
895  end do
896  end subroutine aabb_tree_fix_upwards_tree
897 
899  subroutine aabb_tree_print(this)
900  use stack, only: stack_i4_t
901  class(aabb_tree_t), intent(inout) :: this
902  type(stack_i4_t) :: simple_stack
903 
904  integer :: current_index
905  integer :: root_index, left_index, right_index
906 
907  root_index = this%get_root_index()
908  call simple_stack%init(this%node_capacity)
909  call simple_stack%push(root_index)
910 
911  do while (.not. simple_stack%is_empty())
912  current_index = simple_stack%pop()
913  if (current_index .eq. aabb_null_node) cycle
914 
915  left_index = this%get_left_index(current_index)
916  right_index = this%get_right_index(current_index)
917 
918  call simple_stack%push(this%nodes(current_index)%left_node_index)
919  call simple_stack%push(this%nodes(current_index)%right_node_index)
920 
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)
925 
926  write(*, *) " object_index = ", this%nodes(current_index)%object_index
927  end do
928 
929  end subroutine aabb_tree_print
930 
932  subroutine aabb_tree_resize_node_pool(this, new_capacity)
933  class(aabb_tree_t), intent(inout) :: this
934  integer, intent(in) :: new_capacity
935 
936  type(aabb_node_t), dimension(:), allocatable :: temp
937  integer :: i
938 
939  allocate(temp(new_capacity))
940  temp(:this%node_capacity) = this%nodes(:this%node_capacity)
941 
942  do i = this%allocated_node_count, new_capacity
943  temp(i)%next_node_index = i + 1
944  end do
945  temp(new_capacity)%next_node_index = aabb_null_node
946 
947  call move_alloc(temp, this%nodes)
948 
949  this%node_capacity = new_capacity
950  this%next_free_node_index = this%allocated_node_count + 1
951 
952  end subroutine aabb_tree_resize_node_pool
953 
954 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:580
subroutine aabb_tree_fix_upwards_tree(this, tree_start_index)
Fixes the tree upwards.
Definition: aabb_tree.f90:880
pure logical function aabb_node_is_valid(this)
Returns true if the node is a valid node.
Definition: aabb_tree.f90:273
subroutine aabb_node_init(this)
Initializes the AABB node.
Definition: aabb_tree.f90:197
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:572
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:553
pure type(aabb_node_t) function aabb_tree_get_root_node(this)
Returns the root node of the tree.
Definition: aabb_tree.f90:544
subroutine aabb_tree_insert_object(this, object, object_index)
Inserts an object into the tree.
Definition: aabb_tree.f90:591
pure type(aabb_node_t) function aabb_tree_get_node(this, node_index)
Returns the node at the given index.
Definition: aabb_tree.f90:535
subroutine aabb_tree_print(this)
Prints the tree.
Definition: aabb_tree.f90:900
pure logical function aabb_node_greater(this, other)
Returns true if the node is greater than the other node.
Definition: aabb_tree.f90:305
integer function aabb_tree_allocate_node(this)
Allocates a new node in the tree.
Definition: aabb_tree.f90:653
pure type(aabb_t) function aabb_node_get_aabb(this)
Returns the Axis Aligned Bounding Box (aabb) of the node.
Definition: aabb_tree.f90:211
pure integer function aabb_tree_get_root_index(this)
Returns the index of the root node.
Definition: aabb_tree.f90:494
pure integer function aabb_node_get_right_index(this)
Returns the right index of the node.
Definition: aabb_tree.f90:243
subroutine aabb_tree_deallocate_node(this, node_index)
Deallocates a node in the tree.
Definition: aabb_tree.f90:677
pure integer function aabb_node_get_left_index(this)
Returns the left index of the node.
Definition: aabb_tree.f90:235
pure logical function aabb_node_is_leaf(this)
Returns true if the node is a leaf node.
Definition: aabb_tree.f90:264
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:251
subroutine aabb_tree_init(this, initial_capacity)
Initializes the AABB tree.
Definition: aabb_tree.f90:319
subroutine aabb_tree_insert_leaf(this, leaf_node_index)
Inserts a leaf into the tree.
Definition: aabb_tree.f90:687
subroutine aabb_tree_query_overlaps(this, object, object_index, overlaps)
Queries the tree for overlapping objects.
Definition: aabb_tree.f90:606
subroutine aabb_tree_build_tree(this, objects)
Builds the tree.
Definition: aabb_tree.f90:341
integer function, dimension(:), allocatable sort(array)
Definition: aabb_tree.f90:426
pure logical function aabb_node_less(this, other)
Returns true if the node is less than the other node.
Definition: aabb_tree.f90:295
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:503
pure integer function aabb_node_get_parent_index(this)
Returns the parent index of the node.
Definition: aabb_tree.f90:227
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:513
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:219
logical function aabb_tree_valid_tree(this)
Validates the tree.
Definition: aabb_tree.f90:840
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:562
integer function aabb_tree_get_size(this)
Returns the size of the tree, in number of leaves.
Definition: aabb_tree.f90:458
subroutine aabb_tree_resize_node_pool(this, new_capacity)
Resizes the node pool.
Definition: aabb_tree.f90:933
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:523
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:129
Integer based stack.
Definition: stack.f90:63
Triangular element.
Definition: tri.f90:60