From 2b36ea2ef981d7c12943a446fa25d42588cad3b9 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Fri, 8 Apr 2016 08:46:35 +1000 Subject: [PATCH 1/6] Rename Vector trait to VectorSpace and EuclideanVector to InnerSpace --- src/matrix.rs | 2 +- src/point.rs | 2 +- src/prelude.rs | 4 ++-- src/quaternion.rs | 2 +- src/rotation.rs | 2 +- src/transform.rs | 4 ++-- src/vector.rs | 38 +++++++++++++++++++------------------- 7 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/matrix.rs b/src/matrix.rs index aa1aaf2..e509dd2 100644 --- a/src/matrix.rs +++ b/src/matrix.rs @@ -31,7 +31,7 @@ use array::Array; use num::BaseFloat; use point::{Point, Point3}; use quaternion::Quaternion; -use vector::{Vector, EuclideanVector}; +use vector::{VectorSpace, InnerSpace}; use vector::{Vector2, Vector3, Vector4}; /// A 2 x 2, column major matrix diff --git a/src/point.rs b/src/point.rs index e35877c..a16059b 100644 --- a/src/point.rs +++ b/src/point.rs @@ -143,7 +143,7 @@ pub trait Point: Copy + Clone where type Scalar: BaseNum; /// The associated space of displacement vectors. - type Vector: Vector; + type Vector: VectorSpace; /// The point at the origin of the Euclidean space. fn origin() -> Self; diff --git a/src/prelude.rs b/src/prelude.rs index edbfc0f..1378f96 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -20,5 +20,5 @@ pub use transform::Transform; pub use transform::Transform2; pub use transform::Transform3; -pub use vector::EuclideanVector; -pub use vector::Vector; +pub use vector::InnerSpace; +pub use vector::VectorSpace; diff --git a/src/quaternion.rs b/src/quaternion.rs index 880359d..9a04f92 100644 --- a/src/quaternion.rs +++ b/src/quaternion.rs @@ -26,7 +26,7 @@ use matrix::{Matrix3, Matrix4}; use num::BaseFloat; use point::Point3; use rotation::{Rotation, Rotation3, Basis3}; -use vector::{Vector3, Vector, EuclideanVector}; +use vector::{Vector3, VectorSpace, InnerSpace}; /// A [quaternion](https://en.wikipedia.org/wiki/Quaternion) in scalar/vector diff --git a/src/rotation.rs b/src/rotation.rs index 614a5ac..bff231c 100644 --- a/src/rotation.rs +++ b/src/rotation.rs @@ -22,7 +22,7 @@ use matrix::{Matrix2, Matrix3}; use num::BaseFloat; use point::{Point, Point2, Point3}; use quaternion::Quaternion; -use vector::{EuclideanVector, Vector2, Vector3}; +use vector::{InnerSpace, 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. diff --git a/src/transform.rs b/src/transform.rs index 59e6826..7896c8f 100644 --- a/src/transform.rs +++ b/src/transform.rs @@ -72,7 +72,7 @@ pub trait Transform: Sized { /// A generic transformation consisting of a rotation, /// displacement vector and scale amount. #[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)] -pub struct Decomposed { +pub struct Decomposed { pub scale: V::Scalar, pub rot: R, pub disp: V, @@ -82,7 +82,7 @@ impl> Transform

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

::Scalar: BaseFloat, // FIXME: Investigate why this is needed! -

::Vector: Vector, +

::Vector: VectorSpace, { #[inline] fn one() -> Decomposed { diff --git a/src/vector.rs b/src/vector.rs index 659527f..ffbeff6 100644 --- a/src/vector.rs +++ b/src/vector.rs @@ -22,7 +22,7 @@ //! vector are also provided: //! //! ```rust -//! use cgmath::{Vector, Vector2, Vector3, Vector4, vec3}; +//! use cgmath::{VectorSpace, Vector2, Vector3, Vector4, vec3}; //! //! assert_eq!(Vector2::new(1.0f64, 0.0f64), Vector2::unit_x()); //! assert_eq!(vec3(0.0f64, 0.0f64, 0.0f64), Vector3::zero()); @@ -33,7 +33,7 @@ //! using the built-in operators. //! //! ```rust -//! use cgmath::{Vector, Vector2, Vector3, Vector4}; +//! use cgmath::{VectorSpace, Vector2, Vector3, Vector4}; //! //! let a: Vector2 = Vector2::new(3.0, 4.0); //! let b: Vector2 = Vector2::new(-3.0, -4.0); @@ -61,7 +61,7 @@ //! and [cross products](http://en.wikipedia.org/wiki/Cross_product). //! //! ```rust -//! use cgmath::{Vector, EuclideanVector}; +//! use cgmath::{VectorSpace, InnerSpace}; //! use cgmath::{Vector2, Vector3, Vector4}; //! //! // All vectors implement the dot product as a method: @@ -83,9 +83,9 @@ //! the methods provided by the [`Array`](../array/trait.Array.html) trait. //! This trait also provides a `map()` method for applying arbitrary functions. //! -//! The [`Vector`](../trait.Vector.html) trait presents the most general -//! features of the vectors, while [`EuclideanVector`] -//! (../array/trait.EuclideanVector.html) is more specific to Euclidean space. +//! The [`VectorSpace`](../trait.VectorSpace.html) trait presents the most +//! general features of the vectors, while [`InnerSpace`] +//! (../array/trait.InnerSpace.html) is more specific to Euclidean space. use std::fmt; use std::mem; @@ -143,16 +143,16 @@ use num::{BaseNum, BaseFloat, PartialOrd}; /// let upscaled_translation = translation * scale_factor; /// let downscaled_translation = translation / scale_factor; /// ``` -pub trait Vector: Copy + Clone where +pub trait VectorSpace: Copy + Clone where // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 - Self: Array::Scalar>, + Self: Array::Scalar>, Self: Add, Self: Sub, - Self: Mul<::Scalar, Output = Self>, - Self: Div<::Scalar, Output = Self>, - Self: Rem<::Scalar, Output = Self>, + Self: Mul<::Scalar, Output = Self>, + Self: Div<::Scalar, Output = Self>, + Self: Rem<::Scalar, Output = Self>, { /// The associated scalar. type Scalar: BaseNum; @@ -267,7 +267,7 @@ macro_rules! impl_vector { } } - impl Vector for $VectorN { + impl VectorSpace for $VectorN { type Scalar = S; #[inline] @@ -530,10 +530,10 @@ impl Vector4 { /// /// The dot product allows for the definition of other useful operations, like /// finding the magnitude of a vector or normalizing it. -pub trait EuclideanVector: Vector + Sized where +pub trait InnerSpace: VectorSpace + Sized where // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 - ::Scalar: BaseFloat, - Self: ApproxEq::Scalar>, + ::Scalar: BaseFloat, + Self: ApproxEq::Scalar>, { /// Vector dot (or inner) product. fn dot(self, other: Self) -> Self::Scalar; @@ -593,13 +593,13 @@ pub trait EuclideanVector: Vector + Sized where /// Dot product of two vectors. #[inline] -pub fn dot(a: V, b: V) -> V::Scalar where +pub fn dot(a: V, b: V) -> V::Scalar where V::Scalar: BaseFloat, { V::dot(a, b) } -impl EuclideanVector for Vector2 { +impl InnerSpace for Vector2 { #[inline] fn dot(self, other: Vector2) -> S { Vector2::mul_element_wise(self, other).sum() @@ -611,7 +611,7 @@ impl EuclideanVector for Vector2 { } } -impl EuclideanVector for Vector3 { +impl InnerSpace for Vector3 { #[inline] fn dot(self, other: Vector3) -> S { Vector3::mul_element_wise(self, other).sum() @@ -623,7 +623,7 @@ impl EuclideanVector for Vector3 { } } -impl EuclideanVector for Vector4 { +impl InnerSpace for Vector4 { #[inline] fn dot(self, other: Vector4) -> S { Vector4::mul_element_wise(self, other).sum() From b5f8e7646bd351d72bade2b24fa8b63eeca9a587 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Fri, 8 Apr 2016 15:35:11 +1000 Subject: [PATCH 2/6] Rename Point::Vector to Point::Diff --- src/point.rs | 22 +++++++++++----------- src/rotation.rs | 6 +++--- src/transform.rs | 22 +++++++++++----------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/point.rs b/src/point.rs index a16059b..42dad62 100644 --- a/src/point.rs +++ b/src/point.rs @@ -79,7 +79,7 @@ impl Point3 { } /// Points in a [Euclidean space](https://en.wikipedia.org/wiki/Euclidean_space) -/// with an associated vector space, `Self::Vector`. +/// with an associated space of displacement vectors. /// /// # Point-Vector distinction /// @@ -129,21 +129,21 @@ pub trait Point: Copy + Clone where // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 Self: Array::Scalar>, - Self: Add<::Vector, Output = Self>, - Self: Sub::Vector>, + Self: Add<::Diff, Output = Self>, + Self: Sub::Diff>, Self: Mul<::Scalar, Output = Self>, Self: Div<::Scalar, Output = Self>, Self: Rem<::Scalar, Output = Self>, { - /// The associated scalar. + /// The associated scalar over which the space is defined. /// - /// Due to the equality constraints demanded by `Self::Vector`, this is effectively just an - /// alias to `Self::Vector::Scalar`. + /// Due to the equality constraints demanded by `Self::Diff`, this is effectively just an + /// alias to `Self::Diff::Scalar`. type Scalar: BaseNum; /// The associated space of displacement vectors. - type Vector: VectorSpace; + type Diff: VectorSpace; /// The point at the origin of the Euclidean space. fn origin() -> Self; @@ -152,16 +152,16 @@ pub trait Point: Copy + Clone where /// /// This can be considered equivalent to the addition of the displacement /// vector `v` to to `Self::origin()`. - fn from_vec(v: Self::Vector) -> Self; + fn from_vec(v: Self::Diff) -> Self; /// Convert a point to a displacement vector. /// /// This can be seen as equivalent to the displacement vector from /// `Self::origin()` to `self`. - fn to_vec(self) -> Self::Vector; + fn to_vec(self) -> Self::Diff; /// This is a weird one, but its useful for plane calculations. - fn dot(self, v: Self::Vector) -> Self::Scalar; + fn dot(self, v: Self::Diff) -> Self::Scalar; } macro_rules! impl_point { @@ -197,7 +197,7 @@ macro_rules! impl_point { impl Point for $PointN { type Scalar = S; - type Vector = $VectorN; + type Diff = $VectorN; #[inline] fn origin() -> $PointN { diff --git a/src/rotation.rs b/src/rotation.rs index bff231c..dd010a8 100644 --- a/src/rotation.rs +++ b/src/rotation.rs @@ -35,14 +35,14 @@ pub trait Rotation: PartialEq + Sized where fn one() -> Self; /// Create a rotation to a given direction with an 'up' vector - fn look_at(dir: P::Vector, up: P::Vector) -> Self; + fn look_at(dir: P::Diff, up: P::Diff) -> Self; /// Create a shortest rotation to transform vector 'a' into 'b'. /// Both given vectors are assumed to have unit length. - fn between_vectors(a: P::Vector, b: P::Vector) -> Self; + fn between_vectors(a: P::Diff, b: P::Diff) -> Self; /// Rotate a vector using this rotation. - fn rotate_vector(&self, vec: P::Vector) -> P::Vector; + fn rotate_vector(&self, vec: P::Diff) -> P::Diff; /// Rotate a point using this rotation, by converting it to its /// representation as a vector. diff --git a/src/transform.rs b/src/transform.rs index 7896c8f..9939a47 100644 --- a/src/transform.rs +++ b/src/transform.rs @@ -34,17 +34,17 @@ pub trait Transform: Sized { /// 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: P::Vector) -> Self; + fn look_at(eye: P, center: P, up: P::Diff) -> Self; /// Transform a vector using this transform. - fn transform_vector(&self, vec: P::Vector) -> P::Vector; + fn transform_vector(&self, vec: P::Diff) -> P::Diff; /// 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: P::Vector) -> P::Vector { + fn transform_as_point(&self, vec: P::Diff) -> P::Diff { self.transform_point(P::from_vec(vec)).to_vec() } @@ -78,23 +78,23 @@ pub struct Decomposed { pub disp: V, } -impl> Transform

for Decomposed where +impl> Transform

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

::Scalar: BaseFloat, // FIXME: Investigate why this is needed! -

::Vector: VectorSpace, +

::Diff: VectorSpace, { #[inline] - fn one() -> Decomposed { + fn one() -> Decomposed { Decomposed { scale:

::Scalar::one(), rot: R::one(), - disp: P::Vector::zero(), + disp: P::Diff::zero(), } } #[inline] - fn look_at(eye: P, center: P, up: P::Vector) -> Decomposed { + fn look_at(eye: P, center: P, up: P::Diff) -> Decomposed { let rot = R::look_at(center - eye, up); let disp = rot.rotate_vector(P::origin() - eye); Decomposed { @@ -105,7 +105,7 @@ impl> Transform

for Decomposed where } #[inline] - fn transform_vector(&self, vec: P::Vector) -> P::Vector { + fn transform_vector(&self, vec: P::Diff) -> P::Diff { self.rot.rotate_vector(vec * self.scale) } @@ -114,7 +114,7 @@ impl> Transform

for Decomposed where self.rot.rotate_point(point * self.scale) + 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,7 +122,7 @@ impl> Transform

for Decomposed where } } - fn invert(&self) -> Option> { + fn invert(&self) -> Option> { if self.scale.approx_eq(&

::Scalar::zero()) { None } else { From b4063ea72ae9b88c7ef01f9bf2c2fd207ef50b5a Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Fri, 8 Apr 2016 19:56:30 +1000 Subject: [PATCH 3/6] Rename Point to EuclideanSpace --- src/matrix.rs | 2 +- src/point.rs | 22 +++++++++++----------- src/prelude.rs | 2 +- src/rotation.rs | 8 ++++---- src/transform.rs | 16 ++++++++-------- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/matrix.rs b/src/matrix.rs index e509dd2..032dfc6 100644 --- a/src/matrix.rs +++ b/src/matrix.rs @@ -29,7 +29,7 @@ use angle::{Angle, Rad}; use approx::ApproxEq; use array::Array; use num::BaseFloat; -use point::{Point, Point3}; +use point::{EuclideanSpace, Point3}; use quaternion::Quaternion; use vector::{VectorSpace, InnerSpace}; use vector::{Vector2, Vector3, Vector4}; diff --git a/src/point.rs b/src/point.rs index 42dad62..40eb355 100644 --- a/src/point.rs +++ b/src/point.rs @@ -116,25 +116,25 @@ impl Point3 { /// ## Converting between points and vectors /// /// Points can be converted to and from displacement vectors using the -/// `Point::{from_vec, to_vec}` methods. Note that under the hood these are -/// implemented as inlined a type conversion, so should not have any performance -/// implications. +/// `EuclideanSpace::{from_vec, to_vec}` methods. Note that under the hood these +/// are implemented as inlined a type conversion, so should not have any +/// performance implications. /// /// ## References /// /// - [CGAL 4.7 - 2D and 3D Linear Geometry Kernel: 3.1 Points and Vectors](http://doc.cgal.org/latest/Kernel_23/index.html#Kernel_23PointsandVectors) /// - [What is the difference between a point and a vector](http://math.stackexchange.com/q/645827) /// -pub trait Point: Copy + Clone where +pub trait EuclideanSpace: Copy + Clone where // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 - Self: Array::Scalar>, + Self: Array::Scalar>, - Self: Add<::Diff, Output = Self>, - Self: Sub::Diff>, + Self: Add<::Diff, Output = Self>, + Self: Sub::Diff>, - Self: Mul<::Scalar, Output = Self>, - Self: Div<::Scalar, Output = Self>, - Self: Rem<::Scalar, Output = Self>, + Self: Mul<::Scalar, Output = Self>, + Self: Div<::Scalar, Output = Self>, + Self: Rem<::Scalar, Output = Self>, { /// The associated scalar over which the space is defined. /// @@ -195,7 +195,7 @@ macro_rules! impl_point { } } - impl Point for $PointN { + impl EuclideanSpace for $PointN { type Scalar = S; type Diff = $VectorN; diff --git a/src/prelude.rs b/src/prelude.rs index 1378f96..7275976 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -10,7 +10,7 @@ pub use array::ElementWise; pub use matrix::Matrix; pub use matrix::SquareMatrix; -pub use point::Point; +pub use point::EuclideanSpace; pub use rotation::Rotation; pub use rotation::Rotation2; diff --git a/src/rotation.rs b/src/rotation.rs index dd010a8..2f844b7 100644 --- a/src/rotation.rs +++ b/src/rotation.rs @@ -20,16 +20,16 @@ use approx::ApproxEq; use matrix::SquareMatrix; use matrix::{Matrix2, Matrix3}; use num::BaseFloat; -use point::{Point, Point2, Point3}; +use point::{EuclideanSpace, Point2, Point3}; use quaternion::Quaternion; use vector::{InnerSpace, 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 + Sized where +pub trait Rotation: PartialEq + Sized where // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 - Self: ApproxEq::Scalar>, -

::Scalar: BaseFloat, + Self: ApproxEq::Scalar>, +

::Scalar: BaseFloat, { /// Create the identity transform (causes no transformation). fn one() -> Self; diff --git a/src/transform.rs b/src/transform.rs index 9939a47..66ad4e5 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; @@ -78,16 +78,16 @@ pub struct Decomposed { pub disp: V, } -impl> Transform

for Decomposed where +impl> Transform

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

::Scalar: BaseFloat, +

::Scalar: BaseFloat, // FIXME: Investigate why this is needed! -

::Diff: VectorSpace, +

::Diff: VectorSpace, { #[inline] fn one() -> Decomposed { Decomposed { - scale:

::Scalar::one(), + scale:

::Scalar::one(), rot: R::one(), disp: P::Diff::zero(), } @@ -98,7 +98,7 @@ impl> Transform

for Decomposed where let rot = R::look_at(center - eye, up); let disp = rot.rotate_vector(P::origin() - eye); Decomposed { - scale:

::Scalar::one(), + scale:

::Scalar::one(), rot: rot, disp: disp, } @@ -123,10 +123,10 @@ impl> Transform

for Decomposed where } fn invert(&self) -> Option> { - if self.scale.approx_eq(&

::Scalar::zero()) { + if self.scale.approx_eq(&

::Scalar::zero()) { None } else { - let s =

::Scalar::one() / self.scale; + let s =

::Scalar::one() / self.scale; let r = self.rot.invert(); let d = r.rotate_vector(self.disp.clone()) * -s; Some(Decomposed { From 886e2fb240036b21fbeb6ffe62faf721325bb72e Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Sat, 9 Apr 2016 13:47:04 +1000 Subject: [PATCH 4/6] Unify trait hierarchies for vectors, quaternions and matrices --- src/matrix.rs | 128 +++++++++++++++++++++++++++------------------- src/point.rs | 1 - src/quaternion.rs | 65 ++++++++++------------- src/vector.rs | 8 +-- 4 files changed, 105 insertions(+), 97 deletions(-) diff --git a/src/matrix.rs b/src/matrix.rs index 032dfc6..99c693f 100644 --- a/src/matrix.rs +++ b/src/matrix.rs @@ -248,41 +248,86 @@ impl Matrix4 { } } +impl VectorSpace for Matrix2 { + type Scalar = S; + + #[inline] + fn zero() -> Matrix2 { + Matrix2::new(S::zero(), S::zero(), + S::zero(), S::zero()) + } +} + +impl VectorSpace for Matrix3 { + type Scalar = S; + + #[inline] + fn zero() -> Matrix3 { + Matrix3::new(S::zero(), S::zero(), S::zero(), + S::zero(), S::zero(), S::zero(), + S::zero(), S::zero(), S::zero()) + } +} + +impl VectorSpace for Matrix4 { + type Scalar = S; + + #[inline] + fn zero() -> Matrix4 { + Matrix4::new(S::zero(), S::zero(), S::zero(), S::zero(), + S::zero(), S::zero(), S::zero(), S::zero(), + S::zero(), S::zero(), S::zero(), S::zero(), + S::zero(), S::zero(), S::zero(), S::zero()) + } +} + /// A column-major matrix of arbitrary dimensions. -pub trait Matrix where +/// +/// Because this is constrained to the `VectorSpace` trait, this means that +/// following operators are required to be implemented: +/// +/// Matrix addition: +/// +/// - `Add` +/// - `Sub` +/// - `Neg` +/// +/// Scalar multiplication: +/// +/// - `Mul` +/// - `Div` +/// - `Rem` +/// +/// Note that matrix multiplication is not required for implementors of this +/// trait. This is due to the complexities of implementing these operators with +/// Rust's current type system. For the multiplication of square matrices, +/// see `SquareMatrix`. +pub trait Matrix: VectorSpace where + Self::Scalar: BaseFloat, + // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 Self: Index::Column>, Self: IndexMut::Column>, - Self: ApproxEq::Element>, - - Self: Add, - Self: Sub, - Self: Neg, - - Self: Mul<::Element, Output = Self>, - Self: Div<::Element, Output = Self>, - Self: Rem<::Element, Output = Self>, + Self: ApproxEq::Scalar>, { - /// The type of the elements in the matrix. - type Element: BaseFloat; - /// The row vector of the matrix. - type Row: Array; - /// The column vector of the matrix. - type Column: Array; + type Row: VectorSpace + Array; - /// The type of the transposed matrix - type Transpose: Matrix; + /// The column vector of the matrix. + type Column: VectorSpace + Array; + + /// The result of transposing the matrix + type Transpose: Matrix; /// Get the pointer to the first element of the array. #[inline] - fn as_ptr(&self) -> *const Self::Element { + fn as_ptr(&self) -> *const Self::Scalar { &self[0][0] } /// Get a mutable pointer to the first element of the array. #[inline] - fn as_mut_ptr(&mut self) -> *mut Self::Element { + fn as_mut_ptr(&mut self) -> *mut Self::Scalar { &mut self[0][0] } @@ -302,15 +347,14 @@ pub trait Matrix where /// Swap the values at index `a` and `b` fn swap_elements(&mut self, a: (usize, usize), b: (usize, usize)); - /// Create a matrix with all of the elements set to zero. - fn zero() -> Self; - /// Transpose this matrix, returning a new matrix. fn transpose(&self) -> Self::Transpose; } /// A column-major major matrix where the rows and column vectors are of the same dimensions. pub trait SquareMatrix where + Self::Scalar: BaseFloat, + Self: Matrix< // FIXME: Can be cleaned up once equality constraints in where clauses are implemented Column = ::ColumnRow, @@ -326,12 +370,12 @@ pub trait SquareMatrix where /// This is used to constrain the column and rows to be of the same type in lieu of equality /// constraints being implemented for `where` clauses. Once those are added, this type will /// likely go away. - type ColumnRow: Array; + type ColumnRow: VectorSpace + Array; /// Create a new diagonal matrix using the supplied value. - fn from_value(value: Self::Element) -> Self; + fn from_value(value: Self::Scalar) -> Self; /// Create a matrix from a non-uniform scale - fn from_diagonal(diagonal: Self::Column) -> Self; + fn from_diagonal(diagonal: Self::ColumnRow) -> Self; /// The [identity matrix](https://en.wikipedia.org/wiki/Identity_matrix). Multiplying this /// matrix with another has no effect. @@ -340,14 +384,14 @@ pub trait SquareMatrix where /// Transpose this matrix in-place. fn transpose_self(&mut self); /// Take the determinant of this matrix. - fn determinant(&self) -> Self::Element; + fn determinant(&self) -> Self::Scalar; /// Return a vector containing the diagonal of this matrix. - fn diagonal(&self) -> Self::Column; + fn diagonal(&self) -> Self::ColumnRow; /// Return the trace of this matrix. That is, the sum of the diagonal. #[inline] - fn trace(&self) -> Self::Element { self.diagonal().sum() } + fn trace(&self) -> Self::Scalar { 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 @@ -363,7 +407,7 @@ pub trait SquareMatrix where /// Test if this matrix is invertible. #[inline] - fn is_invertible(&self) -> bool { !self.determinant().approx_eq(&Self::Element::zero()) } + fn is_invertible(&self) -> bool { !self.determinant().approx_eq(&Self::Scalar::zero()) } /// Test if this matrix is the identity matrix. That is, it is diagonal /// and every element in the diagonal is one. @@ -380,7 +424,6 @@ pub trait SquareMatrix where } impl Matrix for Matrix2 { - type Element = S; type Column = Vector2; type Row = Vector2; type Transpose = Matrix2; @@ -409,12 +452,6 @@ impl Matrix for Matrix2 { unsafe { ptr::swap(&mut self[ac][ar], &mut self[bc][br]) }; } - #[inline] - fn zero() -> Matrix2 { - Matrix2::new(S::zero(), S::zero(), - S::zero(), S::zero()) - } - fn transpose(&self) -> Matrix2 { Matrix2::new(self[0][0], self[1][0], self[0][1], self[1][1]) @@ -483,7 +520,6 @@ impl SquareMatrix for Matrix2 { } impl Matrix for Matrix3 { - type Element = S; type Column = Vector3; type Row = Vector3; type Transpose = Matrix3; @@ -514,13 +550,6 @@ impl Matrix for Matrix3 { unsafe { ptr::swap(&mut self[ac][ar], &mut self[bc][br]) }; } - #[inline] - fn zero() -> Matrix3 { - Matrix3::new(S::zero(), S::zero(), S::zero(), - S::zero(), S::zero(), S::zero(), - S::zero(), S::zero(), S::zero()) - } - fn transpose(&self) -> Matrix3 { Matrix3::new(self[0][0], self[1][0], self[2][0], self[0][1], self[1][1], self[2][1], @@ -603,7 +632,6 @@ impl SquareMatrix for Matrix3 { } impl Matrix for Matrix4 { - type Element = S; type Column = Vector4; type Row = Vector4; type Transpose = Matrix4; @@ -636,14 +664,6 @@ impl Matrix for Matrix4 { unsafe { ptr::swap(&mut self[ac][ar], &mut self[bc][br]) }; } - #[inline] - fn zero() -> Matrix4 { - Matrix4::new(S::zero(), S::zero(), S::zero(), S::zero(), - S::zero(), S::zero(), S::zero(), S::zero(), - S::zero(), S::zero(), S::zero(), S::zero(), - S::zero(), S::zero(), S::zero(), S::zero()) - } - fn transpose(&self) -> Matrix4 { Matrix4::new(self[0][0], self[1][0], self[2][0], self[3][0], self[0][1], self[1][1], self[2][1], self[3][1], diff --git a/src/point.rs b/src/point.rs index 40eb355..4a5b6b4 100644 --- a/src/point.rs +++ b/src/point.rs @@ -25,7 +25,6 @@ use rust_num::{One, Zero}; use approx::ApproxEq; use array::Array; -use matrix::Matrix; use num::{BaseNum, BaseFloat}; use vector::*; diff --git a/src/quaternion.rs b/src/quaternion.rs index 9a04f92..ea8d8e3 100644 --- a/src/quaternion.rs +++ b/src/quaternion.rs @@ -54,62 +54,40 @@ impl Quaternion { Quaternion { s: s, v: v } } - /// The additive identity, ie: `q = 0 + 0i + 0j + 0i` - #[inline] - pub fn zero() -> Quaternion { - Quaternion::new(S::zero(), S::zero(), S::zero(), S::zero()) - } - - /// The multiplicative identity, ie: `q = 1 + 0i + 0j + 0i` + /// The multiplicative identity. #[inline] pub fn one() -> Quaternion { Quaternion::from_sv(S::one(), Vector3::zero()) } - /// The dot product of the quaternion and `q`. - #[inline] - pub fn dot(self, other: Quaternion) -> S { - self.s * other.s + self.v.dot(other.v) - } - /// The conjugate of the quaternion. #[inline] pub fn conjugate(self) -> Quaternion { Quaternion::from_sv(self.s, -self.v) } - /// The squared magnitude of the quaternion. This is useful for - /// magnitude comparisons where the exact magnitude does not need to be - /// calculated. - #[inline] - pub fn magnitude2(self) -> S { - self.s * self.s + self.v.magnitude2() - } - - /// The magnitude of the quaternion - /// - /// # Performance notes - /// - /// For instances where the exact magnitude of the quaternion does not need - /// to be known, for example for quaternion-quaternion magnitude comparisons, - /// it is advisable to use the `magnitude2` method instead. - #[inline] - pub fn magnitude(self) -> S { - self.magnitude2().sqrt() - } - - /// Normalize this quaternion, returning the new quaternion. - #[inline] - pub fn normalize(self) -> Quaternion { - self * (S::one() / self.magnitude()) - } - /// Do a normalized linear interpolation with `other`, by `amount`. pub fn nlerp(self, other: Quaternion, amount: S) -> Quaternion { (self * (S::one() - amount) + other * amount).normalize() } } +impl VectorSpace for Quaternion { + type Scalar = S; + + #[inline] + fn zero() -> Quaternion { + Quaternion::from_sv(S::zero(), Vector3::zero()) + } +} + +impl InnerSpace for Quaternion { + #[inline] + fn dot(self, other: Quaternion) -> S { + self.s * other.s + self.v.dot(other.v) + } +} + impl_operator!( Neg for Quaternion { fn neg(quat) -> Quaternion { Quaternion::from_sv(-quat.s, -quat.v) @@ -134,6 +112,15 @@ impl_assignment_operator!( DivAssign for Quaternion { fn div_assign(&mut self, scalar) { self.s /= scalar; self.v /= scalar; } }); +impl_operator!( Rem for Quaternion { + fn rem(lhs, rhs) -> Quaternion { + Quaternion::from_sv(lhs.s % rhs, lhs.v % rhs) + } +}); +impl_assignment_operator!( RemAssign for Quaternion { + fn rem_assign(&mut self, scalar) { self.s %= scalar; self.v %= scalar; } +}); + impl_operator!( Mul > for Quaternion { fn mul(lhs, rhs) -> Vector3 {{ let rhs = rhs.clone(); diff --git a/src/vector.rs b/src/vector.rs index ffbeff6..57bb110 100644 --- a/src/vector.rs +++ b/src/vector.rs @@ -104,6 +104,8 @@ use num::{BaseNum, BaseFloat, PartialOrd}; /// together and [multiplied](https://en.wikipedia.org/wiki/Scalar_multiplication) /// by scalars. /// +/// Examples include vectors, matrices, and quaternions. +/// /// # Required operators /// /// ## Vector addition @@ -144,12 +146,10 @@ use num::{BaseNum, BaseFloat, PartialOrd}; /// let downscaled_translation = translation / scale_factor; /// ``` pub trait VectorSpace: Copy + Clone where - // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 - Self: Array::Scalar>, - Self: Add, Self: Sub, + // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 Self: Mul<::Scalar, Output = Self>, Self: Div<::Scalar, Output = Self>, Self: Rem<::Scalar, Output = Self>, @@ -530,6 +530,8 @@ impl Vector4 { /// /// The dot product allows for the definition of other useful operations, like /// finding the magnitude of a vector or normalizing it. +/// +/// Examples include vectors and quaternions. pub trait InnerSpace: VectorSpace + Sized where // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 ::Scalar: BaseFloat, From a3e6cd26b5ae1f2d9b47df0e0811bfb0c11a2371 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Sat, 9 Apr 2016 13:47:17 +1000 Subject: [PATCH 5/6] Document fields --- src/matrix.rs | 9 +++++++++ src/quaternion.rs | 2 ++ 2 files changed, 11 insertions(+) diff --git a/src/matrix.rs b/src/matrix.rs index 99c693f..08f550a 100644 --- a/src/matrix.rs +++ b/src/matrix.rs @@ -40,7 +40,9 @@ use vector::{Vector2, Vector3, Vector4}; #[repr(C, packed)] #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)] pub struct Matrix2 { + /// The first column of the matrix. pub x: Vector2, + /// The second column of the matrix. pub y: Vector2, } @@ -50,8 +52,11 @@ pub struct Matrix2 { #[repr(C, packed)] #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)] pub struct Matrix3 { + /// The first column of the matrix. pub x: Vector3, + /// The second column of the matrix. pub y: Vector3, + /// The third column of the matrix. pub z: Vector3, } @@ -61,9 +66,13 @@ pub struct Matrix3 { #[repr(C, packed)] #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)] pub struct Matrix4 { + /// The first column of the matrix. pub x: Vector4, + /// The second column of the matrix. pub y: Vector4, + /// The third column of the matrix. pub z: Vector4, + /// The fourth column of the matrix. pub w: Vector4, } diff --git a/src/quaternion.rs b/src/quaternion.rs index ea8d8e3..5bf47d8 100644 --- a/src/quaternion.rs +++ b/src/quaternion.rs @@ -36,7 +36,9 @@ use vector::{Vector3, VectorSpace, InnerSpace}; #[repr(C, packed)] #[derive(Copy, Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)] pub struct Quaternion { + /// The scalar part of the quaternion. pub s: S, + /// The vector part of the quaternion. pub v: Vector3, } From 23fce928c049b1319103319b87febc10a39ae314 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Sat, 9 Apr 2016 13:50:39 +1000 Subject: [PATCH 6/6] Module documentation updates --- src/lib.rs | 44 ++++++++++++++++++++++-------- src/matrix.rs | 2 -- src/vector.rs | 74 --------------------------------------------------- 3 files changed, 33 insertions(+), 87 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3d7b997..73feed4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,19 +13,41 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Computer graphics-centric math. +//! A low-dimensional linear algebra library, targeted at computer graphics. //! -//! This crate provides useful mathematical primitives and operations on them. -//! It is organized into one module per primitive. The core structures are -//! vectors and matrices. A strongly-typed interface is provided, to prevent -//! mixing units or violating mathematical invariants. +//! # Trait overview //! -//! Transformations are not usually done directly on matrices, but go through -//! transformation objects that can be converted to matrices. Rotations go -//! through the `Basis` types, which are guaranteed to be orthogonal matrices. -//! Despite this, one can directly create a limited rotation matrix using the -//! `look_at`, `from_angle`, `from_euler`, and `from_axis_angle` methods. -//! These are provided for convenience. +//! In order to make a clean, composable API, we divide operations into traits +//! that are roughly based on mathematical properties. The main ones that we +//! concern ourselves with are listed below: +//! +//! - `VectorSpace`: Specifies the main operators for vectors, quaternions, and +//! matrices. +//! - `InnerSpace`: For types that have a dot (or inner) product - ie. vectors or +//! quaternions. This also allows for the definition of operations that are +//! based on the dot product, like finding the magnitude or normalizing. +//! - `EuclideanSpace`: Points in euclidean space, with an associated space of +//! displacement vectors. +//! - `Matrix`: Common operations for matrices of arbitrary dimensions. +//! - `SquareMatrix`: A special trait for matrices where the number of columns +//! equal the number of rows. +//! +//! Other traits are included for practical convenience, for example: +//! +//! - `Array`: For contiguous, indexable arrays of elements, specifically +//! vectors. +//! - `ElementWise`: For element-wise addition, subtraction, multiplication, +//! division, and remainder operations. +//! +//! # The prelude +//! +//! Importing each trait individually can become a chore, so we provide a +//! `prelude` module to allow you to import the main trait all at once. For +//! example: +//! +//! ```rust +//! use cgmath::prelude::*; +//! ``` extern crate num as rust_num; extern crate rustc_serialize; diff --git a/src/matrix.rs b/src/matrix.rs index 08f550a..b6a3bb9 100644 --- a/src/matrix.rs +++ b/src/matrix.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Column major, square matrix types and traits. - use std::fmt; use std::mem; use std::ops::*; diff --git a/src/vector.rs b/src/vector.rs index 57bb110..6fb813c 100644 --- a/src/vector.rs +++ b/src/vector.rs @@ -13,80 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Types and traits for two, three, and four-dimensional vectors. -//! -//! ## Working with Vectors -//! -//! Vectors can be created in several different ways. There is, of course, the -//! traditional `new()` method, but unit vectors, zero vectors, and an one -//! vector are also provided: -//! -//! ```rust -//! use cgmath::{VectorSpace, Vector2, Vector3, Vector4, vec3}; -//! -//! assert_eq!(Vector2::new(1.0f64, 0.0f64), Vector2::unit_x()); -//! assert_eq!(vec3(0.0f64, 0.0f64, 0.0f64), Vector3::zero()); -//! ``` -//! -//! Vectors can be manipulated with typical mathematical operations (addition, -//! subtraction, element-wise multiplication, element-wise division, negation) -//! using the built-in operators. -//! -//! ```rust -//! use cgmath::{VectorSpace, Vector2, Vector3, Vector4}; -//! -//! let a: Vector2 = Vector2::new(3.0, 4.0); -//! let b: Vector2 = Vector2::new(-3.0, -4.0); -//! -//! assert_eq!(a + b, Vector2::zero()); -//! assert_eq!(-(a * 2.0), Vector2::new(-6.0, -8.0)); -//! -//! // As with Rust's `int` and `f32` types, Vectors of different types cannot -//! // be added and so on with impunity. The following will fail to compile: -//! // let c = a + Vector3::new(1.0, 0.0, 2.0); -//! -//! // Instead, we need to convert the Vector2 to a Vector3 by "extending" it -//! // with the value for the last coordinate: -//! let c: Vector3 = a.extend(0.0) + Vector3::new(1.0, 0.0, 2.0); -//! -//! // Similarly, we can "truncate" a Vector4 down to a Vector3: -//! let d: Vector3 = c + Vector4::unit_x().truncate(); -//! -//! assert_eq!(d, Vector3::new(5.0f64, 4.0f64, 2.0f64)); -//! ``` -//! -//! Vectors also provide methods for typical operations such as -//! [scalar multiplication](http://en.wikipedia.org/wiki/Scalar_multiplication), -//! [dot products](http://en.wikipedia.org/wiki/Dot_product), -//! and [cross products](http://en.wikipedia.org/wiki/Cross_product). -//! -//! ```rust -//! use cgmath::{VectorSpace, InnerSpace}; -//! use cgmath::{Vector2, Vector3, Vector4}; -//! -//! // All vectors implement the dot product as a method: -//! let a: Vector2 = Vector2::new(3.0, 6.0); -//! let b: Vector2 = Vector2::new(-2.0, 1.0); -//! assert_eq!(a.dot(b), 0.0); -//! -//! // But there is also a top-level function: -//! assert_eq!(a.dot(b), cgmath::dot(a, b)); -//! -//! // Cross products are defined for 3-dimensional vectors: -//! let e: Vector3 = Vector3::unit_x(); -//! let f: Vector3 = Vector3::unit_y(); -//! assert_eq!(e.cross(f), Vector3::unit_z()); -//! ``` -//! -//! Several other useful methods are provided as well. Vector fields can be -//! accessed using array syntax (i.e. `vector[0] == vector.x`), or by using -//! the methods provided by the [`Array`](../array/trait.Array.html) trait. -//! This trait also provides a `map()` method for applying arbitrary functions. -//! -//! The [`VectorSpace`](../trait.VectorSpace.html) trait presents the most -//! general features of the vectors, while [`InnerSpace`] -//! (../array/trait.InnerSpace.html) is more specific to Euclidean space. - use std::fmt; use std::mem; use std::ops::*;