Neko 0.9.99
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
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
189contains
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
954end 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.
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 aabb_tree_build_tree(this, objects)
Builds the tree.
integer function, dimension(:), allocatable sort(array)
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.
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.
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:85
Axis Aligned Bounding Box (aabb) Tree.
Integer based stack.
Definition stack.f90:63
Triangular element.
Definition tri.f90:60