Skip to content

Commit

Permalink
PIPE-165 Create Project.toml
Browse files Browse the repository at this point in the history
* Fixed Voxelization Testset Error's
* Fixed Rasterizer and Voxelization testset warnings
* Fixed Neighbouring voxel test set errors
* Fixed Neighbouring voxel test set
* Changed compatablity in Project.toml
* Gitignore added
* Updates Travis and appveyor files
* Appveyor fix
* Re added Test to Project.toml
  • Loading branch information
Mandeep committed Nov 19, 2019
1 parent aa170b1 commit e2238fb
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 84 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
*.jl.cov
*.jl.*.cov
*.jl.mem
Manifest.toml
3 changes: 1 addition & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ os:
- linux
- osx
julia:
- 0.5
- 0.6
- 1.0
- nightly
notifications:
email: false
Expand Down
11 changes: 11 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
name = "SpatialGrids"
uuid = "69000a82-ef16-11e9-2771-79cc17a85cb9"
authors = ["msb <mandeep.bahal@roames.com.au>"]
version = "0.1.0"

[deps]
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[compat]
julia = "0.7, 1.0, 1.1"
9 changes: 3 additions & 6 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
environment:
matrix:
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.6/julia-0.6-latest-win32.exe"
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.6/julia-0.6-latest-win64.exe"
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe"
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe"
- julia_verison: 1
- julia_version: nightly

matrix:
allow_failures:
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe"
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe"
- julia_version: nightly

branches:
only:
Expand Down
20 changes: 9 additions & 11 deletions src/raster.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
Rasterize points in 2D by a cell size `dx`.
Returns a dictionary containing the indices points that are in a cell.
"""
immutable Raster{T<:SVector,U<:Integer}
struct Raster{T<:SVector,U<:Integer}
pixels::Dict{Tuple{U,U}, Vector{U}}
r_min::T
r_max::T
Expand All @@ -13,7 +13,7 @@ end

# from: https://github.com/andyferris/HeightOrderedGrid.jl/blob/master/src/HeightOrderedGrid.jl
# as opposed to: SVector{N, Float64}(minimum(map(x->x[1], points)), minimum(map(x->x[2], points)), 0)
function bounds{T}(points::Vector{T})
function bounds(points::Vector{T}) where T
xmin = typemax(eltype(eltype(T)))
xmax = typemin(eltype(eltype(T)))
ymin = typemax(eltype(eltype(T)))
Expand All @@ -39,14 +39,11 @@ function bounds{T}(points::Vector{T})

return (xmin, xmax, ymin, ymax)
end


"""
`rasterize_points{T <: AbstractVector}(points::Vector{T}, dx::AbstractFloat) -> Raster`
Returns a `Raster` of `points` with quadratic cellsize `dx`.
"""
function rasterize_points{T <: AbstractVector}(points::Vector{T}, dx::AbstractFloat)
function rasterize_points(points::Vector{T}, dx::Float64) where T <: AbstractVector
(xmin, xmax, ymin, ymax) = bounds(points)

if size(eltype(points))[1] == 2
Expand All @@ -61,6 +58,7 @@ function rasterize_points{T <: AbstractVector}(points::Vector{T}, dx::AbstractFl

pixels = Dict{Tuple{UInt32, UInt32}, Vector{UInt32}}()
inv_dx = 1.0/dx

for i = 1:length(points)
@inbounds p = points[i] - min_xy
key = (floor(UInt32, p[1]*inv_dx), floor(UInt32, p[2]*inv_dx))
Expand All @@ -74,19 +72,19 @@ function rasterize_points{T <: AbstractVector}(points::Vector{T}, dx::AbstractFl
return Raster(pixels,min_xy,max_xy,dx)
end

function rasterize_points{T <: Number}(points::Matrix{T}, dx::AbstractFloat)
@assert isbits(T)
function rasterize_points(points::Matrix{T}, dx::AbstractFloat) where T <: Number
@assert isbitstype(T)
ndim = size(points, 1)
npoints = size(points, 2)
new_data = reinterpret(SVector{ndim, T}, points, (npoints,))
rasterize_points(new_data, dx)
new_data = reshape(reinterpret(SVector{ndim, T}, vec(points)), (npoints,))
rasterize_points(new_data[1:end], dx)
end

Base.keys(r::Raster) = keys(r.pixels)
Base.values(r::Raster) = values(r.pixels)
Base.getindex(r::Raster, ind) = r.pixels[ind]

function Base.show{T,U}(io::IO, raster::Raster{T,U})
function Base.show(io::IO, raster::Raster{T, U}) where {T, U}
println(io, typeof(raster))
println(io, " Number of pixels: ", length(raster.pixels))
print(io, " Cellsize: ", raster.cellsize)
Expand Down
145 changes: 86 additions & 59 deletions src/sparse_voxels.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,19 @@ for voxel in grid
end
```
"""
immutable SparseVoxelGrid{T <: Real}
struct SparseVoxelGrid{T <: Real}
voxel_size::SVector{3, T}
voxel_info::Dict{VoxelId, UnitRange{Int}}
point_indices::Vector{Int}
end

function SparseVoxelGrid{T1 <: AbstractVector, T2 <: Real}(points::Vector{T1}, voxel_size::SVector{3, T2})
function SparseVoxelGrid(points::Vector{T1}, voxel_size::SVector{3, T2}) where {T1 <: AbstractVector, T2 <: Real}
npoints = length(points)

# In order to avoid allocating a vector for each voxel, we construct the data structure in a backward-looking order.

# Assign each point to a voxel id
voxel_ids = Vector{VoxelId}(npoints)
voxel_ids = Vector{VoxelId}(undef,npoints)
for j = 1:npoints
@inbounds voxel_ids[j] = make_voxel_id(points[j], voxel_size)
end
Expand All @@ -66,35 +66,35 @@ function SparseVoxelGrid{T1 <: AbstractVector, T2 <: Real}(points::Vector{T1}, v
end

# Place indices for points into the appropriate index range for the associated voxel
point_indices = Vector{Int}(npoints)
point_indices = Vector{Int}(undef,npoints)
for j = 1:npoints
id = voxel_ids[j]
index_in_group = group_counts[id]
group_counts[id] = index_in_group - 1
point_indices[first(voxel_info[id]) + index_in_group-1] = j
end

return SparseVoxelGrid(voxel_size, voxel_info, point_indices)
end

function SparseVoxelGrid{T1 <: Real}(points::Matrix{T1}, voxel_size)
function SparseVoxelGrid(points::Matrix{T1}, voxel_size) where T1 <: Real
ndims, npoints = size(points)
@assert ndims == 3
new_data = reinterpret(SVector{3, T1}, points, (length(points) ÷ 3, ))
SparseVoxelGrid(new_data, get_voxel_size(voxel_size))
new_data = reshape(reinterpret(SVector{3,T1}, vec(points)),(length(points) ÷ 3, ))
SparseVoxelGrid(new_data[1:end], get_voxel_size(voxel_size))
end

function SparseVoxelGrid{T1 <: AbstractVector}(points::Vector{T1}, voxel_size)
function SparseVoxelGrid(points::Vector{T1}, voxel_size) where T1 <: AbstractVector
SparseVoxelGrid(points, get_voxel_size(voxel_size))
end

get_voxel_size{T <: Real}(voxel_size::NTuple{3, T}) = SVector{3, T}(voxel_size)
get_voxel_size{T <: Real}(voxel_size::T) = SVector{3, T}(voxel_size, voxel_size, voxel_size)
get_voxel_size{T <: Real}(voxel_size::SVector{3, T}) = voxel_size
get_voxel_size(voxel_size::NTuple{3, T}) where T <: Real = SVector{3, T}(voxel_size)
get_voxel_size(voxel_size::T) where T <: Real = SVector{3, T}(voxel_size, voxel_size, voxel_size)
get_voxel_size(voxel_size::SVector{3, T}) where T <: Real = voxel_size

Base.length(grid::SparseVoxelGrid) = length(grid.voxel_info)
Base.isempty(grid::SparseVoxelGrid) = isempty(grid.voxel_info)
Base.haskey(grid::SparseVoxelGrid, k) = haskey(grid.voxel_info, k)

function Base.show(io::IO, grid::SparseVoxelGrid)
println(io, typeof(grid))
println(io, " Number of voxels: ", length(grid))
Expand All @@ -104,51 +104,58 @@ end

"""
make_voxel_id(point::AbstractVector, voxel_size::SVector{3,AbstractFloat})
=(v.voxel_info)
Create the voxel id for a given point and voxel size.
"""
@inline function make_voxel_id{T <: Real}(point::AbstractVector, voxel_size::SVector{3, T})
@inline function make_voxel_id(point::AbstractVector, voxel_size::SVector{3, T}) where T <: Real
(floor(Int, point[1] / voxel_size[1]), floor(Int, point[2] / voxel_size[2]),
floor(Int, point[3] / voxel_size[3]))
end

"An iterator type to return point indices in a voxel. See SparseVoxelGrid() for usage."
immutable Voxel
struct Voxel
id::VoxelId
point_index_range::UnitRange{Int}
all_point_indices::Vector{Int}
end

Base.start(grid::SparseVoxelGrid) = start(grid.voxel_info)
function Base.next(v::SparseVoxelGrid, state)
n = next(v.voxel_info, state)
id = n[1][1]
point_index_range = n[1][2]
Voxel(id, point_index_range, v.point_indices), n[2]
function Base.iterate(v::SparseVoxelGrid, state=(v.voxel_info, 1))
state = iterate(v.voxel_info, state[2])
state == nothing && return nothing
id = state[1][1]
point_index_range = state[1][2]
return Voxel(id, point_index_range, v.point_indices), state
end
Base.done(grid::SparseVoxelGrid, state) = done(grid.voxel_info, state)

Base.eltype(::SparseVoxelGrid) = Voxel


function Base.getindex(grid::SparseVoxelGrid, id::VoxelId)
Voxel(id, grid.voxel_info[id], grid.point_indices)
end

Base.start(v::Voxel) = 1
function Base.next(v::Voxel, state)
v.all_point_indices[v.point_index_range[state]], state + 1

function Base.iterate(v::Voxel, state=(v,1))
if state > length(v.point_index_range)
return nothing
end
return v.all_point_indices[v.point_index_range[state[2]]], state[2] + 1
end
Base.done(v::Voxel, state) = state > length(v.point_index_range)


Base.eltype(::Voxel) = Int
Base.length(v::Voxel) = length(v.point_index_range)

function Base.show(io::IO, v::Voxel)
print(io, typeof(v), " ", v.id, " with ", length(v.point_index_range), " points")
end

"Voxel iterator that returns the `Voxel`s. See `in_cuboid()` for usage."
immutable VoxelCuboid
struct VoxelCuboid
grid::SparseVoxelGrid
voxel_id::VoxelId
range::CartesianRange{CartesianIndex{3}}
range::CartesianIndices{3,Tuple{UnitRange{Int64},UnitRange{Int64},UnitRange{Int64}}}

end

# TODO the `do` syntax for in_cuboid is faster than the iterator - can the iterator be improved?
Expand Down Expand Up @@ -185,9 +192,10 @@ end
in_cuboid(grid::SparseVoxelGrid, voxel::Voxel, radius::Int) = in_cuboid(grid, voxel.id, radius)

function in_cuboid(grid::SparseVoxelGrid, voxel::VoxelId, radius::Int)
start = CartesianIndex((-radius+voxel[1], -radius+voxel[2], -radius+voxel[3]))
stop = CartesianIndex((radius+voxel[1], radius+voxel[2], radius+voxel[3]))
VoxelCuboid(grid, voxel, CartesianRange(start, stop))
index_start = (-radius+voxel[1], -radius+voxel[2], -radius+voxel[3])
index_stop = (radius+voxel[1], radius+voxel[2], radius+voxel[3])
indices = CartesianIndices((index_start[1]:index_stop[1], index_start[2]:index_stop[2], index_start[3]:index_stop[3]))
VoxelCuboid(grid, voxel, indices)
end

in_cuboid(f::Function, grid::SparseVoxelGrid, voxel::Voxel, radius::Int) = in_cuboid(f, grid, voxel.id, radius)
Expand All @@ -205,46 +213,65 @@ function Base.getindex(c::VoxelCuboid, id::CartesianIndex{3})
Voxel(id.I, c.grid.voxel_info[id.I], c.grid.point_indices)
end

function Base.start(c::VoxelCuboid)
state = start(c.range)
if !haskey(c.grid, state.I) # first voxel id is not in grid
# find the next voxel in grid
while !done(c.range, state)
id, state = next(c.range, state)
if haskey(c.grid, id.I) && c.voxel_id != id.I
# return the voxel id
return id, 1
end
end
# no voxel id was found set value to quit iterations
return state, 0
end
# return the starting voxel
return state, 1
end
function Base.next(c::VoxelCuboid, state::Tuple{CartesianIndex{3}, Int})
next_state = state[1]
voxel = c[next_state]
# find the next voxel
while !done(c.range, next_state)
id, next_state = next(c.range, next_state)
if haskey(c.grid.voxel_info, next_state.I) && c.voxel_id != next_state.I

#find the next viable Voxel
function next_voxel(c::VoxelCuboid, state::Tuple{CartesianIndex{3}, Int})
next_state = state
next_state[1] == nothing && return nothing , 0
voxel = c[next_state[1]]
while next_state != nothing
next_state = iterate(c.range, next_state[1])
next_state == nothing && return voxel, (next_state, 0)
id = next_state[1]

if haskey(c.grid.voxel_info, next_state[1].I) && c.voxel_id != next_state[1].I
# return current voxel and the state for the next voxel
return voxel, (next_state, 1)
return voxel, (next_state[1], 1)
end
end
# Next voxel does not exist exists
return voxel, (next_state, 0)
end
Base.done(c::VoxelCuboid, state) = state[2] == 0 || state[1][3] > c.range.stop[3]

function Base.iterate(c::VoxelCuboid, state=(c.range[1], 1))

if state[1] == c.range[1]
if !haskey(c.grid, state[1].I) # first voxel id is not in grids
# find the next voxel in grid
while state != nothing
state = iterate(c.range, state[1])
state == nothing && return nothing
id = state[1]
if haskey(c.grid, id.I) && c.voxel_id != id.I
state = id, 1
@show state
return next_voxel(c, state)
end
end
# no voxel id was found set value to quit iterations
return nothing
end
# return the starting voxel
return next_voxel(c, state)

else
state[1] == nothing && return nothing
return next_voxel(c, state)
end

end

Base.eltype(::VoxelCuboid) = Voxel

if VERSION >= v"0.5.0-dev+3305"
# See https://github.com/JuliaLang/julia/issues/15977
# Possibly could implement length() instead, but it's nontrivial work to compute.
Base.iteratorsize(::Type{VoxelCuboid}) = Base.SizeUnknown()
Base.IteratorSize(::Type{VoxelCuboid}) = Base.SizeUnknown()
end

function Base.show(io::IO, c::VoxelCuboid)
print(io, typeof(c), " ID iteration range: ", c.range.start.I, " -> ", c.range.stop.I)
len = length(c.range)
print(io, typeof(c), " ID iteration range: ", c.range[1].I, " -> ", c.range[len].I)
end

"""
Expand Down
2 changes: 1 addition & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using SpatialGrids
using StaticArrays
using Base.Test
using Test

include("spatial_grid_test.jl")
Loading

0 comments on commit e2238fb

Please sign in to comment.