use cgmath::*;
pub mod control_point {
use super::*;
use std::fmt::Debug;
use std::ops::*;
pub trait ControlPoint<S>:
Add<Self::Diff, Output = Self>
+ Sub<Self::Diff, Output = Self>
+ Sub<Self, Output = Self::Diff>
+ Mul<S, Output = Self>
+ Div<S, Output = Self>
+ AddAssign<Self::Diff>
+ SubAssign<Self::Diff>
+ MulAssign<S>
+ DivAssign<S>
+ Copy
+ Clone
+ Debug {
type Diff: Add<Self::Diff, Output = Self::Diff>
+ Sub<Self::Diff, Output = Self::Diff>
+ Mul<S, Output = Self::Diff>
+ Div<S, Output = Self::Diff>
+ AddAssign<Self::Diff>
+ SubAssign<Self::Diff>
+ MulAssign<S>
+ DivAssign<S>
+ Zero
+ Copy
+ Clone
+ Debug;
fn origin() -> Self;
fn to_vec(self) -> Self::Diff;
}
impl<S: BaseFloat> ControlPoint<S> for Point1<S> {
type Diff = Vector1<S>;
fn origin() -> Self { EuclideanSpace::origin() }
fn to_vec(self) -> Self::Diff { EuclideanSpace::to_vec(self) }
}
impl<S: BaseFloat> ControlPoint<S> for Point2<S> {
type Diff = Vector2<S>;
fn origin() -> Self { EuclideanSpace::origin() }
fn to_vec(self) -> Self::Diff { EuclideanSpace::to_vec(self) }
}
impl<S: BaseFloat> ControlPoint<S> for Point3<S> {
type Diff = Vector3<S>;
fn origin() -> Self { EuclideanSpace::origin() }
fn to_vec(self) -> Self::Diff { EuclideanSpace::to_vec(self) }
}
impl<S: BaseFloat> ControlPoint<S> for Vector1<S> {
type Diff = Vector1<S>;
fn origin() -> Self { Zero::zero() }
fn to_vec(self) -> Self { self }
}
impl<S: BaseFloat> ControlPoint<S> for Vector2<S> {
type Diff = Vector2<S>;
fn origin() -> Self { Zero::zero() }
fn to_vec(self) -> Self { self }
}
impl<S: BaseFloat> ControlPoint<S> for Vector3<S> {
type Diff = Vector3<S>;
fn origin() -> Self { Zero::zero() }
fn to_vec(self) -> Self { self }
}
impl<S: BaseFloat> ControlPoint<S> for Vector4<S> {
type Diff = Vector4<S>;
fn origin() -> Self { Zero::zero() }
fn to_vec(self) -> Self { self }
}
}
pub trait TangentSpace<S: BaseFloat>: VectorSpace<Scalar = S> {
type Space: EuclideanSpace<Scalar = S, Diff = Self>;
}
impl<S: BaseFloat> TangentSpace<S> for Vector1<S> {
type Space = Point1<S>;
}
impl<S: BaseFloat> TangentSpace<S> for Vector2<S> {
type Space = Point2<S>;
}
impl<S: BaseFloat> TangentSpace<S> for Vector3<S> {
type Space = Point3<S>;
}
pub trait Homogeneous<S: BaseFloat>: VectorSpace<Scalar = S> {
type Point: EuclideanSpace<Scalar = S>;
fn truncate(self) -> <Self::Point as EuclideanSpace>::Diff;
fn weight(self) -> S;
fn from_point(point: Self::Point) -> Self;
#[inline(always)]
fn from_point_weight(point: Self::Point, weight: S) -> Self { Self::from_point(point) * weight }
#[inline(always)]
fn to_point(self) -> Self::Point { Self::Point::from_vec(self.truncate() / self.weight()) }
#[inline(always)]
fn rat_der(self, der: Self) -> <Self::Point as EuclideanSpace>::Diff {
let res = (der * self.weight() - self * der.weight()) / (self.weight() * self.weight());
res.truncate()
}
#[inline(always)]
fn rat_der2(self, der: Self, der2: Self) -> <Self::Point as EuclideanSpace>::Diff {
let pre_coef1 = der.weight() / (self.weight() * self.weight());
let coef1 = pre_coef1 + pre_coef1;
let der_last2 = der.weight() * der.weight();
let coef2 = (der_last2 + der_last2 - der2.weight() * self.weight())
/ (self.weight() * self.weight() * self.weight());
let res = der2 / self.weight() - der * coef1 + self * coef2;
res.truncate()
}
#[inline(always)]
fn rat_cross_der(
&self,
uder: Self,
vder: Self,
uvder: Self,
) -> <Self::Point as EuclideanSpace>::Diff {
let self_weight2 = self.weight() * self.weight();
let coef1 = vder.weight() / self_weight2;
let coef2 = uder.weight() / self_weight2;
let der_weight2 = uder.weight() * vder.weight();
let coef3 = (der_weight2 + der_weight2 - uvder.weight() * self.weight())
/ (self_weight2 * self.weight());
let res = uvder / self.weight() - uder * coef1 - vder * coef2 + *self * coef3;
res.truncate()
}
}
impl<S: BaseFloat> Homogeneous<S> for Vector2<S> {
type Point = Point1<S>;
#[inline(always)]
fn truncate(self) -> Vector1<S> { Vector1::new(self[0]) }
#[inline(always)]
fn weight(self) -> S { self[1] }
#[inline(always)]
fn from_point(point: Self::Point) -> Self { Vector2::new(point[0], S::one()) }
}
impl<S: BaseFloat> Homogeneous<S> for Vector3<S> {
type Point = Point2<S>;
#[inline(always)]
fn truncate(self) -> Vector2<S> { self.truncate() }
#[inline(always)]
fn weight(self) -> S { self[2] }
#[inline(always)]
fn from_point(point: Self::Point) -> Self { Vector3::new(point[0], point[1], S::one()) }
}
impl<S: BaseFloat> Homogeneous<S> for Vector4<S> {
type Point = Point3<S>;
#[inline(always)]
fn truncate(self) -> Vector3<S> { self.truncate() }
#[inline(always)]
fn weight(self) -> S { self[3] }
#[inline(always)]
fn from_point(point: Self::Point) -> Self { point.to_homogeneous() }
}