bs-trace 0.3.0

Free RayTracing software
Documentation
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()
    }
}