use glam::Vec3;
const PHI: f32 = 1.618_034;
#[inline(always)]
pub fn icosahedral_fold(p: Vec3) -> Vec3 {
let mut p = p.abs();
let n0 = Vec3::new(0.0, 1.0, PHI).normalize();
let n1 = Vec3::new(1.0, PHI, 0.0).normalize();
let n2 = Vec3::new(PHI, 0.0, 1.0).normalize();
for _ in 0..8 {
if p.y > p.x {
p = Vec3::new(p.y, p.x, p.z);
}
if p.z > p.y {
p = Vec3::new(p.x, p.z, p.y);
}
if p.y > p.x {
p = Vec3::new(p.y, p.x, p.z);
}
let d0 = p.dot(n0);
if d0 < 0.0 {
p -= n0 * (2.0 * d0);
}
let d1 = p.dot(n1);
if d1 < 0.0 {
p -= n1 * (2.0 * d1);
}
let d2 = p.dot(n2);
if d2 < 0.0 {
p -= n2 * (2.0 * d2);
}
}
p
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_icosahedral_symmetry() {
let p = Vec3::new(1.0, 2.0, 3.0);
let q = icosahedral_fold(p);
assert!(q.x >= -1e-6 && q.y >= -1e-6 && q.z >= -1e-6);
}
#[test]
fn test_icosahedral_origin() {
let p = Vec3::ZERO;
let q = icosahedral_fold(p);
assert!(q.length() < 1e-6);
}
}