shape_regions Subroutine

private subroutine shape_regions(self, r, rs, d)

The regions' frustums for body radius r, light radius rs and distance d (see the module documentation), written to their meshes.

Arguments

Type IntentOptional Attributes Name
type(ShadowCones), intent(inout) :: self
real(kind=wp), intent(in) :: r

scene units

real(kind=wp), intent(in) :: rs

scene units

real(kind=wp), intent(in) :: d

scene units


Calls

proc~~shape_regions~~CallsGraph proc~shape_regions shape_regions proc~write_region write_region proc~shape_regions->proc~write_region interface~vkf_mesh_vertices_changed vkf_mesh_vertices_changed proc~write_region->interface~vkf_mesh_vertices_changed interface~vkf_switch_set vkf_switch_set proc~write_region->interface~vkf_switch_set proc~check_status check_status proc~write_region->proc~check_status proc~mesh_arrays mesh_arrays proc~write_region->proc~mesh_arrays interface~vkf_mesh_array vkf_mesh_array proc~mesh_arrays->interface~vkf_mesh_array

Called by

proc~~shape_regions~~CalledByGraph proc~shape_regions shape_regions proc~place place proc~place->proc~shape_regions proc~shadow_late_update ShadowCones%shadow_late_update proc~shadow_late_update->proc~place

Source Code

    subroutine shape_regions(self, r, rs, d)
        type(ShadowCones), intent(inout) :: self
        real(wp), intent(in) :: r, rs, d                    !! scene units
        real(wp) :: sa, ca, ta, sb, cb, tb, apex, len
        integer :: k
        self%region%drawn = .false.
        self%drawn_length_ = 0.0_wp
        if (r > 0.0_wp .and. rs > 0.0_wp .and. d > r + rs) then
            sa = (rs - r) / d                               ! the umbra's half-angle (sine; < 0: widening)
            ca = sqrt(1.0_wp - sa**2)
            ta = sa / ca
            sb = (rs + r) / d                               ! the penumbra's
            cb = sqrt(1.0_wp - sb**2)
            tb = sb / cb
            apex = huge(1.0_wp)
            if (sa > 0.0_wp) apex = r / sa
            len = self%length_
            if (len <= 0.0_wp) then
                len = 100.0_wp * r
                if (sa > 0.0_wp) len = 2.0_wp * apex
            end if
            self%drawn_length_ = len
            ! the umbra: from the outer tangents' circle on the body to the apex (or len)
            associate (g => self%region(umbra))
                g%z0 = r * sa
                g%r0 = r * ca
                g%z1 = min(apex, len)
                g%r1 = max(0.0_wp, g%r0 - (g%z1 - g%z0) * ta)
                if (g%z1 >= apex) g%r1 = 0.0_wp
                g%drawn = g%z1 > g%z0
            end associate
            ! the antumbra: from the apex to len
            associate (g => self%region(antumbra))
                g%z0 = apex
                g%r0 = 0.0_wp
                g%z1 = len
                g%r1 = (len - apex) * ta
                g%drawn = sa > 0.0_wp .and. len > apex
            end associate
            ! the penumbra: from the inner tangents' circle (on the light's side) to len
            associate (g => self%region(penumbra))
                g%z0 = -r * sb
                g%r0 = r * cb
                g%z1 = len
                g%r1 = g%r0 + (len - g%z0) * tb
                g%drawn = len > g%z0
            end associate
        end if
        self%region(umbra)%drawn = self%region(umbra)%drawn .and. iand(self%regions_, SHADOW_UMBRA) /= 0
        self%region(penumbra)%drawn = self%region(penumbra)%drawn .and. iand(self%regions_, SHADOW_PENUMBRA) /= 0
        self%region(antumbra)%drawn = self%region(antumbra)%drawn .and. iand(self%regions_, SHADOW_ANTUMBRA) /= 0
        do k = 1, n_regions
            call write_region(self%region(k))
        end do
    end subroutine shape_regions