Poisson disc for periodic situation

This commit is contained in:
Martin Diehl 2020-09-24 21:26:16 +02:00
parent ec23ab8b61
commit e5b414419a
2 changed files with 17 additions and 12 deletions

View File

@ -31,10 +31,10 @@ def from_random(size,N_seeds,grid=None,seed=None):
coords = grid_coords[rng.choice(_np.prod(grid),N_seeds, replace=False)] \ coords = grid_coords[rng.choice(_np.prod(grid),N_seeds, replace=False)] \
+ _np.broadcast_to(size/grid,(N_seeds,3))*(rng.random((N_seeds,3))*.5-.25) # wobble without leaving grid + _np.broadcast_to(size/grid,(N_seeds,3))*(rng.random((N_seeds,3))*.5-.25) # wobble without leaving grid
coords return coords
def from_Poisson_disc(size,N_seeds,N_candidates,distance,seed=None): def from_Poisson_disc(size,N_seeds,N_candidates,distance,periodic=True,seed=None):
""" """
Seeding in space according to a Poisson disc distribution. Seeding in space according to a Poisson disc distribution.
@ -48,6 +48,8 @@ def from_Poisson_disc(size,N_seeds,N_candidates,distance,seed=None):
Number of candidates to consider for finding best candidate. Number of candidates to consider for finding best candidate.
distance : float distance : float
Minimum acceptable distance to other seeds. Minimum acceptable distance to other seeds.
periodic : boolean, optional
Calculate minimum distance for periodically repeated grid.
seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional
A seed to initialize the BitGenerator. Defaults to None. A seed to initialize the BitGenerator. Defaults to None.
If None, then fresh, unpredictable entropy will be pulled from the OS. If None, then fresh, unpredictable entropy will be pulled from the OS.
@ -61,7 +63,8 @@ def from_Poisson_disc(size,N_seeds,N_candidates,distance,seed=None):
progress = util._ProgressBar(N_seeds+1,'',50) progress = util._ProgressBar(N_seeds+1,'',50)
while i < N_seeds: while i < N_seeds:
candidates = rng.random((N_candidates,3))*_np.broadcast_to(size,(N_candidates,3)) candidates = rng.random((N_candidates,3))*_np.broadcast_to(size,(N_candidates,3))
tree = _spatial.cKDTree(coords[:i]) tree = _spatial.cKDTree(coords[:i],boxsize=size) if periodic else \
_spatial.cKDTree(coords[:i])
distances, dev_null = tree.query(candidates) distances, dev_null = tree.query(candidates)
best = distances.argmax() best = distances.argmax()
if distances[best] > distance: # require minimum separation if distances[best] > distance: # require minimum separation

View File

@ -13,11 +13,13 @@ class TestSeeds:
coords = seeds.from_random(size,N_seeds,grid) coords = seeds.from_random(size,N_seeds,grid)
assert (0<=coords).all() and (coords<size).all() assert (0<=coords).all() and (coords<size).all()
def test_from_Poisson_disc(self): @pytest.mark.parametrize('periodic',[True,False])
def test_from_Poisson_disc(self,periodic):
N_seeds = np.random.randint(30,300) N_seeds = np.random.randint(30,300)
N_candidates = N_seeds//15 N_candidates = N_seeds//15
distance = np.random.random() distance = np.random.random()
size = np.ones(3)*distance*N_seeds size = np.ones(3)*distance*N_seeds
coords = seeds.from_Poisson_disc(size,N_seeds,N_candidates,distance) coords = seeds.from_Poisson_disc(size,N_seeds,N_candidates,distance,periodic=periodic)
min_dists, _ = cKDTree(coords).query(coords, 2) min_dists, _ = cKDTree(coords,boxsize=size).query(coords, 2) if periodic else \
cKDTree(coords).query(coords, 2)
assert (0<= coords).all() and (coords<size).all() and np.min(min_dists[:,1])>=distance assert (0<= coords).all() and (coords<size).all() and np.min(min_dists[:,1])>=distance