From 669e43ab59d28b6a3bc997195c88feb4aae1f47f Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Tue, 3 Nov 2015 15:23:22 +1100 Subject: [PATCH] Make scalar type parametrs out of transform and rotation traits --- src/point.rs | 88 +++++++++++++++++++++++----------------------- src/quaternion.rs | 2 +- src/rotation.rs | 12 ++++--- src/transform.rs | 84 +++++++++++++++++++++---------------------- src/vector.rs | 35 +++++++++--------- tests/transform.rs | 2 +- 6 files changed, 114 insertions(+), 109 deletions(-) diff --git a/src/point.rs b/src/point.rs index 11756ce..a40d967 100644 --- a/src/point.rs +++ b/src/point.rs @@ -66,7 +66,7 @@ impl Point3 { } /// Specifies the numeric operations for point types. -pub trait Point: Array1 + Clone // where +pub trait Point: Array1::Vector as Vector>::Scalar> + Clone // where // FIXME: blocked by rust-lang/rust#20671 // // for<'a, 'b> &'a Self: Add<&'b V, Output = Self>, @@ -77,7 +77,7 @@ pub trait Point: Array1 + Clone // where // for<'a> &'a Self: Rem, { /// The associated displacement vector. - type Vector: Vector; + type Vector: Vector; /// Create a point at the origin. fn origin() -> Self; @@ -89,13 +89,13 @@ pub trait Point: Array1 + Clone // where /// Multiply each component by a scalar, returning the new point. #[must_use] - fn mul_s(&self, s: S) -> Self; + fn mul_s(&self, scalar: <::Vector as Vector>::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: <::Vector as Vector>::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: <::Vector as Vector>::Scalar) -> Self; /// Add a vector to this point, returning the new point. #[must_use] @@ -104,17 +104,17 @@ pub trait Point: Array1 + Clone // where 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: <::Vector as Vector>::Scalar); /// Divide each component by a scalar, in-place. - fn div_self_s(&mut self, s: S); + fn div_self_s(&mut self, scalar: <::Vector as Vector>::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: <::Vector as Vector>::Scalar); /// Add a vector to this point, in-place. fn add_self_v(&mut self, v: &Self::Vector); /// This is a weird one, but its useful for plane calculations. - fn dot(&self, v: &Self::Vector) -> S; + fn dot(&self, v: &Self::Vector) -> <::Vector as Vector>::Scalar; #[must_use] fn min(&self, p: &Self) -> Self; @@ -127,7 +127,7 @@ impl Array1 for Point2 { type Element = S; } -impl Point for Point2 { +impl Point for Point2 { type Vector = Vector2; #[inline] @@ -145,28 +145,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: <::Vector as Vector>::Scalar) -> Point2 { self * scalar } + #[inline] fn div_s(&self, scalar: <::Vector as Vector>::Scalar) -> Point2 { self / scalar } + #[inline] fn rem_s(&self, scalar: <::Vector as Vector>::Scalar) -> 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: <::Vector as Vector>::Scalar) { + 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: <::Vector as Vector>::Scalar) { + 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: <::Vector as Vector>::Scalar) { + self.x = self.x % scalar; + self.y = self.y % scalar; } #[inline] @@ -206,7 +206,7 @@ impl Array1 for Point3 { type Element = S; } -impl Point for Point3 { +impl Point for Point3 { type Vector = Vector3; #[inline] @@ -224,31 +224,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: <::Vector as Vector>::Scalar) -> Point3 { self * scalar } + #[inline] fn div_s(&self, scalar: <::Vector as Vector>::Scalar) -> Point3 { self / scalar } + #[inline] fn rem_s(&self, scalar: <::Vector as Vector>::Scalar) -> 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: <::Vector as Vector>::Scalar) { + 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: <::Vector as Vector>::Scalar) { + 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: <::Vector as Vector>::Scalar) { + self.x = self.x % scalar; + self.y = self.y % scalar; + self.z = self.z % scalar; } #[inline] @@ -294,8 +294,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),+) } } @@ -303,8 +303,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),+) } } @@ -312,8 +312,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 6c9635a..b40799f 100644 --- a/src/quaternion.rs +++ b/src/quaternion.rs @@ -343,7 +343,7 @@ impl From> for Basis3 { fn from(quat: Quaternion) -> Basis3 { Basis3::from_quaternion(&quat) } } -impl Rotation> for Quaternion { +impl Rotation> for Quaternion { #[inline] fn one() -> Quaternion { Quaternion::one() } diff --git a/src/rotation.rs b/src/rotation.rs index eb3930e..b2c7c42 100644 --- a/src/rotation.rs +++ b/src/rotation.rs @@ -25,7 +25,9 @@ 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>: PartialEq + ApproxEq + Sized { +pub trait Rotation: PartialEq + ApproxEq::Vector as Vector>::Scalar> + Sized where + <

::Vector as Vector>::Scalar: BaseFloat, +{ /// Create the identity transform (causes no transformation). fn one() -> Self; @@ -67,7 +69,7 @@ pub trait Rotation>: PartialEq + ApproxEq } /// A two-dimensional rotation. -pub trait Rotation2: Rotation> +pub trait Rotation2: Rotation> + Into> + Into> { /// Create a rotation by a given angle. Thus is a redundant case of both @@ -76,7 +78,7 @@ pub trait Rotation2: Rotation> } /// A three-dimensional rotation. -pub trait Rotation3: Rotation> +pub trait Rotation3: Rotation> + Into> + Into> + Into> { @@ -172,7 +174,7 @@ impl From> for Matrix2 { fn from(b: Basis2) -> Matrix2 { b.mat } } -impl Rotation> for Basis2 { +impl Rotation> for Basis2 { #[inline] fn one() -> Basis2 { Basis2 { mat: Matrix2::one() } } @@ -255,7 +257,7 @@ impl From> for Quaternion { fn from(b: Basis3) -> Quaternion { b.mat.into() } } -impl Rotation> for Basis3 { +impl Rotation> for Basis3 { #[inline] fn one() -> Basis3 { Basis3 { mat: Matrix3::one() } } diff --git a/src/transform.rs b/src/transform.rs index 900df11..d732b24 100644 --- a/src/transform.rs +++ b/src/transform.rs @@ -27,7 +27,7 @@ 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>: Sized { +pub trait Transform: Sized { /// Create an identity transformation. That is, a transformation which /// does nothing. fn one() -> Self; @@ -72,28 +72,30 @@ pub trait Transform>: 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, R: Rotation> Transform for Decomposed { +impl> Transform

for Decomposed where + <

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

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

::Vector as Vector>::Scalar::one(), rot: rot, disp: disp, } @@ -109,7 +111,7 @@ impl, R: Rotation> Transform for Decompose 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), @@ -117,11 +119,11 @@ impl, R: Rotation> Transform for Decompose } } - fn invert(&self) -> Option> { - if self.scale.approx_eq(&S::zero()) { + fn invert(&self) -> Option> { + if self.scale.approx_eq(&<

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

::Vector as Vector>::Scalar::one() / self.scale; let r = self.rot.invert(); let d = r.rotate_vector(&self.disp).mul_s(-s); Some(Decomposed { @@ -133,11 +135,11 @@ impl, R: Rotation> Transform for Decompose } } -pub trait Transform2: Transform> + Into> {} -pub trait Transform3: Transform> + Into> {} +pub trait Transform2: Transform> + Into> {} +pub trait Transform3: Transform> + Into> {} -impl> 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()); @@ -145,8 +147,8 @@ impl> From, R>> for Matri } } -impl> 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()); @@ -154,11 +156,11 @@ impl> From, R>> for Matri } } -impl> Transform2 for Decomposed, R> {} +impl> Transform2 for Decomposed, R> {} -impl> Transform3 for Decomposed, R> {} +impl> Transform3 for Decomposed, R> {} -impl> 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) @@ -171,7 +173,7 @@ pub struct AffineMatrix3 { pub mat: Matrix4, } -impl Transform> for AffineMatrix3 { +impl Transform> for AffineMatrix3 { #[inline] fn one() -> AffineMatrix3 { AffineMatrix3 { mat: Matrix4::one() } @@ -211,35 +213,33 @@ impl Transform3 for AffineMatrix3 {} /// A trait that allows extracting components (rotation, translation, scale) /// from an arbitrary transformations -pub trait ToComponents, R: Rotation> { +pub trait ToComponents> where + <

::Vector as Vector>::Scalar: BaseFloat, +{ /// Extract the (scale, rotation, translation) triple fn decompose(&self) -> (P::Vector, R, P::Vector); } -pub trait ToComponents2>: - ToComponents, R> {} -pub trait ToComponents3>: - ToComponents, R> {} +pub trait ToComponents2>: ToComponents, R> {} +pub trait ToComponents3>: ToComponents, R> {} -pub trait CompositeTransform, R: Rotation>: - Transform + ToComponents {} -pub trait CompositeTransform2>: - Transform2 + ToComponents2 {} -pub trait CompositeTransform3>: - Transform3 + ToComponents3 {} +pub trait CompositeTransform>: Transform

+ ToComponents where + <

::Vector as Vector>::Scalar: BaseFloat, +{} -impl< - S: BaseFloat, - P: Point, - R: Rotation + Clone, -> ToComponents for Decomposed { +pub trait CompositeTransform2>: Transform2 + ToComponents2 {} +pub trait CompositeTransform3>: Transform3 + ToComponents3 {} + +impl + Clone> ToComponents for Decomposed where + <

::Vector as Vector>::Scalar: BaseFloat, +{ fn decompose(&self) -> (P::Vector, R, P::Vector) { (P::Vector::one().mul_s(self.scale), self.rot.clone(), self.disp.clone()) } } -impl + Clone> ToComponents2 for Decomposed, R> {} -impl + Clone> ToComponents3 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> {} +impl + Clone> CompositeTransform2 for Decomposed, R> {} +impl + Clone> CompositeTransform3 for Decomposed, R> {} diff --git a/src/vector.rs b/src/vector.rs index fdd08be..73a092b 100644 --- a/src/vector.rs +++ b/src/vector.rs @@ -127,7 +127,7 @@ pub trait Vector: Array1::Scalar> + Clone // where // for<'a> &'a Self: Div, // for<'a> &'a Self: Rem, { - // The associated scalar + /// The associated scalar. type Scalar: BaseNum; /// Construct a vector from a single value, replicating it. @@ -626,42 +626,45 @@ impl Vector4 { /// Specifies geometric operations for vectors. This is only implemented for /// 2-dimensional and 3-dimensional vectors. -pub trait EuclideanVector: Vector + ApproxEq::Scalar> + Sized { +pub trait EuclideanVector: Vector + Sized where + ::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 { + <::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()) } @@ -669,47 +672,47 @@ pub trait EuclideanVector: Vector + ApproxEq 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(); + 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 e6654d8..51e27f0 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) );