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