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 map
ped 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)
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
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?
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