Volume slider


using Observables

using AbstractPlotting

scene3d = Scene()
rs = LinRange.(0, (6, 4, 10), 150)
slider_t = slider(LinRange(0.1, 3, 100))
# This actually needs to be pretty fast... Lucky for us, we use Julia :)
function make_volume!(rs, val, result = zeros(Float32, length.(rs)), r = rand(Float32, size(result)) .* 0.1)
    @simd for idx in CartesianIndices(result)
        @inbounds begin
            x, y, z = getindex.(rs, Tuple(idx))
            result[idx] = cos(x/val) * sin(y + r[idx]) + sqrt(z*val)
        end
    end
    return result, r
end

vol_tmp, r_tmp = make_volume!(rs, 0.4);
volume = lift(Observables.async_latest(slider_t[end][:value])) do val
    v, r = make_volume!(rs, val, vol_tmp, r_tmp);
    return v
end

linesegments!(scene3d, FRect3D(minimum.(rs), maximum.(rs)))
planes = (:yz, :xz, :xy)
sliders = ntuple(3) do i
    idx_s = slider(1:size(volume[], i), start = size(volume[], i) รท 2)
    idx = idx_s[end][:value]
    plane = planes[i]
    indices = ntuple(3) do j
        planes[j] == plane ? 1 : (:)
    end
    ridx = Iterators.filter((1, 2, 3)) do j
        planes[j] != plane
    end
    heatm = heatmap!(
        scene3d, getindex.((rs,), ridx)..., volume[][indices...],
        interpolate = true, raw = true
    )[end]
    function transform_planes(idx, vol)
        transform!(heatm, (plane, rs[i][idx]))
        indices = ntuple(3) do j
            planes[j] == plane ? idx : (:)
        end
        if checkbounds(Bool, vol, indices...)
            heatm[3][] = view(vol, indices...)
        end
    end
    onany(transform_planes, idx, volume)
    transform_planes(idx[], volume[])
    idx_s
end
center!(scene3d)
scene = vbox(
    hbox(slider_t, sliders...),
    hbox(
        scene3d,
        contour(volume, alpha = 0.1, levels = 10)
    )
)
# Do not execute beyond this point!
RecordEvents(scene, "output")