use super::inertial::Equatorial;
use rand::rngs::StdRng;
use rand::{Rng, SeedableRng};
use std::f64::consts::PI;
pub struct RandomEquatorial {
rng: StdRng,
}
impl RandomEquatorial {
pub fn with_seed(seed: u64) -> Self {
Self {
rng: StdRng::seed_from_u64(seed),
}
}
pub fn new() -> Self {
Self {
rng: StdRng::from_os_rng(),
}
}
}
impl Default for RandomEquatorial {
fn default() -> Self {
Self::new()
}
}
impl Iterator for RandomEquatorial {
type Item = Equatorial;
fn next(&mut self) -> Option<Self::Item> {
let ra = self.rng.random::<f64>() * 2.0 * PI;
let u: f64 = self.rng.random();
let dec = (2.0 * u - 1.0).asin();
Some(Equatorial::new(ra, dec))
}
}
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_relative_eq;
#[test]
fn test_deterministic_with_seed() {
let mut iter1 = RandomEquatorial::with_seed(42);
let mut iter2 = RandomEquatorial::with_seed(42);
for _ in 0..10 {
let coord1 = iter1.next().unwrap();
let coord2 = iter2.next().unwrap();
assert_relative_eq!(coord1.ra, coord2.ra, epsilon = 1e-10);
assert_relative_eq!(coord1.dec, coord2.dec, epsilon = 1e-10);
}
}
#[test]
fn test_different_seeds_produce_different_values() {
let mut iter1 = RandomEquatorial::with_seed(42);
let mut iter2 = RandomEquatorial::with_seed(123);
let coord1 = iter1.next().unwrap();
let coord2 = iter2.next().unwrap();
assert!(coord1.ra != coord2.ra || coord1.dec != coord2.dec);
}
#[test]
fn test_bounds() {
let mut iter = RandomEquatorial::with_seed(12345);
for _ in 0..1000 {
let coord = iter.next().unwrap();
assert!(coord.ra >= 0.0 && coord.ra < 2.0 * PI);
assert!(coord.dec >= -PI / 2.0 && coord.dec <= PI / 2.0);
}
}
#[test]
fn test_distribution_statistics() {
let mut iter = RandomEquatorial::with_seed(999);
let n = 10000;
let mut ra_sum = 0.0;
let mut dec_sin_sum = 0.0;
for _ in 0..n {
let coord = iter.next().unwrap();
ra_sum += coord.ra;
dec_sin_sum += coord.dec.sin();
}
let mean_ra = ra_sum / n as f64;
assert_relative_eq!(mean_ra, PI, epsilon = 0.1);
let mean_sin_dec = dec_sin_sum / n as f64;
assert_relative_eq!(mean_sin_dec, 0.0, epsilon = 0.05);
}
#[test]
fn test_iterator_is_infinite() {
let mut iter = RandomEquatorial::with_seed(777);
for _ in 0..10000 {
assert!(iter.next().is_some());
}
}
}