Well this poisson disk noise turned out tougher than I expected
Mainly because of dealing with 1D to 3D and not knowing enough about the math parser. Had to redesign the algorithm itself… this version is the first attempt so needs optimised and probably still has bugs (there’s even debug code still in). But it’s cool you can watch it drawing it point by point!
gcd_poisson_disk : skip ${1=2},${2=30}
# [0] input image to draw samples on
dim={d>1?3:h>1?2:1} cw={0.999*$1/sqrt($dim)}
({[w,h,d,1]}) y. c # [1] image dimensions vector
{[ceil(I/$cw),-1]} # [2] "accelerator" grid/cells
r[1] 1,1,1,$dim,-1 # keep only used dimensions in [1]
1,1,1,$dim 1,1,1,1 # [3] samples list, [4] active list
{vector$dim(2*ceil(sqrt($dim))+1)} # [5] cell proximity kernel
f. "dot([x,y,z]-int([w/2,h/2,d/2]),[1,w#2,w#2*h#2])" y. c
nm[1] dims nm[2] grid nm[3] samples nm[4] active nm[5] prox
-v -
eval ${-math_lib}"
const N = "$dim";
const radius = $1;
const grid_cw = "$cw";
const max_sample_attempts = $2;
prox = I#5;
mag2(vec) = (dot(vec,vec));
dar_insert(#3,I#1,0); # dummy sample to simplify bounds checks
dar_insert(#3,u(I#1),1); # add initial sample to list
dar_insert(#4,1,0); # add its index to active list
I(#2,int(I[#3,1]/grid_cw)) = 1; # add its index to grid cell
tr=0;
whiledo (dar_size(#4)>0,
R = int(u(dar_size(#4)-1e-4)); # choose a random active list index
P = i[#4,R]; # get the index of that sample
T = I[#3,P]; # position vector of that sample
for (attempts=0, attempts < max_sample_attempts, ++attempts,
dowhile (S=4*(u(vectorN(1))-0.5); M=mag2(S), M <= 1 || M > 4);
X = T + radius * S; # potential sample from annulus around T
if (min(X)<0 || min(I[#1,0]-X)<0, continue()); # check within bounds
# check proximity of surrounding points
G = int(X/grid_cw); # grid cell position vector
GI = dot(G,[1,w#2,w#2*h#2]); # grid cell direct buffer index
for (K=0;rejected=0, K<size(prox), ++K,
V = i[#2,GI+prox[K]]; # sample index from grid to check
if (V>0 && mag2(I[#3,V]-X)<sqr(radius), rejected=1;break())
);
if (!rejected,
Q = dar_size(#3); # sample found, get new index
dar_insert(#3,X,Q); # insert into samples list
dar_insert(#4,Q,dar_size(#4)); # insert its index into active
I(#2,G) = Q; # insert its index into grid
I(#0,X)=1; # draw the point
break();
);
);
if (attempts == max_sample_attempts, dar_remove(#4,P));
++tr; if(tr%2==0,ext('w[0] 400,400,1'));
);
" -v +
using:
gmic 128,128,1,1 gcd_poisson_disk 4