#![doc = " Trait implementations for euclidean3."]
#![doc = ""]
#![doc = " This file is auto-generated by clifford-codegen."]
#![doc = " Do not edit manually."]
use super::types::{Bivector, Rotor, Scalar, Trivector, Vector};
#[allow(unused_imports)]
use crate::ops::{
Antidot, Antireverse, Antisandwich, Antiwedge, BulkContract, BulkExpand, Dot,
InverseAntisandwich, InverseSandwich, Involute, LeftContract, Reverse, RightComplement,
RightContract, Sandwich, ScalarProduct, Transform, Versor, VersorInverse, Wedge,
WeightContract, WeightDual, WeightExpand,
};
use crate::scalar::Float;
#[allow(unused_imports)]
use crate::wrappers::Unit;
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
use std::ops::{Add, Mul, Neg, Sub};
impl<T: Float> Add for Bivector<T> {
type Output = Self;
#[inline]
fn add(self, rhs: Self) -> Self {
Self::new_unchecked(
self.rz() + rhs.rz(),
self.ry() + rhs.ry(),
self.rx() + rhs.rx(),
)
}
}
impl<T: Float> Sub for Bivector<T> {
type Output = Self;
#[inline]
fn sub(self, rhs: Self) -> Self {
Self::new_unchecked(
self.rz() - rhs.rz(),
self.ry() - rhs.ry(),
self.rx() - rhs.rx(),
)
}
}
impl<T: Float> Neg for Bivector<T> {
type Output = Self;
#[inline]
fn neg(self) -> Self {
Self::new_unchecked(-self.rz(), -self.ry(), -self.rx())
}
}
impl<T: Float> Mul<T> for Bivector<T> {
type Output = Self;
#[inline]
fn mul(self, scalar: T) -> Self {
self.scale(scalar)
}
}
impl Mul<Bivector<f32>> for f32 {
type Output = Bivector<f32>;
#[inline]
fn mul(self, v: Bivector<f32>) -> Bivector<f32> {
v.scale(self)
}
}
impl Mul<Bivector<f64>> for f64 {
type Output = Bivector<f64>;
#[inline]
fn mul(self, v: Bivector<f64>) -> Bivector<f64> {
v.scale(self)
}
}
impl<T: Float> Mul<Bivector<T>> for Bivector<T> {
type Output = Rotor<T>;
#[inline]
fn mul(self, rhs: Bivector<T>) -> Rotor<T> {
Rotor::new_unchecked(
-(rhs.rx() * self.rx()) + -(rhs.ry() * self.ry()) + -(rhs.rz() * self.rz()),
-(rhs.rx() * self.ry()) + rhs.ry() * self.rx(),
-(rhs.rz() * self.rx()) + rhs.rx() * self.rz(),
-(rhs.ry() * self.rz()) + rhs.rz() * self.ry(),
)
}
}
impl<T: Float> Mul<Rotor<T>> for Bivector<T> {
type Output = Rotor<T>;
#[inline]
fn mul(self, rhs: Rotor<T>) -> Rotor<T> {
Rotor::new_unchecked(
-(rhs.rx() * self.rx()) + -(rhs.ry() * self.ry()) + -(rhs.rz() * self.rz()),
-(rhs.rx() * self.ry()) + rhs.ry() * self.rx() + rhs.s() * self.rz(),
-(rhs.rz() * self.rx()) + rhs.rx() * self.rz() + rhs.s() * self.ry(),
-(rhs.ry() * self.rz()) + rhs.rz() * self.ry() + rhs.s() * self.rx(),
)
}
}
impl<T: Float> Mul<Scalar<T>> for Bivector<T> {
type Output = Bivector<T>;
#[inline]
fn mul(self, rhs: Scalar<T>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.s() * self.rz(),
rhs.s() * self.ry(),
rhs.s() * self.rx(),
)
}
}
impl<T: Float> Mul<Trivector<T>> for Bivector<T> {
type Output = Vector<T>;
#[inline]
fn mul(self, rhs: Trivector<T>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.ps() * self.rx()),
rhs.ps() * self.ry(),
-(rhs.ps() * self.rz()),
)
}
}
impl<T: Float> Add for Rotor<T> {
type Output = Self;
#[inline]
fn add(self, rhs: Self) -> Self {
Self::new_unchecked(
self.s() + rhs.s(),
self.rz() + rhs.rz(),
self.ry() + rhs.ry(),
self.rx() + rhs.rx(),
)
}
}
impl<T: Float> Sub for Rotor<T> {
type Output = Self;
#[inline]
fn sub(self, rhs: Self) -> Self {
Self::new_unchecked(
self.s() - rhs.s(),
self.rz() - rhs.rz(),
self.ry() - rhs.ry(),
self.rx() - rhs.rx(),
)
}
}
impl<T: Float> Neg for Rotor<T> {
type Output = Self;
#[inline]
fn neg(self) -> Self {
Self::new_unchecked(-self.s(), -self.rz(), -self.ry(), -self.rx())
}
}
impl<T: Float> Mul<T> for Rotor<T> {
type Output = Self;
#[inline]
fn mul(self, scalar: T) -> Self {
self.scale(scalar)
}
}
impl Mul<Rotor<f32>> for f32 {
type Output = Rotor<f32>;
#[inline]
fn mul(self, v: Rotor<f32>) -> Rotor<f32> {
v.scale(self)
}
}
impl Mul<Rotor<f64>> for f64 {
type Output = Rotor<f64>;
#[inline]
fn mul(self, v: Rotor<f64>) -> Rotor<f64> {
v.scale(self)
}
}
impl<T: Float> Mul<Bivector<T>> for Rotor<T> {
type Output = Rotor<T>;
#[inline]
fn mul(self, rhs: Bivector<T>) -> Rotor<T> {
Rotor::new_unchecked(
-(rhs.rx() * self.rx()) + -(rhs.ry() * self.ry()) + -(rhs.rz() * self.rz()),
-(rhs.rx() * self.ry()) + rhs.ry() * self.rx() + rhs.rz() * self.s(),
-(rhs.rz() * self.rx()) + rhs.rx() * self.rz() + rhs.ry() * self.s(),
-(rhs.ry() * self.rz()) + rhs.rx() * self.s() + rhs.rz() * self.ry(),
)
}
}
impl<T: Float> Mul<Rotor<T>> for Rotor<T> {
type Output = Rotor<T>;
#[inline]
fn mul(self, rhs: Rotor<T>) -> Rotor<T> {
Rotor::new_unchecked(
-(rhs.rx() * self.rx())
+ -(rhs.ry() * self.ry())
+ -(rhs.rz() * self.rz())
+ rhs.s() * self.s(),
-(rhs.rx() * self.ry())
+ rhs.ry() * self.rx()
+ rhs.rz() * self.s()
+ rhs.s() * self.rz(),
-(rhs.rz() * self.rx())
+ rhs.rx() * self.rz()
+ rhs.ry() * self.s()
+ rhs.s() * self.ry(),
-(rhs.ry() * self.rz())
+ rhs.rx() * self.s()
+ rhs.rz() * self.ry()
+ rhs.s() * self.rx(),
)
}
}
impl<T: Float> Mul<Scalar<T>> for Rotor<T> {
type Output = Rotor<T>;
#[inline]
fn mul(self, rhs: Scalar<T>) -> Rotor<T> {
Rotor::new_unchecked(
rhs.s() * self.s(),
rhs.s() * self.rz(),
rhs.s() * self.ry(),
rhs.s() * self.rx(),
)
}
}
impl<T: Float> Add for Scalar<T> {
type Output = Self;
#[inline]
fn add(self, rhs: Self) -> Self {
Self::new_unchecked(self.s() + rhs.s())
}
}
impl<T: Float> Sub for Scalar<T> {
type Output = Self;
#[inline]
fn sub(self, rhs: Self) -> Self {
Self::new_unchecked(self.s() - rhs.s())
}
}
impl<T: Float> Neg for Scalar<T> {
type Output = Self;
#[inline]
fn neg(self) -> Self {
Self::new_unchecked(-self.s())
}
}
impl<T: Float> Mul<T> for Scalar<T> {
type Output = Self;
#[inline]
fn mul(self, scalar: T) -> Self {
self.scale(scalar)
}
}
impl Mul<Scalar<f32>> for f32 {
type Output = Scalar<f32>;
#[inline]
fn mul(self, v: Scalar<f32>) -> Scalar<f32> {
v.scale(self)
}
}
impl Mul<Scalar<f64>> for f64 {
type Output = Scalar<f64>;
#[inline]
fn mul(self, v: Scalar<f64>) -> Scalar<f64> {
v.scale(self)
}
}
impl<T: Float> Mul<Bivector<T>> for Scalar<T> {
type Output = Bivector<T>;
#[inline]
fn mul(self, rhs: Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.rz() * self.s(),
rhs.ry() * self.s(),
rhs.rx() * self.s(),
)
}
}
impl<T: Float> Mul<Rotor<T>> for Scalar<T> {
type Output = Rotor<T>;
#[inline]
fn mul(self, rhs: Rotor<T>) -> Rotor<T> {
Rotor::new_unchecked(
rhs.s() * self.s(),
rhs.rz() * self.s(),
rhs.ry() * self.s(),
rhs.rx() * self.s(),
)
}
}
impl<T: Float> Mul<Scalar<T>> for Scalar<T> {
type Output = Scalar<T>;
#[inline]
fn mul(self, rhs: Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(rhs.s() * self.s())
}
}
impl<T: Float> Mul<Trivector<T>> for Scalar<T> {
type Output = Trivector<T>;
#[inline]
fn mul(self, rhs: Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(rhs.ps() * self.s())
}
}
impl<T: Float> Mul<Vector<T>> for Scalar<T> {
type Output = Vector<T>;
#[inline]
fn mul(self, rhs: Vector<T>) -> Vector<T> {
Vector::new_unchecked(rhs.x() * self.s(), rhs.y() * self.s(), rhs.z() * self.s())
}
}
impl<T: Float> Add for Trivector<T> {
type Output = Self;
#[inline]
fn add(self, rhs: Self) -> Self {
Self::new_unchecked(self.ps() + rhs.ps())
}
}
impl<T: Float> Sub for Trivector<T> {
type Output = Self;
#[inline]
fn sub(self, rhs: Self) -> Self {
Self::new_unchecked(self.ps() - rhs.ps())
}
}
impl<T: Float> Neg for Trivector<T> {
type Output = Self;
#[inline]
fn neg(self) -> Self {
Self::new_unchecked(-self.ps())
}
}
impl<T: Float> Mul<T> for Trivector<T> {
type Output = Self;
#[inline]
fn mul(self, scalar: T) -> Self {
self.scale(scalar)
}
}
impl Mul<Trivector<f32>> for f32 {
type Output = Trivector<f32>;
#[inline]
fn mul(self, v: Trivector<f32>) -> Trivector<f32> {
v.scale(self)
}
}
impl Mul<Trivector<f64>> for f64 {
type Output = Trivector<f64>;
#[inline]
fn mul(self, v: Trivector<f64>) -> Trivector<f64> {
v.scale(self)
}
}
impl<T: Float> Mul<Bivector<T>> for Trivector<T> {
type Output = Vector<T>;
#[inline]
fn mul(self, rhs: Bivector<T>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.rx() * self.ps()),
rhs.ry() * self.ps(),
-(rhs.rz() * self.ps()),
)
}
}
impl<T: Float> Mul<Scalar<T>> for Trivector<T> {
type Output = Trivector<T>;
#[inline]
fn mul(self, rhs: Scalar<T>) -> Trivector<T> {
Trivector::new_unchecked(rhs.s() * self.ps())
}
}
impl<T: Float> Mul<Trivector<T>> for Trivector<T> {
type Output = Scalar<T>;
#[inline]
fn mul(self, rhs: Trivector<T>) -> Scalar<T> {
Scalar::new_unchecked(-(rhs.ps() * self.ps()))
}
}
impl<T: Float> Mul<Vector<T>> for Trivector<T> {
type Output = Bivector<T>;
#[inline]
fn mul(self, rhs: Vector<T>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.z() * self.ps(),
-(rhs.y() * self.ps()),
rhs.x() * self.ps(),
)
}
}
impl<T: Float> Add for Vector<T> {
type Output = Self;
#[inline]
fn add(self, rhs: Self) -> Self {
Self::new_unchecked(self.x() + rhs.x(), self.y() + rhs.y(), self.z() + rhs.z())
}
}
impl<T: Float> Sub for Vector<T> {
type Output = Self;
#[inline]
fn sub(self, rhs: Self) -> Self {
Self::new_unchecked(self.x() - rhs.x(), self.y() - rhs.y(), self.z() - rhs.z())
}
}
impl<T: Float> Neg for Vector<T> {
type Output = Self;
#[inline]
fn neg(self) -> Self {
Self::new_unchecked(-self.x(), -self.y(), -self.z())
}
}
impl<T: Float> Mul<T> for Vector<T> {
type Output = Self;
#[inline]
fn mul(self, scalar: T) -> Self {
self.scale(scalar)
}
}
impl Mul<Vector<f32>> for f32 {
type Output = Vector<f32>;
#[inline]
fn mul(self, v: Vector<f32>) -> Vector<f32> {
v.scale(self)
}
}
impl Mul<Vector<f64>> for f64 {
type Output = Vector<f64>;
#[inline]
fn mul(self, v: Vector<f64>) -> Vector<f64> {
v.scale(self)
}
}
impl<T: Float> Mul<Scalar<T>> for Vector<T> {
type Output = Vector<T>;
#[inline]
fn mul(self, rhs: Scalar<T>) -> Vector<T> {
Vector::new_unchecked(rhs.s() * self.x(), rhs.s() * self.y(), rhs.s() * self.z())
}
}
impl<T: Float> Mul<Trivector<T>> for Vector<T> {
type Output = Bivector<T>;
#[inline]
fn mul(self, rhs: Trivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.ps() * self.z(),
-(rhs.ps() * self.y()),
rhs.ps() * self.x(),
)
}
}
impl<T: Float> Mul<Vector<T>> for Vector<T> {
type Output = Rotor<T>;
#[inline]
fn mul(self, rhs: Vector<T>) -> Rotor<T> {
Rotor::new_unchecked(
rhs.x() * self.x() + rhs.y() * self.y() + rhs.z() * self.z(),
-(rhs.x() * self.y()) + rhs.y() * self.x(),
-(rhs.x() * self.z()) + rhs.z() * self.x(),
-(rhs.y() * self.z()) + rhs.z() * self.y(),
)
}
}
#[doc = "Wedge (exterior/outer) product of [`Bivector`] and [`Scalar`].\n\nThe wedge product `a ^ b` computes the outer product, which represents\nthe oriented subspace spanned by both operands. The result grade is the\nsum of the input grades (or zero if they share common factors)."]
impl<T: Float> Wedge<Scalar<T>> for Bivector<T> {
type Output = Bivector<T>;
#[inline]
fn wedge(&self, rhs: &Scalar<T>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.s() * self.rz(),
rhs.s() * self.ry(),
rhs.s() * self.rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Wedge<Scalar<T>> for Unit<Bivector<T>> {
type Output = Bivector<T>;
#[inline]
fn wedge(&self, rhs: &Scalar<T>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.s() * self.as_inner().rz(),
rhs.s() * self.as_inner().ry(),
rhs.s() * self.as_inner().rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Wedge<Unit<Scalar<T>>> for Bivector<T> {
type Output = Bivector<T>;
#[inline]
fn wedge(&self, rhs: &Unit<Scalar<T>>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.as_inner().s() * self.rz(),
rhs.as_inner().s() * self.ry(),
rhs.as_inner().s() * self.rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Wedge<Unit<Scalar<T>>> for Unit<Bivector<T>> {
type Output = Bivector<T>;
#[inline]
fn wedge(&self, rhs: &Unit<Scalar<T>>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.as_inner().s() * self.as_inner().rz(),
rhs.as_inner().s() * self.as_inner().ry(),
rhs.as_inner().s() * self.as_inner().rx(),
)
}
}
#[doc = "Wedge (exterior/outer) product of [`Bivector`] and [`Vector`].\n\nThe wedge product `a ^ b` computes the outer product, which represents\nthe oriented subspace spanned by both operands. The result grade is the\nsum of the input grades (or zero if they share common factors)."]
impl<T: Float> Wedge<Vector<T>> for Bivector<T> {
type Output = Trivector<T>;
#[inline]
fn wedge(&self, rhs: &Vector<T>) -> Trivector<T> {
Trivector::new_unchecked(-(rhs.y() * self.ry()) + rhs.x() * self.rx() + rhs.z() * self.rz())
}
}
#[allow(unused_variables)]
impl<T: Float> Wedge<Vector<T>> for Unit<Bivector<T>> {
type Output = Trivector<T>;
#[inline]
fn wedge(&self, rhs: &Vector<T>) -> Trivector<T> {
Trivector::new_unchecked(
-(rhs.y() * self.as_inner().ry())
+ rhs.x() * self.as_inner().rx()
+ rhs.z() * self.as_inner().rz(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Wedge<Unit<Vector<T>>> for Bivector<T> {
type Output = Trivector<T>;
#[inline]
fn wedge(&self, rhs: &Unit<Vector<T>>) -> Trivector<T> {
Trivector::new_unchecked(
-(rhs.as_inner().y() * self.ry())
+ rhs.as_inner().x() * self.rx()
+ rhs.as_inner().z() * self.rz(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Wedge<Unit<Vector<T>>> for Unit<Bivector<T>> {
type Output = Trivector<T>;
#[inline]
fn wedge(&self, rhs: &Unit<Vector<T>>) -> Trivector<T> {
Trivector::new_unchecked(
-(rhs.as_inner().y() * self.as_inner().ry())
+ rhs.as_inner().x() * self.as_inner().rx()
+ rhs.as_inner().z() * self.as_inner().rz(),
)
}
}
#[doc = "Wedge (exterior/outer) product of [`Scalar`] and [`Bivector`].\n\nThe wedge product `a ^ b` computes the outer product, which represents\nthe oriented subspace spanned by both operands. The result grade is the\nsum of the input grades (or zero if they share common factors)."]
impl<T: Float> Wedge<Bivector<T>> for Scalar<T> {
type Output = Bivector<T>;
#[inline]
fn wedge(&self, rhs: &Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.rz() * self.s(),
rhs.ry() * self.s(),
rhs.rx() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Wedge<Bivector<T>> for Unit<Scalar<T>> {
type Output = Bivector<T>;
#[inline]
fn wedge(&self, rhs: &Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.rz() * self.as_inner().s(),
rhs.ry() * self.as_inner().s(),
rhs.rx() * self.as_inner().s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Wedge<Unit<Bivector<T>>> for Scalar<T> {
type Output = Bivector<T>;
#[inline]
fn wedge(&self, rhs: &Unit<Bivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.as_inner().rz() * self.s(),
rhs.as_inner().ry() * self.s(),
rhs.as_inner().rx() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Wedge<Unit<Bivector<T>>> for Unit<Scalar<T>> {
type Output = Bivector<T>;
#[inline]
fn wedge(&self, rhs: &Unit<Bivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.as_inner().rz() * self.as_inner().s(),
rhs.as_inner().ry() * self.as_inner().s(),
rhs.as_inner().rx() * self.as_inner().s(),
)
}
}
#[doc = "Wedge (exterior/outer) product of [`Scalar`] and [`Scalar`].\n\nThe wedge product `a ^ b` computes the outer product, which represents\nthe oriented subspace spanned by both operands. The result grade is the\nsum of the input grades (or zero if they share common factors)."]
impl<T: Float> Wedge<Scalar<T>> for Scalar<T> {
type Output = Scalar<T>;
#[inline]
fn wedge(&self, rhs: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(rhs.s() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Wedge<Scalar<T>> for Unit<Scalar<T>> {
type Output = Scalar<T>;
#[inline]
fn wedge(&self, rhs: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(rhs.s() * self.as_inner().s())
}
}
#[allow(unused_variables)]
impl<T: Float> Wedge<Unit<Scalar<T>>> for Scalar<T> {
type Output = Scalar<T>;
#[inline]
fn wedge(&self, rhs: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(rhs.as_inner().s() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Wedge<Unit<Scalar<T>>> for Unit<Scalar<T>> {
type Output = Scalar<T>;
#[inline]
fn wedge(&self, rhs: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(rhs.as_inner().s() * self.as_inner().s())
}
}
#[doc = "Wedge (exterior/outer) product of [`Scalar`] and [`Trivector`].\n\nThe wedge product `a ^ b` computes the outer product, which represents\nthe oriented subspace spanned by both operands. The result grade is the\nsum of the input grades (or zero if they share common factors)."]
impl<T: Float> Wedge<Trivector<T>> for Scalar<T> {
type Output = Trivector<T>;
#[inline]
fn wedge(&self, rhs: &Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(rhs.ps() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Wedge<Trivector<T>> for Unit<Scalar<T>> {
type Output = Trivector<T>;
#[inline]
fn wedge(&self, rhs: &Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(rhs.ps() * self.as_inner().s())
}
}
#[allow(unused_variables)]
impl<T: Float> Wedge<Unit<Trivector<T>>> for Scalar<T> {
type Output = Trivector<T>;
#[inline]
fn wedge(&self, rhs: &Unit<Trivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(rhs.as_inner().ps() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Wedge<Unit<Trivector<T>>> for Unit<Scalar<T>> {
type Output = Trivector<T>;
#[inline]
fn wedge(&self, rhs: &Unit<Trivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(rhs.as_inner().ps() * self.as_inner().s())
}
}
#[doc = "Wedge (exterior/outer) product of [`Scalar`] and [`Vector`].\n\nThe wedge product `a ^ b` computes the outer product, which represents\nthe oriented subspace spanned by both operands. The result grade is the\nsum of the input grades (or zero if they share common factors)."]
impl<T: Float> Wedge<Vector<T>> for Scalar<T> {
type Output = Vector<T>;
#[inline]
fn wedge(&self, rhs: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(rhs.x() * self.s(), rhs.y() * self.s(), rhs.z() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Wedge<Vector<T>> for Unit<Scalar<T>> {
type Output = Vector<T>;
#[inline]
fn wedge(&self, rhs: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(
rhs.x() * self.as_inner().s(),
rhs.y() * self.as_inner().s(),
rhs.z() * self.as_inner().s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Wedge<Unit<Vector<T>>> for Scalar<T> {
type Output = Vector<T>;
#[inline]
fn wedge(&self, rhs: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
rhs.as_inner().x() * self.s(),
rhs.as_inner().y() * self.s(),
rhs.as_inner().z() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Wedge<Unit<Vector<T>>> for Unit<Scalar<T>> {
type Output = Vector<T>;
#[inline]
fn wedge(&self, rhs: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
rhs.as_inner().x() * self.as_inner().s(),
rhs.as_inner().y() * self.as_inner().s(),
rhs.as_inner().z() * self.as_inner().s(),
)
}
}
#[doc = "Wedge (exterior/outer) product of [`Trivector`] and [`Scalar`].\n\nThe wedge product `a ^ b` computes the outer product, which represents\nthe oriented subspace spanned by both operands. The result grade is the\nsum of the input grades (or zero if they share common factors)."]
impl<T: Float> Wedge<Scalar<T>> for Trivector<T> {
type Output = Trivector<T>;
#[inline]
fn wedge(&self, rhs: &Scalar<T>) -> Trivector<T> {
Trivector::new_unchecked(rhs.s() * self.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> Wedge<Scalar<T>> for Unit<Trivector<T>> {
type Output = Trivector<T>;
#[inline]
fn wedge(&self, rhs: &Scalar<T>) -> Trivector<T> {
Trivector::new_unchecked(rhs.s() * self.as_inner().ps())
}
}
#[allow(unused_variables)]
impl<T: Float> Wedge<Unit<Scalar<T>>> for Trivector<T> {
type Output = Trivector<T>;
#[inline]
fn wedge(&self, rhs: &Unit<Scalar<T>>) -> Trivector<T> {
Trivector::new_unchecked(rhs.as_inner().s() * self.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> Wedge<Unit<Scalar<T>>> for Unit<Trivector<T>> {
type Output = Trivector<T>;
#[inline]
fn wedge(&self, rhs: &Unit<Scalar<T>>) -> Trivector<T> {
Trivector::new_unchecked(rhs.as_inner().s() * self.as_inner().ps())
}
}
#[doc = "Wedge (exterior/outer) product of [`Vector`] and [`Bivector`].\n\nThe wedge product `a ^ b` computes the outer product, which represents\nthe oriented subspace spanned by both operands. The result grade is the\nsum of the input grades (or zero if they share common factors)."]
impl<T: Float> Wedge<Bivector<T>> for Vector<T> {
type Output = Trivector<T>;
#[inline]
fn wedge(&self, rhs: &Bivector<T>) -> Trivector<T> {
Trivector::new_unchecked(-(rhs.ry() * self.y()) + rhs.rx() * self.x() + rhs.rz() * self.z())
}
}
#[allow(unused_variables)]
impl<T: Float> Wedge<Bivector<T>> for Unit<Vector<T>> {
type Output = Trivector<T>;
#[inline]
fn wedge(&self, rhs: &Bivector<T>) -> Trivector<T> {
Trivector::new_unchecked(
-(rhs.ry() * self.as_inner().y())
+ rhs.rx() * self.as_inner().x()
+ rhs.rz() * self.as_inner().z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Wedge<Unit<Bivector<T>>> for Vector<T> {
type Output = Trivector<T>;
#[inline]
fn wedge(&self, rhs: &Unit<Bivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(
-(rhs.as_inner().ry() * self.y())
+ rhs.as_inner().rx() * self.x()
+ rhs.as_inner().rz() * self.z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Wedge<Unit<Bivector<T>>> for Unit<Vector<T>> {
type Output = Trivector<T>;
#[inline]
fn wedge(&self, rhs: &Unit<Bivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(
-(rhs.as_inner().ry() * self.as_inner().y())
+ rhs.as_inner().rx() * self.as_inner().x()
+ rhs.as_inner().rz() * self.as_inner().z(),
)
}
}
#[doc = "Wedge (exterior/outer) product of [`Vector`] and [`Scalar`].\n\nThe wedge product `a ^ b` computes the outer product, which represents\nthe oriented subspace spanned by both operands. The result grade is the\nsum of the input grades (or zero if they share common factors)."]
impl<T: Float> Wedge<Scalar<T>> for Vector<T> {
type Output = Vector<T>;
#[inline]
fn wedge(&self, rhs: &Scalar<T>) -> Vector<T> {
Vector::new_unchecked(rhs.s() * self.x(), rhs.s() * self.y(), rhs.s() * self.z())
}
}
#[allow(unused_variables)]
impl<T: Float> Wedge<Scalar<T>> for Unit<Vector<T>> {
type Output = Vector<T>;
#[inline]
fn wedge(&self, rhs: &Scalar<T>) -> Vector<T> {
Vector::new_unchecked(
rhs.s() * self.as_inner().x(),
rhs.s() * self.as_inner().y(),
rhs.s() * self.as_inner().z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Wedge<Unit<Scalar<T>>> for Vector<T> {
type Output = Vector<T>;
#[inline]
fn wedge(&self, rhs: &Unit<Scalar<T>>) -> Vector<T> {
Vector::new_unchecked(
rhs.as_inner().s() * self.x(),
rhs.as_inner().s() * self.y(),
rhs.as_inner().s() * self.z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Wedge<Unit<Scalar<T>>> for Unit<Vector<T>> {
type Output = Vector<T>;
#[inline]
fn wedge(&self, rhs: &Unit<Scalar<T>>) -> Vector<T> {
Vector::new_unchecked(
rhs.as_inner().s() * self.as_inner().x(),
rhs.as_inner().s() * self.as_inner().y(),
rhs.as_inner().s() * self.as_inner().z(),
)
}
}
#[doc = "Wedge (exterior/outer) product of [`Vector`] and [`Vector`].\n\nThe wedge product `a ^ b` computes the outer product, which represents\nthe oriented subspace spanned by both operands. The result grade is the\nsum of the input grades (or zero if they share common factors)."]
impl<T: Float> Wedge<Vector<T>> for Vector<T> {
type Output = Bivector<T>;
#[inline]
fn wedge(&self, rhs: &Vector<T>) -> Bivector<T> {
Bivector::new_unchecked(
-(rhs.x() * self.y()) + rhs.y() * self.x(),
-(rhs.x() * self.z()) + rhs.z() * self.x(),
-(rhs.y() * self.z()) + rhs.z() * self.y(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Wedge<Vector<T>> for Unit<Vector<T>> {
type Output = Bivector<T>;
#[inline]
fn wedge(&self, rhs: &Vector<T>) -> Bivector<T> {
Bivector::new_unchecked(
-(rhs.x() * self.as_inner().y()) + rhs.y() * self.as_inner().x(),
-(rhs.x() * self.as_inner().z()) + rhs.z() * self.as_inner().x(),
-(rhs.y() * self.as_inner().z()) + rhs.z() * self.as_inner().y(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Wedge<Unit<Vector<T>>> for Vector<T> {
type Output = Bivector<T>;
#[inline]
fn wedge(&self, rhs: &Unit<Vector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
-(rhs.as_inner().x() * self.y()) + rhs.as_inner().y() * self.x(),
-(rhs.as_inner().x() * self.z()) + rhs.as_inner().z() * self.x(),
-(rhs.as_inner().y() * self.z()) + rhs.as_inner().z() * self.y(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Wedge<Unit<Vector<T>>> for Unit<Vector<T>> {
type Output = Bivector<T>;
#[inline]
fn wedge(&self, rhs: &Unit<Vector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
-(rhs.as_inner().x() * self.as_inner().y()) + rhs.as_inner().y() * self.as_inner().x(),
-(rhs.as_inner().x() * self.as_inner().z()) + rhs.as_inner().z() * self.as_inner().x(),
-(rhs.as_inner().y() * self.as_inner().z()) + rhs.as_inner().z() * self.as_inner().y(),
)
}
}
#[doc = "Antiwedge (regressive/meet) product of [`Bivector`] and [`Bivector`].\n\nThe antiwedge product `a v b` computes the meet of two subspaces,\nreturning the largest subspace contained in both. In projective geometry,\nthis finds intersections (e.g., where two planes meet to form a line)."]
impl<T: Float> Antiwedge<Bivector<T>> for Bivector<T> {
type Output = Vector<T>;
#[inline]
fn antiwedge(&self, rhs: &Bivector<T>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.rz() * self.ry()) + rhs.ry() * self.rz(),
-(rhs.rz() * self.rx()) + rhs.rx() * self.rz(),
-(rhs.ry() * self.rx()) + rhs.rx() * self.ry(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antiwedge<Bivector<T>> for Unit<Bivector<T>> {
type Output = Vector<T>;
#[inline]
fn antiwedge(&self, rhs: &Bivector<T>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.rz() * self.as_inner().ry()) + rhs.ry() * self.as_inner().rz(),
-(rhs.rz() * self.as_inner().rx()) + rhs.rx() * self.as_inner().rz(),
-(rhs.ry() * self.as_inner().rx()) + rhs.rx() * self.as_inner().ry(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antiwedge<Unit<Bivector<T>>> for Bivector<T> {
type Output = Vector<T>;
#[inline]
fn antiwedge(&self, rhs: &Unit<Bivector<T>>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.as_inner().rz() * self.ry()) + rhs.as_inner().ry() * self.rz(),
-(rhs.as_inner().rz() * self.rx()) + rhs.as_inner().rx() * self.rz(),
-(rhs.as_inner().ry() * self.rx()) + rhs.as_inner().rx() * self.ry(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antiwedge<Unit<Bivector<T>>> for Unit<Bivector<T>> {
type Output = Vector<T>;
#[inline]
fn antiwedge(&self, rhs: &Unit<Bivector<T>>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.as_inner().rz() * self.as_inner().ry())
+ rhs.as_inner().ry() * self.as_inner().rz(),
-(rhs.as_inner().rz() * self.as_inner().rx())
+ rhs.as_inner().rx() * self.as_inner().rz(),
-(rhs.as_inner().ry() * self.as_inner().rx())
+ rhs.as_inner().rx() * self.as_inner().ry(),
)
}
}
#[doc = "Antiwedge (regressive/meet) product of [`Bivector`] and [`Trivector`].\n\nThe antiwedge product `a v b` computes the meet of two subspaces,\nreturning the largest subspace contained in both. In projective geometry,\nthis finds intersections (e.g., where two planes meet to form a line)."]
impl<T: Float> Antiwedge<Trivector<T>> for Bivector<T> {
type Output = Bivector<T>;
#[inline]
fn antiwedge(&self, rhs: &Trivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.ps() * self.rz(),
rhs.ps() * self.ry(),
rhs.ps() * self.rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antiwedge<Trivector<T>> for Unit<Bivector<T>> {
type Output = Bivector<T>;
#[inline]
fn antiwedge(&self, rhs: &Trivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.ps() * self.as_inner().rz(),
rhs.ps() * self.as_inner().ry(),
rhs.ps() * self.as_inner().rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antiwedge<Unit<Trivector<T>>> for Bivector<T> {
type Output = Bivector<T>;
#[inline]
fn antiwedge(&self, rhs: &Unit<Trivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.as_inner().ps() * self.rz(),
rhs.as_inner().ps() * self.ry(),
rhs.as_inner().ps() * self.rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antiwedge<Unit<Trivector<T>>> for Unit<Bivector<T>> {
type Output = Bivector<T>;
#[inline]
fn antiwedge(&self, rhs: &Unit<Trivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.as_inner().ps() * self.as_inner().rz(),
rhs.as_inner().ps() * self.as_inner().ry(),
rhs.as_inner().ps() * self.as_inner().rx(),
)
}
}
#[doc = "Antiwedge (regressive/meet) product of [`Bivector`] and [`Vector`].\n\nThe antiwedge product `a v b` computes the meet of two subspaces,\nreturning the largest subspace contained in both. In projective geometry,\nthis finds intersections (e.g., where two planes meet to form a line)."]
impl<T: Float> Antiwedge<Vector<T>> for Bivector<T> {
type Output = Scalar<T>;
#[inline]
fn antiwedge(&self, rhs: &Vector<T>) -> Scalar<T> {
Scalar::new_unchecked(-(rhs.y() * self.ry()) + rhs.x() * self.rx() + rhs.z() * self.rz())
}
}
#[allow(unused_variables)]
impl<T: Float> Antiwedge<Vector<T>> for Unit<Bivector<T>> {
type Output = Scalar<T>;
#[inline]
fn antiwedge(&self, rhs: &Vector<T>) -> Scalar<T> {
Scalar::new_unchecked(
-(rhs.y() * self.as_inner().ry())
+ rhs.x() * self.as_inner().rx()
+ rhs.z() * self.as_inner().rz(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antiwedge<Unit<Vector<T>>> for Bivector<T> {
type Output = Scalar<T>;
#[inline]
fn antiwedge(&self, rhs: &Unit<Vector<T>>) -> Scalar<T> {
Scalar::new_unchecked(
-(rhs.as_inner().y() * self.ry())
+ rhs.as_inner().x() * self.rx()
+ rhs.as_inner().z() * self.rz(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antiwedge<Unit<Vector<T>>> for Unit<Bivector<T>> {
type Output = Scalar<T>;
#[inline]
fn antiwedge(&self, rhs: &Unit<Vector<T>>) -> Scalar<T> {
Scalar::new_unchecked(
-(rhs.as_inner().y() * self.as_inner().ry())
+ rhs.as_inner().x() * self.as_inner().rx()
+ rhs.as_inner().z() * self.as_inner().rz(),
)
}
}
#[doc = "Antiwedge (regressive/meet) product of [`Scalar`] and [`Trivector`].\n\nThe antiwedge product `a v b` computes the meet of two subspaces,\nreturning the largest subspace contained in both. In projective geometry,\nthis finds intersections (e.g., where two planes meet to form a line)."]
impl<T: Float> Antiwedge<Trivector<T>> for Scalar<T> {
type Output = Scalar<T>;
#[inline]
fn antiwedge(&self, rhs: &Trivector<T>) -> Scalar<T> {
Scalar::new_unchecked(rhs.ps() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Antiwedge<Trivector<T>> for Unit<Scalar<T>> {
type Output = Scalar<T>;
#[inline]
fn antiwedge(&self, rhs: &Trivector<T>) -> Scalar<T> {
Scalar::new_unchecked(rhs.ps() * self.as_inner().s())
}
}
#[allow(unused_variables)]
impl<T: Float> Antiwedge<Unit<Trivector<T>>> for Scalar<T> {
type Output = Scalar<T>;
#[inline]
fn antiwedge(&self, rhs: &Unit<Trivector<T>>) -> Scalar<T> {
Scalar::new_unchecked(rhs.as_inner().ps() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Antiwedge<Unit<Trivector<T>>> for Unit<Scalar<T>> {
type Output = Scalar<T>;
#[inline]
fn antiwedge(&self, rhs: &Unit<Trivector<T>>) -> Scalar<T> {
Scalar::new_unchecked(rhs.as_inner().ps() * self.as_inner().s())
}
}
#[doc = "Antiwedge (regressive/meet) product of [`Trivector`] and [`Bivector`].\n\nThe antiwedge product `a v b` computes the meet of two subspaces,\nreturning the largest subspace contained in both. In projective geometry,\nthis finds intersections (e.g., where two planes meet to form a line)."]
impl<T: Float> Antiwedge<Bivector<T>> for Trivector<T> {
type Output = Bivector<T>;
#[inline]
fn antiwedge(&self, rhs: &Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.rz() * self.ps(),
rhs.ry() * self.ps(),
rhs.rx() * self.ps(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antiwedge<Bivector<T>> for Unit<Trivector<T>> {
type Output = Bivector<T>;
#[inline]
fn antiwedge(&self, rhs: &Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.rz() * self.as_inner().ps(),
rhs.ry() * self.as_inner().ps(),
rhs.rx() * self.as_inner().ps(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antiwedge<Unit<Bivector<T>>> for Trivector<T> {
type Output = Bivector<T>;
#[inline]
fn antiwedge(&self, rhs: &Unit<Bivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.as_inner().rz() * self.ps(),
rhs.as_inner().ry() * self.ps(),
rhs.as_inner().rx() * self.ps(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antiwedge<Unit<Bivector<T>>> for Unit<Trivector<T>> {
type Output = Bivector<T>;
#[inline]
fn antiwedge(&self, rhs: &Unit<Bivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.as_inner().rz() * self.as_inner().ps(),
rhs.as_inner().ry() * self.as_inner().ps(),
rhs.as_inner().rx() * self.as_inner().ps(),
)
}
}
#[doc = "Antiwedge (regressive/meet) product of [`Trivector`] and [`Scalar`].\n\nThe antiwedge product `a v b` computes the meet of two subspaces,\nreturning the largest subspace contained in both. In projective geometry,\nthis finds intersections (e.g., where two planes meet to form a line)."]
impl<T: Float> Antiwedge<Scalar<T>> for Trivector<T> {
type Output = Scalar<T>;
#[inline]
fn antiwedge(&self, rhs: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(rhs.s() * self.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> Antiwedge<Scalar<T>> for Unit<Trivector<T>> {
type Output = Scalar<T>;
#[inline]
fn antiwedge(&self, rhs: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(rhs.s() * self.as_inner().ps())
}
}
#[allow(unused_variables)]
impl<T: Float> Antiwedge<Unit<Scalar<T>>> for Trivector<T> {
type Output = Scalar<T>;
#[inline]
fn antiwedge(&self, rhs: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(rhs.as_inner().s() * self.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> Antiwedge<Unit<Scalar<T>>> for Unit<Trivector<T>> {
type Output = Scalar<T>;
#[inline]
fn antiwedge(&self, rhs: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(rhs.as_inner().s() * self.as_inner().ps())
}
}
#[doc = "Antiwedge (regressive/meet) product of [`Trivector`] and [`Trivector`].\n\nThe antiwedge product `a v b` computes the meet of two subspaces,\nreturning the largest subspace contained in both. In projective geometry,\nthis finds intersections (e.g., where two planes meet to form a line)."]
impl<T: Float> Antiwedge<Trivector<T>> for Trivector<T> {
type Output = Trivector<T>;
#[inline]
fn antiwedge(&self, rhs: &Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(rhs.ps() * self.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> Antiwedge<Trivector<T>> for Unit<Trivector<T>> {
type Output = Trivector<T>;
#[inline]
fn antiwedge(&self, rhs: &Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(rhs.ps() * self.as_inner().ps())
}
}
#[allow(unused_variables)]
impl<T: Float> Antiwedge<Unit<Trivector<T>>> for Trivector<T> {
type Output = Trivector<T>;
#[inline]
fn antiwedge(&self, rhs: &Unit<Trivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(rhs.as_inner().ps() * self.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> Antiwedge<Unit<Trivector<T>>> for Unit<Trivector<T>> {
type Output = Trivector<T>;
#[inline]
fn antiwedge(&self, rhs: &Unit<Trivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(rhs.as_inner().ps() * self.as_inner().ps())
}
}
#[doc = "Antiwedge (regressive/meet) product of [`Trivector`] and [`Vector`].\n\nThe antiwedge product `a v b` computes the meet of two subspaces,\nreturning the largest subspace contained in both. In projective geometry,\nthis finds intersections (e.g., where two planes meet to form a line)."]
impl<T: Float> Antiwedge<Vector<T>> for Trivector<T> {
type Output = Vector<T>;
#[inline]
fn antiwedge(&self, rhs: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(
rhs.x() * self.ps(),
rhs.y() * self.ps(),
rhs.z() * self.ps(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antiwedge<Vector<T>> for Unit<Trivector<T>> {
type Output = Vector<T>;
#[inline]
fn antiwedge(&self, rhs: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(
rhs.x() * self.as_inner().ps(),
rhs.y() * self.as_inner().ps(),
rhs.z() * self.as_inner().ps(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antiwedge<Unit<Vector<T>>> for Trivector<T> {
type Output = Vector<T>;
#[inline]
fn antiwedge(&self, rhs: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
rhs.as_inner().x() * self.ps(),
rhs.as_inner().y() * self.ps(),
rhs.as_inner().z() * self.ps(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antiwedge<Unit<Vector<T>>> for Unit<Trivector<T>> {
type Output = Vector<T>;
#[inline]
fn antiwedge(&self, rhs: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
rhs.as_inner().x() * self.as_inner().ps(),
rhs.as_inner().y() * self.as_inner().ps(),
rhs.as_inner().z() * self.as_inner().ps(),
)
}
}
#[doc = "Antiwedge (regressive/meet) product of [`Vector`] and [`Bivector`].\n\nThe antiwedge product `a v b` computes the meet of two subspaces,\nreturning the largest subspace contained in both. In projective geometry,\nthis finds intersections (e.g., where two planes meet to form a line)."]
impl<T: Float> Antiwedge<Bivector<T>> for Vector<T> {
type Output = Scalar<T>;
#[inline]
fn antiwedge(&self, rhs: &Bivector<T>) -> Scalar<T> {
Scalar::new_unchecked(-(rhs.ry() * self.y()) + rhs.rx() * self.x() + rhs.rz() * self.z())
}
}
#[allow(unused_variables)]
impl<T: Float> Antiwedge<Bivector<T>> for Unit<Vector<T>> {
type Output = Scalar<T>;
#[inline]
fn antiwedge(&self, rhs: &Bivector<T>) -> Scalar<T> {
Scalar::new_unchecked(
-(rhs.ry() * self.as_inner().y())
+ rhs.rx() * self.as_inner().x()
+ rhs.rz() * self.as_inner().z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antiwedge<Unit<Bivector<T>>> for Vector<T> {
type Output = Scalar<T>;
#[inline]
fn antiwedge(&self, rhs: &Unit<Bivector<T>>) -> Scalar<T> {
Scalar::new_unchecked(
-(rhs.as_inner().ry() * self.y())
+ rhs.as_inner().rx() * self.x()
+ rhs.as_inner().rz() * self.z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antiwedge<Unit<Bivector<T>>> for Unit<Vector<T>> {
type Output = Scalar<T>;
#[inline]
fn antiwedge(&self, rhs: &Unit<Bivector<T>>) -> Scalar<T> {
Scalar::new_unchecked(
-(rhs.as_inner().ry() * self.as_inner().y())
+ rhs.as_inner().rx() * self.as_inner().x()
+ rhs.as_inner().rz() * self.as_inner().z(),
)
}
}
#[doc = "Antiwedge (regressive/meet) product of [`Vector`] and [`Trivector`].\n\nThe antiwedge product `a v b` computes the meet of two subspaces,\nreturning the largest subspace contained in both. In projective geometry,\nthis finds intersections (e.g., where two planes meet to form a line)."]
impl<T: Float> Antiwedge<Trivector<T>> for Vector<T> {
type Output = Vector<T>;
#[inline]
fn antiwedge(&self, rhs: &Trivector<T>) -> Vector<T> {
Vector::new_unchecked(
rhs.ps() * self.x(),
rhs.ps() * self.y(),
rhs.ps() * self.z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antiwedge<Trivector<T>> for Unit<Vector<T>> {
type Output = Vector<T>;
#[inline]
fn antiwedge(&self, rhs: &Trivector<T>) -> Vector<T> {
Vector::new_unchecked(
rhs.ps() * self.as_inner().x(),
rhs.ps() * self.as_inner().y(),
rhs.ps() * self.as_inner().z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antiwedge<Unit<Trivector<T>>> for Vector<T> {
type Output = Vector<T>;
#[inline]
fn antiwedge(&self, rhs: &Unit<Trivector<T>>) -> Vector<T> {
Vector::new_unchecked(
rhs.as_inner().ps() * self.x(),
rhs.as_inner().ps() * self.y(),
rhs.as_inner().ps() * self.z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antiwedge<Unit<Trivector<T>>> for Unit<Vector<T>> {
type Output = Vector<T>;
#[inline]
fn antiwedge(&self, rhs: &Unit<Trivector<T>>) -> Vector<T> {
Vector::new_unchecked(
rhs.as_inner().ps() * self.as_inner().x(),
rhs.as_inner().ps() * self.as_inner().y(),
rhs.as_inner().ps() * self.as_inner().z(),
)
}
}
#[doc = "Left contraction of [`Bivector`] into [`Bivector`].\n\nThe left contraction `a _| b` projects `a` onto `b`, returning the\ncomponent of `b` orthogonal to `a`. The result grade is grade(b) - grade(a)\n(or zero if grade(a) > grade(b))."]
impl<T: Float> LeftContract<Bivector<T>> for Bivector<T> {
type Output = Scalar<T>;
#[inline]
fn left_contract(&self, rhs: &Bivector<T>) -> Scalar<T> {
Scalar::new_unchecked(
-(rhs.rx() * self.rx()) + -(rhs.ry() * self.ry()) + -(rhs.rz() * self.rz()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> LeftContract<Bivector<T>> for Unit<Bivector<T>> {
type Output = Scalar<T>;
#[inline]
fn left_contract(&self, rhs: &Bivector<T>) -> Scalar<T> {
Scalar::new_unchecked(
-(rhs.rx() * self.as_inner().rx())
+ -(rhs.ry() * self.as_inner().ry())
+ -(rhs.rz() * self.as_inner().rz()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> LeftContract<Unit<Bivector<T>>> for Bivector<T> {
type Output = Scalar<T>;
#[inline]
fn left_contract(&self, rhs: &Unit<Bivector<T>>) -> Scalar<T> {
Scalar::new_unchecked(
-(rhs.as_inner().rx() * self.rx())
+ -(rhs.as_inner().ry() * self.ry())
+ -(rhs.as_inner().rz() * self.rz()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> LeftContract<Unit<Bivector<T>>> for Unit<Bivector<T>> {
type Output = Scalar<T>;
#[inline]
fn left_contract(&self, rhs: &Unit<Bivector<T>>) -> Scalar<T> {
Scalar::new_unchecked(
-(rhs.as_inner().rx() * self.as_inner().rx())
+ -(rhs.as_inner().ry() * self.as_inner().ry())
+ -(rhs.as_inner().rz() * self.as_inner().rz()),
)
}
}
#[doc = "Left contraction of [`Bivector`] into [`Trivector`].\n\nThe left contraction `a _| b` projects `a` onto `b`, returning the\ncomponent of `b` orthogonal to `a`. The result grade is grade(b) - grade(a)\n(or zero if grade(a) > grade(b))."]
impl<T: Float> LeftContract<Trivector<T>> for Bivector<T> {
type Output = Vector<T>;
#[inline]
fn left_contract(&self, rhs: &Trivector<T>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.ps() * self.rx()),
rhs.ps() * self.ry(),
-(rhs.ps() * self.rz()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> LeftContract<Trivector<T>> for Unit<Bivector<T>> {
type Output = Vector<T>;
#[inline]
fn left_contract(&self, rhs: &Trivector<T>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.ps() * self.as_inner().rx()),
rhs.ps() * self.as_inner().ry(),
-(rhs.ps() * self.as_inner().rz()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> LeftContract<Unit<Trivector<T>>> for Bivector<T> {
type Output = Vector<T>;
#[inline]
fn left_contract(&self, rhs: &Unit<Trivector<T>>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.as_inner().ps() * self.rx()),
rhs.as_inner().ps() * self.ry(),
-(rhs.as_inner().ps() * self.rz()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> LeftContract<Unit<Trivector<T>>> for Unit<Bivector<T>> {
type Output = Vector<T>;
#[inline]
fn left_contract(&self, rhs: &Unit<Trivector<T>>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.as_inner().ps() * self.as_inner().rx()),
rhs.as_inner().ps() * self.as_inner().ry(),
-(rhs.as_inner().ps() * self.as_inner().rz()),
)
}
}
#[doc = "Left contraction of [`Scalar`] into [`Bivector`].\n\nThe left contraction `a _| b` projects `a` onto `b`, returning the\ncomponent of `b` orthogonal to `a`. The result grade is grade(b) - grade(a)\n(or zero if grade(a) > grade(b))."]
impl<T: Float> LeftContract<Bivector<T>> for Scalar<T> {
type Output = Bivector<T>;
#[inline]
fn left_contract(&self, rhs: &Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.rz() * self.s(),
rhs.ry() * self.s(),
rhs.rx() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> LeftContract<Bivector<T>> for Unit<Scalar<T>> {
type Output = Bivector<T>;
#[inline]
fn left_contract(&self, rhs: &Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.rz() * self.as_inner().s(),
rhs.ry() * self.as_inner().s(),
rhs.rx() * self.as_inner().s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> LeftContract<Unit<Bivector<T>>> for Scalar<T> {
type Output = Bivector<T>;
#[inline]
fn left_contract(&self, rhs: &Unit<Bivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.as_inner().rz() * self.s(),
rhs.as_inner().ry() * self.s(),
rhs.as_inner().rx() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> LeftContract<Unit<Bivector<T>>> for Unit<Scalar<T>> {
type Output = Bivector<T>;
#[inline]
fn left_contract(&self, rhs: &Unit<Bivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.as_inner().rz() * self.as_inner().s(),
rhs.as_inner().ry() * self.as_inner().s(),
rhs.as_inner().rx() * self.as_inner().s(),
)
}
}
#[doc = "Left contraction of [`Scalar`] into [`Scalar`].\n\nThe left contraction `a _| b` projects `a` onto `b`, returning the\ncomponent of `b` orthogonal to `a`. The result grade is grade(b) - grade(a)\n(or zero if grade(a) > grade(b))."]
impl<T: Float> LeftContract<Scalar<T>> for Scalar<T> {
type Output = Scalar<T>;
#[inline]
fn left_contract(&self, rhs: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(rhs.s() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> LeftContract<Scalar<T>> for Unit<Scalar<T>> {
type Output = Scalar<T>;
#[inline]
fn left_contract(&self, rhs: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(rhs.s() * self.as_inner().s())
}
}
#[allow(unused_variables)]
impl<T: Float> LeftContract<Unit<Scalar<T>>> for Scalar<T> {
type Output = Scalar<T>;
#[inline]
fn left_contract(&self, rhs: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(rhs.as_inner().s() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> LeftContract<Unit<Scalar<T>>> for Unit<Scalar<T>> {
type Output = Scalar<T>;
#[inline]
fn left_contract(&self, rhs: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(rhs.as_inner().s() * self.as_inner().s())
}
}
#[doc = "Left contraction of [`Scalar`] into [`Trivector`].\n\nThe left contraction `a _| b` projects `a` onto `b`, returning the\ncomponent of `b` orthogonal to `a`. The result grade is grade(b) - grade(a)\n(or zero if grade(a) > grade(b))."]
impl<T: Float> LeftContract<Trivector<T>> for Scalar<T> {
type Output = Trivector<T>;
#[inline]
fn left_contract(&self, rhs: &Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(rhs.ps() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> LeftContract<Trivector<T>> for Unit<Scalar<T>> {
type Output = Trivector<T>;
#[inline]
fn left_contract(&self, rhs: &Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(rhs.ps() * self.as_inner().s())
}
}
#[allow(unused_variables)]
impl<T: Float> LeftContract<Unit<Trivector<T>>> for Scalar<T> {
type Output = Trivector<T>;
#[inline]
fn left_contract(&self, rhs: &Unit<Trivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(rhs.as_inner().ps() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> LeftContract<Unit<Trivector<T>>> for Unit<Scalar<T>> {
type Output = Trivector<T>;
#[inline]
fn left_contract(&self, rhs: &Unit<Trivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(rhs.as_inner().ps() * self.as_inner().s())
}
}
#[doc = "Left contraction of [`Scalar`] into [`Vector`].\n\nThe left contraction `a _| b` projects `a` onto `b`, returning the\ncomponent of `b` orthogonal to `a`. The result grade is grade(b) - grade(a)\n(or zero if grade(a) > grade(b))."]
impl<T: Float> LeftContract<Vector<T>> for Scalar<T> {
type Output = Vector<T>;
#[inline]
fn left_contract(&self, rhs: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(rhs.x() * self.s(), rhs.y() * self.s(), rhs.z() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> LeftContract<Vector<T>> for Unit<Scalar<T>> {
type Output = Vector<T>;
#[inline]
fn left_contract(&self, rhs: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(
rhs.x() * self.as_inner().s(),
rhs.y() * self.as_inner().s(),
rhs.z() * self.as_inner().s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> LeftContract<Unit<Vector<T>>> for Scalar<T> {
type Output = Vector<T>;
#[inline]
fn left_contract(&self, rhs: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
rhs.as_inner().x() * self.s(),
rhs.as_inner().y() * self.s(),
rhs.as_inner().z() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> LeftContract<Unit<Vector<T>>> for Unit<Scalar<T>> {
type Output = Vector<T>;
#[inline]
fn left_contract(&self, rhs: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
rhs.as_inner().x() * self.as_inner().s(),
rhs.as_inner().y() * self.as_inner().s(),
rhs.as_inner().z() * self.as_inner().s(),
)
}
}
#[doc = "Left contraction of [`Trivector`] into [`Trivector`].\n\nThe left contraction `a _| b` projects `a` onto `b`, returning the\ncomponent of `b` orthogonal to `a`. The result grade is grade(b) - grade(a)\n(or zero if grade(a) > grade(b))."]
impl<T: Float> LeftContract<Trivector<T>> for Trivector<T> {
type Output = Scalar<T>;
#[inline]
fn left_contract(&self, rhs: &Trivector<T>) -> Scalar<T> {
Scalar::new_unchecked(-(rhs.ps() * self.ps()))
}
}
#[allow(unused_variables)]
impl<T: Float> LeftContract<Trivector<T>> for Unit<Trivector<T>> {
type Output = Scalar<T>;
#[inline]
fn left_contract(&self, rhs: &Trivector<T>) -> Scalar<T> {
Scalar::new_unchecked(-(rhs.ps() * self.as_inner().ps()))
}
}
#[allow(unused_variables)]
impl<T: Float> LeftContract<Unit<Trivector<T>>> for Trivector<T> {
type Output = Scalar<T>;
#[inline]
fn left_contract(&self, rhs: &Unit<Trivector<T>>) -> Scalar<T> {
Scalar::new_unchecked(-(rhs.as_inner().ps() * self.ps()))
}
}
#[allow(unused_variables)]
impl<T: Float> LeftContract<Unit<Trivector<T>>> for Unit<Trivector<T>> {
type Output = Scalar<T>;
#[inline]
fn left_contract(&self, rhs: &Unit<Trivector<T>>) -> Scalar<T> {
Scalar::new_unchecked(-(rhs.as_inner().ps() * self.as_inner().ps()))
}
}
#[doc = "Left contraction of [`Vector`] into [`Bivector`].\n\nThe left contraction `a _| b` projects `a` onto `b`, returning the\ncomponent of `b` orthogonal to `a`. The result grade is grade(b) - grade(a)\n(or zero if grade(a) > grade(b))."]
impl<T: Float> LeftContract<Bivector<T>> for Vector<T> {
type Output = Vector<T>;
#[inline]
fn left_contract(&self, rhs: &Bivector<T>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.ry() * self.z()) + -(rhs.rz() * self.y()),
-(rhs.rx() * self.z()) + rhs.rz() * self.x(),
rhs.rx() * self.y() + rhs.ry() * self.x(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> LeftContract<Bivector<T>> for Unit<Vector<T>> {
type Output = Vector<T>;
#[inline]
fn left_contract(&self, rhs: &Bivector<T>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.ry() * self.as_inner().z()) + -(rhs.rz() * self.as_inner().y()),
-(rhs.rx() * self.as_inner().z()) + rhs.rz() * self.as_inner().x(),
rhs.rx() * self.as_inner().y() + rhs.ry() * self.as_inner().x(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> LeftContract<Unit<Bivector<T>>> for Vector<T> {
type Output = Vector<T>;
#[inline]
fn left_contract(&self, rhs: &Unit<Bivector<T>>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.as_inner().ry() * self.z()) + -(rhs.as_inner().rz() * self.y()),
-(rhs.as_inner().rx() * self.z()) + rhs.as_inner().rz() * self.x(),
rhs.as_inner().rx() * self.y() + rhs.as_inner().ry() * self.x(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> LeftContract<Unit<Bivector<T>>> for Unit<Vector<T>> {
type Output = Vector<T>;
#[inline]
fn left_contract(&self, rhs: &Unit<Bivector<T>>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.as_inner().ry() * self.as_inner().z())
+ -(rhs.as_inner().rz() * self.as_inner().y()),
-(rhs.as_inner().rx() * self.as_inner().z())
+ rhs.as_inner().rz() * self.as_inner().x(),
rhs.as_inner().rx() * self.as_inner().y() + rhs.as_inner().ry() * self.as_inner().x(),
)
}
}
#[doc = "Left contraction of [`Vector`] into [`Trivector`].\n\nThe left contraction `a _| b` projects `a` onto `b`, returning the\ncomponent of `b` orthogonal to `a`. The result grade is grade(b) - grade(a)\n(or zero if grade(a) > grade(b))."]
impl<T: Float> LeftContract<Trivector<T>> for Vector<T> {
type Output = Bivector<T>;
#[inline]
fn left_contract(&self, rhs: &Trivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.ps() * self.z(),
-(rhs.ps() * self.y()),
rhs.ps() * self.x(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> LeftContract<Trivector<T>> for Unit<Vector<T>> {
type Output = Bivector<T>;
#[inline]
fn left_contract(&self, rhs: &Trivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.ps() * self.as_inner().z(),
-(rhs.ps() * self.as_inner().y()),
rhs.ps() * self.as_inner().x(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> LeftContract<Unit<Trivector<T>>> for Vector<T> {
type Output = Bivector<T>;
#[inline]
fn left_contract(&self, rhs: &Unit<Trivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.as_inner().ps() * self.z(),
-(rhs.as_inner().ps() * self.y()),
rhs.as_inner().ps() * self.x(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> LeftContract<Unit<Trivector<T>>> for Unit<Vector<T>> {
type Output = Bivector<T>;
#[inline]
fn left_contract(&self, rhs: &Unit<Trivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.as_inner().ps() * self.as_inner().z(),
-(rhs.as_inner().ps() * self.as_inner().y()),
rhs.as_inner().ps() * self.as_inner().x(),
)
}
}
#[doc = "Left contraction of [`Vector`] into [`Vector`].\n\nThe left contraction `a _| b` projects `a` onto `b`, returning the\ncomponent of `b` orthogonal to `a`. The result grade is grade(b) - grade(a)\n(or zero if grade(a) > grade(b))."]
impl<T: Float> LeftContract<Vector<T>> for Vector<T> {
type Output = Scalar<T>;
#[inline]
fn left_contract(&self, rhs: &Vector<T>) -> Scalar<T> {
Scalar::new_unchecked(rhs.x() * self.x() + rhs.y() * self.y() + rhs.z() * self.z())
}
}
#[allow(unused_variables)]
impl<T: Float> LeftContract<Vector<T>> for Unit<Vector<T>> {
type Output = Scalar<T>;
#[inline]
fn left_contract(&self, rhs: &Vector<T>) -> Scalar<T> {
Scalar::new_unchecked(
rhs.x() * self.as_inner().x()
+ rhs.y() * self.as_inner().y()
+ rhs.z() * self.as_inner().z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> LeftContract<Unit<Vector<T>>> for Vector<T> {
type Output = Scalar<T>;
#[inline]
fn left_contract(&self, rhs: &Unit<Vector<T>>) -> Scalar<T> {
Scalar::new_unchecked(
rhs.as_inner().x() * self.x()
+ rhs.as_inner().y() * self.y()
+ rhs.as_inner().z() * self.z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> LeftContract<Unit<Vector<T>>> for Unit<Vector<T>> {
type Output = Scalar<T>;
#[inline]
fn left_contract(&self, rhs: &Unit<Vector<T>>) -> Scalar<T> {
Scalar::new_unchecked(
rhs.as_inner().x() * self.as_inner().x()
+ rhs.as_inner().y() * self.as_inner().y()
+ rhs.as_inner().z() * self.as_inner().z(),
)
}
}
#[doc = "Right contraction of [`Bivector`] by [`Bivector`].\n\nThe right contraction `a |_ b` projects `b` onto `a`, returning the\ncomponent of `a` orthogonal to `b`. The result grade is grade(a) - grade(b)\n(or zero if grade(b) > grade(a))."]
impl<T: Float> RightContract<Bivector<T>> for Bivector<T> {
type Output = Scalar<T>;
#[inline]
fn right_contract(&self, rhs: &Bivector<T>) -> Scalar<T> {
Scalar::new_unchecked(
-(rhs.rx() * self.rx()) + -(rhs.ry() * self.ry()) + -(rhs.rz() * self.rz()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> RightContract<Bivector<T>> for Unit<Bivector<T>> {
type Output = Scalar<T>;
#[inline]
fn right_contract(&self, rhs: &Bivector<T>) -> Scalar<T> {
Scalar::new_unchecked(
-(rhs.rx() * self.as_inner().rx())
+ -(rhs.ry() * self.as_inner().ry())
+ -(rhs.rz() * self.as_inner().rz()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> RightContract<Unit<Bivector<T>>> for Bivector<T> {
type Output = Scalar<T>;
#[inline]
fn right_contract(&self, rhs: &Unit<Bivector<T>>) -> Scalar<T> {
Scalar::new_unchecked(
-(rhs.as_inner().rx() * self.rx())
+ -(rhs.as_inner().ry() * self.ry())
+ -(rhs.as_inner().rz() * self.rz()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> RightContract<Unit<Bivector<T>>> for Unit<Bivector<T>> {
type Output = Scalar<T>;
#[inline]
fn right_contract(&self, rhs: &Unit<Bivector<T>>) -> Scalar<T> {
Scalar::new_unchecked(
-(rhs.as_inner().rx() * self.as_inner().rx())
+ -(rhs.as_inner().ry() * self.as_inner().ry())
+ -(rhs.as_inner().rz() * self.as_inner().rz()),
)
}
}
#[doc = "Right contraction of [`Bivector`] by [`Scalar`].\n\nThe right contraction `a |_ b` projects `b` onto `a`, returning the\ncomponent of `a` orthogonal to `b`. The result grade is grade(a) - grade(b)\n(or zero if grade(b) > grade(a))."]
impl<T: Float> RightContract<Scalar<T>> for Bivector<T> {
type Output = Bivector<T>;
#[inline]
fn right_contract(&self, rhs: &Scalar<T>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.s() * self.rz(),
rhs.s() * self.ry(),
rhs.s() * self.rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> RightContract<Scalar<T>> for Unit<Bivector<T>> {
type Output = Bivector<T>;
#[inline]
fn right_contract(&self, rhs: &Scalar<T>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.s() * self.as_inner().rz(),
rhs.s() * self.as_inner().ry(),
rhs.s() * self.as_inner().rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> RightContract<Unit<Scalar<T>>> for Bivector<T> {
type Output = Bivector<T>;
#[inline]
fn right_contract(&self, rhs: &Unit<Scalar<T>>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.as_inner().s() * self.rz(),
rhs.as_inner().s() * self.ry(),
rhs.as_inner().s() * self.rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> RightContract<Unit<Scalar<T>>> for Unit<Bivector<T>> {
type Output = Bivector<T>;
#[inline]
fn right_contract(&self, rhs: &Unit<Scalar<T>>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.as_inner().s() * self.as_inner().rz(),
rhs.as_inner().s() * self.as_inner().ry(),
rhs.as_inner().s() * self.as_inner().rx(),
)
}
}
#[doc = "Right contraction of [`Bivector`] by [`Vector`].\n\nThe right contraction `a |_ b` projects `b` onto `a`, returning the\ncomponent of `a` orthogonal to `b`. The result grade is grade(a) - grade(b)\n(or zero if grade(b) > grade(a))."]
impl<T: Float> RightContract<Vector<T>> for Bivector<T> {
type Output = Vector<T>;
#[inline]
fn right_contract(&self, rhs: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(
rhs.y() * self.rz() + rhs.z() * self.ry(),
-(rhs.x() * self.rz()) + rhs.z() * self.rx(),
-(rhs.x() * self.ry()) + -(rhs.y() * self.rx()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> RightContract<Vector<T>> for Unit<Bivector<T>> {
type Output = Vector<T>;
#[inline]
fn right_contract(&self, rhs: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(
rhs.y() * self.as_inner().rz() + rhs.z() * self.as_inner().ry(),
-(rhs.x() * self.as_inner().rz()) + rhs.z() * self.as_inner().rx(),
-(rhs.x() * self.as_inner().ry()) + -(rhs.y() * self.as_inner().rx()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> RightContract<Unit<Vector<T>>> for Bivector<T> {
type Output = Vector<T>;
#[inline]
fn right_contract(&self, rhs: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
rhs.as_inner().y() * self.rz() + rhs.as_inner().z() * self.ry(),
-(rhs.as_inner().x() * self.rz()) + rhs.as_inner().z() * self.rx(),
-(rhs.as_inner().x() * self.ry()) + -(rhs.as_inner().y() * self.rx()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> RightContract<Unit<Vector<T>>> for Unit<Bivector<T>> {
type Output = Vector<T>;
#[inline]
fn right_contract(&self, rhs: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
rhs.as_inner().y() * self.as_inner().rz() + rhs.as_inner().z() * self.as_inner().ry(),
-(rhs.as_inner().x() * self.as_inner().rz())
+ rhs.as_inner().z() * self.as_inner().rx(),
-(rhs.as_inner().x() * self.as_inner().ry())
+ -(rhs.as_inner().y() * self.as_inner().rx()),
)
}
}
#[doc = "Right contraction of [`Scalar`] by [`Scalar`].\n\nThe right contraction `a |_ b` projects `b` onto `a`, returning the\ncomponent of `a` orthogonal to `b`. The result grade is grade(a) - grade(b)\n(or zero if grade(b) > grade(a))."]
impl<T: Float> RightContract<Scalar<T>> for Scalar<T> {
type Output = Scalar<T>;
#[inline]
fn right_contract(&self, rhs: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(rhs.s() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> RightContract<Scalar<T>> for Unit<Scalar<T>> {
type Output = Scalar<T>;
#[inline]
fn right_contract(&self, rhs: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(rhs.s() * self.as_inner().s())
}
}
#[allow(unused_variables)]
impl<T: Float> RightContract<Unit<Scalar<T>>> for Scalar<T> {
type Output = Scalar<T>;
#[inline]
fn right_contract(&self, rhs: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(rhs.as_inner().s() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> RightContract<Unit<Scalar<T>>> for Unit<Scalar<T>> {
type Output = Scalar<T>;
#[inline]
fn right_contract(&self, rhs: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(rhs.as_inner().s() * self.as_inner().s())
}
}
#[doc = "Right contraction of [`Trivector`] by [`Bivector`].\n\nThe right contraction `a |_ b` projects `b` onto `a`, returning the\ncomponent of `a` orthogonal to `b`. The result grade is grade(a) - grade(b)\n(or zero if grade(b) > grade(a))."]
impl<T: Float> RightContract<Bivector<T>> for Trivector<T> {
type Output = Vector<T>;
#[inline]
fn right_contract(&self, rhs: &Bivector<T>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.rx() * self.ps()),
rhs.ry() * self.ps(),
-(rhs.rz() * self.ps()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> RightContract<Bivector<T>> for Unit<Trivector<T>> {
type Output = Vector<T>;
#[inline]
fn right_contract(&self, rhs: &Bivector<T>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.rx() * self.as_inner().ps()),
rhs.ry() * self.as_inner().ps(),
-(rhs.rz() * self.as_inner().ps()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> RightContract<Unit<Bivector<T>>> for Trivector<T> {
type Output = Vector<T>;
#[inline]
fn right_contract(&self, rhs: &Unit<Bivector<T>>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.as_inner().rx() * self.ps()),
rhs.as_inner().ry() * self.ps(),
-(rhs.as_inner().rz() * self.ps()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> RightContract<Unit<Bivector<T>>> for Unit<Trivector<T>> {
type Output = Vector<T>;
#[inline]
fn right_contract(&self, rhs: &Unit<Bivector<T>>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.as_inner().rx() * self.as_inner().ps()),
rhs.as_inner().ry() * self.as_inner().ps(),
-(rhs.as_inner().rz() * self.as_inner().ps()),
)
}
}
#[doc = "Right contraction of [`Trivector`] by [`Scalar`].\n\nThe right contraction `a |_ b` projects `b` onto `a`, returning the\ncomponent of `a` orthogonal to `b`. The result grade is grade(a) - grade(b)\n(or zero if grade(b) > grade(a))."]
impl<T: Float> RightContract<Scalar<T>> for Trivector<T> {
type Output = Trivector<T>;
#[inline]
fn right_contract(&self, rhs: &Scalar<T>) -> Trivector<T> {
Trivector::new_unchecked(rhs.s() * self.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> RightContract<Scalar<T>> for Unit<Trivector<T>> {
type Output = Trivector<T>;
#[inline]
fn right_contract(&self, rhs: &Scalar<T>) -> Trivector<T> {
Trivector::new_unchecked(rhs.s() * self.as_inner().ps())
}
}
#[allow(unused_variables)]
impl<T: Float> RightContract<Unit<Scalar<T>>> for Trivector<T> {
type Output = Trivector<T>;
#[inline]
fn right_contract(&self, rhs: &Unit<Scalar<T>>) -> Trivector<T> {
Trivector::new_unchecked(rhs.as_inner().s() * self.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> RightContract<Unit<Scalar<T>>> for Unit<Trivector<T>> {
type Output = Trivector<T>;
#[inline]
fn right_contract(&self, rhs: &Unit<Scalar<T>>) -> Trivector<T> {
Trivector::new_unchecked(rhs.as_inner().s() * self.as_inner().ps())
}
}
#[doc = "Right contraction of [`Trivector`] by [`Trivector`].\n\nThe right contraction `a |_ b` projects `b` onto `a`, returning the\ncomponent of `a` orthogonal to `b`. The result grade is grade(a) - grade(b)\n(or zero if grade(b) > grade(a))."]
impl<T: Float> RightContract<Trivector<T>> for Trivector<T> {
type Output = Scalar<T>;
#[inline]
fn right_contract(&self, rhs: &Trivector<T>) -> Scalar<T> {
Scalar::new_unchecked(-(rhs.ps() * self.ps()))
}
}
#[allow(unused_variables)]
impl<T: Float> RightContract<Trivector<T>> for Unit<Trivector<T>> {
type Output = Scalar<T>;
#[inline]
fn right_contract(&self, rhs: &Trivector<T>) -> Scalar<T> {
Scalar::new_unchecked(-(rhs.ps() * self.as_inner().ps()))
}
}
#[allow(unused_variables)]
impl<T: Float> RightContract<Unit<Trivector<T>>> for Trivector<T> {
type Output = Scalar<T>;
#[inline]
fn right_contract(&self, rhs: &Unit<Trivector<T>>) -> Scalar<T> {
Scalar::new_unchecked(-(rhs.as_inner().ps() * self.ps()))
}
}
#[allow(unused_variables)]
impl<T: Float> RightContract<Unit<Trivector<T>>> for Unit<Trivector<T>> {
type Output = Scalar<T>;
#[inline]
fn right_contract(&self, rhs: &Unit<Trivector<T>>) -> Scalar<T> {
Scalar::new_unchecked(-(rhs.as_inner().ps() * self.as_inner().ps()))
}
}
#[doc = "Right contraction of [`Trivector`] by [`Vector`].\n\nThe right contraction `a |_ b` projects `b` onto `a`, returning the\ncomponent of `a` orthogonal to `b`. The result grade is grade(a) - grade(b)\n(or zero if grade(b) > grade(a))."]
impl<T: Float> RightContract<Vector<T>> for Trivector<T> {
type Output = Bivector<T>;
#[inline]
fn right_contract(&self, rhs: &Vector<T>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.z() * self.ps(),
-(rhs.y() * self.ps()),
rhs.x() * self.ps(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> RightContract<Vector<T>> for Unit<Trivector<T>> {
type Output = Bivector<T>;
#[inline]
fn right_contract(&self, rhs: &Vector<T>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.z() * self.as_inner().ps(),
-(rhs.y() * self.as_inner().ps()),
rhs.x() * self.as_inner().ps(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> RightContract<Unit<Vector<T>>> for Trivector<T> {
type Output = Bivector<T>;
#[inline]
fn right_contract(&self, rhs: &Unit<Vector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.as_inner().z() * self.ps(),
-(rhs.as_inner().y() * self.ps()),
rhs.as_inner().x() * self.ps(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> RightContract<Unit<Vector<T>>> for Unit<Trivector<T>> {
type Output = Bivector<T>;
#[inline]
fn right_contract(&self, rhs: &Unit<Vector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.as_inner().z() * self.as_inner().ps(),
-(rhs.as_inner().y() * self.as_inner().ps()),
rhs.as_inner().x() * self.as_inner().ps(),
)
}
}
#[doc = "Right contraction of [`Vector`] by [`Scalar`].\n\nThe right contraction `a |_ b` projects `b` onto `a`, returning the\ncomponent of `a` orthogonal to `b`. The result grade is grade(a) - grade(b)\n(or zero if grade(b) > grade(a))."]
impl<T: Float> RightContract<Scalar<T>> for Vector<T> {
type Output = Vector<T>;
#[inline]
fn right_contract(&self, rhs: &Scalar<T>) -> Vector<T> {
Vector::new_unchecked(rhs.s() * self.x(), rhs.s() * self.y(), rhs.s() * self.z())
}
}
#[allow(unused_variables)]
impl<T: Float> RightContract<Scalar<T>> for Unit<Vector<T>> {
type Output = Vector<T>;
#[inline]
fn right_contract(&self, rhs: &Scalar<T>) -> Vector<T> {
Vector::new_unchecked(
rhs.s() * self.as_inner().x(),
rhs.s() * self.as_inner().y(),
rhs.s() * self.as_inner().z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> RightContract<Unit<Scalar<T>>> for Vector<T> {
type Output = Vector<T>;
#[inline]
fn right_contract(&self, rhs: &Unit<Scalar<T>>) -> Vector<T> {
Vector::new_unchecked(
rhs.as_inner().s() * self.x(),
rhs.as_inner().s() * self.y(),
rhs.as_inner().s() * self.z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> RightContract<Unit<Scalar<T>>> for Unit<Vector<T>> {
type Output = Vector<T>;
#[inline]
fn right_contract(&self, rhs: &Unit<Scalar<T>>) -> Vector<T> {
Vector::new_unchecked(
rhs.as_inner().s() * self.as_inner().x(),
rhs.as_inner().s() * self.as_inner().y(),
rhs.as_inner().s() * self.as_inner().z(),
)
}
}
#[doc = "Right contraction of [`Vector`] by [`Vector`].\n\nThe right contraction `a |_ b` projects `b` onto `a`, returning the\ncomponent of `a` orthogonal to `b`. The result grade is grade(a) - grade(b)\n(or zero if grade(b) > grade(a))."]
impl<T: Float> RightContract<Vector<T>> for Vector<T> {
type Output = Scalar<T>;
#[inline]
fn right_contract(&self, rhs: &Vector<T>) -> Scalar<T> {
Scalar::new_unchecked(rhs.x() * self.x() + rhs.y() * self.y() + rhs.z() * self.z())
}
}
#[allow(unused_variables)]
impl<T: Float> RightContract<Vector<T>> for Unit<Vector<T>> {
type Output = Scalar<T>;
#[inline]
fn right_contract(&self, rhs: &Vector<T>) -> Scalar<T> {
Scalar::new_unchecked(
rhs.x() * self.as_inner().x()
+ rhs.y() * self.as_inner().y()
+ rhs.z() * self.as_inner().z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> RightContract<Unit<Vector<T>>> for Vector<T> {
type Output = Scalar<T>;
#[inline]
fn right_contract(&self, rhs: &Unit<Vector<T>>) -> Scalar<T> {
Scalar::new_unchecked(
rhs.as_inner().x() * self.x()
+ rhs.as_inner().y() * self.y()
+ rhs.as_inner().z() * self.z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> RightContract<Unit<Vector<T>>> for Unit<Vector<T>> {
type Output = Scalar<T>;
#[inline]
fn right_contract(&self, rhs: &Unit<Vector<T>>) -> Scalar<T> {
Scalar::new_unchecked(
rhs.as_inner().x() * self.as_inner().x()
+ rhs.as_inner().y() * self.as_inner().y()
+ rhs.as_inner().z() * self.as_inner().z(),
)
}
}
#[doc = "Sandwich product: [`Bivector`] x [`Bivector`] x rev([`Bivector`]).\n\nThe sandwich product `v x a x rev(v)` applies the transformation\nrepresented by the versor `v` to the operand `a`. For rotors, this\nperforms rotation; for motors, it performs rigid body transformation."]
#[allow(unused_variables)]
impl<T: Float> Sandwich<Bivector<T>> for Bivector<T> {
type Output = Bivector<T>;
#[inline]
fn sandwich(&self, operand: &Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
self.rx() * operand.rx() * self.rz() - self.rx() * operand.rz() * self.rx()
+ self.ry() * operand.ry() * self.rz()
- self.ry() * operand.rz() * self.ry()
+ self.rz() * operand.rx() * self.rx()
+ self.rz() * operand.ry() * self.ry()
+ self.rz() * operand.rz() * self.rz(),
self.rx() * operand.rx() * self.ry() - self.rx() * operand.ry() * self.rx()
+ self.ry() * operand.rx() * self.rx()
+ self.ry() * operand.ry() * self.ry()
+ self.ry() * operand.rz() * self.rz()
- self.rz() * operand.ry() * self.rz()
+ self.rz() * operand.rz() * self.ry(),
self.rx() * operand.rx() * self.rx()
+ self.rx() * operand.ry() * self.ry()
+ self.rx() * operand.rz() * self.rz()
- self.ry() * operand.rx() * self.ry()
+ self.ry() * operand.ry() * self.rx()
- self.rz() * operand.rx() * self.rz()
+ self.rz() * operand.rz() * self.rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Bivector<T>> for Unit<Bivector<T>> {
type Output = Bivector<T>;
#[inline]
fn sandwich(&self, operand: &Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
-T::TWO * operand.rz() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.rz() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.rx() * self.as_inner().rx() * self.as_inner().rz()
+ T::TWO * operand.ry() * self.as_inner().ry() * self.as_inner().rz()
+ operand.rz(),
-(operand.ry())
+ T::TWO * operand.rx() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.ry() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.rz() * self.as_inner().ry() * self.as_inner().rz(),
-(operand.rx())
+ T::TWO * operand.rx() * self.as_inner().rx() * self.as_inner().rx()
+ T::TWO * operand.ry() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.rz() * self.as_inner().rx() * self.as_inner().rz(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Bivector<T>>> for Bivector<T> {
type Output = Bivector<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Bivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
-(operand.as_inner().rz() * self.rx() * self.rx())
+ -(operand.as_inner().rz() * self.ry() * self.ry())
+ T::TWO * operand.as_inner().rx() * self.rx() * self.rz()
+ T::TWO * operand.as_inner().ry() * self.ry() * self.rz()
+ operand.as_inner().rz() * self.rz() * self.rz(),
-(operand.as_inner().ry() * self.rx() * self.rx())
+ -(operand.as_inner().ry() * self.rz() * self.rz())
+ T::TWO * operand.as_inner().rx() * self.rx() * self.ry()
+ T::TWO * operand.as_inner().rz() * self.ry() * self.rz()
+ operand.as_inner().ry() * self.ry() * self.ry(),
-(operand.as_inner().rx() * self.ry() * self.ry())
+ -(operand.as_inner().rx() * self.rz() * self.rz())
+ T::TWO * operand.as_inner().ry() * self.rx() * self.ry()
+ T::TWO * operand.as_inner().rz() * self.rx() * self.rz()
+ operand.as_inner().rx() * self.rx() * self.rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Bivector<T>>> for Unit<Bivector<T>> {
type Output = Bivector<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Bivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
-T::TWO * operand.as_inner().rz() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.as_inner().rz() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.as_inner().rx() * self.as_inner().rx() * self.as_inner().rz()
+ T::TWO * operand.as_inner().ry() * self.as_inner().ry() * self.as_inner().rz()
+ operand.as_inner().rz(),
-(operand.as_inner().ry())
+ T::TWO * operand.as_inner().rx() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.as_inner().ry() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.as_inner().rz() * self.as_inner().ry() * self.as_inner().rz(),
-(operand.as_inner().rx())
+ T::TWO * operand.as_inner().rx() * self.as_inner().rx() * self.as_inner().rx()
+ T::TWO * operand.as_inner().ry() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.as_inner().rz() * self.as_inner().rx() * self.as_inner().rz(),
)
}
}
#[doc = "Sandwich product: [`Bivector`] x [`Rotor`] x rev([`Bivector`]).\n\nThe sandwich product `v x a x rev(v)` applies the transformation\nrepresented by the versor `v` to the operand `a`. For rotors, this\nperforms rotation; for motors, it performs rigid body transformation."]
#[allow(unused_variables)]
impl<T: Float> Sandwich<Rotor<T>> for Bivector<T> {
type Output = Rotor<T>;
#[inline]
fn sandwich(&self, operand: &Rotor<T>) -> Rotor<T> {
Rotor::new_unchecked(
self.rx() * operand.ry() * self.rz() - self.rx() * operand.rz() * self.ry()
+ self.rx() * operand.s() * self.rx()
- self.ry() * operand.rx() * self.rz()
+ self.ry() * operand.rz() * self.rx()
+ self.ry() * operand.s() * self.ry()
+ self.rz() * operand.rx() * self.ry()
- self.rz() * operand.ry() * self.rx()
+ self.rz() * operand.s() * self.rz(),
self.rx() * operand.rx() * self.rz()
- self.rx() * operand.rz() * self.rx()
- self.rx() * operand.s() * self.ry()
+ self.ry() * operand.ry() * self.rz()
- self.ry() * operand.rz() * self.ry()
+ self.ry() * operand.s() * self.rx()
+ self.rz() * operand.rx() * self.rx()
+ self.rz() * operand.ry() * self.ry()
+ self.rz() * operand.rz() * self.rz(),
self.rx() * operand.rx() * self.ry() - self.rx() * operand.ry() * self.rx()
+ self.rx() * operand.s() * self.rz()
+ self.ry() * operand.rx() * self.rx()
+ self.ry() * operand.ry() * self.ry()
+ self.ry() * operand.rz() * self.rz()
- self.rz() * operand.ry() * self.rz()
+ self.rz() * operand.rz() * self.ry()
- self.rz() * operand.s() * self.rx(),
self.rx() * operand.rx() * self.rx()
+ self.rx() * operand.ry() * self.ry()
+ self.rx() * operand.rz() * self.rz()
- self.ry() * operand.rx() * self.ry()
+ self.ry() * operand.ry() * self.rx()
- self.ry() * operand.s() * self.rz()
- self.rz() * operand.rx() * self.rz()
+ self.rz() * operand.rz() * self.rx()
+ self.rz() * operand.s() * self.ry(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Rotor<T>> for Unit<Bivector<T>> {
type Output = Rotor<T>;
#[inline]
fn sandwich(&self, operand: &Rotor<T>) -> Rotor<T> {
Rotor::new_unchecked(
operand.s(),
-T::TWO * operand.rz() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.rz() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.rx() * self.as_inner().rx() * self.as_inner().rz()
+ T::TWO * operand.ry() * self.as_inner().ry() * self.as_inner().rz()
+ operand.rz(),
-(operand.ry())
+ T::TWO * operand.rx() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.ry() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.rz() * self.as_inner().ry() * self.as_inner().rz(),
-(operand.rx())
+ T::TWO * operand.rx() * self.as_inner().rx() * self.as_inner().rx()
+ T::TWO * operand.ry() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.rz() * self.as_inner().rx() * self.as_inner().rz(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Rotor<T>>> for Bivector<T> {
type Output = Rotor<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Rotor<T>>) -> Rotor<T> {
Rotor::new_unchecked(
operand.as_inner().s() * self.rx() * self.rx()
+ operand.as_inner().s() * self.ry() * self.ry()
+ operand.as_inner().s() * self.rz() * self.rz(),
-(operand.as_inner().rz() * self.rx() * self.rx())
+ -(operand.as_inner().rz() * self.ry() * self.ry())
+ T::TWO * operand.as_inner().rx() * self.rx() * self.rz()
+ T::TWO * operand.as_inner().ry() * self.ry() * self.rz()
+ operand.as_inner().rz() * self.rz() * self.rz(),
-(operand.as_inner().ry() * self.rx() * self.rx())
+ -(operand.as_inner().ry() * self.rz() * self.rz())
+ T::TWO * operand.as_inner().rx() * self.rx() * self.ry()
+ T::TWO * operand.as_inner().rz() * self.ry() * self.rz()
+ operand.as_inner().ry() * self.ry() * self.ry(),
-(operand.as_inner().rx() * self.ry() * self.ry())
+ -(operand.as_inner().rx() * self.rz() * self.rz())
+ T::TWO * operand.as_inner().ry() * self.rx() * self.ry()
+ T::TWO * operand.as_inner().rz() * self.rx() * self.rz()
+ operand.as_inner().rx() * self.rx() * self.rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Rotor<T>>> for Unit<Bivector<T>> {
type Output = Rotor<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Rotor<T>>) -> Rotor<T> {
Rotor::new_unchecked(
operand.as_inner().s(),
-T::TWO * operand.as_inner().rz() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.as_inner().rz() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.as_inner().rx() * self.as_inner().rx() * self.as_inner().rz()
+ T::TWO * operand.as_inner().ry() * self.as_inner().ry() * self.as_inner().rz()
+ operand.as_inner().rz(),
-(operand.as_inner().ry())
+ T::TWO * operand.as_inner().rx() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.as_inner().ry() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.as_inner().rz() * self.as_inner().ry() * self.as_inner().rz(),
-(operand.as_inner().rx())
+ T::TWO * operand.as_inner().rx() * self.as_inner().rx() * self.as_inner().rx()
+ T::TWO * operand.as_inner().ry() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.as_inner().rz() * self.as_inner().rx() * self.as_inner().rz(),
)
}
}
#[doc = "Sandwich product: [`Bivector`] x [`Scalar`] x rev([`Bivector`]).\n\nThe sandwich product `v x a x rev(v)` applies the transformation\nrepresented by the versor `v` to the operand `a`. For rotors, this\nperforms rotation; for motors, it performs rigid body transformation."]
#[allow(unused_variables)]
impl<T: Float> Sandwich<Scalar<T>> for Bivector<T> {
type Output = Scalar<T>;
#[inline]
fn sandwich(&self, operand: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(
self.rx() * operand.s() * self.rx()
+ self.ry() * operand.s() * self.ry()
+ self.rz() * operand.s() * self.rz(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Scalar<T>> for Unit<Bivector<T>> {
type Output = Scalar<T>;
#[inline]
fn sandwich(&self, operand: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(operand.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Scalar<T>>> for Bivector<T> {
type Output = Scalar<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(
operand.as_inner().s() * self.rx() * self.rx()
+ operand.as_inner().s() * self.ry() * self.ry()
+ operand.as_inner().s() * self.rz() * self.rz(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Scalar<T>>> for Unit<Bivector<T>> {
type Output = Scalar<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(operand.as_inner().s())
}
}
#[doc = "Sandwich product: [`Bivector`] x [`Trivector`] x rev([`Bivector`]).\n\nThe sandwich product `v x a x rev(v)` applies the transformation\nrepresented by the versor `v` to the operand `a`. For rotors, this\nperforms rotation; for motors, it performs rigid body transformation."]
#[allow(unused_variables)]
impl<T: Float> Sandwich<Trivector<T>> for Bivector<T> {
type Output = Trivector<T>;
#[inline]
fn sandwich(&self, operand: &Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(
self.rx() * operand.ps() * self.rx()
+ self.ry() * operand.ps() * self.ry()
+ self.rz() * operand.ps() * self.rz(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Trivector<T>> for Unit<Bivector<T>> {
type Output = Trivector<T>;
#[inline]
fn sandwich(&self, operand: &Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(operand.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Trivector<T>>> for Bivector<T> {
type Output = Trivector<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Trivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(
operand.as_inner().ps() * self.rx() * self.rx()
+ operand.as_inner().ps() * self.ry() * self.ry()
+ operand.as_inner().ps() * self.rz() * self.rz(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Trivector<T>>> for Unit<Bivector<T>> {
type Output = Trivector<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Trivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(operand.as_inner().ps())
}
}
#[doc = "Sandwich product: [`Bivector`] x [`Vector`] x rev([`Bivector`]).\n\nThe sandwich product `v x a x rev(v)` applies the transformation\nrepresented by the versor `v` to the operand `a`. For rotors, this\nperforms rotation; for motors, it performs rigid body transformation."]
#[allow(unused_variables)]
impl<T: Float> Sandwich<Vector<T>> for Bivector<T> {
type Output = Vector<T>;
#[inline]
fn sandwich(&self, operand: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(
self.rx() * operand.x() * self.rx() - self.rx() * operand.y() * self.ry()
+ self.rx() * operand.z() * self.rz()
- self.ry() * operand.x() * self.ry()
- self.ry() * operand.y() * self.rx()
- self.rz() * operand.x() * self.rz()
+ self.rz() * operand.z() * self.rx(),
-(self.rx() * operand.x() * self.ry())
- self.rx() * operand.y() * self.rx()
- self.ry() * operand.x() * self.rx()
+ self.ry() * operand.y() * self.ry()
- self.ry() * operand.z() * self.rz()
- self.rz() * operand.y() * self.rz()
- self.rz() * operand.z() * self.ry(),
self.rx() * operand.x() * self.rz()
- self.rx() * operand.z() * self.rx()
- self.ry() * operand.y() * self.rz()
- self.ry() * operand.z() * self.ry()
+ self.rz() * operand.x() * self.rx()
- self.rz() * operand.y() * self.ry()
+ self.rz() * operand.z() * self.rz(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Vector<T>> for Unit<Bivector<T>> {
type Output = Vector<T>;
#[inline]
fn sandwich(&self, operand: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(
-(operand.x())
+ -T::TWO * operand.y() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.x() * self.as_inner().rx() * self.as_inner().rx()
+ T::TWO * operand.z() * self.as_inner().rx() * self.as_inner().rz(),
-(operand.y())
+ -T::TWO * operand.x() * self.as_inner().rx() * self.as_inner().ry()
+ -T::TWO * operand.z() * self.as_inner().ry() * self.as_inner().rz()
+ T::TWO * operand.y() * self.as_inner().ry() * self.as_inner().ry(),
-T::TWO * operand.y() * self.as_inner().ry() * self.as_inner().rz()
+ -T::TWO * operand.z() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.z() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.x() * self.as_inner().rx() * self.as_inner().rz()
+ operand.z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Vector<T>>> for Bivector<T> {
type Output = Vector<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
-(operand.as_inner().x() * self.ry() * self.ry())
+ -(operand.as_inner().x() * self.rz() * self.rz())
+ -T::TWO * operand.as_inner().y() * self.rx() * self.ry()
+ T::TWO * operand.as_inner().z() * self.rx() * self.rz()
+ operand.as_inner().x() * self.rx() * self.rx(),
-(operand.as_inner().y() * self.rx() * self.rx())
+ -(operand.as_inner().y() * self.rz() * self.rz())
+ -T::TWO * operand.as_inner().x() * self.rx() * self.ry()
+ -T::TWO * operand.as_inner().z() * self.ry() * self.rz()
+ operand.as_inner().y() * self.ry() * self.ry(),
-(operand.as_inner().z() * self.rx() * self.rx())
+ -(operand.as_inner().z() * self.ry() * self.ry())
+ -T::TWO * operand.as_inner().y() * self.ry() * self.rz()
+ T::TWO * operand.as_inner().x() * self.rx() * self.rz()
+ operand.as_inner().z() * self.rz() * self.rz(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Vector<T>>> for Unit<Bivector<T>> {
type Output = Vector<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
-(operand.as_inner().x())
+ -T::TWO * operand.as_inner().y() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.as_inner().x() * self.as_inner().rx() * self.as_inner().rx()
+ T::TWO * operand.as_inner().z() * self.as_inner().rx() * self.as_inner().rz(),
-(operand.as_inner().y())
+ -T::TWO * operand.as_inner().x() * self.as_inner().rx() * self.as_inner().ry()
+ -T::TWO * operand.as_inner().z() * self.as_inner().ry() * self.as_inner().rz()
+ T::TWO * operand.as_inner().y() * self.as_inner().ry() * self.as_inner().ry(),
-T::TWO * operand.as_inner().y() * self.as_inner().ry() * self.as_inner().rz()
+ -T::TWO * operand.as_inner().z() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.as_inner().z() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.as_inner().x() * self.as_inner().rx() * self.as_inner().rz()
+ operand.as_inner().z(),
)
}
}
#[doc = "Sandwich product: [`Rotor`] x [`Bivector`] x rev([`Rotor`]).\n\nThe sandwich product `v x a x rev(v)` applies the transformation\nrepresented by the versor `v` to the operand `a`. For rotors, this\nperforms rotation; for motors, it performs rigid body transformation."]
#[allow(unused_variables)]
impl<T: Float> Sandwich<Bivector<T>> for Rotor<T> {
type Output = Bivector<T>;
#[inline]
fn sandwich(&self, operand: &Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
self.rx() * operand.rx() * self.rz() + self.rx() * operand.ry() * self.s()
- self.rx() * operand.rz() * self.rx()
- self.ry() * operand.rx() * self.s()
+ self.ry() * operand.ry() * self.rz()
- self.ry() * operand.rz() * self.ry()
+ self.rz() * operand.rx() * self.rx()
+ self.rz() * operand.ry() * self.ry()
+ self.rz() * operand.rz() * self.rz()
- self.s() * operand.rx() * self.ry()
+ self.s() * operand.ry() * self.rx()
+ self.s() * operand.rz() * self.s(),
self.rx() * operand.rx() * self.ry()
- self.rx() * operand.ry() * self.rx()
- self.rx() * operand.rz() * self.s()
+ self.ry() * operand.rx() * self.rx()
+ self.ry() * operand.ry() * self.ry()
+ self.ry() * operand.rz() * self.rz()
+ self.rz() * operand.rx() * self.s()
- self.rz() * operand.ry() * self.rz()
+ self.rz() * operand.rz() * self.ry()
+ self.s() * operand.rx() * self.rz()
+ self.s() * operand.ry() * self.s()
- self.s() * operand.rz() * self.rx(),
self.rx() * operand.rx() * self.rx()
+ self.rx() * operand.ry() * self.ry()
+ self.rx() * operand.rz() * self.rz()
- self.ry() * operand.rx() * self.ry()
+ self.ry() * operand.ry() * self.rx()
+ self.ry() * operand.rz() * self.s()
- self.rz() * operand.rx() * self.rz()
- self.rz() * operand.ry() * self.s()
+ self.rz() * operand.rz() * self.rx()
+ self.s() * operand.rx() * self.s()
- self.s() * operand.ry() * self.rz()
+ self.s() * operand.rz() * self.ry(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Bivector<T>> for Unit<Rotor<T>> {
type Output = Bivector<T>;
#[inline]
fn sandwich(&self, operand: &Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
-T::TWO * operand.rx() * self.as_inner().ry() * self.as_inner().s()
+ -T::TWO * operand.rz() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.rz() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.rx() * self.as_inner().rx() * self.as_inner().rz()
+ T::TWO * operand.ry() * self.as_inner().rx() * self.as_inner().s()
+ T::TWO * operand.ry() * self.as_inner().ry() * self.as_inner().rz()
+ operand.rz(),
-T::TWO * operand.ry() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.ry() * self.as_inner().rz() * self.as_inner().rz()
+ -T::TWO * operand.rz() * self.as_inner().rx() * self.as_inner().s()
+ T::TWO * operand.rx() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.rx() * self.as_inner().rz() * self.as_inner().s()
+ T::TWO * operand.rz() * self.as_inner().ry() * self.as_inner().rz()
+ operand.ry(),
-T::TWO * operand.rx() * self.as_inner().ry() * self.as_inner().ry()
+ -T::TWO * operand.rx() * self.as_inner().rz() * self.as_inner().rz()
+ -T::TWO * operand.ry() * self.as_inner().rz() * self.as_inner().s()
+ T::TWO * operand.ry() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.rz() * self.as_inner().rx() * self.as_inner().rz()
+ T::TWO * operand.rz() * self.as_inner().ry() * self.as_inner().s()
+ operand.rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Bivector<T>>> for Rotor<T> {
type Output = Bivector<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Bivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
-(operand.as_inner().rz() * self.rx() * self.rx())
+ -(operand.as_inner().rz() * self.ry() * self.ry())
+ -T::TWO * operand.as_inner().rx() * self.ry() * self.s()
+ T::TWO * operand.as_inner().rx() * self.rx() * self.rz()
+ T::TWO * operand.as_inner().ry() * self.rx() * self.s()
+ T::TWO * operand.as_inner().ry() * self.ry() * self.rz()
+ operand.as_inner().rz() * self.rz() * self.rz()
+ operand.as_inner().rz() * self.s() * self.s(),
-(operand.as_inner().ry() * self.rx() * self.rx())
+ -(operand.as_inner().ry() * self.rz() * self.rz())
+ -T::TWO * operand.as_inner().rz() * self.rx() * self.s()
+ T::TWO * operand.as_inner().rx() * self.rx() * self.ry()
+ T::TWO * operand.as_inner().rx() * self.rz() * self.s()
+ T::TWO * operand.as_inner().rz() * self.ry() * self.rz()
+ operand.as_inner().ry() * self.ry() * self.ry()
+ operand.as_inner().ry() * self.s() * self.s(),
-(operand.as_inner().rx() * self.ry() * self.ry())
+ -(operand.as_inner().rx() * self.rz() * self.rz())
+ -T::TWO * operand.as_inner().ry() * self.rz() * self.s()
+ T::TWO * operand.as_inner().ry() * self.rx() * self.ry()
+ T::TWO * operand.as_inner().rz() * self.rx() * self.rz()
+ T::TWO * operand.as_inner().rz() * self.ry() * self.s()
+ operand.as_inner().rx() * self.rx() * self.rx()
+ operand.as_inner().rx() * self.s() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Bivector<T>>> for Unit<Rotor<T>> {
type Output = Bivector<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Bivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
-T::TWO * operand.as_inner().rx() * self.as_inner().ry() * self.as_inner().s()
+ -T::TWO * operand.as_inner().rz() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.as_inner().rz() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.as_inner().rx() * self.as_inner().rx() * self.as_inner().rz()
+ T::TWO * operand.as_inner().ry() * self.as_inner().rx() * self.as_inner().s()
+ T::TWO * operand.as_inner().ry() * self.as_inner().ry() * self.as_inner().rz()
+ operand.as_inner().rz(),
-T::TWO * operand.as_inner().ry() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.as_inner().ry() * self.as_inner().rz() * self.as_inner().rz()
+ -T::TWO * operand.as_inner().rz() * self.as_inner().rx() * self.as_inner().s()
+ T::TWO * operand.as_inner().rx() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.as_inner().rx() * self.as_inner().rz() * self.as_inner().s()
+ T::TWO * operand.as_inner().rz() * self.as_inner().ry() * self.as_inner().rz()
+ operand.as_inner().ry(),
-T::TWO * operand.as_inner().rx() * self.as_inner().ry() * self.as_inner().ry()
+ -T::TWO * operand.as_inner().rx() * self.as_inner().rz() * self.as_inner().rz()
+ -T::TWO * operand.as_inner().ry() * self.as_inner().rz() * self.as_inner().s()
+ T::TWO * operand.as_inner().ry() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.as_inner().rz() * self.as_inner().rx() * self.as_inner().rz()
+ T::TWO * operand.as_inner().rz() * self.as_inner().ry() * self.as_inner().s()
+ operand.as_inner().rx(),
)
}
}
#[doc = "Sandwich product: [`Rotor`] x [`Rotor`] x rev([`Rotor`]).\n\nThe sandwich product `v x a x rev(v)` applies the transformation\nrepresented by the versor `v` to the operand `a`. For rotors, this\nperforms rotation; for motors, it performs rigid body transformation."]
#[allow(unused_variables)]
impl<T: Float> Sandwich<Rotor<T>> for Rotor<T> {
type Output = Rotor<T>;
#[inline]
fn sandwich(&self, operand: &Rotor<T>) -> Rotor<T> {
Rotor::new_unchecked(
-(self.rx() * operand.rx() * self.s()) + self.rx() * operand.ry() * self.rz()
- self.rx() * operand.rz() * self.ry()
+ self.rx() * operand.s() * self.rx()
- self.ry() * operand.rx() * self.rz()
- self.ry() * operand.ry() * self.s()
+ self.ry() * operand.rz() * self.rx()
+ self.ry() * operand.s() * self.ry()
+ self.rz() * operand.rx() * self.ry()
- self.rz() * operand.ry() * self.rx()
- self.rz() * operand.rz() * self.s()
+ self.rz() * operand.s() * self.rz()
+ self.s() * operand.rx() * self.rx()
+ self.s() * operand.ry() * self.ry()
+ self.s() * operand.rz() * self.rz()
+ self.s() * operand.s() * self.s(),
self.rx() * operand.rx() * self.rz() + self.rx() * operand.ry() * self.s()
- self.rx() * operand.rz() * self.rx()
- self.rx() * operand.s() * self.ry()
- self.ry() * operand.rx() * self.s()
+ self.ry() * operand.ry() * self.rz()
- self.ry() * operand.rz() * self.ry()
+ self.ry() * operand.s() * self.rx()
+ self.rz() * operand.rx() * self.rx()
+ self.rz() * operand.ry() * self.ry()
+ self.rz() * operand.rz() * self.rz()
+ self.rz() * operand.s() * self.s()
- self.s() * operand.rx() * self.ry()
+ self.s() * operand.ry() * self.rx()
+ self.s() * operand.rz() * self.s()
- self.s() * operand.s() * self.rz(),
self.rx() * operand.rx() * self.ry()
- self.rx() * operand.ry() * self.rx()
- self.rx() * operand.rz() * self.s()
+ self.rx() * operand.s() * self.rz()
+ self.ry() * operand.rx() * self.rx()
+ self.ry() * operand.ry() * self.ry()
+ self.ry() * operand.rz() * self.rz()
+ self.ry() * operand.s() * self.s()
+ self.rz() * operand.rx() * self.s()
- self.rz() * operand.ry() * self.rz()
+ self.rz() * operand.rz() * self.ry()
- self.rz() * operand.s() * self.rx()
+ self.s() * operand.rx() * self.rz()
+ self.s() * operand.ry() * self.s()
- self.s() * operand.rz() * self.rx()
- self.s() * operand.s() * self.ry(),
self.rx() * operand.rx() * self.rx()
+ self.rx() * operand.ry() * self.ry()
+ self.rx() * operand.rz() * self.rz()
+ self.rx() * operand.s() * self.s()
- self.ry() * operand.rx() * self.ry()
+ self.ry() * operand.ry() * self.rx()
+ self.ry() * operand.rz() * self.s()
- self.ry() * operand.s() * self.rz()
- self.rz() * operand.rx() * self.rz()
- self.rz() * operand.ry() * self.s()
+ self.rz() * operand.rz() * self.rx()
+ self.rz() * operand.s() * self.ry()
+ self.s() * operand.rx() * self.s()
- self.s() * operand.ry() * self.rz()
+ self.s() * operand.rz() * self.ry()
- self.s() * operand.s() * self.rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Rotor<T>> for Unit<Rotor<T>> {
type Output = Rotor<T>;
#[inline]
fn sandwich(&self, operand: &Rotor<T>) -> Rotor<T> {
Rotor::new_unchecked(
operand.s(),
-T::TWO * operand.rx() * self.as_inner().ry() * self.as_inner().s()
+ -T::TWO * operand.rz() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.rz() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.rx() * self.as_inner().rx() * self.as_inner().rz()
+ T::TWO * operand.ry() * self.as_inner().rx() * self.as_inner().s()
+ T::TWO * operand.ry() * self.as_inner().ry() * self.as_inner().rz()
+ operand.rz(),
-T::TWO * operand.ry() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.ry() * self.as_inner().rz() * self.as_inner().rz()
+ -T::TWO * operand.rz() * self.as_inner().rx() * self.as_inner().s()
+ T::TWO * operand.rx() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.rx() * self.as_inner().rz() * self.as_inner().s()
+ T::TWO * operand.rz() * self.as_inner().ry() * self.as_inner().rz()
+ operand.ry(),
-T::TWO * operand.rx() * self.as_inner().ry() * self.as_inner().ry()
+ -T::TWO * operand.rx() * self.as_inner().rz() * self.as_inner().rz()
+ -T::TWO * operand.ry() * self.as_inner().rz() * self.as_inner().s()
+ T::TWO * operand.ry() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.rz() * self.as_inner().rx() * self.as_inner().rz()
+ T::TWO * operand.rz() * self.as_inner().ry() * self.as_inner().s()
+ operand.rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Rotor<T>>> for Rotor<T> {
type Output = Rotor<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Rotor<T>>) -> Rotor<T> {
Rotor::new_unchecked(
operand.as_inner().s() * self.rx() * self.rx()
+ operand.as_inner().s() * self.ry() * self.ry()
+ operand.as_inner().s() * self.rz() * self.rz()
+ operand.as_inner().s() * self.s() * self.s(),
-(operand.as_inner().rz() * self.rx() * self.rx())
+ -(operand.as_inner().rz() * self.ry() * self.ry())
+ -T::TWO * operand.as_inner().rx() * self.ry() * self.s()
+ T::TWO * operand.as_inner().rx() * self.rx() * self.rz()
+ T::TWO * operand.as_inner().ry() * self.rx() * self.s()
+ T::TWO * operand.as_inner().ry() * self.ry() * self.rz()
+ operand.as_inner().rz() * self.rz() * self.rz()
+ operand.as_inner().rz() * self.s() * self.s(),
-(operand.as_inner().ry() * self.rx() * self.rx())
+ -(operand.as_inner().ry() * self.rz() * self.rz())
+ -T::TWO * operand.as_inner().rz() * self.rx() * self.s()
+ T::TWO * operand.as_inner().rx() * self.rx() * self.ry()
+ T::TWO * operand.as_inner().rx() * self.rz() * self.s()
+ T::TWO * operand.as_inner().rz() * self.ry() * self.rz()
+ operand.as_inner().ry() * self.ry() * self.ry()
+ operand.as_inner().ry() * self.s() * self.s(),
-(operand.as_inner().rx() * self.ry() * self.ry())
+ -(operand.as_inner().rx() * self.rz() * self.rz())
+ -T::TWO * operand.as_inner().ry() * self.rz() * self.s()
+ T::TWO * operand.as_inner().ry() * self.rx() * self.ry()
+ T::TWO * operand.as_inner().rz() * self.rx() * self.rz()
+ T::TWO * operand.as_inner().rz() * self.ry() * self.s()
+ operand.as_inner().rx() * self.rx() * self.rx()
+ operand.as_inner().rx() * self.s() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Rotor<T>>> for Unit<Rotor<T>> {
type Output = Rotor<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Rotor<T>>) -> Rotor<T> {
Rotor::new_unchecked(
operand.as_inner().s(),
-T::TWO * operand.as_inner().rx() * self.as_inner().ry() * self.as_inner().s()
+ -T::TWO * operand.as_inner().rz() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.as_inner().rz() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.as_inner().rx() * self.as_inner().rx() * self.as_inner().rz()
+ T::TWO * operand.as_inner().ry() * self.as_inner().rx() * self.as_inner().s()
+ T::TWO * operand.as_inner().ry() * self.as_inner().ry() * self.as_inner().rz()
+ operand.as_inner().rz(),
-T::TWO * operand.as_inner().ry() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.as_inner().ry() * self.as_inner().rz() * self.as_inner().rz()
+ -T::TWO * operand.as_inner().rz() * self.as_inner().rx() * self.as_inner().s()
+ T::TWO * operand.as_inner().rx() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.as_inner().rx() * self.as_inner().rz() * self.as_inner().s()
+ T::TWO * operand.as_inner().rz() * self.as_inner().ry() * self.as_inner().rz()
+ operand.as_inner().ry(),
-T::TWO * operand.as_inner().rx() * self.as_inner().ry() * self.as_inner().ry()
+ -T::TWO * operand.as_inner().rx() * self.as_inner().rz() * self.as_inner().rz()
+ -T::TWO * operand.as_inner().ry() * self.as_inner().rz() * self.as_inner().s()
+ T::TWO * operand.as_inner().ry() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.as_inner().rz() * self.as_inner().rx() * self.as_inner().rz()
+ T::TWO * operand.as_inner().rz() * self.as_inner().ry() * self.as_inner().s()
+ operand.as_inner().rx(),
)
}
}
#[doc = "Sandwich product: [`Rotor`] x [`Scalar`] x rev([`Rotor`]).\n\nThe sandwich product `v x a x rev(v)` applies the transformation\nrepresented by the versor `v` to the operand `a`. For rotors, this\nperforms rotation; for motors, it performs rigid body transformation."]
#[allow(unused_variables)]
impl<T: Float> Sandwich<Scalar<T>> for Rotor<T> {
type Output = Scalar<T>;
#[inline]
fn sandwich(&self, operand: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(
self.rx() * operand.s() * self.rx()
+ self.ry() * operand.s() * self.ry()
+ self.rz() * operand.s() * self.rz()
+ self.s() * operand.s() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Scalar<T>> for Unit<Rotor<T>> {
type Output = Scalar<T>;
#[inline]
fn sandwich(&self, operand: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(operand.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Scalar<T>>> for Rotor<T> {
type Output = Scalar<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(
operand.as_inner().s() * self.rx() * self.rx()
+ operand.as_inner().s() * self.ry() * self.ry()
+ operand.as_inner().s() * self.rz() * self.rz()
+ operand.as_inner().s() * self.s() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Scalar<T>>> for Unit<Rotor<T>> {
type Output = Scalar<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(operand.as_inner().s())
}
}
#[doc = "Sandwich product: [`Rotor`] x [`Trivector`] x rev([`Rotor`]).\n\nThe sandwich product `v x a x rev(v)` applies the transformation\nrepresented by the versor `v` to the operand `a`. For rotors, this\nperforms rotation; for motors, it performs rigid body transformation."]
#[allow(unused_variables)]
impl<T: Float> Sandwich<Trivector<T>> for Rotor<T> {
type Output = Trivector<T>;
#[inline]
fn sandwich(&self, operand: &Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(
self.rx() * operand.ps() * self.rx()
+ self.ry() * operand.ps() * self.ry()
+ self.rz() * operand.ps() * self.rz()
+ self.s() * operand.ps() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Trivector<T>> for Unit<Rotor<T>> {
type Output = Trivector<T>;
#[inline]
fn sandwich(&self, operand: &Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(operand.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Trivector<T>>> for Rotor<T> {
type Output = Trivector<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Trivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(
operand.as_inner().ps() * self.rx() * self.rx()
+ operand.as_inner().ps() * self.ry() * self.ry()
+ operand.as_inner().ps() * self.rz() * self.rz()
+ operand.as_inner().ps() * self.s() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Trivector<T>>> for Unit<Rotor<T>> {
type Output = Trivector<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Trivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(operand.as_inner().ps())
}
}
#[doc = "Sandwich product: [`Rotor`] x [`Vector`] x rev([`Rotor`]).\n\nThe sandwich product `v x a x rev(v)` applies the transformation\nrepresented by the versor `v` to the operand `a`. For rotors, this\nperforms rotation; for motors, it performs rigid body transformation."]
#[allow(unused_variables)]
impl<T: Float> Sandwich<Vector<T>> for Rotor<T> {
type Output = Vector<T>;
#[inline]
fn sandwich(&self, operand: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(
self.rx() * operand.x() * self.rx() - self.rx() * operand.y() * self.ry()
+ self.rx() * operand.z() * self.rz()
- self.ry() * operand.x() * self.ry()
- self.ry() * operand.y() * self.rx()
+ self.ry() * operand.z() * self.s()
- self.rz() * operand.x() * self.rz()
+ self.rz() * operand.y() * self.s()
+ self.rz() * operand.z() * self.rx()
+ self.s() * operand.x() * self.s()
+ self.s() * operand.y() * self.rz()
+ self.s() * operand.z() * self.ry(),
-(self.rx() * operand.x() * self.ry()) - self.rx() * operand.y() * self.rx()
+ self.rx() * operand.z() * self.s()
- self.ry() * operand.x() * self.rx()
+ self.ry() * operand.y() * self.ry()
- self.ry() * operand.z() * self.rz()
- self.rz() * operand.x() * self.s()
- self.rz() * operand.y() * self.rz()
- self.rz() * operand.z() * self.ry()
- self.s() * operand.x() * self.rz()
+ self.s() * operand.y() * self.s()
+ self.s() * operand.z() * self.rx(),
self.rx() * operand.x() * self.rz()
- self.rx() * operand.y() * self.s()
- self.rx() * operand.z() * self.rx()
- self.ry() * operand.x() * self.s()
- self.ry() * operand.y() * self.rz()
- self.ry() * operand.z() * self.ry()
+ self.rz() * operand.x() * self.rx()
- self.rz() * operand.y() * self.ry()
+ self.rz() * operand.z() * self.rz()
- self.s() * operand.x() * self.ry()
- self.s() * operand.y() * self.rx()
+ self.s() * operand.z() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Vector<T>> for Unit<Rotor<T>> {
type Output = Vector<T>;
#[inline]
fn sandwich(&self, operand: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(
-T::TWO * operand.x() * self.as_inner().ry() * self.as_inner().ry()
+ -T::TWO * operand.x() * self.as_inner().rz() * self.as_inner().rz()
+ -T::TWO * operand.y() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.y() * self.as_inner().rz() * self.as_inner().s()
+ T::TWO * operand.z() * self.as_inner().rx() * self.as_inner().rz()
+ T::TWO * operand.z() * self.as_inner().ry() * self.as_inner().s()
+ operand.x(),
-T::TWO * operand.x() * self.as_inner().rx() * self.as_inner().ry()
+ -T::TWO * operand.x() * self.as_inner().rz() * self.as_inner().s()
+ -T::TWO * operand.y() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.y() * self.as_inner().rz() * self.as_inner().rz()
+ -T::TWO * operand.z() * self.as_inner().ry() * self.as_inner().rz()
+ T::TWO * operand.z() * self.as_inner().rx() * self.as_inner().s()
+ operand.y(),
-T::TWO * operand.x() * self.as_inner().ry() * self.as_inner().s()
+ -T::TWO * operand.y() * self.as_inner().rx() * self.as_inner().s()
+ -T::TWO * operand.y() * self.as_inner().ry() * self.as_inner().rz()
+ -T::TWO * operand.z() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.z() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.x() * self.as_inner().rx() * self.as_inner().rz()
+ operand.z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Vector<T>>> for Rotor<T> {
type Output = Vector<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
-(operand.as_inner().x() * self.ry() * self.ry())
+ -(operand.as_inner().x() * self.rz() * self.rz())
+ -T::TWO * operand.as_inner().y() * self.rx() * self.ry()
+ T::TWO * operand.as_inner().y() * self.rz() * self.s()
+ T::TWO * operand.as_inner().z() * self.rx() * self.rz()
+ T::TWO * operand.as_inner().z() * self.ry() * self.s()
+ operand.as_inner().x() * self.rx() * self.rx()
+ operand.as_inner().x() * self.s() * self.s(),
-(operand.as_inner().y() * self.rx() * self.rx())
+ -(operand.as_inner().y() * self.rz() * self.rz())
+ -T::TWO * operand.as_inner().x() * self.rx() * self.ry()
+ -T::TWO * operand.as_inner().x() * self.rz() * self.s()
+ -T::TWO * operand.as_inner().z() * self.ry() * self.rz()
+ T::TWO * operand.as_inner().z() * self.rx() * self.s()
+ operand.as_inner().y() * self.ry() * self.ry()
+ operand.as_inner().y() * self.s() * self.s(),
-(operand.as_inner().z() * self.rx() * self.rx())
+ -(operand.as_inner().z() * self.ry() * self.ry())
+ -T::TWO * operand.as_inner().x() * self.ry() * self.s()
+ -T::TWO * operand.as_inner().y() * self.rx() * self.s()
+ -T::TWO * operand.as_inner().y() * self.ry() * self.rz()
+ T::TWO * operand.as_inner().x() * self.rx() * self.rz()
+ operand.as_inner().z() * self.rz() * self.rz()
+ operand.as_inner().z() * self.s() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Vector<T>>> for Unit<Rotor<T>> {
type Output = Vector<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
-T::TWO * operand.as_inner().x() * self.as_inner().ry() * self.as_inner().ry()
+ -T::TWO * operand.as_inner().x() * self.as_inner().rz() * self.as_inner().rz()
+ -T::TWO * operand.as_inner().y() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.as_inner().y() * self.as_inner().rz() * self.as_inner().s()
+ T::TWO * operand.as_inner().z() * self.as_inner().rx() * self.as_inner().rz()
+ T::TWO * operand.as_inner().z() * self.as_inner().ry() * self.as_inner().s()
+ operand.as_inner().x(),
-T::TWO * operand.as_inner().x() * self.as_inner().rx() * self.as_inner().ry()
+ -T::TWO * operand.as_inner().x() * self.as_inner().rz() * self.as_inner().s()
+ -T::TWO * operand.as_inner().y() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.as_inner().y() * self.as_inner().rz() * self.as_inner().rz()
+ -T::TWO * operand.as_inner().z() * self.as_inner().ry() * self.as_inner().rz()
+ T::TWO * operand.as_inner().z() * self.as_inner().rx() * self.as_inner().s()
+ operand.as_inner().y(),
-T::TWO * operand.as_inner().x() * self.as_inner().ry() * self.as_inner().s()
+ -T::TWO * operand.as_inner().y() * self.as_inner().rx() * self.as_inner().s()
+ -T::TWO * operand.as_inner().y() * self.as_inner().ry() * self.as_inner().rz()
+ -T::TWO * operand.as_inner().z() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.as_inner().z() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.as_inner().x() * self.as_inner().rx() * self.as_inner().rz()
+ operand.as_inner().z(),
)
}
}
#[doc = "Sandwich product: [`Scalar`] x [`Bivector`] x rev([`Scalar`]).\n\nThe sandwich product `v x a x rev(v)` applies the transformation\nrepresented by the versor `v` to the operand `a`. For rotors, this\nperforms rotation; for motors, it performs rigid body transformation."]
#[allow(unused_variables)]
impl<T: Float> Sandwich<Bivector<T>> for Scalar<T> {
type Output = Bivector<T>;
#[inline]
fn sandwich(&self, operand: &Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
self.s() * operand.rz() * self.s(),
self.s() * operand.ry() * self.s(),
self.s() * operand.rx() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Bivector<T>> for Unit<Scalar<T>> {
type Output = Bivector<T>;
#[inline]
fn sandwich(&self, operand: &Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(operand.rz(), operand.ry(), operand.rx())
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Bivector<T>>> for Scalar<T> {
type Output = Bivector<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Bivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
operand.as_inner().rz() * self.s() * self.s(),
operand.as_inner().ry() * self.s() * self.s(),
operand.as_inner().rx() * self.s() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Bivector<T>>> for Unit<Scalar<T>> {
type Output = Bivector<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Bivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
operand.as_inner().rz(),
operand.as_inner().ry(),
operand.as_inner().rx(),
)
}
}
#[doc = "Sandwich product: [`Scalar`] x [`Rotor`] x rev([`Scalar`]).\n\nThe sandwich product `v x a x rev(v)` applies the transformation\nrepresented by the versor `v` to the operand `a`. For rotors, this\nperforms rotation; for motors, it performs rigid body transformation."]
#[allow(unused_variables)]
impl<T: Float> Sandwich<Rotor<T>> for Scalar<T> {
type Output = Rotor<T>;
#[inline]
fn sandwich(&self, operand: &Rotor<T>) -> Rotor<T> {
Rotor::new_unchecked(
self.s() * operand.s() * self.s(),
self.s() * operand.rz() * self.s(),
self.s() * operand.ry() * self.s(),
self.s() * operand.rx() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Rotor<T>> for Unit<Scalar<T>> {
type Output = Rotor<T>;
#[inline]
fn sandwich(&self, operand: &Rotor<T>) -> Rotor<T> {
Rotor::new_unchecked(operand.s(), operand.rz(), operand.ry(), operand.rx())
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Rotor<T>>> for Scalar<T> {
type Output = Rotor<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Rotor<T>>) -> Rotor<T> {
Rotor::new_unchecked(
operand.as_inner().s() * self.s() * self.s(),
operand.as_inner().rz() * self.s() * self.s(),
operand.as_inner().ry() * self.s() * self.s(),
operand.as_inner().rx() * self.s() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Rotor<T>>> for Unit<Scalar<T>> {
type Output = Rotor<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Rotor<T>>) -> Rotor<T> {
Rotor::new_unchecked(
operand.as_inner().s(),
operand.as_inner().rz(),
operand.as_inner().ry(),
operand.as_inner().rx(),
)
}
}
#[doc = "Sandwich product: [`Scalar`] x [`Scalar`] x rev([`Scalar`]).\n\nThe sandwich product `v x a x rev(v)` applies the transformation\nrepresented by the versor `v` to the operand `a`. For rotors, this\nperforms rotation; for motors, it performs rigid body transformation."]
#[allow(unused_variables)]
impl<T: Float> Sandwich<Scalar<T>> for Scalar<T> {
type Output = Scalar<T>;
#[inline]
fn sandwich(&self, operand: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(self.s() * operand.s() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Scalar<T>> for Unit<Scalar<T>> {
type Output = Scalar<T>;
#[inline]
fn sandwich(&self, operand: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(operand.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Scalar<T>>> for Scalar<T> {
type Output = Scalar<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(operand.as_inner().s() * self.s() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Scalar<T>>> for Unit<Scalar<T>> {
type Output = Scalar<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(operand.as_inner().s())
}
}
#[doc = "Sandwich product: [`Scalar`] x [`Trivector`] x rev([`Scalar`]).\n\nThe sandwich product `v x a x rev(v)` applies the transformation\nrepresented by the versor `v` to the operand `a`. For rotors, this\nperforms rotation; for motors, it performs rigid body transformation."]
#[allow(unused_variables)]
impl<T: Float> Sandwich<Trivector<T>> for Scalar<T> {
type Output = Trivector<T>;
#[inline]
fn sandwich(&self, operand: &Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(self.s() * operand.ps() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Trivector<T>> for Unit<Scalar<T>> {
type Output = Trivector<T>;
#[inline]
fn sandwich(&self, operand: &Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(operand.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Trivector<T>>> for Scalar<T> {
type Output = Trivector<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Trivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(operand.as_inner().ps() * self.s() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Trivector<T>>> for Unit<Scalar<T>> {
type Output = Trivector<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Trivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(operand.as_inner().ps())
}
}
#[doc = "Sandwich product: [`Scalar`] x [`Vector`] x rev([`Scalar`]).\n\nThe sandwich product `v x a x rev(v)` applies the transformation\nrepresented by the versor `v` to the operand `a`. For rotors, this\nperforms rotation; for motors, it performs rigid body transformation."]
#[allow(unused_variables)]
impl<T: Float> Sandwich<Vector<T>> for Scalar<T> {
type Output = Vector<T>;
#[inline]
fn sandwich(&self, operand: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(
self.s() * operand.x() * self.s(),
self.s() * operand.y() * self.s(),
self.s() * operand.z() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Vector<T>> for Unit<Scalar<T>> {
type Output = Vector<T>;
#[inline]
fn sandwich(&self, operand: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(operand.x(), operand.y(), operand.z())
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Vector<T>>> for Scalar<T> {
type Output = Vector<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
operand.as_inner().x() * self.s() * self.s(),
operand.as_inner().y() * self.s() * self.s(),
operand.as_inner().z() * self.s() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Vector<T>>> for Unit<Scalar<T>> {
type Output = Vector<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
operand.as_inner().x(),
operand.as_inner().y(),
operand.as_inner().z(),
)
}
}
#[doc = "Sandwich product: [`Trivector`] x [`Bivector`] x rev([`Trivector`]).\n\nThe sandwich product `v x a x rev(v)` applies the transformation\nrepresented by the versor `v` to the operand `a`. For rotors, this\nperforms rotation; for motors, it performs rigid body transformation."]
#[allow(unused_variables)]
impl<T: Float> Sandwich<Bivector<T>> for Trivector<T> {
type Output = Bivector<T>;
#[inline]
fn sandwich(&self, operand: &Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
self.ps() * operand.rz() * self.ps(),
self.ps() * operand.ry() * self.ps(),
self.ps() * operand.rx() * self.ps(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Bivector<T>> for Unit<Trivector<T>> {
type Output = Bivector<T>;
#[inline]
fn sandwich(&self, operand: &Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(operand.rz(), operand.ry(), operand.rx())
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Bivector<T>>> for Trivector<T> {
type Output = Bivector<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Bivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
operand.as_inner().rz() * self.ps() * self.ps(),
operand.as_inner().ry() * self.ps() * self.ps(),
operand.as_inner().rx() * self.ps() * self.ps(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Bivector<T>>> for Unit<Trivector<T>> {
type Output = Bivector<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Bivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
operand.as_inner().rz(),
operand.as_inner().ry(),
operand.as_inner().rx(),
)
}
}
#[doc = "Sandwich product: [`Trivector`] x [`Rotor`] x rev([`Trivector`]).\n\nThe sandwich product `v x a x rev(v)` applies the transformation\nrepresented by the versor `v` to the operand `a`. For rotors, this\nperforms rotation; for motors, it performs rigid body transformation."]
#[allow(unused_variables)]
impl<T: Float> Sandwich<Rotor<T>> for Trivector<T> {
type Output = Rotor<T>;
#[inline]
fn sandwich(&self, operand: &Rotor<T>) -> Rotor<T> {
Rotor::new_unchecked(
self.ps() * operand.s() * self.ps(),
self.ps() * operand.rz() * self.ps(),
self.ps() * operand.ry() * self.ps(),
self.ps() * operand.rx() * self.ps(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Rotor<T>> for Unit<Trivector<T>> {
type Output = Rotor<T>;
#[inline]
fn sandwich(&self, operand: &Rotor<T>) -> Rotor<T> {
Rotor::new_unchecked(operand.s(), operand.rz(), operand.ry(), operand.rx())
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Rotor<T>>> for Trivector<T> {
type Output = Rotor<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Rotor<T>>) -> Rotor<T> {
Rotor::new_unchecked(
operand.as_inner().s() * self.ps() * self.ps(),
operand.as_inner().rz() * self.ps() * self.ps(),
operand.as_inner().ry() * self.ps() * self.ps(),
operand.as_inner().rx() * self.ps() * self.ps(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Rotor<T>>> for Unit<Trivector<T>> {
type Output = Rotor<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Rotor<T>>) -> Rotor<T> {
Rotor::new_unchecked(
operand.as_inner().s(),
operand.as_inner().rz(),
operand.as_inner().ry(),
operand.as_inner().rx(),
)
}
}
#[doc = "Sandwich product: [`Trivector`] x [`Scalar`] x rev([`Trivector`]).\n\nThe sandwich product `v x a x rev(v)` applies the transformation\nrepresented by the versor `v` to the operand `a`. For rotors, this\nperforms rotation; for motors, it performs rigid body transformation."]
#[allow(unused_variables)]
impl<T: Float> Sandwich<Scalar<T>> for Trivector<T> {
type Output = Scalar<T>;
#[inline]
fn sandwich(&self, operand: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(self.ps() * operand.s() * self.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Scalar<T>> for Unit<Trivector<T>> {
type Output = Scalar<T>;
#[inline]
fn sandwich(&self, operand: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(operand.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Scalar<T>>> for Trivector<T> {
type Output = Scalar<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(operand.as_inner().s() * self.ps() * self.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Scalar<T>>> for Unit<Trivector<T>> {
type Output = Scalar<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(operand.as_inner().s())
}
}
#[doc = "Sandwich product: [`Trivector`] x [`Trivector`] x rev([`Trivector`]).\n\nThe sandwich product `v x a x rev(v)` applies the transformation\nrepresented by the versor `v` to the operand `a`. For rotors, this\nperforms rotation; for motors, it performs rigid body transformation."]
#[allow(unused_variables)]
impl<T: Float> Sandwich<Trivector<T>> for Trivector<T> {
type Output = Trivector<T>;
#[inline]
fn sandwich(&self, operand: &Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(self.ps() * operand.ps() * self.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Trivector<T>> for Unit<Trivector<T>> {
type Output = Trivector<T>;
#[inline]
fn sandwich(&self, operand: &Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(operand.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Trivector<T>>> for Trivector<T> {
type Output = Trivector<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Trivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(operand.as_inner().ps() * self.ps() * self.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Trivector<T>>> for Unit<Trivector<T>> {
type Output = Trivector<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Trivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(operand.as_inner().ps())
}
}
#[doc = "Sandwich product: [`Trivector`] x [`Vector`] x rev([`Trivector`]).\n\nThe sandwich product `v x a x rev(v)` applies the transformation\nrepresented by the versor `v` to the operand `a`. For rotors, this\nperforms rotation; for motors, it performs rigid body transformation."]
#[allow(unused_variables)]
impl<T: Float> Sandwich<Vector<T>> for Trivector<T> {
type Output = Vector<T>;
#[inline]
fn sandwich(&self, operand: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(
self.ps() * operand.x() * self.ps(),
self.ps() * operand.y() * self.ps(),
self.ps() * operand.z() * self.ps(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Vector<T>> for Unit<Trivector<T>> {
type Output = Vector<T>;
#[inline]
fn sandwich(&self, operand: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(operand.x(), operand.y(), operand.z())
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Vector<T>>> for Trivector<T> {
type Output = Vector<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
operand.as_inner().x() * self.ps() * self.ps(),
operand.as_inner().y() * self.ps() * self.ps(),
operand.as_inner().z() * self.ps() * self.ps(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Vector<T>>> for Unit<Trivector<T>> {
type Output = Vector<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
operand.as_inner().x(),
operand.as_inner().y(),
operand.as_inner().z(),
)
}
}
#[doc = "Sandwich product: [`Vector`] x [`Bivector`] x rev([`Vector`]).\n\nThe sandwich product `v x a x rev(v)` applies the transformation\nrepresented by the versor `v` to the operand `a`. For rotors, this\nperforms rotation; for motors, it performs rigid body transformation."]
#[allow(unused_variables)]
impl<T: Float> Sandwich<Bivector<T>> for Vector<T> {
type Output = Bivector<T>;
#[inline]
fn sandwich(&self, operand: &Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
self.x() * operand.rx() * self.z()
- self.x() * operand.rz() * self.x()
- self.y() * operand.ry() * self.z()
- self.y() * operand.rz() * self.y()
+ self.z() * operand.rx() * self.x()
- self.z() * operand.ry() * self.y()
+ self.z() * operand.rz() * self.z(),
-(self.x() * operand.rx() * self.y())
- self.x() * operand.ry() * self.x()
- self.y() * operand.rx() * self.x()
+ self.y() * operand.ry() * self.y()
- self.y() * operand.rz() * self.z()
- self.z() * operand.ry() * self.z()
- self.z() * operand.rz() * self.y(),
self.x() * operand.rx() * self.x() - self.x() * operand.ry() * self.y()
+ self.x() * operand.rz() * self.z()
- self.y() * operand.rx() * self.y()
- self.y() * operand.ry() * self.x()
- self.z() * operand.rx() * self.z()
+ self.z() * operand.rz() * self.x(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Bivector<T>> for Unit<Vector<T>> {
type Output = Bivector<T>;
#[inline]
fn sandwich(&self, operand: &Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
-(operand.rz())
+ -T::TWO * operand.ry() * self.as_inner().y() * self.as_inner().z()
+ T::TWO * operand.rx() * self.as_inner().x() * self.as_inner().z()
+ T::TWO * operand.rz() * self.as_inner().z() * self.as_inner().z(),
-(operand.ry())
+ -T::TWO * operand.rx() * self.as_inner().x() * self.as_inner().y()
+ -T::TWO * operand.rz() * self.as_inner().y() * self.as_inner().z()
+ T::TWO * operand.ry() * self.as_inner().y() * self.as_inner().y(),
-T::TWO * operand.rx() * self.as_inner().y() * self.as_inner().y()
+ -T::TWO * operand.rx() * self.as_inner().z() * self.as_inner().z()
+ -T::TWO * operand.ry() * self.as_inner().x() * self.as_inner().y()
+ T::TWO * operand.rz() * self.as_inner().x() * self.as_inner().z()
+ operand.rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Bivector<T>>> for Vector<T> {
type Output = Bivector<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Bivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
-(operand.as_inner().rz() * self.x() * self.x())
+ -(operand.as_inner().rz() * self.y() * self.y())
+ -T::TWO * operand.as_inner().ry() * self.y() * self.z()
+ T::TWO * operand.as_inner().rx() * self.x() * self.z()
+ operand.as_inner().rz() * self.z() * self.z(),
-(operand.as_inner().ry() * self.x() * self.x())
+ -(operand.as_inner().ry() * self.z() * self.z())
+ -T::TWO * operand.as_inner().rx() * self.x() * self.y()
+ -T::TWO * operand.as_inner().rz() * self.y() * self.z()
+ operand.as_inner().ry() * self.y() * self.y(),
-(operand.as_inner().rx() * self.y() * self.y())
+ -(operand.as_inner().rx() * self.z() * self.z())
+ -T::TWO * operand.as_inner().ry() * self.x() * self.y()
+ T::TWO * operand.as_inner().rz() * self.x() * self.z()
+ operand.as_inner().rx() * self.x() * self.x(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Bivector<T>>> for Unit<Vector<T>> {
type Output = Bivector<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Bivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
-(operand.as_inner().rz())
+ -T::TWO * operand.as_inner().ry() * self.as_inner().y() * self.as_inner().z()
+ T::TWO * operand.as_inner().rx() * self.as_inner().x() * self.as_inner().z()
+ T::TWO * operand.as_inner().rz() * self.as_inner().z() * self.as_inner().z(),
-(operand.as_inner().ry())
+ -T::TWO * operand.as_inner().rx() * self.as_inner().x() * self.as_inner().y()
+ -T::TWO * operand.as_inner().rz() * self.as_inner().y() * self.as_inner().z()
+ T::TWO * operand.as_inner().ry() * self.as_inner().y() * self.as_inner().y(),
-T::TWO * operand.as_inner().rx() * self.as_inner().y() * self.as_inner().y()
+ -T::TWO * operand.as_inner().rx() * self.as_inner().z() * self.as_inner().z()
+ -T::TWO * operand.as_inner().ry() * self.as_inner().x() * self.as_inner().y()
+ T::TWO * operand.as_inner().rz() * self.as_inner().x() * self.as_inner().z()
+ operand.as_inner().rx(),
)
}
}
#[doc = "Sandwich product: [`Vector`] x [`Rotor`] x rev([`Vector`]).\n\nThe sandwich product `v x a x rev(v)` applies the transformation\nrepresented by the versor `v` to the operand `a`. For rotors, this\nperforms rotation; for motors, it performs rigid body transformation."]
#[allow(unused_variables)]
impl<T: Float> Sandwich<Rotor<T>> for Vector<T> {
type Output = Rotor<T>;
#[inline]
fn sandwich(&self, operand: &Rotor<T>) -> Rotor<T> {
Rotor::new_unchecked(
self.x() * operand.ry() * self.z()
+ self.x() * operand.rz() * self.y()
+ self.x() * operand.s() * self.x()
+ self.y() * operand.rx() * self.z()
- self.y() * operand.rz() * self.x()
+ self.y() * operand.s() * self.y()
- self.z() * operand.rx() * self.y()
- self.z() * operand.ry() * self.x()
+ self.z() * operand.s() * self.z(),
self.x() * operand.rx() * self.z() - self.x() * operand.rz() * self.x()
+ self.x() * operand.s() * self.y()
- self.y() * operand.ry() * self.z()
- self.y() * operand.rz() * self.y()
- self.y() * operand.s() * self.x()
+ self.z() * operand.rx() * self.x()
- self.z() * operand.ry() * self.y()
+ self.z() * operand.rz() * self.z(),
-(self.x() * operand.rx() * self.y()) - self.x() * operand.ry() * self.x()
+ self.x() * operand.s() * self.z()
- self.y() * operand.rx() * self.x()
+ self.y() * operand.ry() * self.y()
- self.y() * operand.rz() * self.z()
- self.z() * operand.ry() * self.z()
- self.z() * operand.rz() * self.y()
- self.z() * operand.s() * self.x(),
self.x() * operand.rx() * self.x() - self.x() * operand.ry() * self.y()
+ self.x() * operand.rz() * self.z()
- self.y() * operand.rx() * self.y()
- self.y() * operand.ry() * self.x()
+ self.y() * operand.s() * self.z()
- self.z() * operand.rx() * self.z()
+ self.z() * operand.rz() * self.x()
- self.z() * operand.s() * self.y(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Rotor<T>> for Unit<Vector<T>> {
type Output = Rotor<T>;
#[inline]
fn sandwich(&self, operand: &Rotor<T>) -> Rotor<T> {
Rotor::new_unchecked(
operand.s(),
-(operand.rz())
+ -T::TWO * operand.ry() * self.as_inner().y() * self.as_inner().z()
+ T::TWO * operand.rx() * self.as_inner().x() * self.as_inner().z()
+ T::TWO * operand.rz() * self.as_inner().z() * self.as_inner().z(),
-(operand.ry())
+ -T::TWO * operand.rx() * self.as_inner().x() * self.as_inner().y()
+ -T::TWO * operand.rz() * self.as_inner().y() * self.as_inner().z()
+ T::TWO * operand.ry() * self.as_inner().y() * self.as_inner().y(),
-T::TWO * operand.rx() * self.as_inner().y() * self.as_inner().y()
+ -T::TWO * operand.rx() * self.as_inner().z() * self.as_inner().z()
+ -T::TWO * operand.ry() * self.as_inner().x() * self.as_inner().y()
+ T::TWO * operand.rz() * self.as_inner().x() * self.as_inner().z()
+ operand.rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Rotor<T>>> for Vector<T> {
type Output = Rotor<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Rotor<T>>) -> Rotor<T> {
Rotor::new_unchecked(
operand.as_inner().s() * self.x() * self.x()
+ operand.as_inner().s() * self.y() * self.y()
+ operand.as_inner().s() * self.z() * self.z(),
-(operand.as_inner().rz() * self.x() * self.x())
+ -(operand.as_inner().rz() * self.y() * self.y())
+ -T::TWO * operand.as_inner().ry() * self.y() * self.z()
+ T::TWO * operand.as_inner().rx() * self.x() * self.z()
+ operand.as_inner().rz() * self.z() * self.z(),
-(operand.as_inner().ry() * self.x() * self.x())
+ -(operand.as_inner().ry() * self.z() * self.z())
+ -T::TWO * operand.as_inner().rx() * self.x() * self.y()
+ -T::TWO * operand.as_inner().rz() * self.y() * self.z()
+ operand.as_inner().ry() * self.y() * self.y(),
-(operand.as_inner().rx() * self.y() * self.y())
+ -(operand.as_inner().rx() * self.z() * self.z())
+ -T::TWO * operand.as_inner().ry() * self.x() * self.y()
+ T::TWO * operand.as_inner().rz() * self.x() * self.z()
+ operand.as_inner().rx() * self.x() * self.x(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Rotor<T>>> for Unit<Vector<T>> {
type Output = Rotor<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Rotor<T>>) -> Rotor<T> {
Rotor::new_unchecked(
operand.as_inner().s(),
-(operand.as_inner().rz())
+ -T::TWO * operand.as_inner().ry() * self.as_inner().y() * self.as_inner().z()
+ T::TWO * operand.as_inner().rx() * self.as_inner().x() * self.as_inner().z()
+ T::TWO * operand.as_inner().rz() * self.as_inner().z() * self.as_inner().z(),
-(operand.as_inner().ry())
+ -T::TWO * operand.as_inner().rx() * self.as_inner().x() * self.as_inner().y()
+ -T::TWO * operand.as_inner().rz() * self.as_inner().y() * self.as_inner().z()
+ T::TWO * operand.as_inner().ry() * self.as_inner().y() * self.as_inner().y(),
-T::TWO * operand.as_inner().rx() * self.as_inner().y() * self.as_inner().y()
+ -T::TWO * operand.as_inner().rx() * self.as_inner().z() * self.as_inner().z()
+ -T::TWO * operand.as_inner().ry() * self.as_inner().x() * self.as_inner().y()
+ T::TWO * operand.as_inner().rz() * self.as_inner().x() * self.as_inner().z()
+ operand.as_inner().rx(),
)
}
}
#[doc = "Sandwich product: [`Vector`] x [`Scalar`] x rev([`Vector`]).\n\nThe sandwich product `v x a x rev(v)` applies the transformation\nrepresented by the versor `v` to the operand `a`. For rotors, this\nperforms rotation; for motors, it performs rigid body transformation."]
#[allow(unused_variables)]
impl<T: Float> Sandwich<Scalar<T>> for Vector<T> {
type Output = Scalar<T>;
#[inline]
fn sandwich(&self, operand: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(
self.x() * operand.s() * self.x()
+ self.y() * operand.s() * self.y()
+ self.z() * operand.s() * self.z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Scalar<T>> for Unit<Vector<T>> {
type Output = Scalar<T>;
#[inline]
fn sandwich(&self, operand: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(operand.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Scalar<T>>> for Vector<T> {
type Output = Scalar<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(
operand.as_inner().s() * self.x() * self.x()
+ operand.as_inner().s() * self.y() * self.y()
+ operand.as_inner().s() * self.z() * self.z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Scalar<T>>> for Unit<Vector<T>> {
type Output = Scalar<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(operand.as_inner().s())
}
}
#[doc = "Sandwich product: [`Vector`] x [`Trivector`] x rev([`Vector`]).\n\nThe sandwich product `v x a x rev(v)` applies the transformation\nrepresented by the versor `v` to the operand `a`. For rotors, this\nperforms rotation; for motors, it performs rigid body transformation."]
#[allow(unused_variables)]
impl<T: Float> Sandwich<Trivector<T>> for Vector<T> {
type Output = Trivector<T>;
#[inline]
fn sandwich(&self, operand: &Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(
self.x() * operand.ps() * self.x()
+ self.y() * operand.ps() * self.y()
+ self.z() * operand.ps() * self.z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Trivector<T>> for Unit<Vector<T>> {
type Output = Trivector<T>;
#[inline]
fn sandwich(&self, operand: &Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(operand.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Trivector<T>>> for Vector<T> {
type Output = Trivector<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Trivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(
operand.as_inner().ps() * self.x() * self.x()
+ operand.as_inner().ps() * self.y() * self.y()
+ operand.as_inner().ps() * self.z() * self.z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Trivector<T>>> for Unit<Vector<T>> {
type Output = Trivector<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Trivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(operand.as_inner().ps())
}
}
#[doc = "Sandwich product: [`Vector`] x [`Vector`] x rev([`Vector`]).\n\nThe sandwich product `v x a x rev(v)` applies the transformation\nrepresented by the versor `v` to the operand `a`. For rotors, this\nperforms rotation; for motors, it performs rigid body transformation."]
#[allow(unused_variables)]
impl<T: Float> Sandwich<Vector<T>> for Vector<T> {
type Output = Vector<T>;
#[inline]
fn sandwich(&self, operand: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(
self.x() * operand.x() * self.x()
+ self.x() * operand.y() * self.y()
+ self.x() * operand.z() * self.z()
- self.y() * operand.x() * self.y()
+ self.y() * operand.y() * self.x()
- self.z() * operand.x() * self.z()
+ self.z() * operand.z() * self.x(),
self.x() * operand.x() * self.y() - self.x() * operand.y() * self.x()
+ self.y() * operand.x() * self.x()
+ self.y() * operand.y() * self.y()
+ self.y() * operand.z() * self.z()
- self.z() * operand.y() * self.z()
+ self.z() * operand.z() * self.y(),
self.x() * operand.x() * self.z() - self.x() * operand.z() * self.x()
+ self.y() * operand.y() * self.z()
- self.y() * operand.z() * self.y()
+ self.z() * operand.x() * self.x()
+ self.z() * operand.y() * self.y()
+ self.z() * operand.z() * self.z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Vector<T>> for Unit<Vector<T>> {
type Output = Vector<T>;
#[inline]
fn sandwich(&self, operand: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(
-T::TWO * operand.x() * self.as_inner().y() * self.as_inner().y()
+ -T::TWO * operand.x() * self.as_inner().z() * self.as_inner().z()
+ T::TWO * operand.y() * self.as_inner().x() * self.as_inner().y()
+ T::TWO * operand.z() * self.as_inner().x() * self.as_inner().z()
+ operand.x(),
-(operand.y())
+ T::TWO * operand.x() * self.as_inner().x() * self.as_inner().y()
+ T::TWO * operand.y() * self.as_inner().y() * self.as_inner().y()
+ T::TWO * operand.z() * self.as_inner().y() * self.as_inner().z(),
-(operand.z())
+ T::TWO * operand.x() * self.as_inner().x() * self.as_inner().z()
+ T::TWO * operand.y() * self.as_inner().y() * self.as_inner().z()
+ T::TWO * operand.z() * self.as_inner().z() * self.as_inner().z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Vector<T>>> for Vector<T> {
type Output = Vector<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
-(operand.as_inner().x() * self.y() * self.y())
+ -(operand.as_inner().x() * self.z() * self.z())
+ T::TWO * operand.as_inner().y() * self.x() * self.y()
+ T::TWO * operand.as_inner().z() * self.x() * self.z()
+ operand.as_inner().x() * self.x() * self.x(),
-(operand.as_inner().y() * self.x() * self.x())
+ -(operand.as_inner().y() * self.z() * self.z())
+ T::TWO * operand.as_inner().x() * self.x() * self.y()
+ T::TWO * operand.as_inner().z() * self.y() * self.z()
+ operand.as_inner().y() * self.y() * self.y(),
-(operand.as_inner().z() * self.x() * self.x())
+ -(operand.as_inner().z() * self.y() * self.y())
+ T::TWO * operand.as_inner().x() * self.x() * self.z()
+ T::TWO * operand.as_inner().y() * self.y() * self.z()
+ operand.as_inner().z() * self.z() * self.z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Sandwich<Unit<Vector<T>>> for Unit<Vector<T>> {
type Output = Vector<T>;
#[inline]
fn sandwich(&self, operand: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
-T::TWO * operand.as_inner().x() * self.as_inner().y() * self.as_inner().y()
+ -T::TWO * operand.as_inner().x() * self.as_inner().z() * self.as_inner().z()
+ T::TWO * operand.as_inner().y() * self.as_inner().x() * self.as_inner().y()
+ T::TWO * operand.as_inner().z() * self.as_inner().x() * self.as_inner().z()
+ operand.as_inner().x(),
-(operand.as_inner().y())
+ T::TWO * operand.as_inner().x() * self.as_inner().x() * self.as_inner().y()
+ T::TWO * operand.as_inner().y() * self.as_inner().y() * self.as_inner().y()
+ T::TWO * operand.as_inner().z() * self.as_inner().y() * self.as_inner().z(),
-(operand.as_inner().z())
+ T::TWO * operand.as_inner().x() * self.as_inner().x() * self.as_inner().z()
+ T::TWO * operand.as_inner().y() * self.as_inner().y() * self.as_inner().z()
+ T::TWO * operand.as_inner().z() * self.as_inner().z() * self.as_inner().z(),
)
}
}
#[doc = "Antisandwich product: [`Bivector`] x [`Bivector`] x antirev([`Bivector`]).\n\nThe antisandwich product `v x a x antirev(v)` is the dual of the\nsandwich product, used in Projective GA for transforming dual objects\n(planes, ideal points). Motors use antisandwich for plane transforms."]
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Bivector<T>> for Bivector<T> {
type Output = Bivector<T>;
#[inline]
fn antisandwich(&self, operand: &Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
self.rx() * operand.rx() * self.rz() - self.rx() * operand.rz() * self.rx()
+ self.ry() * operand.ry() * self.rz()
- self.ry() * operand.rz() * self.ry()
+ self.rz() * operand.rx() * self.rx()
+ self.rz() * operand.ry() * self.ry()
+ self.rz() * operand.rz() * self.rz(),
self.rx() * operand.rx() * self.ry() - self.rx() * operand.ry() * self.rx()
+ self.ry() * operand.rx() * self.rx()
+ self.ry() * operand.ry() * self.ry()
+ self.ry() * operand.rz() * self.rz()
- self.rz() * operand.ry() * self.rz()
+ self.rz() * operand.rz() * self.ry(),
self.rx() * operand.rx() * self.rx()
+ self.rx() * operand.ry() * self.ry()
+ self.rx() * operand.rz() * self.rz()
- self.ry() * operand.rx() * self.ry()
+ self.ry() * operand.ry() * self.rx()
- self.rz() * operand.rx() * self.rz()
+ self.rz() * operand.rz() * self.rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Bivector<T>> for Unit<Bivector<T>> {
type Output = Bivector<T>;
#[inline]
fn antisandwich(&self, operand: &Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
-T::TWO * operand.rz() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.rz() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.rx() * self.as_inner().rx() * self.as_inner().rz()
+ T::TWO * operand.ry() * self.as_inner().ry() * self.as_inner().rz()
+ operand.rz(),
-(operand.ry())
+ T::TWO * operand.rx() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.ry() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.rz() * self.as_inner().ry() * self.as_inner().rz(),
-(operand.rx())
+ T::TWO * operand.rx() * self.as_inner().rx() * self.as_inner().rx()
+ T::TWO * operand.ry() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.rz() * self.as_inner().rx() * self.as_inner().rz(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Bivector<T>>> for Bivector<T> {
type Output = Bivector<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Bivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
-(operand.as_inner().rz() * self.rx() * self.rx())
+ -(operand.as_inner().rz() * self.ry() * self.ry())
+ T::TWO * operand.as_inner().rx() * self.rx() * self.rz()
+ T::TWO * operand.as_inner().ry() * self.ry() * self.rz()
+ operand.as_inner().rz() * self.rz() * self.rz(),
-(operand.as_inner().ry() * self.rx() * self.rx())
+ -(operand.as_inner().ry() * self.rz() * self.rz())
+ T::TWO * operand.as_inner().rx() * self.rx() * self.ry()
+ T::TWO * operand.as_inner().rz() * self.ry() * self.rz()
+ operand.as_inner().ry() * self.ry() * self.ry(),
-(operand.as_inner().rx() * self.ry() * self.ry())
+ -(operand.as_inner().rx() * self.rz() * self.rz())
+ T::TWO * operand.as_inner().ry() * self.rx() * self.ry()
+ T::TWO * operand.as_inner().rz() * self.rx() * self.rz()
+ operand.as_inner().rx() * self.rx() * self.rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Bivector<T>>> for Unit<Bivector<T>> {
type Output = Bivector<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Bivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
-T::TWO * operand.as_inner().rz() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.as_inner().rz() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.as_inner().rx() * self.as_inner().rx() * self.as_inner().rz()
+ T::TWO * operand.as_inner().ry() * self.as_inner().ry() * self.as_inner().rz()
+ operand.as_inner().rz(),
-(operand.as_inner().ry())
+ T::TWO * operand.as_inner().rx() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.as_inner().ry() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.as_inner().rz() * self.as_inner().ry() * self.as_inner().rz(),
-(operand.as_inner().rx())
+ T::TWO * operand.as_inner().rx() * self.as_inner().rx() * self.as_inner().rx()
+ T::TWO * operand.as_inner().ry() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.as_inner().rz() * self.as_inner().rx() * self.as_inner().rz(),
)
}
}
#[doc = "Antisandwich product: [`Bivector`] x [`Rotor`] x antirev([`Bivector`]).\n\nThe antisandwich product `v x a x antirev(v)` is the dual of the\nsandwich product, used in Projective GA for transforming dual objects\n(planes, ideal points). Motors use antisandwich for plane transforms."]
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Rotor<T>> for Bivector<T> {
type Output = Rotor<T>;
#[inline]
fn antisandwich(&self, operand: &Rotor<T>) -> Rotor<T> {
Rotor::new_unchecked(
-(self.rx() * operand.ry() * self.rz())
+ self.rx() * operand.rz() * self.ry()
+ self.rx() * operand.s() * self.rx()
+ self.ry() * operand.rx() * self.rz()
- self.ry() * operand.rz() * self.rx()
+ self.ry() * operand.s() * self.ry()
- self.rz() * operand.rx() * self.ry()
+ self.rz() * operand.ry() * self.rx()
+ self.rz() * operand.s() * self.rz(),
self.rx() * operand.rx() * self.rz() - self.rx() * operand.rz() * self.rx()
+ self.rx() * operand.s() * self.ry()
+ self.ry() * operand.ry() * self.rz()
- self.ry() * operand.rz() * self.ry()
- self.ry() * operand.s() * self.rx()
+ self.rz() * operand.rx() * self.rx()
+ self.rz() * operand.ry() * self.ry()
+ self.rz() * operand.rz() * self.rz(),
self.rx() * operand.rx() * self.ry()
- self.rx() * operand.ry() * self.rx()
- self.rx() * operand.s() * self.rz()
+ self.ry() * operand.rx() * self.rx()
+ self.ry() * operand.ry() * self.ry()
+ self.ry() * operand.rz() * self.rz()
- self.rz() * operand.ry() * self.rz()
+ self.rz() * operand.rz() * self.ry()
+ self.rz() * operand.s() * self.rx(),
self.rx() * operand.rx() * self.rx()
+ self.rx() * operand.ry() * self.ry()
+ self.rx() * operand.rz() * self.rz()
- self.ry() * operand.rx() * self.ry()
+ self.ry() * operand.ry() * self.rx()
+ self.ry() * operand.s() * self.rz()
- self.rz() * operand.rx() * self.rz()
+ self.rz() * operand.rz() * self.rx()
- self.rz() * operand.s() * self.ry(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Rotor<T>> for Unit<Bivector<T>> {
type Output = Rotor<T>;
#[inline]
fn antisandwich(&self, operand: &Rotor<T>) -> Rotor<T> {
Rotor::new_unchecked(
operand.s(),
-T::TWO * operand.rz() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.rz() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.rx() * self.as_inner().rx() * self.as_inner().rz()
+ T::TWO * operand.ry() * self.as_inner().ry() * self.as_inner().rz()
+ operand.rz(),
-(operand.ry())
+ T::TWO * operand.rx() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.ry() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.rz() * self.as_inner().ry() * self.as_inner().rz(),
-(operand.rx())
+ T::TWO * operand.rx() * self.as_inner().rx() * self.as_inner().rx()
+ T::TWO * operand.ry() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.rz() * self.as_inner().rx() * self.as_inner().rz(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Rotor<T>>> for Bivector<T> {
type Output = Rotor<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Rotor<T>>) -> Rotor<T> {
Rotor::new_unchecked(
operand.as_inner().s() * self.rx() * self.rx()
+ operand.as_inner().s() * self.ry() * self.ry()
+ operand.as_inner().s() * self.rz() * self.rz(),
-(operand.as_inner().rz() * self.rx() * self.rx())
+ -(operand.as_inner().rz() * self.ry() * self.ry())
+ T::TWO * operand.as_inner().rx() * self.rx() * self.rz()
+ T::TWO * operand.as_inner().ry() * self.ry() * self.rz()
+ operand.as_inner().rz() * self.rz() * self.rz(),
-(operand.as_inner().ry() * self.rx() * self.rx())
+ -(operand.as_inner().ry() * self.rz() * self.rz())
+ T::TWO * operand.as_inner().rx() * self.rx() * self.ry()
+ T::TWO * operand.as_inner().rz() * self.ry() * self.rz()
+ operand.as_inner().ry() * self.ry() * self.ry(),
-(operand.as_inner().rx() * self.ry() * self.ry())
+ -(operand.as_inner().rx() * self.rz() * self.rz())
+ T::TWO * operand.as_inner().ry() * self.rx() * self.ry()
+ T::TWO * operand.as_inner().rz() * self.rx() * self.rz()
+ operand.as_inner().rx() * self.rx() * self.rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Rotor<T>>> for Unit<Bivector<T>> {
type Output = Rotor<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Rotor<T>>) -> Rotor<T> {
Rotor::new_unchecked(
operand.as_inner().s(),
-T::TWO * operand.as_inner().rz() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.as_inner().rz() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.as_inner().rx() * self.as_inner().rx() * self.as_inner().rz()
+ T::TWO * operand.as_inner().ry() * self.as_inner().ry() * self.as_inner().rz()
+ operand.as_inner().rz(),
-(operand.as_inner().ry())
+ T::TWO * operand.as_inner().rx() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.as_inner().ry() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.as_inner().rz() * self.as_inner().ry() * self.as_inner().rz(),
-(operand.as_inner().rx())
+ T::TWO * operand.as_inner().rx() * self.as_inner().rx() * self.as_inner().rx()
+ T::TWO * operand.as_inner().ry() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.as_inner().rz() * self.as_inner().rx() * self.as_inner().rz(),
)
}
}
#[doc = "Antisandwich product: [`Bivector`] x [`Scalar`] x antirev([`Bivector`]).\n\nThe antisandwich product `v x a x antirev(v)` is the dual of the\nsandwich product, used in Projective GA for transforming dual objects\n(planes, ideal points). Motors use antisandwich for plane transforms."]
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Scalar<T>> for Bivector<T> {
type Output = Scalar<T>;
#[inline]
fn antisandwich(&self, operand: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(
self.rx() * operand.s() * self.rx()
+ self.ry() * operand.s() * self.ry()
+ self.rz() * operand.s() * self.rz(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Scalar<T>> for Unit<Bivector<T>> {
type Output = Scalar<T>;
#[inline]
fn antisandwich(&self, operand: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(operand.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Scalar<T>>> for Bivector<T> {
type Output = Scalar<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(
operand.as_inner().s() * self.rx() * self.rx()
+ operand.as_inner().s() * self.ry() * self.ry()
+ operand.as_inner().s() * self.rz() * self.rz(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Scalar<T>>> for Unit<Bivector<T>> {
type Output = Scalar<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(operand.as_inner().s())
}
}
#[doc = "Antisandwich product: [`Bivector`] x [`Trivector`] x antirev([`Bivector`]).\n\nThe antisandwich product `v x a x antirev(v)` is the dual of the\nsandwich product, used in Projective GA for transforming dual objects\n(planes, ideal points). Motors use antisandwich for plane transforms."]
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Trivector<T>> for Bivector<T> {
type Output = Trivector<T>;
#[inline]
fn antisandwich(&self, operand: &Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(
self.rx() * operand.ps() * self.rx()
+ self.ry() * operand.ps() * self.ry()
+ self.rz() * operand.ps() * self.rz(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Trivector<T>> for Unit<Bivector<T>> {
type Output = Trivector<T>;
#[inline]
fn antisandwich(&self, operand: &Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(operand.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Trivector<T>>> for Bivector<T> {
type Output = Trivector<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Trivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(
operand.as_inner().ps() * self.rx() * self.rx()
+ operand.as_inner().ps() * self.ry() * self.ry()
+ operand.as_inner().ps() * self.rz() * self.rz(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Trivector<T>>> for Unit<Bivector<T>> {
type Output = Trivector<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Trivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(operand.as_inner().ps())
}
}
#[doc = "Antisandwich product: [`Bivector`] x [`Vector`] x antirev([`Bivector`]).\n\nThe antisandwich product `v x a x antirev(v)` is the dual of the\nsandwich product, used in Projective GA for transforming dual objects\n(planes, ideal points). Motors use antisandwich for plane transforms."]
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Vector<T>> for Bivector<T> {
type Output = Vector<T>;
#[inline]
fn antisandwich(&self, operand: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(
self.rx() * operand.x() * self.rx() - self.rx() * operand.y() * self.ry()
+ self.rx() * operand.z() * self.rz()
- self.ry() * operand.x() * self.ry()
- self.ry() * operand.y() * self.rx()
- self.rz() * operand.x() * self.rz()
+ self.rz() * operand.z() * self.rx(),
-(self.rx() * operand.x() * self.ry())
- self.rx() * operand.y() * self.rx()
- self.ry() * operand.x() * self.rx()
+ self.ry() * operand.y() * self.ry()
- self.ry() * operand.z() * self.rz()
- self.rz() * operand.y() * self.rz()
- self.rz() * operand.z() * self.ry(),
self.rx() * operand.x() * self.rz()
- self.rx() * operand.z() * self.rx()
- self.ry() * operand.y() * self.rz()
- self.ry() * operand.z() * self.ry()
+ self.rz() * operand.x() * self.rx()
- self.rz() * operand.y() * self.ry()
+ self.rz() * operand.z() * self.rz(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Vector<T>> for Unit<Bivector<T>> {
type Output = Vector<T>;
#[inline]
fn antisandwich(&self, operand: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(
-(operand.x())
+ -T::TWO * operand.y() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.x() * self.as_inner().rx() * self.as_inner().rx()
+ T::TWO * operand.z() * self.as_inner().rx() * self.as_inner().rz(),
-(operand.y())
+ -T::TWO * operand.x() * self.as_inner().rx() * self.as_inner().ry()
+ -T::TWO * operand.z() * self.as_inner().ry() * self.as_inner().rz()
+ T::TWO * operand.y() * self.as_inner().ry() * self.as_inner().ry(),
-T::TWO * operand.y() * self.as_inner().ry() * self.as_inner().rz()
+ -T::TWO * operand.z() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.z() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.x() * self.as_inner().rx() * self.as_inner().rz()
+ operand.z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Vector<T>>> for Bivector<T> {
type Output = Vector<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
-(operand.as_inner().x() * self.ry() * self.ry())
+ -(operand.as_inner().x() * self.rz() * self.rz())
+ -T::TWO * operand.as_inner().y() * self.rx() * self.ry()
+ T::TWO * operand.as_inner().z() * self.rx() * self.rz()
+ operand.as_inner().x() * self.rx() * self.rx(),
-(operand.as_inner().y() * self.rx() * self.rx())
+ -(operand.as_inner().y() * self.rz() * self.rz())
+ -T::TWO * operand.as_inner().x() * self.rx() * self.ry()
+ -T::TWO * operand.as_inner().z() * self.ry() * self.rz()
+ operand.as_inner().y() * self.ry() * self.ry(),
-(operand.as_inner().z() * self.rx() * self.rx())
+ -(operand.as_inner().z() * self.ry() * self.ry())
+ -T::TWO * operand.as_inner().y() * self.ry() * self.rz()
+ T::TWO * operand.as_inner().x() * self.rx() * self.rz()
+ operand.as_inner().z() * self.rz() * self.rz(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Vector<T>>> for Unit<Bivector<T>> {
type Output = Vector<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
-(operand.as_inner().x())
+ -T::TWO * operand.as_inner().y() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.as_inner().x() * self.as_inner().rx() * self.as_inner().rx()
+ T::TWO * operand.as_inner().z() * self.as_inner().rx() * self.as_inner().rz(),
-(operand.as_inner().y())
+ -T::TWO * operand.as_inner().x() * self.as_inner().rx() * self.as_inner().ry()
+ -T::TWO * operand.as_inner().z() * self.as_inner().ry() * self.as_inner().rz()
+ T::TWO * operand.as_inner().y() * self.as_inner().ry() * self.as_inner().ry(),
-T::TWO * operand.as_inner().y() * self.as_inner().ry() * self.as_inner().rz()
+ -T::TWO * operand.as_inner().z() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.as_inner().z() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.as_inner().x() * self.as_inner().rx() * self.as_inner().rz()
+ operand.as_inner().z(),
)
}
}
#[doc = "Antisandwich product: [`Rotor`] x [`Bivector`] x antirev([`Rotor`]).\n\nThe antisandwich product `v x a x antirev(v)` is the dual of the\nsandwich product, used in Projective GA for transforming dual objects\n(planes, ideal points). Motors use antisandwich for plane transforms."]
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Bivector<T>> for Rotor<T> {
type Output = Bivector<T>;
#[inline]
fn antisandwich(&self, operand: &Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
self.rx() * operand.rx() * self.rz()
- self.rx() * operand.ry() * self.s()
- self.rx() * operand.rz() * self.rx()
+ self.ry() * operand.rx() * self.s()
+ self.ry() * operand.ry() * self.rz()
- self.ry() * operand.rz() * self.ry()
+ self.rz() * operand.rx() * self.rx()
+ self.rz() * operand.ry() * self.ry()
+ self.rz() * operand.rz() * self.rz()
+ self.s() * operand.rx() * self.ry()
- self.s() * operand.ry() * self.rx()
+ self.s() * operand.rz() * self.s(),
self.rx() * operand.rx() * self.ry() - self.rx() * operand.ry() * self.rx()
+ self.rx() * operand.rz() * self.s()
+ self.ry() * operand.rx() * self.rx()
+ self.ry() * operand.ry() * self.ry()
+ self.ry() * operand.rz() * self.rz()
- self.rz() * operand.rx() * self.s()
- self.rz() * operand.ry() * self.rz()
+ self.rz() * operand.rz() * self.ry()
- self.s() * operand.rx() * self.rz()
+ self.s() * operand.ry() * self.s()
+ self.s() * operand.rz() * self.rx(),
self.rx() * operand.rx() * self.rx()
+ self.rx() * operand.ry() * self.ry()
+ self.rx() * operand.rz() * self.rz()
- self.ry() * operand.rx() * self.ry()
+ self.ry() * operand.ry() * self.rx()
- self.ry() * operand.rz() * self.s()
- self.rz() * operand.rx() * self.rz()
+ self.rz() * operand.ry() * self.s()
+ self.rz() * operand.rz() * self.rx()
+ self.s() * operand.rx() * self.s()
+ self.s() * operand.ry() * self.rz()
- self.s() * operand.rz() * self.ry(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Bivector<T>> for Unit<Rotor<T>> {
type Output = Bivector<T>;
#[inline]
fn antisandwich(&self, operand: &Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
-T::TWO * operand.ry() * self.as_inner().rx() * self.as_inner().s()
+ -T::TWO * operand.rz() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.rz() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.rx() * self.as_inner().rx() * self.as_inner().rz()
+ T::TWO * operand.rx() * self.as_inner().ry() * self.as_inner().s()
+ T::TWO * operand.ry() * self.as_inner().ry() * self.as_inner().rz()
+ operand.rz(),
-T::TWO * operand.rx() * self.as_inner().rz() * self.as_inner().s()
+ -T::TWO * operand.ry() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.ry() * self.as_inner().rz() * self.as_inner().rz()
+ T::TWO * operand.rx() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.rz() * self.as_inner().rx() * self.as_inner().s()
+ T::TWO * operand.rz() * self.as_inner().ry() * self.as_inner().rz()
+ operand.ry(),
-T::TWO * operand.rx() * self.as_inner().ry() * self.as_inner().ry()
+ -T::TWO * operand.rx() * self.as_inner().rz() * self.as_inner().rz()
+ -T::TWO * operand.rz() * self.as_inner().ry() * self.as_inner().s()
+ T::TWO * operand.ry() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.ry() * self.as_inner().rz() * self.as_inner().s()
+ T::TWO * operand.rz() * self.as_inner().rx() * self.as_inner().rz()
+ operand.rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Bivector<T>>> for Rotor<T> {
type Output = Bivector<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Bivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
-(operand.as_inner().rz() * self.rx() * self.rx())
+ -(operand.as_inner().rz() * self.ry() * self.ry())
+ -T::TWO * operand.as_inner().ry() * self.rx() * self.s()
+ T::TWO * operand.as_inner().rx() * self.rx() * self.rz()
+ T::TWO * operand.as_inner().rx() * self.ry() * self.s()
+ T::TWO * operand.as_inner().ry() * self.ry() * self.rz()
+ operand.as_inner().rz() * self.rz() * self.rz()
+ operand.as_inner().rz() * self.s() * self.s(),
-(operand.as_inner().ry() * self.rx() * self.rx())
+ -(operand.as_inner().ry() * self.rz() * self.rz())
+ -T::TWO * operand.as_inner().rx() * self.rz() * self.s()
+ T::TWO * operand.as_inner().rx() * self.rx() * self.ry()
+ T::TWO * operand.as_inner().rz() * self.rx() * self.s()
+ T::TWO * operand.as_inner().rz() * self.ry() * self.rz()
+ operand.as_inner().ry() * self.ry() * self.ry()
+ operand.as_inner().ry() * self.s() * self.s(),
-(operand.as_inner().rx() * self.ry() * self.ry())
+ -(operand.as_inner().rx() * self.rz() * self.rz())
+ -T::TWO * operand.as_inner().rz() * self.ry() * self.s()
+ T::TWO * operand.as_inner().ry() * self.rx() * self.ry()
+ T::TWO * operand.as_inner().ry() * self.rz() * self.s()
+ T::TWO * operand.as_inner().rz() * self.rx() * self.rz()
+ operand.as_inner().rx() * self.rx() * self.rx()
+ operand.as_inner().rx() * self.s() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Bivector<T>>> for Unit<Rotor<T>> {
type Output = Bivector<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Bivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
-T::TWO * operand.as_inner().ry() * self.as_inner().rx() * self.as_inner().s()
+ -T::TWO * operand.as_inner().rz() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.as_inner().rz() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.as_inner().rx() * self.as_inner().rx() * self.as_inner().rz()
+ T::TWO * operand.as_inner().rx() * self.as_inner().ry() * self.as_inner().s()
+ T::TWO * operand.as_inner().ry() * self.as_inner().ry() * self.as_inner().rz()
+ operand.as_inner().rz(),
-T::TWO * operand.as_inner().rx() * self.as_inner().rz() * self.as_inner().s()
+ -T::TWO * operand.as_inner().ry() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.as_inner().ry() * self.as_inner().rz() * self.as_inner().rz()
+ T::TWO * operand.as_inner().rx() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.as_inner().rz() * self.as_inner().rx() * self.as_inner().s()
+ T::TWO * operand.as_inner().rz() * self.as_inner().ry() * self.as_inner().rz()
+ operand.as_inner().ry(),
-T::TWO * operand.as_inner().rx() * self.as_inner().ry() * self.as_inner().ry()
+ -T::TWO * operand.as_inner().rx() * self.as_inner().rz() * self.as_inner().rz()
+ -T::TWO * operand.as_inner().rz() * self.as_inner().ry() * self.as_inner().s()
+ T::TWO * operand.as_inner().ry() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.as_inner().ry() * self.as_inner().rz() * self.as_inner().s()
+ T::TWO * operand.as_inner().rz() * self.as_inner().rx() * self.as_inner().rz()
+ operand.as_inner().rx(),
)
}
}
#[doc = "Antisandwich product: [`Rotor`] x [`Rotor`] x antirev([`Rotor`]).\n\nThe antisandwich product `v x a x antirev(v)` is the dual of the\nsandwich product, used in Projective GA for transforming dual objects\n(planes, ideal points). Motors use antisandwich for plane transforms."]
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Rotor<T>> for Rotor<T> {
type Output = Rotor<T>;
#[inline]
fn antisandwich(&self, operand: &Rotor<T>) -> Rotor<T> {
Rotor::new_unchecked(
-(self.rx() * operand.rx() * self.s()) - self.rx() * operand.ry() * self.rz()
+ self.rx() * operand.rz() * self.ry()
+ self.rx() * operand.s() * self.rx()
+ self.ry() * operand.rx() * self.rz()
- self.ry() * operand.ry() * self.s()
- self.ry() * operand.rz() * self.rx()
+ self.ry() * operand.s() * self.ry()
- self.rz() * operand.rx() * self.ry()
+ self.rz() * operand.ry() * self.rx()
- self.rz() * operand.rz() * self.s()
+ self.rz() * operand.s() * self.rz()
+ self.s() * operand.rx() * self.rx()
+ self.s() * operand.ry() * self.ry()
+ self.s() * operand.rz() * self.rz()
+ self.s() * operand.s() * self.s(),
self.rx() * operand.rx() * self.rz()
- self.rx() * operand.ry() * self.s()
- self.rx() * operand.rz() * self.rx()
+ self.rx() * operand.s() * self.ry()
+ self.ry() * operand.rx() * self.s()
+ self.ry() * operand.ry() * self.rz()
- self.ry() * operand.rz() * self.ry()
- self.ry() * operand.s() * self.rx()
+ self.rz() * operand.rx() * self.rx()
+ self.rz() * operand.ry() * self.ry()
+ self.rz() * operand.rz() * self.rz()
+ self.rz() * operand.s() * self.s()
+ self.s() * operand.rx() * self.ry()
- self.s() * operand.ry() * self.rx()
+ self.s() * operand.rz() * self.s()
- self.s() * operand.s() * self.rz(),
self.rx() * operand.rx() * self.ry() - self.rx() * operand.ry() * self.rx()
+ self.rx() * operand.rz() * self.s()
- self.rx() * operand.s() * self.rz()
+ self.ry() * operand.rx() * self.rx()
+ self.ry() * operand.ry() * self.ry()
+ self.ry() * operand.rz() * self.rz()
+ self.ry() * operand.s() * self.s()
- self.rz() * operand.rx() * self.s()
- self.rz() * operand.ry() * self.rz()
+ self.rz() * operand.rz() * self.ry()
+ self.rz() * operand.s() * self.rx()
- self.s() * operand.rx() * self.rz()
+ self.s() * operand.ry() * self.s()
+ self.s() * operand.rz() * self.rx()
- self.s() * operand.s() * self.ry(),
self.rx() * operand.rx() * self.rx()
+ self.rx() * operand.ry() * self.ry()
+ self.rx() * operand.rz() * self.rz()
+ self.rx() * operand.s() * self.s()
- self.ry() * operand.rx() * self.ry()
+ self.ry() * operand.ry() * self.rx()
- self.ry() * operand.rz() * self.s()
+ self.ry() * operand.s() * self.rz()
- self.rz() * operand.rx() * self.rz()
+ self.rz() * operand.ry() * self.s()
+ self.rz() * operand.rz() * self.rx()
- self.rz() * operand.s() * self.ry()
+ self.s() * operand.rx() * self.s()
+ self.s() * operand.ry() * self.rz()
- self.s() * operand.rz() * self.ry()
- self.s() * operand.s() * self.rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Rotor<T>> for Unit<Rotor<T>> {
type Output = Rotor<T>;
#[inline]
fn antisandwich(&self, operand: &Rotor<T>) -> Rotor<T> {
Rotor::new_unchecked(
operand.s(),
-T::TWO * operand.ry() * self.as_inner().rx() * self.as_inner().s()
+ -T::TWO * operand.rz() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.rz() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.rx() * self.as_inner().rx() * self.as_inner().rz()
+ T::TWO * operand.rx() * self.as_inner().ry() * self.as_inner().s()
+ T::TWO * operand.ry() * self.as_inner().ry() * self.as_inner().rz()
+ operand.rz(),
-T::TWO * operand.rx() * self.as_inner().rz() * self.as_inner().s()
+ -T::TWO * operand.ry() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.ry() * self.as_inner().rz() * self.as_inner().rz()
+ T::TWO * operand.rx() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.rz() * self.as_inner().rx() * self.as_inner().s()
+ T::TWO * operand.rz() * self.as_inner().ry() * self.as_inner().rz()
+ operand.ry(),
-T::TWO * operand.rx() * self.as_inner().ry() * self.as_inner().ry()
+ -T::TWO * operand.rx() * self.as_inner().rz() * self.as_inner().rz()
+ -T::TWO * operand.rz() * self.as_inner().ry() * self.as_inner().s()
+ T::TWO * operand.ry() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.ry() * self.as_inner().rz() * self.as_inner().s()
+ T::TWO * operand.rz() * self.as_inner().rx() * self.as_inner().rz()
+ operand.rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Rotor<T>>> for Rotor<T> {
type Output = Rotor<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Rotor<T>>) -> Rotor<T> {
Rotor::new_unchecked(
operand.as_inner().s() * self.rx() * self.rx()
+ operand.as_inner().s() * self.ry() * self.ry()
+ operand.as_inner().s() * self.rz() * self.rz()
+ operand.as_inner().s() * self.s() * self.s(),
-(operand.as_inner().rz() * self.rx() * self.rx())
+ -(operand.as_inner().rz() * self.ry() * self.ry())
+ -T::TWO * operand.as_inner().ry() * self.rx() * self.s()
+ T::TWO * operand.as_inner().rx() * self.rx() * self.rz()
+ T::TWO * operand.as_inner().rx() * self.ry() * self.s()
+ T::TWO * operand.as_inner().ry() * self.ry() * self.rz()
+ operand.as_inner().rz() * self.rz() * self.rz()
+ operand.as_inner().rz() * self.s() * self.s(),
-(operand.as_inner().ry() * self.rx() * self.rx())
+ -(operand.as_inner().ry() * self.rz() * self.rz())
+ -T::TWO * operand.as_inner().rx() * self.rz() * self.s()
+ T::TWO * operand.as_inner().rx() * self.rx() * self.ry()
+ T::TWO * operand.as_inner().rz() * self.rx() * self.s()
+ T::TWO * operand.as_inner().rz() * self.ry() * self.rz()
+ operand.as_inner().ry() * self.ry() * self.ry()
+ operand.as_inner().ry() * self.s() * self.s(),
-(operand.as_inner().rx() * self.ry() * self.ry())
+ -(operand.as_inner().rx() * self.rz() * self.rz())
+ -T::TWO * operand.as_inner().rz() * self.ry() * self.s()
+ T::TWO * operand.as_inner().ry() * self.rx() * self.ry()
+ T::TWO * operand.as_inner().ry() * self.rz() * self.s()
+ T::TWO * operand.as_inner().rz() * self.rx() * self.rz()
+ operand.as_inner().rx() * self.rx() * self.rx()
+ operand.as_inner().rx() * self.s() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Rotor<T>>> for Unit<Rotor<T>> {
type Output = Rotor<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Rotor<T>>) -> Rotor<T> {
Rotor::new_unchecked(
operand.as_inner().s(),
-T::TWO * operand.as_inner().ry() * self.as_inner().rx() * self.as_inner().s()
+ -T::TWO * operand.as_inner().rz() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.as_inner().rz() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.as_inner().rx() * self.as_inner().rx() * self.as_inner().rz()
+ T::TWO * operand.as_inner().rx() * self.as_inner().ry() * self.as_inner().s()
+ T::TWO * operand.as_inner().ry() * self.as_inner().ry() * self.as_inner().rz()
+ operand.as_inner().rz(),
-T::TWO * operand.as_inner().rx() * self.as_inner().rz() * self.as_inner().s()
+ -T::TWO * operand.as_inner().ry() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.as_inner().ry() * self.as_inner().rz() * self.as_inner().rz()
+ T::TWO * operand.as_inner().rx() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.as_inner().rz() * self.as_inner().rx() * self.as_inner().s()
+ T::TWO * operand.as_inner().rz() * self.as_inner().ry() * self.as_inner().rz()
+ operand.as_inner().ry(),
-T::TWO * operand.as_inner().rx() * self.as_inner().ry() * self.as_inner().ry()
+ -T::TWO * operand.as_inner().rx() * self.as_inner().rz() * self.as_inner().rz()
+ -T::TWO * operand.as_inner().rz() * self.as_inner().ry() * self.as_inner().s()
+ T::TWO * operand.as_inner().ry() * self.as_inner().rx() * self.as_inner().ry()
+ T::TWO * operand.as_inner().ry() * self.as_inner().rz() * self.as_inner().s()
+ T::TWO * operand.as_inner().rz() * self.as_inner().rx() * self.as_inner().rz()
+ operand.as_inner().rx(),
)
}
}
#[doc = "Antisandwich product: [`Rotor`] x [`Scalar`] x antirev([`Rotor`]).\n\nThe antisandwich product `v x a x antirev(v)` is the dual of the\nsandwich product, used in Projective GA for transforming dual objects\n(planes, ideal points). Motors use antisandwich for plane transforms."]
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Scalar<T>> for Rotor<T> {
type Output = Scalar<T>;
#[inline]
fn antisandwich(&self, operand: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(
self.rx() * operand.s() * self.rx()
+ self.ry() * operand.s() * self.ry()
+ self.rz() * operand.s() * self.rz()
+ self.s() * operand.s() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Scalar<T>> for Unit<Rotor<T>> {
type Output = Scalar<T>;
#[inline]
fn antisandwich(&self, operand: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(operand.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Scalar<T>>> for Rotor<T> {
type Output = Scalar<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(
operand.as_inner().s() * self.rx() * self.rx()
+ operand.as_inner().s() * self.ry() * self.ry()
+ operand.as_inner().s() * self.rz() * self.rz()
+ operand.as_inner().s() * self.s() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Scalar<T>>> for Unit<Rotor<T>> {
type Output = Scalar<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(operand.as_inner().s())
}
}
#[doc = "Antisandwich product: [`Rotor`] x [`Trivector`] x antirev([`Rotor`]).\n\nThe antisandwich product `v x a x antirev(v)` is the dual of the\nsandwich product, used in Projective GA for transforming dual objects\n(planes, ideal points). Motors use antisandwich for plane transforms."]
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Trivector<T>> for Rotor<T> {
type Output = Trivector<T>;
#[inline]
fn antisandwich(&self, operand: &Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(
self.rx() * operand.ps() * self.rx()
+ self.ry() * operand.ps() * self.ry()
+ self.rz() * operand.ps() * self.rz()
+ self.s() * operand.ps() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Trivector<T>> for Unit<Rotor<T>> {
type Output = Trivector<T>;
#[inline]
fn antisandwich(&self, operand: &Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(operand.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Trivector<T>>> for Rotor<T> {
type Output = Trivector<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Trivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(
operand.as_inner().ps() * self.rx() * self.rx()
+ operand.as_inner().ps() * self.ry() * self.ry()
+ operand.as_inner().ps() * self.rz() * self.rz()
+ operand.as_inner().ps() * self.s() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Trivector<T>>> for Unit<Rotor<T>> {
type Output = Trivector<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Trivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(operand.as_inner().ps())
}
}
#[doc = "Antisandwich product: [`Rotor`] x [`Vector`] x antirev([`Rotor`]).\n\nThe antisandwich product `v x a x antirev(v)` is the dual of the\nsandwich product, used in Projective GA for transforming dual objects\n(planes, ideal points). Motors use antisandwich for plane transforms."]
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Vector<T>> for Rotor<T> {
type Output = Vector<T>;
#[inline]
fn antisandwich(&self, operand: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(
self.rx() * operand.x() * self.rx() - self.rx() * operand.y() * self.ry()
+ self.rx() * operand.z() * self.rz()
- self.ry() * operand.x() * self.ry()
- self.ry() * operand.y() * self.rx()
- self.ry() * operand.z() * self.s()
- self.rz() * operand.x() * self.rz()
- self.rz() * operand.y() * self.s()
+ self.rz() * operand.z() * self.rx()
+ self.s() * operand.x() * self.s()
- self.s() * operand.y() * self.rz()
- self.s() * operand.z() * self.ry(),
-(self.rx() * operand.x() * self.ry())
- self.rx() * operand.y() * self.rx()
- self.rx() * operand.z() * self.s()
- self.ry() * operand.x() * self.rx()
+ self.ry() * operand.y() * self.ry()
- self.ry() * operand.z() * self.rz()
+ self.rz() * operand.x() * self.s()
- self.rz() * operand.y() * self.rz()
- self.rz() * operand.z() * self.ry()
+ self.s() * operand.x() * self.rz()
+ self.s() * operand.y() * self.s()
- self.s() * operand.z() * self.rx(),
self.rx() * operand.x() * self.rz() + self.rx() * operand.y() * self.s()
- self.rx() * operand.z() * self.rx()
+ self.ry() * operand.x() * self.s()
- self.ry() * operand.y() * self.rz()
- self.ry() * operand.z() * self.ry()
+ self.rz() * operand.x() * self.rx()
- self.rz() * operand.y() * self.ry()
+ self.rz() * operand.z() * self.rz()
+ self.s() * operand.x() * self.ry()
+ self.s() * operand.y() * self.rx()
+ self.s() * operand.z() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Vector<T>> for Unit<Rotor<T>> {
type Output = Vector<T>;
#[inline]
fn antisandwich(&self, operand: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(
-T::TWO * operand.x() * self.as_inner().ry() * self.as_inner().ry()
+ -T::TWO * operand.x() * self.as_inner().rz() * self.as_inner().rz()
+ -T::TWO * operand.y() * self.as_inner().rx() * self.as_inner().ry()
+ -T::TWO * operand.y() * self.as_inner().rz() * self.as_inner().s()
+ -T::TWO * operand.z() * self.as_inner().ry() * self.as_inner().s()
+ T::TWO * operand.z() * self.as_inner().rx() * self.as_inner().rz()
+ operand.x(),
-T::TWO * operand.x() * self.as_inner().rx() * self.as_inner().ry()
+ -T::TWO * operand.y() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.y() * self.as_inner().rz() * self.as_inner().rz()
+ -T::TWO * operand.z() * self.as_inner().rx() * self.as_inner().s()
+ -T::TWO * operand.z() * self.as_inner().ry() * self.as_inner().rz()
+ T::TWO * operand.x() * self.as_inner().rz() * self.as_inner().s()
+ operand.y(),
-T::TWO * operand.y() * self.as_inner().ry() * self.as_inner().rz()
+ -T::TWO * operand.z() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.z() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.x() * self.as_inner().rx() * self.as_inner().rz()
+ T::TWO * operand.x() * self.as_inner().ry() * self.as_inner().s()
+ T::TWO * operand.y() * self.as_inner().rx() * self.as_inner().s()
+ operand.z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Vector<T>>> for Rotor<T> {
type Output = Vector<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
-(operand.as_inner().x() * self.ry() * self.ry())
+ -(operand.as_inner().x() * self.rz() * self.rz())
+ -T::TWO * operand.as_inner().y() * self.rx() * self.ry()
+ -T::TWO * operand.as_inner().y() * self.rz() * self.s()
+ -T::TWO * operand.as_inner().z() * self.ry() * self.s()
+ T::TWO * operand.as_inner().z() * self.rx() * self.rz()
+ operand.as_inner().x() * self.rx() * self.rx()
+ operand.as_inner().x() * self.s() * self.s(),
-(operand.as_inner().y() * self.rx() * self.rx())
+ -(operand.as_inner().y() * self.rz() * self.rz())
+ -T::TWO * operand.as_inner().x() * self.rx() * self.ry()
+ -T::TWO * operand.as_inner().z() * self.rx() * self.s()
+ -T::TWO * operand.as_inner().z() * self.ry() * self.rz()
+ T::TWO * operand.as_inner().x() * self.rz() * self.s()
+ operand.as_inner().y() * self.ry() * self.ry()
+ operand.as_inner().y() * self.s() * self.s(),
-(operand.as_inner().z() * self.rx() * self.rx())
+ -(operand.as_inner().z() * self.ry() * self.ry())
+ -T::TWO * operand.as_inner().y() * self.ry() * self.rz()
+ T::TWO * operand.as_inner().x() * self.rx() * self.rz()
+ T::TWO * operand.as_inner().x() * self.ry() * self.s()
+ T::TWO * operand.as_inner().y() * self.rx() * self.s()
+ operand.as_inner().z() * self.rz() * self.rz()
+ operand.as_inner().z() * self.s() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Vector<T>>> for Unit<Rotor<T>> {
type Output = Vector<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
-T::TWO * operand.as_inner().x() * self.as_inner().ry() * self.as_inner().ry()
+ -T::TWO * operand.as_inner().x() * self.as_inner().rz() * self.as_inner().rz()
+ -T::TWO * operand.as_inner().y() * self.as_inner().rx() * self.as_inner().ry()
+ -T::TWO * operand.as_inner().y() * self.as_inner().rz() * self.as_inner().s()
+ -T::TWO * operand.as_inner().z() * self.as_inner().ry() * self.as_inner().s()
+ T::TWO * operand.as_inner().z() * self.as_inner().rx() * self.as_inner().rz()
+ operand.as_inner().x(),
-T::TWO * operand.as_inner().x() * self.as_inner().rx() * self.as_inner().ry()
+ -T::TWO * operand.as_inner().y() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.as_inner().y() * self.as_inner().rz() * self.as_inner().rz()
+ -T::TWO * operand.as_inner().z() * self.as_inner().rx() * self.as_inner().s()
+ -T::TWO * operand.as_inner().z() * self.as_inner().ry() * self.as_inner().rz()
+ T::TWO * operand.as_inner().x() * self.as_inner().rz() * self.as_inner().s()
+ operand.as_inner().y(),
-T::TWO * operand.as_inner().y() * self.as_inner().ry() * self.as_inner().rz()
+ -T::TWO * operand.as_inner().z() * self.as_inner().rx() * self.as_inner().rx()
+ -T::TWO * operand.as_inner().z() * self.as_inner().ry() * self.as_inner().ry()
+ T::TWO * operand.as_inner().x() * self.as_inner().rx() * self.as_inner().rz()
+ T::TWO * operand.as_inner().x() * self.as_inner().ry() * self.as_inner().s()
+ T::TWO * operand.as_inner().y() * self.as_inner().rx() * self.as_inner().s()
+ operand.as_inner().z(),
)
}
}
#[doc = "Antisandwich product: [`Scalar`] x [`Bivector`] x antirev([`Scalar`]).\n\nThe antisandwich product `v x a x antirev(v)` is the dual of the\nsandwich product, used in Projective GA for transforming dual objects\n(planes, ideal points). Motors use antisandwich for plane transforms."]
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Bivector<T>> for Scalar<T> {
type Output = Bivector<T>;
#[inline]
fn antisandwich(&self, operand: &Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
self.s() * operand.rz() * self.s(),
self.s() * operand.ry() * self.s(),
self.s() * operand.rx() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Bivector<T>> for Unit<Scalar<T>> {
type Output = Bivector<T>;
#[inline]
fn antisandwich(&self, operand: &Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(operand.rz(), operand.ry(), operand.rx())
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Bivector<T>>> for Scalar<T> {
type Output = Bivector<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Bivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
operand.as_inner().rz() * self.s() * self.s(),
operand.as_inner().ry() * self.s() * self.s(),
operand.as_inner().rx() * self.s() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Bivector<T>>> for Unit<Scalar<T>> {
type Output = Bivector<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Bivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
operand.as_inner().rz(),
operand.as_inner().ry(),
operand.as_inner().rx(),
)
}
}
#[doc = "Antisandwich product: [`Scalar`] x [`Rotor`] x antirev([`Scalar`]).\n\nThe antisandwich product `v x a x antirev(v)` is the dual of the\nsandwich product, used in Projective GA for transforming dual objects\n(planes, ideal points). Motors use antisandwich for plane transforms."]
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Rotor<T>> for Scalar<T> {
type Output = Rotor<T>;
#[inline]
fn antisandwich(&self, operand: &Rotor<T>) -> Rotor<T> {
Rotor::new_unchecked(
self.s() * operand.s() * self.s(),
self.s() * operand.rz() * self.s(),
self.s() * operand.ry() * self.s(),
self.s() * operand.rx() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Rotor<T>> for Unit<Scalar<T>> {
type Output = Rotor<T>;
#[inline]
fn antisandwich(&self, operand: &Rotor<T>) -> Rotor<T> {
Rotor::new_unchecked(operand.s(), operand.rz(), operand.ry(), operand.rx())
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Rotor<T>>> for Scalar<T> {
type Output = Rotor<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Rotor<T>>) -> Rotor<T> {
Rotor::new_unchecked(
operand.as_inner().s() * self.s() * self.s(),
operand.as_inner().rz() * self.s() * self.s(),
operand.as_inner().ry() * self.s() * self.s(),
operand.as_inner().rx() * self.s() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Rotor<T>>> for Unit<Scalar<T>> {
type Output = Rotor<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Rotor<T>>) -> Rotor<T> {
Rotor::new_unchecked(
operand.as_inner().s(),
operand.as_inner().rz(),
operand.as_inner().ry(),
operand.as_inner().rx(),
)
}
}
#[doc = "Antisandwich product: [`Scalar`] x [`Scalar`] x antirev([`Scalar`]).\n\nThe antisandwich product `v x a x antirev(v)` is the dual of the\nsandwich product, used in Projective GA for transforming dual objects\n(planes, ideal points). Motors use antisandwich for plane transforms."]
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Scalar<T>> for Scalar<T> {
type Output = Scalar<T>;
#[inline]
fn antisandwich(&self, operand: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(self.s() * operand.s() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Scalar<T>> for Unit<Scalar<T>> {
type Output = Scalar<T>;
#[inline]
fn antisandwich(&self, operand: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(operand.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Scalar<T>>> for Scalar<T> {
type Output = Scalar<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(operand.as_inner().s() * self.s() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Scalar<T>>> for Unit<Scalar<T>> {
type Output = Scalar<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(operand.as_inner().s())
}
}
#[doc = "Antisandwich product: [`Scalar`] x [`Trivector`] x antirev([`Scalar`]).\n\nThe antisandwich product `v x a x antirev(v)` is the dual of the\nsandwich product, used in Projective GA for transforming dual objects\n(planes, ideal points). Motors use antisandwich for plane transforms."]
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Trivector<T>> for Scalar<T> {
type Output = Trivector<T>;
#[inline]
fn antisandwich(&self, operand: &Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(self.s() * operand.ps() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Trivector<T>> for Unit<Scalar<T>> {
type Output = Trivector<T>;
#[inline]
fn antisandwich(&self, operand: &Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(operand.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Trivector<T>>> for Scalar<T> {
type Output = Trivector<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Trivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(operand.as_inner().ps() * self.s() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Trivector<T>>> for Unit<Scalar<T>> {
type Output = Trivector<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Trivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(operand.as_inner().ps())
}
}
#[doc = "Antisandwich product: [`Scalar`] x [`Vector`] x antirev([`Scalar`]).\n\nThe antisandwich product `v x a x antirev(v)` is the dual of the\nsandwich product, used in Projective GA for transforming dual objects\n(planes, ideal points). Motors use antisandwich for plane transforms."]
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Vector<T>> for Scalar<T> {
type Output = Vector<T>;
#[inline]
fn antisandwich(&self, operand: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(
self.s() * operand.x() * self.s(),
self.s() * operand.y() * self.s(),
self.s() * operand.z() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Vector<T>> for Unit<Scalar<T>> {
type Output = Vector<T>;
#[inline]
fn antisandwich(&self, operand: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(operand.x(), operand.y(), operand.z())
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Vector<T>>> for Scalar<T> {
type Output = Vector<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
operand.as_inner().x() * self.s() * self.s(),
operand.as_inner().y() * self.s() * self.s(),
operand.as_inner().z() * self.s() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Vector<T>>> for Unit<Scalar<T>> {
type Output = Vector<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
operand.as_inner().x(),
operand.as_inner().y(),
operand.as_inner().z(),
)
}
}
#[doc = "Antisandwich product: [`Trivector`] x [`Bivector`] x antirev([`Trivector`]).\n\nThe antisandwich product `v x a x antirev(v)` is the dual of the\nsandwich product, used in Projective GA for transforming dual objects\n(planes, ideal points). Motors use antisandwich for plane transforms."]
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Bivector<T>> for Trivector<T> {
type Output = Bivector<T>;
#[inline]
fn antisandwich(&self, operand: &Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
self.ps() * operand.rz() * self.ps(),
self.ps() * operand.ry() * self.ps(),
self.ps() * operand.rx() * self.ps(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Bivector<T>> for Unit<Trivector<T>> {
type Output = Bivector<T>;
#[inline]
fn antisandwich(&self, operand: &Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(operand.rz(), operand.ry(), operand.rx())
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Bivector<T>>> for Trivector<T> {
type Output = Bivector<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Bivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
operand.as_inner().rz() * self.ps() * self.ps(),
operand.as_inner().ry() * self.ps() * self.ps(),
operand.as_inner().rx() * self.ps() * self.ps(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Bivector<T>>> for Unit<Trivector<T>> {
type Output = Bivector<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Bivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
operand.as_inner().rz(),
operand.as_inner().ry(),
operand.as_inner().rx(),
)
}
}
#[doc = "Antisandwich product: [`Trivector`] x [`Rotor`] x antirev([`Trivector`]).\n\nThe antisandwich product `v x a x antirev(v)` is the dual of the\nsandwich product, used in Projective GA for transforming dual objects\n(planes, ideal points). Motors use antisandwich for plane transforms."]
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Rotor<T>> for Trivector<T> {
type Output = Rotor<T>;
#[inline]
fn antisandwich(&self, operand: &Rotor<T>) -> Rotor<T> {
Rotor::new_unchecked(
self.ps() * operand.s() * self.ps(),
self.ps() * operand.rz() * self.ps(),
self.ps() * operand.ry() * self.ps(),
self.ps() * operand.rx() * self.ps(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Rotor<T>> for Unit<Trivector<T>> {
type Output = Rotor<T>;
#[inline]
fn antisandwich(&self, operand: &Rotor<T>) -> Rotor<T> {
Rotor::new_unchecked(operand.s(), operand.rz(), operand.ry(), operand.rx())
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Rotor<T>>> for Trivector<T> {
type Output = Rotor<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Rotor<T>>) -> Rotor<T> {
Rotor::new_unchecked(
operand.as_inner().s() * self.ps() * self.ps(),
operand.as_inner().rz() * self.ps() * self.ps(),
operand.as_inner().ry() * self.ps() * self.ps(),
operand.as_inner().rx() * self.ps() * self.ps(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Rotor<T>>> for Unit<Trivector<T>> {
type Output = Rotor<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Rotor<T>>) -> Rotor<T> {
Rotor::new_unchecked(
operand.as_inner().s(),
operand.as_inner().rz(),
operand.as_inner().ry(),
operand.as_inner().rx(),
)
}
}
#[doc = "Antisandwich product: [`Trivector`] x [`Scalar`] x antirev([`Trivector`]).\n\nThe antisandwich product `v x a x antirev(v)` is the dual of the\nsandwich product, used in Projective GA for transforming dual objects\n(planes, ideal points). Motors use antisandwich for plane transforms."]
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Scalar<T>> for Trivector<T> {
type Output = Scalar<T>;
#[inline]
fn antisandwich(&self, operand: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(self.ps() * operand.s() * self.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Scalar<T>> for Unit<Trivector<T>> {
type Output = Scalar<T>;
#[inline]
fn antisandwich(&self, operand: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(operand.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Scalar<T>>> for Trivector<T> {
type Output = Scalar<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(operand.as_inner().s() * self.ps() * self.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Scalar<T>>> for Unit<Trivector<T>> {
type Output = Scalar<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(operand.as_inner().s())
}
}
#[doc = "Antisandwich product: [`Trivector`] x [`Trivector`] x antirev([`Trivector`]).\n\nThe antisandwich product `v x a x antirev(v)` is the dual of the\nsandwich product, used in Projective GA for transforming dual objects\n(planes, ideal points). Motors use antisandwich for plane transforms."]
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Trivector<T>> for Trivector<T> {
type Output = Trivector<T>;
#[inline]
fn antisandwich(&self, operand: &Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(self.ps() * operand.ps() * self.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Trivector<T>> for Unit<Trivector<T>> {
type Output = Trivector<T>;
#[inline]
fn antisandwich(&self, operand: &Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(operand.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Trivector<T>>> for Trivector<T> {
type Output = Trivector<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Trivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(operand.as_inner().ps() * self.ps() * self.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Trivector<T>>> for Unit<Trivector<T>> {
type Output = Trivector<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Trivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(operand.as_inner().ps())
}
}
#[doc = "Antisandwich product: [`Trivector`] x [`Vector`] x antirev([`Trivector`]).\n\nThe antisandwich product `v x a x antirev(v)` is the dual of the\nsandwich product, used in Projective GA for transforming dual objects\n(planes, ideal points). Motors use antisandwich for plane transforms."]
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Vector<T>> for Trivector<T> {
type Output = Vector<T>;
#[inline]
fn antisandwich(&self, operand: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(
self.ps() * operand.x() * self.ps(),
self.ps() * operand.y() * self.ps(),
self.ps() * operand.z() * self.ps(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Vector<T>> for Unit<Trivector<T>> {
type Output = Vector<T>;
#[inline]
fn antisandwich(&self, operand: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(operand.x(), operand.y(), operand.z())
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Vector<T>>> for Trivector<T> {
type Output = Vector<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
operand.as_inner().x() * self.ps() * self.ps(),
operand.as_inner().y() * self.ps() * self.ps(),
operand.as_inner().z() * self.ps() * self.ps(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Vector<T>>> for Unit<Trivector<T>> {
type Output = Vector<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
operand.as_inner().x(),
operand.as_inner().y(),
operand.as_inner().z(),
)
}
}
#[doc = "Antisandwich product: [`Vector`] x [`Bivector`] x antirev([`Vector`]).\n\nThe antisandwich product `v x a x antirev(v)` is the dual of the\nsandwich product, used in Projective GA for transforming dual objects\n(planes, ideal points). Motors use antisandwich for plane transforms."]
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Bivector<T>> for Vector<T> {
type Output = Bivector<T>;
#[inline]
fn antisandwich(&self, operand: &Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
self.x() * operand.rx() * self.z()
- self.x() * operand.rz() * self.x()
- self.y() * operand.ry() * self.z()
- self.y() * operand.rz() * self.y()
+ self.z() * operand.rx() * self.x()
- self.z() * operand.ry() * self.y()
+ self.z() * operand.rz() * self.z(),
-(self.x() * operand.rx() * self.y())
- self.x() * operand.ry() * self.x()
- self.y() * operand.rx() * self.x()
+ self.y() * operand.ry() * self.y()
- self.y() * operand.rz() * self.z()
- self.z() * operand.ry() * self.z()
- self.z() * operand.rz() * self.y(),
self.x() * operand.rx() * self.x() - self.x() * operand.ry() * self.y()
+ self.x() * operand.rz() * self.z()
- self.y() * operand.rx() * self.y()
- self.y() * operand.ry() * self.x()
- self.z() * operand.rx() * self.z()
+ self.z() * operand.rz() * self.x(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Bivector<T>> for Unit<Vector<T>> {
type Output = Bivector<T>;
#[inline]
fn antisandwich(&self, operand: &Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
-(operand.rz())
+ -T::TWO * operand.ry() * self.as_inner().y() * self.as_inner().z()
+ T::TWO * operand.rx() * self.as_inner().x() * self.as_inner().z()
+ T::TWO * operand.rz() * self.as_inner().z() * self.as_inner().z(),
-(operand.ry())
+ -T::TWO * operand.rx() * self.as_inner().x() * self.as_inner().y()
+ -T::TWO * operand.rz() * self.as_inner().y() * self.as_inner().z()
+ T::TWO * operand.ry() * self.as_inner().y() * self.as_inner().y(),
-T::TWO * operand.rx() * self.as_inner().y() * self.as_inner().y()
+ -T::TWO * operand.rx() * self.as_inner().z() * self.as_inner().z()
+ -T::TWO * operand.ry() * self.as_inner().x() * self.as_inner().y()
+ T::TWO * operand.rz() * self.as_inner().x() * self.as_inner().z()
+ operand.rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Bivector<T>>> for Vector<T> {
type Output = Bivector<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Bivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
-(operand.as_inner().rz() * self.x() * self.x())
+ -(operand.as_inner().rz() * self.y() * self.y())
+ -T::TWO * operand.as_inner().ry() * self.y() * self.z()
+ T::TWO * operand.as_inner().rx() * self.x() * self.z()
+ operand.as_inner().rz() * self.z() * self.z(),
-(operand.as_inner().ry() * self.x() * self.x())
+ -(operand.as_inner().ry() * self.z() * self.z())
+ -T::TWO * operand.as_inner().rx() * self.x() * self.y()
+ -T::TWO * operand.as_inner().rz() * self.y() * self.z()
+ operand.as_inner().ry() * self.y() * self.y(),
-(operand.as_inner().rx() * self.y() * self.y())
+ -(operand.as_inner().rx() * self.z() * self.z())
+ -T::TWO * operand.as_inner().ry() * self.x() * self.y()
+ T::TWO * operand.as_inner().rz() * self.x() * self.z()
+ operand.as_inner().rx() * self.x() * self.x(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Bivector<T>>> for Unit<Vector<T>> {
type Output = Bivector<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Bivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
-(operand.as_inner().rz())
+ -T::TWO * operand.as_inner().ry() * self.as_inner().y() * self.as_inner().z()
+ T::TWO * operand.as_inner().rx() * self.as_inner().x() * self.as_inner().z()
+ T::TWO * operand.as_inner().rz() * self.as_inner().z() * self.as_inner().z(),
-(operand.as_inner().ry())
+ -T::TWO * operand.as_inner().rx() * self.as_inner().x() * self.as_inner().y()
+ -T::TWO * operand.as_inner().rz() * self.as_inner().y() * self.as_inner().z()
+ T::TWO * operand.as_inner().ry() * self.as_inner().y() * self.as_inner().y(),
-T::TWO * operand.as_inner().rx() * self.as_inner().y() * self.as_inner().y()
+ -T::TWO * operand.as_inner().rx() * self.as_inner().z() * self.as_inner().z()
+ -T::TWO * operand.as_inner().ry() * self.as_inner().x() * self.as_inner().y()
+ T::TWO * operand.as_inner().rz() * self.as_inner().x() * self.as_inner().z()
+ operand.as_inner().rx(),
)
}
}
#[doc = "Antisandwich product: [`Vector`] x [`Rotor`] x antirev([`Vector`]).\n\nThe antisandwich product `v x a x antirev(v)` is the dual of the\nsandwich product, used in Projective GA for transforming dual objects\n(planes, ideal points). Motors use antisandwich for plane transforms."]
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Rotor<T>> for Vector<T> {
type Output = Rotor<T>;
#[inline]
fn antisandwich(&self, operand: &Rotor<T>) -> Rotor<T> {
Rotor::new_unchecked(
-(self.x() * operand.ry() * self.z()) - self.x() * operand.rz() * self.y()
+ self.x() * operand.s() * self.x()
- self.y() * operand.rx() * self.z()
+ self.y() * operand.rz() * self.x()
+ self.y() * operand.s() * self.y()
+ self.z() * operand.rx() * self.y()
+ self.z() * operand.ry() * self.x()
+ self.z() * operand.s() * self.z(),
self.x() * operand.rx() * self.z()
- self.x() * operand.rz() * self.x()
- self.x() * operand.s() * self.y()
- self.y() * operand.ry() * self.z()
- self.y() * operand.rz() * self.y()
+ self.y() * operand.s() * self.x()
+ self.z() * operand.rx() * self.x()
- self.z() * operand.ry() * self.y()
+ self.z() * operand.rz() * self.z(),
-(self.x() * operand.rx() * self.y())
- self.x() * operand.ry() * self.x()
- self.x() * operand.s() * self.z()
- self.y() * operand.rx() * self.x()
+ self.y() * operand.ry() * self.y()
- self.y() * operand.rz() * self.z()
- self.z() * operand.ry() * self.z()
- self.z() * operand.rz() * self.y()
+ self.z() * operand.s() * self.x(),
self.x() * operand.rx() * self.x() - self.x() * operand.ry() * self.y()
+ self.x() * operand.rz() * self.z()
- self.y() * operand.rx() * self.y()
- self.y() * operand.ry() * self.x()
- self.y() * operand.s() * self.z()
- self.z() * operand.rx() * self.z()
+ self.z() * operand.rz() * self.x()
+ self.z() * operand.s() * self.y(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Rotor<T>> for Unit<Vector<T>> {
type Output = Rotor<T>;
#[inline]
fn antisandwich(&self, operand: &Rotor<T>) -> Rotor<T> {
Rotor::new_unchecked(
operand.s(),
-(operand.rz())
+ -T::TWO * operand.ry() * self.as_inner().y() * self.as_inner().z()
+ T::TWO * operand.rx() * self.as_inner().x() * self.as_inner().z()
+ T::TWO * operand.rz() * self.as_inner().z() * self.as_inner().z(),
-(operand.ry())
+ -T::TWO * operand.rx() * self.as_inner().x() * self.as_inner().y()
+ -T::TWO * operand.rz() * self.as_inner().y() * self.as_inner().z()
+ T::TWO * operand.ry() * self.as_inner().y() * self.as_inner().y(),
-T::TWO * operand.rx() * self.as_inner().y() * self.as_inner().y()
+ -T::TWO * operand.rx() * self.as_inner().z() * self.as_inner().z()
+ -T::TWO * operand.ry() * self.as_inner().x() * self.as_inner().y()
+ T::TWO * operand.rz() * self.as_inner().x() * self.as_inner().z()
+ operand.rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Rotor<T>>> for Vector<T> {
type Output = Rotor<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Rotor<T>>) -> Rotor<T> {
Rotor::new_unchecked(
operand.as_inner().s() * self.x() * self.x()
+ operand.as_inner().s() * self.y() * self.y()
+ operand.as_inner().s() * self.z() * self.z(),
-(operand.as_inner().rz() * self.x() * self.x())
+ -(operand.as_inner().rz() * self.y() * self.y())
+ -T::TWO * operand.as_inner().ry() * self.y() * self.z()
+ T::TWO * operand.as_inner().rx() * self.x() * self.z()
+ operand.as_inner().rz() * self.z() * self.z(),
-(operand.as_inner().ry() * self.x() * self.x())
+ -(operand.as_inner().ry() * self.z() * self.z())
+ -T::TWO * operand.as_inner().rx() * self.x() * self.y()
+ -T::TWO * operand.as_inner().rz() * self.y() * self.z()
+ operand.as_inner().ry() * self.y() * self.y(),
-(operand.as_inner().rx() * self.y() * self.y())
+ -(operand.as_inner().rx() * self.z() * self.z())
+ -T::TWO * operand.as_inner().ry() * self.x() * self.y()
+ T::TWO * operand.as_inner().rz() * self.x() * self.z()
+ operand.as_inner().rx() * self.x() * self.x(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Rotor<T>>> for Unit<Vector<T>> {
type Output = Rotor<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Rotor<T>>) -> Rotor<T> {
Rotor::new_unchecked(
operand.as_inner().s(),
-(operand.as_inner().rz())
+ -T::TWO * operand.as_inner().ry() * self.as_inner().y() * self.as_inner().z()
+ T::TWO * operand.as_inner().rx() * self.as_inner().x() * self.as_inner().z()
+ T::TWO * operand.as_inner().rz() * self.as_inner().z() * self.as_inner().z(),
-(operand.as_inner().ry())
+ -T::TWO * operand.as_inner().rx() * self.as_inner().x() * self.as_inner().y()
+ -T::TWO * operand.as_inner().rz() * self.as_inner().y() * self.as_inner().z()
+ T::TWO * operand.as_inner().ry() * self.as_inner().y() * self.as_inner().y(),
-T::TWO * operand.as_inner().rx() * self.as_inner().y() * self.as_inner().y()
+ -T::TWO * operand.as_inner().rx() * self.as_inner().z() * self.as_inner().z()
+ -T::TWO * operand.as_inner().ry() * self.as_inner().x() * self.as_inner().y()
+ T::TWO * operand.as_inner().rz() * self.as_inner().x() * self.as_inner().z()
+ operand.as_inner().rx(),
)
}
}
#[doc = "Antisandwich product: [`Vector`] x [`Scalar`] x antirev([`Vector`]).\n\nThe antisandwich product `v x a x antirev(v)` is the dual of the\nsandwich product, used in Projective GA for transforming dual objects\n(planes, ideal points). Motors use antisandwich for plane transforms."]
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Scalar<T>> for Vector<T> {
type Output = Scalar<T>;
#[inline]
fn antisandwich(&self, operand: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(
self.x() * operand.s() * self.x()
+ self.y() * operand.s() * self.y()
+ self.z() * operand.s() * self.z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Scalar<T>> for Unit<Vector<T>> {
type Output = Scalar<T>;
#[inline]
fn antisandwich(&self, operand: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(operand.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Scalar<T>>> for Vector<T> {
type Output = Scalar<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(
operand.as_inner().s() * self.x() * self.x()
+ operand.as_inner().s() * self.y() * self.y()
+ operand.as_inner().s() * self.z() * self.z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Scalar<T>>> for Unit<Vector<T>> {
type Output = Scalar<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(operand.as_inner().s())
}
}
#[doc = "Antisandwich product: [`Vector`] x [`Trivector`] x antirev([`Vector`]).\n\nThe antisandwich product `v x a x antirev(v)` is the dual of the\nsandwich product, used in Projective GA for transforming dual objects\n(planes, ideal points). Motors use antisandwich for plane transforms."]
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Trivector<T>> for Vector<T> {
type Output = Trivector<T>;
#[inline]
fn antisandwich(&self, operand: &Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(
self.x() * operand.ps() * self.x()
+ self.y() * operand.ps() * self.y()
+ self.z() * operand.ps() * self.z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Trivector<T>> for Unit<Vector<T>> {
type Output = Trivector<T>;
#[inline]
fn antisandwich(&self, operand: &Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(operand.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Trivector<T>>> for Vector<T> {
type Output = Trivector<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Trivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(
operand.as_inner().ps() * self.x() * self.x()
+ operand.as_inner().ps() * self.y() * self.y()
+ operand.as_inner().ps() * self.z() * self.z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Trivector<T>>> for Unit<Vector<T>> {
type Output = Trivector<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Trivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(operand.as_inner().ps())
}
}
#[doc = "Antisandwich product: [`Vector`] x [`Vector`] x antirev([`Vector`]).\n\nThe antisandwich product `v x a x antirev(v)` is the dual of the\nsandwich product, used in Projective GA for transforming dual objects\n(planes, ideal points). Motors use antisandwich for plane transforms."]
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Vector<T>> for Vector<T> {
type Output = Vector<T>;
#[inline]
fn antisandwich(&self, operand: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(
self.x() * operand.x() * self.x()
+ self.x() * operand.y() * self.y()
+ self.x() * operand.z() * self.z()
- self.y() * operand.x() * self.y()
+ self.y() * operand.y() * self.x()
- self.z() * operand.x() * self.z()
+ self.z() * operand.z() * self.x(),
self.x() * operand.x() * self.y() - self.x() * operand.y() * self.x()
+ self.y() * operand.x() * self.x()
+ self.y() * operand.y() * self.y()
+ self.y() * operand.z() * self.z()
- self.z() * operand.y() * self.z()
+ self.z() * operand.z() * self.y(),
self.x() * operand.x() * self.z() - self.x() * operand.z() * self.x()
+ self.y() * operand.y() * self.z()
- self.y() * operand.z() * self.y()
+ self.z() * operand.x() * self.x()
+ self.z() * operand.y() * self.y()
+ self.z() * operand.z() * self.z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Vector<T>> for Unit<Vector<T>> {
type Output = Vector<T>;
#[inline]
fn antisandwich(&self, operand: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(
-T::TWO * operand.x() * self.as_inner().y() * self.as_inner().y()
+ -T::TWO * operand.x() * self.as_inner().z() * self.as_inner().z()
+ T::TWO * operand.y() * self.as_inner().x() * self.as_inner().y()
+ T::TWO * operand.z() * self.as_inner().x() * self.as_inner().z()
+ operand.x(),
-(operand.y())
+ T::TWO * operand.x() * self.as_inner().x() * self.as_inner().y()
+ T::TWO * operand.y() * self.as_inner().y() * self.as_inner().y()
+ T::TWO * operand.z() * self.as_inner().y() * self.as_inner().z(),
-(operand.z())
+ T::TWO * operand.x() * self.as_inner().x() * self.as_inner().z()
+ T::TWO * operand.y() * self.as_inner().y() * self.as_inner().z()
+ T::TWO * operand.z() * self.as_inner().z() * self.as_inner().z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Vector<T>>> for Vector<T> {
type Output = Vector<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
-(operand.as_inner().x() * self.y() * self.y())
+ -(operand.as_inner().x() * self.z() * self.z())
+ T::TWO * operand.as_inner().y() * self.x() * self.y()
+ T::TWO * operand.as_inner().z() * self.x() * self.z()
+ operand.as_inner().x() * self.x() * self.x(),
-(operand.as_inner().y() * self.x() * self.x())
+ -(operand.as_inner().y() * self.z() * self.z())
+ T::TWO * operand.as_inner().x() * self.x() * self.y()
+ T::TWO * operand.as_inner().z() * self.y() * self.z()
+ operand.as_inner().y() * self.y() * self.y(),
-(operand.as_inner().z() * self.x() * self.x())
+ -(operand.as_inner().z() * self.y() * self.y())
+ T::TWO * operand.as_inner().x() * self.x() * self.z()
+ T::TWO * operand.as_inner().y() * self.y() * self.z()
+ operand.as_inner().z() * self.z() * self.z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> Antisandwich<Unit<Vector<T>>> for Unit<Vector<T>> {
type Output = Vector<T>;
#[inline]
fn antisandwich(&self, operand: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
-T::TWO * operand.as_inner().x() * self.as_inner().y() * self.as_inner().y()
+ -T::TWO * operand.as_inner().x() * self.as_inner().z() * self.as_inner().z()
+ T::TWO * operand.as_inner().y() * self.as_inner().x() * self.as_inner().y()
+ T::TWO * operand.as_inner().z() * self.as_inner().x() * self.as_inner().z()
+ operand.as_inner().x(),
-(operand.as_inner().y())
+ T::TWO * operand.as_inner().x() * self.as_inner().x() * self.as_inner().y()
+ T::TWO * operand.as_inner().y() * self.as_inner().y() * self.as_inner().y()
+ T::TWO * operand.as_inner().z() * self.as_inner().y() * self.as_inner().z(),
-(operand.as_inner().z())
+ T::TWO * operand.as_inner().x() * self.as_inner().x() * self.as_inner().z()
+ T::TWO * operand.as_inner().y() * self.as_inner().y() * self.as_inner().z()
+ T::TWO * operand.as_inner().z() * self.as_inner().z() * self.as_inner().z(),
)
}
}
#[doc = "Transform a [`Bivector`] using this [`Bivector`].\n\nApplies the geometric transformation represented by this versor.\nFor rotors, this performs rotation. For motors, this performs rigid\nbody transformation (rotation + translation). Internally uses the\nsandwich product."]
impl<T: Float> Transform<Bivector<T>> for Bivector<T> {
type Output = Bivector<T>;
#[inline]
fn transform(&self, operand: &Bivector<T>) -> Bivector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Bivector<T>> for Unit<Bivector<T>> {
type Output = Bivector<T>;
#[inline]
fn transform(&self, operand: &Bivector<T>) -> Bivector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Bivector<T>>> for Bivector<T> {
type Output = Bivector<T>;
#[inline]
fn transform(&self, operand: &Unit<Bivector<T>>) -> Bivector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Bivector<T>>> for Unit<Bivector<T>> {
type Output = Bivector<T>;
#[inline]
fn transform(&self, operand: &Unit<Bivector<T>>) -> Bivector<T> {
self.sandwich(operand)
}
}
#[doc = "Transform a [`Rotor`] using this [`Bivector`].\n\nApplies the geometric transformation represented by this versor.\nFor rotors, this performs rotation. For motors, this performs rigid\nbody transformation (rotation + translation). Internally uses the\nsandwich product."]
impl<T: Float> Transform<Rotor<T>> for Bivector<T> {
type Output = Rotor<T>;
#[inline]
fn transform(&self, operand: &Rotor<T>) -> Rotor<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Rotor<T>> for Unit<Bivector<T>> {
type Output = Rotor<T>;
#[inline]
fn transform(&self, operand: &Rotor<T>) -> Rotor<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Rotor<T>>> for Bivector<T> {
type Output = Rotor<T>;
#[inline]
fn transform(&self, operand: &Unit<Rotor<T>>) -> Rotor<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Rotor<T>>> for Unit<Bivector<T>> {
type Output = Rotor<T>;
#[inline]
fn transform(&self, operand: &Unit<Rotor<T>>) -> Rotor<T> {
self.sandwich(operand)
}
}
#[doc = "Transform a [`Scalar`] using this [`Bivector`].\n\nApplies the geometric transformation represented by this versor.\nFor rotors, this performs rotation. For motors, this performs rigid\nbody transformation (rotation + translation). Internally uses the\nsandwich product."]
impl<T: Float> Transform<Scalar<T>> for Bivector<T> {
type Output = Scalar<T>;
#[inline]
fn transform(&self, operand: &Scalar<T>) -> Scalar<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Scalar<T>> for Unit<Bivector<T>> {
type Output = Scalar<T>;
#[inline]
fn transform(&self, operand: &Scalar<T>) -> Scalar<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Scalar<T>>> for Bivector<T> {
type Output = Scalar<T>;
#[inline]
fn transform(&self, operand: &Unit<Scalar<T>>) -> Scalar<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Scalar<T>>> for Unit<Bivector<T>> {
type Output = Scalar<T>;
#[inline]
fn transform(&self, operand: &Unit<Scalar<T>>) -> Scalar<T> {
self.sandwich(operand)
}
}
#[doc = "Transform a [`Trivector`] using this [`Bivector`].\n\nApplies the geometric transformation represented by this versor.\nFor rotors, this performs rotation. For motors, this performs rigid\nbody transformation (rotation + translation). Internally uses the\nsandwich product."]
impl<T: Float> Transform<Trivector<T>> for Bivector<T> {
type Output = Trivector<T>;
#[inline]
fn transform(&self, operand: &Trivector<T>) -> Trivector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Trivector<T>> for Unit<Bivector<T>> {
type Output = Trivector<T>;
#[inline]
fn transform(&self, operand: &Trivector<T>) -> Trivector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Trivector<T>>> for Bivector<T> {
type Output = Trivector<T>;
#[inline]
fn transform(&self, operand: &Unit<Trivector<T>>) -> Trivector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Trivector<T>>> for Unit<Bivector<T>> {
type Output = Trivector<T>;
#[inline]
fn transform(&self, operand: &Unit<Trivector<T>>) -> Trivector<T> {
self.sandwich(operand)
}
}
#[doc = "Transform a [`Vector`] using this [`Bivector`].\n\nApplies the geometric transformation represented by this versor.\nFor rotors, this performs rotation. For motors, this performs rigid\nbody transformation (rotation + translation). Internally uses the\nsandwich product."]
impl<T: Float> Transform<Vector<T>> for Bivector<T> {
type Output = Vector<T>;
#[inline]
fn transform(&self, operand: &Vector<T>) -> Vector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Vector<T>> for Unit<Bivector<T>> {
type Output = Vector<T>;
#[inline]
fn transform(&self, operand: &Vector<T>) -> Vector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Vector<T>>> for Bivector<T> {
type Output = Vector<T>;
#[inline]
fn transform(&self, operand: &Unit<Vector<T>>) -> Vector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Vector<T>>> for Unit<Bivector<T>> {
type Output = Vector<T>;
#[inline]
fn transform(&self, operand: &Unit<Vector<T>>) -> Vector<T> {
self.sandwich(operand)
}
}
#[doc = "Transform a [`Bivector`] using this [`Rotor`].\n\nApplies the geometric transformation represented by this versor.\nFor rotors, this performs rotation. For motors, this performs rigid\nbody transformation (rotation + translation). Internally uses the\nsandwich product."]
impl<T: Float> Transform<Bivector<T>> for Rotor<T> {
type Output = Bivector<T>;
#[inline]
fn transform(&self, operand: &Bivector<T>) -> Bivector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Bivector<T>> for Unit<Rotor<T>> {
type Output = Bivector<T>;
#[inline]
fn transform(&self, operand: &Bivector<T>) -> Bivector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Bivector<T>>> for Rotor<T> {
type Output = Bivector<T>;
#[inline]
fn transform(&self, operand: &Unit<Bivector<T>>) -> Bivector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Bivector<T>>> for Unit<Rotor<T>> {
type Output = Bivector<T>;
#[inline]
fn transform(&self, operand: &Unit<Bivector<T>>) -> Bivector<T> {
self.sandwich(operand)
}
}
#[doc = "Transform a [`Rotor`] using this [`Rotor`].\n\nApplies the geometric transformation represented by this versor.\nFor rotors, this performs rotation. For motors, this performs rigid\nbody transformation (rotation + translation). Internally uses the\nsandwich product."]
impl<T: Float> Transform<Rotor<T>> for Rotor<T> {
type Output = Rotor<T>;
#[inline]
fn transform(&self, operand: &Rotor<T>) -> Rotor<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Rotor<T>> for Unit<Rotor<T>> {
type Output = Rotor<T>;
#[inline]
fn transform(&self, operand: &Rotor<T>) -> Rotor<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Rotor<T>>> for Rotor<T> {
type Output = Rotor<T>;
#[inline]
fn transform(&self, operand: &Unit<Rotor<T>>) -> Rotor<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Rotor<T>>> for Unit<Rotor<T>> {
type Output = Rotor<T>;
#[inline]
fn transform(&self, operand: &Unit<Rotor<T>>) -> Rotor<T> {
self.sandwich(operand)
}
}
#[doc = "Transform a [`Scalar`] using this [`Rotor`].\n\nApplies the geometric transformation represented by this versor.\nFor rotors, this performs rotation. For motors, this performs rigid\nbody transformation (rotation + translation). Internally uses the\nsandwich product."]
impl<T: Float> Transform<Scalar<T>> for Rotor<T> {
type Output = Scalar<T>;
#[inline]
fn transform(&self, operand: &Scalar<T>) -> Scalar<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Scalar<T>> for Unit<Rotor<T>> {
type Output = Scalar<T>;
#[inline]
fn transform(&self, operand: &Scalar<T>) -> Scalar<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Scalar<T>>> for Rotor<T> {
type Output = Scalar<T>;
#[inline]
fn transform(&self, operand: &Unit<Scalar<T>>) -> Scalar<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Scalar<T>>> for Unit<Rotor<T>> {
type Output = Scalar<T>;
#[inline]
fn transform(&self, operand: &Unit<Scalar<T>>) -> Scalar<T> {
self.sandwich(operand)
}
}
#[doc = "Transform a [`Trivector`] using this [`Rotor`].\n\nApplies the geometric transformation represented by this versor.\nFor rotors, this performs rotation. For motors, this performs rigid\nbody transformation (rotation + translation). Internally uses the\nsandwich product."]
impl<T: Float> Transform<Trivector<T>> for Rotor<T> {
type Output = Trivector<T>;
#[inline]
fn transform(&self, operand: &Trivector<T>) -> Trivector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Trivector<T>> for Unit<Rotor<T>> {
type Output = Trivector<T>;
#[inline]
fn transform(&self, operand: &Trivector<T>) -> Trivector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Trivector<T>>> for Rotor<T> {
type Output = Trivector<T>;
#[inline]
fn transform(&self, operand: &Unit<Trivector<T>>) -> Trivector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Trivector<T>>> for Unit<Rotor<T>> {
type Output = Trivector<T>;
#[inline]
fn transform(&self, operand: &Unit<Trivector<T>>) -> Trivector<T> {
self.sandwich(operand)
}
}
#[doc = "Transform a [`Vector`] using this [`Rotor`].\n\nApplies the geometric transformation represented by this versor.\nFor rotors, this performs rotation. For motors, this performs rigid\nbody transformation (rotation + translation). Internally uses the\nsandwich product."]
impl<T: Float> Transform<Vector<T>> for Rotor<T> {
type Output = Vector<T>;
#[inline]
fn transform(&self, operand: &Vector<T>) -> Vector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Vector<T>> for Unit<Rotor<T>> {
type Output = Vector<T>;
#[inline]
fn transform(&self, operand: &Vector<T>) -> Vector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Vector<T>>> for Rotor<T> {
type Output = Vector<T>;
#[inline]
fn transform(&self, operand: &Unit<Vector<T>>) -> Vector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Vector<T>>> for Unit<Rotor<T>> {
type Output = Vector<T>;
#[inline]
fn transform(&self, operand: &Unit<Vector<T>>) -> Vector<T> {
self.sandwich(operand)
}
}
#[doc = "Transform a [`Bivector`] using this [`Scalar`].\n\nApplies the geometric transformation represented by this versor.\nFor rotors, this performs rotation. For motors, this performs rigid\nbody transformation (rotation + translation). Internally uses the\nsandwich product."]
impl<T: Float> Transform<Bivector<T>> for Scalar<T> {
type Output = Bivector<T>;
#[inline]
fn transform(&self, operand: &Bivector<T>) -> Bivector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Bivector<T>> for Unit<Scalar<T>> {
type Output = Bivector<T>;
#[inline]
fn transform(&self, operand: &Bivector<T>) -> Bivector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Bivector<T>>> for Scalar<T> {
type Output = Bivector<T>;
#[inline]
fn transform(&self, operand: &Unit<Bivector<T>>) -> Bivector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Bivector<T>>> for Unit<Scalar<T>> {
type Output = Bivector<T>;
#[inline]
fn transform(&self, operand: &Unit<Bivector<T>>) -> Bivector<T> {
self.sandwich(operand)
}
}
#[doc = "Transform a [`Rotor`] using this [`Scalar`].\n\nApplies the geometric transformation represented by this versor.\nFor rotors, this performs rotation. For motors, this performs rigid\nbody transformation (rotation + translation). Internally uses the\nsandwich product."]
impl<T: Float> Transform<Rotor<T>> for Scalar<T> {
type Output = Rotor<T>;
#[inline]
fn transform(&self, operand: &Rotor<T>) -> Rotor<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Rotor<T>> for Unit<Scalar<T>> {
type Output = Rotor<T>;
#[inline]
fn transform(&self, operand: &Rotor<T>) -> Rotor<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Rotor<T>>> for Scalar<T> {
type Output = Rotor<T>;
#[inline]
fn transform(&self, operand: &Unit<Rotor<T>>) -> Rotor<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Rotor<T>>> for Unit<Scalar<T>> {
type Output = Rotor<T>;
#[inline]
fn transform(&self, operand: &Unit<Rotor<T>>) -> Rotor<T> {
self.sandwich(operand)
}
}
#[doc = "Transform a [`Scalar`] using this [`Scalar`].\n\nApplies the geometric transformation represented by this versor.\nFor rotors, this performs rotation. For motors, this performs rigid\nbody transformation (rotation + translation). Internally uses the\nsandwich product."]
impl<T: Float> Transform<Scalar<T>> for Scalar<T> {
type Output = Scalar<T>;
#[inline]
fn transform(&self, operand: &Scalar<T>) -> Scalar<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Scalar<T>> for Unit<Scalar<T>> {
type Output = Scalar<T>;
#[inline]
fn transform(&self, operand: &Scalar<T>) -> Scalar<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Scalar<T>>> for Scalar<T> {
type Output = Scalar<T>;
#[inline]
fn transform(&self, operand: &Unit<Scalar<T>>) -> Scalar<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Scalar<T>>> for Unit<Scalar<T>> {
type Output = Scalar<T>;
#[inline]
fn transform(&self, operand: &Unit<Scalar<T>>) -> Scalar<T> {
self.sandwich(operand)
}
}
#[doc = "Transform a [`Trivector`] using this [`Scalar`].\n\nApplies the geometric transformation represented by this versor.\nFor rotors, this performs rotation. For motors, this performs rigid\nbody transformation (rotation + translation). Internally uses the\nsandwich product."]
impl<T: Float> Transform<Trivector<T>> for Scalar<T> {
type Output = Trivector<T>;
#[inline]
fn transform(&self, operand: &Trivector<T>) -> Trivector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Trivector<T>> for Unit<Scalar<T>> {
type Output = Trivector<T>;
#[inline]
fn transform(&self, operand: &Trivector<T>) -> Trivector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Trivector<T>>> for Scalar<T> {
type Output = Trivector<T>;
#[inline]
fn transform(&self, operand: &Unit<Trivector<T>>) -> Trivector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Trivector<T>>> for Unit<Scalar<T>> {
type Output = Trivector<T>;
#[inline]
fn transform(&self, operand: &Unit<Trivector<T>>) -> Trivector<T> {
self.sandwich(operand)
}
}
#[doc = "Transform a [`Vector`] using this [`Scalar`].\n\nApplies the geometric transformation represented by this versor.\nFor rotors, this performs rotation. For motors, this performs rigid\nbody transformation (rotation + translation). Internally uses the\nsandwich product."]
impl<T: Float> Transform<Vector<T>> for Scalar<T> {
type Output = Vector<T>;
#[inline]
fn transform(&self, operand: &Vector<T>) -> Vector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Vector<T>> for Unit<Scalar<T>> {
type Output = Vector<T>;
#[inline]
fn transform(&self, operand: &Vector<T>) -> Vector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Vector<T>>> for Scalar<T> {
type Output = Vector<T>;
#[inline]
fn transform(&self, operand: &Unit<Vector<T>>) -> Vector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Vector<T>>> for Unit<Scalar<T>> {
type Output = Vector<T>;
#[inline]
fn transform(&self, operand: &Unit<Vector<T>>) -> Vector<T> {
self.sandwich(operand)
}
}
#[doc = "Transform a [`Bivector`] using this [`Trivector`].\n\nApplies the geometric transformation represented by this versor.\nFor rotors, this performs rotation. For motors, this performs rigid\nbody transformation (rotation + translation). Internally uses the\nsandwich product."]
impl<T: Float> Transform<Bivector<T>> for Trivector<T> {
type Output = Bivector<T>;
#[inline]
fn transform(&self, operand: &Bivector<T>) -> Bivector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Bivector<T>> for Unit<Trivector<T>> {
type Output = Bivector<T>;
#[inline]
fn transform(&self, operand: &Bivector<T>) -> Bivector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Bivector<T>>> for Trivector<T> {
type Output = Bivector<T>;
#[inline]
fn transform(&self, operand: &Unit<Bivector<T>>) -> Bivector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Bivector<T>>> for Unit<Trivector<T>> {
type Output = Bivector<T>;
#[inline]
fn transform(&self, operand: &Unit<Bivector<T>>) -> Bivector<T> {
self.sandwich(operand)
}
}
#[doc = "Transform a [`Rotor`] using this [`Trivector`].\n\nApplies the geometric transformation represented by this versor.\nFor rotors, this performs rotation. For motors, this performs rigid\nbody transformation (rotation + translation). Internally uses the\nsandwich product."]
impl<T: Float> Transform<Rotor<T>> for Trivector<T> {
type Output = Rotor<T>;
#[inline]
fn transform(&self, operand: &Rotor<T>) -> Rotor<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Rotor<T>> for Unit<Trivector<T>> {
type Output = Rotor<T>;
#[inline]
fn transform(&self, operand: &Rotor<T>) -> Rotor<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Rotor<T>>> for Trivector<T> {
type Output = Rotor<T>;
#[inline]
fn transform(&self, operand: &Unit<Rotor<T>>) -> Rotor<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Rotor<T>>> for Unit<Trivector<T>> {
type Output = Rotor<T>;
#[inline]
fn transform(&self, operand: &Unit<Rotor<T>>) -> Rotor<T> {
self.sandwich(operand)
}
}
#[doc = "Transform a [`Scalar`] using this [`Trivector`].\n\nApplies the geometric transformation represented by this versor.\nFor rotors, this performs rotation. For motors, this performs rigid\nbody transformation (rotation + translation). Internally uses the\nsandwich product."]
impl<T: Float> Transform<Scalar<T>> for Trivector<T> {
type Output = Scalar<T>;
#[inline]
fn transform(&self, operand: &Scalar<T>) -> Scalar<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Scalar<T>> for Unit<Trivector<T>> {
type Output = Scalar<T>;
#[inline]
fn transform(&self, operand: &Scalar<T>) -> Scalar<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Scalar<T>>> for Trivector<T> {
type Output = Scalar<T>;
#[inline]
fn transform(&self, operand: &Unit<Scalar<T>>) -> Scalar<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Scalar<T>>> for Unit<Trivector<T>> {
type Output = Scalar<T>;
#[inline]
fn transform(&self, operand: &Unit<Scalar<T>>) -> Scalar<T> {
self.sandwich(operand)
}
}
#[doc = "Transform a [`Trivector`] using this [`Trivector`].\n\nApplies the geometric transformation represented by this versor.\nFor rotors, this performs rotation. For motors, this performs rigid\nbody transformation (rotation + translation). Internally uses the\nsandwich product."]
impl<T: Float> Transform<Trivector<T>> for Trivector<T> {
type Output = Trivector<T>;
#[inline]
fn transform(&self, operand: &Trivector<T>) -> Trivector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Trivector<T>> for Unit<Trivector<T>> {
type Output = Trivector<T>;
#[inline]
fn transform(&self, operand: &Trivector<T>) -> Trivector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Trivector<T>>> for Trivector<T> {
type Output = Trivector<T>;
#[inline]
fn transform(&self, operand: &Unit<Trivector<T>>) -> Trivector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Trivector<T>>> for Unit<Trivector<T>> {
type Output = Trivector<T>;
#[inline]
fn transform(&self, operand: &Unit<Trivector<T>>) -> Trivector<T> {
self.sandwich(operand)
}
}
#[doc = "Transform a [`Vector`] using this [`Trivector`].\n\nApplies the geometric transformation represented by this versor.\nFor rotors, this performs rotation. For motors, this performs rigid\nbody transformation (rotation + translation). Internally uses the\nsandwich product."]
impl<T: Float> Transform<Vector<T>> for Trivector<T> {
type Output = Vector<T>;
#[inline]
fn transform(&self, operand: &Vector<T>) -> Vector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Vector<T>> for Unit<Trivector<T>> {
type Output = Vector<T>;
#[inline]
fn transform(&self, operand: &Vector<T>) -> Vector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Vector<T>>> for Trivector<T> {
type Output = Vector<T>;
#[inline]
fn transform(&self, operand: &Unit<Vector<T>>) -> Vector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Vector<T>>> for Unit<Trivector<T>> {
type Output = Vector<T>;
#[inline]
fn transform(&self, operand: &Unit<Vector<T>>) -> Vector<T> {
self.sandwich(operand)
}
}
#[doc = "Transform a [`Bivector`] using this [`Vector`].\n\nApplies the geometric transformation represented by this versor.\nFor rotors, this performs rotation. For motors, this performs rigid\nbody transformation (rotation + translation). Internally uses the\nsandwich product."]
impl<T: Float> Transform<Bivector<T>> for Vector<T> {
type Output = Bivector<T>;
#[inline]
fn transform(&self, operand: &Bivector<T>) -> Bivector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Bivector<T>> for Unit<Vector<T>> {
type Output = Bivector<T>;
#[inline]
fn transform(&self, operand: &Bivector<T>) -> Bivector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Bivector<T>>> for Vector<T> {
type Output = Bivector<T>;
#[inline]
fn transform(&self, operand: &Unit<Bivector<T>>) -> Bivector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Bivector<T>>> for Unit<Vector<T>> {
type Output = Bivector<T>;
#[inline]
fn transform(&self, operand: &Unit<Bivector<T>>) -> Bivector<T> {
self.sandwich(operand)
}
}
#[doc = "Transform a [`Rotor`] using this [`Vector`].\n\nApplies the geometric transformation represented by this versor.\nFor rotors, this performs rotation. For motors, this performs rigid\nbody transformation (rotation + translation). Internally uses the\nsandwich product."]
impl<T: Float> Transform<Rotor<T>> for Vector<T> {
type Output = Rotor<T>;
#[inline]
fn transform(&self, operand: &Rotor<T>) -> Rotor<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Rotor<T>> for Unit<Vector<T>> {
type Output = Rotor<T>;
#[inline]
fn transform(&self, operand: &Rotor<T>) -> Rotor<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Rotor<T>>> for Vector<T> {
type Output = Rotor<T>;
#[inline]
fn transform(&self, operand: &Unit<Rotor<T>>) -> Rotor<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Rotor<T>>> for Unit<Vector<T>> {
type Output = Rotor<T>;
#[inline]
fn transform(&self, operand: &Unit<Rotor<T>>) -> Rotor<T> {
self.sandwich(operand)
}
}
#[doc = "Transform a [`Scalar`] using this [`Vector`].\n\nApplies the geometric transformation represented by this versor.\nFor rotors, this performs rotation. For motors, this performs rigid\nbody transformation (rotation + translation). Internally uses the\nsandwich product."]
impl<T: Float> Transform<Scalar<T>> for Vector<T> {
type Output = Scalar<T>;
#[inline]
fn transform(&self, operand: &Scalar<T>) -> Scalar<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Scalar<T>> for Unit<Vector<T>> {
type Output = Scalar<T>;
#[inline]
fn transform(&self, operand: &Scalar<T>) -> Scalar<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Scalar<T>>> for Vector<T> {
type Output = Scalar<T>;
#[inline]
fn transform(&self, operand: &Unit<Scalar<T>>) -> Scalar<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Scalar<T>>> for Unit<Vector<T>> {
type Output = Scalar<T>;
#[inline]
fn transform(&self, operand: &Unit<Scalar<T>>) -> Scalar<T> {
self.sandwich(operand)
}
}
#[doc = "Transform a [`Trivector`] using this [`Vector`].\n\nApplies the geometric transformation represented by this versor.\nFor rotors, this performs rotation. For motors, this performs rigid\nbody transformation (rotation + translation). Internally uses the\nsandwich product."]
impl<T: Float> Transform<Trivector<T>> for Vector<T> {
type Output = Trivector<T>;
#[inline]
fn transform(&self, operand: &Trivector<T>) -> Trivector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Trivector<T>> for Unit<Vector<T>> {
type Output = Trivector<T>;
#[inline]
fn transform(&self, operand: &Trivector<T>) -> Trivector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Trivector<T>>> for Vector<T> {
type Output = Trivector<T>;
#[inline]
fn transform(&self, operand: &Unit<Trivector<T>>) -> Trivector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Trivector<T>>> for Unit<Vector<T>> {
type Output = Trivector<T>;
#[inline]
fn transform(&self, operand: &Unit<Trivector<T>>) -> Trivector<T> {
self.sandwich(operand)
}
}
#[doc = "Transform a [`Vector`] using this [`Vector`].\n\nApplies the geometric transformation represented by this versor.\nFor rotors, this performs rotation. For motors, this performs rigid\nbody transformation (rotation + translation). Internally uses the\nsandwich product."]
impl<T: Float> Transform<Vector<T>> for Vector<T> {
type Output = Vector<T>;
#[inline]
fn transform(&self, operand: &Vector<T>) -> Vector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Vector<T>> for Unit<Vector<T>> {
type Output = Vector<T>;
#[inline]
fn transform(&self, operand: &Vector<T>) -> Vector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Vector<T>>> for Vector<T> {
type Output = Vector<T>;
#[inline]
fn transform(&self, operand: &Unit<Vector<T>>) -> Vector<T> {
self.sandwich(operand)
}
}
impl<T: Float> Transform<Unit<Vector<T>>> for Unit<Vector<T>> {
type Output = Vector<T>;
#[inline]
fn transform(&self, operand: &Unit<Vector<T>>) -> Vector<T> {
self.sandwich(operand)
}
}
#[allow(unused_variables)]
impl<T: Float> InverseSandwich<Bivector<T>> for Bivector<T> {
type Output = Bivector<T>;
#[inline]
fn try_inverse_sandwich(&self, operand: &Bivector<T>) -> Option<Bivector<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Bivector::new_unchecked(
(self.rx() * operand.rx() * self.rz() - self.rx() * operand.rz() * self.rx()
+ self.ry() * operand.ry() * self.rz()
- self.ry() * operand.rz() * self.ry()
+ self.rz() * operand.rx() * self.rx()
+ self.rz() * operand.ry() * self.ry()
+ self.rz() * operand.rz() * self.rz())
* inv_norm_sq,
(self.rx() * operand.rx() * self.ry() - self.rx() * operand.ry() * self.rx()
+ self.ry() * operand.rx() * self.rx()
+ self.ry() * operand.ry() * self.ry()
+ self.ry() * operand.rz() * self.rz()
- self.rz() * operand.ry() * self.rz()
+ self.rz() * operand.rz() * self.ry())
* inv_norm_sq,
(self.rx() * operand.rx() * self.rx()
+ self.rx() * operand.ry() * self.ry()
+ self.rx() * operand.rz() * self.rz()
- self.ry() * operand.rx() * self.ry()
+ self.ry() * operand.ry() * self.rx()
- self.rz() * operand.rx() * self.rz()
+ self.rz() * operand.rz() * self.rx())
* inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseSandwich<Rotor<T>> for Bivector<T> {
type Output = Rotor<T>;
#[inline]
fn try_inverse_sandwich(&self, operand: &Rotor<T>) -> Option<Rotor<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Rotor::new_unchecked(
(self.rx() * operand.ry() * self.rz() - self.rx() * operand.rz() * self.ry()
+ self.rx() * operand.s() * self.rx()
- self.ry() * operand.rx() * self.rz()
+ self.ry() * operand.rz() * self.rx()
+ self.ry() * operand.s() * self.ry()
+ self.rz() * operand.rx() * self.ry()
- self.rz() * operand.ry() * self.rx()
+ self.rz() * operand.s() * self.rz())
* inv_norm_sq,
(self.rx() * operand.rx() * self.rz()
- self.rx() * operand.rz() * self.rx()
- self.rx() * operand.s() * self.ry()
+ self.ry() * operand.ry() * self.rz()
- self.ry() * operand.rz() * self.ry()
+ self.ry() * operand.s() * self.rx()
+ self.rz() * operand.rx() * self.rx()
+ self.rz() * operand.ry() * self.ry()
+ self.rz() * operand.rz() * self.rz())
* inv_norm_sq,
(self.rx() * operand.rx() * self.ry() - self.rx() * operand.ry() * self.rx()
+ self.rx() * operand.s() * self.rz()
+ self.ry() * operand.rx() * self.rx()
+ self.ry() * operand.ry() * self.ry()
+ self.ry() * operand.rz() * self.rz()
- self.rz() * operand.ry() * self.rz()
+ self.rz() * operand.rz() * self.ry()
- self.rz() * operand.s() * self.rx())
* inv_norm_sq,
(self.rx() * operand.rx() * self.rx()
+ self.rx() * operand.ry() * self.ry()
+ self.rx() * operand.rz() * self.rz()
- self.ry() * operand.rx() * self.ry()
+ self.ry() * operand.ry() * self.rx()
- self.ry() * operand.s() * self.rz()
- self.rz() * operand.rx() * self.rz()
+ self.rz() * operand.rz() * self.rx()
+ self.rz() * operand.s() * self.ry())
* inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseSandwich<Scalar<T>> for Bivector<T> {
type Output = Scalar<T>;
#[inline]
fn try_inverse_sandwich(&self, operand: &Scalar<T>) -> Option<Scalar<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Scalar::new_unchecked(
(self.rx() * operand.s() * self.rx()
+ self.ry() * operand.s() * self.ry()
+ self.rz() * operand.s() * self.rz())
* inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseSandwich<Trivector<T>> for Bivector<T> {
type Output = Trivector<T>;
#[inline]
fn try_inverse_sandwich(&self, operand: &Trivector<T>) -> Option<Trivector<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Trivector::new_unchecked(
(self.rx() * operand.ps() * self.rx()
+ self.ry() * operand.ps() * self.ry()
+ self.rz() * operand.ps() * self.rz())
* inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseSandwich<Vector<T>> for Bivector<T> {
type Output = Vector<T>;
#[inline]
fn try_inverse_sandwich(&self, operand: &Vector<T>) -> Option<Vector<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Vector::new_unchecked(
(self.rx() * operand.x() * self.rx() - self.rx() * operand.y() * self.ry()
+ self.rx() * operand.z() * self.rz()
- self.ry() * operand.x() * self.ry()
- self.ry() * operand.y() * self.rx()
- self.rz() * operand.x() * self.rz()
+ self.rz() * operand.z() * self.rx())
* inv_norm_sq,
(-(self.rx() * operand.x() * self.ry())
- self.rx() * operand.y() * self.rx()
- self.ry() * operand.x() * self.rx()
+ self.ry() * operand.y() * self.ry()
- self.ry() * operand.z() * self.rz()
- self.rz() * operand.y() * self.rz()
- self.rz() * operand.z() * self.ry())
* inv_norm_sq,
(self.rx() * operand.x() * self.rz()
- self.rx() * operand.z() * self.rx()
- self.ry() * operand.y() * self.rz()
- self.ry() * operand.z() * self.ry()
+ self.rz() * operand.x() * self.rx()
- self.rz() * operand.y() * self.ry()
+ self.rz() * operand.z() * self.rz())
* inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseSandwich<Bivector<T>> for Rotor<T> {
type Output = Bivector<T>;
#[inline]
fn try_inverse_sandwich(&self, operand: &Bivector<T>) -> Option<Bivector<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Bivector::new_unchecked(
(self.rx() * operand.rx() * self.rz() + self.rx() * operand.ry() * self.s()
- self.rx() * operand.rz() * self.rx()
- self.ry() * operand.rx() * self.s()
+ self.ry() * operand.ry() * self.rz()
- self.ry() * operand.rz() * self.ry()
+ self.rz() * operand.rx() * self.rx()
+ self.rz() * operand.ry() * self.ry()
+ self.rz() * operand.rz() * self.rz()
- self.s() * operand.rx() * self.ry()
+ self.s() * operand.ry() * self.rx()
+ self.s() * operand.rz() * self.s())
* inv_norm_sq,
(self.rx() * operand.rx() * self.ry()
- self.rx() * operand.ry() * self.rx()
- self.rx() * operand.rz() * self.s()
+ self.ry() * operand.rx() * self.rx()
+ self.ry() * operand.ry() * self.ry()
+ self.ry() * operand.rz() * self.rz()
+ self.rz() * operand.rx() * self.s()
- self.rz() * operand.ry() * self.rz()
+ self.rz() * operand.rz() * self.ry()
+ self.s() * operand.rx() * self.rz()
+ self.s() * operand.ry() * self.s()
- self.s() * operand.rz() * self.rx())
* inv_norm_sq,
(self.rx() * operand.rx() * self.rx()
+ self.rx() * operand.ry() * self.ry()
+ self.rx() * operand.rz() * self.rz()
- self.ry() * operand.rx() * self.ry()
+ self.ry() * operand.ry() * self.rx()
+ self.ry() * operand.rz() * self.s()
- self.rz() * operand.rx() * self.rz()
- self.rz() * operand.ry() * self.s()
+ self.rz() * operand.rz() * self.rx()
+ self.s() * operand.rx() * self.s()
- self.s() * operand.ry() * self.rz()
+ self.s() * operand.rz() * self.ry())
* inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseSandwich<Rotor<T>> for Rotor<T> {
type Output = Rotor<T>;
#[inline]
fn try_inverse_sandwich(&self, operand: &Rotor<T>) -> Option<Rotor<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Rotor::new_unchecked(
(-(self.rx() * operand.rx() * self.s()) + self.rx() * operand.ry() * self.rz()
- self.rx() * operand.rz() * self.ry()
+ self.rx() * operand.s() * self.rx()
- self.ry() * operand.rx() * self.rz()
- self.ry() * operand.ry() * self.s()
+ self.ry() * operand.rz() * self.rx()
+ self.ry() * operand.s() * self.ry()
+ self.rz() * operand.rx() * self.ry()
- self.rz() * operand.ry() * self.rx()
- self.rz() * operand.rz() * self.s()
+ self.rz() * operand.s() * self.rz()
+ self.s() * operand.rx() * self.rx()
+ self.s() * operand.ry() * self.ry()
+ self.s() * operand.rz() * self.rz()
+ self.s() * operand.s() * self.s())
* inv_norm_sq,
(self.rx() * operand.rx() * self.rz() + self.rx() * operand.ry() * self.s()
- self.rx() * operand.rz() * self.rx()
- self.rx() * operand.s() * self.ry()
- self.ry() * operand.rx() * self.s()
+ self.ry() * operand.ry() * self.rz()
- self.ry() * operand.rz() * self.ry()
+ self.ry() * operand.s() * self.rx()
+ self.rz() * operand.rx() * self.rx()
+ self.rz() * operand.ry() * self.ry()
+ self.rz() * operand.rz() * self.rz()
+ self.rz() * operand.s() * self.s()
- self.s() * operand.rx() * self.ry()
+ self.s() * operand.ry() * self.rx()
+ self.s() * operand.rz() * self.s()
- self.s() * operand.s() * self.rz())
* inv_norm_sq,
(self.rx() * operand.rx() * self.ry()
- self.rx() * operand.ry() * self.rx()
- self.rx() * operand.rz() * self.s()
+ self.rx() * operand.s() * self.rz()
+ self.ry() * operand.rx() * self.rx()
+ self.ry() * operand.ry() * self.ry()
+ self.ry() * operand.rz() * self.rz()
+ self.ry() * operand.s() * self.s()
+ self.rz() * operand.rx() * self.s()
- self.rz() * operand.ry() * self.rz()
+ self.rz() * operand.rz() * self.ry()
- self.rz() * operand.s() * self.rx()
+ self.s() * operand.rx() * self.rz()
+ self.s() * operand.ry() * self.s()
- self.s() * operand.rz() * self.rx()
- self.s() * operand.s() * self.ry())
* inv_norm_sq,
(self.rx() * operand.rx() * self.rx()
+ self.rx() * operand.ry() * self.ry()
+ self.rx() * operand.rz() * self.rz()
+ self.rx() * operand.s() * self.s()
- self.ry() * operand.rx() * self.ry()
+ self.ry() * operand.ry() * self.rx()
+ self.ry() * operand.rz() * self.s()
- self.ry() * operand.s() * self.rz()
- self.rz() * operand.rx() * self.rz()
- self.rz() * operand.ry() * self.s()
+ self.rz() * operand.rz() * self.rx()
+ self.rz() * operand.s() * self.ry()
+ self.s() * operand.rx() * self.s()
- self.s() * operand.ry() * self.rz()
+ self.s() * operand.rz() * self.ry()
- self.s() * operand.s() * self.rx())
* inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseSandwich<Scalar<T>> for Rotor<T> {
type Output = Scalar<T>;
#[inline]
fn try_inverse_sandwich(&self, operand: &Scalar<T>) -> Option<Scalar<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Scalar::new_unchecked(
(self.rx() * operand.s() * self.rx()
+ self.ry() * operand.s() * self.ry()
+ self.rz() * operand.s() * self.rz()
+ self.s() * operand.s() * self.s())
* inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseSandwich<Trivector<T>> for Rotor<T> {
type Output = Trivector<T>;
#[inline]
fn try_inverse_sandwich(&self, operand: &Trivector<T>) -> Option<Trivector<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Trivector::new_unchecked(
(self.rx() * operand.ps() * self.rx()
+ self.ry() * operand.ps() * self.ry()
+ self.rz() * operand.ps() * self.rz()
+ self.s() * operand.ps() * self.s())
* inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseSandwich<Vector<T>> for Rotor<T> {
type Output = Vector<T>;
#[inline]
fn try_inverse_sandwich(&self, operand: &Vector<T>) -> Option<Vector<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Vector::new_unchecked(
(self.rx() * operand.x() * self.rx() - self.rx() * operand.y() * self.ry()
+ self.rx() * operand.z() * self.rz()
- self.ry() * operand.x() * self.ry()
- self.ry() * operand.y() * self.rx()
+ self.ry() * operand.z() * self.s()
- self.rz() * operand.x() * self.rz()
+ self.rz() * operand.y() * self.s()
+ self.rz() * operand.z() * self.rx()
+ self.s() * operand.x() * self.s()
+ self.s() * operand.y() * self.rz()
+ self.s() * operand.z() * self.ry())
* inv_norm_sq,
(-(self.rx() * operand.x() * self.ry()) - self.rx() * operand.y() * self.rx()
+ self.rx() * operand.z() * self.s()
- self.ry() * operand.x() * self.rx()
+ self.ry() * operand.y() * self.ry()
- self.ry() * operand.z() * self.rz()
- self.rz() * operand.x() * self.s()
- self.rz() * operand.y() * self.rz()
- self.rz() * operand.z() * self.ry()
- self.s() * operand.x() * self.rz()
+ self.s() * operand.y() * self.s()
+ self.s() * operand.z() * self.rx())
* inv_norm_sq,
(self.rx() * operand.x() * self.rz()
- self.rx() * operand.y() * self.s()
- self.rx() * operand.z() * self.rx()
- self.ry() * operand.x() * self.s()
- self.ry() * operand.y() * self.rz()
- self.ry() * operand.z() * self.ry()
+ self.rz() * operand.x() * self.rx()
- self.rz() * operand.y() * self.ry()
+ self.rz() * operand.z() * self.rz()
- self.s() * operand.x() * self.ry()
- self.s() * operand.y() * self.rx()
+ self.s() * operand.z() * self.s())
* inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseSandwich<Bivector<T>> for Scalar<T> {
type Output = Bivector<T>;
#[inline]
fn try_inverse_sandwich(&self, operand: &Bivector<T>) -> Option<Bivector<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Bivector::new_unchecked(
(self.s() * operand.rz() * self.s()) * inv_norm_sq,
(self.s() * operand.ry() * self.s()) * inv_norm_sq,
(self.s() * operand.rx() * self.s()) * inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseSandwich<Rotor<T>> for Scalar<T> {
type Output = Rotor<T>;
#[inline]
fn try_inverse_sandwich(&self, operand: &Rotor<T>) -> Option<Rotor<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Rotor::new_unchecked(
(self.s() * operand.s() * self.s()) * inv_norm_sq,
(self.s() * operand.rz() * self.s()) * inv_norm_sq,
(self.s() * operand.ry() * self.s()) * inv_norm_sq,
(self.s() * operand.rx() * self.s()) * inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseSandwich<Scalar<T>> for Scalar<T> {
type Output = Scalar<T>;
#[inline]
fn try_inverse_sandwich(&self, operand: &Scalar<T>) -> Option<Scalar<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Scalar::new_unchecked(
(self.s() * operand.s() * self.s()) * inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseSandwich<Trivector<T>> for Scalar<T> {
type Output = Trivector<T>;
#[inline]
fn try_inverse_sandwich(&self, operand: &Trivector<T>) -> Option<Trivector<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Trivector::new_unchecked(
(self.s() * operand.ps() * self.s()) * inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseSandwich<Vector<T>> for Scalar<T> {
type Output = Vector<T>;
#[inline]
fn try_inverse_sandwich(&self, operand: &Vector<T>) -> Option<Vector<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Vector::new_unchecked(
(self.s() * operand.x() * self.s()) * inv_norm_sq,
(self.s() * operand.y() * self.s()) * inv_norm_sq,
(self.s() * operand.z() * self.s()) * inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseSandwich<Bivector<T>> for Trivector<T> {
type Output = Bivector<T>;
#[inline]
fn try_inverse_sandwich(&self, operand: &Bivector<T>) -> Option<Bivector<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Bivector::new_unchecked(
(self.ps() * operand.rz() * self.ps()) * inv_norm_sq,
(self.ps() * operand.ry() * self.ps()) * inv_norm_sq,
(self.ps() * operand.rx() * self.ps()) * inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseSandwich<Rotor<T>> for Trivector<T> {
type Output = Rotor<T>;
#[inline]
fn try_inverse_sandwich(&self, operand: &Rotor<T>) -> Option<Rotor<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Rotor::new_unchecked(
(self.ps() * operand.s() * self.ps()) * inv_norm_sq,
(self.ps() * operand.rz() * self.ps()) * inv_norm_sq,
(self.ps() * operand.ry() * self.ps()) * inv_norm_sq,
(self.ps() * operand.rx() * self.ps()) * inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseSandwich<Scalar<T>> for Trivector<T> {
type Output = Scalar<T>;
#[inline]
fn try_inverse_sandwich(&self, operand: &Scalar<T>) -> Option<Scalar<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Scalar::new_unchecked(
(self.ps() * operand.s() * self.ps()) * inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseSandwich<Trivector<T>> for Trivector<T> {
type Output = Trivector<T>;
#[inline]
fn try_inverse_sandwich(&self, operand: &Trivector<T>) -> Option<Trivector<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Trivector::new_unchecked(
(self.ps() * operand.ps() * self.ps()) * inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseSandwich<Vector<T>> for Trivector<T> {
type Output = Vector<T>;
#[inline]
fn try_inverse_sandwich(&self, operand: &Vector<T>) -> Option<Vector<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Vector::new_unchecked(
(self.ps() * operand.x() * self.ps()) * inv_norm_sq,
(self.ps() * operand.y() * self.ps()) * inv_norm_sq,
(self.ps() * operand.z() * self.ps()) * inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseSandwich<Bivector<T>> for Vector<T> {
type Output = Bivector<T>;
#[inline]
fn try_inverse_sandwich(&self, operand: &Bivector<T>) -> Option<Bivector<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Bivector::new_unchecked(
(self.x() * operand.rx() * self.z()
- self.x() * operand.rz() * self.x()
- self.y() * operand.ry() * self.z()
- self.y() * operand.rz() * self.y()
+ self.z() * operand.rx() * self.x()
- self.z() * operand.ry() * self.y()
+ self.z() * operand.rz() * self.z())
* inv_norm_sq,
(-(self.x() * operand.rx() * self.y())
- self.x() * operand.ry() * self.x()
- self.y() * operand.rx() * self.x()
+ self.y() * operand.ry() * self.y()
- self.y() * operand.rz() * self.z()
- self.z() * operand.ry() * self.z()
- self.z() * operand.rz() * self.y())
* inv_norm_sq,
(self.x() * operand.rx() * self.x() - self.x() * operand.ry() * self.y()
+ self.x() * operand.rz() * self.z()
- self.y() * operand.rx() * self.y()
- self.y() * operand.ry() * self.x()
- self.z() * operand.rx() * self.z()
+ self.z() * operand.rz() * self.x())
* inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseSandwich<Rotor<T>> for Vector<T> {
type Output = Rotor<T>;
#[inline]
fn try_inverse_sandwich(&self, operand: &Rotor<T>) -> Option<Rotor<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Rotor::new_unchecked(
(self.x() * operand.ry() * self.z()
+ self.x() * operand.rz() * self.y()
+ self.x() * operand.s() * self.x()
+ self.y() * operand.rx() * self.z()
- self.y() * operand.rz() * self.x()
+ self.y() * operand.s() * self.y()
- self.z() * operand.rx() * self.y()
- self.z() * operand.ry() * self.x()
+ self.z() * operand.s() * self.z())
* inv_norm_sq,
(self.x() * operand.rx() * self.z() - self.x() * operand.rz() * self.x()
+ self.x() * operand.s() * self.y()
- self.y() * operand.ry() * self.z()
- self.y() * operand.rz() * self.y()
- self.y() * operand.s() * self.x()
+ self.z() * operand.rx() * self.x()
- self.z() * operand.ry() * self.y()
+ self.z() * operand.rz() * self.z())
* inv_norm_sq,
(-(self.x() * operand.rx() * self.y()) - self.x() * operand.ry() * self.x()
+ self.x() * operand.s() * self.z()
- self.y() * operand.rx() * self.x()
+ self.y() * operand.ry() * self.y()
- self.y() * operand.rz() * self.z()
- self.z() * operand.ry() * self.z()
- self.z() * operand.rz() * self.y()
- self.z() * operand.s() * self.x())
* inv_norm_sq,
(self.x() * operand.rx() * self.x() - self.x() * operand.ry() * self.y()
+ self.x() * operand.rz() * self.z()
- self.y() * operand.rx() * self.y()
- self.y() * operand.ry() * self.x()
+ self.y() * operand.s() * self.z()
- self.z() * operand.rx() * self.z()
+ self.z() * operand.rz() * self.x()
- self.z() * operand.s() * self.y())
* inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseSandwich<Scalar<T>> for Vector<T> {
type Output = Scalar<T>;
#[inline]
fn try_inverse_sandwich(&self, operand: &Scalar<T>) -> Option<Scalar<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Scalar::new_unchecked(
(self.x() * operand.s() * self.x()
+ self.y() * operand.s() * self.y()
+ self.z() * operand.s() * self.z())
* inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseSandwich<Trivector<T>> for Vector<T> {
type Output = Trivector<T>;
#[inline]
fn try_inverse_sandwich(&self, operand: &Trivector<T>) -> Option<Trivector<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Trivector::new_unchecked(
(self.x() * operand.ps() * self.x()
+ self.y() * operand.ps() * self.y()
+ self.z() * operand.ps() * self.z())
* inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseSandwich<Vector<T>> for Vector<T> {
type Output = Vector<T>;
#[inline]
fn try_inverse_sandwich(&self, operand: &Vector<T>) -> Option<Vector<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Vector::new_unchecked(
(self.x() * operand.x() * self.x()
+ self.x() * operand.y() * self.y()
+ self.x() * operand.z() * self.z()
- self.y() * operand.x() * self.y()
+ self.y() * operand.y() * self.x()
- self.z() * operand.x() * self.z()
+ self.z() * operand.z() * self.x())
* inv_norm_sq,
(self.x() * operand.x() * self.y() - self.x() * operand.y() * self.x()
+ self.y() * operand.x() * self.x()
+ self.y() * operand.y() * self.y()
+ self.y() * operand.z() * self.z()
- self.z() * operand.y() * self.z()
+ self.z() * operand.z() * self.y())
* inv_norm_sq,
(self.x() * operand.x() * self.z() - self.x() * operand.z() * self.x()
+ self.y() * operand.y() * self.z()
- self.y() * operand.z() * self.y()
+ self.z() * operand.x() * self.x()
+ self.z() * operand.y() * self.y()
+ self.z() * operand.z() * self.z())
* inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseAntisandwich<Bivector<T>> for Bivector<T> {
type Output = Bivector<T>;
#[inline]
fn try_inverse_antisandwich(&self, operand: &Bivector<T>) -> Option<Bivector<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Bivector::new_unchecked(
(self.rx() * operand.rx() * self.rz() - self.rx() * operand.rz() * self.rx()
+ self.ry() * operand.ry() * self.rz()
- self.ry() * operand.rz() * self.ry()
+ self.rz() * operand.rx() * self.rx()
+ self.rz() * operand.ry() * self.ry()
+ self.rz() * operand.rz() * self.rz())
* inv_norm_sq,
(self.rx() * operand.rx() * self.ry() - self.rx() * operand.ry() * self.rx()
+ self.ry() * operand.rx() * self.rx()
+ self.ry() * operand.ry() * self.ry()
+ self.ry() * operand.rz() * self.rz()
- self.rz() * operand.ry() * self.rz()
+ self.rz() * operand.rz() * self.ry())
* inv_norm_sq,
(self.rx() * operand.rx() * self.rx()
+ self.rx() * operand.ry() * self.ry()
+ self.rx() * operand.rz() * self.rz()
- self.ry() * operand.rx() * self.ry()
+ self.ry() * operand.ry() * self.rx()
- self.rz() * operand.rx() * self.rz()
+ self.rz() * operand.rz() * self.rx())
* inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseAntisandwich<Rotor<T>> for Bivector<T> {
type Output = Rotor<T>;
#[inline]
fn try_inverse_antisandwich(&self, operand: &Rotor<T>) -> Option<Rotor<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Rotor::new_unchecked(
(-(self.rx() * operand.ry() * self.rz())
+ self.rx() * operand.rz() * self.ry()
+ self.rx() * operand.s() * self.rx()
+ self.ry() * operand.rx() * self.rz()
- self.ry() * operand.rz() * self.rx()
+ self.ry() * operand.s() * self.ry()
- self.rz() * operand.rx() * self.ry()
+ self.rz() * operand.ry() * self.rx()
+ self.rz() * operand.s() * self.rz())
* inv_norm_sq,
(self.rx() * operand.rx() * self.rz() - self.rx() * operand.rz() * self.rx()
+ self.rx() * operand.s() * self.ry()
+ self.ry() * operand.ry() * self.rz()
- self.ry() * operand.rz() * self.ry()
- self.ry() * operand.s() * self.rx()
+ self.rz() * operand.rx() * self.rx()
+ self.rz() * operand.ry() * self.ry()
+ self.rz() * operand.rz() * self.rz())
* inv_norm_sq,
(self.rx() * operand.rx() * self.ry()
- self.rx() * operand.ry() * self.rx()
- self.rx() * operand.s() * self.rz()
+ self.ry() * operand.rx() * self.rx()
+ self.ry() * operand.ry() * self.ry()
+ self.ry() * operand.rz() * self.rz()
- self.rz() * operand.ry() * self.rz()
+ self.rz() * operand.rz() * self.ry()
+ self.rz() * operand.s() * self.rx())
* inv_norm_sq,
(self.rx() * operand.rx() * self.rx()
+ self.rx() * operand.ry() * self.ry()
+ self.rx() * operand.rz() * self.rz()
- self.ry() * operand.rx() * self.ry()
+ self.ry() * operand.ry() * self.rx()
+ self.ry() * operand.s() * self.rz()
- self.rz() * operand.rx() * self.rz()
+ self.rz() * operand.rz() * self.rx()
- self.rz() * operand.s() * self.ry())
* inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseAntisandwich<Scalar<T>> for Bivector<T> {
type Output = Scalar<T>;
#[inline]
fn try_inverse_antisandwich(&self, operand: &Scalar<T>) -> Option<Scalar<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Scalar::new_unchecked(
(self.rx() * operand.s() * self.rx()
+ self.ry() * operand.s() * self.ry()
+ self.rz() * operand.s() * self.rz())
* inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseAntisandwich<Trivector<T>> for Bivector<T> {
type Output = Trivector<T>;
#[inline]
fn try_inverse_antisandwich(&self, operand: &Trivector<T>) -> Option<Trivector<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Trivector::new_unchecked(
(self.rx() * operand.ps() * self.rx()
+ self.ry() * operand.ps() * self.ry()
+ self.rz() * operand.ps() * self.rz())
* inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseAntisandwich<Vector<T>> for Bivector<T> {
type Output = Vector<T>;
#[inline]
fn try_inverse_antisandwich(&self, operand: &Vector<T>) -> Option<Vector<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Vector::new_unchecked(
(self.rx() * operand.x() * self.rx() - self.rx() * operand.y() * self.ry()
+ self.rx() * operand.z() * self.rz()
- self.ry() * operand.x() * self.ry()
- self.ry() * operand.y() * self.rx()
- self.rz() * operand.x() * self.rz()
+ self.rz() * operand.z() * self.rx())
* inv_norm_sq,
(-(self.rx() * operand.x() * self.ry())
- self.rx() * operand.y() * self.rx()
- self.ry() * operand.x() * self.rx()
+ self.ry() * operand.y() * self.ry()
- self.ry() * operand.z() * self.rz()
- self.rz() * operand.y() * self.rz()
- self.rz() * operand.z() * self.ry())
* inv_norm_sq,
(self.rx() * operand.x() * self.rz()
- self.rx() * operand.z() * self.rx()
- self.ry() * operand.y() * self.rz()
- self.ry() * operand.z() * self.ry()
+ self.rz() * operand.x() * self.rx()
- self.rz() * operand.y() * self.ry()
+ self.rz() * operand.z() * self.rz())
* inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseAntisandwich<Bivector<T>> for Rotor<T> {
type Output = Bivector<T>;
#[inline]
fn try_inverse_antisandwich(&self, operand: &Bivector<T>) -> Option<Bivector<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Bivector::new_unchecked(
(self.rx() * operand.rx() * self.rz()
- self.rx() * operand.ry() * self.s()
- self.rx() * operand.rz() * self.rx()
+ self.ry() * operand.rx() * self.s()
+ self.ry() * operand.ry() * self.rz()
- self.ry() * operand.rz() * self.ry()
+ self.rz() * operand.rx() * self.rx()
+ self.rz() * operand.ry() * self.ry()
+ self.rz() * operand.rz() * self.rz()
+ self.s() * operand.rx() * self.ry()
- self.s() * operand.ry() * self.rx()
+ self.s() * operand.rz() * self.s())
* inv_norm_sq,
(self.rx() * operand.rx() * self.ry() - self.rx() * operand.ry() * self.rx()
+ self.rx() * operand.rz() * self.s()
+ self.ry() * operand.rx() * self.rx()
+ self.ry() * operand.ry() * self.ry()
+ self.ry() * operand.rz() * self.rz()
- self.rz() * operand.rx() * self.s()
- self.rz() * operand.ry() * self.rz()
+ self.rz() * operand.rz() * self.ry()
- self.s() * operand.rx() * self.rz()
+ self.s() * operand.ry() * self.s()
+ self.s() * operand.rz() * self.rx())
* inv_norm_sq,
(self.rx() * operand.rx() * self.rx()
+ self.rx() * operand.ry() * self.ry()
+ self.rx() * operand.rz() * self.rz()
- self.ry() * operand.rx() * self.ry()
+ self.ry() * operand.ry() * self.rx()
- self.ry() * operand.rz() * self.s()
- self.rz() * operand.rx() * self.rz()
+ self.rz() * operand.ry() * self.s()
+ self.rz() * operand.rz() * self.rx()
+ self.s() * operand.rx() * self.s()
+ self.s() * operand.ry() * self.rz()
- self.s() * operand.rz() * self.ry())
* inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseAntisandwich<Rotor<T>> for Rotor<T> {
type Output = Rotor<T>;
#[inline]
fn try_inverse_antisandwich(&self, operand: &Rotor<T>) -> Option<Rotor<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Rotor::new_unchecked(
(-(self.rx() * operand.rx() * self.s()) - self.rx() * operand.ry() * self.rz()
+ self.rx() * operand.rz() * self.ry()
+ self.rx() * operand.s() * self.rx()
+ self.ry() * operand.rx() * self.rz()
- self.ry() * operand.ry() * self.s()
- self.ry() * operand.rz() * self.rx()
+ self.ry() * operand.s() * self.ry()
- self.rz() * operand.rx() * self.ry()
+ self.rz() * operand.ry() * self.rx()
- self.rz() * operand.rz() * self.s()
+ self.rz() * operand.s() * self.rz()
+ self.s() * operand.rx() * self.rx()
+ self.s() * operand.ry() * self.ry()
+ self.s() * operand.rz() * self.rz()
+ self.s() * operand.s() * self.s())
* inv_norm_sq,
(self.rx() * operand.rx() * self.rz()
- self.rx() * operand.ry() * self.s()
- self.rx() * operand.rz() * self.rx()
+ self.rx() * operand.s() * self.ry()
+ self.ry() * operand.rx() * self.s()
+ self.ry() * operand.ry() * self.rz()
- self.ry() * operand.rz() * self.ry()
- self.ry() * operand.s() * self.rx()
+ self.rz() * operand.rx() * self.rx()
+ self.rz() * operand.ry() * self.ry()
+ self.rz() * operand.rz() * self.rz()
+ self.rz() * operand.s() * self.s()
+ self.s() * operand.rx() * self.ry()
- self.s() * operand.ry() * self.rx()
+ self.s() * operand.rz() * self.s()
- self.s() * operand.s() * self.rz())
* inv_norm_sq,
(self.rx() * operand.rx() * self.ry() - self.rx() * operand.ry() * self.rx()
+ self.rx() * operand.rz() * self.s()
- self.rx() * operand.s() * self.rz()
+ self.ry() * operand.rx() * self.rx()
+ self.ry() * operand.ry() * self.ry()
+ self.ry() * operand.rz() * self.rz()
+ self.ry() * operand.s() * self.s()
- self.rz() * operand.rx() * self.s()
- self.rz() * operand.ry() * self.rz()
+ self.rz() * operand.rz() * self.ry()
+ self.rz() * operand.s() * self.rx()
- self.s() * operand.rx() * self.rz()
+ self.s() * operand.ry() * self.s()
+ self.s() * operand.rz() * self.rx()
- self.s() * operand.s() * self.ry())
* inv_norm_sq,
(self.rx() * operand.rx() * self.rx()
+ self.rx() * operand.ry() * self.ry()
+ self.rx() * operand.rz() * self.rz()
+ self.rx() * operand.s() * self.s()
- self.ry() * operand.rx() * self.ry()
+ self.ry() * operand.ry() * self.rx()
- self.ry() * operand.rz() * self.s()
+ self.ry() * operand.s() * self.rz()
- self.rz() * operand.rx() * self.rz()
+ self.rz() * operand.ry() * self.s()
+ self.rz() * operand.rz() * self.rx()
- self.rz() * operand.s() * self.ry()
+ self.s() * operand.rx() * self.s()
+ self.s() * operand.ry() * self.rz()
- self.s() * operand.rz() * self.ry()
- self.s() * operand.s() * self.rx())
* inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseAntisandwich<Scalar<T>> for Rotor<T> {
type Output = Scalar<T>;
#[inline]
fn try_inverse_antisandwich(&self, operand: &Scalar<T>) -> Option<Scalar<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Scalar::new_unchecked(
(self.rx() * operand.s() * self.rx()
+ self.ry() * operand.s() * self.ry()
+ self.rz() * operand.s() * self.rz()
+ self.s() * operand.s() * self.s())
* inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseAntisandwich<Trivector<T>> for Rotor<T> {
type Output = Trivector<T>;
#[inline]
fn try_inverse_antisandwich(&self, operand: &Trivector<T>) -> Option<Trivector<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Trivector::new_unchecked(
(self.rx() * operand.ps() * self.rx()
+ self.ry() * operand.ps() * self.ry()
+ self.rz() * operand.ps() * self.rz()
+ self.s() * operand.ps() * self.s())
* inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseAntisandwich<Vector<T>> for Rotor<T> {
type Output = Vector<T>;
#[inline]
fn try_inverse_antisandwich(&self, operand: &Vector<T>) -> Option<Vector<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Vector::new_unchecked(
(self.rx() * operand.x() * self.rx() - self.rx() * operand.y() * self.ry()
+ self.rx() * operand.z() * self.rz()
- self.ry() * operand.x() * self.ry()
- self.ry() * operand.y() * self.rx()
- self.ry() * operand.z() * self.s()
- self.rz() * operand.x() * self.rz()
- self.rz() * operand.y() * self.s()
+ self.rz() * operand.z() * self.rx()
+ self.s() * operand.x() * self.s()
- self.s() * operand.y() * self.rz()
- self.s() * operand.z() * self.ry())
* inv_norm_sq,
(-(self.rx() * operand.x() * self.ry())
- self.rx() * operand.y() * self.rx()
- self.rx() * operand.z() * self.s()
- self.ry() * operand.x() * self.rx()
+ self.ry() * operand.y() * self.ry()
- self.ry() * operand.z() * self.rz()
+ self.rz() * operand.x() * self.s()
- self.rz() * operand.y() * self.rz()
- self.rz() * operand.z() * self.ry()
+ self.s() * operand.x() * self.rz()
+ self.s() * operand.y() * self.s()
- self.s() * operand.z() * self.rx())
* inv_norm_sq,
(self.rx() * operand.x() * self.rz() + self.rx() * operand.y() * self.s()
- self.rx() * operand.z() * self.rx()
+ self.ry() * operand.x() * self.s()
- self.ry() * operand.y() * self.rz()
- self.ry() * operand.z() * self.ry()
+ self.rz() * operand.x() * self.rx()
- self.rz() * operand.y() * self.ry()
+ self.rz() * operand.z() * self.rz()
+ self.s() * operand.x() * self.ry()
+ self.s() * operand.y() * self.rx()
+ self.s() * operand.z() * self.s())
* inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseAntisandwich<Bivector<T>> for Scalar<T> {
type Output = Bivector<T>;
#[inline]
fn try_inverse_antisandwich(&self, operand: &Bivector<T>) -> Option<Bivector<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Bivector::new_unchecked(
(self.s() * operand.rz() * self.s()) * inv_norm_sq,
(self.s() * operand.ry() * self.s()) * inv_norm_sq,
(self.s() * operand.rx() * self.s()) * inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseAntisandwich<Rotor<T>> for Scalar<T> {
type Output = Rotor<T>;
#[inline]
fn try_inverse_antisandwich(&self, operand: &Rotor<T>) -> Option<Rotor<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Rotor::new_unchecked(
(self.s() * operand.s() * self.s()) * inv_norm_sq,
(self.s() * operand.rz() * self.s()) * inv_norm_sq,
(self.s() * operand.ry() * self.s()) * inv_norm_sq,
(self.s() * operand.rx() * self.s()) * inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseAntisandwich<Scalar<T>> for Scalar<T> {
type Output = Scalar<T>;
#[inline]
fn try_inverse_antisandwich(&self, operand: &Scalar<T>) -> Option<Scalar<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Scalar::new_unchecked(
(self.s() * operand.s() * self.s()) * inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseAntisandwich<Trivector<T>> for Scalar<T> {
type Output = Trivector<T>;
#[inline]
fn try_inverse_antisandwich(&self, operand: &Trivector<T>) -> Option<Trivector<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Trivector::new_unchecked(
(self.s() * operand.ps() * self.s()) * inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseAntisandwich<Vector<T>> for Scalar<T> {
type Output = Vector<T>;
#[inline]
fn try_inverse_antisandwich(&self, operand: &Vector<T>) -> Option<Vector<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Vector::new_unchecked(
(self.s() * operand.x() * self.s()) * inv_norm_sq,
(self.s() * operand.y() * self.s()) * inv_norm_sq,
(self.s() * operand.z() * self.s()) * inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseAntisandwich<Bivector<T>> for Trivector<T> {
type Output = Bivector<T>;
#[inline]
fn try_inverse_antisandwich(&self, operand: &Bivector<T>) -> Option<Bivector<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Bivector::new_unchecked(
(self.ps() * operand.rz() * self.ps()) * inv_norm_sq,
(self.ps() * operand.ry() * self.ps()) * inv_norm_sq,
(self.ps() * operand.rx() * self.ps()) * inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseAntisandwich<Rotor<T>> for Trivector<T> {
type Output = Rotor<T>;
#[inline]
fn try_inverse_antisandwich(&self, operand: &Rotor<T>) -> Option<Rotor<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Rotor::new_unchecked(
(self.ps() * operand.s() * self.ps()) * inv_norm_sq,
(self.ps() * operand.rz() * self.ps()) * inv_norm_sq,
(self.ps() * operand.ry() * self.ps()) * inv_norm_sq,
(self.ps() * operand.rx() * self.ps()) * inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseAntisandwich<Scalar<T>> for Trivector<T> {
type Output = Scalar<T>;
#[inline]
fn try_inverse_antisandwich(&self, operand: &Scalar<T>) -> Option<Scalar<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Scalar::new_unchecked(
(self.ps() * operand.s() * self.ps()) * inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseAntisandwich<Trivector<T>> for Trivector<T> {
type Output = Trivector<T>;
#[inline]
fn try_inverse_antisandwich(&self, operand: &Trivector<T>) -> Option<Trivector<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Trivector::new_unchecked(
(self.ps() * operand.ps() * self.ps()) * inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseAntisandwich<Vector<T>> for Trivector<T> {
type Output = Vector<T>;
#[inline]
fn try_inverse_antisandwich(&self, operand: &Vector<T>) -> Option<Vector<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Vector::new_unchecked(
(self.ps() * operand.x() * self.ps()) * inv_norm_sq,
(self.ps() * operand.y() * self.ps()) * inv_norm_sq,
(self.ps() * operand.z() * self.ps()) * inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseAntisandwich<Bivector<T>> for Vector<T> {
type Output = Bivector<T>;
#[inline]
fn try_inverse_antisandwich(&self, operand: &Bivector<T>) -> Option<Bivector<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Bivector::new_unchecked(
(self.x() * operand.rx() * self.z()
- self.x() * operand.rz() * self.x()
- self.y() * operand.ry() * self.z()
- self.y() * operand.rz() * self.y()
+ self.z() * operand.rx() * self.x()
- self.z() * operand.ry() * self.y()
+ self.z() * operand.rz() * self.z())
* inv_norm_sq,
(-(self.x() * operand.rx() * self.y())
- self.x() * operand.ry() * self.x()
- self.y() * operand.rx() * self.x()
+ self.y() * operand.ry() * self.y()
- self.y() * operand.rz() * self.z()
- self.z() * operand.ry() * self.z()
- self.z() * operand.rz() * self.y())
* inv_norm_sq,
(self.x() * operand.rx() * self.x() - self.x() * operand.ry() * self.y()
+ self.x() * operand.rz() * self.z()
- self.y() * operand.rx() * self.y()
- self.y() * operand.ry() * self.x()
- self.z() * operand.rx() * self.z()
+ self.z() * operand.rz() * self.x())
* inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseAntisandwich<Rotor<T>> for Vector<T> {
type Output = Rotor<T>;
#[inline]
fn try_inverse_antisandwich(&self, operand: &Rotor<T>) -> Option<Rotor<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Rotor::new_unchecked(
(-(self.x() * operand.ry() * self.z()) - self.x() * operand.rz() * self.y()
+ self.x() * operand.s() * self.x()
- self.y() * operand.rx() * self.z()
+ self.y() * operand.rz() * self.x()
+ self.y() * operand.s() * self.y()
+ self.z() * operand.rx() * self.y()
+ self.z() * operand.ry() * self.x()
+ self.z() * operand.s() * self.z())
* inv_norm_sq,
(self.x() * operand.rx() * self.z()
- self.x() * operand.rz() * self.x()
- self.x() * operand.s() * self.y()
- self.y() * operand.ry() * self.z()
- self.y() * operand.rz() * self.y()
+ self.y() * operand.s() * self.x()
+ self.z() * operand.rx() * self.x()
- self.z() * operand.ry() * self.y()
+ self.z() * operand.rz() * self.z())
* inv_norm_sq,
(-(self.x() * operand.rx() * self.y())
- self.x() * operand.ry() * self.x()
- self.x() * operand.s() * self.z()
- self.y() * operand.rx() * self.x()
+ self.y() * operand.ry() * self.y()
- self.y() * operand.rz() * self.z()
- self.z() * operand.ry() * self.z()
- self.z() * operand.rz() * self.y()
+ self.z() * operand.s() * self.x())
* inv_norm_sq,
(self.x() * operand.rx() * self.x() - self.x() * operand.ry() * self.y()
+ self.x() * operand.rz() * self.z()
- self.y() * operand.rx() * self.y()
- self.y() * operand.ry() * self.x()
- self.y() * operand.s() * self.z()
- self.z() * operand.rx() * self.z()
+ self.z() * operand.rz() * self.x()
+ self.z() * operand.s() * self.y())
* inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseAntisandwich<Scalar<T>> for Vector<T> {
type Output = Scalar<T>;
#[inline]
fn try_inverse_antisandwich(&self, operand: &Scalar<T>) -> Option<Scalar<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Scalar::new_unchecked(
(self.x() * operand.s() * self.x()
+ self.y() * operand.s() * self.y()
+ self.z() * operand.s() * self.z())
* inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseAntisandwich<Trivector<T>> for Vector<T> {
type Output = Trivector<T>;
#[inline]
fn try_inverse_antisandwich(&self, operand: &Trivector<T>) -> Option<Trivector<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Trivector::new_unchecked(
(self.x() * operand.ps() * self.x()
+ self.y() * operand.ps() * self.y()
+ self.z() * operand.ps() * self.z())
* inv_norm_sq,
))
}
}
#[allow(unused_variables)]
impl<T: Float> InverseAntisandwich<Vector<T>> for Vector<T> {
type Output = Vector<T>;
#[inline]
fn try_inverse_antisandwich(&self, operand: &Vector<T>) -> Option<Vector<T>> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Vector::new_unchecked(
(self.x() * operand.x() * self.x()
+ self.x() * operand.y() * self.y()
+ self.x() * operand.z() * self.z()
- self.y() * operand.x() * self.y()
+ self.y() * operand.y() * self.x()
- self.z() * operand.x() * self.z()
+ self.z() * operand.z() * self.x())
* inv_norm_sq,
(self.x() * operand.x() * self.y() - self.x() * operand.y() * self.x()
+ self.y() * operand.x() * self.x()
+ self.y() * operand.y() * self.y()
+ self.y() * operand.z() * self.z()
- self.z() * operand.y() * self.z()
+ self.z() * operand.z() * self.y())
* inv_norm_sq,
(self.x() * operand.x() * self.z() - self.x() * operand.z() * self.x()
+ self.y() * operand.y() * self.z()
- self.y() * operand.z() * self.y()
+ self.z() * operand.x() * self.x()
+ self.z() * operand.y() * self.y()
+ self.z() * operand.z() * self.z())
* inv_norm_sq,
))
}
}
impl<T: Float> Versor<Bivector<T>> for Bivector<T> {
type Output = Rotor<T>;
#[inline]
fn compose(&self, other: &Bivector<T>) -> Rotor<T> {
*self * *other
}
}
impl<T: Float> Versor<Rotor<T>> for Bivector<T> {
type Output = Rotor<T>;
#[inline]
fn compose(&self, other: &Rotor<T>) -> Rotor<T> {
*self * *other
}
}
impl<T: Float> Versor<Scalar<T>> for Bivector<T> {
type Output = Bivector<T>;
#[inline]
fn compose(&self, other: &Scalar<T>) -> Bivector<T> {
*self * *other
}
}
impl<T: Float> Versor<Trivector<T>> for Bivector<T> {
type Output = Vector<T>;
#[inline]
fn compose(&self, other: &Trivector<T>) -> Vector<T> {
*self * *other
}
}
impl<T: Float> Versor<Bivector<T>> for Rotor<T> {
type Output = Rotor<T>;
#[inline]
fn compose(&self, other: &Bivector<T>) -> Rotor<T> {
*self * *other
}
}
impl<T: Float> Versor<Rotor<T>> for Rotor<T> {
type Output = Rotor<T>;
#[inline]
fn compose(&self, other: &Rotor<T>) -> Rotor<T> {
*self * *other
}
}
impl<T: Float> Versor<Scalar<T>> for Rotor<T> {
type Output = Rotor<T>;
#[inline]
fn compose(&self, other: &Scalar<T>) -> Rotor<T> {
*self * *other
}
}
impl<T: Float> Versor<Bivector<T>> for Scalar<T> {
type Output = Bivector<T>;
#[inline]
fn compose(&self, other: &Bivector<T>) -> Bivector<T> {
*self * *other
}
}
impl<T: Float> Versor<Rotor<T>> for Scalar<T> {
type Output = Rotor<T>;
#[inline]
fn compose(&self, other: &Rotor<T>) -> Rotor<T> {
*self * *other
}
}
impl<T: Float> Versor<Scalar<T>> for Scalar<T> {
type Output = Scalar<T>;
#[inline]
fn compose(&self, other: &Scalar<T>) -> Scalar<T> {
*self * *other
}
}
impl<T: Float> Versor<Trivector<T>> for Scalar<T> {
type Output = Trivector<T>;
#[inline]
fn compose(&self, other: &Trivector<T>) -> Trivector<T> {
*self * *other
}
}
impl<T: Float> Versor<Vector<T>> for Scalar<T> {
type Output = Vector<T>;
#[inline]
fn compose(&self, other: &Vector<T>) -> Vector<T> {
*self * *other
}
}
impl<T: Float> Versor<Bivector<T>> for Trivector<T> {
type Output = Vector<T>;
#[inline]
fn compose(&self, other: &Bivector<T>) -> Vector<T> {
*self * *other
}
}
impl<T: Float> Versor<Scalar<T>> for Trivector<T> {
type Output = Trivector<T>;
#[inline]
fn compose(&self, other: &Scalar<T>) -> Trivector<T> {
*self * *other
}
}
impl<T: Float> Versor<Trivector<T>> for Trivector<T> {
type Output = Scalar<T>;
#[inline]
fn compose(&self, other: &Trivector<T>) -> Scalar<T> {
*self * *other
}
}
impl<T: Float> Versor<Vector<T>> for Trivector<T> {
type Output = Bivector<T>;
#[inline]
fn compose(&self, other: &Vector<T>) -> Bivector<T> {
*self * *other
}
}
impl<T: Float> Versor<Scalar<T>> for Vector<T> {
type Output = Vector<T>;
#[inline]
fn compose(&self, other: &Scalar<T>) -> Vector<T> {
*self * *other
}
}
impl<T: Float> Versor<Trivector<T>> for Vector<T> {
type Output = Bivector<T>;
#[inline]
fn compose(&self, other: &Trivector<T>) -> Bivector<T> {
*self * *other
}
}
impl<T: Float> Versor<Vector<T>> for Vector<T> {
type Output = Rotor<T>;
#[inline]
fn compose(&self, other: &Vector<T>) -> Rotor<T> {
*self * *other
}
}
impl<T: Float> ScalarProduct<Bivector<T>> for Bivector<T> {
type Scalar = T;
#[inline]
fn scalar_product(&self, rhs: &Bivector<T>) -> T {
-(self.rz() * rhs.rz()) - self.ry() * rhs.ry() - self.rx() * rhs.rx()
}
}
#[allow(unused_variables)]
impl<T: Float> ScalarProduct<Bivector<T>> for Unit<Bivector<T>> {
type Scalar = T;
#[inline]
fn scalar_product(&self, rhs: &Bivector<T>) -> T {
-(rhs.rx() * self.as_inner().rx())
+ -(rhs.ry() * self.as_inner().ry())
+ -(rhs.rz() * self.as_inner().rz())
}
}
#[allow(unused_variables)]
impl<T: Float> ScalarProduct<Unit<Bivector<T>>> for Bivector<T> {
type Scalar = T;
#[inline]
fn scalar_product(&self, rhs: &Unit<Bivector<T>>) -> T {
-(rhs.as_inner().rx() * self.rx())
+ -(rhs.as_inner().ry() * self.ry())
+ -(rhs.as_inner().rz() * self.rz())
}
}
#[allow(unused_variables)]
impl<T: Float> ScalarProduct<Unit<Bivector<T>>> for Unit<Bivector<T>> {
type Scalar = T;
#[inline]
fn scalar_product(&self, rhs: &Unit<Bivector<T>>) -> T {
-(rhs.as_inner().rx() * self.as_inner().rx())
+ -(rhs.as_inner().ry() * self.as_inner().ry())
+ -(rhs.as_inner().rz() * self.as_inner().rz())
}
}
impl<T: Float> ScalarProduct<Scalar<T>> for Scalar<T> {
type Scalar = T;
#[inline]
fn scalar_product(&self, rhs: &Scalar<T>) -> T {
self.s() * rhs.s()
}
}
#[allow(unused_variables)]
impl<T: Float> ScalarProduct<Scalar<T>> for Unit<Scalar<T>> {
type Scalar = T;
#[inline]
fn scalar_product(&self, rhs: &Scalar<T>) -> T {
rhs.s() * self.as_inner().s()
}
}
#[allow(unused_variables)]
impl<T: Float> ScalarProduct<Unit<Scalar<T>>> for Scalar<T> {
type Scalar = T;
#[inline]
fn scalar_product(&self, rhs: &Unit<Scalar<T>>) -> T {
rhs.as_inner().s() * self.s()
}
}
#[allow(unused_variables)]
impl<T: Float> ScalarProduct<Unit<Scalar<T>>> for Unit<Scalar<T>> {
type Scalar = T;
#[inline]
fn scalar_product(&self, rhs: &Unit<Scalar<T>>) -> T {
rhs.as_inner().s() * self.as_inner().s()
}
}
impl<T: Float> ScalarProduct<Trivector<T>> for Trivector<T> {
type Scalar = T;
#[inline]
fn scalar_product(&self, rhs: &Trivector<T>) -> T {
-(self.ps() * rhs.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> ScalarProduct<Trivector<T>> for Unit<Trivector<T>> {
type Scalar = T;
#[inline]
fn scalar_product(&self, rhs: &Trivector<T>) -> T {
-(rhs.ps() * self.as_inner().ps())
}
}
#[allow(unused_variables)]
impl<T: Float> ScalarProduct<Unit<Trivector<T>>> for Trivector<T> {
type Scalar = T;
#[inline]
fn scalar_product(&self, rhs: &Unit<Trivector<T>>) -> T {
-(rhs.as_inner().ps() * self.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> ScalarProduct<Unit<Trivector<T>>> for Unit<Trivector<T>> {
type Scalar = T;
#[inline]
fn scalar_product(&self, rhs: &Unit<Trivector<T>>) -> T {
-(rhs.as_inner().ps() * self.as_inner().ps())
}
}
impl<T: Float> ScalarProduct<Vector<T>> for Vector<T> {
type Scalar = T;
#[inline]
fn scalar_product(&self, rhs: &Vector<T>) -> T {
self.x() * rhs.x() + self.y() * rhs.y() + self.z() * rhs.z()
}
}
#[allow(unused_variables)]
impl<T: Float> ScalarProduct<Vector<T>> for Unit<Vector<T>> {
type Scalar = T;
#[inline]
fn scalar_product(&self, rhs: &Vector<T>) -> T {
rhs.x() * self.as_inner().x()
+ rhs.y() * self.as_inner().y()
+ rhs.z() * self.as_inner().z()
}
}
#[allow(unused_variables)]
impl<T: Float> ScalarProduct<Unit<Vector<T>>> for Vector<T> {
type Scalar = T;
#[inline]
fn scalar_product(&self, rhs: &Unit<Vector<T>>) -> T {
rhs.as_inner().x() * self.x()
+ rhs.as_inner().y() * self.y()
+ rhs.as_inner().z() * self.z()
}
}
#[allow(unused_variables)]
impl<T: Float> ScalarProduct<Unit<Vector<T>>> for Unit<Vector<T>> {
type Scalar = T;
#[inline]
fn scalar_product(&self, rhs: &Unit<Vector<T>>) -> T {
rhs.as_inner().x() * self.as_inner().x()
+ rhs.as_inner().y() * self.as_inner().y()
+ rhs.as_inner().z() * self.as_inner().z()
}
}
#[doc = "Bulk contraction of [`Bivector`] with [`Bivector`].\n\nThe bulk contraction extracts the Euclidean (non-degenerate) component\nof the interior product. In PGA, this isolates the finite/spatial part."]
impl<T: Float> BulkContract<Bivector<T>> for Bivector<T> {
type Output = Scalar<T>;
#[inline]
fn bulk_contract(&self, rhs: &Bivector<T>) -> Scalar<T> {
Scalar::new_unchecked(rhs.rx() * self.rx() + rhs.ry() * self.ry() + rhs.rz() * self.rz())
}
}
#[allow(unused_variables)]
impl<T: Float> BulkContract<Bivector<T>> for Unit<Bivector<T>> {
type Output = Scalar<T>;
#[inline]
fn bulk_contract(&self, rhs: &Bivector<T>) -> Scalar<T> {
Scalar::new_unchecked(
rhs.rx() * self.as_inner().rx()
+ rhs.ry() * self.as_inner().ry()
+ rhs.rz() * self.as_inner().rz(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkContract<Unit<Bivector<T>>> for Bivector<T> {
type Output = Scalar<T>;
#[inline]
fn bulk_contract(&self, rhs: &Unit<Bivector<T>>) -> Scalar<T> {
Scalar::new_unchecked(
rhs.as_inner().rx() * self.rx()
+ rhs.as_inner().ry() * self.ry()
+ rhs.as_inner().rz() * self.rz(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkContract<Unit<Bivector<T>>> for Unit<Bivector<T>> {
type Output = Scalar<T>;
#[inline]
fn bulk_contract(&self, rhs: &Unit<Bivector<T>>) -> Scalar<T> {
Scalar::new_unchecked(
rhs.as_inner().rx() * self.as_inner().rx()
+ rhs.as_inner().ry() * self.as_inner().ry()
+ rhs.as_inner().rz() * self.as_inner().rz(),
)
}
}
#[doc = "Bulk contraction of [`Bivector`] with [`Scalar`].\n\nThe bulk contraction extracts the Euclidean (non-degenerate) component\nof the interior product. In PGA, this isolates the finite/spatial part."]
impl<T: Float> BulkContract<Scalar<T>> for Bivector<T> {
type Output = Bivector<T>;
#[inline]
fn bulk_contract(&self, rhs: &Scalar<T>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.s() * self.rz(),
rhs.s() * self.ry(),
rhs.s() * self.rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkContract<Scalar<T>> for Unit<Bivector<T>> {
type Output = Bivector<T>;
#[inline]
fn bulk_contract(&self, rhs: &Scalar<T>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.s() * self.as_inner().rz(),
rhs.s() * self.as_inner().ry(),
rhs.s() * self.as_inner().rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkContract<Unit<Scalar<T>>> for Bivector<T> {
type Output = Bivector<T>;
#[inline]
fn bulk_contract(&self, rhs: &Unit<Scalar<T>>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.as_inner().s() * self.rz(),
rhs.as_inner().s() * self.ry(),
rhs.as_inner().s() * self.rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkContract<Unit<Scalar<T>>> for Unit<Bivector<T>> {
type Output = Bivector<T>;
#[inline]
fn bulk_contract(&self, rhs: &Unit<Scalar<T>>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.as_inner().s() * self.as_inner().rz(),
rhs.as_inner().s() * self.as_inner().ry(),
rhs.as_inner().s() * self.as_inner().rx(),
)
}
}
#[doc = "Bulk contraction of [`Bivector`] with [`Vector`].\n\nThe bulk contraction extracts the Euclidean (non-degenerate) component\nof the interior product. In PGA, this isolates the finite/spatial part."]
impl<T: Float> BulkContract<Vector<T>> for Bivector<T> {
type Output = Vector<T>;
#[inline]
fn bulk_contract(&self, rhs: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.y() * self.rz()) + -(rhs.z() * self.ry()),
-(rhs.z() * self.rx()) + rhs.x() * self.rz(),
rhs.x() * self.ry() + rhs.y() * self.rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkContract<Vector<T>> for Unit<Bivector<T>> {
type Output = Vector<T>;
#[inline]
fn bulk_contract(&self, rhs: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.y() * self.as_inner().rz()) + -(rhs.z() * self.as_inner().ry()),
-(rhs.z() * self.as_inner().rx()) + rhs.x() * self.as_inner().rz(),
rhs.x() * self.as_inner().ry() + rhs.y() * self.as_inner().rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkContract<Unit<Vector<T>>> for Bivector<T> {
type Output = Vector<T>;
#[inline]
fn bulk_contract(&self, rhs: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.as_inner().y() * self.rz()) + -(rhs.as_inner().z() * self.ry()),
-(rhs.as_inner().z() * self.rx()) + rhs.as_inner().x() * self.rz(),
rhs.as_inner().x() * self.ry() + rhs.as_inner().y() * self.rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkContract<Unit<Vector<T>>> for Unit<Bivector<T>> {
type Output = Vector<T>;
#[inline]
fn bulk_contract(&self, rhs: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.as_inner().y() * self.as_inner().rz())
+ -(rhs.as_inner().z() * self.as_inner().ry()),
-(rhs.as_inner().z() * self.as_inner().rx())
+ rhs.as_inner().x() * self.as_inner().rz(),
rhs.as_inner().x() * self.as_inner().ry() + rhs.as_inner().y() * self.as_inner().rx(),
)
}
}
#[doc = "Bulk contraction of [`Scalar`] with [`Scalar`].\n\nThe bulk contraction extracts the Euclidean (non-degenerate) component\nof the interior product. In PGA, this isolates the finite/spatial part."]
impl<T: Float> BulkContract<Scalar<T>> for Scalar<T> {
type Output = Scalar<T>;
#[inline]
fn bulk_contract(&self, rhs: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(rhs.s() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> BulkContract<Scalar<T>> for Unit<Scalar<T>> {
type Output = Scalar<T>;
#[inline]
fn bulk_contract(&self, rhs: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(rhs.s() * self.as_inner().s())
}
}
#[allow(unused_variables)]
impl<T: Float> BulkContract<Unit<Scalar<T>>> for Scalar<T> {
type Output = Scalar<T>;
#[inline]
fn bulk_contract(&self, rhs: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(rhs.as_inner().s() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> BulkContract<Unit<Scalar<T>>> for Unit<Scalar<T>> {
type Output = Scalar<T>;
#[inline]
fn bulk_contract(&self, rhs: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(rhs.as_inner().s() * self.as_inner().s())
}
}
#[doc = "Bulk contraction of [`Trivector`] with [`Bivector`].\n\nThe bulk contraction extracts the Euclidean (non-degenerate) component\nof the interior product. In PGA, this isolates the finite/spatial part."]
impl<T: Float> BulkContract<Bivector<T>> for Trivector<T> {
type Output = Vector<T>;
#[inline]
fn bulk_contract(&self, rhs: &Bivector<T>) -> Vector<T> {
Vector::new_unchecked(
rhs.rx() * self.ps(),
-(rhs.ry() * self.ps()),
rhs.rz() * self.ps(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkContract<Bivector<T>> for Unit<Trivector<T>> {
type Output = Vector<T>;
#[inline]
fn bulk_contract(&self, rhs: &Bivector<T>) -> Vector<T> {
Vector::new_unchecked(
rhs.rx() * self.as_inner().ps(),
-(rhs.ry() * self.as_inner().ps()),
rhs.rz() * self.as_inner().ps(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkContract<Unit<Bivector<T>>> for Trivector<T> {
type Output = Vector<T>;
#[inline]
fn bulk_contract(&self, rhs: &Unit<Bivector<T>>) -> Vector<T> {
Vector::new_unchecked(
rhs.as_inner().rx() * self.ps(),
-(rhs.as_inner().ry() * self.ps()),
rhs.as_inner().rz() * self.ps(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkContract<Unit<Bivector<T>>> for Unit<Trivector<T>> {
type Output = Vector<T>;
#[inline]
fn bulk_contract(&self, rhs: &Unit<Bivector<T>>) -> Vector<T> {
Vector::new_unchecked(
rhs.as_inner().rx() * self.as_inner().ps(),
-(rhs.as_inner().ry() * self.as_inner().ps()),
rhs.as_inner().rz() * self.as_inner().ps(),
)
}
}
#[doc = "Bulk contraction of [`Trivector`] with [`Scalar`].\n\nThe bulk contraction extracts the Euclidean (non-degenerate) component\nof the interior product. In PGA, this isolates the finite/spatial part."]
impl<T: Float> BulkContract<Scalar<T>> for Trivector<T> {
type Output = Trivector<T>;
#[inline]
fn bulk_contract(&self, rhs: &Scalar<T>) -> Trivector<T> {
Trivector::new_unchecked(rhs.s() * self.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> BulkContract<Scalar<T>> for Unit<Trivector<T>> {
type Output = Trivector<T>;
#[inline]
fn bulk_contract(&self, rhs: &Scalar<T>) -> Trivector<T> {
Trivector::new_unchecked(rhs.s() * self.as_inner().ps())
}
}
#[allow(unused_variables)]
impl<T: Float> BulkContract<Unit<Scalar<T>>> for Trivector<T> {
type Output = Trivector<T>;
#[inline]
fn bulk_contract(&self, rhs: &Unit<Scalar<T>>) -> Trivector<T> {
Trivector::new_unchecked(rhs.as_inner().s() * self.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> BulkContract<Unit<Scalar<T>>> for Unit<Trivector<T>> {
type Output = Trivector<T>;
#[inline]
fn bulk_contract(&self, rhs: &Unit<Scalar<T>>) -> Trivector<T> {
Trivector::new_unchecked(rhs.as_inner().s() * self.as_inner().ps())
}
}
#[doc = "Bulk contraction of [`Trivector`] with [`Trivector`].\n\nThe bulk contraction extracts the Euclidean (non-degenerate) component\nof the interior product. In PGA, this isolates the finite/spatial part."]
impl<T: Float> BulkContract<Trivector<T>> for Trivector<T> {
type Output = Scalar<T>;
#[inline]
fn bulk_contract(&self, rhs: &Trivector<T>) -> Scalar<T> {
Scalar::new_unchecked(rhs.ps() * self.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> BulkContract<Trivector<T>> for Unit<Trivector<T>> {
type Output = Scalar<T>;
#[inline]
fn bulk_contract(&self, rhs: &Trivector<T>) -> Scalar<T> {
Scalar::new_unchecked(rhs.ps() * self.as_inner().ps())
}
}
#[allow(unused_variables)]
impl<T: Float> BulkContract<Unit<Trivector<T>>> for Trivector<T> {
type Output = Scalar<T>;
#[inline]
fn bulk_contract(&self, rhs: &Unit<Trivector<T>>) -> Scalar<T> {
Scalar::new_unchecked(rhs.as_inner().ps() * self.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> BulkContract<Unit<Trivector<T>>> for Unit<Trivector<T>> {
type Output = Scalar<T>;
#[inline]
fn bulk_contract(&self, rhs: &Unit<Trivector<T>>) -> Scalar<T> {
Scalar::new_unchecked(rhs.as_inner().ps() * self.as_inner().ps())
}
}
#[doc = "Bulk contraction of [`Trivector`] with [`Vector`].\n\nThe bulk contraction extracts the Euclidean (non-degenerate) component\nof the interior product. In PGA, this isolates the finite/spatial part."]
impl<T: Float> BulkContract<Vector<T>> for Trivector<T> {
type Output = Bivector<T>;
#[inline]
fn bulk_contract(&self, rhs: &Vector<T>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.z() * self.ps(),
-(rhs.y() * self.ps()),
rhs.x() * self.ps(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkContract<Vector<T>> for Unit<Trivector<T>> {
type Output = Bivector<T>;
#[inline]
fn bulk_contract(&self, rhs: &Vector<T>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.z() * self.as_inner().ps(),
-(rhs.y() * self.as_inner().ps()),
rhs.x() * self.as_inner().ps(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkContract<Unit<Vector<T>>> for Trivector<T> {
type Output = Bivector<T>;
#[inline]
fn bulk_contract(&self, rhs: &Unit<Vector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.as_inner().z() * self.ps(),
-(rhs.as_inner().y() * self.ps()),
rhs.as_inner().x() * self.ps(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkContract<Unit<Vector<T>>> for Unit<Trivector<T>> {
type Output = Bivector<T>;
#[inline]
fn bulk_contract(&self, rhs: &Unit<Vector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.as_inner().z() * self.as_inner().ps(),
-(rhs.as_inner().y() * self.as_inner().ps()),
rhs.as_inner().x() * self.as_inner().ps(),
)
}
}
#[doc = "Bulk contraction of [`Vector`] with [`Scalar`].\n\nThe bulk contraction extracts the Euclidean (non-degenerate) component\nof the interior product. In PGA, this isolates the finite/spatial part."]
impl<T: Float> BulkContract<Scalar<T>> for Vector<T> {
type Output = Vector<T>;
#[inline]
fn bulk_contract(&self, rhs: &Scalar<T>) -> Vector<T> {
Vector::new_unchecked(rhs.s() * self.x(), rhs.s() * self.y(), rhs.s() * self.z())
}
}
#[allow(unused_variables)]
impl<T: Float> BulkContract<Scalar<T>> for Unit<Vector<T>> {
type Output = Vector<T>;
#[inline]
fn bulk_contract(&self, rhs: &Scalar<T>) -> Vector<T> {
Vector::new_unchecked(
rhs.s() * self.as_inner().x(),
rhs.s() * self.as_inner().y(),
rhs.s() * self.as_inner().z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkContract<Unit<Scalar<T>>> for Vector<T> {
type Output = Vector<T>;
#[inline]
fn bulk_contract(&self, rhs: &Unit<Scalar<T>>) -> Vector<T> {
Vector::new_unchecked(
rhs.as_inner().s() * self.x(),
rhs.as_inner().s() * self.y(),
rhs.as_inner().s() * self.z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkContract<Unit<Scalar<T>>> for Unit<Vector<T>> {
type Output = Vector<T>;
#[inline]
fn bulk_contract(&self, rhs: &Unit<Scalar<T>>) -> Vector<T> {
Vector::new_unchecked(
rhs.as_inner().s() * self.as_inner().x(),
rhs.as_inner().s() * self.as_inner().y(),
rhs.as_inner().s() * self.as_inner().z(),
)
}
}
#[doc = "Bulk contraction of [`Vector`] with [`Vector`].\n\nThe bulk contraction extracts the Euclidean (non-degenerate) component\nof the interior product. In PGA, this isolates the finite/spatial part."]
impl<T: Float> BulkContract<Vector<T>> for Vector<T> {
type Output = Scalar<T>;
#[inline]
fn bulk_contract(&self, rhs: &Vector<T>) -> Scalar<T> {
Scalar::new_unchecked(rhs.x() * self.x() + rhs.y() * self.y() + rhs.z() * self.z())
}
}
#[allow(unused_variables)]
impl<T: Float> BulkContract<Vector<T>> for Unit<Vector<T>> {
type Output = Scalar<T>;
#[inline]
fn bulk_contract(&self, rhs: &Vector<T>) -> Scalar<T> {
Scalar::new_unchecked(
rhs.x() * self.as_inner().x()
+ rhs.y() * self.as_inner().y()
+ rhs.z() * self.as_inner().z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkContract<Unit<Vector<T>>> for Vector<T> {
type Output = Scalar<T>;
#[inline]
fn bulk_contract(&self, rhs: &Unit<Vector<T>>) -> Scalar<T> {
Scalar::new_unchecked(
rhs.as_inner().x() * self.x()
+ rhs.as_inner().y() * self.y()
+ rhs.as_inner().z() * self.z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkContract<Unit<Vector<T>>> for Unit<Vector<T>> {
type Output = Scalar<T>;
#[inline]
fn bulk_contract(&self, rhs: &Unit<Vector<T>>) -> Scalar<T> {
Scalar::new_unchecked(
rhs.as_inner().x() * self.as_inner().x()
+ rhs.as_inner().y() * self.as_inner().y()
+ rhs.as_inner().z() * self.as_inner().z(),
)
}
}
#[doc = "Weight contraction of [`Bivector`] with [`Bivector`].\n\nThe weight contraction extracts the degenerate/ideal component of the\ninterior product. In PGA, this measures the 'weight' or projective part."]
impl<T: Float> WeightContract<Bivector<T>> for Bivector<T> {
type Output = Scalar<T>;
#[inline]
fn weight_contract(&self, rhs: &Bivector<T>) -> Scalar<T> {
Scalar::new_unchecked(
-(rhs.rx() * self.rx()) + -(rhs.ry() * self.ry()) + -(rhs.rz() * self.rz()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightContract<Bivector<T>> for Unit<Bivector<T>> {
type Output = Scalar<T>;
#[inline]
fn weight_contract(&self, rhs: &Bivector<T>) -> Scalar<T> {
Scalar::new_unchecked(
-(rhs.rx() * self.as_inner().rx())
+ -(rhs.ry() * self.as_inner().ry())
+ -(rhs.rz() * self.as_inner().rz()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightContract<Unit<Bivector<T>>> for Bivector<T> {
type Output = Scalar<T>;
#[inline]
fn weight_contract(&self, rhs: &Unit<Bivector<T>>) -> Scalar<T> {
Scalar::new_unchecked(
-(rhs.as_inner().rx() * self.rx())
+ -(rhs.as_inner().ry() * self.ry())
+ -(rhs.as_inner().rz() * self.rz()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightContract<Unit<Bivector<T>>> for Unit<Bivector<T>> {
type Output = Scalar<T>;
#[inline]
fn weight_contract(&self, rhs: &Unit<Bivector<T>>) -> Scalar<T> {
Scalar::new_unchecked(
-(rhs.as_inner().rx() * self.as_inner().rx())
+ -(rhs.as_inner().ry() * self.as_inner().ry())
+ -(rhs.as_inner().rz() * self.as_inner().rz()),
)
}
}
#[doc = "Weight contraction of [`Bivector`] with [`Scalar`].\n\nThe weight contraction extracts the degenerate/ideal component of the\ninterior product. In PGA, this measures the 'weight' or projective part."]
impl<T: Float> WeightContract<Scalar<T>> for Bivector<T> {
type Output = Bivector<T>;
#[inline]
fn weight_contract(&self, rhs: &Scalar<T>) -> Bivector<T> {
Bivector::new_unchecked(
-(rhs.s() * self.rz()),
-(rhs.s() * self.ry()),
-(rhs.s() * self.rx()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightContract<Scalar<T>> for Unit<Bivector<T>> {
type Output = Bivector<T>;
#[inline]
fn weight_contract(&self, rhs: &Scalar<T>) -> Bivector<T> {
Bivector::new_unchecked(
-(rhs.s() * self.as_inner().rz()),
-(rhs.s() * self.as_inner().ry()),
-(rhs.s() * self.as_inner().rx()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightContract<Unit<Scalar<T>>> for Bivector<T> {
type Output = Bivector<T>;
#[inline]
fn weight_contract(&self, rhs: &Unit<Scalar<T>>) -> Bivector<T> {
Bivector::new_unchecked(
-(rhs.as_inner().s() * self.rz()),
-(rhs.as_inner().s() * self.ry()),
-(rhs.as_inner().s() * self.rx()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightContract<Unit<Scalar<T>>> for Unit<Bivector<T>> {
type Output = Bivector<T>;
#[inline]
fn weight_contract(&self, rhs: &Unit<Scalar<T>>) -> Bivector<T> {
Bivector::new_unchecked(
-(rhs.as_inner().s() * self.as_inner().rz()),
-(rhs.as_inner().s() * self.as_inner().ry()),
-(rhs.as_inner().s() * self.as_inner().rx()),
)
}
}
#[doc = "Weight contraction of [`Bivector`] with [`Vector`].\n\nThe weight contraction extracts the degenerate/ideal component of the\ninterior product. In PGA, this measures the 'weight' or projective part."]
impl<T: Float> WeightContract<Vector<T>> for Bivector<T> {
type Output = Vector<T>;
#[inline]
fn weight_contract(&self, rhs: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(
rhs.y() * self.rz() + rhs.z() * self.ry(),
-(rhs.x() * self.rz()) + rhs.z() * self.rx(),
-(rhs.x() * self.ry()) + -(rhs.y() * self.rx()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightContract<Vector<T>> for Unit<Bivector<T>> {
type Output = Vector<T>;
#[inline]
fn weight_contract(&self, rhs: &Vector<T>) -> Vector<T> {
Vector::new_unchecked(
rhs.y() * self.as_inner().rz() + rhs.z() * self.as_inner().ry(),
-(rhs.x() * self.as_inner().rz()) + rhs.z() * self.as_inner().rx(),
-(rhs.x() * self.as_inner().ry()) + -(rhs.y() * self.as_inner().rx()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightContract<Unit<Vector<T>>> for Bivector<T> {
type Output = Vector<T>;
#[inline]
fn weight_contract(&self, rhs: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
rhs.as_inner().y() * self.rz() + rhs.as_inner().z() * self.ry(),
-(rhs.as_inner().x() * self.rz()) + rhs.as_inner().z() * self.rx(),
-(rhs.as_inner().x() * self.ry()) + -(rhs.as_inner().y() * self.rx()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightContract<Unit<Vector<T>>> for Unit<Bivector<T>> {
type Output = Vector<T>;
#[inline]
fn weight_contract(&self, rhs: &Unit<Vector<T>>) -> Vector<T> {
Vector::new_unchecked(
rhs.as_inner().y() * self.as_inner().rz() + rhs.as_inner().z() * self.as_inner().ry(),
-(rhs.as_inner().x() * self.as_inner().rz())
+ rhs.as_inner().z() * self.as_inner().rx(),
-(rhs.as_inner().x() * self.as_inner().ry())
+ -(rhs.as_inner().y() * self.as_inner().rx()),
)
}
}
#[doc = "Weight contraction of [`Scalar`] with [`Scalar`].\n\nThe weight contraction extracts the degenerate/ideal component of the\ninterior product. In PGA, this measures the 'weight' or projective part."]
impl<T: Float> WeightContract<Scalar<T>> for Scalar<T> {
type Output = Scalar<T>;
#[inline]
fn weight_contract(&self, rhs: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(-(rhs.s() * self.s()))
}
}
#[allow(unused_variables)]
impl<T: Float> WeightContract<Scalar<T>> for Unit<Scalar<T>> {
type Output = Scalar<T>;
#[inline]
fn weight_contract(&self, rhs: &Scalar<T>) -> Scalar<T> {
Scalar::new_unchecked(-(rhs.s() * self.as_inner().s()))
}
}
#[allow(unused_variables)]
impl<T: Float> WeightContract<Unit<Scalar<T>>> for Scalar<T> {
type Output = Scalar<T>;
#[inline]
fn weight_contract(&self, rhs: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(-(rhs.as_inner().s() * self.s()))
}
}
#[allow(unused_variables)]
impl<T: Float> WeightContract<Unit<Scalar<T>>> for Unit<Scalar<T>> {
type Output = Scalar<T>;
#[inline]
fn weight_contract(&self, rhs: &Unit<Scalar<T>>) -> Scalar<T> {
Scalar::new_unchecked(-(rhs.as_inner().s() * self.as_inner().s()))
}
}
#[doc = "Weight contraction of [`Trivector`] with [`Bivector`].\n\nThe weight contraction extracts the degenerate/ideal component of the\ninterior product. In PGA, this measures the 'weight' or projective part."]
impl<T: Float> WeightContract<Bivector<T>> for Trivector<T> {
type Output = Vector<T>;
#[inline]
fn weight_contract(&self, rhs: &Bivector<T>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.rx() * self.ps()),
rhs.ry() * self.ps(),
-(rhs.rz() * self.ps()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightContract<Bivector<T>> for Unit<Trivector<T>> {
type Output = Vector<T>;
#[inline]
fn weight_contract(&self, rhs: &Bivector<T>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.rx() * self.as_inner().ps()),
rhs.ry() * self.as_inner().ps(),
-(rhs.rz() * self.as_inner().ps()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightContract<Unit<Bivector<T>>> for Trivector<T> {
type Output = Vector<T>;
#[inline]
fn weight_contract(&self, rhs: &Unit<Bivector<T>>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.as_inner().rx() * self.ps()),
rhs.as_inner().ry() * self.ps(),
-(rhs.as_inner().rz() * self.ps()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightContract<Unit<Bivector<T>>> for Unit<Trivector<T>> {
type Output = Vector<T>;
#[inline]
fn weight_contract(&self, rhs: &Unit<Bivector<T>>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.as_inner().rx() * self.as_inner().ps()),
rhs.as_inner().ry() * self.as_inner().ps(),
-(rhs.as_inner().rz() * self.as_inner().ps()),
)
}
}
#[doc = "Weight contraction of [`Trivector`] with [`Scalar`].\n\nThe weight contraction extracts the degenerate/ideal component of the\ninterior product. In PGA, this measures the 'weight' or projective part."]
impl<T: Float> WeightContract<Scalar<T>> for Trivector<T> {
type Output = Trivector<T>;
#[inline]
fn weight_contract(&self, rhs: &Scalar<T>) -> Trivector<T> {
Trivector::new_unchecked(-(rhs.s() * self.ps()))
}
}
#[allow(unused_variables)]
impl<T: Float> WeightContract<Scalar<T>> for Unit<Trivector<T>> {
type Output = Trivector<T>;
#[inline]
fn weight_contract(&self, rhs: &Scalar<T>) -> Trivector<T> {
Trivector::new_unchecked(-(rhs.s() * self.as_inner().ps()))
}
}
#[allow(unused_variables)]
impl<T: Float> WeightContract<Unit<Scalar<T>>> for Trivector<T> {
type Output = Trivector<T>;
#[inline]
fn weight_contract(&self, rhs: &Unit<Scalar<T>>) -> Trivector<T> {
Trivector::new_unchecked(-(rhs.as_inner().s() * self.ps()))
}
}
#[allow(unused_variables)]
impl<T: Float> WeightContract<Unit<Scalar<T>>> for Unit<Trivector<T>> {
type Output = Trivector<T>;
#[inline]
fn weight_contract(&self, rhs: &Unit<Scalar<T>>) -> Trivector<T> {
Trivector::new_unchecked(-(rhs.as_inner().s() * self.as_inner().ps()))
}
}
#[doc = "Weight contraction of [`Trivector`] with [`Trivector`].\n\nThe weight contraction extracts the degenerate/ideal component of the\ninterior product. In PGA, this measures the 'weight' or projective part."]
impl<T: Float> WeightContract<Trivector<T>> for Trivector<T> {
type Output = Scalar<T>;
#[inline]
fn weight_contract(&self, rhs: &Trivector<T>) -> Scalar<T> {
Scalar::new_unchecked(-(rhs.ps() * self.ps()))
}
}
#[allow(unused_variables)]
impl<T: Float> WeightContract<Trivector<T>> for Unit<Trivector<T>> {
type Output = Scalar<T>;
#[inline]
fn weight_contract(&self, rhs: &Trivector<T>) -> Scalar<T> {
Scalar::new_unchecked(-(rhs.ps() * self.as_inner().ps()))
}
}
#[allow(unused_variables)]
impl<T: Float> WeightContract<Unit<Trivector<T>>> for Trivector<T> {
type Output = Scalar<T>;
#[inline]
fn weight_contract(&self, rhs: &Unit<Trivector<T>>) -> Scalar<T> {
Scalar::new_unchecked(-(rhs.as_inner().ps() * self.ps()))
}
}
#[allow(unused_variables)]
impl<T: Float> WeightContract<Unit<Trivector<T>>> for Unit<Trivector<T>> {
type Output = Scalar<T>;
#[inline]
fn weight_contract(&self, rhs: &Unit<Trivector<T>>) -> Scalar<T> {
Scalar::new_unchecked(-(rhs.as_inner().ps() * self.as_inner().ps()))
}
}
#[doc = "Weight contraction of [`Trivector`] with [`Vector`].\n\nThe weight contraction extracts the degenerate/ideal component of the\ninterior product. In PGA, this measures the 'weight' or projective part."]
impl<T: Float> WeightContract<Vector<T>> for Trivector<T> {
type Output = Bivector<T>;
#[inline]
fn weight_contract(&self, rhs: &Vector<T>) -> Bivector<T> {
Bivector::new_unchecked(
-(rhs.z() * self.ps()),
rhs.y() * self.ps(),
-(rhs.x() * self.ps()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightContract<Vector<T>> for Unit<Trivector<T>> {
type Output = Bivector<T>;
#[inline]
fn weight_contract(&self, rhs: &Vector<T>) -> Bivector<T> {
Bivector::new_unchecked(
-(rhs.z() * self.as_inner().ps()),
rhs.y() * self.as_inner().ps(),
-(rhs.x() * self.as_inner().ps()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightContract<Unit<Vector<T>>> for Trivector<T> {
type Output = Bivector<T>;
#[inline]
fn weight_contract(&self, rhs: &Unit<Vector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
-(rhs.as_inner().z() * self.ps()),
rhs.as_inner().y() * self.ps(),
-(rhs.as_inner().x() * self.ps()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightContract<Unit<Vector<T>>> for Unit<Trivector<T>> {
type Output = Bivector<T>;
#[inline]
fn weight_contract(&self, rhs: &Unit<Vector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
-(rhs.as_inner().z() * self.as_inner().ps()),
rhs.as_inner().y() * self.as_inner().ps(),
-(rhs.as_inner().x() * self.as_inner().ps()),
)
}
}
#[doc = "Weight contraction of [`Vector`] with [`Scalar`].\n\nThe weight contraction extracts the degenerate/ideal component of the\ninterior product. In PGA, this measures the 'weight' or projective part."]
impl<T: Float> WeightContract<Scalar<T>> for Vector<T> {
type Output = Vector<T>;
#[inline]
fn weight_contract(&self, rhs: &Scalar<T>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.s() * self.x()),
-(rhs.s() * self.y()),
-(rhs.s() * self.z()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightContract<Scalar<T>> for Unit<Vector<T>> {
type Output = Vector<T>;
#[inline]
fn weight_contract(&self, rhs: &Scalar<T>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.s() * self.as_inner().x()),
-(rhs.s() * self.as_inner().y()),
-(rhs.s() * self.as_inner().z()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightContract<Unit<Scalar<T>>> for Vector<T> {
type Output = Vector<T>;
#[inline]
fn weight_contract(&self, rhs: &Unit<Scalar<T>>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.as_inner().s() * self.x()),
-(rhs.as_inner().s() * self.y()),
-(rhs.as_inner().s() * self.z()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightContract<Unit<Scalar<T>>> for Unit<Vector<T>> {
type Output = Vector<T>;
#[inline]
fn weight_contract(&self, rhs: &Unit<Scalar<T>>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.as_inner().s() * self.as_inner().x()),
-(rhs.as_inner().s() * self.as_inner().y()),
-(rhs.as_inner().s() * self.as_inner().z()),
)
}
}
#[doc = "Weight contraction of [`Vector`] with [`Vector`].\n\nThe weight contraction extracts the degenerate/ideal component of the\ninterior product. In PGA, this measures the 'weight' or projective part."]
impl<T: Float> WeightContract<Vector<T>> for Vector<T> {
type Output = Scalar<T>;
#[inline]
fn weight_contract(&self, rhs: &Vector<T>) -> Scalar<T> {
Scalar::new_unchecked(-(rhs.x() * self.x()) + -(rhs.y() * self.y()) + -(rhs.z() * self.z()))
}
}
#[allow(unused_variables)]
impl<T: Float> WeightContract<Vector<T>> for Unit<Vector<T>> {
type Output = Scalar<T>;
#[inline]
fn weight_contract(&self, rhs: &Vector<T>) -> Scalar<T> {
Scalar::new_unchecked(
-(rhs.x() * self.as_inner().x())
+ -(rhs.y() * self.as_inner().y())
+ -(rhs.z() * self.as_inner().z()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightContract<Unit<Vector<T>>> for Vector<T> {
type Output = Scalar<T>;
#[inline]
fn weight_contract(&self, rhs: &Unit<Vector<T>>) -> Scalar<T> {
Scalar::new_unchecked(
-(rhs.as_inner().x() * self.x())
+ -(rhs.as_inner().y() * self.y())
+ -(rhs.as_inner().z() * self.z()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightContract<Unit<Vector<T>>> for Unit<Vector<T>> {
type Output = Scalar<T>;
#[inline]
fn weight_contract(&self, rhs: &Unit<Vector<T>>) -> Scalar<T> {
Scalar::new_unchecked(
-(rhs.as_inner().x() * self.as_inner().x())
+ -(rhs.as_inner().y() * self.as_inner().y())
+ -(rhs.as_inner().z() * self.as_inner().z()),
)
}
}
#[doc = "Bulk expansion of [`Bivector`] with [`Bivector`].\n\nThe bulk expansion is the dual of bulk contraction, extracting the\nEuclidean component of the exterior product complement."]
impl<T: Float> BulkExpand<Bivector<T>> for Bivector<T> {
type Output = Trivector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Bivector<T>) -> Trivector<T> {
Trivector::new_unchecked(rhs.rx() * self.rx() + rhs.ry() * self.ry() + rhs.rz() * self.rz())
}
}
#[allow(unused_variables)]
impl<T: Float> BulkExpand<Bivector<T>> for Unit<Bivector<T>> {
type Output = Trivector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Bivector<T>) -> Trivector<T> {
Trivector::new_unchecked(
rhs.rx() * self.as_inner().rx()
+ rhs.ry() * self.as_inner().ry()
+ rhs.rz() * self.as_inner().rz(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkExpand<Unit<Bivector<T>>> for Bivector<T> {
type Output = Trivector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Unit<Bivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(
rhs.as_inner().rx() * self.rx()
+ rhs.as_inner().ry() * self.ry()
+ rhs.as_inner().rz() * self.rz(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkExpand<Unit<Bivector<T>>> for Unit<Bivector<T>> {
type Output = Trivector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Unit<Bivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(
rhs.as_inner().rx() * self.as_inner().rx()
+ rhs.as_inner().ry() * self.as_inner().ry()
+ rhs.as_inner().rz() * self.as_inner().rz(),
)
}
}
#[doc = "Bulk expansion of [`Bivector`] with [`Trivector`].\n\nThe bulk expansion is the dual of bulk contraction, extracting the\nEuclidean component of the exterior product complement."]
impl<T: Float> BulkExpand<Trivector<T>> for Bivector<T> {
type Output = Bivector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Trivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.ps() * self.rz(),
rhs.ps() * self.ry(),
rhs.ps() * self.rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkExpand<Trivector<T>> for Unit<Bivector<T>> {
type Output = Bivector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Trivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.ps() * self.as_inner().rz(),
rhs.ps() * self.as_inner().ry(),
rhs.ps() * self.as_inner().rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkExpand<Unit<Trivector<T>>> for Bivector<T> {
type Output = Bivector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Unit<Trivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.as_inner().ps() * self.rz(),
rhs.as_inner().ps() * self.ry(),
rhs.as_inner().ps() * self.rx(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkExpand<Unit<Trivector<T>>> for Unit<Bivector<T>> {
type Output = Bivector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Unit<Trivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.as_inner().ps() * self.as_inner().rz(),
rhs.as_inner().ps() * self.as_inner().ry(),
rhs.as_inner().ps() * self.as_inner().rx(),
)
}
}
#[doc = "Bulk expansion of [`Scalar`] with [`Bivector`].\n\nThe bulk expansion is the dual of bulk contraction, extracting the\nEuclidean component of the exterior product complement."]
impl<T: Float> BulkExpand<Bivector<T>> for Scalar<T> {
type Output = Vector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Bivector<T>) -> Vector<T> {
Vector::new_unchecked(
rhs.rx() * self.s(),
-(rhs.ry() * self.s()),
rhs.rz() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkExpand<Bivector<T>> for Unit<Scalar<T>> {
type Output = Vector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Bivector<T>) -> Vector<T> {
Vector::new_unchecked(
rhs.rx() * self.as_inner().s(),
-(rhs.ry() * self.as_inner().s()),
rhs.rz() * self.as_inner().s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkExpand<Unit<Bivector<T>>> for Scalar<T> {
type Output = Vector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Unit<Bivector<T>>) -> Vector<T> {
Vector::new_unchecked(
rhs.as_inner().rx() * self.s(),
-(rhs.as_inner().ry() * self.s()),
rhs.as_inner().rz() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkExpand<Unit<Bivector<T>>> for Unit<Scalar<T>> {
type Output = Vector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Unit<Bivector<T>>) -> Vector<T> {
Vector::new_unchecked(
rhs.as_inner().rx() * self.as_inner().s(),
-(rhs.as_inner().ry() * self.as_inner().s()),
rhs.as_inner().rz() * self.as_inner().s(),
)
}
}
#[doc = "Bulk expansion of [`Scalar`] with [`Scalar`].\n\nThe bulk expansion is the dual of bulk contraction, extracting the\nEuclidean component of the exterior product complement."]
impl<T: Float> BulkExpand<Scalar<T>> for Scalar<T> {
type Output = Trivector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Scalar<T>) -> Trivector<T> {
Trivector::new_unchecked(rhs.s() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> BulkExpand<Scalar<T>> for Unit<Scalar<T>> {
type Output = Trivector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Scalar<T>) -> Trivector<T> {
Trivector::new_unchecked(rhs.s() * self.as_inner().s())
}
}
#[allow(unused_variables)]
impl<T: Float> BulkExpand<Unit<Scalar<T>>> for Scalar<T> {
type Output = Trivector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Unit<Scalar<T>>) -> Trivector<T> {
Trivector::new_unchecked(rhs.as_inner().s() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> BulkExpand<Unit<Scalar<T>>> for Unit<Scalar<T>> {
type Output = Trivector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Unit<Scalar<T>>) -> Trivector<T> {
Trivector::new_unchecked(rhs.as_inner().s() * self.as_inner().s())
}
}
#[doc = "Bulk expansion of [`Scalar`] with [`Trivector`].\n\nThe bulk expansion is the dual of bulk contraction, extracting the\nEuclidean component of the exterior product complement."]
impl<T: Float> BulkExpand<Trivector<T>> for Scalar<T> {
type Output = Scalar<T>;
#[inline]
fn bulk_expand(&self, rhs: &Trivector<T>) -> Scalar<T> {
Scalar::new_unchecked(rhs.ps() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> BulkExpand<Trivector<T>> for Unit<Scalar<T>> {
type Output = Scalar<T>;
#[inline]
fn bulk_expand(&self, rhs: &Trivector<T>) -> Scalar<T> {
Scalar::new_unchecked(rhs.ps() * self.as_inner().s())
}
}
#[allow(unused_variables)]
impl<T: Float> BulkExpand<Unit<Trivector<T>>> for Scalar<T> {
type Output = Scalar<T>;
#[inline]
fn bulk_expand(&self, rhs: &Unit<Trivector<T>>) -> Scalar<T> {
Scalar::new_unchecked(rhs.as_inner().ps() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> BulkExpand<Unit<Trivector<T>>> for Unit<Scalar<T>> {
type Output = Scalar<T>;
#[inline]
fn bulk_expand(&self, rhs: &Unit<Trivector<T>>) -> Scalar<T> {
Scalar::new_unchecked(rhs.as_inner().ps() * self.as_inner().s())
}
}
#[doc = "Bulk expansion of [`Scalar`] with [`Vector`].\n\nThe bulk expansion is the dual of bulk contraction, extracting the\nEuclidean component of the exterior product complement."]
impl<T: Float> BulkExpand<Vector<T>> for Scalar<T> {
type Output = Bivector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Vector<T>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.z() * self.s(),
-(rhs.y() * self.s()),
rhs.x() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkExpand<Vector<T>> for Unit<Scalar<T>> {
type Output = Bivector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Vector<T>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.z() * self.as_inner().s(),
-(rhs.y() * self.as_inner().s()),
rhs.x() * self.as_inner().s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkExpand<Unit<Vector<T>>> for Scalar<T> {
type Output = Bivector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Unit<Vector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.as_inner().z() * self.s(),
-(rhs.as_inner().y() * self.s()),
rhs.as_inner().x() * self.s(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkExpand<Unit<Vector<T>>> for Unit<Scalar<T>> {
type Output = Bivector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Unit<Vector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.as_inner().z() * self.as_inner().s(),
-(rhs.as_inner().y() * self.as_inner().s()),
rhs.as_inner().x() * self.as_inner().s(),
)
}
}
#[doc = "Bulk expansion of [`Trivector`] with [`Trivector`].\n\nThe bulk expansion is the dual of bulk contraction, extracting the\nEuclidean component of the exterior product complement."]
impl<T: Float> BulkExpand<Trivector<T>> for Trivector<T> {
type Output = Trivector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(rhs.ps() * self.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> BulkExpand<Trivector<T>> for Unit<Trivector<T>> {
type Output = Trivector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(rhs.ps() * self.as_inner().ps())
}
}
#[allow(unused_variables)]
impl<T: Float> BulkExpand<Unit<Trivector<T>>> for Trivector<T> {
type Output = Trivector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Unit<Trivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(rhs.as_inner().ps() * self.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> BulkExpand<Unit<Trivector<T>>> for Unit<Trivector<T>> {
type Output = Trivector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Unit<Trivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(rhs.as_inner().ps() * self.as_inner().ps())
}
}
#[doc = "Bulk expansion of [`Vector`] with [`Bivector`].\n\nThe bulk expansion is the dual of bulk contraction, extracting the\nEuclidean component of the exterior product complement."]
impl<T: Float> BulkExpand<Bivector<T>> for Vector<T> {
type Output = Bivector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
-(rhs.rx() * self.y()) + -(rhs.ry() * self.x()),
-(rhs.rx() * self.z()) + rhs.rz() * self.x(),
rhs.ry() * self.z() + rhs.rz() * self.y(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkExpand<Bivector<T>> for Unit<Vector<T>> {
type Output = Bivector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
-(rhs.rx() * self.as_inner().y()) + -(rhs.ry() * self.as_inner().x()),
-(rhs.rx() * self.as_inner().z()) + rhs.rz() * self.as_inner().x(),
rhs.ry() * self.as_inner().z() + rhs.rz() * self.as_inner().y(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkExpand<Unit<Bivector<T>>> for Vector<T> {
type Output = Bivector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Unit<Bivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
-(rhs.as_inner().rx() * self.y()) + -(rhs.as_inner().ry() * self.x()),
-(rhs.as_inner().rx() * self.z()) + rhs.as_inner().rz() * self.x(),
rhs.as_inner().ry() * self.z() + rhs.as_inner().rz() * self.y(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkExpand<Unit<Bivector<T>>> for Unit<Vector<T>> {
type Output = Bivector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Unit<Bivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
-(rhs.as_inner().rx() * self.as_inner().y())
+ -(rhs.as_inner().ry() * self.as_inner().x()),
-(rhs.as_inner().rx() * self.as_inner().z())
+ rhs.as_inner().rz() * self.as_inner().x(),
rhs.as_inner().ry() * self.as_inner().z() + rhs.as_inner().rz() * self.as_inner().y(),
)
}
}
#[doc = "Bulk expansion of [`Vector`] with [`Trivector`].\n\nThe bulk expansion is the dual of bulk contraction, extracting the\nEuclidean component of the exterior product complement."]
impl<T: Float> BulkExpand<Trivector<T>> for Vector<T> {
type Output = Vector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Trivector<T>) -> Vector<T> {
Vector::new_unchecked(
rhs.ps() * self.x(),
rhs.ps() * self.y(),
rhs.ps() * self.z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkExpand<Trivector<T>> for Unit<Vector<T>> {
type Output = Vector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Trivector<T>) -> Vector<T> {
Vector::new_unchecked(
rhs.ps() * self.as_inner().x(),
rhs.ps() * self.as_inner().y(),
rhs.ps() * self.as_inner().z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkExpand<Unit<Trivector<T>>> for Vector<T> {
type Output = Vector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Unit<Trivector<T>>) -> Vector<T> {
Vector::new_unchecked(
rhs.as_inner().ps() * self.x(),
rhs.as_inner().ps() * self.y(),
rhs.as_inner().ps() * self.z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkExpand<Unit<Trivector<T>>> for Unit<Vector<T>> {
type Output = Vector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Unit<Trivector<T>>) -> Vector<T> {
Vector::new_unchecked(
rhs.as_inner().ps() * self.as_inner().x(),
rhs.as_inner().ps() * self.as_inner().y(),
rhs.as_inner().ps() * self.as_inner().z(),
)
}
}
#[doc = "Bulk expansion of [`Vector`] with [`Vector`].\n\nThe bulk expansion is the dual of bulk contraction, extracting the\nEuclidean component of the exterior product complement."]
impl<T: Float> BulkExpand<Vector<T>> for Vector<T> {
type Output = Trivector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Vector<T>) -> Trivector<T> {
Trivector::new_unchecked(rhs.x() * self.x() + rhs.y() * self.y() + rhs.z() * self.z())
}
}
#[allow(unused_variables)]
impl<T: Float> BulkExpand<Vector<T>> for Unit<Vector<T>> {
type Output = Trivector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Vector<T>) -> Trivector<T> {
Trivector::new_unchecked(
rhs.x() * self.as_inner().x()
+ rhs.y() * self.as_inner().y()
+ rhs.z() * self.as_inner().z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkExpand<Unit<Vector<T>>> for Vector<T> {
type Output = Trivector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Unit<Vector<T>>) -> Trivector<T> {
Trivector::new_unchecked(
rhs.as_inner().x() * self.x()
+ rhs.as_inner().y() * self.y()
+ rhs.as_inner().z() * self.z(),
)
}
}
#[allow(unused_variables)]
impl<T: Float> BulkExpand<Unit<Vector<T>>> for Unit<Vector<T>> {
type Output = Trivector<T>;
#[inline]
fn bulk_expand(&self, rhs: &Unit<Vector<T>>) -> Trivector<T> {
Trivector::new_unchecked(
rhs.as_inner().x() * self.as_inner().x()
+ rhs.as_inner().y() * self.as_inner().y()
+ rhs.as_inner().z() * self.as_inner().z(),
)
}
}
#[doc = "Weight expansion of [`Bivector`] with [`Bivector`].\n\nThe weight expansion is the dual of weight contraction, extracting the\ndegenerate/ideal component of the exterior product complement."]
impl<T: Float> WeightExpand<Bivector<T>> for Bivector<T> {
type Output = Trivector<T>;
#[inline]
fn weight_expand(&self, rhs: &Bivector<T>) -> Trivector<T> {
Trivector::new_unchecked(
-(rhs.rx() * self.rx()) + -(rhs.ry() * self.ry()) + -(rhs.rz() * self.rz()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightExpand<Bivector<T>> for Unit<Bivector<T>> {
type Output = Trivector<T>;
#[inline]
fn weight_expand(&self, rhs: &Bivector<T>) -> Trivector<T> {
Trivector::new_unchecked(
-(rhs.rx() * self.as_inner().rx())
+ -(rhs.ry() * self.as_inner().ry())
+ -(rhs.rz() * self.as_inner().rz()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightExpand<Unit<Bivector<T>>> for Bivector<T> {
type Output = Trivector<T>;
#[inline]
fn weight_expand(&self, rhs: &Unit<Bivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(
-(rhs.as_inner().rx() * self.rx())
+ -(rhs.as_inner().ry() * self.ry())
+ -(rhs.as_inner().rz() * self.rz()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightExpand<Unit<Bivector<T>>> for Unit<Bivector<T>> {
type Output = Trivector<T>;
#[inline]
fn weight_expand(&self, rhs: &Unit<Bivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(
-(rhs.as_inner().rx() * self.as_inner().rx())
+ -(rhs.as_inner().ry() * self.as_inner().ry())
+ -(rhs.as_inner().rz() * self.as_inner().rz()),
)
}
}
#[doc = "Weight expansion of [`Bivector`] with [`Trivector`].\n\nThe weight expansion is the dual of weight contraction, extracting the\ndegenerate/ideal component of the exterior product complement."]
impl<T: Float> WeightExpand<Trivector<T>> for Bivector<T> {
type Output = Bivector<T>;
#[inline]
fn weight_expand(&self, rhs: &Trivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
-(rhs.ps() * self.rz()),
-(rhs.ps() * self.ry()),
-(rhs.ps() * self.rx()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightExpand<Trivector<T>> for Unit<Bivector<T>> {
type Output = Bivector<T>;
#[inline]
fn weight_expand(&self, rhs: &Trivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
-(rhs.ps() * self.as_inner().rz()),
-(rhs.ps() * self.as_inner().ry()),
-(rhs.ps() * self.as_inner().rx()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightExpand<Unit<Trivector<T>>> for Bivector<T> {
type Output = Bivector<T>;
#[inline]
fn weight_expand(&self, rhs: &Unit<Trivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
-(rhs.as_inner().ps() * self.rz()),
-(rhs.as_inner().ps() * self.ry()),
-(rhs.as_inner().ps() * self.rx()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightExpand<Unit<Trivector<T>>> for Unit<Bivector<T>> {
type Output = Bivector<T>;
#[inline]
fn weight_expand(&self, rhs: &Unit<Trivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
-(rhs.as_inner().ps() * self.as_inner().rz()),
-(rhs.as_inner().ps() * self.as_inner().ry()),
-(rhs.as_inner().ps() * self.as_inner().rx()),
)
}
}
#[doc = "Weight expansion of [`Scalar`] with [`Bivector`].\n\nThe weight expansion is the dual of weight contraction, extracting the\ndegenerate/ideal component of the exterior product complement."]
impl<T: Float> WeightExpand<Bivector<T>> for Scalar<T> {
type Output = Vector<T>;
#[inline]
fn weight_expand(&self, rhs: &Bivector<T>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.rx() * self.s()),
rhs.ry() * self.s(),
-(rhs.rz() * self.s()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightExpand<Bivector<T>> for Unit<Scalar<T>> {
type Output = Vector<T>;
#[inline]
fn weight_expand(&self, rhs: &Bivector<T>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.rx() * self.as_inner().s()),
rhs.ry() * self.as_inner().s(),
-(rhs.rz() * self.as_inner().s()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightExpand<Unit<Bivector<T>>> for Scalar<T> {
type Output = Vector<T>;
#[inline]
fn weight_expand(&self, rhs: &Unit<Bivector<T>>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.as_inner().rx() * self.s()),
rhs.as_inner().ry() * self.s(),
-(rhs.as_inner().rz() * self.s()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightExpand<Unit<Bivector<T>>> for Unit<Scalar<T>> {
type Output = Vector<T>;
#[inline]
fn weight_expand(&self, rhs: &Unit<Bivector<T>>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.as_inner().rx() * self.as_inner().s()),
rhs.as_inner().ry() * self.as_inner().s(),
-(rhs.as_inner().rz() * self.as_inner().s()),
)
}
}
#[doc = "Weight expansion of [`Scalar`] with [`Scalar`].\n\nThe weight expansion is the dual of weight contraction, extracting the\ndegenerate/ideal component of the exterior product complement."]
impl<T: Float> WeightExpand<Scalar<T>> for Scalar<T> {
type Output = Trivector<T>;
#[inline]
fn weight_expand(&self, rhs: &Scalar<T>) -> Trivector<T> {
Trivector::new_unchecked(-(rhs.s() * self.s()))
}
}
#[allow(unused_variables)]
impl<T: Float> WeightExpand<Scalar<T>> for Unit<Scalar<T>> {
type Output = Trivector<T>;
#[inline]
fn weight_expand(&self, rhs: &Scalar<T>) -> Trivector<T> {
Trivector::new_unchecked(-(rhs.s() * self.as_inner().s()))
}
}
#[allow(unused_variables)]
impl<T: Float> WeightExpand<Unit<Scalar<T>>> for Scalar<T> {
type Output = Trivector<T>;
#[inline]
fn weight_expand(&self, rhs: &Unit<Scalar<T>>) -> Trivector<T> {
Trivector::new_unchecked(-(rhs.as_inner().s() * self.s()))
}
}
#[allow(unused_variables)]
impl<T: Float> WeightExpand<Unit<Scalar<T>>> for Unit<Scalar<T>> {
type Output = Trivector<T>;
#[inline]
fn weight_expand(&self, rhs: &Unit<Scalar<T>>) -> Trivector<T> {
Trivector::new_unchecked(-(rhs.as_inner().s() * self.as_inner().s()))
}
}
#[doc = "Weight expansion of [`Scalar`] with [`Trivector`].\n\nThe weight expansion is the dual of weight contraction, extracting the\ndegenerate/ideal component of the exterior product complement."]
impl<T: Float> WeightExpand<Trivector<T>> for Scalar<T> {
type Output = Scalar<T>;
#[inline]
fn weight_expand(&self, rhs: &Trivector<T>) -> Scalar<T> {
Scalar::new_unchecked(-(rhs.ps() * self.s()))
}
}
#[allow(unused_variables)]
impl<T: Float> WeightExpand<Trivector<T>> for Unit<Scalar<T>> {
type Output = Scalar<T>;
#[inline]
fn weight_expand(&self, rhs: &Trivector<T>) -> Scalar<T> {
Scalar::new_unchecked(-(rhs.ps() * self.as_inner().s()))
}
}
#[allow(unused_variables)]
impl<T: Float> WeightExpand<Unit<Trivector<T>>> for Scalar<T> {
type Output = Scalar<T>;
#[inline]
fn weight_expand(&self, rhs: &Unit<Trivector<T>>) -> Scalar<T> {
Scalar::new_unchecked(-(rhs.as_inner().ps() * self.s()))
}
}
#[allow(unused_variables)]
impl<T: Float> WeightExpand<Unit<Trivector<T>>> for Unit<Scalar<T>> {
type Output = Scalar<T>;
#[inline]
fn weight_expand(&self, rhs: &Unit<Trivector<T>>) -> Scalar<T> {
Scalar::new_unchecked(-(rhs.as_inner().ps() * self.as_inner().s()))
}
}
#[doc = "Weight expansion of [`Scalar`] with [`Vector`].\n\nThe weight expansion is the dual of weight contraction, extracting the\ndegenerate/ideal component of the exterior product complement."]
impl<T: Float> WeightExpand<Vector<T>> for Scalar<T> {
type Output = Bivector<T>;
#[inline]
fn weight_expand(&self, rhs: &Vector<T>) -> Bivector<T> {
Bivector::new_unchecked(
-(rhs.z() * self.s()),
rhs.y() * self.s(),
-(rhs.x() * self.s()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightExpand<Vector<T>> for Unit<Scalar<T>> {
type Output = Bivector<T>;
#[inline]
fn weight_expand(&self, rhs: &Vector<T>) -> Bivector<T> {
Bivector::new_unchecked(
-(rhs.z() * self.as_inner().s()),
rhs.y() * self.as_inner().s(),
-(rhs.x() * self.as_inner().s()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightExpand<Unit<Vector<T>>> for Scalar<T> {
type Output = Bivector<T>;
#[inline]
fn weight_expand(&self, rhs: &Unit<Vector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
-(rhs.as_inner().z() * self.s()),
rhs.as_inner().y() * self.s(),
-(rhs.as_inner().x() * self.s()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightExpand<Unit<Vector<T>>> for Unit<Scalar<T>> {
type Output = Bivector<T>;
#[inline]
fn weight_expand(&self, rhs: &Unit<Vector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
-(rhs.as_inner().z() * self.as_inner().s()),
rhs.as_inner().y() * self.as_inner().s(),
-(rhs.as_inner().x() * self.as_inner().s()),
)
}
}
#[doc = "Weight expansion of [`Trivector`] with [`Trivector`].\n\nThe weight expansion is the dual of weight contraction, extracting the\ndegenerate/ideal component of the exterior product complement."]
impl<T: Float> WeightExpand<Trivector<T>> for Trivector<T> {
type Output = Trivector<T>;
#[inline]
fn weight_expand(&self, rhs: &Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(-(rhs.ps() * self.ps()))
}
}
#[allow(unused_variables)]
impl<T: Float> WeightExpand<Trivector<T>> for Unit<Trivector<T>> {
type Output = Trivector<T>;
#[inline]
fn weight_expand(&self, rhs: &Trivector<T>) -> Trivector<T> {
Trivector::new_unchecked(-(rhs.ps() * self.as_inner().ps()))
}
}
#[allow(unused_variables)]
impl<T: Float> WeightExpand<Unit<Trivector<T>>> for Trivector<T> {
type Output = Trivector<T>;
#[inline]
fn weight_expand(&self, rhs: &Unit<Trivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(-(rhs.as_inner().ps() * self.ps()))
}
}
#[allow(unused_variables)]
impl<T: Float> WeightExpand<Unit<Trivector<T>>> for Unit<Trivector<T>> {
type Output = Trivector<T>;
#[inline]
fn weight_expand(&self, rhs: &Unit<Trivector<T>>) -> Trivector<T> {
Trivector::new_unchecked(-(rhs.as_inner().ps() * self.as_inner().ps()))
}
}
#[doc = "Weight expansion of [`Vector`] with [`Bivector`].\n\nThe weight expansion is the dual of weight contraction, extracting the\ndegenerate/ideal component of the exterior product complement."]
impl<T: Float> WeightExpand<Bivector<T>> for Vector<T> {
type Output = Bivector<T>;
#[inline]
fn weight_expand(&self, rhs: &Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.rx() * self.y() + rhs.ry() * self.x(),
-(rhs.rz() * self.x()) + rhs.rx() * self.z(),
-(rhs.ry() * self.z()) + -(rhs.rz() * self.y()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightExpand<Bivector<T>> for Unit<Vector<T>> {
type Output = Bivector<T>;
#[inline]
fn weight_expand(&self, rhs: &Bivector<T>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.rx() * self.as_inner().y() + rhs.ry() * self.as_inner().x(),
-(rhs.rz() * self.as_inner().x()) + rhs.rx() * self.as_inner().z(),
-(rhs.ry() * self.as_inner().z()) + -(rhs.rz() * self.as_inner().y()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightExpand<Unit<Bivector<T>>> for Vector<T> {
type Output = Bivector<T>;
#[inline]
fn weight_expand(&self, rhs: &Unit<Bivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.as_inner().rx() * self.y() + rhs.as_inner().ry() * self.x(),
-(rhs.as_inner().rz() * self.x()) + rhs.as_inner().rx() * self.z(),
-(rhs.as_inner().ry() * self.z()) + -(rhs.as_inner().rz() * self.y()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightExpand<Unit<Bivector<T>>> for Unit<Vector<T>> {
type Output = Bivector<T>;
#[inline]
fn weight_expand(&self, rhs: &Unit<Bivector<T>>) -> Bivector<T> {
Bivector::new_unchecked(
rhs.as_inner().rx() * self.as_inner().y() + rhs.as_inner().ry() * self.as_inner().x(),
-(rhs.as_inner().rz() * self.as_inner().x())
+ rhs.as_inner().rx() * self.as_inner().z(),
-(rhs.as_inner().ry() * self.as_inner().z())
+ -(rhs.as_inner().rz() * self.as_inner().y()),
)
}
}
#[doc = "Weight expansion of [`Vector`] with [`Trivector`].\n\nThe weight expansion is the dual of weight contraction, extracting the\ndegenerate/ideal component of the exterior product complement."]
impl<T: Float> WeightExpand<Trivector<T>> for Vector<T> {
type Output = Vector<T>;
#[inline]
fn weight_expand(&self, rhs: &Trivector<T>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.ps() * self.x()),
-(rhs.ps() * self.y()),
-(rhs.ps() * self.z()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightExpand<Trivector<T>> for Unit<Vector<T>> {
type Output = Vector<T>;
#[inline]
fn weight_expand(&self, rhs: &Trivector<T>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.ps() * self.as_inner().x()),
-(rhs.ps() * self.as_inner().y()),
-(rhs.ps() * self.as_inner().z()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightExpand<Unit<Trivector<T>>> for Vector<T> {
type Output = Vector<T>;
#[inline]
fn weight_expand(&self, rhs: &Unit<Trivector<T>>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.as_inner().ps() * self.x()),
-(rhs.as_inner().ps() * self.y()),
-(rhs.as_inner().ps() * self.z()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightExpand<Unit<Trivector<T>>> for Unit<Vector<T>> {
type Output = Vector<T>;
#[inline]
fn weight_expand(&self, rhs: &Unit<Trivector<T>>) -> Vector<T> {
Vector::new_unchecked(
-(rhs.as_inner().ps() * self.as_inner().x()),
-(rhs.as_inner().ps() * self.as_inner().y()),
-(rhs.as_inner().ps() * self.as_inner().z()),
)
}
}
#[doc = "Weight expansion of [`Vector`] with [`Vector`].\n\nThe weight expansion is the dual of weight contraction, extracting the\ndegenerate/ideal component of the exterior product complement."]
impl<T: Float> WeightExpand<Vector<T>> for Vector<T> {
type Output = Trivector<T>;
#[inline]
fn weight_expand(&self, rhs: &Vector<T>) -> Trivector<T> {
Trivector::new_unchecked(
-(rhs.x() * self.x()) + -(rhs.y() * self.y()) + -(rhs.z() * self.z()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightExpand<Vector<T>> for Unit<Vector<T>> {
type Output = Trivector<T>;
#[inline]
fn weight_expand(&self, rhs: &Vector<T>) -> Trivector<T> {
Trivector::new_unchecked(
-(rhs.x() * self.as_inner().x())
+ -(rhs.y() * self.as_inner().y())
+ -(rhs.z() * self.as_inner().z()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightExpand<Unit<Vector<T>>> for Vector<T> {
type Output = Trivector<T>;
#[inline]
fn weight_expand(&self, rhs: &Unit<Vector<T>>) -> Trivector<T> {
Trivector::new_unchecked(
-(rhs.as_inner().x() * self.x())
+ -(rhs.as_inner().y() * self.y())
+ -(rhs.as_inner().z() * self.z()),
)
}
}
#[allow(unused_variables)]
impl<T: Float> WeightExpand<Unit<Vector<T>>> for Unit<Vector<T>> {
type Output = Trivector<T>;
#[inline]
fn weight_expand(&self, rhs: &Unit<Vector<T>>) -> Trivector<T> {
Trivector::new_unchecked(
-(rhs.as_inner().x() * self.as_inner().x())
+ -(rhs.as_inner().y() * self.as_inner().y())
+ -(rhs.as_inner().z() * self.as_inner().z()),
)
}
}
impl<T: Float> Dot<Bivector<T>> for Bivector<T> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Bivector<T>) -> T {
-(self.rz() * rhs.rz()) - self.ry() * rhs.ry() - self.rx() * rhs.rx()
}
}
#[allow(unused_variables)]
impl<T: Float> Dot<Bivector<T>> for Unit<Bivector<T>> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Bivector<T>) -> T {
-(rhs.rx() * self.as_inner().rx())
+ -(rhs.ry() * self.as_inner().ry())
+ -(rhs.rz() * self.as_inner().rz())
}
}
#[allow(unused_variables)]
impl<T: Float> Dot<Unit<Bivector<T>>> for Bivector<T> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Unit<Bivector<T>>) -> T {
-(rhs.as_inner().rx() * self.rx())
+ -(rhs.as_inner().ry() * self.ry())
+ -(rhs.as_inner().rz() * self.rz())
}
}
#[allow(unused_variables)]
impl<T: Float> Dot<Unit<Bivector<T>>> for Unit<Bivector<T>> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Unit<Bivector<T>>) -> T {
-(rhs.as_inner().rx() * self.as_inner().rx())
+ -(rhs.as_inner().ry() * self.as_inner().ry())
+ -(rhs.as_inner().rz() * self.as_inner().rz())
}
}
impl<T: Float> Dot<Rotor<T>> for Bivector<T> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Rotor<T>) -> T {
-(self.rz() * rhs.rz()) - self.ry() * rhs.ry() - self.rx() * rhs.rx()
}
}
#[allow(unused_variables)]
impl<T: Float> Dot<Rotor<T>> for Unit<Bivector<T>> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Rotor<T>) -> T {
-(rhs.rx() * self.as_inner().rx())
+ -(rhs.ry() * self.as_inner().ry())
+ -(rhs.rz() * self.as_inner().rz())
}
}
#[allow(unused_variables)]
impl<T: Float> Dot<Unit<Rotor<T>>> for Bivector<T> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Unit<Rotor<T>>) -> T {
-(rhs.as_inner().rx() * self.rx())
+ -(rhs.as_inner().ry() * self.ry())
+ -(rhs.as_inner().rz() * self.rz())
}
}
#[allow(unused_variables)]
impl<T: Float> Dot<Unit<Rotor<T>>> for Unit<Bivector<T>> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Unit<Rotor<T>>) -> T {
-(rhs.as_inner().rx() * self.as_inner().rx())
+ -(rhs.as_inner().ry() * self.as_inner().ry())
+ -(rhs.as_inner().rz() * self.as_inner().rz())
}
}
impl<T: Float> Dot<Bivector<T>> for Rotor<T> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Bivector<T>) -> T {
-(self.rz() * rhs.rz()) - self.ry() * rhs.ry() - self.rx() * rhs.rx()
}
}
#[allow(unused_variables)]
impl<T: Float> Dot<Bivector<T>> for Unit<Rotor<T>> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Bivector<T>) -> T {
-(rhs.rx() * self.as_inner().rx())
+ -(rhs.ry() * self.as_inner().ry())
+ -(rhs.rz() * self.as_inner().rz())
}
}
#[allow(unused_variables)]
impl<T: Float> Dot<Unit<Bivector<T>>> for Rotor<T> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Unit<Bivector<T>>) -> T {
-(rhs.as_inner().rx() * self.rx())
+ -(rhs.as_inner().ry() * self.ry())
+ -(rhs.as_inner().rz() * self.rz())
}
}
#[allow(unused_variables)]
impl<T: Float> Dot<Unit<Bivector<T>>> for Unit<Rotor<T>> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Unit<Bivector<T>>) -> T {
-(rhs.as_inner().rx() * self.as_inner().rx())
+ -(rhs.as_inner().ry() * self.as_inner().ry())
+ -(rhs.as_inner().rz() * self.as_inner().rz())
}
}
impl<T: Float> Dot<Rotor<T>> for Rotor<T> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Rotor<T>) -> T {
self.s() * rhs.s() - self.rz() * rhs.rz() - self.ry() * rhs.ry() - self.rx() * rhs.rx()
}
}
#[allow(unused_variables)]
impl<T: Float> Dot<Rotor<T>> for Unit<Rotor<T>> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Rotor<T>) -> T {
-(rhs.rx() * self.as_inner().rx())
+ -(rhs.ry() * self.as_inner().ry())
+ -(rhs.rz() * self.as_inner().rz())
+ rhs.s() * self.as_inner().s()
}
}
#[allow(unused_variables)]
impl<T: Float> Dot<Unit<Rotor<T>>> for Rotor<T> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Unit<Rotor<T>>) -> T {
-(rhs.as_inner().rx() * self.rx())
+ -(rhs.as_inner().ry() * self.ry())
+ -(rhs.as_inner().rz() * self.rz())
+ rhs.as_inner().s() * self.s()
}
}
#[allow(unused_variables)]
impl<T: Float> Dot<Unit<Rotor<T>>> for Unit<Rotor<T>> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Unit<Rotor<T>>) -> T {
-(rhs.as_inner().rx() * self.as_inner().rx())
+ -(rhs.as_inner().ry() * self.as_inner().ry())
+ -(rhs.as_inner().rz() * self.as_inner().rz())
+ rhs.as_inner().s() * self.as_inner().s()
}
}
impl<T: Float> Dot<Scalar<T>> for Rotor<T> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Scalar<T>) -> T {
self.s() * rhs.s()
}
}
#[allow(unused_variables)]
impl<T: Float> Dot<Scalar<T>> for Unit<Rotor<T>> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Scalar<T>) -> T {
rhs.s() * self.as_inner().s()
}
}
#[allow(unused_variables)]
impl<T: Float> Dot<Unit<Scalar<T>>> for Rotor<T> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Unit<Scalar<T>>) -> T {
rhs.as_inner().s() * self.s()
}
}
#[allow(unused_variables)]
impl<T: Float> Dot<Unit<Scalar<T>>> for Unit<Rotor<T>> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Unit<Scalar<T>>) -> T {
rhs.as_inner().s() * self.as_inner().s()
}
}
impl<T: Float> Dot<Rotor<T>> for Scalar<T> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Rotor<T>) -> T {
self.s() * rhs.s()
}
}
#[allow(unused_variables)]
impl<T: Float> Dot<Rotor<T>> for Unit<Scalar<T>> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Rotor<T>) -> T {
rhs.s() * self.as_inner().s()
}
}
#[allow(unused_variables)]
impl<T: Float> Dot<Unit<Rotor<T>>> for Scalar<T> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Unit<Rotor<T>>) -> T {
rhs.as_inner().s() * self.s()
}
}
#[allow(unused_variables)]
impl<T: Float> Dot<Unit<Rotor<T>>> for Unit<Scalar<T>> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Unit<Rotor<T>>) -> T {
rhs.as_inner().s() * self.as_inner().s()
}
}
impl<T: Float> Dot<Scalar<T>> for Scalar<T> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Scalar<T>) -> T {
self.s() * rhs.s()
}
}
#[allow(unused_variables)]
impl<T: Float> Dot<Scalar<T>> for Unit<Scalar<T>> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Scalar<T>) -> T {
rhs.s() * self.as_inner().s()
}
}
#[allow(unused_variables)]
impl<T: Float> Dot<Unit<Scalar<T>>> for Scalar<T> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Unit<Scalar<T>>) -> T {
rhs.as_inner().s() * self.s()
}
}
#[allow(unused_variables)]
impl<T: Float> Dot<Unit<Scalar<T>>> for Unit<Scalar<T>> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Unit<Scalar<T>>) -> T {
rhs.as_inner().s() * self.as_inner().s()
}
}
impl<T: Float> Dot<Trivector<T>> for Trivector<T> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Trivector<T>) -> T {
-(self.ps() * rhs.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> Dot<Trivector<T>> for Unit<Trivector<T>> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Trivector<T>) -> T {
-(rhs.ps() * self.as_inner().ps())
}
}
#[allow(unused_variables)]
impl<T: Float> Dot<Unit<Trivector<T>>> for Trivector<T> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Unit<Trivector<T>>) -> T {
-(rhs.as_inner().ps() * self.ps())
}
}
#[allow(unused_variables)]
impl<T: Float> Dot<Unit<Trivector<T>>> for Unit<Trivector<T>> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Unit<Trivector<T>>) -> T {
-(rhs.as_inner().ps() * self.as_inner().ps())
}
}
impl<T: Float> Dot<Vector<T>> for Vector<T> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Vector<T>) -> T {
self.x() * rhs.x() + self.y() * rhs.y() + self.z() * rhs.z()
}
}
#[allow(unused_variables)]
impl<T: Float> Dot<Vector<T>> for Unit<Vector<T>> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Vector<T>) -> T {
rhs.x() * self.as_inner().x()
+ rhs.y() * self.as_inner().y()
+ rhs.z() * self.as_inner().z()
}
}
#[allow(unused_variables)]
impl<T: Float> Dot<Unit<Vector<T>>> for Vector<T> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Unit<Vector<T>>) -> T {
rhs.as_inner().x() * self.x()
+ rhs.as_inner().y() * self.y()
+ rhs.as_inner().z() * self.z()
}
}
#[allow(unused_variables)]
impl<T: Float> Dot<Unit<Vector<T>>> for Unit<Vector<T>> {
type Scalar = T;
#[inline]
fn dot(&self, rhs: &Unit<Vector<T>>) -> T {
rhs.as_inner().x() * self.as_inner().x()
+ rhs.as_inner().y() * self.as_inner().y()
+ rhs.as_inner().z() * self.as_inner().z()
}
}
impl<T: Float> Antidot<Bivector<T>> for Bivector<T> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Bivector<T>) -> T {
self.rz() * rhs.rz() + self.ry() * rhs.ry() + self.rx() * rhs.rx()
}
}
#[allow(unused_variables)]
impl<T: Float> Antidot<Bivector<T>> for Unit<Bivector<T>> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Bivector<T>) -> T {
rhs.rx() * self.as_inner().rx()
+ rhs.ry() * self.as_inner().ry()
+ rhs.rz() * self.as_inner().rz()
}
}
#[allow(unused_variables)]
impl<T: Float> Antidot<Unit<Bivector<T>>> for Bivector<T> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Unit<Bivector<T>>) -> T {
rhs.as_inner().rx() * self.rx()
+ rhs.as_inner().ry() * self.ry()
+ rhs.as_inner().rz() * self.rz()
}
}
#[allow(unused_variables)]
impl<T: Float> Antidot<Unit<Bivector<T>>> for Unit<Bivector<T>> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Unit<Bivector<T>>) -> T {
rhs.as_inner().rx() * self.as_inner().rx()
+ rhs.as_inner().ry() * self.as_inner().ry()
+ rhs.as_inner().rz() * self.as_inner().rz()
}
}
impl<T: Float> Antidot<Rotor<T>> for Bivector<T> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Rotor<T>) -> T {
self.rz() * rhs.rz() + self.ry() * rhs.ry() + self.rx() * rhs.rx()
}
}
#[allow(unused_variables)]
impl<T: Float> Antidot<Rotor<T>> for Unit<Bivector<T>> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Rotor<T>) -> T {
rhs.rx() * self.as_inner().rx()
+ rhs.ry() * self.as_inner().ry()
+ rhs.rz() * self.as_inner().rz()
}
}
#[allow(unused_variables)]
impl<T: Float> Antidot<Unit<Rotor<T>>> for Bivector<T> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Unit<Rotor<T>>) -> T {
rhs.as_inner().rx() * self.rx()
+ rhs.as_inner().ry() * self.ry()
+ rhs.as_inner().rz() * self.rz()
}
}
#[allow(unused_variables)]
impl<T: Float> Antidot<Unit<Rotor<T>>> for Unit<Bivector<T>> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Unit<Rotor<T>>) -> T {
rhs.as_inner().rx() * self.as_inner().rx()
+ rhs.as_inner().ry() * self.as_inner().ry()
+ rhs.as_inner().rz() * self.as_inner().rz()
}
}
impl<T: Float> Antidot<Bivector<T>> for Rotor<T> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Bivector<T>) -> T {
self.rz() * rhs.rz() + self.ry() * rhs.ry() + self.rx() * rhs.rx()
}
}
#[allow(unused_variables)]
impl<T: Float> Antidot<Bivector<T>> for Unit<Rotor<T>> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Bivector<T>) -> T {
rhs.rx() * self.as_inner().rx()
+ rhs.ry() * self.as_inner().ry()
+ rhs.rz() * self.as_inner().rz()
}
}
#[allow(unused_variables)]
impl<T: Float> Antidot<Unit<Bivector<T>>> for Rotor<T> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Unit<Bivector<T>>) -> T {
rhs.as_inner().rx() * self.rx()
+ rhs.as_inner().ry() * self.ry()
+ rhs.as_inner().rz() * self.rz()
}
}
#[allow(unused_variables)]
impl<T: Float> Antidot<Unit<Bivector<T>>> for Unit<Rotor<T>> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Unit<Bivector<T>>) -> T {
rhs.as_inner().rx() * self.as_inner().rx()
+ rhs.as_inner().ry() * self.as_inner().ry()
+ rhs.as_inner().rz() * self.as_inner().rz()
}
}
impl<T: Float> Antidot<Rotor<T>> for Rotor<T> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Rotor<T>) -> T {
-(self.s() * rhs.s()) + self.rz() * rhs.rz() + self.ry() * rhs.ry() + self.rx() * rhs.rx()
}
}
#[allow(unused_variables)]
impl<T: Float> Antidot<Rotor<T>> for Unit<Rotor<T>> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Rotor<T>) -> T {
-(rhs.s() * self.as_inner().s())
+ rhs.rx() * self.as_inner().rx()
+ rhs.ry() * self.as_inner().ry()
+ rhs.rz() * self.as_inner().rz()
}
}
#[allow(unused_variables)]
impl<T: Float> Antidot<Unit<Rotor<T>>> for Rotor<T> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Unit<Rotor<T>>) -> T {
-(rhs.as_inner().s() * self.s())
+ rhs.as_inner().rx() * self.rx()
+ rhs.as_inner().ry() * self.ry()
+ rhs.as_inner().rz() * self.rz()
}
}
#[allow(unused_variables)]
impl<T: Float> Antidot<Unit<Rotor<T>>> for Unit<Rotor<T>> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Unit<Rotor<T>>) -> T {
-(rhs.as_inner().s() * self.as_inner().s())
+ rhs.as_inner().rx() * self.as_inner().rx()
+ rhs.as_inner().ry() * self.as_inner().ry()
+ rhs.as_inner().rz() * self.as_inner().rz()
}
}
impl<T: Float> Antidot<Scalar<T>> for Rotor<T> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Scalar<T>) -> T {
-(self.s() * rhs.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Antidot<Scalar<T>> for Unit<Rotor<T>> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Scalar<T>) -> T {
-(rhs.s() * self.as_inner().s())
}
}
#[allow(unused_variables)]
impl<T: Float> Antidot<Unit<Scalar<T>>> for Rotor<T> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Unit<Scalar<T>>) -> T {
-(rhs.as_inner().s() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Antidot<Unit<Scalar<T>>> for Unit<Rotor<T>> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Unit<Scalar<T>>) -> T {
-(rhs.as_inner().s() * self.as_inner().s())
}
}
impl<T: Float> Antidot<Rotor<T>> for Scalar<T> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Rotor<T>) -> T {
-(self.s() * rhs.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Antidot<Rotor<T>> for Unit<Scalar<T>> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Rotor<T>) -> T {
-(rhs.s() * self.as_inner().s())
}
}
#[allow(unused_variables)]
impl<T: Float> Antidot<Unit<Rotor<T>>> for Scalar<T> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Unit<Rotor<T>>) -> T {
-(rhs.as_inner().s() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Antidot<Unit<Rotor<T>>> for Unit<Scalar<T>> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Unit<Rotor<T>>) -> T {
-(rhs.as_inner().s() * self.as_inner().s())
}
}
impl<T: Float> Antidot<Scalar<T>> for Scalar<T> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Scalar<T>) -> T {
-(self.s() * rhs.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Antidot<Scalar<T>> for Unit<Scalar<T>> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Scalar<T>) -> T {
-(rhs.s() * self.as_inner().s())
}
}
#[allow(unused_variables)]
impl<T: Float> Antidot<Unit<Scalar<T>>> for Scalar<T> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Unit<Scalar<T>>) -> T {
-(rhs.as_inner().s() * self.s())
}
}
#[allow(unused_variables)]
impl<T: Float> Antidot<Unit<Scalar<T>>> for Unit<Scalar<T>> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Unit<Scalar<T>>) -> T {
-(rhs.as_inner().s() * self.as_inner().s())
}
}
impl<T: Float> Antidot<Trivector<T>> for Trivector<T> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Trivector<T>) -> T {
self.ps() * rhs.ps()
}
}
#[allow(unused_variables)]
impl<T: Float> Antidot<Trivector<T>> for Unit<Trivector<T>> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Trivector<T>) -> T {
rhs.ps() * self.as_inner().ps()
}
}
#[allow(unused_variables)]
impl<T: Float> Antidot<Unit<Trivector<T>>> for Trivector<T> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Unit<Trivector<T>>) -> T {
rhs.as_inner().ps() * self.ps()
}
}
#[allow(unused_variables)]
impl<T: Float> Antidot<Unit<Trivector<T>>> for Unit<Trivector<T>> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Unit<Trivector<T>>) -> T {
rhs.as_inner().ps() * self.as_inner().ps()
}
}
impl<T: Float> Antidot<Vector<T>> for Vector<T> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Vector<T>) -> T {
-(self.x() * rhs.x()) - self.y() * rhs.y() - self.z() * rhs.z()
}
}
#[allow(unused_variables)]
impl<T: Float> Antidot<Vector<T>> for Unit<Vector<T>> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Vector<T>) -> T {
-(rhs.x() * self.as_inner().x())
+ -(rhs.y() * self.as_inner().y())
+ -(rhs.z() * self.as_inner().z())
}
}
#[allow(unused_variables)]
impl<T: Float> Antidot<Unit<Vector<T>>> for Vector<T> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Unit<Vector<T>>) -> T {
-(rhs.as_inner().x() * self.x())
+ -(rhs.as_inner().y() * self.y())
+ -(rhs.as_inner().z() * self.z())
}
}
#[allow(unused_variables)]
impl<T: Float> Antidot<Unit<Vector<T>>> for Unit<Vector<T>> {
type Scalar = T;
#[inline]
fn antidot(&self, rhs: &Unit<Vector<T>>) -> T {
-(rhs.as_inner().x() * self.as_inner().x())
+ -(rhs.as_inner().y() * self.as_inner().y())
+ -(rhs.as_inner().z() * self.as_inner().z())
}
}
impl<T: Float> Reverse for Bivector<T> {
#[inline]
fn reverse(&self) -> Self {
Self::new_unchecked(-self.rz(), -self.ry(), -self.rx())
}
}
impl<T: Float> Reverse for Rotor<T> {
#[inline]
fn reverse(&self) -> Self {
Self::new_unchecked(self.s(), -self.rz(), -self.ry(), -self.rx())
}
}
impl<T: Float> Reverse for Scalar<T> {
#[inline]
fn reverse(&self) -> Self {
Self::new_unchecked(self.s())
}
}
impl<T: Float> Reverse for Trivector<T> {
#[inline]
fn reverse(&self) -> Self {
Self::new_unchecked(-self.ps())
}
}
impl<T: Float> Reverse for Vector<T> {
#[inline]
fn reverse(&self) -> Self {
Self::new_unchecked(self.x(), self.y(), self.z())
}
}
impl<T: Float> Antireverse for Bivector<T> {
#[inline]
fn antireverse(&self) -> Self {
Self::new_unchecked(self.rz(), self.ry(), self.rx())
}
}
impl<T: Float> Antireverse for Rotor<T> {
#[inline]
fn antireverse(&self) -> Self {
Self::new_unchecked(-self.s(), self.rz(), self.ry(), self.rx())
}
}
impl<T: Float> Antireverse for Scalar<T> {
#[inline]
fn antireverse(&self) -> Self {
Self::new_unchecked(-self.s())
}
}
impl<T: Float> Antireverse for Trivector<T> {
#[inline]
fn antireverse(&self) -> Self {
Self::new_unchecked(self.ps())
}
}
impl<T: Float> Antireverse for Vector<T> {
#[inline]
fn antireverse(&self) -> Self {
Self::new_unchecked(-self.x(), -self.y(), -self.z())
}
}
impl<T: Float> Involute for Bivector<T> {
#[inline]
fn involute(&self) -> Self {
Self::new_unchecked(-self.rz(), -self.ry(), -self.rx())
}
}
impl<T: Float> Involute for Rotor<T> {
#[inline]
fn involute(&self) -> Self {
Self::new_unchecked(self.s(), -self.rz(), -self.ry(), -self.rx())
}
}
impl<T: Float> Involute for Scalar<T> {
#[inline]
fn involute(&self) -> Self {
Self::new_unchecked(self.s())
}
}
impl<T: Float> Involute for Trivector<T> {
#[inline]
fn involute(&self) -> Self {
Self::new_unchecked(-self.ps())
}
}
impl<T: Float> Involute for Vector<T> {
#[inline]
fn involute(&self) -> Self {
Self::new_unchecked(self.x(), self.y(), self.z())
}
}
impl<T: Float> RightComplement for Bivector<T> {
type Output = Vector<T>;
#[inline]
fn right_complement(&self) -> Vector<T> {
Vector::new_unchecked(self.rx(), -self.ry(), self.rz())
}
}
impl<T: Float> RightComplement for Scalar<T> {
type Output = Trivector<T>;
#[inline]
fn right_complement(&self) -> Trivector<T> {
Trivector::new_unchecked(self.s())
}
}
impl<T: Float> RightComplement for Trivector<T> {
type Output = Scalar<T>;
#[inline]
fn right_complement(&self) -> Scalar<T> {
Scalar::new_unchecked(self.ps())
}
}
impl<T: Float> RightComplement for Vector<T> {
type Output = Bivector<T>;
#[inline]
fn right_complement(&self) -> Bivector<T> {
Bivector::new_unchecked(self.z(), -self.y(), self.x())
}
}
impl<T: Float> WeightDual for Bivector<T> {
type Output = Vector<T>;
#[inline]
fn weight_dual(&self) -> Vector<T> {
Vector::new_unchecked(-self.rx(), self.ry(), -self.rz())
}
}
impl<T: Float> WeightDual for Scalar<T> {
type Output = Trivector<T>;
#[inline]
fn weight_dual(&self) -> Trivector<T> {
Trivector::new_unchecked(-self.s())
}
}
impl<T: Float> WeightDual for Trivector<T> {
type Output = Scalar<T>;
#[inline]
fn weight_dual(&self) -> Scalar<T> {
Scalar::new_unchecked(-self.ps())
}
}
impl<T: Float> WeightDual for Vector<T> {
type Output = Bivector<T>;
#[inline]
fn weight_dual(&self) -> Bivector<T> {
Bivector::new_unchecked(-self.z(), self.y(), -self.x())
}
}
impl<T: Float> VersorInverse for Bivector<T> {
fn try_inverse(&self) -> Option<Self> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Self::new_unchecked(
-self.rz() * inv_norm_sq,
-self.ry() * inv_norm_sq,
-self.rx() * inv_norm_sq,
))
}
}
impl<T: Float> VersorInverse for Rotor<T> {
fn try_inverse(&self) -> Option<Self> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Self::new_unchecked(
self.s() * inv_norm_sq,
-self.rz() * inv_norm_sq,
-self.ry() * inv_norm_sq,
-self.rx() * inv_norm_sq,
))
}
}
impl<T: Float> VersorInverse for Scalar<T> {
fn try_inverse(&self) -> Option<Self> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Self::new_unchecked(self.s() * inv_norm_sq))
}
}
impl<T: Float> VersorInverse for Trivector<T> {
fn try_inverse(&self) -> Option<Self> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Self::new_unchecked(-self.ps() * inv_norm_sq))
}
}
impl<T: Float> VersorInverse for Vector<T> {
fn try_inverse(&self) -> Option<Self> {
let norm_sq = <Self as crate::norm::Normed>::norm_squared(self);
if norm_sq.abs() < T::epsilon() {
return None;
}
let inv_norm_sq = T::one() / norm_sq;
Some(Self::new_unchecked(
self.x() * inv_norm_sq,
self.y() * inv_norm_sq,
self.z() * inv_norm_sq,
))
}
}
impl<T: Float> crate::norm::Normed for Bivector<T> {
type Scalar = T;
#[inline]
fn norm_squared(&self) -> T {
self.rz() * self.rz() + self.ry() * self.ry() + self.rx() * self.rx()
}
fn try_normalize(&self) -> Option<Self> {
let n = self.norm();
if n < T::epsilon() {
None
} else {
Some(self.scale(T::one() / n))
}
}
#[inline]
fn scale(&self, factor: T) -> Self {
Self::new_unchecked(self.rz() * factor, self.ry() * factor, self.rx() * factor)
}
}
impl<T: Float> crate::norm::Normed for Rotor<T> {
type Scalar = T;
#[inline]
fn norm_squared(&self) -> T {
self.s() * self.s() + self.rz() * self.rz() + self.ry() * self.ry() + self.rx() * self.rx()
}
fn try_normalize(&self) -> Option<Self> {
let n = self.norm();
if n < T::epsilon() {
None
} else {
Some(self.scale(T::one() / n))
}
}
#[inline]
fn scale(&self, factor: T) -> Self {
Self::new_unchecked(
self.s() * factor,
self.rz() * factor,
self.ry() * factor,
self.rx() * factor,
)
}
}
impl<T: Float> crate::norm::Normed for Scalar<T> {
type Scalar = T;
#[inline]
fn norm_squared(&self) -> T {
self.s() * self.s()
}
fn try_normalize(&self) -> Option<Self> {
let n = self.norm();
if n < T::epsilon() {
None
} else {
Some(self.scale(T::one() / n))
}
}
#[inline]
fn scale(&self, factor: T) -> Self {
Self::new_unchecked(self.s() * factor)
}
}
impl<T: Float> crate::norm::Normed for Trivector<T> {
type Scalar = T;
#[inline]
fn norm_squared(&self) -> T {
self.ps() * self.ps()
}
fn try_normalize(&self) -> Option<Self> {
let n = self.norm();
if n < T::epsilon() {
None
} else {
Some(self.scale(T::one() / n))
}
}
#[inline]
fn scale(&self, factor: T) -> Self {
Self::new_unchecked(self.ps() * factor)
}
}
impl<T: Float> crate::norm::Normed for Vector<T> {
type Scalar = T;
#[inline]
fn norm_squared(&self) -> T {
self.x() * self.x() + self.y() * self.y() + self.z() * self.z()
}
fn try_normalize(&self) -> Option<Self> {
let n = self.norm();
if n < T::epsilon() {
None
} else {
Some(self.scale(T::one() / n))
}
}
#[inline]
fn scale(&self, factor: T) -> Self {
Self::new_unchecked(self.x() * factor, self.y() * factor, self.z() * factor)
}
}
impl<T: Float + AbsDiffEq<Epsilon = T>> AbsDiffEq for Bivector<T> {
type Epsilon = T;
fn default_epsilon() -> Self::Epsilon {
T::default_epsilon()
}
fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
self.rz().abs_diff_eq(&other.rz(), epsilon)
&& self.ry().abs_diff_eq(&other.ry(), epsilon)
&& self.rx().abs_diff_eq(&other.rx(), epsilon)
}
}
impl<T: Float + RelativeEq<Epsilon = T>> RelativeEq for Bivector<T> {
fn default_max_relative() -> Self::Epsilon {
T::default_max_relative()
}
fn relative_eq(
&self,
other: &Self,
epsilon: Self::Epsilon,
max_relative: Self::Epsilon,
) -> bool {
self.rz().relative_eq(&other.rz(), epsilon, max_relative)
&& self.ry().relative_eq(&other.ry(), epsilon, max_relative)
&& self.rx().relative_eq(&other.rx(), epsilon, max_relative)
}
}
impl<T: Float + UlpsEq<Epsilon = T>> UlpsEq for Bivector<T> {
fn default_max_ulps() -> u32 {
T::default_max_ulps()
}
fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
self.rz().ulps_eq(&other.rz(), epsilon, max_ulps)
&& self.ry().ulps_eq(&other.ry(), epsilon, max_ulps)
&& self.rx().ulps_eq(&other.rx(), epsilon, max_ulps)
}
}
impl<T: Float + AbsDiffEq<Epsilon = T>> AbsDiffEq for Rotor<T> {
type Epsilon = T;
fn default_epsilon() -> Self::Epsilon {
T::default_epsilon()
}
fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
self.s().abs_diff_eq(&other.s(), epsilon)
&& self.rz().abs_diff_eq(&other.rz(), epsilon)
&& self.ry().abs_diff_eq(&other.ry(), epsilon)
&& self.rx().abs_diff_eq(&other.rx(), epsilon)
}
}
impl<T: Float + RelativeEq<Epsilon = T>> RelativeEq for Rotor<T> {
fn default_max_relative() -> Self::Epsilon {
T::default_max_relative()
}
fn relative_eq(
&self,
other: &Self,
epsilon: Self::Epsilon,
max_relative: Self::Epsilon,
) -> bool {
self.s().relative_eq(&other.s(), epsilon, max_relative)
&& self.rz().relative_eq(&other.rz(), epsilon, max_relative)
&& self.ry().relative_eq(&other.ry(), epsilon, max_relative)
&& self.rx().relative_eq(&other.rx(), epsilon, max_relative)
}
}
impl<T: Float + UlpsEq<Epsilon = T>> UlpsEq for Rotor<T> {
fn default_max_ulps() -> u32 {
T::default_max_ulps()
}
fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
self.s().ulps_eq(&other.s(), epsilon, max_ulps)
&& self.rz().ulps_eq(&other.rz(), epsilon, max_ulps)
&& self.ry().ulps_eq(&other.ry(), epsilon, max_ulps)
&& self.rx().ulps_eq(&other.rx(), epsilon, max_ulps)
}
}
impl<T: Float + AbsDiffEq<Epsilon = T>> AbsDiffEq for Scalar<T> {
type Epsilon = T;
fn default_epsilon() -> Self::Epsilon {
T::default_epsilon()
}
fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
self.s().abs_diff_eq(&other.s(), epsilon)
}
}
impl<T: Float + RelativeEq<Epsilon = T>> RelativeEq for Scalar<T> {
fn default_max_relative() -> Self::Epsilon {
T::default_max_relative()
}
fn relative_eq(
&self,
other: &Self,
epsilon: Self::Epsilon,
max_relative: Self::Epsilon,
) -> bool {
self.s().relative_eq(&other.s(), epsilon, max_relative)
}
}
impl<T: Float + UlpsEq<Epsilon = T>> UlpsEq for Scalar<T> {
fn default_max_ulps() -> u32 {
T::default_max_ulps()
}
fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
self.s().ulps_eq(&other.s(), epsilon, max_ulps)
}
}
impl<T: Float + AbsDiffEq<Epsilon = T>> AbsDiffEq for Trivector<T> {
type Epsilon = T;
fn default_epsilon() -> Self::Epsilon {
T::default_epsilon()
}
fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
self.ps().abs_diff_eq(&other.ps(), epsilon)
}
}
impl<T: Float + RelativeEq<Epsilon = T>> RelativeEq for Trivector<T> {
fn default_max_relative() -> Self::Epsilon {
T::default_max_relative()
}
fn relative_eq(
&self,
other: &Self,
epsilon: Self::Epsilon,
max_relative: Self::Epsilon,
) -> bool {
self.ps().relative_eq(&other.ps(), epsilon, max_relative)
}
}
impl<T: Float + UlpsEq<Epsilon = T>> UlpsEq for Trivector<T> {
fn default_max_ulps() -> u32 {
T::default_max_ulps()
}
fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
self.ps().ulps_eq(&other.ps(), epsilon, max_ulps)
}
}
impl<T: Float + AbsDiffEq<Epsilon = T>> AbsDiffEq for Vector<T> {
type Epsilon = T;
fn default_epsilon() -> Self::Epsilon {
T::default_epsilon()
}
fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
self.x().abs_diff_eq(&other.x(), epsilon)
&& self.y().abs_diff_eq(&other.y(), epsilon)
&& self.z().abs_diff_eq(&other.z(), epsilon)
}
}
impl<T: Float + RelativeEq<Epsilon = T>> RelativeEq for Vector<T> {
fn default_max_relative() -> Self::Epsilon {
T::default_max_relative()
}
fn relative_eq(
&self,
other: &Self,
epsilon: Self::Epsilon,
max_relative: Self::Epsilon,
) -> bool {
self.x().relative_eq(&other.x(), epsilon, max_relative)
&& self.y().relative_eq(&other.y(), epsilon, max_relative)
&& self.z().relative_eq(&other.z(), epsilon, max_relative)
}
}
impl<T: Float + UlpsEq<Epsilon = T>> UlpsEq for Vector<T> {
fn default_max_ulps() -> u32 {
T::default_max_ulps()
}
fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
self.x().ulps_eq(&other.x(), epsilon, max_ulps)
&& self.y().ulps_eq(&other.y(), epsilon, max_ulps)
&& self.z().ulps_eq(&other.z(), epsilon, max_ulps)
}
}
#[cfg(any(test, feature = "proptest-support"))]
#[allow(clippy::missing_docs_in_private_items)]
mod arbitrary_impls {
use super::*;
use proptest::prelude::*;
use proptest::strategy::BoxedStrategy;
use std::fmt::Debug;
impl<T: Float + Debug + 'static> Arbitrary for Bivector<T> {
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
(-100.0f64..100.0, -100.0f64..100.0, -100.0f64..100.0)
.prop_map(|(x0, x1, x2)| {
Bivector::new_unchecked(T::from_f64(x0), T::from_f64(x1), T::from_f64(x2))
})
.boxed()
}
}
impl<T: Float + Debug + 'static> Arbitrary for Rotor<T> {
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
(
-100.0f64..100.0,
-100.0f64..100.0,
-100.0f64..100.0,
-100.0f64..100.0,
)
.prop_map(|(x0, x1, x2, x3)| {
Rotor::new_unchecked(
T::from_f64(x0),
T::from_f64(x1),
T::from_f64(x2),
T::from_f64(x3),
)
})
.boxed()
}
}
impl<T: Float + Debug + 'static> Arbitrary for Scalar<T> {
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
(-100.0f64..100.0)
.prop_map(|x0| Scalar::new_unchecked(T::from_f64(x0)))
.boxed()
}
}
impl<T: Float + Debug + 'static> Arbitrary for Trivector<T> {
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
(-100.0f64..100.0)
.prop_map(|x0| Trivector::new_unchecked(T::from_f64(x0)))
.boxed()
}
}
impl<T: Float + Debug + 'static> Arbitrary for Vector<T> {
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
(-100.0f64..100.0, -100.0f64..100.0, -100.0f64..100.0)
.prop_map(|(x0, x1, x2)| {
Vector::new_unchecked(T::from_f64(x0), T::from_f64(x1), T::from_f64(x2))
})
.boxed()
}
}
}
#[cfg(test)]
#[allow(clippy::missing_docs_in_private_items)]
mod verification_tests {
use super::*;
use crate::algebra::Multivector;
#[allow(unused_imports)]
use crate::norm::{DegenerateNormed, Normed};
use crate::signature::Euclidean3;
#[allow(unused_imports)]
use crate::wrappers::Unit;
use approx::relative_eq;
use proptest::prelude::*;
const REL_EPSILON: f64 = 1e-10;
proptest! {
#[test]
fn bivector_add_matches_multivector(a in any::<Bivector<f64>>(), b in any::<Bivector<f64>>()) {
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result = a + b;
let generic_result = mv_a + mv_b;
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Add mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
#[test]
fn bivector_sub_matches_multivector(a in any::<Bivector<f64>>(), b in any::<Bivector<f64>>()) {
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result = a - b;
let generic_result = mv_a - mv_b;
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Sub mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
#[test]
fn bivector_neg_matches_multivector(a in any::<Bivector<f64>>()) {
let mv_a: Multivector<f64, Euclidean3> = a.into();
let specialized_result = -a;
let generic_result = -mv_a;
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Neg mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn rotor_add_matches_multivector(a in any::<Rotor<f64>>(), b in any::<Rotor<f64>>()) {
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result = a + b;
let generic_result = mv_a + mv_b;
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Add mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
#[test]
fn rotor_sub_matches_multivector(a in any::<Rotor<f64>>(), b in any::<Rotor<f64>>()) {
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result = a - b;
let generic_result = mv_a - mv_b;
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Sub mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
#[test]
fn rotor_neg_matches_multivector(a in any::<Rotor<f64>>()) {
let mv_a: Multivector<f64, Euclidean3> = a.into();
let specialized_result = -a;
let generic_result = -mv_a;
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Neg mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn scalar_add_matches_multivector(a in any::<Scalar<f64>>(), b in any::<Scalar<f64>>()) {
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result = a + b;
let generic_result = mv_a + mv_b;
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Add mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
#[test]
fn scalar_sub_matches_multivector(a in any::<Scalar<f64>>(), b in any::<Scalar<f64>>()) {
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result = a - b;
let generic_result = mv_a - mv_b;
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Sub mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
#[test]
fn scalar_neg_matches_multivector(a in any::<Scalar<f64>>()) {
let mv_a: Multivector<f64, Euclidean3> = a.into();
let specialized_result = -a;
let generic_result = -mv_a;
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Neg mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn trivector_add_matches_multivector(a in any::<Trivector<f64>>(), b in any::<Trivector<f64>>()) {
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result = a + b;
let generic_result = mv_a + mv_b;
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Add mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
#[test]
fn trivector_sub_matches_multivector(a in any::<Trivector<f64>>(), b in any::<Trivector<f64>>()) {
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result = a - b;
let generic_result = mv_a - mv_b;
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Sub mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
#[test]
fn trivector_neg_matches_multivector(a in any::<Trivector<f64>>()) {
let mv_a: Multivector<f64, Euclidean3> = a.into();
let specialized_result = -a;
let generic_result = -mv_a;
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Neg mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn vector_add_matches_multivector(a in any::<Vector<f64>>(), b in any::<Vector<f64>>()) {
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result = a + b;
let generic_result = mv_a + mv_b;
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Add mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
#[test]
fn vector_sub_matches_multivector(a in any::<Vector<f64>>(), b in any::<Vector<f64>>()) {
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result = a - b;
let generic_result = mv_a - mv_b;
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Sub mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
#[test]
fn vector_neg_matches_multivector(a in any::<Vector<f64>>()) {
let mv_a: Multivector<f64, Euclidean3> = a.into();
let specialized_result = -a;
let generic_result = -mv_a;
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Neg mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn wedge_bivector_scalar_bivector_matches_multivector(a in any::<Bivector<f64>>(), b in any::<Scalar<f64>>()) {
use crate::ops::Wedge;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Bivector<f64> = a.wedge(&b);
let generic_result = mv_a.exterior(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Wedge product mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn wedge_bivector_vector_trivector_matches_multivector(a in any::<Bivector<f64>>(), b in any::<Vector<f64>>()) {
use crate::ops::Wedge;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Trivector<f64> = a.wedge(&b);
let generic_result = mv_a.exterior(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Wedge product mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn wedge_scalar_bivector_bivector_matches_multivector(a in any::<Scalar<f64>>(), b in any::<Bivector<f64>>()) {
use crate::ops::Wedge;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Bivector<f64> = a.wedge(&b);
let generic_result = mv_a.exterior(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Wedge product mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn wedge_scalar_scalar_scalar_matches_multivector(a in any::<Scalar<f64>>(), b in any::<Scalar<f64>>()) {
use crate::ops::Wedge;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Scalar<f64> = a.wedge(&b);
let generic_result = mv_a.exterior(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Wedge product mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn wedge_scalar_trivector_trivector_matches_multivector(a in any::<Scalar<f64>>(), b in any::<Trivector<f64>>()) {
use crate::ops::Wedge;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Trivector<f64> = a.wedge(&b);
let generic_result = mv_a.exterior(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Wedge product mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn wedge_scalar_vector_vector_matches_multivector(a in any::<Scalar<f64>>(), b in any::<Vector<f64>>()) {
use crate::ops::Wedge;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Vector<f64> = a.wedge(&b);
let generic_result = mv_a.exterior(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Wedge product mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn wedge_trivector_scalar_trivector_matches_multivector(a in any::<Trivector<f64>>(), b in any::<Scalar<f64>>()) {
use crate::ops::Wedge;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Trivector<f64> = a.wedge(&b);
let generic_result = mv_a.exterior(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Wedge product mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn wedge_vector_bivector_trivector_matches_multivector(a in any::<Vector<f64>>(), b in any::<Bivector<f64>>()) {
use crate::ops::Wedge;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Trivector<f64> = a.wedge(&b);
let generic_result = mv_a.exterior(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Wedge product mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn wedge_vector_scalar_vector_matches_multivector(a in any::<Vector<f64>>(), b in any::<Scalar<f64>>()) {
use crate::ops::Wedge;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Vector<f64> = a.wedge(&b);
let generic_result = mv_a.exterior(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Wedge product mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn wedge_vector_vector_bivector_matches_multivector(a in any::<Vector<f64>>(), b in any::<Vector<f64>>()) {
use crate::ops::Wedge;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Bivector<f64> = a.wedge(&b);
let generic_result = mv_a.exterior(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Wedge product mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn bulk_contraction_bivector_bivector_scalar_matches_multivector(a in any::<Bivector<f64>>(), b in any::<Bivector<f64>>()) {
use crate::ops::BulkContract;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Scalar<f64> = a.bulk_contract(&b);
let generic_result = mv_a.bulk_contraction(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Bulk contraction mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn bulk_contraction_bivector_scalar_bivector_matches_multivector(a in any::<Bivector<f64>>(), b in any::<Scalar<f64>>()) {
use crate::ops::BulkContract;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Bivector<f64> = a.bulk_contract(&b);
let generic_result = mv_a.bulk_contraction(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Bulk contraction mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn bulk_contraction_bivector_vector_vector_matches_multivector(a in any::<Bivector<f64>>(), b in any::<Vector<f64>>()) {
use crate::ops::BulkContract;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Vector<f64> = a.bulk_contract(&b);
let generic_result = mv_a.bulk_contraction(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Bulk contraction mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn bulk_contraction_scalar_scalar_scalar_matches_multivector(a in any::<Scalar<f64>>(), b in any::<Scalar<f64>>()) {
use crate::ops::BulkContract;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Scalar<f64> = a.bulk_contract(&b);
let generic_result = mv_a.bulk_contraction(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Bulk contraction mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn bulk_contraction_trivector_bivector_vector_matches_multivector(a in any::<Trivector<f64>>(), b in any::<Bivector<f64>>()) {
use crate::ops::BulkContract;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Vector<f64> = a.bulk_contract(&b);
let generic_result = mv_a.bulk_contraction(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Bulk contraction mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn bulk_contraction_trivector_scalar_trivector_matches_multivector(a in any::<Trivector<f64>>(), b in any::<Scalar<f64>>()) {
use crate::ops::BulkContract;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Trivector<f64> = a.bulk_contract(&b);
let generic_result = mv_a.bulk_contraction(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Bulk contraction mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn bulk_contraction_trivector_trivector_scalar_matches_multivector(a in any::<Trivector<f64>>(), b in any::<Trivector<f64>>()) {
use crate::ops::BulkContract;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Scalar<f64> = a.bulk_contract(&b);
let generic_result = mv_a.bulk_contraction(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Bulk contraction mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn bulk_contraction_trivector_vector_bivector_matches_multivector(a in any::<Trivector<f64>>(), b in any::<Vector<f64>>()) {
use crate::ops::BulkContract;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Bivector<f64> = a.bulk_contract(&b);
let generic_result = mv_a.bulk_contraction(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Bulk contraction mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn bulk_contraction_vector_scalar_vector_matches_multivector(a in any::<Vector<f64>>(), b in any::<Scalar<f64>>()) {
use crate::ops::BulkContract;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Vector<f64> = a.bulk_contract(&b);
let generic_result = mv_a.bulk_contraction(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Bulk contraction mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn bulk_contraction_vector_vector_scalar_matches_multivector(a in any::<Vector<f64>>(), b in any::<Vector<f64>>()) {
use crate::ops::BulkContract;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Scalar<f64> = a.bulk_contract(&b);
let generic_result = mv_a.bulk_contraction(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Bulk contraction mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn weight_contraction_bivector_bivector_scalar_matches_multivector(a in any::<Bivector<f64>>(), b in any::<Bivector<f64>>()) {
use crate::ops::WeightContract;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Scalar<f64> = a.weight_contract(&b);
let generic_result = mv_a.weight_contraction(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Weight contraction mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn weight_contraction_bivector_scalar_bivector_matches_multivector(a in any::<Bivector<f64>>(), b in any::<Scalar<f64>>()) {
use crate::ops::WeightContract;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Bivector<f64> = a.weight_contract(&b);
let generic_result = mv_a.weight_contraction(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Weight contraction mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn weight_contraction_bivector_vector_vector_matches_multivector(a in any::<Bivector<f64>>(), b in any::<Vector<f64>>()) {
use crate::ops::WeightContract;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Vector<f64> = a.weight_contract(&b);
let generic_result = mv_a.weight_contraction(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Weight contraction mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn weight_contraction_scalar_scalar_scalar_matches_multivector(a in any::<Scalar<f64>>(), b in any::<Scalar<f64>>()) {
use crate::ops::WeightContract;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Scalar<f64> = a.weight_contract(&b);
let generic_result = mv_a.weight_contraction(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Weight contraction mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn weight_contraction_trivector_bivector_vector_matches_multivector(a in any::<Trivector<f64>>(), b in any::<Bivector<f64>>()) {
use crate::ops::WeightContract;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Vector<f64> = a.weight_contract(&b);
let generic_result = mv_a.weight_contraction(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Weight contraction mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn weight_contraction_trivector_scalar_trivector_matches_multivector(a in any::<Trivector<f64>>(), b in any::<Scalar<f64>>()) {
use crate::ops::WeightContract;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Trivector<f64> = a.weight_contract(&b);
let generic_result = mv_a.weight_contraction(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Weight contraction mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn weight_contraction_trivector_trivector_scalar_matches_multivector(a in any::<Trivector<f64>>(), b in any::<Trivector<f64>>()) {
use crate::ops::WeightContract;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Scalar<f64> = a.weight_contract(&b);
let generic_result = mv_a.weight_contraction(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Weight contraction mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn weight_contraction_trivector_vector_bivector_matches_multivector(a in any::<Trivector<f64>>(), b in any::<Vector<f64>>()) {
use crate::ops::WeightContract;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Bivector<f64> = a.weight_contract(&b);
let generic_result = mv_a.weight_contraction(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Weight contraction mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn weight_contraction_vector_scalar_vector_matches_multivector(a in any::<Vector<f64>>(), b in any::<Scalar<f64>>()) {
use crate::ops::WeightContract;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Vector<f64> = a.weight_contract(&b);
let generic_result = mv_a.weight_contraction(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Weight contraction mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn weight_contraction_vector_vector_scalar_matches_multivector(a in any::<Vector<f64>>(), b in any::<Vector<f64>>()) {
use crate::ops::WeightContract;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Scalar<f64> = a.weight_contract(&b);
let generic_result = mv_a.weight_contraction(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Weight contraction mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn bulk_expansion_bivector_bivector_trivector_matches_multivector(a in any::<Bivector<f64>>(), b in any::<Bivector<f64>>()) {
use crate::ops::BulkExpand;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Trivector<f64> = a.bulk_expand(&b);
let generic_result = mv_a.bulk_expansion(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Bulk expansion mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn bulk_expansion_bivector_trivector_bivector_matches_multivector(a in any::<Bivector<f64>>(), b in any::<Trivector<f64>>()) {
use crate::ops::BulkExpand;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Bivector<f64> = a.bulk_expand(&b);
let generic_result = mv_a.bulk_expansion(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Bulk expansion mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn bulk_expansion_scalar_bivector_vector_matches_multivector(a in any::<Scalar<f64>>(), b in any::<Bivector<f64>>()) {
use crate::ops::BulkExpand;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Vector<f64> = a.bulk_expand(&b);
let generic_result = mv_a.bulk_expansion(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Bulk expansion mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn bulk_expansion_scalar_scalar_trivector_matches_multivector(a in any::<Scalar<f64>>(), b in any::<Scalar<f64>>()) {
use crate::ops::BulkExpand;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Trivector<f64> = a.bulk_expand(&b);
let generic_result = mv_a.bulk_expansion(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Bulk expansion mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn bulk_expansion_scalar_trivector_scalar_matches_multivector(a in any::<Scalar<f64>>(), b in any::<Trivector<f64>>()) {
use crate::ops::BulkExpand;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Scalar<f64> = a.bulk_expand(&b);
let generic_result = mv_a.bulk_expansion(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Bulk expansion mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn bulk_expansion_scalar_vector_bivector_matches_multivector(a in any::<Scalar<f64>>(), b in any::<Vector<f64>>()) {
use crate::ops::BulkExpand;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Bivector<f64> = a.bulk_expand(&b);
let generic_result = mv_a.bulk_expansion(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Bulk expansion mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn bulk_expansion_trivector_trivector_trivector_matches_multivector(a in any::<Trivector<f64>>(), b in any::<Trivector<f64>>()) {
use crate::ops::BulkExpand;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Trivector<f64> = a.bulk_expand(&b);
let generic_result = mv_a.bulk_expansion(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Bulk expansion mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn bulk_expansion_vector_bivector_bivector_matches_multivector(a in any::<Vector<f64>>(), b in any::<Bivector<f64>>()) {
use crate::ops::BulkExpand;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Bivector<f64> = a.bulk_expand(&b);
let generic_result = mv_a.bulk_expansion(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Bulk expansion mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn bulk_expansion_vector_trivector_vector_matches_multivector(a in any::<Vector<f64>>(), b in any::<Trivector<f64>>()) {
use crate::ops::BulkExpand;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Vector<f64> = a.bulk_expand(&b);
let generic_result = mv_a.bulk_expansion(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Bulk expansion mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn bulk_expansion_vector_vector_trivector_matches_multivector(a in any::<Vector<f64>>(), b in any::<Vector<f64>>()) {
use crate::ops::BulkExpand;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Trivector<f64> = a.bulk_expand(&b);
let generic_result = mv_a.bulk_expansion(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Bulk expansion mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn weight_expansion_bivector_bivector_trivector_matches_multivector(a in any::<Bivector<f64>>(), b in any::<Bivector<f64>>()) {
use crate::ops::WeightExpand;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Trivector<f64> = a.weight_expand(&b);
let generic_result = mv_a.weight_expansion(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Weight expansion mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn weight_expansion_bivector_trivector_bivector_matches_multivector(a in any::<Bivector<f64>>(), b in any::<Trivector<f64>>()) {
use crate::ops::WeightExpand;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Bivector<f64> = a.weight_expand(&b);
let generic_result = mv_a.weight_expansion(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Weight expansion mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn weight_expansion_scalar_bivector_vector_matches_multivector(a in any::<Scalar<f64>>(), b in any::<Bivector<f64>>()) {
use crate::ops::WeightExpand;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Vector<f64> = a.weight_expand(&b);
let generic_result = mv_a.weight_expansion(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Weight expansion mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn weight_expansion_scalar_scalar_trivector_matches_multivector(a in any::<Scalar<f64>>(), b in any::<Scalar<f64>>()) {
use crate::ops::WeightExpand;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Trivector<f64> = a.weight_expand(&b);
let generic_result = mv_a.weight_expansion(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Weight expansion mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn weight_expansion_scalar_trivector_scalar_matches_multivector(a in any::<Scalar<f64>>(), b in any::<Trivector<f64>>()) {
use crate::ops::WeightExpand;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Scalar<f64> = a.weight_expand(&b);
let generic_result = mv_a.weight_expansion(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Weight expansion mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn weight_expansion_scalar_vector_bivector_matches_multivector(a in any::<Scalar<f64>>(), b in any::<Vector<f64>>()) {
use crate::ops::WeightExpand;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Bivector<f64> = a.weight_expand(&b);
let generic_result = mv_a.weight_expansion(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Weight expansion mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn weight_expansion_trivector_trivector_trivector_matches_multivector(a in any::<Trivector<f64>>(), b in any::<Trivector<f64>>()) {
use crate::ops::WeightExpand;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Trivector<f64> = a.weight_expand(&b);
let generic_result = mv_a.weight_expansion(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Weight expansion mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn weight_expansion_vector_bivector_bivector_matches_multivector(a in any::<Vector<f64>>(), b in any::<Bivector<f64>>()) {
use crate::ops::WeightExpand;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Bivector<f64> = a.weight_expand(&b);
let generic_result = mv_a.weight_expansion(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Weight expansion mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn weight_expansion_vector_trivector_vector_matches_multivector(a in any::<Vector<f64>>(), b in any::<Trivector<f64>>()) {
use crate::ops::WeightExpand;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Vector<f64> = a.weight_expand(&b);
let generic_result = mv_a.weight_expansion(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Weight expansion mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn weight_expansion_vector_vector_trivector_matches_multivector(a in any::<Vector<f64>>(), b in any::<Vector<f64>>()) {
use crate::ops::WeightExpand;
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let specialized_result: Trivector<f64> = a.weight_expand(&b);
let generic_result = mv_a.weight_expansion(&mv_b);
let specialized_mv: Multivector<f64, Euclidean3> = specialized_result.into();
prop_assert!(
relative_eq!(specialized_mv, generic_result, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Weight expansion mismatch: specialized={:?}, generic={:?}",
specialized_mv, generic_result
);
}
}
proptest! {
#[test]
fn de_morgan_geometric_bivector(a in any::<Bivector<f64>>(), b in any::<Bivector<f64>>()) {
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let lhs = (mv_a * mv_b).complement();
let rhs = mv_a.complement().antiproduct(&mv_b.complement());
prop_assert!(
relative_eq!(lhs, rhs, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"De Morgan (geometric) failed: complement(a*b)={:?}, complement(a)⋇complement(b)={:?}",
lhs, rhs
);
}
#[test]
fn de_morgan_antiproduct_bivector(a in any::<Bivector<f64>>(), b in any::<Bivector<f64>>()) {
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let lhs = mv_a.antiproduct(&mv_b).complement();
let rhs = mv_a.complement() * mv_b.complement();
prop_assert!(
relative_eq!(lhs, rhs, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"De Morgan (antiproduct) failed: complement(a⋇b)={:?}, complement(a)*complement(b)={:?}",
lhs, rhs
);
}
}
proptest! {
#[test]
fn de_morgan_geometric_scalar(a in any::<Scalar<f64>>(), b in any::<Scalar<f64>>()) {
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let lhs = (mv_a * mv_b).complement();
let rhs = mv_a.complement().antiproduct(&mv_b.complement());
prop_assert!(
relative_eq!(lhs, rhs, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"De Morgan (geometric) failed: complement(a*b)={:?}, complement(a)⋇complement(b)={:?}",
lhs, rhs
);
}
#[test]
fn de_morgan_antiproduct_scalar(a in any::<Scalar<f64>>(), b in any::<Scalar<f64>>()) {
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let lhs = mv_a.antiproduct(&mv_b).complement();
let rhs = mv_a.complement() * mv_b.complement();
prop_assert!(
relative_eq!(lhs, rhs, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"De Morgan (antiproduct) failed: complement(a⋇b)={:?}, complement(a)*complement(b)={:?}",
lhs, rhs
);
}
}
proptest! {
#[test]
fn de_morgan_geometric_trivector(a in any::<Trivector<f64>>(), b in any::<Trivector<f64>>()) {
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let lhs = (mv_a * mv_b).complement();
let rhs = mv_a.complement().antiproduct(&mv_b.complement());
prop_assert!(
relative_eq!(lhs, rhs, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"De Morgan (geometric) failed: complement(a*b)={:?}, complement(a)⋇complement(b)={:?}",
lhs, rhs
);
}
#[test]
fn de_morgan_antiproduct_trivector(a in any::<Trivector<f64>>(), b in any::<Trivector<f64>>()) {
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let lhs = mv_a.antiproduct(&mv_b).complement();
let rhs = mv_a.complement() * mv_b.complement();
prop_assert!(
relative_eq!(lhs, rhs, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"De Morgan (antiproduct) failed: complement(a⋇b)={:?}, complement(a)*complement(b)={:?}",
lhs, rhs
);
}
}
proptest! {
#[test]
fn de_morgan_geometric_vector(a in any::<Vector<f64>>(), b in any::<Vector<f64>>()) {
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let lhs = (mv_a * mv_b).complement();
let rhs = mv_a.complement().antiproduct(&mv_b.complement());
prop_assert!(
relative_eq!(lhs, rhs, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"De Morgan (geometric) failed: complement(a*b)={:?}, complement(a)⋇complement(b)={:?}",
lhs, rhs
);
}
#[test]
fn de_morgan_antiproduct_vector(a in any::<Vector<f64>>(), b in any::<Vector<f64>>()) {
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = b.into();
let lhs = mv_a.antiproduct(&mv_b).complement();
let rhs = mv_a.complement() * mv_b.complement();
prop_assert!(
relative_eq!(lhs, rhs, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"De Morgan (antiproduct) failed: complement(a⋇b)={:?}, complement(a)*complement(b)={:?}",
lhs, rhs
);
}
}
proptest! {
#[test]
fn project_idempotent_bivector_vector(a in any::<Bivector<f64>>(), unit_b in any::<Unit<Vector<f64>>>()) {
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = unit_b.into_inner().into();
let first = mv_a.project(&mv_b);
let second = first.project(&mv_b);
prop_assert!(
relative_eq!(first, second, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Project idempotency failed: first={:?}, second={:?}",
first, second
);
}
}
proptest! {
#[test]
fn project_idempotent_trivector_bivector(a in any::<Trivector<f64>>(), unit_b in any::<Unit<Bivector<f64>>>()) {
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = unit_b.into_inner().into();
let first = mv_a.project(&mv_b);
let second = first.project(&mv_b);
prop_assert!(
relative_eq!(first, second, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Project idempotency failed: first={:?}, second={:?}",
first, second
);
}
}
proptest! {
#[test]
fn project_idempotent_trivector_vector(a in any::<Trivector<f64>>(), unit_b in any::<Unit<Vector<f64>>>()) {
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = unit_b.into_inner().into();
let first = mv_a.project(&mv_b);
let second = first.project(&mv_b);
prop_assert!(
relative_eq!(first, second, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Project idempotency failed: first={:?}, second={:?}",
first, second
);
}
}
proptest! {
#[test]
fn antiproject_idempotent_bivector_trivector(a in any::<Bivector<f64>>(), unit_b in any::<Unit<Trivector<f64>>>()) {
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = unit_b.into_inner().into();
let first = mv_a.antiproject(&mv_b);
let second = first.antiproject(&mv_b);
prop_assert!(
relative_eq!(first, second, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Antiproject idempotency failed: first={:?}, second={:?}",
first, second
);
}
}
proptest! {
#[test]
fn antiproject_idempotent_vector_bivector(a in any::<Vector<f64>>(), unit_b in any::<Unit<Bivector<f64>>>()) {
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = unit_b.into_inner().into();
let first = mv_a.antiproject(&mv_b);
let second = first.antiproject(&mv_b);
prop_assert!(
relative_eq!(first, second, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Antiproject idempotency failed: first={:?}, second={:?}",
first, second
);
}
}
proptest! {
#[test]
fn antiproject_idempotent_vector_trivector(a in any::<Vector<f64>>(), unit_b in any::<Unit<Trivector<f64>>>()) {
let mv_a: Multivector<f64, Euclidean3> = a.into();
let mv_b: Multivector<f64, Euclidean3> = unit_b.into_inner().into();
let first = mv_a.antiproject(&mv_b);
let second = first.antiproject(&mv_b);
prop_assert!(
relative_eq!(first, second, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Antiproject idempotency failed: first={:?}, second={:?}",
first, second
);
}
}
proptest! {
#[test]
fn unit_bivector_norm_matches_inner(u in any::<Unit<Bivector<f64>>>()) {
let inner_norm = <Bivector<f64> as Normed>::norm(u.as_inner());
let wrapper_norm = <Unit<Bivector<f64>> as Normed>::norm(&u);
prop_assert!(
relative_eq!(inner_norm, 1.0, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Inner norm should be 1.0, got {}", inner_norm
);
prop_assert!(
relative_eq!(wrapper_norm, 1.0, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Wrapper norm should be 1.0, got {}", wrapper_norm
);
prop_assert!(
relative_eq!(inner_norm, wrapper_norm, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Norms should match: {} vs {}", inner_norm, wrapper_norm
);
}
#[test]
fn unit_bivector_norm_squared_matches_inner(u in any::<Unit<Bivector<f64>>>()) {
let inner_ns = <Bivector<f64> as Normed>::norm_squared(u.as_inner());
let wrapper_ns = <Unit<Bivector<f64>> as Normed>::norm_squared(&u);
prop_assert!(
relative_eq!(inner_ns, 1.0, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Inner norm_squared should be 1.0, got {}", inner_ns
);
prop_assert!(
relative_eq!(wrapper_ns, 1.0, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Wrapper norm_squared should be 1.0, got {}", wrapper_ns
);
}
}
proptest! {
#[test]
fn unit_rotor_norm_matches_inner(u in any::<Unit<Rotor<f64>>>()) {
let inner_norm = <Rotor<f64> as Normed>::norm(u.as_inner());
let wrapper_norm = <Unit<Rotor<f64>> as Normed>::norm(&u);
prop_assert!(
relative_eq!(inner_norm, 1.0, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Inner norm should be 1.0, got {}", inner_norm
);
prop_assert!(
relative_eq!(wrapper_norm, 1.0, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Wrapper norm should be 1.0, got {}", wrapper_norm
);
prop_assert!(
relative_eq!(inner_norm, wrapper_norm, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Norms should match: {} vs {}", inner_norm, wrapper_norm
);
}
#[test]
fn unit_rotor_norm_squared_matches_inner(u in any::<Unit<Rotor<f64>>>()) {
let inner_ns = <Rotor<f64> as Normed>::norm_squared(u.as_inner());
let wrapper_ns = <Unit<Rotor<f64>> as Normed>::norm_squared(&u);
prop_assert!(
relative_eq!(inner_ns, 1.0, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Inner norm_squared should be 1.0, got {}", inner_ns
);
prop_assert!(
relative_eq!(wrapper_ns, 1.0, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Wrapper norm_squared should be 1.0, got {}", wrapper_ns
);
}
}
proptest! {
#[test]
fn unit_scalar_norm_matches_inner(u in any::<Unit<Scalar<f64>>>()) {
let inner_norm = <Scalar<f64> as Normed>::norm(u.as_inner());
let wrapper_norm = <Unit<Scalar<f64>> as Normed>::norm(&u);
prop_assert!(
relative_eq!(inner_norm, 1.0, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Inner norm should be 1.0, got {}", inner_norm
);
prop_assert!(
relative_eq!(wrapper_norm, 1.0, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Wrapper norm should be 1.0, got {}", wrapper_norm
);
prop_assert!(
relative_eq!(inner_norm, wrapper_norm, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Norms should match: {} vs {}", inner_norm, wrapper_norm
);
}
#[test]
fn unit_scalar_norm_squared_matches_inner(u in any::<Unit<Scalar<f64>>>()) {
let inner_ns = <Scalar<f64> as Normed>::norm_squared(u.as_inner());
let wrapper_ns = <Unit<Scalar<f64>> as Normed>::norm_squared(&u);
prop_assert!(
relative_eq!(inner_ns, 1.0, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Inner norm_squared should be 1.0, got {}", inner_ns
);
prop_assert!(
relative_eq!(wrapper_ns, 1.0, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Wrapper norm_squared should be 1.0, got {}", wrapper_ns
);
}
}
proptest! {
#[test]
fn unit_trivector_norm_matches_inner(u in any::<Unit<Trivector<f64>>>()) {
let inner_norm = <Trivector<f64> as Normed>::norm(u.as_inner());
let wrapper_norm = <Unit<Trivector<f64>> as Normed>::norm(&u);
prop_assert!(
relative_eq!(inner_norm, 1.0, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Inner norm should be 1.0, got {}", inner_norm
);
prop_assert!(
relative_eq!(wrapper_norm, 1.0, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Wrapper norm should be 1.0, got {}", wrapper_norm
);
prop_assert!(
relative_eq!(inner_norm, wrapper_norm, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Norms should match: {} vs {}", inner_norm, wrapper_norm
);
}
#[test]
fn unit_trivector_norm_squared_matches_inner(u in any::<Unit<Trivector<f64>>>()) {
let inner_ns = <Trivector<f64> as Normed>::norm_squared(u.as_inner());
let wrapper_ns = <Unit<Trivector<f64>> as Normed>::norm_squared(&u);
prop_assert!(
relative_eq!(inner_ns, 1.0, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Inner norm_squared should be 1.0, got {}", inner_ns
);
prop_assert!(
relative_eq!(wrapper_ns, 1.0, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Wrapper norm_squared should be 1.0, got {}", wrapper_ns
);
}
}
proptest! {
#[test]
fn unit_vector_norm_matches_inner(u in any::<Unit<Vector<f64>>>()) {
let inner_norm = <Vector<f64> as Normed>::norm(u.as_inner());
let wrapper_norm = <Unit<Vector<f64>> as Normed>::norm(&u);
prop_assert!(
relative_eq!(inner_norm, 1.0, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Inner norm should be 1.0, got {}", inner_norm
);
prop_assert!(
relative_eq!(wrapper_norm, 1.0, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Wrapper norm should be 1.0, got {}", wrapper_norm
);
prop_assert!(
relative_eq!(inner_norm, wrapper_norm, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Norms should match: {} vs {}", inner_norm, wrapper_norm
);
}
#[test]
fn unit_vector_norm_squared_matches_inner(u in any::<Unit<Vector<f64>>>()) {
let inner_ns = <Vector<f64> as Normed>::norm_squared(u.as_inner());
let wrapper_ns = <Unit<Vector<f64>> as Normed>::norm_squared(&u);
prop_assert!(
relative_eq!(inner_ns, 1.0, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Inner norm_squared should be 1.0, got {}", inner_ns
);
prop_assert!(
relative_eq!(wrapper_ns, 1.0, epsilon = REL_EPSILON, max_relative = REL_EPSILON),
"Wrapper norm_squared should be 1.0, got {}", wrapper_ns
);
}
}
}