Merge pull request #246 from bjz/associated-types
Convert trait type parameters to associated types
This commit is contained in:
commit
d784e4e531
11 changed files with 328 additions and 256 deletions
12
src/angle.rs
12
src/angle.rs
|
@ -80,7 +80,7 @@ pub trait Angle
|
|||
>
|
||||
: Clone + Zero
|
||||
+ PartialEq + PartialOrd
|
||||
+ ApproxEq<S>
|
||||
+ ApproxEq<Epsilon = S>
|
||||
+ Neg<Output=Self>
|
||||
+ Into<Rad<S>>
|
||||
+ Into<Deg<S>>
|
||||
|
@ -279,16 +279,18 @@ fmt::Debug for Deg<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: BaseFloat>
|
||||
ApproxEq<S> for Rad<S> {
|
||||
impl<S: BaseFloat> ApproxEq for Rad<S> {
|
||||
type Epsilon = S;
|
||||
|
||||
#[inline]
|
||||
fn approx_eq_eps(&self, other: &Rad<S>, epsilon: &S) -> bool {
|
||||
self.s.approx_eq_eps(&other.s, epsilon)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: BaseFloat>
|
||||
ApproxEq<S> for Deg<S> {
|
||||
impl<S: BaseFloat> ApproxEq for Deg<S> {
|
||||
type Epsilon = S;
|
||||
|
||||
#[inline]
|
||||
fn approx_eq_eps(&self, other: &Deg<S>, epsilon: &S) -> bool {
|
||||
self.s.approx_eq_eps(&other.s, epsilon)
|
||||
|
|
|
@ -16,23 +16,26 @@
|
|||
use rust_num::{Float, NumCast};
|
||||
use rust_num::traits::cast;
|
||||
|
||||
pub trait ApproxEq<T: NumCast + Float>: Sized {
|
||||
fn approx_epsilon(_hack: Option<Self>) -> T {
|
||||
pub trait ApproxEq: Sized {
|
||||
type Epsilon: NumCast + Float;
|
||||
|
||||
fn approx_epsilon() -> Self::Epsilon {
|
||||
cast(1.0e-5f64).unwrap()
|
||||
}
|
||||
|
||||
fn approx_eq(&self, other: &Self) -> bool {
|
||||
let eps: T = ApproxEq::approx_epsilon(None::<Self>);
|
||||
self.approx_eq_eps(other, &eps)
|
||||
self.approx_eq_eps(other, &Self::approx_epsilon())
|
||||
}
|
||||
|
||||
fn approx_eq_eps(&self, other: &Self, epsilon: &T) -> bool;
|
||||
fn approx_eq_eps(&self, other: &Self, epsilon: &Self::Epsilon) -> bool;
|
||||
}
|
||||
|
||||
|
||||
macro_rules! approx_float(
|
||||
($S:ident) => (
|
||||
impl ApproxEq<$S> for $S {
|
||||
impl ApproxEq for $S {
|
||||
type Epsilon = $S;
|
||||
|
||||
#[inline]
|
||||
fn approx_eq_eps(&self, other: &$S, epsilon: &$S) -> bool {
|
||||
(*self - *other).abs() < *epsilon
|
||||
|
@ -62,9 +65,8 @@ macro_rules! assert_approx_eq(
|
|||
($given: expr, $expected: expr) => ({
|
||||
let (given_val, expected_val) = (&($given), &($expected));
|
||||
if !given_val.approx_eq(expected_val) {
|
||||
panic!("assertion failed: `left ≈ right` (left: `{:?}`, right: `{:?}`, tolerance: `{:?}`)",
|
||||
*given_val, *expected_val,
|
||||
ApproxEq::approx_epsilon(Some(*given_val))
|
||||
panic!("assertion failed: `left ≈ right` (left: `{:?}`, right: `{:?}`)",
|
||||
*given_val, *expected_val
|
||||
);
|
||||
}
|
||||
})
|
||||
|
|
33
src/array.rs
33
src/array.rs
|
@ -18,14 +18,20 @@ use std::ptr;
|
|||
use std::ops::*;
|
||||
|
||||
/// An array containing elements of type `Element`
|
||||
pub trait Array1<Element: Copy>: Index<usize, Output=Element> + IndexMut<usize, Output=Element> {
|
||||
pub trait Array1 where
|
||||
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
|
||||
Self: Index<usize, Output = <Self as Array1>::Element>,
|
||||
Self: IndexMut<usize, Output = <Self as Array1>::Element>,
|
||||
{
|
||||
type Element: Copy;
|
||||
|
||||
/// Get the pointer to the first element of the array.
|
||||
fn ptr<'a>(&'a self) -> &'a Element {
|
||||
fn ptr<'a>(&'a self) -> &'a Self::Element {
|
||||
&self[0]
|
||||
}
|
||||
|
||||
/// Get a mutable pointer to the first element of the array.
|
||||
fn mut_ptr<'a>(&'a mut self) -> &'a mut Element {
|
||||
fn mut_ptr<'a>(&'a mut self) -> &'a mut Self::Element {
|
||||
&mut self[0]
|
||||
}
|
||||
|
||||
|
@ -38,21 +44,28 @@ pub trait Array1<Element: Copy>: Index<usize, Output=Element> + IndexMut<usize,
|
|||
|
||||
/// Replace an element in the array.
|
||||
#[inline]
|
||||
fn replace_elem(&mut self, i: usize, src: Element) -> Element {
|
||||
fn replace_elem(&mut self, i: usize, src: Self::Element) -> Self::Element {
|
||||
mem::replace(&mut self[i], src)
|
||||
}
|
||||
}
|
||||
|
||||
/// A column-major array
|
||||
pub trait Array2<Column: Array1<Element>+'static, Row: Array1<Element>, Element: Copy>:
|
||||
Index<usize, Output=Column> + IndexMut<usize, Output=Column> {
|
||||
pub trait Array2 where
|
||||
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
|
||||
Self: Index<usize, Output = <Self as Array2>::Column>,
|
||||
Self: IndexMut<usize, Output = <Self as Array2>::Column>,
|
||||
{
|
||||
type Element: Copy;
|
||||
type Column: Array1<Element = Self::Element>;
|
||||
type Row: Array1<Element = Self::Element>;
|
||||
|
||||
/// Get the pointer to the first element of the array.
|
||||
fn ptr<'a>(&'a self) -> &'a Element {
|
||||
fn ptr<'a>(&'a self) -> &'a Self::Element {
|
||||
&self[0][0]
|
||||
}
|
||||
|
||||
/// Get a mutable pointer to the first element of the array.
|
||||
fn mut_ptr<'a>(&'a mut self) -> &'a mut Element {
|
||||
fn mut_ptr<'a>(&'a mut self) -> &'a mut Self::Element {
|
||||
&mut self[0][0]
|
||||
}
|
||||
|
||||
|
@ -64,12 +77,12 @@ pub trait Array2<Column: Array1<Element>+'static, Row: Array1<Element>, Element:
|
|||
|
||||
/// Replace a column in the array.
|
||||
#[inline]
|
||||
fn replace_col(&mut self, c: usize, src: Column) -> Column {
|
||||
fn replace_col(&mut self, c: usize, src: Self::Column) -> Self::Column {
|
||||
mem::replace(&mut self[c], src)
|
||||
}
|
||||
|
||||
/// Get a row from this array by-value.
|
||||
fn row(&self, r: usize) -> Row;
|
||||
fn row(&self, r: usize) -> Self::Row;
|
||||
|
||||
/// Swap two rows of this array.
|
||||
fn swap_rows(&mut self, a: usize, b: usize);
|
||||
|
|
|
@ -249,7 +249,15 @@ impl<S: Copy + Neg<Output = S>> Matrix4<S> {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait Matrix<S: BaseFloat, V: Vector<S> + 'static>: Array2<V, V, S> + ApproxEq<S> + Sized // where
|
||||
pub trait Matrix where
|
||||
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
|
||||
Self: Array2<
|
||||
Element = <<Self as Matrix>::ColumnRow as Vector>::Scalar,
|
||||
Column = <Self as Matrix>::ColumnRow,
|
||||
Row = <Self as Matrix>::ColumnRow,
|
||||
>,
|
||||
Self: ApproxEq<Epsilon = <<Self as Matrix>::ColumnRow as Vector>::Scalar> + Sized,
|
||||
Self::Element: BaseFloat,
|
||||
// FIXME: blocked by rust-lang/rust#20671
|
||||
//
|
||||
// for<'a, 'b> &'a Self: Add<&'b Self, Output = Self>,
|
||||
|
@ -261,28 +269,31 @@ pub trait Matrix<S: BaseFloat, V: Vector<S> + 'static>: Array2<V, V, S> + Approx
|
|||
// for<'a> &'a Self: Div<S, Output = Self>,
|
||||
// for<'a> &'a Self: Rem<S, Output = Self>,
|
||||
{
|
||||
// FIXME: Will not be needed once equality constraints in where clauses is implemented
|
||||
type ColumnRow: Vector;
|
||||
|
||||
/// Create a new diagonal matrix using the supplied value.
|
||||
fn from_value(value: S) -> Self;
|
||||
fn from_value(value: Self::Element) -> Self;
|
||||
/// Create a matrix from a non-uniform scale
|
||||
fn from_diagonal(value: &V) -> Self;
|
||||
fn from_diagonal(diagonal: &Self::Column) -> Self;
|
||||
|
||||
/// Create a matrix with all elements equal to zero.
|
||||
#[inline]
|
||||
fn zero() -> Self { Self::from_value(S::zero()) }
|
||||
fn zero() -> Self { Self::from_value(Self::Element::zero()) }
|
||||
/// Create a matrix where the each element of the diagonal is equal to one.
|
||||
#[inline]
|
||||
fn one() -> Self { Self::from_value(S::one()) }
|
||||
fn one() -> Self { Self::from_value(Self::Element::one()) }
|
||||
|
||||
/// Multiply this matrix by a scalar, returning the new matrix.
|
||||
#[must_use]
|
||||
fn mul_s(&self, s: S) -> Self;
|
||||
fn mul_s(&self, s: Self::Element) -> Self;
|
||||
/// Divide this matrix by a scalar, returning the new matrix.
|
||||
#[must_use]
|
||||
fn div_s(&self, s: S) -> Self;
|
||||
fn div_s(&self, s: Self::Element) -> Self;
|
||||
/// Take the remainder of this matrix by a scalar, returning the new
|
||||
/// matrix.
|
||||
#[must_use]
|
||||
fn rem_s(&self, s: S) -> Self;
|
||||
fn rem_s(&self, s: Self::Element) -> Self;
|
||||
|
||||
/// Add this matrix with another matrix, returning the new metrix.
|
||||
#[must_use]
|
||||
|
@ -292,18 +303,18 @@ pub trait Matrix<S: BaseFloat, V: Vector<S> + 'static>: Array2<V, V, S> + Approx
|
|||
fn sub_m(&self, m: &Self) -> Self;
|
||||
|
||||
/// Multiplay a vector by this matrix, returning a new vector.
|
||||
fn mul_v(&self, v: &V) -> V;
|
||||
fn mul_v(&self, v: &Self::Column) -> Self::Column;
|
||||
|
||||
/// Multiply this matrix by another matrix, returning the new matrix.
|
||||
#[must_use]
|
||||
fn mul_m(&self, m: &Self) -> Self;
|
||||
|
||||
/// Multiply this matrix by a scalar, in-place.
|
||||
fn mul_self_s(&mut self, s: S);
|
||||
fn mul_self_s(&mut self, s: Self::Element);
|
||||
/// Divide this matrix by a scalar, in-place.
|
||||
fn div_self_s(&mut self, s: S);
|
||||
fn div_self_s(&mut self, s: Self::Element);
|
||||
/// Take the remainder of this matrix, in-place.
|
||||
fn rem_self_s(&mut self, s: S);
|
||||
fn rem_self_s(&mut self, s: Self::Element);
|
||||
|
||||
/// Add this matrix with another matrix, in-place.
|
||||
fn add_self_m(&mut self, m: &Self);
|
||||
|
@ -320,14 +331,14 @@ pub trait Matrix<S: BaseFloat, V: Vector<S> + 'static>: Array2<V, V, S> + Approx
|
|||
/// Transpose this matrix in-place.
|
||||
fn transpose_self(&mut self);
|
||||
/// Take the determinant of this matrix.
|
||||
fn determinant(&self) -> S;
|
||||
fn determinant(&self) -> Self::Element;
|
||||
|
||||
/// Return a vector containing the diagonal of this matrix.
|
||||
fn diagonal(&self) -> V;
|
||||
fn diagonal(&self) -> Self::Column;
|
||||
|
||||
/// Return the trace of this matrix. That is, the sum of the diagonal.
|
||||
#[inline]
|
||||
fn trace(&self) -> S { self.diagonal().sum() }
|
||||
fn trace(&self) -> Self::Element { self.diagonal().sum() }
|
||||
|
||||
/// Invert this matrix, returning a new matrix. `m.mul_m(m.invert())` is
|
||||
/// the identity matrix. Returns `None` if this matrix is not invertible
|
||||
|
@ -343,7 +354,7 @@ pub trait Matrix<S: BaseFloat, V: Vector<S> + 'static>: Array2<V, V, S> + Approx
|
|||
|
||||
/// Test if this matrix is invertible.
|
||||
#[inline]
|
||||
fn is_invertible(&self) -> bool { !self.determinant().approx_eq(&S::zero()) }
|
||||
fn is_invertible(&self) -> bool { !self.determinant().approx_eq(&Self::Element::zero()) }
|
||||
|
||||
/// Test if this matrix is the identity matrix. That is, it is diagonal
|
||||
/// and every element in the diagonal is one.
|
||||
|
@ -359,7 +370,11 @@ pub trait Matrix<S: BaseFloat, V: Vector<S> + 'static>: Array2<V, V, S> + Approx
|
|||
fn is_symmetric(&self) -> bool;
|
||||
}
|
||||
|
||||
impl<S: Copy + 'static> Array2<Vector2<S>, Vector2<S>, S> for Matrix2<S> {
|
||||
impl<S: Copy> Array2 for Matrix2<S> {
|
||||
type Element = S;
|
||||
type Column = Vector2<S>;
|
||||
type Row = Vector2<S>;
|
||||
|
||||
#[inline]
|
||||
fn row(&self, r: usize) -> Vector2<S> {
|
||||
Vector2::new(self[0][r],
|
||||
|
@ -373,7 +388,11 @@ impl<S: Copy + 'static> Array2<Vector2<S>, Vector2<S>, S> for Matrix2<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: Copy + 'static> Array2<Vector3<S>, Vector3<S>, S> for Matrix3<S> {
|
||||
impl<S: Copy> Array2 for Matrix3<S> {
|
||||
type Element = S;
|
||||
type Column = Vector3<S>;
|
||||
type Row = Vector3<S>;
|
||||
|
||||
#[inline]
|
||||
fn row(&self, r: usize) -> Vector3<S> {
|
||||
Vector3::new(self[0][r],
|
||||
|
@ -389,7 +408,11 @@ impl<S: Copy + 'static> Array2<Vector3<S>, Vector3<S>, S> for Matrix3<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: Copy + 'static> Array2<Vector4<S>, Vector4<S>, S> for Matrix4<S> {
|
||||
impl<S: Copy> Array2 for Matrix4<S> {
|
||||
type Element = S;
|
||||
type Column = Vector4<S>;
|
||||
type Row = Vector4<S>;
|
||||
|
||||
#[inline]
|
||||
fn row(&self, r: usize) -> Vector4<S> {
|
||||
Vector4::new(self[0][r],
|
||||
|
@ -407,7 +430,9 @@ impl<S: Copy + 'static> Array2<Vector4<S>, Vector4<S>, S> for Matrix4<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: BaseFloat> Matrix<S, Vector2<S>> for Matrix2<S> {
|
||||
impl<S: BaseFloat> Matrix for Matrix2<S> {
|
||||
type ColumnRow = Vector2<S>;
|
||||
|
||||
#[inline]
|
||||
fn from_value(value: S) -> Matrix2<S> {
|
||||
Matrix2::new(value, S::zero(),
|
||||
|
@ -504,7 +529,9 @@ impl<S: BaseFloat> Matrix<S, Vector2<S>> for Matrix2<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: BaseFloat> Matrix<S, Vector3<S>> for Matrix3<S> {
|
||||
impl<S: BaseFloat> Matrix for Matrix3<S> {
|
||||
type ColumnRow = Vector3<S>;
|
||||
|
||||
#[inline]
|
||||
fn from_value(value: S) -> Matrix3<S> {
|
||||
Matrix3::new(value, S::zero(), S::zero(),
|
||||
|
@ -620,7 +647,9 @@ impl<S: BaseFloat> Matrix<S, Vector3<S>> for Matrix3<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: BaseFloat> Matrix<S, Vector4<S>> for Matrix4<S> {
|
||||
impl<S: BaseFloat> Matrix for Matrix4<S> {
|
||||
type ColumnRow = Vector4<S>;
|
||||
|
||||
#[inline]
|
||||
fn from_value(value: S) -> Matrix4<S> {
|
||||
Matrix4::new(value, S::zero(), S::zero(), S::zero(),
|
||||
|
@ -790,7 +819,9 @@ impl<S: BaseFloat> Matrix<S, Vector4<S>> for Matrix4<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: BaseFloat> ApproxEq<S> for Matrix2<S> {
|
||||
impl<S: BaseFloat> ApproxEq for Matrix2<S> {
|
||||
type Epsilon = S;
|
||||
|
||||
#[inline]
|
||||
fn approx_eq_eps(&self, other: &Matrix2<S>, epsilon: &S) -> bool {
|
||||
self[0].approx_eq_eps(&other[0], epsilon) &&
|
||||
|
@ -798,7 +829,9 @@ impl<S: BaseFloat> ApproxEq<S> for Matrix2<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: BaseFloat> ApproxEq<S> for Matrix3<S> {
|
||||
impl<S: BaseFloat> ApproxEq for Matrix3<S> {
|
||||
type Epsilon = S;
|
||||
|
||||
#[inline]
|
||||
fn approx_eq_eps(&self, other: &Matrix3<S>, epsilon: &S) -> bool {
|
||||
self[0].approx_eq_eps(&other[0], epsilon) &&
|
||||
|
@ -807,7 +840,9 @@ impl<S: BaseFloat> ApproxEq<S> for Matrix3<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: BaseFloat> ApproxEq<S> for Matrix4<S> {
|
||||
impl<S: BaseFloat> ApproxEq for Matrix4<S> {
|
||||
type Epsilon = S;
|
||||
|
||||
#[inline]
|
||||
fn approx_eq_eps(&self, other: &Matrix4<S>, epsilon: &S) -> bool {
|
||||
self[0].approx_eq_eps(&other[0], epsilon) &&
|
||||
|
|
|
@ -110,7 +110,7 @@ impl BaseInt for u64 {}
|
|||
impl BaseInt for usize {}
|
||||
|
||||
/// Base floating point types
|
||||
pub trait BaseFloat : BaseNum + Float + ApproxEq<Self> {}
|
||||
pub trait BaseFloat : BaseNum + Float + ApproxEq<Epsilon = Self> {}
|
||||
|
||||
impl BaseFloat for f32 {}
|
||||
impl BaseFloat for f64 {}
|
||||
|
|
128
src/point.rs
128
src/point.rs
|
@ -66,7 +66,9 @@ impl<S: BaseNum> Point3<S> {
|
|||
}
|
||||
|
||||
/// Specifies the numeric operations for point types.
|
||||
pub trait Point<S: BaseNum, V: Vector<S>>: Array1<S> + Clone // where
|
||||
pub trait Point: Clone where
|
||||
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
|
||||
Self: Array1<Element = <Self as Point>::Scalar>,
|
||||
// FIXME: blocked by rust-lang/rust#20671
|
||||
//
|
||||
// for<'a, 'b> &'a Self: Add<&'b V, Output = Self>,
|
||||
|
@ -76,42 +78,50 @@ pub trait Point<S: BaseNum, V: Vector<S>>: Array1<S> + Clone // where
|
|||
// for<'a> &'a Self: Div<S, Output = Self>,
|
||||
// for<'a> &'a Self: Rem<S, Output = Self>,
|
||||
{
|
||||
/// The associated scalar.
|
||||
///
|
||||
/// Due to the equality constraints demanded by `Self::Vector`, this is effectively just an
|
||||
/// alias to `Self::Vector::Scalar`.
|
||||
type Scalar: BaseNum;
|
||||
/// The associated displacement vector.
|
||||
type Vector: Vector<Scalar = Self::Scalar>;
|
||||
|
||||
/// Create a point at the origin.
|
||||
fn origin() -> Self;
|
||||
|
||||
/// Create a point from a vector.
|
||||
fn from_vec(v: &V) -> Self;
|
||||
fn from_vec(v: &Self::Vector) -> Self;
|
||||
/// Convert a point to a vector.
|
||||
fn to_vec(&self) -> V;
|
||||
fn to_vec(&self) -> Self::Vector;
|
||||
|
||||
/// Multiply each component by a scalar, returning the new point.
|
||||
#[must_use]
|
||||
fn mul_s(&self, s: S) -> Self;
|
||||
fn mul_s(&self, scalar: Self::Scalar) -> Self;
|
||||
/// Divide each component by a scalar, returning the new point.
|
||||
#[must_use]
|
||||
fn div_s(&self, s: S) -> Self;
|
||||
fn div_s(&self, scalar: Self::Scalar) -> Self;
|
||||
/// Subtract a scalar from each component, returning the new point.
|
||||
#[must_use]
|
||||
fn rem_s(&self, s: S) -> Self;
|
||||
fn rem_s(&self, scalar: Self::Scalar) -> Self;
|
||||
|
||||
/// Add a vector to this point, returning the new point.
|
||||
#[must_use]
|
||||
fn add_v(&self, v: &V) -> Self;
|
||||
fn add_v(&self, v: &Self::Vector) -> Self;
|
||||
/// Subtract another point from this one, returning a new vector.
|
||||
fn sub_p(&self, p: &Self) -> V;
|
||||
fn sub_p(&self, p: &Self) -> Self::Vector;
|
||||
|
||||
/// Multiply each component by a scalar, in-place.
|
||||
fn mul_self_s(&mut self, s: S);
|
||||
fn mul_self_s(&mut self, scalar: Self::Scalar);
|
||||
/// Divide each component by a scalar, in-place.
|
||||
fn div_self_s(&mut self, s: S);
|
||||
fn div_self_s(&mut self, scalar: Self::Scalar);
|
||||
/// Take the remainder of each component by a scalar, in-place.
|
||||
fn rem_self_s(&mut self, s: S);
|
||||
fn rem_self_s(&mut self, scalar: Self::Scalar);
|
||||
|
||||
/// Add a vector to this point, in-place.
|
||||
fn add_self_v(&mut self, v: &V);
|
||||
fn add_self_v(&mut self, v: &Self::Vector);
|
||||
|
||||
/// This is a weird one, but its useful for plane calculations.
|
||||
fn dot(&self, v: &V) -> S;
|
||||
fn dot(&self, v: &Self::Vector) -> Self::Scalar;
|
||||
|
||||
#[must_use]
|
||||
fn min(&self, p: &Self) -> Self;
|
||||
|
@ -120,9 +130,14 @@ pub trait Point<S: BaseNum, V: Vector<S>>: Array1<S> + Clone // where
|
|||
fn max(&self, p: &Self) -> Self;
|
||||
}
|
||||
|
||||
impl<S: BaseNum> Array1<S> for Point2<S> {}
|
||||
impl<S: BaseNum> Array1 for Point2<S> {
|
||||
type Element = S;
|
||||
}
|
||||
|
||||
impl<S: BaseNum> Point for Point2<S> {
|
||||
type Scalar = S;
|
||||
type Vector = Vector2<S>;
|
||||
|
||||
impl<S: BaseNum> Point<S, Vector2<S>> for Point2<S> {
|
||||
#[inline]
|
||||
fn origin() -> Point2<S> {
|
||||
Point2::new(S::zero(), S::zero())
|
||||
|
@ -138,28 +153,28 @@ impl<S: BaseNum> Point<S, Vector2<S>> for Point2<S> {
|
|||
Vector2::new(self.x, self.y)
|
||||
}
|
||||
|
||||
#[inline] fn mul_s(&self, s: S) -> Point2<S> { self * s }
|
||||
#[inline] fn div_s(&self, s: S) -> Point2<S> { self / s }
|
||||
#[inline] fn rem_s(&self, s: S) -> Point2<S> { self % s }
|
||||
#[inline] fn mul_s(&self, scalar: S) -> Point2<S> { self * scalar }
|
||||
#[inline] fn div_s(&self, scalar: S) -> Point2<S> { self / scalar }
|
||||
#[inline] fn rem_s(&self, scalar: S) -> Point2<S> { self % scalar }
|
||||
#[inline] fn add_v(&self, v: &Vector2<S>) -> Point2<S> { self + v }
|
||||
#[inline] fn sub_p(&self, p: &Point2<S>) -> Vector2<S> { self - p }
|
||||
|
||||
#[inline]
|
||||
fn mul_self_s(&mut self, s: S) {
|
||||
self.x = self.x * s;
|
||||
self.y = self.y * s;
|
||||
fn mul_self_s(&mut self, scalar: S) {
|
||||
self.x = self.x * scalar;
|
||||
self.y = self.y * scalar;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn div_self_s(&mut self, s: S) {
|
||||
self.x = self.x / s;
|
||||
self.y = self.y / s;
|
||||
fn div_self_s(&mut self, scalar: S) {
|
||||
self.x = self.x / scalar;
|
||||
self.y = self.y / scalar;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rem_self_s(&mut self, s: S) {
|
||||
self.x = self.x % s;
|
||||
self.y = self.y % s;
|
||||
fn rem_self_s(&mut self, scalar: S) {
|
||||
self.x = self.x % scalar;
|
||||
self.y = self.y % scalar;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -185,7 +200,9 @@ impl<S: BaseNum> Point<S, Vector2<S>> for Point2<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: BaseFloat> ApproxEq<S> for Point2<S> {
|
||||
impl<S: BaseFloat> ApproxEq for Point2<S> {
|
||||
type Epsilon = S;
|
||||
|
||||
#[inline]
|
||||
fn approx_eq_eps(&self, other: &Point2<S>, epsilon: &S) -> bool {
|
||||
self.x.approx_eq_eps(&other.x, epsilon) &&
|
||||
|
@ -193,9 +210,14 @@ impl<S: BaseFloat> ApproxEq<S> for Point2<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: BaseNum> Array1<S> for Point3<S> {}
|
||||
impl<S: BaseNum> Array1 for Point3<S> {
|
||||
type Element = S;
|
||||
}
|
||||
|
||||
impl<S: BaseNum> Point for Point3<S> {
|
||||
type Scalar = S;
|
||||
type Vector = Vector3<S>;
|
||||
|
||||
impl<S: BaseNum> Point<S, Vector3<S>> for Point3<S> {
|
||||
#[inline]
|
||||
fn origin() -> Point3<S> {
|
||||
Point3::new(S::zero(), S::zero(), S::zero())
|
||||
|
@ -211,31 +233,31 @@ impl<S: BaseNum> Point<S, Vector3<S>> for Point3<S> {
|
|||
Vector3::new(self.x, self.y, self.z)
|
||||
}
|
||||
|
||||
#[inline] fn mul_s(&self, s: S) -> Point3<S> { self * s }
|
||||
#[inline] fn div_s(&self, s: S) -> Point3<S> { self / s }
|
||||
#[inline] fn rem_s(&self, s: S) -> Point3<S> { self % s }
|
||||
#[inline] fn mul_s(&self, scalar: S) -> Point3<S> { self * scalar }
|
||||
#[inline] fn div_s(&self, scalar: S) -> Point3<S> { self / scalar }
|
||||
#[inline] fn rem_s(&self, scalar: S) -> Point3<S> { self % scalar }
|
||||
#[inline] fn add_v(&self, v: &Vector3<S>) -> Point3<S> { self + v }
|
||||
#[inline] fn sub_p(&self, p: &Point3<S>) -> Vector3<S> { self - p }
|
||||
|
||||
#[inline]
|
||||
fn mul_self_s(&mut self, s: S) {
|
||||
self.x = self.x * s;
|
||||
self.y = self.y * s;
|
||||
self.z = self.z * s;
|
||||
fn mul_self_s(&mut self, scalar: S) {
|
||||
self.x = self.x * scalar;
|
||||
self.y = self.y * scalar;
|
||||
self.z = self.z * scalar;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn div_self_s(&mut self, s: S) {
|
||||
self.x = self.x / s;
|
||||
self.y = self.y / s;
|
||||
self.z = self.z / s;
|
||||
fn div_self_s(&mut self, scalar: S) {
|
||||
self.x = self.x / scalar;
|
||||
self.y = self.y / scalar;
|
||||
self.z = self.z / scalar;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rem_self_s(&mut self, s: S) {
|
||||
self.x = self.x % s;
|
||||
self.y = self.y % s;
|
||||
self.z = self.z % s;
|
||||
fn rem_self_s(&mut self, scalar: S) {
|
||||
self.x = self.x % scalar;
|
||||
self.y = self.y % scalar;
|
||||
self.z = self.z % scalar;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -263,7 +285,9 @@ impl<S: BaseNum> Point<S, Vector3<S>> for Point3<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: BaseFloat> ApproxEq<S> for Point3<S> {
|
||||
impl<S: BaseFloat> ApproxEq for Point3<S> {
|
||||
type Epsilon = S;
|
||||
|
||||
#[inline]
|
||||
fn approx_eq_eps(&self, other: &Point3<S>, epsilon: &S) -> bool {
|
||||
self.x.approx_eq_eps(&other.x, epsilon) &&
|
||||
|
@ -279,8 +303,8 @@ macro_rules! impl_operators {
|
|||
type Output = $PointN<S>;
|
||||
|
||||
#[inline]
|
||||
fn mul(self, s: S) -> $PointN<S> {
|
||||
$PointN::new($(self.$field * s),+)
|
||||
fn mul(self, scalar: S) -> $PointN<S> {
|
||||
$PointN::new($(self.$field * scalar),+)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -288,8 +312,8 @@ macro_rules! impl_operators {
|
|||
type Output = $PointN<S>;
|
||||
|
||||
#[inline]
|
||||
fn div(self, s: S) -> $PointN<S> {
|
||||
$PointN::new($(self.$field / s),+)
|
||||
fn div(self, scalar: S) -> $PointN<S> {
|
||||
$PointN::new($(self.$field / scalar),+)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -297,8 +321,8 @@ macro_rules! impl_operators {
|
|||
type Output = $PointN<S>;
|
||||
|
||||
#[inline]
|
||||
fn rem(self, s: S) -> $PointN<S> {
|
||||
$PointN::new($(self.$field % s),+)
|
||||
fn rem(self, scalar: S) -> $PointN<S> {
|
||||
$PointN::new($(self.$field % scalar),+)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,9 @@ pub struct Quaternion<S> {
|
|||
pub v: Vector3<S>,
|
||||
}
|
||||
|
||||
impl<S: Copy + BaseFloat> Array1<S> for Quaternion<S> {}
|
||||
impl<S: Copy + BaseFloat> Array1 for Quaternion<S> {
|
||||
type Element = S;
|
||||
}
|
||||
|
||||
impl<S: BaseFloat> Quaternion<S> {
|
||||
/// Construct a new quaternion from one scalar component and three
|
||||
|
@ -170,7 +172,9 @@ impl<'a, 'b, S: BaseFloat> Mul<&'b Quaternion<S>> for &'a Quaternion<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: BaseFloat> ApproxEq<S> for Quaternion<S> {
|
||||
impl<S: BaseFloat> ApproxEq for Quaternion<S> {
|
||||
type Epsilon = S;
|
||||
|
||||
#[inline]
|
||||
fn approx_eq_eps(&self, other: &Quaternion<S>, epsilon: &S) -> bool {
|
||||
self.s.approx_eq_eps(&other.s, epsilon) &&
|
||||
|
@ -339,7 +343,7 @@ impl<S: BaseFloat> From<Quaternion<S>> for Basis3<S> {
|
|||
fn from(quat: Quaternion<S>) -> Basis3<S> { Basis3::from_quaternion(&quat) }
|
||||
}
|
||||
|
||||
impl<S: BaseFloat + 'static> Rotation<S, Vector3<S>, Point3<S>> for Quaternion<S> {
|
||||
impl<S: BaseFloat> Rotation<Point3<S>> for Quaternion<S> {
|
||||
#[inline]
|
||||
fn one() -> Quaternion<S> { Quaternion::one() }
|
||||
|
||||
|
|
|
@ -25,19 +25,23 @@ use vector::{Vector, Vector2, Vector3};
|
|||
|
||||
/// A trait for a generic rotation. A rotation is a transformation that
|
||||
/// creates a circular motion, and preserves at least one point in the space.
|
||||
pub trait Rotation<S: BaseFloat, V: Vector<S>, P: Point<S, V>>: PartialEq + ApproxEq<S> + Sized {
|
||||
pub trait Rotation<P: Point>: PartialEq + Sized where
|
||||
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
|
||||
Self: ApproxEq<Epsilon = <P as Point>::Scalar>,
|
||||
<P as Point>::Scalar: BaseFloat,
|
||||
{
|
||||
/// Create the identity transform (causes no transformation).
|
||||
fn one() -> Self;
|
||||
|
||||
/// Create a rotation to a given direction with an 'up' vector
|
||||
fn look_at(dir: &V, up: &V) -> Self;
|
||||
fn look_at(dir: &P::Vector, up: &P::Vector) -> Self;
|
||||
|
||||
/// Create a shortest rotation to transform vector 'a' into 'b'.
|
||||
/// Both given vectors are assumed to have unit length.
|
||||
fn between_vectors(a: &V, b: &V) -> Self;
|
||||
fn between_vectors(a: &P::Vector, b: &P::Vector) -> Self;
|
||||
|
||||
/// Rotate a vector using this rotation.
|
||||
fn rotate_vector(&self, vec: &V) -> V;
|
||||
fn rotate_vector(&self, vec: &P::Vector) -> P::Vector;
|
||||
|
||||
/// Rotate a point using this rotation, by converting it to its
|
||||
/// representation as a vector.
|
||||
|
@ -67,7 +71,7 @@ pub trait Rotation<S: BaseFloat, V: Vector<S>, P: Point<S, V>>: PartialEq + Appr
|
|||
}
|
||||
|
||||
/// A two-dimensional rotation.
|
||||
pub trait Rotation2<S: BaseFloat>: Rotation<S, Vector2<S>, Point2<S>>
|
||||
pub trait Rotation2<S: BaseFloat>: Rotation<Point2<S>>
|
||||
+ Into<Matrix2<S>>
|
||||
+ Into<Basis2<S>> {
|
||||
/// Create a rotation by a given angle. Thus is a redundant case of both
|
||||
|
@ -76,7 +80,7 @@ pub trait Rotation2<S: BaseFloat>: Rotation<S, Vector2<S>, Point2<S>>
|
|||
}
|
||||
|
||||
/// A three-dimensional rotation.
|
||||
pub trait Rotation3<S: BaseFloat>: Rotation<S, Vector3<S>, Point3<S>>
|
||||
pub trait Rotation3<S: BaseFloat>: Rotation<Point3<S>>
|
||||
+ Into<Matrix3<S>>
|
||||
+ Into<Basis3<S>>
|
||||
+ Into<Quaternion<S>> {
|
||||
|
@ -172,7 +176,7 @@ impl<S: BaseFloat> From<Basis2<S>> for Matrix2<S> {
|
|||
fn from(b: Basis2<S>) -> Matrix2<S> { b.mat }
|
||||
}
|
||||
|
||||
impl<S: BaseFloat + 'static> Rotation<S, Vector2<S>, Point2<S>> for Basis2<S> {
|
||||
impl<S: BaseFloat> Rotation<Point2<S>> for Basis2<S> {
|
||||
#[inline]
|
||||
fn one() -> Basis2<S> { Basis2 { mat: Matrix2::one() } }
|
||||
|
||||
|
@ -206,14 +210,16 @@ impl<S: BaseFloat + 'static> Rotation<S, Vector2<S>, Point2<S>> for Basis2<S> {
|
|||
fn invert_self(&mut self) { self.mat.invert_self(); }
|
||||
}
|
||||
|
||||
impl<S: BaseFloat> ApproxEq<S> for Basis2<S> {
|
||||
impl<S: BaseFloat> ApproxEq for Basis2<S> {
|
||||
type Epsilon = S;
|
||||
|
||||
#[inline]
|
||||
fn approx_eq_eps(&self, other: &Basis2<S>, epsilon: &S) -> bool {
|
||||
self.mat.approx_eq_eps(&other.mat, epsilon)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: BaseFloat + 'static> Rotation2<S> for Basis2<S> {
|
||||
impl<S: BaseFloat> Rotation2<S> for Basis2<S> {
|
||||
fn from_angle(theta: Rad<S>) -> Basis2<S> { Basis2 { mat: Matrix2::from_angle(theta) } }
|
||||
}
|
||||
|
||||
|
@ -248,12 +254,12 @@ impl<S: BaseFloat> From<Basis3<S>> for Matrix3<S> {
|
|||
fn from(b: Basis3<S>) -> Matrix3<S> { b.mat }
|
||||
}
|
||||
|
||||
impl<S: BaseFloat + 'static> From<Basis3<S>> for Quaternion<S> {
|
||||
impl<S: BaseFloat> From<Basis3<S>> for Quaternion<S> {
|
||||
#[inline]
|
||||
fn from(b: Basis3<S>) -> Quaternion<S> { b.mat.into() }
|
||||
}
|
||||
|
||||
impl<S: BaseFloat + 'static> Rotation<S, Vector3<S>, Point3<S>> for Basis3<S> {
|
||||
impl<S: BaseFloat> Rotation<Point3<S>> for Basis3<S> {
|
||||
#[inline]
|
||||
fn one() -> Basis3<S> { Basis3 { mat: Matrix3::one() } }
|
||||
|
||||
|
@ -288,14 +294,16 @@ impl<S: BaseFloat + 'static> Rotation<S, Vector3<S>, Point3<S>> for Basis3<S> {
|
|||
fn invert_self(&mut self) { self.mat.invert_self(); }
|
||||
}
|
||||
|
||||
impl<S: BaseFloat> ApproxEq<S> for Basis3<S> {
|
||||
impl<S: BaseFloat> ApproxEq for Basis3<S> {
|
||||
type Epsilon = S;
|
||||
|
||||
#[inline]
|
||||
fn approx_eq_eps(&self, other: &Basis3<S>, epsilon: &S) -> bool {
|
||||
self.mat.approx_eq_eps(&other.mat, epsilon)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: BaseFloat + 'static> Rotation3<S> for Basis3<S> {
|
||||
impl<S: BaseFloat> Rotation3<S> for Basis3<S> {
|
||||
fn from_axis_angle(axis: &Vector3<S>, angle: Rad<S>) -> Basis3<S> {
|
||||
Basis3 { mat: Matrix3::from_axis_angle(axis, angle) }
|
||||
}
|
||||
|
|
141
src/transform.rs
141
src/transform.rs
|
@ -27,24 +27,24 @@ use vector::*;
|
|||
/// A trait representing an [affine
|
||||
/// transformation](https://en.wikipedia.org/wiki/Affine_transformation) that
|
||||
/// can be applied to points or vectors. An affine transformation is one which
|
||||
pub trait Transform<S: BaseNum, V: Vector<S>, P: Point<S, V>>: Sized {
|
||||
pub trait Transform<P: Point>: Sized {
|
||||
/// Create an identity transformation. That is, a transformation which
|
||||
/// does nothing.
|
||||
fn one() -> Self;
|
||||
|
||||
/// Create a transformation that rotates a vector to look at `center` from
|
||||
/// `eye`, using `up` for orientation.
|
||||
fn look_at(eye: &P, center: &P, up: &V) -> Self;
|
||||
fn look_at(eye: &P, center: &P, up: &P::Vector) -> Self;
|
||||
|
||||
/// Transform a vector using this transform.
|
||||
fn transform_vector(&self, vec: &V) -> V;
|
||||
fn transform_vector(&self, vec: &P::Vector) -> P::Vector;
|
||||
|
||||
/// Transform a point using this transform.
|
||||
fn transform_point(&self, point: &P) -> P;
|
||||
|
||||
/// Transform a vector as a point using this transform.
|
||||
#[inline]
|
||||
fn transform_as_point(&self, vec: &V) -> V {
|
||||
fn transform_as_point(&self, vec: &P::Vector) -> P::Vector {
|
||||
self.transform_point(&P::from_vec(vec)).to_vec()
|
||||
}
|
||||
|
||||
|
@ -72,40 +72,38 @@ pub trait Transform<S: BaseNum, V: Vector<S>, P: Point<S, V>>: Sized {
|
|||
/// A generic transformation consisting of a rotation,
|
||||
/// displacement vector and scale amount.
|
||||
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
|
||||
pub struct Decomposed<S, V, R> {
|
||||
pub scale: S,
|
||||
pub struct Decomposed<V: Vector, R> {
|
||||
pub scale: V::Scalar,
|
||||
pub rot: R,
|
||||
pub disp: V,
|
||||
}
|
||||
|
||||
impl<
|
||||
S: BaseFloat,
|
||||
V: Vector<S>,
|
||||
P: Point<S, V>,
|
||||
R: Rotation<S, V, P>,
|
||||
> Transform<S, V, P> for Decomposed<S, V, R> {
|
||||
impl<P: Point, R: Rotation<P>> Transform<P> for Decomposed<P::Vector, R> where
|
||||
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
|
||||
<P as Point>::Scalar: BaseFloat,
|
||||
{
|
||||
#[inline]
|
||||
fn one() -> Decomposed<S, V, R> {
|
||||
fn one() -> Decomposed<P::Vector, R> {
|
||||
Decomposed {
|
||||
scale: S::one(),
|
||||
scale: <P as Point>::Scalar::one(),
|
||||
rot: R::one(),
|
||||
disp: V::zero(),
|
||||
disp: P::Vector::zero(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn look_at(eye: &P, center: &P, up: &V) -> Decomposed<S, V, R> {
|
||||
fn look_at(eye: &P, center: &P, up: &P::Vector) -> Decomposed<P::Vector, R> {
|
||||
let rot = R::look_at(¢er.sub_p(eye), up);
|
||||
let disp = rot.rotate_vector(&P::origin().sub_p(eye));
|
||||
Decomposed {
|
||||
scale: S::one(),
|
||||
scale: <P as Point>::Scalar::one(),
|
||||
rot: rot,
|
||||
disp: disp,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn transform_vector(&self, vec: &V) -> V {
|
||||
fn transform_vector(&self, vec: &P::Vector) -> P::Vector {
|
||||
self.rot.rotate_vector(&vec.mul_s(self.scale.clone()))
|
||||
}
|
||||
|
||||
|
@ -114,7 +112,7 @@ impl<
|
|||
self.rot.rotate_point(&point.mul_s(self.scale.clone())).add_v(&self.disp)
|
||||
}
|
||||
|
||||
fn concat(&self, other: &Decomposed<S, V, R>) -> Decomposed<S, V, R> {
|
||||
fn concat(&self, other: &Decomposed<P::Vector, R>) -> Decomposed<P::Vector, R> {
|
||||
Decomposed {
|
||||
scale: self.scale * other.scale,
|
||||
rot: self.rot.concat(&other.rot),
|
||||
|
@ -122,11 +120,11 @@ impl<
|
|||
}
|
||||
}
|
||||
|
||||
fn invert(&self) -> Option<Decomposed<S, V, R>> {
|
||||
if self.scale.approx_eq(&S::zero()) {
|
||||
fn invert(&self) -> Option<Decomposed<P::Vector, R>> {
|
||||
if self.scale.approx_eq(&<P as Point>::Scalar::zero()) {
|
||||
None
|
||||
} else {
|
||||
let s = S::one() / self.scale;
|
||||
let s = <P as Point>::Scalar::one() / self.scale;
|
||||
let r = self.rot.invert();
|
||||
let d = r.rotate_vector(&self.disp).mul_s(-s);
|
||||
Some(Decomposed {
|
||||
|
@ -138,14 +136,11 @@ impl<
|
|||
}
|
||||
}
|
||||
|
||||
pub trait Transform2<S: BaseNum>: Transform<S, Vector2<S>, Point2<S>> + Into<Matrix3<S>> {}
|
||||
pub trait Transform3<S: BaseNum>: Transform<S, Vector3<S>, Point3<S>> + Into<Matrix4<S>> {}
|
||||
pub trait Transform2<S: BaseNum>: Transform<Point2<S>> + Into<Matrix3<S>> {}
|
||||
pub trait Transform3<S: BaseNum>: Transform<Point3<S>> + Into<Matrix4<S>> {}
|
||||
|
||||
impl<
|
||||
S: BaseFloat + 'static,
|
||||
R: Rotation2<S>,
|
||||
> From<Decomposed<S, Vector2<S>, R>> for Matrix3<S> {
|
||||
fn from(dec: Decomposed<S, Vector2<S>, R>) -> Matrix3<S> {
|
||||
impl<S: BaseFloat, R: Rotation2<S>> From<Decomposed<Vector2<S>, R>> for Matrix3<S> {
|
||||
fn from(dec: Decomposed<Vector2<S>, R>) -> Matrix3<S> {
|
||||
let m: Matrix2<_> = dec.rot.into();
|
||||
let mut m: Matrix3<_> = m.mul_s(dec.scale).into();
|
||||
m.z = dec.disp.extend(S::one());
|
||||
|
@ -153,11 +148,8 @@ impl<
|
|||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
S: BaseFloat + 'static,
|
||||
R: Rotation3<S>,
|
||||
> From<Decomposed<S, Vector3<S>, R>> for Matrix4<S> {
|
||||
fn from(dec: Decomposed<S, Vector3<S>, R>) -> Matrix4<S> {
|
||||
impl<S: BaseFloat, R: Rotation3<S>> From<Decomposed<Vector3<S>, R>> for Matrix4<S> {
|
||||
fn from(dec: Decomposed<Vector3<S>, R>) -> Matrix4<S> {
|
||||
let m: Matrix3<_> = dec.rot.into();
|
||||
let mut m: Matrix4<_> = m.mul_s(dec.scale).into();
|
||||
m.w = dec.disp.extend(S::one());
|
||||
|
@ -165,20 +157,11 @@ impl<
|
|||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
S: BaseFloat + 'static,
|
||||
R: Rotation2<S>,
|
||||
> Transform2<S> for Decomposed<S, Vector2<S>, R> {}
|
||||
impl<S: BaseFloat, R: Rotation2<S>> Transform2<S> for Decomposed<Vector2<S>, R> {}
|
||||
|
||||
impl<
|
||||
S: BaseFloat + 'static,
|
||||
R: Rotation3<S>,
|
||||
> Transform3<S> for Decomposed<S, Vector3<S>, R> {}
|
||||
impl<S: BaseFloat, R: Rotation3<S>> Transform3<S> for Decomposed<Vector3<S>, R> {}
|
||||
|
||||
impl<
|
||||
S: BaseFloat,
|
||||
R: fmt::Debug + Rotation3<S>,
|
||||
> fmt::Debug for Decomposed<S, Vector3<S>, R> {
|
||||
impl<S: BaseFloat, R: fmt::Debug + Rotation3<S>> fmt::Debug for Decomposed<Vector3<S>, R> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "(scale({:?}), rot({:?}), disp{:?})",
|
||||
self.scale, self.rot, self.disp)
|
||||
|
@ -191,7 +174,7 @@ pub struct AffineMatrix3<S> {
|
|||
pub mat: Matrix4<S>,
|
||||
}
|
||||
|
||||
impl<S: BaseFloat + 'static> Transform<S, Vector3<S>, Point3<S>> for AffineMatrix3<S> {
|
||||
impl<S: BaseFloat> Transform<Point3<S>> for AffineMatrix3<S> {
|
||||
#[inline]
|
||||
fn one() -> AffineMatrix3<S> {
|
||||
AffineMatrix3 { mat: Matrix4::one() }
|
||||
|
@ -227,54 +210,40 @@ impl<S: BaseNum> From<AffineMatrix3<S>> for Matrix4<S> {
|
|||
#[inline] fn from(aff: AffineMatrix3<S>) -> Matrix4<S> { aff.mat }
|
||||
}
|
||||
|
||||
impl<S: BaseFloat + 'static> Transform3<S> for AffineMatrix3<S> {}
|
||||
impl<S: BaseFloat> Transform3<S> for AffineMatrix3<S> {}
|
||||
|
||||
/// A trait that allows extracting components (rotation, translation, scale)
|
||||
/// from an arbitrary transformations
|
||||
pub trait ToComponents<S: BaseFloat, V: Vector<S>, P: Point<S, V>, R: Rotation<S, V, P>> {
|
||||
pub trait ToComponents<P: Point, R: Rotation<P>> where
|
||||
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
|
||||
<P as Point>::Scalar: BaseFloat,
|
||||
{
|
||||
/// Extract the (scale, rotation, translation) triple
|
||||
fn decompose(&self) -> (V, R, V);
|
||||
fn decompose(&self) -> (P::Vector, R, P::Vector);
|
||||
}
|
||||
|
||||
pub trait ToComponents2<S: BaseFloat, R: Rotation2<S>>:
|
||||
ToComponents<S, Vector2<S>, Point2<S>, R> {}
|
||||
pub trait ToComponents3<S: BaseFloat, R: Rotation3<S>>:
|
||||
ToComponents<S, Vector3<S>, Point3<S>, R> {}
|
||||
pub trait ToComponents2<S: BaseFloat, R: Rotation2<S>>: ToComponents<Point2<S>, R> {}
|
||||
pub trait ToComponents3<S: BaseFloat, R: Rotation3<S>>: ToComponents<Point3<S>, R> {}
|
||||
|
||||
pub trait CompositeTransform<S: BaseFloat, V: Vector<S>, P: Point<S, V>, R: Rotation<S, V, P>>:
|
||||
Transform<S, V, P> + ToComponents<S, V, P, R> {}
|
||||
pub trait CompositeTransform2<S: BaseFloat, R: Rotation2<S>>:
|
||||
Transform2<S> + ToComponents2<S, R> {}
|
||||
pub trait CompositeTransform3<S: BaseFloat, R: Rotation3<S>>:
|
||||
Transform3<S> + ToComponents3<S, R> {}
|
||||
pub trait CompositeTransform<P: Point, R: Rotation<P>>: Transform<P> + ToComponents<P, R> where
|
||||
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
|
||||
<P as Point>::Scalar: BaseFloat,
|
||||
{}
|
||||
|
||||
impl<
|
||||
S: BaseFloat,
|
||||
V: Vector<S> + Clone,
|
||||
P: Point<S, V>,
|
||||
R: Rotation<S, V, P> + Clone,
|
||||
> ToComponents<S, V, P, R> for Decomposed<S, V, R> {
|
||||
fn decompose(&self) -> (V, R, V) {
|
||||
(V::one().mul_s(self.scale), self.rot.clone(), self.disp.clone())
|
||||
pub trait CompositeTransform2<S: BaseFloat, R: Rotation2<S>>: Transform2<S> + ToComponents2<S, R> {}
|
||||
pub trait CompositeTransform3<S: BaseFloat, R: Rotation3<S>>: Transform3<S> + ToComponents3<S, R> {}
|
||||
|
||||
impl<P: Point, R: Rotation<P> + Clone> ToComponents<P, R> for Decomposed<P::Vector, R> where
|
||||
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
|
||||
<P as Point>::Scalar: BaseFloat,
|
||||
{
|
||||
fn decompose(&self) -> (P::Vector, R, P::Vector) {
|
||||
(P::Vector::one().mul_s(self.scale), self.rot.clone(), self.disp.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
S: BaseFloat,
|
||||
R: Rotation2<S> + Clone,
|
||||
> ToComponents2<S, R> for Decomposed<S, Vector2<S>, R> {}
|
||||
impl<S: BaseFloat, R: Rotation2<S> + Clone> ToComponents2<S, R> for Decomposed<Vector2<S>, R> {}
|
||||
impl<S: BaseFloat, R: Rotation3<S> + Clone> ToComponents3<S, R> for Decomposed<Vector3<S>, R> {}
|
||||
|
||||
impl<
|
||||
S: BaseFloat,
|
||||
R: Rotation3<S> + Clone,
|
||||
> ToComponents3<S, R> for Decomposed<S, Vector3<S>, R> {}
|
||||
|
||||
impl<
|
||||
S: BaseFloat + 'static,
|
||||
R: Rotation2<S> + Clone,
|
||||
> CompositeTransform2<S, R> for Decomposed<S, Vector2<S>, R> {}
|
||||
|
||||
impl<
|
||||
S: BaseFloat + 'static,
|
||||
R: Rotation3<S> + Clone,
|
||||
> CompositeTransform3<S, R> for Decomposed<S, Vector3<S>, R> {}
|
||||
impl<S: BaseFloat, R: Rotation2<S> + Clone> CompositeTransform2<S, R> for Decomposed<Vector2<S>, R> {}
|
||||
impl<S: BaseFloat, R: Rotation3<S> + Clone> CompositeTransform3<S, R> for Decomposed<Vector3<S>, R> {}
|
||||
|
|
117
src/vector.rs
117
src/vector.rs
|
@ -111,7 +111,9 @@ use num::{BaseNum, BaseFloat};
|
|||
/// A trait that specifies a range of numeric operations for vectors. Not all
|
||||
/// of these make sense from a linear algebra point of view, but are included
|
||||
/// for pragmatic reasons.
|
||||
pub trait Vector<S: BaseNum>: Array1<S> + Clone // where
|
||||
pub trait Vector: Clone where
|
||||
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
|
||||
Self: Array1<Element = <Self as Vector>::Scalar>,
|
||||
// FIXME: blocked by rust-lang/rust#20671
|
||||
//
|
||||
// for<'a, 'b> &'a Self: Add<&'b Self, Output = Self>,
|
||||
|
@ -127,31 +129,34 @@ pub trait Vector<S: BaseNum>: Array1<S> + Clone // where
|
|||
// for<'a> &'a Self: Div<S, Output = Self>,
|
||||
// for<'a> &'a Self: Rem<S, Output = Self>,
|
||||
{
|
||||
/// The associated scalar.
|
||||
type Scalar: BaseNum;
|
||||
|
||||
/// Construct a vector from a single value, replicating it.
|
||||
fn from_value(s: S) -> Self;
|
||||
fn from_value(scalar: Self::Scalar) -> Self;
|
||||
|
||||
/// The zero vector (with all components set to zero)
|
||||
#[inline]
|
||||
fn zero() -> Self { Self::from_value(S::zero()) }
|
||||
fn zero() -> Self { Self::from_value(Self::Scalar::zero()) }
|
||||
/// The identity vector (with all components set to one)
|
||||
#[inline]
|
||||
fn one() -> Self { Self::from_value(S::one()) }
|
||||
fn one() -> Self { Self::from_value(Self::Scalar::one()) }
|
||||
|
||||
/// Add a scalar to this vector, returning a new vector.
|
||||
#[must_use]
|
||||
fn add_s(&self, s: S) -> Self;
|
||||
fn add_s(&self, scalar: Self::Scalar) -> Self;
|
||||
/// Subtract a scalar from this vector, returning a new vector.
|
||||
#[must_use]
|
||||
fn sub_s(&self, s: S) -> Self;
|
||||
fn sub_s(&self, scalar: Self::Scalar) -> Self;
|
||||
/// Multiply this vector by a scalar, returning a new vector.
|
||||
#[must_use]
|
||||
fn mul_s(&self, s: S) -> Self;
|
||||
fn mul_s(&self, scalar: Self::Scalar) -> Self;
|
||||
/// Divide this vector by a scalar, returning a new vector.
|
||||
#[must_use]
|
||||
fn div_s(&self, s: S) -> Self;
|
||||
fn div_s(&self, scalar: Self::Scalar) -> Self;
|
||||
/// Take the remainder of this vector by a scalar, returning a new vector.
|
||||
#[must_use]
|
||||
fn rem_s(&self, s: S) -> Self;
|
||||
fn rem_s(&self, scalar: Self::Scalar) -> Self;
|
||||
|
||||
/// Add this vector to another, returning a new vector.
|
||||
#[must_use]
|
||||
|
@ -170,15 +175,15 @@ pub trait Vector<S: BaseNum>: Array1<S> + Clone // where
|
|||
fn rem_v(&self, v: &Self) -> Self;
|
||||
|
||||
/// Add a scalar to this vector in-place.
|
||||
fn add_self_s(&mut self, s: S);
|
||||
fn add_self_s(&mut self, scalar: Self::Scalar);
|
||||
/// Subtract a scalar from this vector, in-place.
|
||||
fn sub_self_s(&mut self, s: S);
|
||||
fn sub_self_s(&mut self, scalar: Self::Scalar);
|
||||
/// Multiply this vector by a scalar, in-place.
|
||||
fn mul_self_s(&mut self, s: S);
|
||||
fn mul_self_s(&mut self, scalar: Self::Scalar);
|
||||
/// Divide this vector by a scalar, in-place.
|
||||
fn div_self_s(&mut self, s: S);
|
||||
fn div_self_s(&mut self, scalar: Self::Scalar);
|
||||
/// Take the remainder of this vector by a scalar, in-place.
|
||||
fn rem_self_s(&mut self, s: S);
|
||||
fn rem_self_s(&mut self, scalar: Self::Scalar);
|
||||
|
||||
/// Add another vector to this one, in-place.
|
||||
fn add_self_v(&mut self, v: &Self);
|
||||
|
@ -192,22 +197,22 @@ pub trait Vector<S: BaseNum>: Array1<S> + Clone // where
|
|||
fn rem_self_v(&mut self, v: &Self);
|
||||
|
||||
/// The sum of the components of the vector.
|
||||
fn sum(&self) -> S;
|
||||
fn sum(&self) -> Self::Scalar;
|
||||
/// The product of the components of the vector.
|
||||
fn product(&self) -> S;
|
||||
fn product(&self) -> Self::Scalar;
|
||||
|
||||
/// Vector dot product.
|
||||
#[inline]
|
||||
fn dot(&self, v: &Self) -> S { self.mul_v(v).sum() }
|
||||
fn dot(&self, v: &Self) -> Self::Scalar { self.mul_v(v).sum() }
|
||||
|
||||
/// The minimum component of the vector.
|
||||
fn comp_min(&self) -> S;
|
||||
fn comp_min(&self) -> Self::Scalar;
|
||||
/// The maximum component of the vector.
|
||||
fn comp_max(&self) -> S;
|
||||
fn comp_max(&self) -> Self::Scalar;
|
||||
}
|
||||
|
||||
/// Dot product of two vectors.
|
||||
#[inline] pub fn dot<S: BaseNum, V: Vector<S>>(a: V, b: V) -> S { a.dot(&b) }
|
||||
#[inline] pub fn dot<V: Vector>(a: V, b: V) -> V::Scalar { a.dot(&b) }
|
||||
|
||||
// Utility macro for generating associated functions for the vectors
|
||||
macro_rules! vec {
|
||||
|
@ -245,16 +250,20 @@ macro_rules! vec {
|
|||
}
|
||||
}
|
||||
|
||||
impl<$S: Copy> Array1<$S> for $VectorN<$S> {}
|
||||
impl<S: Copy> Array1 for $VectorN<S> {
|
||||
type Element = S;
|
||||
}
|
||||
|
||||
impl<S: BaseNum> Vector<S> for $VectorN<S> {
|
||||
#[inline] fn from_value(s: S) -> $VectorN<S> { $VectorN { $($field: s),+ } }
|
||||
impl<S: BaseNum> Vector for $VectorN<S> {
|
||||
type Scalar = S;
|
||||
|
||||
#[inline] fn add_s(&self, s: S) -> $VectorN<S> { self + s }
|
||||
#[inline] fn sub_s(&self, s: S) -> $VectorN<S> { self - s }
|
||||
#[inline] fn mul_s(&self, s: S) -> $VectorN<S> { self * s }
|
||||
#[inline] fn div_s(&self, s: S) -> $VectorN<S> { self / s }
|
||||
#[inline] fn rem_s(&self, s: S) -> $VectorN<S> { self % s }
|
||||
#[inline] fn from_value(scalar: S) -> $VectorN<S> { $VectorN { $($field: scalar),+ } }
|
||||
|
||||
#[inline] fn add_s(&self, scalar: S) -> $VectorN<S> { self + scalar }
|
||||
#[inline] fn sub_s(&self, scalar: S) -> $VectorN<S> { self - scalar }
|
||||
#[inline] fn mul_s(&self, scalar: S) -> $VectorN<S> { self * scalar }
|
||||
#[inline] fn div_s(&self, scalar: S) -> $VectorN<S> { self / scalar }
|
||||
#[inline] fn rem_s(&self, scalar: S) -> $VectorN<S> { self % scalar }
|
||||
|
||||
#[inline] fn add_v(&self, v: &$VectorN<S>) -> $VectorN<S> { self + v }
|
||||
#[inline] fn sub_v(&self, v: &$VectorN<S>) -> $VectorN<S> { self - v }
|
||||
|
@ -262,11 +271,11 @@ macro_rules! vec {
|
|||
#[inline] fn div_v(&self, v: &$VectorN<S>) -> $VectorN<S> { self / v }
|
||||
#[inline] fn rem_v(&self, v: &$VectorN<S>) -> $VectorN<S> { self % v }
|
||||
|
||||
#[inline] fn add_self_s(&mut self, s: S) { *self = &*self + s; }
|
||||
#[inline] fn sub_self_s(&mut self, s: S) { *self = &*self - s; }
|
||||
#[inline] fn mul_self_s(&mut self, s: S) { *self = &*self * s; }
|
||||
#[inline] fn div_self_s(&mut self, s: S) { *self = &*self / s; }
|
||||
#[inline] fn rem_self_s(&mut self, s: S) { *self = &*self % s; }
|
||||
#[inline] fn add_self_s(&mut self, scalar: S) { *self = &*self + scalar; }
|
||||
#[inline] fn sub_self_s(&mut self, scalar: S) { *self = &*self - scalar; }
|
||||
#[inline] fn mul_self_s(&mut self, scalar: S) { *self = &*self * scalar; }
|
||||
#[inline] fn div_self_s(&mut self, scalar: S) { *self = &*self / scalar; }
|
||||
#[inline] fn rem_self_s(&mut self, scalar: S) { *self = &*self % scalar; }
|
||||
|
||||
#[inline] fn add_self_v(&mut self, v: &$VectorN<S>) { *self = &*self + v; }
|
||||
#[inline] fn sub_self_v(&mut self, v: &$VectorN<S>) { *self = &*self - v; }
|
||||
|
@ -287,7 +296,9 @@ macro_rules! vec {
|
|||
fn neg(self) -> $VectorN<S> { $VectorN::new($(-self.$field),+) }
|
||||
}
|
||||
|
||||
impl<S: BaseFloat> ApproxEq<S> for $VectorN<S> {
|
||||
impl<S: BaseFloat> ApproxEq for $VectorN<S> {
|
||||
type Epsilon = S;
|
||||
|
||||
#[inline]
|
||||
fn approx_eq_eps(&self, other: &$VectorN<S>, epsilon: &S) -> bool {
|
||||
$(self.$field.approx_eq_eps(&other.$field, epsilon))&&+
|
||||
|
@ -617,44 +628,47 @@ impl<S: BaseNum> Vector4<S> {
|
|||
|
||||
/// Specifies geometric operations for vectors. This is only implemented for
|
||||
/// 2-dimensional and 3-dimensional vectors.
|
||||
pub trait EuclideanVector<S: BaseFloat>: Vector<S>
|
||||
+ ApproxEq<S>
|
||||
+ Sized {
|
||||
pub trait EuclideanVector: Vector + Sized where
|
||||
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
|
||||
<Self as Vector>::Scalar: BaseFloat,
|
||||
Self: ApproxEq<Epsilon = <Self as Vector>::Scalar>,
|
||||
{
|
||||
/// Returns `true` if the vector is perpendicular (at right angles) to the
|
||||
/// other vector.
|
||||
fn is_perpendicular(&self, other: &Self) -> bool {
|
||||
self.dot(other).approx_eq(&S::zero())
|
||||
self.dot(other).approx_eq(&Self::Scalar::zero())
|
||||
}
|
||||
|
||||
/// Returns the squared length of the vector. This does not perform an
|
||||
/// expensive square root operation like in the `length` method and can
|
||||
/// therefore be more efficient for comparing the lengths of two vectors.
|
||||
#[inline]
|
||||
fn length2(&self) -> S {
|
||||
fn length2(&self) -> Self::Scalar {
|
||||
self.dot(self)
|
||||
}
|
||||
|
||||
/// The norm of the vector.
|
||||
#[inline]
|
||||
fn length(&self) -> S {
|
||||
self.dot(self).sqrt()
|
||||
fn length(&self) -> Self::Scalar {
|
||||
// Not sure why these annotations are needed
|
||||
<<Self as Vector>::Scalar as ::rust_num::Float>::sqrt(self.dot(self))
|
||||
}
|
||||
|
||||
/// The angle between the vector and `other`, in radians.
|
||||
fn angle(&self, other: &Self) -> Rad<S>;
|
||||
fn angle(&self, other: &Self) -> Rad<Self::Scalar>;
|
||||
|
||||
/// Returns a vector with the same direction, but with a `length` (or
|
||||
/// `norm`) of `1`.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
fn normalize(&self) -> Self {
|
||||
self.normalize_to(S::one())
|
||||
self.normalize_to(Self::Scalar::one())
|
||||
}
|
||||
|
||||
/// Returns a vector with the same direction and a given `length`.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
fn normalize_to(&self, length: S) -> Self {
|
||||
fn normalize_to(&self, length: Self::Scalar) -> Self {
|
||||
self.mul_s(length / self.length())
|
||||
}
|
||||
|
||||
|
@ -662,47 +676,48 @@ pub trait EuclideanVector<S: BaseFloat>: Vector<S>
|
|||
/// towards the length of `other` by the specified amount.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
fn lerp(&self, other: &Self, amount: S) -> Self {
|
||||
fn lerp(&self, other: &Self, amount: Self::Scalar) -> Self {
|
||||
self.add_v(&other.sub_v(self).mul_s(amount))
|
||||
}
|
||||
|
||||
/// Normalises the vector to a length of `1`.
|
||||
#[inline]
|
||||
fn normalize_self(&mut self) {
|
||||
let rlen = self.length().recip();
|
||||
// Not sure why these annotations are needed
|
||||
let rlen = <<Self as Vector>::Scalar as ::rust_num::Float>::recip(self.length());
|
||||
self.mul_self_s(rlen);
|
||||
}
|
||||
|
||||
/// Normalizes the vector to `length`.
|
||||
#[inline]
|
||||
fn normalize_self_to(&mut self, length: S) {
|
||||
fn normalize_self_to(&mut self, length: Self::Scalar) {
|
||||
let n = length / self.length();
|
||||
self.mul_self_s(n);
|
||||
}
|
||||
|
||||
/// Linearly interpolates the length of the vector towards the length of
|
||||
/// `other` by the specified amount.
|
||||
fn lerp_self(&mut self, other: &Self, amount: S) {
|
||||
fn lerp_self(&mut self, other: &Self, amount: Self::Scalar) {
|
||||
let v = other.sub_v(self).mul_s(amount);
|
||||
self.add_self_v(&v);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: BaseFloat> EuclideanVector<S> for Vector2<S> {
|
||||
impl<S: BaseFloat> EuclideanVector for Vector2<S> {
|
||||
#[inline]
|
||||
fn angle(&self, other: &Vector2<S>) -> Rad<S> {
|
||||
atan2(self.perp_dot(other), self.dot(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: BaseFloat> EuclideanVector<S> for Vector3<S> {
|
||||
impl<S: BaseFloat> EuclideanVector for Vector3<S> {
|
||||
#[inline]
|
||||
fn angle(&self, other: &Vector3<S>) -> Rad<S> {
|
||||
atan2(self.cross(other).length(), self.dot(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: BaseFloat> EuclideanVector<S> for Vector4<S> {
|
||||
impl<S: BaseFloat> EuclideanVector for Vector4<S> {
|
||||
#[inline]
|
||||
fn angle(&self, other: &Vector4<S>) -> Rad<S> {
|
||||
acos(self.dot(other) / (self.length() * other.length()))
|
||||
|
|
|
@ -36,7 +36,7 @@ fn test_look_at() {
|
|||
let eye = Point3::new(0.0f64, 0.0, -5.0);
|
||||
let center = Point3::new(0.0f64, 0.0, 0.0);
|
||||
let up = Vector3::new(1.0f64, 0.0, 0.0);
|
||||
let t: Decomposed<f64,Vector3<f64>,Quaternion<f64>> = Transform::look_at(&eye, ¢er, &up);
|
||||
let t: Decomposed<Vector3<f64>, Quaternion<f64>> = Transform::look_at(&eye, ¢er, &up);
|
||||
let point = Point3::new(1.0f64, 0.0, 0.0);
|
||||
let view_point = Point3::new(0.0f64, 1.0, 5.0);
|
||||
assert!( t.transform_point(&point).approx_eq(&view_point) );
|
||||
|
|
Loading…
Reference in a new issue