From 8dd2874b59deceb3e39a20449f08d8a75af21b6d Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Tue, 19 Apr 2016 20:51:40 +1000 Subject: [PATCH] Move traits into common module --- src/angle.rs | 204 +------------- src/array.rs | 86 ------ src/lib.rs | 25 +- src/matrix.rs | 156 +---------- src/point.rs | 91 +------ src/prelude.rs | 13 +- src/projection.rs | 4 +- src/quaternion.rs | 6 +- src/rotation.rs | 9 +- src/structure.rs | 664 ++++++++++++++++++++++++++++++++++++++++++++++ src/transform.rs | 18 +- src/vector.rs | 148 +---------- 12 files changed, 714 insertions(+), 710 deletions(-) delete mode 100644 src/array.rs create mode 100644 src/structure.rs diff --git a/src/angle.rs b/src/angle.rs index f97d8af..ff30b4a 100644 --- a/src/angle.rs +++ b/src/angle.rs @@ -21,10 +21,11 @@ use std::ops::*; use rand::{Rand, Rng}; use rand::distributions::range::SampleRange; - use rust_num::{Float, Zero}; use rust_num::traits::cast; +use structure::Angle; + use approx::ApproxEq; use num::BaseFloat; @@ -61,207 +62,6 @@ impl From> for Rad where S: BaseFloat { } } -/// Angles and their associated trigonometric functions. -/// -/// Typed angles allow for the writing of self-documenting code that makes it -/// clear when semantic violations have occured - for example, adding degrees to -/// radians, or adding a number to an angle. -/// -pub trait Angle where - Self: Copy + Clone, - Self: PartialEq + PartialOrd, - // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 - Self: ApproxEq::Unitless>, - - Self: Neg, - Self: Add, - Self: Sub, - Self: Rem, - Self: Mul<::Unitless, Output = Self>, - Self: Div::Unitless>, - Self: Div<::Unitless, Output = Self>, -{ - type Unitless: BaseFloat; - - /// Return the angle, normalized to the range `[0, full_turn)`. - #[inline] - fn normalize(self) -> Self { - let rem = self % Self::full_turn(); - if rem < Self::zero() { rem + Self::full_turn() } else { rem } - } - - /// Return the angle rotated by half a turn. - #[inline] - fn opposite(self) -> Self { - Self::normalize(self + Self::turn_div_2()) - } - - /// Returns the interior bisector of the two angles. - #[inline] - fn bisect(self, other: Self) -> Self { - let half = cast(0.5f64).unwrap(); - Self::normalize((self - other) * half + self) - } - - /// The additive identity. - /// - /// Adding this to another angle has no affect. - /// - /// For example: - /// - /// ```rust - /// use cgmath::prelude::*; - /// use cgmath::Deg; - /// - /// let v = Deg::new(180.0); - /// assert_eq!(v + Deg::zero(), v); - /// ``` - fn zero() -> Self; - - /// A full rotation. - fn full_turn() -> Self; - - /// Half of a full rotation. - fn turn_div_2() -> Self; - - /// A third of a full rotation. - fn turn_div_3() -> Self; - - /// A quarter of a full rotation. - fn turn_div_4() -> Self; - - /// A sixth of a full rotation. - fn turn_div_6() -> Self; - - /// Compute the sine of the angle, returning a unitless ratio. - /// - /// ```rust - /// use cgmath::prelude::*; - /// use cgmath::Rad; - /// - /// let angle = Rad::new(35.0); - /// let ratio: f32 = Rad::sin(angle); - /// ``` - fn sin(self) -> Self::Unitless; - - /// Compute the cosine of the angle, returning a unitless ratio. - /// - /// ```rust - /// use cgmath::prelude::*; - /// use cgmath::Rad; - /// - /// let angle = Rad::new(35.0); - /// let ratio: f32 = Rad::cos(angle); - /// ``` - fn cos(self) -> Self::Unitless; - - /// Compute the tangent of the angle, returning a unitless ratio. - /// - /// ```rust - /// use cgmath::prelude::*; - /// use cgmath::Rad; - /// - /// let angle = Rad::new(35.0); - /// let ratio: f32 = Rad::tan(angle); - /// ``` - fn tan(self) -> Self::Unitless; - - /// Compute the sine and cosine of the angle, returning the result as a - /// pair. - /// - /// This does not have any performance benefits, but calculating both the - /// sine and cosine of a single angle is a common operation. - /// - /// ```rust - /// use cgmath::prelude::*; - /// use cgmath::Rad; - /// - /// let angle = Rad::new(35.0); - /// let (s, c) = Rad::sin_cos(angle); - /// ``` - fn sin_cos(self) -> (Self::Unitless, Self::Unitless); - - /// Compute the cosecant of the angle. - /// - /// This is the same as computing the reciprocal of `Self::sin`. - /// - /// ```rust - /// use cgmath::prelude::*; - /// use cgmath::Rad; - /// - /// let angle = Rad::new(35.0); - /// let ratio: f32 = Rad::csc(angle); - /// ``` - #[inline] - fn csc(self) -> Self::Unitless { - Self::sin(self).recip() - } - - /// Compute the secant of the angle. - /// - /// This is the same as computing the reciprocal of `Self::tan`. - /// - /// ```rust - /// use cgmath::prelude::*; - /// use cgmath::Rad; - /// - /// let angle = Rad::new(35.0); - /// let ratio: f32 = Rad::cot(angle); - /// ``` - #[inline] - fn cot(self) -> Self::Unitless { - Self::tan(self).recip() - } - - /// Compute the cotatangent of the angle. - /// - /// This is the same as computing the reciprocal of `Self::cos`. - /// - /// ```rust - /// use cgmath::prelude::*; - /// use cgmath::Rad; - /// - /// let angle = Rad::new(35.0); - /// let ratio: f32 = Rad::sec(angle); - /// ``` - #[inline] - fn sec(self) -> Self::Unitless { - Self::cos(self).recip() - } - - /// Compute the arcsine of the ratio, returning the resulting angle. - /// - /// ```rust - /// use cgmath::prelude::*; - /// use cgmath::Rad; - /// - /// let angle: Rad = Rad::asin(0.5); - /// ``` - fn asin(ratio: Self::Unitless) -> Self; - - /// Compute the arccosine of the ratio, returning the resulting angle. - /// - /// ```rust - /// use cgmath::prelude::*; - /// use cgmath::Rad; - /// - /// let angle: Rad = Rad::acos(0.5); - /// ``` - fn acos(ratio: Self::Unitless) -> Self; - - /// Compute the arctangent of the ratio, returning the resulting angle. - /// - /// ```rust - /// use cgmath::prelude::*; - /// use cgmath::Rad; - /// - /// let angle: Rad = Rad::atan(0.5); - /// ``` - fn atan(ratio: Self::Unitless) -> Self; - - fn atan2(a: Self::Unitless, b: Self::Unitless) -> Self; -} - macro_rules! impl_angle { ($Angle:ident, $fmt:expr, $full_turn:expr, $hi:expr) => { impl $Angle { diff --git a/src/array.rs b/src/array.rs deleted file mode 100644 index 3f1f14c..0000000 --- a/src/array.rs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2013 The OMath Developers. For a full listing of the authors, -// refer to the Cargo.toml file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::ptr; -use std::ops::*; - -use num::PartialOrd; - -/// An array containing elements of type `Element` -pub trait Array where - // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 - Self: Index::Element>, - Self: IndexMut::Element>, -{ - type Element: Copy; - - /// Construct a vector from a single value, replicating it. - /// - /// ```rust - /// use cgmath::prelude::*; - /// use cgmath::Vector3; - /// - /// assert_eq!(Vector3::from_value(1), - /// Vector3::new(1, 1, 1)); - /// ``` - fn from_value(value: Self::Element) -> Self; - - /// Get the pointer to the first element of the array. - #[inline] - fn as_ptr(&self) -> *const Self::Element { - &self[0] - } - - /// Get a mutable pointer to the first element of the array. - #[inline] - fn as_mut_ptr(&mut self) -> *mut Self::Element { - &mut self[0] - } - - /// Swap the elements at indices `i` and `j` in-place. - #[inline] - fn swap_elements(&mut self, i: usize, j: usize) { - // Yeah, ok borrow checker – I know what I'm doing here - unsafe { ptr::swap(&mut self[i], &mut self[j]) }; - } - - /// The sum of the elements of the array. - fn sum(self) -> Self::Element where Self::Element: Add::Element>; - - /// The product of the elements of the array. - fn product(self) -> Self::Element where Self::Element: Mul::Element>; - - /// The minimum element of the array. - fn min(self) -> Self::Element where Self::Element: PartialOrd; - - /// The maximum element of the array. - fn max(self) -> Self::Element where Self::Element: PartialOrd; -} - -/// Element-wise arithmetic operations. These are supplied for pragmatic -/// reasons, but will usually fall outside of traditional algebraic properties. -pub trait ElementWise { - fn add_element_wise(self, rhs: Rhs) -> Self; - fn sub_element_wise(self, rhs: Rhs) -> Self; - fn mul_element_wise(self, rhs: Rhs) -> Self; - fn div_element_wise(self, rhs: Rhs) -> Self; - fn rem_element_wise(self, rhs: Rhs) -> Self; - - fn add_assign_element_wise(&mut self, rhs: Rhs); - fn sub_assign_element_wise(&mut self, rhs: Rhs); - fn mul_assign_element_wise(&mut self, rhs: Rhs); - fn div_assign_element_wise(&mut self, rhs: Rhs); - fn rem_assign_element_wise(&mut self, rhs: Rhs); -} diff --git a/src/lib.rs b/src/lib.rs index 73feed4..e114e8a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,21 +55,21 @@ extern crate rand; // Re-exports -pub use array::*; -pub use matrix::*; -pub use quaternion::*; -pub use vector::*; +pub use approx::*; +pub use num::*; +pub use structure::*; -pub use angle::*; -pub use point::*; +pub use matrix::{Matrix2, Matrix3, Matrix4}; +pub use quaternion::Quaternion; +pub use vector::{Vector2, Vector3, Vector4, dot, vec2, vec3, vec4}; + +pub use angle::{Deg, Rad, deg, rad}; +pub use point::{Point2, Point3}; pub use rotation::*; pub use transform::*; pub use projection::*; -pub use approx::ApproxEq; -pub use num::*; - pub use rust_num::{One, Zero, one, zero}; // Modules @@ -79,7 +79,9 @@ pub mod prelude; mod macros; -mod array; +mod approx; +mod num; +mod structure; mod matrix; mod quaternion; @@ -91,6 +93,3 @@ mod rotation; mod transform; mod projection; - -mod approx; -mod num; diff --git a/src/matrix.rs b/src/matrix.rs index dfc28c3..66e9de5 100644 --- a/src/matrix.rs +++ b/src/matrix.rs @@ -13,23 +13,21 @@ // See the License for the specific language governing permissions and // limitations under the License. +use rand::{Rand, Rng}; +use rust_num::{Zero, One}; +use rust_num::traits::cast; use std::fmt; use std::mem; use std::ops::*; use std::ptr; -use rand::{Rand, Rng}; +use structure::*; -use rust_num::{Zero, One}; -use rust_num::traits::cast; - -use angle::{Angle, Rad}; +use angle::Rad; use approx::ApproxEq; -use array::Array; use num::BaseFloat; -use point::{EuclideanSpace, Point3}; +use point::Point3; use quaternion::Quaternion; -use vector::{VectorSpace, InnerSpace}; use vector::{Vector2, Vector3, Vector4}; /// A 2 x 2, column major matrix @@ -288,148 +286,6 @@ impl VectorSpace for Matrix4 { } } -/// A column-major matrix of arbitrary dimensions. -/// -/// 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::Scalar>, -{ - /// The row vector of the matrix. - type Row: VectorSpace + Array; - - /// 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::Scalar { - &self[0][0] - } - - /// Get a mutable pointer to the first element of the array. - #[inline] - fn as_mut_ptr(&mut self) -> *mut Self::Scalar { - &mut self[0][0] - } - - /// Replace a column in the array. - #[inline] - fn replace_col(&mut self, c: usize, src: Self::Column) -> Self::Column { - mem::replace(&mut self[c], src) - } - - /// Get a row from this matrix by-value. - fn row(&self, r: usize) -> Self::Row; - - /// Swap two rows of this array. - fn swap_rows(&mut self, a: usize, b: usize); - /// Swap two columns of this array. - fn swap_columns(&mut self, a: usize, b: usize); - /// Swap the values at index `a` and `b` - fn swap_elements(&mut self, a: (usize, usize), b: (usize, usize)); - - /// 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, - Row = ::ColumnRow, - Transpose = Self, - >, - Self: Mul<::ColumnRow, Output = ::ColumnRow>, - Self: Mul, -{ - // FIXME: Will not be needed once equality constraints in where clauses are implemented - /// The row/column vector of the matrix. - /// - /// 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: VectorSpace + Array; - - /// Create a new diagonal matrix using the supplied value. - fn from_value(value: Self::Scalar) -> Self; - /// Create a matrix from a non-uniform scale - 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. - fn identity() -> Self; - - /// Transpose this matrix in-place. - fn transpose_self(&mut self); - /// Take the determinant of this matrix. - fn determinant(&self) -> Self::Scalar; - - /// Return a vector containing the diagonal of this matrix. - fn diagonal(&self) -> Self::ColumnRow; - - /// Return the trace of this matrix. That is, the sum of the diagonal. - #[inline] - 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 - /// (has a determinant of zero). - #[must_use] - fn invert(&self) -> Option; - - /// Invert this matrix in-place. - #[inline] - fn invert_self(&mut self) { - *self = self.invert().expect("Attempted to invert a matrix with zero determinant."); - } - - /// Test if this matrix is invertible. - #[inline] - 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. - #[inline] - fn is_identity(&self) -> bool { self.approx_eq(&Self::identity()) } - - /// Test if this is a diagonal matrix. That is, every element outside of - /// the diagonal is 0. - fn is_diagonal(&self) -> bool; - - /// Test if this matrix is symmetric. That is, it is equal to its - /// transpose. - fn is_symmetric(&self) -> bool; -} - impl Matrix for Matrix2 { type Column = Vector2; type Row = Vector2; diff --git a/src/point.rs b/src/point.rs index 4a5b6b4..accfc17 100644 --- a/src/point.rs +++ b/src/point.rs @@ -23,10 +23,11 @@ use std::ops::*; use rust_num::{One, Zero}; +use structure::*; + use approx::ApproxEq; -use array::Array; use num::{BaseNum, BaseFloat}; -use vector::*; +use vector::{Vector2, Vector3, Vector4}; /// A point in 2-dimensional space. /// @@ -77,92 +78,6 @@ impl Point3 { } } -/// Points in a [Euclidean space](https://en.wikipedia.org/wiki/Euclidean_space) -/// with an associated space of displacement vectors. -/// -/// # Point-Vector distinction -/// -/// `cgmath` distinguishes between points and vectors in the following way: -/// -/// - Points are _locations_ relative to an origin -/// - Vectors are _displacements_ between those points -/// -/// For example, to find the midpoint between two points, you can write the -/// following: -/// -/// ```rust -/// use cgmath::Point3; -/// -/// let p0 = Point3::new(1.0, 2.0, 3.0); -/// let p1 = Point3::new(-3.0, 1.0, 2.0); -/// let midpoint: Point3 = p0 + (p1 - p0) * 0.5; -/// ``` -/// -/// Breaking the expression up, and adding explicit types makes it clearer -/// to see what is going on: -/// -/// ```rust -/// # use cgmath::{Point3, Vector3}; -/// # -/// # let p0 = Point3::new(1.0, 2.0, 3.0); -/// # let p1 = Point3::new(-3.0, 1.0, 2.0); -/// # -/// let dv: Vector3 = p1 - p0; -/// let half_dv: Vector3 = dv * 0.5; -/// let midpoint: Point3 = p0 + half_dv; -/// ``` -/// -/// ## Converting between points and vectors -/// -/// Points can be converted to and from displacement vectors using the -/// `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 EuclideanSpace: Copy + Clone where - // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 - Self: Array::Scalar>, - - 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 over which the space is defined. - /// - /// 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 Diff: VectorSpace; - - /// The point at the origin of the Euclidean space. - fn origin() -> Self; - - /// Convert a displacement vector to a point. - /// - /// This can be considered equivalent to the addition of the displacement - /// vector `v` to to `Self::origin()`. - 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::Diff; - - /// This is a weird one, but its useful for plane calculations. - fn dot(self, v: Self::Diff) -> Self::Scalar; -} - macro_rules! impl_point { ($PointN:ident { $($field:ident),+ }, $VectorN:ident, $n:expr) => { impl Array for $PointN { diff --git a/src/prelude.rs b/src/prelude.rs index 7275976..882f502 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -2,15 +2,7 @@ //! glob-importing this module, you can avoid the need to import each trait //! individually, while still being selective about what types you import. -pub use angle::Angle; - -pub use array::Array; -pub use array::ElementWise; - -pub use matrix::Matrix; -pub use matrix::SquareMatrix; - -pub use point::EuclideanSpace; +pub use structure::*; pub use rotation::Rotation; pub use rotation::Rotation2; @@ -19,6 +11,3 @@ pub use rotation::Rotation3; pub use transform::Transform; pub use transform::Transform2; pub use transform::Transform3; - -pub use vector::InnerSpace; -pub use vector::VectorSpace; diff --git a/src/projection.rs b/src/projection.rs index c7f96d0..9636524 100644 --- a/src/projection.rs +++ b/src/projection.rs @@ -16,7 +16,9 @@ use rust_num::{Zero, One}; use rust_num::traits::cast; -use angle::{Angle, Rad}; +use structure::Angle; + +use angle::Rad; use matrix::Matrix4; use num::BaseFloat; diff --git a/src/quaternion.rs b/src/quaternion.rs index 16dd56a..54d49b2 100644 --- a/src/quaternion.rs +++ b/src/quaternion.rs @@ -20,13 +20,15 @@ use rand::{Rand, Rng}; use rust_num::{Float, One, Zero}; use rust_num::traits::cast; -use angle::{Angle, Rad}; +use structure::*; + +use angle::Rad; use approx::ApproxEq; use matrix::{Matrix3, Matrix4}; use num::BaseFloat; use point::Point3; use rotation::{Rotation, Rotation3, Basis3}; -use vector::{Vector3, VectorSpace, InnerSpace}; +use vector::Vector3; /// A [quaternion](https://en.wikipedia.org/wiki/Quaternion) in scalar/vector diff --git a/src/rotation.rs b/src/rotation.rs index 2f844b7..ce362d4 100644 --- a/src/rotation.rs +++ b/src/rotation.rs @@ -15,14 +15,15 @@ use std::fmt; -use angle::{Angle, Rad}; +use structure::*; + +use angle::Rad; use approx::ApproxEq; -use matrix::SquareMatrix; use matrix::{Matrix2, Matrix3}; use num::BaseFloat; -use point::{EuclideanSpace, Point2, Point3}; +use point::{Point2, Point3}; use quaternion::Quaternion; -use vector::{InnerSpace, Vector2, Vector3}; +use 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. diff --git a/src/structure.rs b/src/structure.rs new file mode 100644 index 0000000..9eb6966 --- /dev/null +++ b/src/structure.rs @@ -0,0 +1,664 @@ +// Copyright 2016 The CGMath Developers. For a full listing of the authors, +// refer to the Cargo.toml file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Generic algebraic structures + +use rust_num::{cast, Float, One, Zero}; +use std::cmp; +use std::ops::*; + +use approx::ApproxEq; + +use angle::Rad; +use num::{BaseNum, BaseFloat, PartialOrd}; + +/// An array containing elements of type `Element` +pub trait Array where + // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 + Self: Index::Element>, + Self: IndexMut::Element>, +{ + type Element: Copy; + + /// Construct a vector from a single value, replicating it. + /// + /// ```rust + /// use cgmath::prelude::*; + /// use cgmath::Vector3; + /// + /// assert_eq!(Vector3::from_value(1), + /// Vector3::new(1, 1, 1)); + /// ``` + fn from_value(value: Self::Element) -> Self; + + /// Get the pointer to the first element of the array. + #[inline] + fn as_ptr(&self) -> *const Self::Element { + &self[0] + } + + /// Get a mutable pointer to the first element of the array. + #[inline] + fn as_mut_ptr(&mut self) -> *mut Self::Element { + &mut self[0] + } + + /// Swap the elements at indices `i` and `j` in-place. + #[inline] + fn swap_elements(&mut self, i: usize, j: usize) { + use std::ptr; + + // Yeah, ok borrow checker – I know what I'm doing here + unsafe { ptr::swap(&mut self[i], &mut self[j]) }; + } + + /// The sum of the elements of the array. + fn sum(self) -> Self::Element where Self::Element: Add::Element>; + + /// The product of the elements of the array. + fn product(self) -> Self::Element where Self::Element: Mul::Element>; + + /// The minimum element of the array. + fn min(self) -> Self::Element where Self::Element: PartialOrd; + + /// The maximum element of the array. + fn max(self) -> Self::Element where Self::Element: PartialOrd; +} + +/// Element-wise arithmetic operations. These are supplied for pragmatic +/// reasons, but will usually fall outside of traditional algebraic properties. +pub trait ElementWise { + fn add_element_wise(self, rhs: Rhs) -> Self; + fn sub_element_wise(self, rhs: Rhs) -> Self; + fn mul_element_wise(self, rhs: Rhs) -> Self; + fn div_element_wise(self, rhs: Rhs) -> Self; + fn rem_element_wise(self, rhs: Rhs) -> Self; + + fn add_assign_element_wise(&mut self, rhs: Rhs); + fn sub_assign_element_wise(&mut self, rhs: Rhs); + fn mul_assign_element_wise(&mut self, rhs: Rhs); + fn div_assign_element_wise(&mut self, rhs: Rhs); + fn rem_assign_element_wise(&mut self, rhs: Rhs); +} + +/// Vectors that can be [added](http://mathworld.wolfram.com/VectorAddition.html) +/// together and [multiplied](https://en.wikipedia.org/wiki/Scalar_multiplication) +/// by scalars. +/// +/// Examples include vectors, matrices, and quaternions. +/// +/// # Required operators +/// +/// ## Vector addition +/// +/// Vectors can be added, subtracted, or negated via the following traits: +/// +/// - `Add` +/// - `Sub` +/// - `Neg` +/// +/// ```rust +/// use cgmath::Vector3; +/// +/// let velocity0 = Vector3::new(1, 2, 0); +/// let velocity1 = Vector3::new(1, 1, 0); +/// +/// let total_velocity = velocity0 + velocity1; +/// let velocity_diff = velocity1 - velocity0; +/// let reversed_velocity0 = -velocity0; +/// ``` +/// +/// ## Scalar multiplication +/// +/// Vectors can be multiplied or divided by their associated scalars via the +/// following traits: +/// +/// - `Mul` +/// - `Div` +/// - `Rem` +/// +/// ```rust +/// use cgmath::Vector2; +/// +/// let translation = Vector2::new(3.0, 4.0); +/// let scale_factor = 2.0; +/// +/// let upscaled_translation = translation * scale_factor; +/// let downscaled_translation = translation / scale_factor; +/// ``` +pub trait VectorSpace: Copy + Clone where + 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>, +{ + /// The associated scalar. + type Scalar: BaseNum; + + /// The additive identity. + /// + /// Adding this to another `Self` value has no effect. + /// + /// ```rust + /// use cgmath::prelude::*; + /// use cgmath::Vector2; + /// + /// let v = Vector2::new(1, 2); + /// assert_eq!(v + Vector2::zero(), v); + /// ``` + fn zero() -> Self; +} + +/// Vectors that also have a [dot](https://en.wikipedia.org/wiki/Dot_product) +/// (or [inner](https://en.wikipedia.org/wiki/Inner_product_space)) product. +/// +/// 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, + Self: ApproxEq::Scalar>, +{ + /// Vector dot (or inner) product. + fn dot(self, other: Self) -> Self::Scalar; + + /// Returns `true` if the vector is perpendicular (at right angles) to the + /// other vector. + fn is_perpendicular(self, other: Self) -> bool { + Self::dot(self, other).approx_eq(&Self::Scalar::zero()) + } + + /// Returns the squared magnitude of the vector. + /// + /// This does not perform an expensive square root operation like in + /// `Vector::magnitude` method, and so can be used to compare vectors more + /// efficiently. + #[inline] + fn magnitude2(self) -> Self::Scalar { + Self::dot(self, self) + } + + /// The distance from the tail to the tip of the vector. + #[inline] + fn magnitude(self) -> Self::Scalar { + use rust_num::Float; + + // FIXME: Not sure why we can't use method syntax for `sqrt` here... + Float::sqrt(self.magnitude2()) + } + + /// Returns the angle between two vectors in radians. + fn angle(self, other: Self) -> Rad { + Rad::acos(Self::dot(self, other) / (self.magnitude() * other.magnitude())) + } + + /// Returns a vector with the same direction, but with a magnitude of `1`. + #[inline] + #[must_use] + fn normalize(self) -> Self { + self.normalize_to(Self::Scalar::one()) + } + + /// Returns a vector with the same direction and a given magnitude. + #[inline] + #[must_use] + fn normalize_to(self, magnitude: Self::Scalar) -> Self { + self * (magnitude / self.magnitude()) + } + + /// Returns the result of linearly interpolating the magnitude of the vector + /// towards the magnitude of `other` by the specified amount. + #[inline] + #[must_use] + fn lerp(self, other: Self, amount: Self::Scalar) -> Self { + self + ((other - self) * amount) + } +} + +/// Points in a [Euclidean space](https://en.wikipedia.org/wiki/Euclidean_space) +/// with an associated space of displacement vectors. +/// +/// # Point-Vector distinction +/// +/// `cgmath` distinguishes between points and vectors in the following way: +/// +/// - Points are _locations_ relative to an origin +/// - Vectors are _displacements_ between those points +/// +/// For example, to find the midpoint between two points, you can write the +/// following: +/// +/// ```rust +/// use cgmath::Point3; +/// +/// let p0 = Point3::new(1.0, 2.0, 3.0); +/// let p1 = Point3::new(-3.0, 1.0, 2.0); +/// let midpoint: Point3 = p0 + (p1 - p0) * 0.5; +/// ``` +/// +/// Breaking the expression up, and adding explicit types makes it clearer +/// to see what is going on: +/// +/// ```rust +/// # use cgmath::{Point3, Vector3}; +/// # +/// # let p0 = Point3::new(1.0, 2.0, 3.0); +/// # let p1 = Point3::new(-3.0, 1.0, 2.0); +/// # +/// let dv: Vector3 = p1 - p0; +/// let half_dv: Vector3 = dv * 0.5; +/// let midpoint: Point3 = p0 + half_dv; +/// ``` +/// +/// ## Converting between points and vectors +/// +/// Points can be converted to and from displacement vectors using the +/// `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 EuclideanSpace: Copy + Clone where + // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 + Self: Array::Scalar>, + + 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 over which the space is defined. + /// + /// 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 Diff: VectorSpace; + + /// The point at the origin of the Euclidean space. + fn origin() -> Self; + + /// Convert a displacement vector to a point. + /// + /// This can be considered equivalent to the addition of the displacement + /// vector `v` to to `Self::origin()`. + 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::Diff; + + /// This is a weird one, but its useful for plane calculations. + fn dot(self, v: Self::Diff) -> Self::Scalar; +} + +/// A column-major matrix of arbitrary dimensions. +/// +/// 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::Scalar>, +{ + /// The row vector of the matrix. + type Row: VectorSpace + Array; + + /// 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::Scalar { + &self[0][0] + } + + /// Get a mutable pointer to the first element of the array. + #[inline] + fn as_mut_ptr(&mut self) -> *mut Self::Scalar { + &mut self[0][0] + } + + /// Replace a column in the array. + #[inline] + fn replace_col(&mut self, c: usize, src: Self::Column) -> Self::Column { + use std::mem; + + mem::replace(&mut self[c], src) + } + + /// Get a row from this matrix by-value. + fn row(&self, r: usize) -> Self::Row; + + /// Swap two rows of this array. + fn swap_rows(&mut self, a: usize, b: usize); + /// Swap two columns of this array. + fn swap_columns(&mut self, a: usize, b: usize); + /// Swap the values at index `a` and `b` + fn swap_elements(&mut self, a: (usize, usize), b: (usize, usize)); + + /// 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, + Row = ::ColumnRow, + Transpose = Self, + >, + Self: Mul<::ColumnRow, Output = ::ColumnRow>, + Self: Mul, +{ + // FIXME: Will not be needed once equality constraints in where clauses are implemented + /// The row/column vector of the matrix. + /// + /// 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: VectorSpace + Array; + + /// Create a new diagonal matrix using the supplied value. + fn from_value(value: Self::Scalar) -> Self; + /// Create a matrix from a non-uniform scale + 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. + fn identity() -> Self; + + /// Transpose this matrix in-place. + fn transpose_self(&mut self); + /// Take the determinant of this matrix. + fn determinant(&self) -> Self::Scalar; + + /// Return a vector containing the diagonal of this matrix. + fn diagonal(&self) -> Self::ColumnRow; + + /// Return the trace of this matrix. That is, the sum of the diagonal. + #[inline] + 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 + /// (has a determinant of zero). + #[must_use] + fn invert(&self) -> Option; + + /// Invert this matrix in-place. + #[inline] + fn invert_self(&mut self) { + *self = self.invert().expect("Attempted to invert a matrix with zero determinant."); + } + + /// Test if this matrix is invertible. + #[inline] + 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. + #[inline] + fn is_identity(&self) -> bool { self.approx_eq(&Self::identity()) } + + /// Test if this is a diagonal matrix. That is, every element outside of + /// the diagonal is 0. + fn is_diagonal(&self) -> bool; + + /// Test if this matrix is symmetric. That is, it is equal to its + /// transpose. + fn is_symmetric(&self) -> bool; +} + +/// Angles and their associated trigonometric functions. +/// +/// Typed angles allow for the writing of self-documenting code that makes it +/// clear when semantic violations have occured - for example, adding degrees to +/// radians, or adding a number to an angle. +/// +pub trait Angle where + Self: Copy + Clone, + Self: PartialEq + cmp::PartialOrd, + // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 + Self: ApproxEq::Unitless>, + + Self: Neg, + Self: Add, + Self: Sub, + Self: Rem, + Self: Mul<::Unitless, Output = Self>, + Self: Div::Unitless>, + Self: Div<::Unitless, Output = Self>, +{ + type Unitless: BaseFloat; + + /// Return the angle, normalized to the range `[0, full_turn)`. + #[inline] + fn normalize(self) -> Self { + let rem = self % Self::full_turn(); + if rem < Self::zero() { rem + Self::full_turn() } else { rem } + } + + /// Return the angle rotated by half a turn. + #[inline] + fn opposite(self) -> Self { + Self::normalize(self + Self::turn_div_2()) + } + + /// Returns the interior bisector of the two angles. + #[inline] + fn bisect(self, other: Self) -> Self { + let half = cast(0.5f64).unwrap(); + Self::normalize((self - other) * half + self) + } + + /// The additive identity. + /// + /// Adding this to another angle has no affect. + /// + /// For example: + /// + /// ```rust + /// use cgmath::prelude::*; + /// use cgmath::Deg; + /// + /// let v = Deg::new(180.0); + /// assert_eq!(v + Deg::zero(), v); + /// ``` + fn zero() -> Self; + + /// A full rotation. + fn full_turn() -> Self; + + /// Half of a full rotation. + fn turn_div_2() -> Self; + + /// A third of a full rotation. + fn turn_div_3() -> Self; + + /// A quarter of a full rotation. + fn turn_div_4() -> Self; + + /// A sixth of a full rotation. + fn turn_div_6() -> Self; + + /// Compute the sine of the angle, returning a unitless ratio. + /// + /// ```rust + /// use cgmath::prelude::*; + /// use cgmath::Rad; + /// + /// let angle = Rad::new(35.0); + /// let ratio: f32 = Rad::sin(angle); + /// ``` + fn sin(self) -> Self::Unitless; + + /// Compute the cosine of the angle, returning a unitless ratio. + /// + /// ```rust + /// use cgmath::prelude::*; + /// use cgmath::Rad; + /// + /// let angle = Rad::new(35.0); + /// let ratio: f32 = Rad::cos(angle); + /// ``` + fn cos(self) -> Self::Unitless; + + /// Compute the tangent of the angle, returning a unitless ratio. + /// + /// ```rust + /// use cgmath::prelude::*; + /// use cgmath::Rad; + /// + /// let angle = Rad::new(35.0); + /// let ratio: f32 = Rad::tan(angle); + /// ``` + fn tan(self) -> Self::Unitless; + + /// Compute the sine and cosine of the angle, returning the result as a + /// pair. + /// + /// This does not have any performance benefits, but calculating both the + /// sine and cosine of a single angle is a common operation. + /// + /// ```rust + /// use cgmath::prelude::*; + /// use cgmath::Rad; + /// + /// let angle = Rad::new(35.0); + /// let (s, c) = Rad::sin_cos(angle); + /// ``` + fn sin_cos(self) -> (Self::Unitless, Self::Unitless); + + /// Compute the cosecant of the angle. + /// + /// This is the same as computing the reciprocal of `Self::sin`. + /// + /// ```rust + /// use cgmath::prelude::*; + /// use cgmath::Rad; + /// + /// let angle = Rad::new(35.0); + /// let ratio: f32 = Rad::csc(angle); + /// ``` + #[inline] + fn csc(self) -> Self::Unitless { + Self::sin(self).recip() + } + + /// Compute the secant of the angle. + /// + /// This is the same as computing the reciprocal of `Self::tan`. + /// + /// ```rust + /// use cgmath::prelude::*; + /// use cgmath::Rad; + /// + /// let angle = Rad::new(35.0); + /// let ratio: f32 = Rad::cot(angle); + /// ``` + #[inline] + fn cot(self) -> Self::Unitless { + Self::tan(self).recip() + } + + /// Compute the cotatangent of the angle. + /// + /// This is the same as computing the reciprocal of `Self::cos`. + /// + /// ```rust + /// use cgmath::prelude::*; + /// use cgmath::Rad; + /// + /// let angle = Rad::new(35.0); + /// let ratio: f32 = Rad::sec(angle); + /// ``` + #[inline] + fn sec(self) -> Self::Unitless { + Self::cos(self).recip() + } + + /// Compute the arcsine of the ratio, returning the resulting angle. + /// + /// ```rust + /// use cgmath::prelude::*; + /// use cgmath::Rad; + /// + /// let angle: Rad = Rad::asin(0.5); + /// ``` + fn asin(ratio: Self::Unitless) -> Self; + + /// Compute the arccosine of the ratio, returning the resulting angle. + /// + /// ```rust + /// use cgmath::prelude::*; + /// use cgmath::Rad; + /// + /// let angle: Rad = Rad::acos(0.5); + /// ``` + fn acos(ratio: Self::Unitless) -> Self; + + /// Compute the arctangent of the ratio, returning the resulting angle. + /// + /// ```rust + /// use cgmath::prelude::*; + /// use cgmath::Rad; + /// + /// let angle: Rad = Rad::atan(0.5); + /// ``` + fn atan(ratio: Self::Unitless) -> Self; + + fn atan2(a: Self::Unitless, b: Self::Unitless) -> Self; +} diff --git a/src/transform.rs b/src/transform.rs index 66ad4e5..7c6a0a9 100644 --- a/src/transform.rs +++ b/src/transform.rs @@ -17,12 +17,14 @@ use std::fmt; use rust_num::{Zero, One}; +use structure::*; + use approx::ApproxEq; -use matrix::*; -use num::*; -use point::*; +use matrix::{Matrix2, Matrix3, Matrix4}; +use num::{BaseFloat, BaseNum}; +use point::{Point2, Point3}; use rotation::*; -use vector::*; +use vector::{Vector2, Vector3}; /// A trait representing an [affine /// transformation](https://en.wikipedia.org/wiki/Affine_transformation) that @@ -87,7 +89,7 @@ impl> Transform

for Decomposed #[inline] fn one() -> Decomposed { Decomposed { - scale:

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

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

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

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

::Scalar::zero()) { + if self.scale.approx_eq(&P::Scalar::zero()) { None } else { - let s =

::Scalar::one() / self.scale; + let s = P::Scalar::one() / self.scale; let r = self.rot.invert(); let d = r.rotate_vector(self.disp.clone()) * -s; Some(Decomposed { diff --git a/src/vector.rs b/src/vector.rs index 112ce14..0e5d7f1 100644 --- a/src/vector.rs +++ b/src/vector.rs @@ -13,90 +13,18 @@ // See the License for the specific language governing permissions and // limitations under the License. +use rand::{Rand, Rng}; +use rust_num::{NumCast, Zero, One}; use std::fmt; use std::mem; use std::ops::*; -use rand::{Rand, Rng}; +use structure::*; -use rust_num::{NumCast, Zero, One}; - -use angle::{Angle, Rad}; +use angle::Rad; use approx::ApproxEq; -use array::{Array, ElementWise}; use num::{BaseNum, BaseFloat, PartialOrd}; -/// Vectors that can be [added](http://mathworld.wolfram.com/VectorAddition.html) -/// together and [multiplied](https://en.wikipedia.org/wiki/Scalar_multiplication) -/// by scalars. -/// -/// Examples include vectors, matrices, and quaternions. -/// -/// # Required operators -/// -/// ## Vector addition -/// -/// Vectors can be added, subtracted, or negated via the following traits: -/// -/// - `Add` -/// - `Sub` -/// - `Neg` -/// -/// ```rust -/// use cgmath::Vector3; -/// -/// let velocity0 = Vector3::new(1, 2, 0); -/// let velocity1 = Vector3::new(1, 1, 0); -/// -/// let total_velocity = velocity0 + velocity1; -/// let velocity_diff = velocity1 - velocity0; -/// let reversed_velocity0 = -velocity0; -/// ``` -/// -/// ## Scalar multiplication -/// -/// Vectors can be multiplied or divided by their associated scalars via the -/// following traits: -/// -/// - `Mul` -/// - `Div` -/// - `Rem` -/// -/// ```rust -/// use cgmath::Vector2; -/// -/// let translation = Vector2::new(3.0, 4.0); -/// let scale_factor = 2.0; -/// -/// let upscaled_translation = translation * scale_factor; -/// let downscaled_translation = translation / scale_factor; -/// ``` -pub trait VectorSpace: Copy + Clone where - 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>, -{ - /// The associated scalar. - type Scalar: BaseNum; - - /// The additive identity. - /// - /// Adding this to another `Self` value has no effect. - /// - /// ```rust - /// use cgmath::prelude::*; - /// use cgmath::Vector2; - /// - /// let v = Vector2::new(1, 2); - /// assert_eq!(v + Vector2::zero(), v); - /// ``` - fn zero() -> Self; -} - /// A 2-dimensional vector. /// /// This type is marked as `#[repr(C, packed)]`. @@ -451,74 +379,6 @@ impl Vector4 { } } -/// Vectors that also have a [dot](https://en.wikipedia.org/wiki/Dot_product) -/// (or [inner](https://en.wikipedia.org/wiki/Inner_product_space)) product. -/// -/// 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, - Self: ApproxEq::Scalar>, -{ - /// Vector dot (or inner) product. - fn dot(self, other: Self) -> Self::Scalar; - - /// Returns `true` if the vector is perpendicular (at right angles) to the - /// other vector. - fn is_perpendicular(self, other: Self) -> bool { - Self::dot(self, other).approx_eq(&Self::Scalar::zero()) - } - - /// Returns the squared magnitude of the vector. - /// - /// This does not perform an expensive square root operation like in - /// `Vector::magnitude` method, and so can be used to compare vectors more - /// efficiently. - #[inline] - fn magnitude2(self) -> Self::Scalar { - Self::dot(self, self) - } - - /// The distance from the tail to the tip of the vector. - #[inline] - fn magnitude(self) -> Self::Scalar { - use rust_num::Float; - - // FIXME: Not sure why we can't use method syntax for `sqrt` here... - Float::sqrt(self.magnitude2()) - } - - /// Returns the angle between two vectors in radians. - fn angle(self, other: Self) -> Rad { - Rad::acos(Self::dot(self, other) / (self.magnitude() * other.magnitude())) - } - - /// Returns a vector with the same direction, but with a magnitude of `1`. - #[inline] - #[must_use] - fn normalize(self) -> Self { - self.normalize_to(Self::Scalar::one()) - } - - /// Returns a vector with the same direction and a given magnitude. - #[inline] - #[must_use] - fn normalize_to(self, magnitude: Self::Scalar) -> Self { - self * (magnitude / self.magnitude()) - } - - /// Returns the result of linearly interpolating the magnitude of the vector - /// towards the magnitude of `other` by the specified amount. - #[inline] - #[must_use] - fn lerp(self, other: Self, amount: Self::Scalar) -> Self { - self + ((other - self) * amount) - } -} - /// Dot product of two vectors. #[inline] pub fn dot(a: V, b: V) -> V::Scalar where