build_collision_grid Subroutine

public subroutine build_collision_grid(mesh)

三角形AABBを一様グリッドへ登録し、衝突判定の候補探索を高速化する。 要素数が少ない場合は線形探索にフォールバックする。

Arguments

Type IntentOptional Attributes Name
type(mesh_type), intent(inout) :: mesh

Calls

proc~~build_collision_grid~~CallsGraph proc~build_collision_grid build_collision_grid proc~cell_id~2 cell_id proc~build_collision_grid->proc~cell_id~2 proc~coord_to_cell~2 coord_to_cell proc~build_collision_grid->proc~coord_to_cell~2

Called by

proc~~build_collision_grid~~CalledByGraph proc~build_collision_grid build_collision_grid proc~update_mesh_geometry update_mesh_geometry proc~update_mesh_geometry->proc~build_collision_grid proc~init_mesh init_mesh proc~init_mesh->proc~update_mesh_geometry proc~prepare_periodic2_collision_mesh prepare_periodic2_collision_mesh proc~prepare_periodic2_collision_mesh->proc~update_mesh_geometry proc~apply_obj_transform apply_obj_transform proc~apply_obj_transform->proc~init_mesh proc~build_mesh_from_indexed build_mesh_from_indexed proc~build_mesh_from_indexed->proc~init_mesh proc~build_template_mesh build_template_mesh proc~build_template_mesh->proc~init_mesh proc~build_one_template build_one_template proc~build_template_mesh->proc~build_one_template proc~load_or_init_run_state load_or_init_run_state proc~load_or_init_run_state->proc~prepare_periodic2_collision_mesh proc~build_mesh_from_config build_mesh_from_config proc~load_or_init_run_state->proc~build_mesh_from_config proc~make_annulus make_annulus proc~make_annulus->proc~init_mesh proc~make_box make_box proc~make_box->proc~init_mesh proc~make_cylinder make_cylinder proc~make_cylinder->proc~init_mesh proc~make_plane make_plane proc~make_plane->proc~init_mesh proc~make_plate_hole make_plate_hole proc~make_plate_hole->proc~init_mesh proc~make_sphere make_sphere proc~make_sphere->proc~init_mesh proc~build_mesh_from_config->proc~apply_obj_transform proc~build_mesh_from_config->proc~build_template_mesh proc~load_obj_mesh load_obj_mesh proc~build_mesh_from_config->proc~load_obj_mesh proc~build_one_template->proc~make_annulus proc~build_one_template->proc~make_box proc~build_one_template->proc~make_cylinder proc~build_one_template->proc~make_plane proc~build_one_template->proc~make_plate_hole proc~build_one_template->proc~make_sphere proc~make_disk make_disk proc~build_one_template->proc~make_disk proc~load_obj_mesh->proc~build_mesh_from_indexed proc~make_disk->proc~make_annulus program~main main program~main->proc~load_or_init_run_state

Source Code

  subroutine build_collision_grid(mesh)
    type(mesh_type), intent(inout) :: mesh

    integer(i32), parameter :: min_nelem_for_grid = 64_i32
    integer(i32), parameter :: target_elems_per_cell = 8_i32
    integer(i32), parameter :: max_cells_axis = 128_i32
    real(dp), parameter :: rel_span_eps = 1.0d-9
    real(dp), parameter :: abs_span_eps = 1.0d-12

    integer(i32) :: nx, ny, nz, ncells
    integer(i32) :: i, iaxis, ix0, ix1, iy0, iy1, iz0, iz1, ix, iy, iz, cid, total_refs, pos
    integer(i32), allocatable :: counts(:), offsets(:)
    real(dp) :: span(3), span_ref, target_cells, cell_size, eps_expand

    mesh%use_collision_grid = .false.
    mesh%grid_bb_min = minval(mesh%bb_min, dim=2)
    mesh%grid_bb_max = maxval(mesh%bb_max, dim=2)
    mesh%grid_ncell = 1_i32
    mesh%grid_inv_cell = 1.0d0

    if (allocated(mesh%grid_cell_start)) deallocate (mesh%grid_cell_start)
    if (allocated(mesh%grid_cell_elem)) deallocate (mesh%grid_cell_elem)

    if (mesh%nelem < min_nelem_for_grid) then
      allocate (mesh%grid_cell_start(2), mesh%grid_cell_elem(0))
      mesh%grid_cell_start = [1_i32, 1_i32]
      return
    end if

    span = mesh%grid_bb_max - mesh%grid_bb_min
    span_ref = max(maxval(abs(span)), 1.0d0)
    eps_expand = max(abs_span_eps, rel_span_eps*span_ref)
    do iaxis = 1, 3
      if (span(iaxis) <= abs_span_eps) then
        mesh%grid_bb_min(iaxis) = mesh%grid_bb_min(iaxis) - 0.5d0*eps_expand
        mesh%grid_bb_max(iaxis) = mesh%grid_bb_max(iaxis) + 0.5d0*eps_expand
      end if
    end do
    span = mesh%grid_bb_max - mesh%grid_bb_min

    target_cells = max(1.0d0, real(mesh%nelem, dp)/real(target_elems_per_cell, dp))
    cell_size = (span(1)*span(2)*span(3)/target_cells)**(1.0d0/3.0d0)
    if (cell_size <= 0.0d0) cell_size = span_ref

    do iaxis = 1, 3
      mesh%grid_ncell(iaxis) = int(span(iaxis)/cell_size, kind=i32)
      if (mesh%grid_ncell(iaxis) < 1_i32) mesh%grid_ncell(iaxis) = 1_i32
      if (mesh%grid_ncell(iaxis) > max_cells_axis) mesh%grid_ncell(iaxis) = max_cells_axis
      mesh%grid_inv_cell(iaxis) = real(mesh%grid_ncell(iaxis), dp)/span(iaxis)
    end do

    nx = mesh%grid_ncell(1)
    ny = mesh%grid_ncell(2)
    nz = mesh%grid_ncell(3)
    ncells = nx*ny*nz

    allocate (counts(ncells))
    counts = 0_i32
    do i = 1, mesh%nelem
      ix0 = coord_to_cell(mesh, mesh%bb_min(1, i), 1_i32)
      ix1 = coord_to_cell(mesh, mesh%bb_max(1, i), 1_i32)
      iy0 = coord_to_cell(mesh, mesh%bb_min(2, i), 2_i32)
      iy1 = coord_to_cell(mesh, mesh%bb_max(2, i), 2_i32)
      iz0 = coord_to_cell(mesh, mesh%bb_min(3, i), 3_i32)
      iz1 = coord_to_cell(mesh, mesh%bb_max(3, i), 3_i32)
      do iz = iz0, iz1
        do iy = iy0, iy1
          do ix = ix0, ix1
            cid = cell_id(ix, iy, iz, nx, ny)
            counts(cid) = counts(cid) + 1_i32
          end do
        end do
      end do
    end do

    allocate (mesh%grid_cell_start(ncells + 1))
    mesh%grid_cell_start(1) = 1_i32
    do cid = 1, ncells
      mesh%grid_cell_start(cid + 1) = mesh%grid_cell_start(cid) + counts(cid)
    end do

    total_refs = mesh%grid_cell_start(ncells + 1) - 1_i32
    if (total_refs < 0_i32) then
      error stop "collision grid CSR construction failed"
    end if
    allocate (mesh%grid_cell_elem(total_refs))

    if (total_refs > 0_i32) then
      allocate (offsets(ncells))
      offsets = mesh%grid_cell_start(1:ncells)
      do i = 1, mesh%nelem
        ix0 = coord_to_cell(mesh, mesh%bb_min(1, i), 1_i32)
        ix1 = coord_to_cell(mesh, mesh%bb_max(1, i), 1_i32)
        iy0 = coord_to_cell(mesh, mesh%bb_min(2, i), 2_i32)
        iy1 = coord_to_cell(mesh, mesh%bb_max(2, i), 2_i32)
        iz0 = coord_to_cell(mesh, mesh%bb_min(3, i), 3_i32)
        iz1 = coord_to_cell(mesh, mesh%bb_max(3, i), 3_i32)
        do iz = iz0, iz1
          do iy = iy0, iy1
            do ix = ix0, ix1
              cid = cell_id(ix, iy, iz, nx, ny)
              pos = offsets(cid)
              mesh%grid_cell_elem(pos) = i
              offsets(cid) = pos + 1_i32
            end do
          end do
        end do
      end do
      deallocate (offsets)
    end if

    deallocate (counts)
    mesh%use_collision_grid = .true.
  end subroutine build_collision_grid