use crate::*;
use std::ops::{Div, DivAssign, Mul, MulAssign};
use derive_more::{Add, AddAssign, Neg, Sub, SubAssign};
use inner_space::{DotProduct, InnerSpace, Transform, VectorSpace};
use num_traits::{Inv, One, Zero, real::Real};
#[derive(Copy, Clone, Debug, PartialEq, Eq, Add, AddAssign, Sub, SubAssign, Neg)]
pub struct Rotor<T> {
pub scalar: T,
pub xy: T,
}
impl<T> Rotor<T> {
pub fn new(scalar: T, xy: T) -> Self {
Self { scalar, xy }
}
}
impl<T: Real> Rotor<T> {
pub fn rotate(self, vector: Vector<T>) -> Vector<T> {
self.normalize().rotate_normalized(vector)
}
pub fn rotate_normalized(self, vector: Vector<T>) -> Vector<T> {
let Self { scalar, xy } = self * self;
Vector {
x: scalar * vector.x + xy * vector.y,
y: scalar * vector.y - xy * vector.x,
}
}
pub fn reverse(self) -> Self {
Self {
scalar: self.scalar,
xy: -self.xy,
}
}
}
impl<T: Zero> Rotor<T> {
pub fn scalar(scalar: T) -> Self {
Self {
scalar,
xy: T::zero(),
}
}
pub fn xy(xy: T) -> Self {
Self {
scalar: T::zero(),
xy,
}
}
}
impl<T: Zero> Zero for Rotor<T> {
fn zero() -> Self {
Self {
scalar: T::zero(),
xy: T::zero(),
}
}
fn is_zero(&self) -> bool {
self.scalar.is_zero() && self.xy.is_zero()
}
}
impl<T: Real> One for Rotor<T> {
fn one() -> Self {
Self {
scalar: T::one(),
xy: T::zero(),
}
}
fn is_one(&self) -> bool {
self.scalar.is_one() && self.xy.is_zero()
}
}
impl<T: Real> Inv for Rotor<T> {
type Output = Self;
fn inv(self) -> Self {
let rev = self.reverse();
rev / self.dot(&rev)
}
}
impl<T: Real> From<T> for Rotor<T> {
fn from(scalar: T) -> Self {
Self::scalar(scalar)
}
}
impl<T> Mul<T> for Rotor<T>
where
T: Mul<Output = T> + Copy,
{
type Output = Self;
fn mul(self, other: T) -> Self {
Self {
scalar: self.scalar * other,
xy: self.xy * other,
}
}
}
impl<T> MulAssign<T> for Rotor<T>
where
T: MulAssign + Copy,
{
fn mul_assign(&mut self, other: T) {
self.scalar *= other;
self.xy *= other;
}
}
impl<T> Div<T> for Rotor<T>
where
T: Div<Output = T> + Copy,
{
type Output = Self;
fn div(self, other: T) -> Self {
Self {
scalar: self.scalar / other,
xy: self.xy / other,
}
}
}
impl<T> DivAssign<T> for Rotor<T>
where
T: DivAssign + Copy,
{
fn div_assign(&mut self, other: T) {
self.scalar /= other;
self.xy /= other;
}
}
impl<T: Real> VectorSpace for Rotor<T> {
type Scalar = T;
}
impl<T: Real> DotProduct for Rotor<T> {
type Output = Self::Scalar;
fn dot(&self, other: &Self) -> T {
self.scalar * other.scalar - self.xy * other.xy
}
}
impl<T: Real> DotProduct<Vector<T>> for Rotor<T> {
type Output = Vector<T>;
#[inline]
fn dot(&self, other: &Vector<T>) -> Vector<T> {
other.dot(self)
}
}
impl<T: Real> DotProduct<Bivector<T>> for Rotor<T> {
type Output = Self;
#[inline]
fn dot(&self, other: &Bivector<T>) -> Self {
other.dot(self)
}
}
impl<T: Real> Mul for Rotor<T> {
type Output = Self;
fn mul(self, other: Self) -> Self {
Self {
scalar: self.dot(&other),
xy: self.scalar * other.xy + other.scalar * self.xy,
}
}
}
impl<T: Real> MulAssign for Rotor<T> {
fn mul_assign(&mut self, other: Self) {
*self = *self * other;
}
}
impl<T: Real> Div for Rotor<T> {
type Output = Self;
fn div(self, other: Self) -> Self {
self * other.inv()
}
}
impl<T: Real> DivAssign for Rotor<T> {
fn div_assign(&mut self, other: Self) {
*self = *self / other;
}
}
impl<T: Real> Transform<Vector<T>> for Rotor<T> {
fn apply_point(&self, point: Vector<T>) -> Vector<T> {
self.rotate(point)
}
}
impl<T: Real + std::fmt::Display> std::fmt::Display for Rotor<T> {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(formatter, "({}, {})", self.scalar, self.xy)
}
}
impl<T: Real + std::str::FromStr> std::str::FromStr for Rotor<T> {
type Err = String;
fn from_str(source: &str) -> Result<Self, Self::Err> {
let trimmed = source
.strip_prefix('(')
.and_then(|s| s.strip_suffix(')'))
.ok_or_else(|| format!("expected format (scalar, xy), got {source}"))?;
let mut parts = trimmed.split(',');
let scalar = parts
.next()
.ok_or_else(|| "missing scalar component".to_string())?
.trim()
.parse::<T>()
.map_err(|_| "failed to parse scalar component".to_string())?;
let xy = parts
.next()
.ok_or_else(|| "missing xy component".to_string())?
.trim()
.parse::<T>()
.map_err(|_| "failed to parse xy component".to_string())?;
if parts.next().is_some() {
return Err("too many components".to_string());
}
Ok(Self { scalar, xy })
}
}