Regular grid

Hello there,
I’m implementing Siddon’s algorithm for the calculation of the radiological path through an array of voxels. I was wondering what would be the most Juliesque way to define a regular grid? As an array of StepRange, for example? There is probably a package around there that already defines such a structure.
Thanks for your advice!
Sébastien

Depends on what functionality you need from the grid.
The most bare-bones rectangular grid is Iterators.product(1:10, 1:100): it can be iterated or mapped over, but isn’t even an array.
More extensive grids can be created with the RectiGrids.jl package. They are arrays, and even more, KeyedArrays, providing convenient lookup methods. (disclaimer: I’m the package author)

3 Likes

one quick and dirty way is to do

ones(5)*transpose(range(-1, 5, length=4))

5×4 Matrix{Float64}:
 -1.0  1.0  3.0  5.0
 -1.0  1.0  3.0  5.0
 -1.0  1.0  3.0  5.0
 -1.0  1.0  3.0  5.0
 -1.0  1.0  3.0  5.0
range(-1, 5, length=4)*transpose(ones(5))

4×5 Matrix{Float64}:
 -1.0  -1.0  -1.0  -1.0  -1.0
  1.0   1.0   1.0   1.0   1.0
  3.0   3.0   3.0   3.0   3.0
  5.0   5.0   5.0   5.0   5.0

(@aplavin reply is definitely more Juliasque, as it does not allocate memory in advance and it can map over multiple dimensions and different type of collections, the above would be analogous to Matlab’s meshgrid)

Shorter:

julia> ones(5) * (-1:2:5)'
5×4 Matrix{Float64}:
 -1.0  1.0  3.0  5.0
 -1.0  1.0  3.0  5.0
 -1.0  1.0  3.0  5.0
 -1.0  1.0  3.0  5.0
 -1.0  1.0  3.0  5.0
3 Likes

To be more precise, I need a RegularGrid type, that knows about the number of cells in each direction, the step in each direction, etc. A kind of multidimensional range.

This is what I’ve come up with for the time being

struct RegularGrid{NDIMS,T}
    size::SVector{NDIMS,Int}
    step::SVector{NDIMS,T}
    center::SVector{NDIMS,T}
    bb_min::SVector{NDIMS, T}
    bb_max::SVector{NDIMS, T}
    function RegularGrid{NDIMS, T}(size, step, center) where {NDIMS, T}
        bb_min = center .- 0.5 * size .* step
        bb_max = center .+ 0.5 * size .* step
        new(size, step, center, bb_min, bb_max)
    end
end

Base.ndims(::RegularGrid{NDIMS,T}) where {NDIMS,T} = NDIMS
Base.eltype(::RegularGrid{NDIMS,T}) where {NDIMS,T} = T
Base.ndims(::Type{RegularGrid{NDIMS,T}}) where {NDIMS,T} = NDIMS
Base.eltype(::Type{RegularGrid{NDIMS,T}}) where {NDIMS,T} = T

Base.size(grid::RegularGrid{NDIMS,T}, dim) where {NDIMS,T} = grid.size[dim]
Base.step(grid::RegularGrid{NDIMS,T}, dim) where {NDIMS,T} = grid.step[dim]

This does the job, but I’d rather use a struct that has already been defined in another package.

Thanks, RectiGrids.jl looks promising. Does the grids thus defined know about the spacing of the cells?

https://juliageometry.github.io/Meshes.jl/dev/meshes.html#Overview

2 Likes

Thank you! This is definitely what I’m looking for.

Of course!

julia> using RectiGrids

julia> G = grid(x=1:10, y=20:10:100);

julia> axiskeys(G, :x)
1:10

julia> step(axiskeys(G, :y))
10

https://www.generic-mapping-tools.org/GMT.jl/dev/types/#Grid-type