Neko 1.99.1
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 end subroutine aabb_tree_build_tree
542
544 subroutine sort(array, indices)
545 type(aabb_t), dimension(:), intent(in) :: array
546 integer, intent(inout), dimension(:), allocatable :: indices
547 logical, dimension(:), allocatable :: visited
548
549 integer :: i, imin
550 integer :: minidx
551
552 allocate(indices(size(array)))
553 allocate(visited(size(array)))
554
555 visited = .false.
556 indices = 0
557 do i = 1, size(array)
558 minidx = -1
559 do imin = 1, size(array)
560 if (.not. visited(imin) .and. minidx .eq. -1) minidx = imin
561 if (minidx .gt. -1) then
562 if (visited(imin) .and. array(imin) .lt. array(minidx)) minidx = imin
563 end if
564 end do
565
566 indices(i) = minidx
567 visited(minidx) = .true.
568 end do
569
570 end subroutine sort
571
572 ! -------------------------------------------------------------------------- !
573 ! Getters
574
576 function aabb_tree_get_size(this) result(size)
577 class(aabb_tree_t), intent(in) :: this
578 integer :: size
579
580 type(stack_i4_t) :: simple_stack
581 integer :: idx, tmp
582
583 call simple_stack%init(this%allocated_node_count)
584 size = 0
585 tmp = this%get_root_index()
586 if (tmp .ne. aabb_null_node) then
587 call simple_stack%push(tmp)
588 end if
589
590 do while (.not. simple_stack%is_empty())
591 idx = simple_stack%pop()
592 if (idx .eq. aabb_null_node) cycle
593
594 if (this%nodes(idx)%is_leaf()) then
595 size = size + 1
596 else
597 tmp = this%get_left_index(idx)
598 call simple_stack%push(tmp)
599 tmp = this%get_right_index(idx)
600 call simple_stack%push(tmp)
601 end if
602 end do
603
604 end function aabb_tree_get_size
605
606 ! -------------------------------------------------------------------------- !
607 ! Get index of nodes
608
610 pure function aabb_tree_get_root_index(this) result(root_index)
611 class(aabb_tree_t), intent(in) :: this
612 integer :: root_index
613
614 root_index = this%root_node_index
615 end function aabb_tree_get_root_index
616
618 pure function aabb_tree_get_parent_index(this, node_index) &
619 result(parent_index)
620 class(aabb_tree_t), intent(in) :: this
621 integer, intent(in) :: node_index
622 integer :: parent_index
623
624 parent_index = this%nodes(node_index)%parent_node_index
625 end function aabb_tree_get_parent_index
626
628 pure function aabb_tree_get_left_index(this, node_index) &
629 result(left_index)
630 class(aabb_tree_t), intent(in) :: this
631 integer, intent(in) :: node_index
632 integer :: left_index
633
634 left_index = this%nodes(node_index)%left_node_index
635 end function aabb_tree_get_left_index
636
638 pure function aabb_tree_get_right_index(this, node_index) &
639 result(right_index)
640 class(aabb_tree_t), intent(in) :: this
641 integer, intent(in) :: node_index
642 integer :: right_index
643
644 right_index = this%nodes(node_index)%right_node_index
645 end function aabb_tree_get_right_index
646
647 ! -------------------------------------------------------------------------- !
648 ! Get nodes
649
651 pure function aabb_tree_get_node(this, node_index) result(node)
652 class(aabb_tree_t), intent(in) :: this
653 integer, intent(in) :: node_index
654 type(aabb_node_t) :: node
655
656 node = this%nodes(node_index)
657 end function aabb_tree_get_node
658
660 pure function aabb_tree_get_root_node(this) result(root_node)
661 class(aabb_tree_t), intent(in) :: this
662 type(aabb_node_t) :: root_node
663
664 root_node = this%nodes(this%root_node_index)
665 end function aabb_tree_get_root_node
666
668 pure function aabb_tree_get_parent_node(this, node_index) &
669 result(parent_node)
670 class(aabb_tree_t), intent(in) :: this
671 integer, intent(in) :: node_index
672 type(aabb_node_t) :: parent_node
673
674 parent_node = this%nodes(this%nodes(node_index)%parent_node_index)
675 end function aabb_tree_get_parent_node
676
678 pure function aabb_tree_get_left_node(this, node_index) result(left_node)
679 class(aabb_tree_t), intent(in) :: this
680 integer, intent(in) :: node_index
681 type(aabb_node_t) :: left_node
682
683 left_node = this%nodes(this%nodes(node_index)%left_node_index)
684 end function aabb_tree_get_left_node
685
687 pure function aabb_tree_get_right_node(this, node_index) &
688 result(right_node)
689 class(aabb_tree_t), intent(in) :: this
690 integer, intent(in) :: node_index
691 type(aabb_node_t) :: right_node
692
693 right_node = this%nodes(this%nodes(node_index)%right_node_index)
694 end function aabb_tree_get_right_node
695
696 pure function aabb_tree_get_aabb(this, node_index) result(out_box)
697 class(aabb_tree_t), intent(in) :: this
698 integer, intent(in) :: node_index
699 type(aabb_t) :: out_box
700
701 out_box = this%nodes(node_index)%aabb
702 end function aabb_tree_get_aabb
703
704 ! -------------------------------------------------------------------------- !
705
707 subroutine aabb_tree_insert_object(this, object, object_index)
708 class(aabb_tree_t), intent(inout) :: this
709 class(*), intent(in) :: object
710 integer, intent(in) :: object_index
711
712 integer :: node_index
713
714 node_index = this%allocate_node()
715 this%nodes(node_index)%aabb = get_aabb(object)
716 this%nodes(node_index)%object_index = object_index
717
718 call this%insert_leaf(node_index)
719 end subroutine aabb_tree_insert_object
720
722 subroutine aabb_tree_query_overlaps(this, object, object_index, overlaps)
723 class(aabb_tree_t), intent(in) :: this
724 class(*), intent(in) :: object
725 integer, intent(in) :: object_index
726 type(stack_i4_t), intent(inout) :: overlaps
727
728 type(stack_i4_t) :: simple_stack
729 type(aabb_t) :: object_box
730
731 integer :: root_index, left_index, right_index
732 integer :: node_index, tmp_index
733
734 object_box = get_aabb(object)
735 root_index = this%get_root_index()
736
737 call simple_stack%init()
738 call simple_stack%push(root_index)
739
740 do while (.not. simple_stack%is_empty())
741 node_index = simple_stack%pop()
742
743 if (node_index == aabb_null_node) cycle
744
745 if (this%nodes(node_index)%aabb%overlaps(object_box)) then
746 if (this%nodes(node_index)%is_leaf()) then
747 if (this%nodes(node_index)%object_index .ne. object_index) then
748 tmp_index = this%nodes(node_index)%object_index
749 call overlaps%push(tmp_index)
750 end if
751 else
752 left_index = this%get_left_index(node_index)
753 if (left_index .ne. aabb_null_node) then
754 call simple_stack%push(left_index)
755 end if
756 right_index = this%get_right_index(node_index)
757 if (right_index .ne. aabb_null_node) then
758 call simple_stack%push(right_index)
759 end if
760 end if
761 end if
762 end do
763 call simple_stack%free()
764 end subroutine aabb_tree_query_overlaps
765
766 ! -------------------------------------------------------------------------- !
767 ! Internal methods
768
770 function aabb_tree_allocate_node(this) result(node_index)
771 class(aabb_tree_t), intent(inout) :: this
772 integer :: node_index
773
774 if (this%next_free_node_index == aabb_null_node) then
775 call this%resize_node_pool(this%node_capacity + this%growth_size)
776 end if
777
778 node_index = this%next_free_node_index
779
780 associate(new_node => this%nodes(node_index))
781 this%next_free_node_index = new_node%next_node_index
782
783 new_node%parent_node_index = aabb_null_node
784 new_node%left_node_index = aabb_null_node
785 new_node%right_node_index = aabb_null_node
786
787 this%next_free_node_index = new_node%next_node_index
788 this%allocated_node_count = this%allocated_node_count + 1
789
790 end associate
791 end function aabb_tree_allocate_node
792
794 subroutine aabb_tree_deallocate_node(this, node_index)
795 class(aabb_tree_t), intent(inout) :: this
796 integer, intent(in) :: node_index
797
798 this%nodes(node_index)%next_node_index = this%next_free_node_index
799 this%next_free_node_index = node_index
800 this%allocated_node_count = this%allocated_node_count - 1
801 end subroutine aabb_tree_deallocate_node
802
804 subroutine aabb_tree_insert_leaf(this, leaf_node_index)
805 class(aabb_tree_t), intent(inout) :: this
806 integer, intent(in) :: leaf_node_index
807
808 integer :: tree_node_index
809
810 real(kind=rp) :: cost_left
811 real(kind=rp) :: cost_right
812
813 type(aabb_node_t) :: leaf_node
814 type(aabb_node_t) :: tree_node
815 type(aabb_node_t) :: left_node
816 type(aabb_node_t) :: right_node
817
818 type(aabb_t) :: combined_aabb
819 real(kind=rp) :: new_parent_node_cost
820 real(kind=rp) :: minimum_push_down_cost
821 type(aabb_t) :: new_left_aabb
822 type(aabb_t) :: new_right_aabb
823 integer :: leaf_sibling_index
824 type(aabb_node_t) :: leaf_sibling
825 integer :: old_parent_index
826 integer :: new_parent_index
827 type(aabb_node_t) :: new_parent
828 type(aabb_node_t) :: old_parent
829
830 ! make sure were inserting a new leaf
831 leaf_node = this%nodes(leaf_node_index)
832
833 ! if the tree is empty then we make the root the leaf
834 if (this%root_node_index .eq. aabb_null_node) then
835 this%root_node_index = leaf_node_index
836 leaf_node%parent_node_index = aabb_null_node
837 leaf_node%left_node_index = aabb_null_node
838 leaf_node%right_node_index = aabb_null_node
839
840 return
841 end if
842
843 ! search for the best place to put the new leaf in the tree
844 ! we use surface area and depth as search heuristics
845 tree_node_index = this%root_node_index
846 tree_node = this%get_node(tree_node_index)
847 do while (.not. tree_node%is_leaf())
848
849 ! because of the test in the while loop above we know we are never a
850 ! leaf inside it
851 left_node = this%get_left_node(tree_node_index)
852 right_node = this%get_right_node(tree_node_index)
853
854 ! ------------------------------------------------------------------- !
855
856 combined_aabb = merge(tree_node%aabb, leaf_node%get_aabb())
857
858 new_parent_node_cost = 2.0_rp * combined_aabb%get_surface_area()
859 minimum_push_down_cost = 2.0_rp * ( &
860 & combined_aabb%get_surface_area() &
861 & - tree_node%aabb%get_surface_area()&
862 & )
863
864 ! use the costs to figure out whether to create a new parent here or
865 ! descend
866 if (left_node%is_leaf()) then
867 new_left_aabb = merge(leaf_node%aabb, left_node%get_aabb())
868 cost_left = new_left_aabb%get_surface_area() + minimum_push_down_cost
869 else
870 new_left_aabb = merge(leaf_node%aabb, left_node%get_aabb())
871 cost_left = ( &
872 & new_left_aabb%get_surface_area() &
873 & - left_node%aabb%get_surface_area()&
874 & ) + minimum_push_down_cost
875 end if
876
877 if (right_node%is_leaf()) then
878 new_right_aabb = merge(leaf_node%aabb, right_node%aabb)
879 cost_right = new_right_aabb%get_surface_area() + &
880 minimum_push_down_cost
881 else
882 new_right_aabb = merge(leaf_node%aabb, right_node%aabb)
883 cost_right = ( &
884 & new_right_aabb%get_surface_area() &
885 & - right_node%aabb%get_surface_area() &
886 & ) + minimum_push_down_cost
887 end if
888
889 ! if the cost of creating a new parent node here is less than descending
890 ! in either direction then we know we need to create a new parent node,
891 ! errrr, here and attach the leaf to that
892 if (new_parent_node_cost < cost_left .and. &
893 new_parent_node_cost < cost_right) then
894 exit
895 end if
896
897 ! otherwise descend in the cheapest direction
898 if (cost_left .lt. cost_right) then
899 tree_node_index = tree_node%get_left_index()
900 else
901 tree_node_index = tree_node%get_right_index()
902 end if
903
904 ! ------------------------------------------------------------------- !
905 ! Update the node and continue the loop
906 tree_node = this%get_node(tree_node_index)
907 end do
908
909 ! the leafs sibling is going to be the node we found above and we are
910 ! going to create a new parent node and attach the leaf and this item
911 leaf_sibling_index = tree_node_index
912 leaf_sibling = this%nodes(leaf_sibling_index)
913 old_parent_index = this%get_parent_index(leaf_sibling_index)
914 new_parent_index = this%allocate_node()
915 new_parent = this%nodes(new_parent_index)
916 new_parent%parent_node_index = old_parent_index
917 new_parent%aabb = merge(leaf_node%aabb, leaf_sibling%aabb)
918
919 if (leaf_node .lt. leaf_sibling) then
920 new_parent%left_node_index = leaf_node_index
921 new_parent%right_node_index = leaf_sibling_index
922 else
923 new_parent%left_node_index = leaf_sibling_index
924 new_parent%right_node_index = leaf_node_index
925 end if
926
927 leaf_node%parent_node_index = new_parent_index
928 leaf_sibling%parent_node_index = new_parent_index
929
930 if (old_parent_index .eq. aabb_null_node) then
931 ! the old parent was the root and so this is now the root
932 this%root_node_index = new_parent_index
933 else
934 ! the old parent was not the root and so we need to patch the left or
935 ! right index to point to the new node
936 old_parent = this%nodes(old_parent_index)
937 if (old_parent%left_node_index .eq. leaf_sibling_index) then
938 old_parent%left_node_index = new_parent_index
939 else
940 old_parent%right_node_index = new_parent_index
941 end if
942 this%nodes(old_parent_index) = old_parent
943 end if
944
945 this%nodes(leaf_node_index) = leaf_node
946 this%nodes(leaf_sibling_index) = leaf_sibling
947 this%nodes(new_parent_index) = new_parent
948
949 ! finally we need to walk back up the tree fixing heights and areas
950 tree_node_index = leaf_node%parent_node_index
951
952 call this%fix_upwards_tree(tree_node_index)
953
954 end subroutine aabb_tree_insert_leaf
955
957 function aabb_tree_valid_tree(this) result(valid)
958 class(aabb_tree_t), intent(in) :: this
959 logical :: valid
960
961 type(stack_i4_t) :: simple_stack
962 integer :: current_index
963 integer :: root_index, left_index, right_index
964
965 valid = .true.
966 if (this%root_node_index .eq. aabb_null_node) then
967 valid = .false.
968 end if
969
970 root_index = this%get_root_index()
971
972 call simple_stack%init(this%node_capacity)
973 call simple_stack%push(root_index)
974
975 do while (.not. simple_stack%is_empty())
976 current_index = simple_stack%pop()
977 if (current_index == aabb_null_node) cycle
978
979 valid = valid .and. this%nodes(current_index)%is_valid()
980
981 if (.not. this%nodes(current_index)%is_leaf()) then
982 left_index = this%get_left_index(current_index)
983 right_index = this%get_right_index(current_index)
984
985 call simple_stack%push(left_index)
986 call simple_stack%push(right_index)
987 end if
988 end do
989 end function aabb_tree_valid_tree
990
994 subroutine aabb_tree_fix_upwards_tree(this, tree_start_index)
995 class(aabb_tree_t), intent(inout) :: this
996 integer, intent(in) :: tree_start_index
997
998 type(aabb_node_t) :: left_node
999 type(aabb_node_t) :: right_node
1000 integer :: tree_node_index
1001
1002 tree_node_index = tree_start_index
1003 do while (tree_node_index .ne. aabb_null_node)
1004 left_node = this%get_left_node(tree_node_index)
1005 right_node = this%get_right_node(tree_node_index)
1006
1007 this%nodes(tree_node_index)%aabb = merge(left_node%aabb, right_node%aabb)
1008
1009 tree_node_index = this%get_parent_index(tree_node_index)
1010 end do
1011 end subroutine aabb_tree_fix_upwards_tree
1012
1014 subroutine aabb_tree_print(this)
1015 class(aabb_tree_t), intent(inout) :: this
1016 type(stack_i4_t) :: simple_stack
1017
1018 integer :: current_index
1019 integer :: root_index, left_index, right_index
1020
1021 root_index = this%get_root_index()
1022 call simple_stack%init(this%node_capacity)
1023 call simple_stack%push(root_index)
1024
1025 do while (.not. simple_stack%is_empty())
1026 current_index = simple_stack%pop()
1027 if (current_index .eq. aabb_null_node) cycle
1028
1029 left_index = this%get_left_index(current_index)
1030 right_index = this%get_right_index(current_index)
1031
1032 call simple_stack%push(this%nodes(current_index)%left_node_index)
1033 call simple_stack%push(this%nodes(current_index)%right_node_index)
1034
1035 write(*, *) "i = ", current_index
1036 write(*, *) " Parent : ", this%get_parent_index(current_index)
1037 write(*, *) " Children: ", this%get_left_index(current_index), &
1038 this%get_right_index(current_index)
1039
1040 write(*, *) " object_index = ", this%nodes(current_index)%object_index
1041 end do
1042
1043 end subroutine aabb_tree_print
1044
1046 subroutine aabb_tree_resize_node_pool(this, new_capacity)
1047 class(aabb_tree_t), intent(inout) :: this
1048 integer, intent(in) :: new_capacity
1049
1050 type(aabb_node_t), dimension(:), allocatable :: temp
1051 integer :: i
1052
1053 allocate(temp(new_capacity))
1054 temp(:this%node_capacity) = this%nodes(:this%node_capacity)
1055
1056 do i = this%allocated_node_count, new_capacity
1057 temp(i)%next_node_index = i + 1
1058 end do
1059 temp(new_capacity)%next_node_index = aabb_null_node
1060
1061 call move_alloc(temp, this%nodes)
1062
1063 this%node_capacity = new_capacity
1064 this%next_free_node_index = this%allocated_node_count + 1
1065
1066 end subroutine aabb_tree_resize_node_pool
1067
1068end 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