use itertools::Itertools;
use rand::{Rng, RngCore};
pub trait SamplingStrategy: Send + Sync {
fn get_sample_positions(
&self,
rng: &mut Box<dyn RngCore>,
x: usize,
y: usize,
) -> Vec<(f64, f64)>;
}
pub struct SingleSampling<const W: usize, const H: usize>;
pub struct SubdivisionSampling<const W: usize, const H: usize, const NUM_SUBDIVS: usize>;
pub struct RandomSampling<const W: usize, const H: usize, const NUM_SAMPLES: usize> {}
impl<const W: usize, const H: usize> SingleSampling<W, H> {
pub const fn new() -> Self {
SingleSampling {}
}
}
impl<const W: usize, const H: usize> SamplingStrategy for SingleSampling<W, H> {
fn get_sample_positions(
&self,
rng: &mut Box<dyn RngCore>,
x: usize,
y: usize,
) -> Vec<(f64, f64)> {
vec![(x as f64 / W as f64, y as f64 / H as f64)]
}
}
impl<const W: usize, const H: usize, const NUM_SUBDIVS: usize>
SubdivisionSampling<W, H, NUM_SUBDIVS>
{
pub const fn new() -> Self {
SubdivisionSampling {}
}
}
impl<const W: usize, const H: usize, const NUM_SUBDIVS: usize> SamplingStrategy
for SubdivisionSampling<W, H, NUM_SUBDIVS>
{
fn get_sample_positions(
&self,
rng: &mut Box<dyn RngCore>,
x: usize,
y: usize,
) -> Vec<(f64, f64)> {
(0..NUM_SUBDIVS)
.cartesian_product(0..NUM_SUBDIVS)
.map(|(x_adj, y_adj)| {
(
(x_adj as f64 + 0.5) / NUM_SUBDIVS as f64,
(y_adj as f64 + 0.5) / NUM_SUBDIVS as f64,
)
})
.map(|(x_adj, y_adj)| ((x_adj + x as f64) / W as f64, (y_adj + y as f64) / H as f64))
.collect()
}
}
impl<const W: usize, const H: usize, const NUM_SAMPLES: usize> RandomSampling<W, H, NUM_SAMPLES> {
pub const fn new() -> Self {
RandomSampling {}
}
}
impl<const W: usize, const H: usize, const NUM_SAMPLES: usize> SamplingStrategy
for RandomSampling<W, H, NUM_SAMPLES>
{
fn get_sample_positions(
&self,
rng: &mut Box<dyn RngCore>,
x: usize,
y: usize,
) -> Vec<(f64, f64)> {
(0..NUM_SAMPLES)
.map(|_| {
let x_adj: f64 = rng.gen_range(0.0..1.0);
let y_adj: f64 = rng.gen_range(0.0..1.0);
let x = x as f64 + x_adj;
let y = y as f64 + y_adj;
(x / W as f64, y / H as f64)
})
.collect()
}
}