use crate::algorithm::{Algorithm, Creator};
use crate::utils::*;
use crate::{Builder, Float, Vector};
use rand::distributions::{Distribution, Standard, Uniform};
use rand::Rng;
use sphere::sphere_volume;
#[derive(Debug, Clone, Copy)]
pub struct Ebeida;
impl<F, V> Creator<F, V> for Ebeida
where
F: Float,
V: Vector<F>,
Standard: Distribution<F>,
Standard: Distribution<V>,
{
type Algo = Algo<F, V>;
fn create(poisson: &Builder<F, V>) -> Self::Algo {
let dim = V::dimension();
let grid = Grid::new(poisson.radius, poisson.poisson_type);
let mut indices = Vec::with_capacity(grid.cells() * dim);
let choices = (0..grid.side()).collect::<Vec<_>>();
indices.extend(each_combination(&choices));
let a = match dim {
2 => 0.3,
3 => 0.3,
4 => 0.6,
5 => 10.,
6 => 700.,
_ => 700. + 100. * dim as f64,
};
Algo {
a: a,
grid: grid,
throws: (a * indices.len() as f64).ceil() as usize,
range: Uniform::new(0, indices.len()),
indices: indices,
level: 0,
success: 0,
outside: vec![],
mantissa_digits: {
let (mantissa, _, _) = F::max_value().integer_decode();
mantissa.count_ones() as usize
},
}
}
}
pub struct Algo<F, V>
where
F: Float,
V: Vector<F>,
{
grid: Grid<F, V>,
indices: Vec<V>,
level: usize,
range: Uniform<usize>,
throws: usize,
success: usize,
outside: Vec<V>,
mantissa_digits: usize,
a: f64,
}
impl<F, V> Algorithm<F, V> for Algo<F, V>
where
F: Float,
V: Vector<F>,
Standard: Distribution<F>,
Standard: Distribution<V>,
{
fn next<R>(&mut self, poisson: &mut Builder<F, V>, rng: &mut R) -> Option<V>
where
R: Rng,
{
if self.indices.is_empty() {
return None;
}
while self.level < self.mantissa_digits {
while self.throws > 0 {
self.throws -= 1;
let index = rng.sample(self.range);
let cur = self.indices[index].clone();
let parent = get_parent(cur.clone(), self.level);
if !self
.grid
.get(parent.clone())
.expect("Indexing base grid by valid parent failed.")
.is_empty()
{
self.indices.swap_remove(index);
if self.indices.is_empty() {
return None;
}
self.range = Uniform::new(0, self.indices.len());
} else {
let sample = choose_random_sample(rng, &self.grid, cur.clone(), self.level);
if is_disk_free(
&self.grid,
poisson,
cur.clone(),
self.level,
sample.clone(),
&self.outside,
) {
self.grid
.get_mut(parent)
.expect("Indexing base grid by already indexed valid parent failed.")
.push(sample.clone());
self.indices.swap_remove(index);
if !self.indices.is_empty() {
self.range = Uniform::new(0, self.indices.len());
}
self.success += 1;
return Some(sample);
}
}
}
self.subdivide(&poisson);
if self.indices.is_empty() {
return None;
}
self.range = Uniform::new(0, self.indices.len());
self.throws = (self.a * self.indices.len() as f64).ceil() as usize;
self.level += 1;
}
let index = rng.sample(self.range);
let cur = self.indices.swap_remove(index);
let side = 2usize.pow(self.level as u32);
let sample = index_to_sample(&cur, side);
if is_disk_free(
&self.grid,
poisson,
cur.clone(),
self.level,
sample.clone(),
&self.outside,
) {
Some(sample)
} else {
None
}
}
fn size_hint(&self, poisson: &Builder<F, V>) -> (usize, Option<usize>) {
let dim = V::dimension();
let side = 2usize.pow(self.level as u32);
let spacing = self.grid.cell() / F::cast(side);
let grid_volume = F::cast(self.indices.len()) * spacing.powi(dim as i32);
let sphere_volume = sphere_volume(F::cast(2) * poisson.radius, dim as u64);
let lower = grid_volume / sphere_volume;
let mut lower = lower.floor().to_usize().expect(
"Grids volume divided by spheres volume should be always \
castable to usize.",
);
if lower > 0 {
lower -= 1;
}
let upper = self.grid.cells() - self.success;
(lower, Some(upper))
}
fn restrict(&mut self, sample: V) {
self.success += 1;
let index = sample_to_index(&sample, self.grid.side());
if let Some(g) = self.grid.get_mut(index) {
g.push(sample);
} else {
self.outside.push(sample);
}
}
fn stays_legal(&self, poisson: &Builder<F, V>, sample: V) -> bool {
let index = sample_to_index(&sample, self.grid.side());
is_disk_free(&self.grid, poisson, index, 0, sample.clone(), &self.outside)
}
}
impl<F, V> Algo<F, V>
where
F: Float,
V: Vector<F>,
{
fn subdivide(&mut self, poisson: &Builder<F, V>) {
let choices = &[0, 1];
let (grid, outside, level) = (&self.grid, &self.outside, self.level);
self.indices.flat_map_inplace(|i| {
each_combination(choices)
.map(move |n: V| n + i.clone() * F::cast(2))
.filter(|c| !covered(grid, poisson, outside, c.clone(), level + 1))
});
}
}
fn covered<F, V>(
grid: &Grid<F, V>,
poisson: &Builder<F, V>,
outside: &[V],
index: V,
level: usize,
) -> bool
where
F: Float,
V: Vector<F>,
{
let side = 2usize.pow(level as u32);
let spacing = grid.cell() / F::cast(side);
let sqradius = (F::cast(2) * poisson.radius).powi(2);
let parent = get_parent(index.clone(), level);
each_combination(&[0, 1])
.map(|t| (index.clone() + t) * spacing)
.all(|t| {
each_combination(&[-2, -1, 0, 1, 2])
.filter_map(|t| grid.get(parent.clone() + t))
.flat_map(|t| t)
.any(|v| sqdist(v.clone(), t.clone(), poisson.poisson_type) < sqradius)
|| !is_valid(poisson, &outside, t)
})
}