using PlotlyJS
import StaticArrays:SVector, @SVector
The WebIO Jupyter extension was not detected. See the WebIO Jupyter integration documentation for more information.
function distsq(A::SVector{2, T}, B::SVector{2, T}) where T <: Real
return (A[1]-B[1])^2 + (A[2]-B[2])^2
end
function grid_idxs(point:: SVector{2, T}, cellsize::T) where T <: Real
""" Returns cell indices, (i,j)=(row, col) for `point` """
return ceil(Int, point[2] / cellsize) + 1, ceil(Int, point[1] / cellsize) + 1
end
function ispoint_inrectangle(point::SVector{2, T}, rlims::Tuple{T, T}) where T <: Real
"""
Check whether a point is within the rectangle
[0, rlims[1]] x [0, rlims[2]];
here rlims =(width, height)
"""
return (0 <= point[1] <= rlims[1]) && (0 <= point[2] <= rlims[2])
end
function unif_sampling_annulus(center::SVector{2, T}, inner_rad::T, outer_rad::T;
k=30) where T <: Real
"""
Samples uniformly k points from the annulus of center, `center`,
and radii, inner_radius, outer_radius
"""
rad = sqrt.(inner_rad^2 .+ (outer_rad^2 - inner_rad^2)*rand(k))
angle = 2π * rand(k)
x, y = center[1] .+ rad .* cos.(angle), center[2] .+ rad .*sin.(angle)
return [@SVector([xi, yi]) for (xi, yi) in zip(x,y)]
end
unif_sampling_annulus (generic function with 1 method)
function Poisson_disk_sampling(;width =1.0, height=1.0, radius=0.05, k=30)
"""
Bridson Algorithm to generate Poisson disk samples
within a 2D rectangle, [0, width] x [0, height]
Ref: R Bridson, Fast Poisson disk sampling in arbitrary dimensions,
in SIGGRAPH '07: ACM SIGGRAPH 2007 sketches
https://www.cs.ubc.ca/~rbridson/docs/bridson-siggraph07-poissondisk.pdf
"""
function is_accepted(point:: SVector{2, T}) where T <: Real
"""
Check whether the point, `point` can be added to the active_list
"""
i, j = grid_idxs(point, cellsize)
m, n = maximum([i-2, 1]), maximum([j-2, 1])
p, q = minimum([i+2, grows]), minimum([j+2, gcols])
for k in n:q
for l in m:p
gpoint = grid[(k-1) * grows + l]
if ismissing(gpoint)
continue
end
if distsq(point, gpoint) <= r2
return false
end
end
end
return true
end
cellsize = radius/sqrt(2)
gcols = ceil(Int, width / cellsize) + 1
grows = ceil(Int, height / cellsize) + 1
grid = Vector{Any}(missing, grows*gcols)
r2 = radius*radius
active_list = SVector{2, Float64}[]
#generate a random point within the rectangle of interest
# and insert it into the active_list and grid
point = @SVector([width*rand(1)[1], height*rand(1)[1]])
push!(active_list, point)
i, j = grid_idxs(point, cellsize)
grid[(j-1)*grows+i] = point
while length(active_list) > 0
i = rand(1:length(active_list), 1)[1]
pt = active_list[i]
active_list = active_list[1:end .!= i] #removes the point in pos i
rpoints = unif_sampling_annulus(pt, radius, 2*radius; k=k)
for rp in rpoints
if !ispoint_inrectangle(rp, (width, height)) || !is_accepted(rp)
continue
end
push!(active_list, rp)
i, j = grid_idxs(rp, cellsize)
grid[(j-1)*grows+i] = rp
end
end
return filter(x->!ismissing(x), grid)
end
Poisson_disk_sampling (generic function with 1 method)
vector_of_samples = Poisson_disk_sampling(;width =5.0, height=3.0, radius=0.045, k=30)
xcoords = [p[1] for p in vector_of_samples]
ycoords = [p[2] for p in vector_of_samples]
fig1 = Plot(scatter(x=xcoords, y=ycoords, mode="markers", marker_size=3),
Layout(width=600, height=400,
xaxis_showgrid=false, yaxis_showgrid=false))
display(fig1)
vector_of_samples = Poisson_disk_sampling(;width=4.0, height=4.0, radius=0.05, k=30)
#perform a translation of the default rectangle [0, width] x [0, height] to [3, 3+]x [-2, -2+height]
xcoords = [p[1] for p in vector_of_samples] .+ 3.0
ycoords = [p[2] for p in vector_of_samples] .- 2.0
fig2 = Plot(scatter(x=xcoords, y=ycoords, mode="markers", marker_size=3),
Layout(width=500, height=500,
xaxis_showgrid=false, yaxis_showgrid=false,
xaxis_zeroline=false, yaxis_zeroline=false ))
display(fig2)