use crate::{Vec2, Vec3, Float};
use rand::{
prelude::SliceRandom,
rngs::ThreadRng, Rng
};
type MyRng = ThreadRng;
fn _get_rng() -> MyRng {
rand::thread_rng()
}
pub fn rand_float() -> Float {
_get_rng().gen()
}
pub fn rand_vec_vec3(n: usize) -> Vec<Vec3> {
(0..n).map(|_| square_to_sphere(unit_square())).collect()
}
pub fn perm_n(n: usize) -> Vec<usize> {
let mut v: Vec<usize> = (0..n).collect();
v.shuffle(&mut _get_rng());
v
}
pub fn unit_square() -> Vec2 {
Vec2::new(rand_float(), rand_float())
}
pub fn square_to_disk(rand_sq: Vec2) -> Vec2 {
let offset = 2.0 * rand_sq - Vec2::ONE;
if offset.x == 0.0 && offset.y == 0.0 {
Vec2::ZERO
} else {
let (r, theta) = if offset.x.abs() > offset.y.abs() {
(
offset.x,
crate::PI * (offset.y / offset.x) / 4.0
)
} else {
(
offset.y,
crate::PI * (0.5 - (offset.x / offset.y) / 4.0)
)
};
r * Vec2::new(theta.cos(), theta.sin())
}
}
pub fn square_to_cos_hemisphere(rand_sq: Vec2) -> Vec3 {
let rand_disk = square_to_disk(rand_sq);
let z = (1.0 - rand_disk.x * rand_disk.x - rand_disk.y * rand_disk.y)
.max(0.0)
.sqrt();
rand_disk.extend(z)
}
pub fn square_to_sphere(rand_sq: Vec2) -> Vec3 {
let z = 1.0 - 2.0 * rand_sq.y;
let r = (1.0 - z * z).sqrt();
let phi = 2.0 * crate::PI * rand_sq.x;
Vec3::new(r * phi.cos(), r * phi.sin(), z)
}