use super::scalar::{DetF32, Deterministic};
use core::ops::{Add, Mul, Sub};
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct DetVector2 {
pub x: DetF32,
pub y: DetF32,
}
unsafe impl Deterministic for DetVector2 {}
impl DetVector2 {
#[inline]
pub const fn new(x: DetF32, y: DetF32) -> Self {
Self { x, y }
}
#[inline]
pub fn from_f32(x: f32, y: f32) -> Self {
Self {
x: DetF32::from_f32(x),
y: DetF32::from_f32(y),
}
}
pub const ZERO: Self = Self::new(DetF32::ZERO, DetF32::ZERO);
pub const X_AXIS: Self = Self::new(DetF32::ONE, DetF32::ZERO);
pub const Y_AXIS: Self = Self::new(DetF32::ZERO, DetF32::ONE);
#[inline(never)]
pub fn dot(self, other: Self) -> DetF32 {
self.x * other.x + self.y * other.y
}
#[inline(never)]
pub fn magnitude_sq(self) -> DetF32 {
self.dot(self)
}
#[inline(never)]
pub fn magnitude(self) -> DetF32 {
self.magnitude_sq().sqrt()
}
#[inline(never)]
pub fn normalize(self) -> Self {
let mag = self.magnitude();
Self {
x: self.x / mag,
y: self.y / mag,
}
}
#[inline(never)]
pub fn wedge(self, other: Self) -> DetF32 {
self.x * other.y - self.y * other.x
}
}
impl Add for DetVector2 {
type Output = Self;
#[inline(never)]
fn add(self, rhs: Self) -> Self {
Self {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
impl Sub for DetVector2 {
type Output = Self;
#[inline(never)]
fn sub(self, rhs: Self) -> Self {
Self {
x: self.x - rhs.x,
y: self.y - rhs.y,
}
}
}
impl Mul<DetF32> for DetVector2 {
type Output = Self;
#[inline(never)]
fn mul(self, scalar: DetF32) -> Self {
Self {
x: self.x * scalar,
y: self.y * scalar,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct DetRotor2 {
pub s: DetF32,
pub b: DetF32,
}
unsafe impl Deterministic for DetRotor2 {}
impl DetRotor2 {
#[inline]
pub const fn new(s: DetF32, b: DetF32) -> Self {
Self { s, b }
}
pub const IDENTITY: Self = Self::new(DetF32::ONE, DetF32::ZERO);
#[inline(never)]
pub fn from_angle(angle: DetF32) -> Self {
let half_angle = angle * DetF32::HALF;
Self {
s: half_angle.cos(),
b: half_angle.sin(),
}
}
#[inline(never)]
pub fn compose(self, other: Self) -> Self {
Self {
s: self.s * other.s - self.b * other.b,
b: self.s * other.b + self.b * other.s,
}
}
#[inline(never)]
pub fn transform(self, v: DetVector2) -> DetVector2 {
let s2 = self.s * self.s;
let b2 = self.b * self.b;
let sb2 = self.s * self.b * DetF32::TWO;
DetVector2 {
x: (s2 - b2) * v.x - sb2 * v.y,
y: sb2 * v.x + (s2 - b2) * v.y,
}
}
#[inline]
pub fn inverse(self) -> Self {
Self {
s: self.s,
b: -self.b,
}
}
#[inline(never)]
pub fn to_angle(self) -> DetF32 {
DetF32::atan2(self.b, self.s) * DetF32::TWO
}
}
impl Mul for DetRotor2 {
type Output = Self;
#[inline(never)]
fn mul(self, rhs: Self) -> Self {
self.compose(rhs)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_rotor_identity() {
let v = DetVector2::new(DetF32::ONE, DetF32::TWO);
let r = DetRotor2::IDENTITY;
let result = r.transform(v);
assert_eq!(result.x.to_bits(), v.x.to_bits());
assert_eq!(result.y.to_bits(), v.y.to_bits());
}
#[test]
fn test_rotor_composition_determinism() {
let r1 = DetRotor2::from_angle(DetF32::PI * DetF32::from_f32(0.25)); let r2 = DetRotor2::from_angle(DetF32::PI * DetF32::from_f32(0.25));
let composed1 = r1 * r2;
let composed2 = r1 * r2;
let composed3 = r1 * r2;
assert_eq!(composed1.s.to_bits(), composed2.s.to_bits());
assert_eq!(composed1.b.to_bits(), composed2.b.to_bits());
assert_eq!(composed2.s.to_bits(), composed3.s.to_bits());
assert_eq!(composed2.b.to_bits(), composed3.b.to_bits());
let v = DetVector2::X_AXIS;
let result1 = composed1.transform(v);
let result2 = composed2.transform(v);
assert_eq!(result1.x.to_bits(), result2.x.to_bits());
assert_eq!(result1.y.to_bits(), result2.y.to_bits());
}
#[test]
fn test_deterministic_bits() {
let angle = DetF32::from_bits(0x3f490fdb);
let r1 = DetRotor2::from_angle(angle);
let r2 = DetRotor2::from_angle(angle);
assert_eq!(r1.s.to_bits(), r2.s.to_bits());
assert_eq!(r1.b.to_bits(), r2.b.to_bits());
}
}