Neko 1.99.2
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
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
71 use aabb, only : aabb_t, get_aabb, merge
72 use tri, only : tri_t
73 use num_types, only : rp, dp
74 use stack, only : stack_i4_t
75 use utils, only : neko_error
76 implicit none
77 private
78
79 integer, parameter, public :: aabb_null_node = -1
80
81 ! ========================================================================== !
82 ! Type definitions
83 ! ========================================================================== !
84
86 type, public :: aabb_node_t
87 private
88 type(aabb_t), public :: aabb
89 integer :: object_index = -1
90
91 ! tree links
92 integer :: parent_node_index = aabb_null_node
93 integer :: left_node_index = aabb_null_node
94 integer :: right_node_index = aabb_null_node
95
96 ! node linked list link
97 integer :: next_node_index = aabb_null_node
98
99 contains
100 procedure, pass(this), public :: init => aabb_node_init
101
102 ! Getters
103 procedure, pass(this), public :: get_aabb => aabb_node_get_aabb
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 => &
112
113 ! Unary operations
114 procedure, pass(this), public :: min_distance => aabb_node_min_distance
115
116 ! Boolean operators
117 procedure, pass(this), public :: is_leaf => aabb_node_is_leaf
118 procedure, pass(this), public :: is_valid => aabb_node_is_valid
119
120 ! Comparison operators
121 generic :: operator(.lt.) => less
122 generic :: operator(.gt.) => greater
123
124 procedure, pass(this) :: less => aabb_node_less
125 procedure, pass(this) :: greater => aabb_node_greater
126
127 end type aabb_node_t
128
130 type, public :: aabb_tree_t
131 private
132 type(aabb_node_t), allocatable :: nodes(:)
133 integer :: root_node_index = aabb_null_node
134 integer :: allocated_node_count = 0
135 integer :: next_free_node_index = aabb_null_node
136 integer :: node_capacity = 0
137 integer :: growth_size = 1
138
139 contains
140
141 ! Initializers
142 procedure, pass(this), public :: init => aabb_tree_init
143 procedure, pass(this), public :: build_generic => aabb_tree_build_tree
144 procedure, pass(this), public :: build_from_aabb => aabb_tree_build_tree_aabb
145 procedure, pass(this), public :: insert_object => &
147 generic :: build => build_generic
148
149 ! Getters
150 procedure, pass(this), public :: get_size => aabb_tree_get_size
151
152 procedure, pass(this), public :: get_root_index => &
154 procedure, pass(this), public :: get_parent_index => &
156 procedure, pass(this), public :: get_left_index => &
158 procedure, pass(this), public :: get_right_index => &
160
161 procedure, pass(this), public :: get_node => aabb_tree_get_node
162 procedure, pass(this), public :: get_root_node => &
164 procedure, pass(this), public :: get_parent_node => &
166 procedure, pass(this), public :: get_left_node => &
168 procedure, pass(this), public :: get_right_node => &
170
171 procedure, pass(this), public :: get_aabb => aabb_tree_get_aabb
172
173 procedure, pass(this), public :: query_overlaps => &
175
176 procedure, pass(this), public :: print => aabb_tree_print
177
178 ! ----------------------------------------------------------------------- !
179 ! Internal methods
180
181 procedure, pass(this) :: allocate_node => aabb_tree_allocate_node
182 procedure, pass(this) :: deallocate_node => aabb_tree_deallocate_node
183 procedure, pass(this) :: resize_node_pool => aabb_tree_resize_node_pool
184 procedure, pass(this) :: insert_leaf => aabb_tree_insert_leaf
185
186 procedure, pass(this) :: fix_upwards_tree => aabb_tree_fix_upwards_tree
187
188 procedure, pass(this) :: valid_tree => aabb_tree_valid_tree
189
190 end type aabb_tree_t
191
192contains
193
194 ! ========================================================================== !
195 ! Definitions of node methods
196 ! ========================================================================== !
197
199 subroutine aabb_node_init(this)
200 class(aabb_node_t), intent(inout) :: this
201
202 this%object_index = -1
203 this%parent_node_index = aabb_null_node
204 this%left_node_index = aabb_null_node
205 this%right_node_index = aabb_null_node
206 this%next_node_index = aabb_null_node
207 end subroutine aabb_node_init
208
209 ! -------------------------------------------------------------------------- !
210 ! Getters
211
213 pure function aabb_node_get_aabb(this) result(res)
214 class(aabb_node_t), intent(in) :: this
215 type(aabb_t) :: res
216
217 res = this%aabb
218 end function aabb_node_get_aabb
219
221 pure function aabb_node_get_object_index(this) result(object_index)
222 class(aabb_node_t), intent(in) :: this
223 integer :: object_index
224
225 object_index = this%object_index
226 end function aabb_node_get_object_index
227
229 pure function aabb_node_get_parent_index(this) result(parent_index)
230 class(aabb_node_t), intent(in) :: this
231 integer :: parent_index
232
233 parent_index = this%parent_node_index
234 end function aabb_node_get_parent_index
235
237 pure function aabb_node_get_left_index(this) result(left_index)
238 class(aabb_node_t), intent(in) :: this
239 integer :: left_index
240
241 left_index = this%left_node_index
242 end function aabb_node_get_left_index
243
245 pure function aabb_node_get_right_index(this) result(right_index)
246 class(aabb_node_t), intent(in) :: this
247 integer :: right_index
248
249 right_index = this%right_node_index
250 end function aabb_node_get_right_index
251
253 function aabb_node_min_distance(this, p) result(distance)
254 class(aabb_node_t), intent(in) :: this
255 real(kind=dp), dimension(3), intent(in) :: p
256 real(kind=dp) :: distance
257
258 distance = 0.5_rp * this%aabb%get_diameter() &
259 - norm2(this%aabb%get_center() - p)
260 end function aabb_node_min_distance
261
262 ! -------------------------------------------------------------------------- !
263 ! Boolean operators
264
266 pure function aabb_node_is_leaf(this) result(res)
267 class(aabb_node_t), intent(in) :: this
268 logical :: res
269
270 res = this%left_node_index == aabb_null_node .and. &
271 this%right_node_index == aabb_null_node
272 end function aabb_node_is_leaf
273
275 pure function aabb_node_is_valid(this) result(valid)
276 class(aabb_node_t), intent(in) :: this
277 logical :: valid
278
279 if (this%is_leaf()) then
280 valid = &
281 & this%left_node_index .eq. aabb_null_node .and. &
282 & this%right_node_index .eq. aabb_null_node .and. &
283 & this%object_index .gt. 0
284 else
285 valid = &
286 & this%left_node_index .ne. aabb_null_node .and. &
287 & this%right_node_index .ne. aabb_null_node .and. &
288 & this%object_index .eq. -1
289 end if
290
291 end function aabb_node_is_valid
292
293 ! -------------------------------------------------------------------------- !
294 ! Comparison operators
295
297 pure function aabb_node_less(this, other) result(res)
298 class(aabb_node_t), intent(in) :: this
299 class(aabb_node_t), intent(in) :: other
300 logical :: res
301
302 res = this%aabb .lt. other%aabb
303
304 end function aabb_node_less
305
307 pure function aabb_node_greater(this, other) result(res)
308 class(aabb_node_t), intent(in) :: this
309 class(aabb_node_t), intent(in) :: other
310 logical :: res
311
312 res = this%aabb .gt. other%aabb
313
314 end function aabb_node_greater
315
316 ! ========================================================================== !
317 ! Definitions of tree methods
318 ! ========================================================================== !
319
321 subroutine aabb_tree_init(this, initial_capacity)
322 class(aabb_tree_t), intent(inout) :: this
323 integer, intent(in) :: initial_capacity
324 integer :: i, nonzero_capacity
325
326 if (initial_capacity < 1) then
327 nonzero_capacity = 1
328 else
329 nonzero_capacity = initial_capacity
330 end if
331
332 this%root_node_index = aabb_null_node
333 this%allocated_node_count = 0
334 this%next_free_node_index = 1
335 this%node_capacity = nonzero_capacity
336 this%growth_size = nonzero_capacity
337
338 if (allocated(this%nodes)) deallocate(this%nodes)
339 allocate(this%nodes(nonzero_capacity))
340
341 do i = 1, nonzero_capacity
342 this%nodes(i)%next_node_index = i + 1
343 end do
344 this%nodes(nonzero_capacity)%next_node_index = aabb_null_node
345 end subroutine aabb_tree_init
346
348 subroutine aabb_tree_build_tree_aabb(this, objects, padding)
349 class(aabb_tree_t), intent(inout) :: this
350 type(aabb_t), intent(in) :: objects(:)
351 real(kind=dp), optional, intent(in) :: padding
352
353 integer :: i_obj, i_node, i
354 logical :: done
355
356 integer :: start_layer, end_layer
357
358 type(aabb_t), allocatable :: box_list(:)
359 integer, dimension(:), allocatable :: sorted_indices
360
361 real(kind=dp) :: aabb_padding
362
363 if (allocated(box_list)) deallocate(box_list)
364 allocate(box_list(size(objects)))
365
366 call this%init(size(objects) * 2)
367 if (size(objects) .eq. 0) then
368 return
369 end if
370
371 ! ------------------------------------------------------------------------ !
372 ! Start by sorting the list of objects, then build a balanced binary tree
373 ! from the sorted list
374
375
376 if (present(padding)) then
377 aabb_padding = padding
378 else
379 aabb_padding = 0.0_dp
380 end if
381
382 do i_obj = 1, size(objects)
383 box_list(i_obj) = get_aabb(objects(i_obj), aabb_padding)
384 end do
385 call sort(box_list, sorted_indices)
386
387 do i = 1, size(sorted_indices)
388 i_obj = sorted_indices(i)
389 i_node = this%allocate_node()
390 this%nodes(i_node)%aabb = box_list(i_obj)
391 this%nodes(i_node)%object_index = i_obj
392 end do
393
394
395 start_layer = 1
396 end_layer = size(objects)
397 done = .false.
398 do while (.not. done)
399
400 ! build the next layer
401 do i = start_layer, end_layer - 1, 2
402 i_node = this%allocate_node()
403
404 this%nodes(i_node)%aabb = merge(this%nodes(i)%aabb, &
405 this%nodes(i + 1)%aabb)
406
407 this%nodes(i_node)%left_node_index = i
408 this%nodes(i_node)%right_node_index = i + 1
409
410 this%nodes(i)%parent_node_index = i_node
411 this%nodes(i + 1)%parent_node_index = i_node
412 end do
413
414 ! if the number of nodes is odd, we need to create a new node to hold the
415 ! last node
416 if (mod(end_layer - start_layer, 2) .eq. 0) then
417 i_node = this%allocate_node()
418 this%nodes(i_node)%aabb = this%nodes(end_layer)%aabb
419 this%nodes(i_node)%left_node_index = end_layer
420 this%nodes(i_node)%right_node_index = aabb_null_node
421
422 this%nodes(end_layer)%parent_node_index = i_node
423 end if
424
425 ! move to the next layer
426 start_layer = end_layer + 1
427 end_layer = this%allocated_node_count
428
429 ! If there is only one node left, we are done
430 done = start_layer .eq. end_layer
431 end do
432
433 ! The last node allocated is the root node
434 this%root_node_index = this%allocated_node_count
435
436 if (this%get_size() .ne. size(objects)) then
437 print *, "this%get_size() = ", this%get_size()
438 print *, "size(objects) = ", size(objects)
439 call neko_error("Invalid tree size")
440 end if
441
442 end subroutine aabb_tree_build_tree_aabb
443
444
445
447 subroutine aabb_tree_build_tree(this, objects, padding)
448 class(aabb_tree_t), intent(inout) :: this
449 class(*), target, intent(in) :: objects(:)
450 real(kind=dp), optional, intent(in) :: padding
451
452 integer :: i_obj, i_node, i
453 logical :: done
454
455 integer :: start_layer, end_layer
456
457 type(aabb_t), allocatable :: box_list(:)
458 integer, dimension(:), allocatable :: sorted_indices
459
460 real(kind=dp) :: aabb_padding
461
462 if (allocated(box_list)) deallocate(box_list)
463 allocate(box_list(size(objects)))
464
465 call this%init(size(objects) * 2)
466 if (size(objects) .eq. 0) then
467 return
468 end if
469
470 ! ------------------------------------------------------------------------ !
471 ! Start by sorting the list of objects, then build a balanced binary tree
472 ! from the sorted list
473
474
475 if (present(padding)) then
476 aabb_padding = padding
477 else
478 aabb_padding = 0.0_dp
479 end if
480
481 do i_obj = 1, size(objects)
482 box_list(i_obj) = get_aabb(objects(i_obj), aabb_padding)
483 end do
484 call sort(box_list, sorted_indices)
485
486 do i = 1, size(sorted_indices)
487 i_obj = sorted_indices(i)
488 i_node = this%allocate_node()
489 this%nodes(i_node)%aabb = box_list(i_obj)
490 this%nodes(i_node)%object_index = i_obj
491 end do
492
493
494 start_layer = 1
495 end_layer = size(objects)
496 done = .false.
497 do while (.not. done)
498
499 ! build the next layer
500 do i = start_layer, end_layer - 1, 2
501 i_node = this%allocate_node()
502
503 this%nodes(i_node)%aabb = merge(this%nodes(i)%aabb, &
504 this%nodes(i + 1)%aabb)
505
506 this%nodes(i_node)%left_node_index = i
507 this%nodes(i_node)%right_node_index = i + 1
508
509 this%nodes(i)%parent_node_index = i_node
510 this%nodes(i + 1)%parent_node_index = i_node
511 end do
512
513 ! if the number of nodes is odd, we need to create a new node to hold the
514 ! last node
515 if (mod(end_layer - start_layer, 2) .eq. 0) then
516 i_node = this%allocate_node()
517 this%nodes(i_node)%aabb = this%nodes(end_layer)%aabb
518 this%nodes(i_node)%left_node_index = end_layer
519 this%nodes(i_node)%right_node_index = aabb_null_node
520
521 this%nodes(end_layer)%parent_node_index = i_node
522 end if
523
524 ! move to the next layer
525 start_layer = end_layer + 1
526 end_layer = this%allocated_node_count
527
528 ! If there is only one node left, we are done
529 done = start_layer .eq. end_layer
530 end do
531
532 ! The last node allocated is the root node
533 this%root_node_index = this%allocated_node_count
534
535 if (this%get_size() .ne. size(objects)) then
536 print *, "this%get_size() = ", this%get_size()
537 print *, "size(objects) = ", size(objects)
538 call neko_error("Invalid tree size")
539 end if
540
541 if (allocated(box_list)) deallocate(box_list)
542 if (allocated(sorted_indices)) deallocate(sorted_indices)
543 end subroutine aabb_tree_build_tree
544
546 subroutine sort(array, indices)
547 type(aabb_t), dimension(:), intent(in) :: array
548 integer, intent(inout), dimension(:), allocatable :: indices
549 logical, dimension(:), allocatable :: visited
550
551 integer :: i, imin
552 integer :: minidx
553
554 allocate(indices(size(array)))
555 allocate(visited(size(array)))
556
557 visited = .false.
558 indices = 0
559 do i = 1, size(array)
560 minidx = -1
561 do imin = 1, size(array)
562 if (.not. visited(imin) .and. minidx .eq. -1) minidx = imin
563 if (minidx .gt. -1) then
564 if (visited(imin) .and. array(imin) .lt. array(minidx)) minidx = imin
565 end if
566 end do
567
568 indices(i) = minidx
569 visited(minidx) = .true.
570 end do
571
572 if (allocated(visited)) deallocate(visited)
573 end subroutine sort
574
575 ! -------------------------------------------------------------------------- !
576 ! Getters
577
579 function aabb_tree_get_size(this) result(size)
580 class(aabb_tree_t), intent(in) :: this
581 integer :: size
582
583 type(stack_i4_t) :: simple_stack
584 integer :: idx, tmp
585
586 call simple_stack%init(this%allocated_node_count)
587 size = 0
588 tmp = this%get_root_index()
589 if (tmp .ne. aabb_null_node) then
590 call simple_stack%push(tmp)
591 end if
592
593 do while (.not. simple_stack%is_empty())
594 idx = simple_stack%pop()
595 if (idx .eq. aabb_null_node) cycle
596
597 if (this%nodes(idx)%is_leaf()) then
598 size = size + 1
599 else
600 tmp = this%get_left_index(idx)
601 call simple_stack%push(tmp)
602 tmp = this%get_right_index(idx)
603 call simple_stack%push(tmp)
604 end if
605 end do
606
607 call simple_stack%free()
608 end function aabb_tree_get_size
609
610 ! -------------------------------------------------------------------------- !
611 ! Get index of nodes
612
614 pure function aabb_tree_get_root_index(this) result(root_index)
615 class(aabb_tree_t), intent(in) :: this
616 integer :: root_index
617
618 root_index = this%root_node_index
619 end function aabb_tree_get_root_index
620
622 pure function aabb_tree_get_parent_index(this, node_index) &
623 result(parent_index)
624 class(aabb_tree_t), intent(in) :: this
625 integer, intent(in) :: node_index
626 integer :: parent_index
627
628 parent_index = this%nodes(node_index)%parent_node_index
629 end function aabb_tree_get_parent_index
630
632 pure function aabb_tree_get_left_index(this, node_index) &
633 result(left_index)
634 class(aabb_tree_t), intent(in) :: this
635 integer, intent(in) :: node_index
636 integer :: left_index
637
638 left_index = this%nodes(node_index)%left_node_index
639 end function aabb_tree_get_left_index
640
642 pure function aabb_tree_get_right_index(this, node_index) &
643 result(right_index)
644 class(aabb_tree_t), intent(in) :: this
645 integer, intent(in) :: node_index
646 integer :: right_index
647
648 right_index = this%nodes(node_index)%right_node_index
649 end function aabb_tree_get_right_index
650
651 ! -------------------------------------------------------------------------- !
652 ! Get nodes
653
655 pure function aabb_tree_get_node(this, node_index) result(node)
656 class(aabb_tree_t), intent(in) :: this
657 integer, intent(in) :: node_index
658 type(aabb_node_t) :: node
659
660 node = this%nodes(node_index)
661 end function aabb_tree_get_node
662
664 pure function aabb_tree_get_root_node(this) result(root_node)
665 class(aabb_tree_t), intent(in) :: this
666 type(aabb_node_t) :: root_node
667
668 root_node = this%nodes(this%root_node_index)
669 end function aabb_tree_get_root_node
670
672 pure function aabb_tree_get_parent_node(this, node_index) &
673 result(parent_node)
674 class(aabb_tree_t), intent(in) :: this
675 integer, intent(in) :: node_index
676 type(aabb_node_t) :: parent_node
677
678 parent_node = this%nodes(this%nodes(node_index)%parent_node_index)
679 end function aabb_tree_get_parent_node
680
682 pure function aabb_tree_get_left_node(this, node_index) result(left_node)
683 class(aabb_tree_t), intent(in) :: this
684 integer, intent(in) :: node_index
685 type(aabb_node_t) :: left_node
686
687 left_node = this%nodes(this%nodes(node_index)%left_node_index)
688 end function aabb_tree_get_left_node
689
691 pure function aabb_tree_get_right_node(this, node_index) &
692 result(right_node)
693 class(aabb_tree_t), intent(in) :: this
694 integer, intent(in) :: node_index
695 type(aabb_node_t) :: right_node
696
697 right_node = this%nodes(this%nodes(node_index)%right_node_index)
698 end function aabb_tree_get_right_node
699
700 pure function aabb_tree_get_aabb(this, node_index) result(out_box)
701 class(aabb_tree_t), intent(in) :: this
702 integer, intent(in) :: node_index
703 type(aabb_t) :: out_box
704
705 out_box = this%nodes(node_index)%aabb
706 end function aabb_tree_get_aabb
707
708 ! -------------------------------------------------------------------------- !
709
711 subroutine aabb_tree_insert_object(this, object, object_index)
712 class(aabb_tree_t), intent(inout) :: this
713 class(*), intent(in) :: object
714 integer, intent(in) :: object_index
715
716 integer :: node_index
717
718 node_index = this%allocate_node()
719 this%nodes(node_index)%aabb = get_aabb(object)
720 this%nodes(node_index)%object_index = object_index
721
722 call this%insert_leaf(node_index)
723 end subroutine aabb_tree_insert_object
724
726 subroutine aabb_tree_query_overlaps(this, object, object_index, overlaps)
727 class(aabb_tree_t), intent(in) :: this
728 class(*), intent(in) :: object
729 integer, intent(in) :: object_index
730 type(stack_i4_t), intent(inout) :: overlaps
731
732 type(stack_i4_t) :: simple_stack
733 type(aabb_t) :: object_box
734
735 integer :: root_index, left_index, right_index
736 integer :: node_index, tmp_index
737
738 object_box = get_aabb(object)
739 root_index = this%get_root_index()
740
741 call simple_stack%init()
742 call simple_stack%push(root_index)
743
744 do while (.not. simple_stack%is_empty())
745 node_index = simple_stack%pop()
746
747 if (node_index == aabb_null_node) cycle
748
749 if (this%nodes(node_index)%aabb%overlaps(object_box)) then
750 if (this%nodes(node_index)%is_leaf()) then
751 if (this%nodes(node_index)%object_index .ne. object_index) then
752 tmp_index = this%nodes(node_index)%object_index
753 call overlaps%push(tmp_index)
754 end if
755 else
756 left_index = this%get_left_index(node_index)
757 if (left_index .ne. aabb_null_node) then
758 call simple_stack%push(left_index)
759 end if
760 right_index = this%get_right_index(node_index)
761 if (right_index .ne. aabb_null_node) then
762 call simple_stack%push(right_index)
763 end if
764 end if
765 end if
766 end do
767 call simple_stack%free()
768 end subroutine aabb_tree_query_overlaps
769
770 ! -------------------------------------------------------------------------- !
771 ! Internal methods
772
774 function aabb_tree_allocate_node(this) result(node_index)
775 class(aabb_tree_t), intent(inout) :: this
776 integer :: node_index
777
778 if (this%next_free_node_index == aabb_null_node) then
779 call this%resize_node_pool(this%node_capacity + this%growth_size)
780 end if
781
782 node_index = this%next_free_node_index
783
784 associate(new_node => this%nodes(node_index))
785 this%next_free_node_index = new_node%next_node_index
786
787 new_node%parent_node_index = aabb_null_node
788 new_node%left_node_index = aabb_null_node
789 new_node%right_node_index = aabb_null_node
790
791 this%next_free_node_index = new_node%next_node_index
792 this%allocated_node_count = this%allocated_node_count + 1
793
794 end associate
795 end function aabb_tree_allocate_node
796
798 subroutine aabb_tree_deallocate_node(this, node_index)
799 class(aabb_tree_t), intent(inout) :: this
800 integer, intent(in) :: node_index
801
802 this%nodes(node_index)%next_node_index = this%next_free_node_index
803 this%next_free_node_index = node_index
804 this%allocated_node_count = this%allocated_node_count - 1
805 end subroutine aabb_tree_deallocate_node
806
808 subroutine aabb_tree_insert_leaf(this, leaf_node_index)
809 class(aabb_tree_t), intent(inout) :: this
810 integer, intent(in) :: leaf_node_index
811
812 integer :: tree_node_index
813
814 real(kind=rp) :: cost_left
815 real(kind=rp) :: cost_right
816
817 type(aabb_node_t) :: leaf_node
818 type(aabb_node_t) :: tree_node
819 type(aabb_node_t) :: left_node
820 type(aabb_node_t) :: right_node
821
822 type(aabb_t) :: combined_aabb
823 real(kind=rp) :: new_parent_node_cost
824 real(kind=rp) :: minimum_push_down_cost
825 type(aabb_t) :: new_left_aabb
826 type(aabb_t) :: new_right_aabb
827 integer :: leaf_sibling_index
828 type(aabb_node_t) :: leaf_sibling
829 integer :: old_parent_index
830 integer :: new_parent_index
831 type(aabb_node_t) :: new_parent
832 type(aabb_node_t) :: old_parent
833
834 ! make sure were inserting a new leaf
835 leaf_node = this%nodes(leaf_node_index)
836
837 ! if the tree is empty then we make the root the leaf
838 if (this%root_node_index .eq. aabb_null_node) then
839 this%root_node_index = leaf_node_index
840 leaf_node%parent_node_index = aabb_null_node
841 leaf_node%left_node_index = aabb_null_node
842 leaf_node%right_node_index = aabb_null_node
843
844 return
845 end if
846
847 ! search for the best place to put the new leaf in the tree
848 ! we use surface area and depth as search heuristics
849 tree_node_index = this%root_node_index
850 tree_node = this%get_node(tree_node_index)
851 do while (.not. tree_node%is_leaf())
852
853 ! because of the test in the while loop above we know we are never a
854 ! leaf inside it
855 left_node = this%get_left_node(tree_node_index)
856 right_node = this%get_right_node(tree_node_index)
857
858 ! ------------------------------------------------------------------- !
859
860 combined_aabb = merge(tree_node%aabb, leaf_node%get_aabb())
861
862 new_parent_node_cost = 2.0_rp * combined_aabb%get_surface_area()
863 minimum_push_down_cost = 2.0_rp * ( &
864 & combined_aabb%get_surface_area() &
865 & - tree_node%aabb%get_surface_area()&
866 & )
867
868 ! use the costs to figure out whether to create a new parent here or
869 ! descend
870 if (left_node%is_leaf()) then
871 new_left_aabb = merge(leaf_node%aabb, left_node%get_aabb())
872 cost_left = new_left_aabb%get_surface_area() + minimum_push_down_cost
873 else
874 new_left_aabb = merge(leaf_node%aabb, left_node%get_aabb())
875 cost_left = ( &
876 & new_left_aabb%get_surface_area() &
877 & - left_node%aabb%get_surface_area()&
878 & ) + minimum_push_down_cost
879 end if
880
881 if (right_node%is_leaf()) then
882 new_right_aabb = merge(leaf_node%aabb, right_node%aabb)
883 cost_right = new_right_aabb%get_surface_area() + &
884 minimum_push_down_cost
885 else
886 new_right_aabb = merge(leaf_node%aabb, right_node%aabb)
887 cost_right = ( &
888 & new_right_aabb%get_surface_area() &
889 & - right_node%aabb%get_surface_area() &
890 & ) + minimum_push_down_cost
891 end if
892
893 ! if the cost of creating a new parent node here is less than descending
894 ! in either direction then we know we need to create a new parent node,
895 ! errrr, here and attach the leaf to that
896 if (new_parent_node_cost < cost_left .and. &
897 new_parent_node_cost < cost_right) then
898 exit
899 end if
900
901 ! otherwise descend in the cheapest direction
902 if (cost_left .lt. cost_right) then
903 tree_node_index = tree_node%get_left_index()
904 else
905 tree_node_index = tree_node%get_right_index()
906 end if
907
908 ! ------------------------------------------------------------------- !
909 ! Update the node and continue the loop
910 tree_node = this%get_node(tree_node_index)
911 end do
912
913 ! the leafs sibling is going to be the node we found above and we are
914 ! going to create a new parent node and attach the leaf and this item
915 leaf_sibling_index = tree_node_index
916 leaf_sibling = this%nodes(leaf_sibling_index)
917 old_parent_index = this%get_parent_index(leaf_sibling_index)
918 new_parent_index = this%allocate_node()
919 new_parent = this%nodes(new_parent_index)
920 new_parent%parent_node_index = old_parent_index
921 new_parent%aabb = merge(leaf_node%aabb, leaf_sibling%aabb)
922
923 if (leaf_node .lt. leaf_sibling) then
924 new_parent%left_node_index = leaf_node_index
925 new_parent%right_node_index = leaf_sibling_index
926 else
927 new_parent%left_node_index = leaf_sibling_index
928 new_parent%right_node_index = leaf_node_index
929 end if
930
931 leaf_node%parent_node_index = new_parent_index
932 leaf_sibling%parent_node_index = new_parent_index
933
934 if (old_parent_index .eq. aabb_null_node) then
935 ! the old parent was the root and so this is now the root
936 this%root_node_index = new_parent_index
937 else
938 ! the old parent was not the root and so we need to patch the left or
939 ! right index to point to the new node
940 old_parent = this%nodes(old_parent_index)
941 if (old_parent%left_node_index .eq. leaf_sibling_index) then
942 old_parent%left_node_index = new_parent_index
943 else
944 old_parent%right_node_index = new_parent_index
945 end if
946 this%nodes(old_parent_index) = old_parent
947 end if
948
949 this%nodes(leaf_node_index) = leaf_node
950 this%nodes(leaf_sibling_index) = leaf_sibling
951 this%nodes(new_parent_index) = new_parent
952
953 ! finally we need to walk back up the tree fixing heights and areas
954 tree_node_index = leaf_node%parent_node_index
955
956 call this%fix_upwards_tree(tree_node_index)
957
958 end subroutine aabb_tree_insert_leaf
959
961 function aabb_tree_valid_tree(this) result(valid)
962 class(aabb_tree_t), intent(in) :: this
963 logical :: valid
964
965 type(stack_i4_t) :: simple_stack
966 integer :: current_index
967 integer :: root_index, left_index, right_index
968
969 valid = .true.
970 if (this%root_node_index .eq. aabb_null_node) then
971 valid = .false.
972 end if
973
974 root_index = this%get_root_index()
975
976 call simple_stack%init(this%node_capacity)
977 call simple_stack%push(root_index)
978
979 do while (.not. simple_stack%is_empty())
980 current_index = simple_stack%pop()
981 if (current_index == aabb_null_node) cycle
982
983 valid = valid .and. this%nodes(current_index)%is_valid()
984
985 if (.not. this%nodes(current_index)%is_leaf()) then
986 left_index = this%get_left_index(current_index)
987 right_index = this%get_right_index(current_index)
988
989 call simple_stack%push(left_index)
990 call simple_stack%push(right_index)
991 end if
992 end do
993 end function aabb_tree_valid_tree
994
998 subroutine aabb_tree_fix_upwards_tree(this, tree_start_index)
999 class(aabb_tree_t), intent(inout) :: this
1000 integer, intent(in) :: tree_start_index
1001
1002 type(aabb_node_t) :: left_node
1003 type(aabb_node_t) :: right_node
1004 integer :: tree_node_index
1005
1006 tree_node_index = tree_start_index
1007 do while (tree_node_index .ne. aabb_null_node)
1008 left_node = this%get_left_node(tree_node_index)
1009 right_node = this%get_right_node(tree_node_index)
1010
1011 this%nodes(tree_node_index)%aabb = merge(left_node%aabb, right_node%aabb)
1012
1013 tree_node_index = this%get_parent_index(tree_node_index)
1014 end do
1015 end subroutine aabb_tree_fix_upwards_tree
1016
1018 subroutine aabb_tree_print(this)
1019 class(aabb_tree_t), intent(inout) :: this
1020 type(stack_i4_t) :: simple_stack
1021
1022 integer :: current_index
1023 integer :: root_index, left_index, right_index
1024
1025 root_index = this%get_root_index()
1026 call simple_stack%init(this%node_capacity)
1027 call simple_stack%push(root_index)
1028
1029 do while (.not. simple_stack%is_empty())
1030 current_index = simple_stack%pop()
1031 if (current_index .eq. aabb_null_node) cycle
1032
1033 left_index = this%get_left_index(current_index)
1034 right_index = this%get_right_index(current_index)
1035
1036 call simple_stack%push(this%nodes(current_index)%left_node_index)
1037 call simple_stack%push(this%nodes(current_index)%right_node_index)
1038
1039 write(*, *) "i = ", current_index
1040 write(*, *) " Parent : ", this%get_parent_index(current_index)
1041 write(*, *) " Children: ", this%get_left_index(current_index), &
1042 this%get_right_index(current_index)
1043
1044 write(*, *) " object_index = ", this%nodes(current_index)%object_index
1045 end do
1046
1047 end subroutine aabb_tree_print
1048
1050 subroutine aabb_tree_resize_node_pool(this, new_capacity)
1051 class(aabb_tree_t), intent(inout) :: this
1052 integer, intent(in) :: new_capacity
1053
1054 type(aabb_node_t), dimension(:), allocatable :: temp
1055 integer :: i
1056
1057 allocate(temp(new_capacity))
1058 temp(:this%node_capacity) = this%nodes(:this%node_capacity)
1059
1060 do i = this%allocated_node_count, new_capacity
1061 temp(i)%next_node_index = i + 1
1062 end do
1063 temp(new_capacity)%next_node_index = aabb_null_node
1064
1065 call move_alloc(temp, this%nodes)
1066
1067 this%node_capacity = new_capacity
1068 this%next_free_node_index = this%allocated_node_count + 1
1069
1070 end subroutine aabb_tree_resize_node_pool
1071
1072end 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)
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
Definition aabb_tree.f90:79
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.
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:86
Axis Aligned Bounding Box (aabb) Tree.
Integer based stack.
Definition stack.f90:63
Triangular element.
Definition tri.f90:61