pub fn quantize(value: f32, step: f32) -> f32 {
assert!(step > 0.0, "step must be positive");
let factor = 1.0 / step;
(value * factor).round() / factor
}
pub fn clamp(value: f32, min: f32, max: f32) -> f32 {
value.max(min).min(max)
}
pub fn nearest(value: f32, points: &[f32]) -> f32 {
points
.iter()
.map(|&p| (p, (p - value).abs()))
.min_by(|a, b| a.1.partial_cmp(&b.1).unwrap())
.map(|(p, _)| p)
.unwrap_or(f32::INFINITY)
}
pub fn principal_angle(angle: f32) -> f32 {
((angle + 180.0) % 360.0) - 180.0
}
pub fn angle_to_axis(angle: f32) -> super::vector2::Axis {
let a = ((angle % 360.0) + 360.0) % 360.0;
let dist_horizontal = (a - 0.0)
.abs()
.min((a - 180.0).abs())
.min((a - 360.0).abs());
let dist_vertical = (a - 90.0).abs().min((a - 270.0).abs());
if dist_horizontal <= dist_vertical {
super::vector2::Axis::X
} else {
super::vector2::Axis::Y
}
}
pub fn is_uniform(arr: &[f32], tolerance: f32) -> bool {
if arr.len() <= 1 {
return true;
}
let first = arr[0];
if tolerance == 0.0 {
arr.iter().all(|&v| v == first)
} else {
arr.iter().all(|&v| (v - first).abs() <= tolerance)
}
}
pub fn mean(values: &[f32]) -> f32 {
assert!(!values.is_empty(), "cannot compute mean of empty slice");
let sum: f32 = values.iter().sum();
sum / values.len() as f32
}
pub fn combinations<T: Clone>(arr: &[T], k: usize) -> Vec<Vec<T>> {
if k == 0 {
return vec![vec![]];
}
if arr.is_empty() {
return vec![];
}
let (first, rest) = arr.split_first().unwrap();
let mut with_first: Vec<Vec<T>> = combinations(rest, k - 1)
.into_iter()
.map(|mut combo| {
combo.insert(0, first.clone());
combo
})
.collect();
let mut without_first = combinations(rest, k);
with_first.append(&mut without_first);
with_first
}
pub fn permutations<T: Clone>(arr: &[T], k: usize) -> Vec<Vec<T>> {
if k == 0 {
return vec![vec![]];
}
if arr.is_empty() {
return vec![];
}
let mut result = Vec::new();
for (idx, item) in arr.iter().enumerate() {
let mut rest = arr.to_vec();
rest.remove(idx);
for mut perm in permutations(&rest, k - 1) {
perm.insert(0, item.clone());
result.push(perm);
}
}
result
}
pub fn powerset<T: Clone>(arr: &[T], k: Option<usize>) -> Vec<Vec<T>> {
match k {
None => {
let mut result = vec![vec![]];
for size in 1..=arr.len() {
result.extend(combinations(arr, size));
}
result
}
Some(size) => {
if size > arr.len() {
vec![]
} else {
combinations(arr, size)
}
}
}
}