diff --git a/src/angle.rs b/src/angle.rs index 0a0075b7..51a48dd4 100644 --- a/src/angle.rs +++ b/src/angle.rs @@ -80,7 +80,7 @@ pub trait Angle > : Clone + Zero + PartialEq + PartialOrd -+ ApproxEq ++ ApproxEq + Neg + Into> + Into> @@ -279,16 +279,18 @@ fmt::Debug for Deg { } } -impl -ApproxEq for Rad { +impl ApproxEq for Rad { + type Epsilon = S; + #[inline] fn approx_eq_eps(&self, other: &Rad, epsilon: &S) -> bool { self.s.approx_eq_eps(&other.s, epsilon) } } -impl -ApproxEq for Deg { +impl ApproxEq for Deg { + type Epsilon = S; + #[inline] fn approx_eq_eps(&self, other: &Deg, epsilon: &S) -> bool { self.s.approx_eq_eps(&other.s, epsilon) diff --git a/src/approx.rs b/src/approx.rs index 9d72430b..901952ef 100644 --- a/src/approx.rs +++ b/src/approx.rs @@ -16,23 +16,26 @@ use rust_num::{Float, NumCast}; use rust_num::traits::cast; -pub trait ApproxEq: Sized { - fn approx_epsilon(_hack: Option) -> 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.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 ); } }) diff --git a/src/array.rs b/src/array.rs index f2e0e59c..ba8fb55a 100644 --- a/src/array.rs +++ b/src/array.rs @@ -18,14 +18,20 @@ use std::ptr; use std::ops::*; /// An array containing elements of type `Element` -pub trait Array1: Index + IndexMut { +pub trait Array1 where + // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 + Self: Index::Element>, + Self: IndexMut::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: Index + IndexMut 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+'static, Row: Array1, Element: Copy>: - Index + IndexMut { +pub trait Array2 where + // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 + Self: Index::Column>, + Self: IndexMut::Column>, +{ + type Element: Copy; + type Column: Array1; + type Row: Array1; + /// 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+'static, Row: Array1, 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); diff --git a/src/matrix.rs b/src/matrix.rs index 1b3df687..bc34d41a 100644 --- a/src/matrix.rs +++ b/src/matrix.rs @@ -249,7 +249,15 @@ impl> Matrix4 { } } -pub trait Matrix + 'static>: Array2 + ApproxEq + Sized // where +pub trait Matrix where + // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 + Self: Array2< + Element = <::ColumnRow as Vector>::Scalar, + Column = ::ColumnRow, + Row = ::ColumnRow, + >, + Self: ApproxEq::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 + 'static>: Array2 + Approx // for<'a> &'a Self: Div, // for<'a> &'a Self: Rem, { + // 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 + 'static>: Array2 + 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 + 'static>: Array2 + 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 + 'static>: Array2 + 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 + 'static>: Array2 + Approx fn is_symmetric(&self) -> bool; } -impl Array2, Vector2, S> for Matrix2 { +impl Array2 for Matrix2 { + type Element = S; + type Column = Vector2; + type Row = Vector2; + #[inline] fn row(&self, r: usize) -> Vector2 { Vector2::new(self[0][r], @@ -373,7 +388,11 @@ impl Array2, Vector2, S> for Matrix2 { } } -impl Array2, Vector3, S> for Matrix3 { +impl Array2 for Matrix3 { + type Element = S; + type Column = Vector3; + type Row = Vector3; + #[inline] fn row(&self, r: usize) -> Vector3 { Vector3::new(self[0][r], @@ -389,7 +408,11 @@ impl Array2, Vector3, S> for Matrix3 { } } -impl Array2, Vector4, S> for Matrix4 { +impl Array2 for Matrix4 { + type Element = S; + type Column = Vector4; + type Row = Vector4; + #[inline] fn row(&self, r: usize) -> Vector4 { Vector4::new(self[0][r], @@ -407,7 +430,9 @@ impl Array2, Vector4, S> for Matrix4 { } } -impl Matrix> for Matrix2 { +impl Matrix for Matrix2 { + type ColumnRow = Vector2; + #[inline] fn from_value(value: S) -> Matrix2 { Matrix2::new(value, S::zero(), @@ -504,7 +529,9 @@ impl Matrix> for Matrix2 { } } -impl Matrix> for Matrix3 { +impl Matrix for Matrix3 { + type ColumnRow = Vector3; + #[inline] fn from_value(value: S) -> Matrix3 { Matrix3::new(value, S::zero(), S::zero(), @@ -620,7 +647,9 @@ impl Matrix> for Matrix3 { } } -impl Matrix> for Matrix4 { +impl Matrix for Matrix4 { + type ColumnRow = Vector4; + #[inline] fn from_value(value: S) -> Matrix4 { Matrix4::new(value, S::zero(), S::zero(), S::zero(), @@ -790,7 +819,9 @@ impl Matrix> for Matrix4 { } } -impl ApproxEq for Matrix2 { +impl ApproxEq for Matrix2 { + type Epsilon = S; + #[inline] fn approx_eq_eps(&self, other: &Matrix2, epsilon: &S) -> bool { self[0].approx_eq_eps(&other[0], epsilon) && @@ -798,7 +829,9 @@ impl ApproxEq for Matrix2 { } } -impl ApproxEq for Matrix3 { +impl ApproxEq for Matrix3 { + type Epsilon = S; + #[inline] fn approx_eq_eps(&self, other: &Matrix3, epsilon: &S) -> bool { self[0].approx_eq_eps(&other[0], epsilon) && @@ -807,7 +840,9 @@ impl ApproxEq for Matrix3 { } } -impl ApproxEq for Matrix4 { +impl ApproxEq for Matrix4 { + type Epsilon = S; + #[inline] fn approx_eq_eps(&self, other: &Matrix4, epsilon: &S) -> bool { self[0].approx_eq_eps(&other[0], epsilon) && diff --git a/src/num.rs b/src/num.rs index 787edb0f..9811d17f 100644 --- a/src/num.rs +++ b/src/num.rs @@ -110,7 +110,7 @@ impl BaseInt for u64 {} impl BaseInt for usize {} /// Base floating point types -pub trait BaseFloat : BaseNum + Float + ApproxEq {} +pub trait BaseFloat : BaseNum + Float + ApproxEq {} impl BaseFloat for f32 {} impl BaseFloat for f64 {} diff --git a/src/point.rs b/src/point.rs index 613e1df1..c2d05682 100644 --- a/src/point.rs +++ b/src/point.rs @@ -66,7 +66,9 @@ impl Point3 { } /// Specifies the numeric operations for point types. -pub trait Point>: Array1 + Clone // where +pub trait Point: Clone where + // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 + Self: Array1::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>: Array1 + Clone // where // for<'a> &'a Self: Div, // for<'a> &'a Self: Rem, { + /// 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; + /// 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>: Array1 + Clone // where fn max(&self, p: &Self) -> Self; } -impl Array1 for Point2 {} +impl Array1 for Point2 { + type Element = S; +} + +impl Point for Point2 { + type Scalar = S; + type Vector = Vector2; -impl Point> for Point2 { #[inline] fn origin() -> Point2 { Point2::new(S::zero(), S::zero()) @@ -138,28 +153,28 @@ impl Point> for Point2 { Vector2::new(self.x, self.y) } - #[inline] fn mul_s(&self, s: S) -> Point2 { self * s } - #[inline] fn div_s(&self, s: S) -> Point2 { self / s } - #[inline] fn rem_s(&self, s: S) -> Point2 { self % s } + #[inline] fn mul_s(&self, scalar: S) -> Point2 { self * scalar } + #[inline] fn div_s(&self, scalar: S) -> Point2 { self / scalar } + #[inline] fn rem_s(&self, scalar: S) -> Point2 { self % scalar } #[inline] fn add_v(&self, v: &Vector2) -> Point2 { self + v } #[inline] fn sub_p(&self, p: &Point2) -> Vector2 { 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 Point> for Point2 { } } -impl ApproxEq for Point2 { +impl ApproxEq for Point2 { + type Epsilon = S; + #[inline] fn approx_eq_eps(&self, other: &Point2, epsilon: &S) -> bool { self.x.approx_eq_eps(&other.x, epsilon) && @@ -193,9 +210,14 @@ impl ApproxEq for Point2 { } } -impl Array1 for Point3 {} +impl Array1 for Point3 { + type Element = S; +} + +impl Point for Point3 { + type Scalar = S; + type Vector = Vector3; -impl Point> for Point3 { #[inline] fn origin() -> Point3 { Point3::new(S::zero(), S::zero(), S::zero()) @@ -211,31 +233,31 @@ impl Point> for Point3 { Vector3::new(self.x, self.y, self.z) } - #[inline] fn mul_s(&self, s: S) -> Point3 { self * s } - #[inline] fn div_s(&self, s: S) -> Point3 { self / s } - #[inline] fn rem_s(&self, s: S) -> Point3 { self % s } + #[inline] fn mul_s(&self, scalar: S) -> Point3 { self * scalar } + #[inline] fn div_s(&self, scalar: S) -> Point3 { self / scalar } + #[inline] fn rem_s(&self, scalar: S) -> Point3 { self % scalar } #[inline] fn add_v(&self, v: &Vector3) -> Point3 { self + v } #[inline] fn sub_p(&self, p: &Point3) -> Vector3 { 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 Point> for Point3 { } } -impl ApproxEq for Point3 { +impl ApproxEq for Point3 { + type Epsilon = S; + #[inline] fn approx_eq_eps(&self, other: &Point3, epsilon: &S) -> bool { self.x.approx_eq_eps(&other.x, epsilon) && @@ -279,8 +303,8 @@ macro_rules! impl_operators { type Output = $PointN; #[inline] - fn mul(self, s: S) -> $PointN { - $PointN::new($(self.$field * s),+) + fn mul(self, scalar: S) -> $PointN { + $PointN::new($(self.$field * scalar),+) } } @@ -288,8 +312,8 @@ macro_rules! impl_operators { type Output = $PointN; #[inline] - fn div(self, s: S) -> $PointN { - $PointN::new($(self.$field / s),+) + fn div(self, scalar: S) -> $PointN { + $PointN::new($(self.$field / scalar),+) } } @@ -297,8 +321,8 @@ macro_rules! impl_operators { type Output = $PointN; #[inline] - fn rem(self, s: S) -> $PointN { - $PointN::new($(self.$field % s),+) + fn rem(self, scalar: S) -> $PointN { + $PointN::new($(self.$field % scalar),+) } } diff --git a/src/quaternion.rs b/src/quaternion.rs index 29ddcc53..b40799f7 100644 --- a/src/quaternion.rs +++ b/src/quaternion.rs @@ -40,7 +40,9 @@ pub struct Quaternion { pub v: Vector3, } -impl Array1 for Quaternion {} +impl Array1 for Quaternion { + type Element = S; +} impl Quaternion { /// Construct a new quaternion from one scalar component and three @@ -170,7 +172,9 @@ impl<'a, 'b, S: BaseFloat> Mul<&'b Quaternion> for &'a Quaternion { } } -impl ApproxEq for Quaternion { +impl ApproxEq for Quaternion { + type Epsilon = S; + #[inline] fn approx_eq_eps(&self, other: &Quaternion, epsilon: &S) -> bool { self.s.approx_eq_eps(&other.s, epsilon) && @@ -339,7 +343,7 @@ impl From> for Basis3 { fn from(quat: Quaternion) -> Basis3 { Basis3::from_quaternion(&quat) } } -impl Rotation, Point3> for Quaternion { +impl Rotation> for Quaternion { #[inline] fn one() -> Quaternion { Quaternion::one() } diff --git a/src/rotation.rs b/src/rotation.rs index ec683d9f..068bfccf 100644 --- a/src/rotation.rs +++ b/src/rotation.rs @@ -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, P: Point>: PartialEq + ApproxEq + Sized { +pub trait Rotation: PartialEq + Sized where + // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 + Self: ApproxEq::Scalar>, +

::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, P: Point>: PartialEq + Appr } /// A two-dimensional rotation. -pub trait Rotation2: Rotation, Point2> +pub trait Rotation2: Rotation> + Into> + Into> { /// Create a rotation by a given angle. Thus is a redundant case of both @@ -76,7 +80,7 @@ pub trait Rotation2: Rotation, Point2> } /// A three-dimensional rotation. -pub trait Rotation3: Rotation, Point3> +pub trait Rotation3: Rotation> + Into> + Into> + Into> { @@ -172,7 +176,7 @@ impl From> for Matrix2 { fn from(b: Basis2) -> Matrix2 { b.mat } } -impl Rotation, Point2> for Basis2 { +impl Rotation> for Basis2 { #[inline] fn one() -> Basis2 { Basis2 { mat: Matrix2::one() } } @@ -206,14 +210,16 @@ impl Rotation, Point2> for Basis2 { fn invert_self(&mut self) { self.mat.invert_self(); } } -impl ApproxEq for Basis2 { +impl ApproxEq for Basis2 { + type Epsilon = S; + #[inline] fn approx_eq_eps(&self, other: &Basis2, epsilon: &S) -> bool { self.mat.approx_eq_eps(&other.mat, epsilon) } } -impl Rotation2 for Basis2 { +impl Rotation2 for Basis2 { fn from_angle(theta: Rad) -> Basis2 { Basis2 { mat: Matrix2::from_angle(theta) } } } @@ -248,12 +254,12 @@ impl From> for Matrix3 { fn from(b: Basis3) -> Matrix3 { b.mat } } -impl From> for Quaternion { +impl From> for Quaternion { #[inline] fn from(b: Basis3) -> Quaternion { b.mat.into() } } -impl Rotation, Point3> for Basis3 { +impl Rotation> for Basis3 { #[inline] fn one() -> Basis3 { Basis3 { mat: Matrix3::one() } } @@ -288,14 +294,16 @@ impl Rotation, Point3> for Basis3 { fn invert_self(&mut self) { self.mat.invert_self(); } } -impl ApproxEq for Basis3 { +impl ApproxEq for Basis3 { + type Epsilon = S; + #[inline] fn approx_eq_eps(&self, other: &Basis3, epsilon: &S) -> bool { self.mat.approx_eq_eps(&other.mat, epsilon) } } -impl Rotation3 for Basis3 { +impl Rotation3 for Basis3 { fn from_axis_angle(axis: &Vector3, angle: Rad) -> Basis3 { Basis3 { mat: Matrix3::from_axis_angle(axis, angle) } } diff --git a/src/transform.rs b/src/transform.rs index 6560eb28..a1583ab7 100644 --- a/src/transform.rs +++ b/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, P: Point>: Sized { +pub trait Transform: 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, P: Point>: Sized { /// A generic transformation consisting of a rotation, /// displacement vector and scale amount. #[derive(Copy, Clone, RustcEncodable, RustcDecodable)] -pub struct Decomposed { - pub scale: S, +pub struct Decomposed { + pub scale: V::Scalar, pub rot: R, pub disp: V, } -impl< - S: BaseFloat, - V: Vector, - P: Point, - R: Rotation, -> Transform for Decomposed { +impl> Transform

for Decomposed where + // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 +

::Scalar: BaseFloat, +{ #[inline] - fn one() -> Decomposed { + fn one() -> Decomposed { Decomposed { - scale: S::one(), + scale:

::Scalar::one(), rot: R::one(), - disp: V::zero(), + disp: P::Vector::zero(), } } #[inline] - fn look_at(eye: &P, center: &P, up: &V) -> Decomposed { + fn look_at(eye: &P, center: &P, up: &P::Vector) -> Decomposed { 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:

::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) -> Decomposed { + fn concat(&self, other: &Decomposed) -> Decomposed { Decomposed { scale: self.scale * other.scale, rot: self.rot.concat(&other.rot), @@ -122,11 +120,11 @@ impl< } } - fn invert(&self) -> Option> { - if self.scale.approx_eq(&S::zero()) { + fn invert(&self) -> Option> { + if self.scale.approx_eq(&

::Scalar::zero()) { None } else { - let s = S::one() / self.scale; + let s =

::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: Transform, Point2> + Into> {} -pub trait Transform3: Transform, Point3> + Into> {} +pub trait Transform2: Transform> + Into> {} +pub trait Transform3: Transform> + Into> {} -impl< - S: BaseFloat + 'static, - R: Rotation2, -> From, R>> for Matrix3 { - fn from(dec: Decomposed, R>) -> Matrix3 { +impl> From, R>> for Matrix3 { + fn from(dec: Decomposed, R>) -> Matrix3 { 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, -> From, R>> for Matrix4 { - fn from(dec: Decomposed, R>) -> Matrix4 { +impl> From, R>> for Matrix4 { + fn from(dec: Decomposed, R>) -> Matrix4 { 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, -> Transform2 for Decomposed, R> {} +impl> Transform2 for Decomposed, R> {} -impl< - S: BaseFloat + 'static, - R: Rotation3, -> Transform3 for Decomposed, R> {} +impl> Transform3 for Decomposed, R> {} -impl< - S: BaseFloat, - R: fmt::Debug + Rotation3, -> fmt::Debug for Decomposed, R> { +impl> fmt::Debug for Decomposed, 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 { pub mat: Matrix4, } -impl Transform, Point3> for AffineMatrix3 { +impl Transform> for AffineMatrix3 { #[inline] fn one() -> AffineMatrix3 { AffineMatrix3 { mat: Matrix4::one() } @@ -227,54 +210,40 @@ impl From> for Matrix4 { #[inline] fn from(aff: AffineMatrix3) -> Matrix4 { aff.mat } } -impl Transform3 for AffineMatrix3 {} +impl Transform3 for AffineMatrix3 {} /// A trait that allows extracting components (rotation, translation, scale) /// from an arbitrary transformations -pub trait ToComponents, P: Point, R: Rotation> { +pub trait ToComponents> where + // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 +

::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>: - ToComponents, Point2, R> {} -pub trait ToComponents3>: - ToComponents, Point3, R> {} - -pub trait CompositeTransform, P: Point, R: Rotation>: - Transform + ToComponents {} -pub trait CompositeTransform2>: - Transform2 + ToComponents2 {} -pub trait CompositeTransform3>: - Transform3 + ToComponents3 {} - -impl< - S: BaseFloat, - V: Vector + Clone, - P: Point, - R: Rotation + Clone, -> ToComponents for Decomposed { - fn decompose(&self) -> (V, R, V) { - (V::one().mul_s(self.scale), self.rot.clone(), self.disp.clone()) +pub trait ToComponents2>: ToComponents, R> {} +pub trait ToComponents3>: ToComponents, R> {} + +pub trait CompositeTransform>: Transform

+ ToComponents where + // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 +

::Scalar: BaseFloat, +{} + +pub trait CompositeTransform2>: Transform2 + ToComponents2 {} +pub trait CompositeTransform3>: Transform3 + ToComponents3 {} + +impl + Clone> ToComponents for Decomposed where + // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 +

::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 + Clone, -> ToComponents2 for Decomposed, R> {} - -impl< - S: BaseFloat, - R: Rotation3 + Clone, -> ToComponents3 for Decomposed, R> {} - -impl< - S: BaseFloat + 'static, - R: Rotation2 + Clone, -> CompositeTransform2 for Decomposed, R> {} - -impl< - S: BaseFloat + 'static, - R: Rotation3 + Clone, -> CompositeTransform3 for Decomposed, R> {} +impl + Clone> ToComponents2 for Decomposed, R> {} +impl + Clone> ToComponents3 for Decomposed, R> {} + +impl + Clone> CompositeTransform2 for Decomposed, R> {} +impl + Clone> CompositeTransform3 for Decomposed, R> {} diff --git a/src/vector.rs b/src/vector.rs index 4acbb516..2b11b163 100644 --- a/src/vector.rs +++ b/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: Array1 + Clone // where +pub trait Vector: Clone where + // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 + Self: Array1::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: Array1 + Clone // where // for<'a> &'a Self: Div, // for<'a> &'a Self: Rem, { + /// 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: Array1 + 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: Array1 + 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>(a: V, b: V) -> S { a.dot(&b) } +#[inline] pub fn dot(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 Array1 for $VectorN { + type Element = S; + } + + impl Vector for $VectorN { + type Scalar = S; - impl Vector for $VectorN { - #[inline] fn from_value(s: S) -> $VectorN { $VectorN { $($field: s),+ } } + #[inline] fn from_value(scalar: S) -> $VectorN { $VectorN { $($field: scalar),+ } } - #[inline] fn add_s(&self, s: S) -> $VectorN { self + s } - #[inline] fn sub_s(&self, s: S) -> $VectorN { self - s } - #[inline] fn mul_s(&self, s: S) -> $VectorN { self * s } - #[inline] fn div_s(&self, s: S) -> $VectorN { self / s } - #[inline] fn rem_s(&self, s: S) -> $VectorN { self % s } + #[inline] fn add_s(&self, scalar: S) -> $VectorN { self + scalar } + #[inline] fn sub_s(&self, scalar: S) -> $VectorN { self - scalar } + #[inline] fn mul_s(&self, scalar: S) -> $VectorN { self * scalar } + #[inline] fn div_s(&self, scalar: S) -> $VectorN { self / scalar } + #[inline] fn rem_s(&self, scalar: S) -> $VectorN { self % scalar } #[inline] fn add_v(&self, v: &$VectorN) -> $VectorN { self + v } #[inline] fn sub_v(&self, v: &$VectorN) -> $VectorN { self - v } @@ -262,11 +271,11 @@ macro_rules! vec { #[inline] fn div_v(&self, v: &$VectorN) -> $VectorN { self / v } #[inline] fn rem_v(&self, v: &$VectorN) -> $VectorN { 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) { *self = &*self + v; } #[inline] fn sub_self_v(&mut self, v: &$VectorN) { *self = &*self - v; } @@ -287,7 +296,9 @@ macro_rules! vec { fn neg(self) -> $VectorN { $VectorN::new($(-self.$field),+) } } - impl ApproxEq for $VectorN { + impl ApproxEq for $VectorN { + type Epsilon = S; + #[inline] fn approx_eq_eps(&self, other: &$VectorN, epsilon: &S) -> bool { $(self.$field.approx_eq_eps(&other.$field, epsilon))&&+ @@ -617,44 +628,47 @@ impl Vector4 { /// Specifies geometric operations for vectors. This is only implemented for /// 2-dimensional and 3-dimensional vectors. -pub trait EuclideanVector: Vector - + ApproxEq - + Sized { +pub trait EuclideanVector: Vector + Sized where + // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 + ::Scalar: BaseFloat, + Self: ApproxEq::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 + <::Scalar as ::rust_num::Float>::sqrt(self.dot(self)) } /// The angle between the vector and `other`, in radians. - fn angle(&self, other: &Self) -> Rad; + fn angle(&self, other: &Self) -> Rad; /// 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: Vector /// 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 = <::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 EuclideanVector for Vector2 { +impl EuclideanVector for Vector2 { #[inline] fn angle(&self, other: &Vector2) -> Rad { atan2(self.perp_dot(other), self.dot(other)) } } -impl EuclideanVector for Vector3 { +impl EuclideanVector for Vector3 { #[inline] fn angle(&self, other: &Vector3) -> Rad { atan2(self.cross(other).length(), self.dot(other)) } } -impl EuclideanVector for Vector4 { +impl EuclideanVector for Vector4 { #[inline] fn angle(&self, other: &Vector4) -> Rad { acos(self.dot(other) / (self.length() * other.length())) diff --git a/tests/transform.rs b/tests/transform.rs index e6654d8e..51e27f0f 100644 --- a/tests/transform.rs +++ b/tests/transform.rs @@ -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,Quaternion> = Transform::look_at(&eye, ¢er, &up); + let t: Decomposed, Quaternion> = 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) );