use core::ops::{Add, Div, Mul, Sub};
use num_traits::identities::{One, Zero};
#[derive(Debug, Copy, Clone, PartialEq, Hash, Default)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct Homogeneous<E, R> {
element: E,
rational: R,
}
impl<E, R> Homogeneous<E, R>
where
R: One,
{
pub fn new(element: E) -> Self {
Homogeneous {
element,
rational: R::one(),
}
}
}
impl<E, R> Homogeneous<E, R>
where
R: Zero,
{
pub fn infinity(direction: E) -> Self {
Homogeneous {
element: direction,
rational: R::zero(),
}
}
}
impl<E, R> Homogeneous<E, R>
where
R: Zero + PartialEq,
{
pub fn is_infinite(&self) -> bool {
self.rational == R::zero()
}
}
impl<E, R> Homogeneous<E, R>
where
E: Copy,
{
pub fn direction(&self) -> E {
self.element
}
}
impl<E, R> Homogeneous<E, R>
where
E: Mul<R, Output = E>,
R: Zero + Copy,
{
pub fn weighted(element: E, weight: R) -> Option<Self> {
if weight.is_zero() {
return None;
}
Some(Self::weighted_unchecked(element, weight))
}
pub fn weighted_or_infinite(element: E, weight: R) -> Self {
if weight.is_zero() {
return Self::infinity(element);
}
Self::weighted_unchecked(element, weight)
}
}
impl<E, R> Homogeneous<E, R>
where
E: Mul<R, Output = E>,
R: One + Zero + Copy,
{
pub fn weighted_or_one(element: E, weight: R) -> Self {
if weight.is_zero() {
return Self::new(element);
}
Self::weighted_unchecked(element, weight)
}
}
impl<E, R> Homogeneous<E, R>
where
E: Mul<R, Output = E>,
R: Copy,
{
pub fn weighted_unchecked(element: E, weight: R) -> Self {
Homogeneous {
element: element * weight,
rational: weight,
}
}
}
impl<E, R> Homogeneous<E, R>
where
E: Div<R, Output = E>,
{
pub fn project(self) -> E {
self.element / self.rational
}
}
impl<E, R> Add for Homogeneous<E, R>
where
E: Add<Output = E>,
R: Add<Output = R>,
{
type Output = Homogeneous<E, R>;
fn add(self, rhs: Homogeneous<E, R>) -> Self::Output {
Homogeneous {
element: self.element + rhs.element,
rational: self.rational + rhs.rational,
}
}
}
impl<E, R> Sub for Homogeneous<E, R>
where
E: Sub<Output = E>,
R: Sub<Output = R>,
{
type Output = Homogeneous<E, R>;
fn sub(self, rhs: Homogeneous<E, R>) -> Self::Output {
Homogeneous {
element: self.element - rhs.element,
rational: self.rational - rhs.rational,
}
}
}
impl<E, R> Mul for Homogeneous<E, R>
where
E: Mul<Output = E>,
R: Mul<Output = R>,
{
type Output = Homogeneous<E, R>;
fn mul(self, rhs: Homogeneous<E, R>) -> Self::Output {
Homogeneous {
element: self.element * rhs.element,
rational: self.rational * rhs.rational,
}
}
}
impl<E, R> Div for Homogeneous<E, R>
where
E: Div<Output = E>,
R: Div<Output = R>,
{
type Output = Homogeneous<E, R>;
fn div(self, rhs: Homogeneous<E, R>) -> Self::Output {
Homogeneous {
element: self.element / rhs.element,
rational: self.rational / rhs.rational,
}
}
}
impl<E, R> Mul<R> for Homogeneous<E, R>
where
E: Mul<R, Output = E>,
R: Mul<Output = R> + Copy,
{
type Output = Homogeneous<E, R>;
fn mul(self, rhs: R) -> Self::Output {
Homogeneous {
element: self.element * rhs,
rational: self.rational * rhs,
}
}
}
impl<E, R> Div<R> for Homogeneous<E, R>
where
E: Div<R, Output = E>,
R: Div<Output = R> + Copy,
{
type Output = Homogeneous<E, R>;
fn div(self, rhs: R) -> Self::Output {
Homogeneous {
element: self.element / rhs,
rational: self.rational / rhs,
}
}
}