#[repr(C, align(64))]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct CkMultivector3D {
pub c: [f32; 16],
}
impl Default for CkMultivector3D {
#[inline(always)]
fn default() -> Self {
Self::zero()
}
}
impl CkMultivector3D {
#[inline(always)]
pub const fn zero() -> Self {
Self { c: [0.0f32; 16] }
}
#[inline(always)]
pub fn scalar(val: f32) -> Self {
let mut m = Self::zero();
m.c[0] = val;
m
}
#[inline(always)]
pub fn e1() -> Self {
let mut m = Self::zero();
m.c[1] = 1.0;
m
}
#[inline(always)]
pub fn e2() -> Self {
let mut m = Self::zero();
m.c[2] = 1.0;
m
}
#[inline(always)]
pub fn e3() -> Self {
let mut m = Self::zero();
m.c[3] = 1.0;
m
}
#[inline(always)]
pub fn e0() -> Self {
let mut m = Self::zero();
m.c[4] = 1.0;
m
}
#[inline]
pub fn reverse(&self) -> Self {
let mut res = *self;
for i in 5..=10 {
res.c[i] = -res.c[i];
}
for i in 11..=14 {
res.c[i] = -res.c[i];
}
res
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct CkPoint3D {
pub x: f32,
pub y: f32,
pub z: f32,
pub w: f32,
}
impl CkPoint3D {
#[inline(always)]
pub fn new(x: f32, y: f32, z: f32) -> Self {
Self { x, y, z, w: 1.0 }
}
#[inline(always)]
pub fn origin() -> Self {
Self { x: 0.0, y: 0.0, z: 0.0, w: 1.0 }
}
#[inline]
pub fn to_multivector(&self) -> CkMultivector3D {
let mut m = CkMultivector3D::zero();
m.c[1] = self.x;
m.c[2] = self.y;
m.c[3] = self.z;
m.c[4] = self.w;
m
}
#[inline(always)]
pub fn norm_sq(&self, tau: f32) -> f32 {
self.x * self.x + self.y * self.y + self.z * self.z + tau * (self.w * self.w)
}
#[inline(always)]
pub fn inner_product(&self, other: &Self, tau: f32) -> f32 {
self.x * other.x + self.y * other.y + self.z * other.z + tau * (self.w * other.w)
}
pub fn geodesic_distance(&self, other: &Self, tau: f32) -> f32 {
let dx = self.x / self.w - other.x / other.w;
let dy = self.y / self.w - other.y / other.w;
let dz = self.z / self.w - other.z / other.w;
let diff_sq = dx * dx + dy * dy + dz * dz;
if tau.abs() < 1e-7 {
return diff_sq.sqrt();
}
let p_sq = (self.x * self.x + self.y * self.y + self.z * self.z) / (self.w * self.w);
let q_sq = (other.x * other.x + other.y * other.y + other.z * other.z) / (other.w * other.w);
if tau < 0.0 {
let abs_tau = -tau;
let inv_sqrt_tau = 1.0f32 / abs_tau.sqrt();
let u_factor = (1.0f32 - abs_tau * p_sq).max(1e-7);
let v_factor = (1.0f32 - abs_tau * q_sq).max(1e-7);
let denom = u_factor * v_factor;
let delta = 1.0f32 + (2.0f32 * abs_tau * diff_sq) / denom;
let delta_clamped = delta.max(1.0f32);
let arcosh = (delta_clamped + (delta_clamped * delta_clamped - 1.0f32).sqrt()).ln();
inv_sqrt_tau * arcosh
} else {
let inv_sqrt_tau = 1.0f32 / tau.sqrt();
let u_factor = 1.0f32 + tau * p_sq;
let v_factor = 1.0f32 + tau * q_sq;
let denom = (u_factor * v_factor).max(1e-7);
let arg = 1.0f32 - (2.0f32 * tau * diff_sq) / denom;
let arg_clamped = arg.clamp(-1.0f32, 1.0f32);
inv_sqrt_tau * arg_clamped.acos()
}
}
#[inline]
pub fn join(&self, other: &Self) -> CkLine3D {
let vx = self.y * other.z - self.z * other.y;
let vy = self.z * other.x - self.x * other.z;
let vz = self.x * other.y - self.y * other.x;
let mx = self.x * other.w - other.x * self.w;
let my = self.y * other.w - other.y * self.w;
let mz = self.z * other.w - other.z * self.w;
CkLine3D {
vx,
vy,
vz,
mx,
my,
mz,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct CkPlane3D {
pub nx: f32,
pub ny: f32,
pub nz: f32,
pub d: f32,
}
impl CkPlane3D {
#[inline(always)]
pub fn new(nx: f32, ny: f32, nz: f32, d: f32) -> Self {
Self { nx, ny, nz, d }
}
#[inline(always)]
pub fn norm_sq(&self, tau: f32) -> f32 {
self.nx * self.nx + self.ny * self.ny + self.nz * self.nz + tau * (self.d * self.d)
}
pub fn reflect_point(&self, p: &CkPoint3D, tau: f32) -> CkPoint3D {
let h_norm_sq = self.norm_sq(tau);
assert!(h_norm_sq.abs() > 1e-12, "Degenerate plane in Cayley-Klein reflection");
let p_dot_h = self.nx * p.x + self.ny * p.y + self.nz * p.z - tau * self.d * p.w;
let scale = 2.0f32 * p_dot_h / h_norm_sq;
CkPoint3D {
x: p.x - scale * self.nx,
y: p.y - scale * self.ny,
z: p.z - scale * self.nz,
w: p.w + scale * self.d,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct CkLine3D {
pub vx: f32,
pub vy: f32,
pub vz: f32,
pub mx: f32,
pub my: f32,
pub mz: f32,
}
impl CkLine3D {
#[inline(always)]
pub fn plucker_inner(&self) -> f32 {
self.vx * self.mx + self.vy * self.my + self.vz * self.mz
}
#[inline]
pub fn to_multivector(&self) -> CkMultivector3D {
let mut m = CkMultivector3D::zero();
m.c[6] = self.vx; m.c[7] = self.vy; m.c[5] = self.vz; m.c[8] = self.mx; m.c[9] = self.my; m.c[10] = self.mz; m
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct CkMotor3D {
pub s: f32,
pub rot: [f32; 3], pub trans: [f32; 3], pub p: f32, }
impl Default for CkMotor3D {
#[inline(always)]
fn default() -> Self {
Self::identity()
}
}
impl CkMotor3D {
#[inline(always)]
pub fn identity() -> Self {
Self {
s: 1.0,
rot: [0.0; 3],
trans: [0.0; 3],
p: 0.0,
}
}
pub fn from_rotation(axis: [f32; 3], theta: f32) -> Self {
let half = theta * 0.5f32;
let c = half.cos();
let s = half.sin();
Self {
s: c,
rot: [s * axis[0], s * axis[1], s * axis[2]],
trans: [0.0; 3],
p: 0.0,
}
}
pub fn from_translation(direction: [f32; 3], delta: f32, tau: f32) -> Self {
let half_d = delta * 0.5f32;
if tau.abs() < 1e-7 {
Self {
s: 1.0,
rot: [0.0; 3],
trans: [half_d * direction[0], half_d * direction[1], half_d * direction[2]],
p: 0.0,
}
} else if tau < 0.0 {
let sqrt_abs = (-tau).sqrt();
let arg = half_d * sqrt_abs;
let c = arg.cosh();
let s = arg.sinh() / sqrt_abs;
Self {
s: c,
rot: [0.0; 3],
trans: [s * direction[0], s * direction[1], s * direction[2]],
p: 0.0,
}
} else {
let sqrt_tau = tau.sqrt();
let arg = half_d * sqrt_tau;
let c = arg.cos();
let s = arg.sin() / sqrt_tau;
Self {
s: c,
rot: [0.0; 3],
trans: [s * direction[0], s * direction[1], s * direction[2]],
p: 0.0,
}
}
}
pub fn transform_point(&self, p: &CkPoint3D, tau: f32) -> CkPoint3D {
let rx = self.rot[0];
let ry = self.rot[1];
let rz = self.rot[2];
let s = self.s;
let px = p.x;
let py = p.y;
let pz = p.z;
let tx = 2.0 * (ry * pz - rz * py);
let ty = 2.0 * (rz * px - rx * pz);
let tz = 2.0 * (rx * py - ry * px);
let x_rot = px + s * tx + (ry * tz - rz * ty);
let y_rot = py + s * ty + (rz * tx - rx * tz);
let z_rot = pz + s * tz + (rx * ty - ry * tx);
let mx = self.trans[0];
let my = self.trans[1];
let mz = self.trans[2];
let x_trans = x_rot * s + (2.0 * mx * p.w);
let y_trans = y_rot * s + (2.0 * my * p.w);
let z_trans = z_rot * s + (2.0 * mz * p.w);
let w_trans = p.w * s - (2.0 * tau * (mx * x_rot + my * y_rot + mz * z_rot));
let inv_w = if w_trans.abs() > 1e-7 { 1.0 / w_trans } else { 1.0 };
CkPoint3D {
x: x_trans * inv_w,
y: y_trans * inv_w,
z: z_trans * inv_w,
w: 1.0,
}
}
}