use glam::Vec3;
#[inline(always)]
pub fn modifier_polar_repeat(p: Vec3, count: u32) -> Vec3 {
let count_f = count as f32;
let angle = std::f32::consts::TAU / count_f;
let a = angle.mul_add(0.5, p.z.atan2(p.x));
let r = p.x.hypot(p.z);
let a_mod = angle.mul_add(-0.5, 100.0f32.mul_add(angle, a) % angle);
Vec3::new(r * a_mod.cos(), p.y, r * a_mod.sin())
}
#[inline(always)]
pub fn modifier_polar_repeat_rk(p: Vec3, sector: f32, recip_sector: f32) -> Vec3 {
let a = p.z.atan2(p.x);
let r = p.x.hypot(p.z);
let sector_angle = sector.mul_add(-(a * recip_sector).round(), a);
let (s, c) = sector_angle.sin_cos();
Vec3::new(r * c, p.y, r * s)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_polar_repeat_on_axis() {
let p = Vec3::new(0.0, 5.0, 0.0);
let q = modifier_polar_repeat(p, 6);
assert!(q.x.abs() < 0.001, "x should be ~0: {}", q.x);
assert!((q.y - 5.0).abs() < 0.001);
}
#[test]
fn test_polar_repeat_preserves_radius() {
let p = Vec3::new(3.0, 0.0, 4.0);
let q = modifier_polar_repeat(p, 8);
let r_original = p.x.hypot(p.z);
let r_result = q.x.hypot(q.z);
assert!((r_original - r_result).abs() < 0.001);
}
#[test]
fn test_polar_repeat_preserves_y() {
let p = Vec3::new(1.0, 7.0, 2.0);
let q = modifier_polar_repeat(p, 4);
assert!((q.y - 7.0).abs() < 0.001);
}
#[test]
fn test_polar_repeat_symmetry() {
let r = 5.0;
let count = 6u32;
let angle = std::f32::consts::TAU / count as f32;
let p1 = Vec3::new(r * 0.0_f32.cos(), 0.0, r * 0.0_f32.sin());
let p2 = Vec3::new(r * angle.cos(), 0.0, r * angle.sin());
let q1 = modifier_polar_repeat(p1, count);
let q2 = modifier_polar_repeat(p2, count);
assert!(
(q1 - q2).length() < 0.01,
"Symmetric points should map to same result: {:?} vs {:?}",
q1,
q2
);
}
}