Skip to content
Snippets Groups Projects
adaptive_distance_fields.jl 2.46 KiB
Newer Older
  • Learn to ignore specific revisions
  • module AdaptivelySampledDistanceFields
    
        using StaticArrays
        using RegionTrees
        import RegionTrees: needs_refinement, refine_data
        using Interpolations
    
        @generated function evaluate(itp::AbstractInterpolation, point::SVector{N}) where N
            Expr(:call, :itp, [:(point[$i]) for i in 1:N]...)
        end
    
        function evaluate(itp::AbstractInterpolation, point::AbstractArray)
            itp(point...)
        end
    
        function evaluate(cell::Cell{D}, point::AbstractArray) where D <: AbstractInterpolation
            leaf = findleaf(cell, point)
            evaluate(leaf.data, leaf.boundary, point)
        end
    
        function evaluate(interp::AbstractInterpolation, boundary::HyperRectangle, point::AbstractArray)
            coords = (point .- boundary.origin) ./ boundary.widths .+ 1
            evaluate(interp, coords)
        end
    
        mutable struct SignedDistanceRefinery{F <: Function} <: AbstractRefinery
            signed_distance_func::F
            atol::Float64
            rtol::Float64
        end
    
        function needs_refinement(refinery::SignedDistanceRefinery, cell::Cell)
            minimum(cell.boundary.widths) > refinery.atol && needs_refinement(cell, refinery.signed_distance_func, refinery.atol, refinery.rtol)
        end
    
        function needs_refinement(cell::Cell, signed_distance_func, atol, rtol)
            for c in body_and_face_centers(cell.boundary)
                value_interp = evaluate(cell, c)
                value_true = signed_distance_func(c)
                if !isapprox(value_interp, value_true, rtol=rtol, atol=atol)
                    return true
                end
            end
            false
        end
    
        function refine_data(refinery::SignedDistanceRefinery, cell::Cell, indices)
            refine_data(refinery, child_boundary(cell, indices))
        end
    
        function refine_data(refinery::SignedDistanceRefinery, boundary::HyperRectangle)
            interpolate!(refinery.signed_distance_func.(vertices(boundary)),
                        BSpline(Linear()))
        end
    
        struct ASDF{C <: Cell} <: Function
            root::C
        end
    
        function ASDF(signed_distance::Function, origin::AbstractArray,
                    widths::AbstractArray,
                    rtol=1e-2,
                    atol=1e-2)
            refinery = SignedDistanceRefinery(signed_distance, atol, rtol)
            boundary = HyperRectangle(origin, widths)
            root = Cell(boundary, refine_data(refinery, boundary))
            adaptivesampling!(root, refinery)
            ASDF(root)
        end
    
        function (field::ASDF)(point::AbstractArray)
            evaluate(field.root, point)
        end
    
    
    end