diff --git a/src/angle.rs b/src/angle.rs index 24eb535..900ac67 100644 --- a/src/angle.rs +++ b/src/angle.rs @@ -21,10 +21,10 @@ use std::ops::*; use rand::{Rand, Rng}; use rand::distributions::range::SampleRange; -use num_traits::{Float, Zero}; +use num_traits::Float; use num_traits::cast; -use structure::Angle; +use structure::*; use approx::ApproxEq; use num::BaseFloat; @@ -71,19 +71,22 @@ macro_rules! impl_angle { } } - impl Angle for $Angle { - type Unitless = S; - + impl Zero for $Angle { #[inline] fn zero() -> $Angle { $Angle::new(S::zero()) } + #[inline] + fn is_zero(&self) -> bool { + $Angle::approx_eq(self, &$Angle::zero()) + } + } + + impl Angle for $Angle { + type Unitless = S; + #[inline] fn full_turn() -> $Angle { $Angle::new(cast($full_turn).unwrap()) } - #[inline] fn turn_div_2() -> $Angle { let factor: S = cast(2).unwrap(); $Angle::full_turn() / factor } - #[inline] fn turn_div_3() -> $Angle { let factor: S = cast(3).unwrap(); $Angle::full_turn() / factor } - #[inline] fn turn_div_4() -> $Angle { let factor: S = cast(4).unwrap(); $Angle::full_turn() / factor } - #[inline] fn turn_div_6() -> $Angle { let factor: S = cast(6).unwrap(); $Angle::full_turn() / factor } #[inline] fn sin(self) -> S { Rad::from(self).s.sin() } #[inline] fn cos(self) -> S { Rad::from(self).s.cos() } diff --git a/src/euler.rs b/src/euler.rs index 32a66aa..ec28b45 100644 --- a/src/euler.rs +++ b/src/euler.rs @@ -14,7 +14,7 @@ // limitations under the License. use rand::{Rand, Rng}; -use num_traits::{cast, Zero}; +use num_traits::cast; use structure::*; diff --git a/src/lib.rs b/src/lib.rs index 17fc201..6f33b80 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -72,8 +72,6 @@ pub use transform::*; pub use projection::*; -pub use num_traits::{One, Zero}; - // Modules pub mod conv; diff --git a/src/matrix.rs b/src/matrix.rs index 97c3089..d405847 100644 --- a/src/matrix.rs +++ b/src/matrix.rs @@ -14,7 +14,6 @@ // limitations under the License. use rand::{Rand, Rng}; -use num_traits::{Zero, One}; use num_traits::cast; use std::fmt; use std::mem; @@ -267,30 +266,34 @@ impl Matrix4 { } } -impl VectorSpace for Matrix2 { - type Scalar = S; - +impl Zero for Matrix2 { #[inline] fn zero() -> Matrix2 { Matrix2::new(S::zero(), S::zero(), S::zero(), S::zero()) } + + #[inline] + fn is_zero(&self) -> bool { + Matrix2::approx_eq(self, &Matrix2::zero()) + } } -impl VectorSpace for Matrix3 { - type Scalar = S; - +impl Zero for Matrix3 { #[inline] fn zero() -> Matrix3 { Matrix3::new(S::zero(), S::zero(), S::zero(), S::zero(), S::zero(), S::zero(), S::zero(), S::zero(), S::zero()) } + + #[inline] + fn is_zero(&self) -> bool { + Matrix3::approx_eq(self, &Matrix3::zero()) + } } -impl VectorSpace for Matrix4 { - type Scalar = S; - +impl Zero for Matrix4 { #[inline] fn zero() -> Matrix4 { Matrix4::new(S::zero(), S::zero(), S::zero(), S::zero(), @@ -298,6 +301,44 @@ impl VectorSpace for Matrix4 { S::zero(), S::zero(), S::zero(), S::zero(), S::zero(), S::zero(), S::zero(), S::zero()) } + + #[inline] + fn is_zero(&self) -> bool { + Matrix4::approx_eq(self, &Matrix4::zero()) + } +} + +impl One for Matrix2 { + #[inline] + fn one() -> Matrix2 { + Matrix2::from_value(S::one()) + } +} + +impl One for Matrix3 { + #[inline] + fn one() -> Matrix3 { + Matrix3::from_value(S::one()) + } +} + +impl One for Matrix4 { + #[inline] + fn one() -> Matrix4 { + Matrix4::from_value(S::one()) + } +} + +impl VectorSpace for Matrix2 { + type Scalar = S; +} + +impl VectorSpace for Matrix3 { + type Scalar = S; +} + +impl VectorSpace for Matrix4 { + type Scalar = S; } impl Matrix for Matrix2 { @@ -350,11 +391,6 @@ impl SquareMatrix for Matrix2 { S::zero(), value.y) } - #[inline] - fn identity() -> Matrix2 { - Matrix2::from_value(S::one()) - } - #[inline] fn transpose_self(&mut self) { self.swap_elements((0, 1), (1, 0)); @@ -451,11 +487,6 @@ impl SquareMatrix for Matrix3 { S::zero(), S::zero(), value.z) } - #[inline] - fn identity() -> Matrix3 { - Matrix3::from_value(S::one()) - } - #[inline] fn transpose_self(&mut self) { self.swap_elements((0, 1), (1, 0)); @@ -568,11 +599,6 @@ impl SquareMatrix for Matrix4 { S::zero(), S::zero(), S::zero(), value.w) } - #[inline] - fn identity() -> Matrix4 { - Matrix4::from_value(S::one()) - } - fn transpose_self(&mut self) { self.swap_elements((0, 1), (1, 0)); self.swap_elements((0, 2), (2, 0)); diff --git a/src/point.rs b/src/point.rs index 31cde6b..4a808a2 100644 --- a/src/point.rs +++ b/src/point.rs @@ -21,8 +21,6 @@ use std::fmt; use std::mem; use std::ops::*; -use num_traits::{One, Zero}; - use structure::*; use approx::ApproxEq; diff --git a/src/quaternion.rs b/src/quaternion.rs index f94df92..4bd39a6 100644 --- a/src/quaternion.rs +++ b/src/quaternion.rs @@ -17,7 +17,7 @@ use std::mem; use std::ops::*; use rand::{Rand, Rng}; -use num_traits::{Float, One, Zero}; +use num_traits::Float; use num_traits::cast; use structure::*; @@ -120,13 +120,20 @@ impl Quaternion { } } -impl VectorSpace for Quaternion { - type Scalar = S; - +impl Zero for Quaternion { #[inline] fn zero() -> Quaternion { Quaternion::from_sv(S::zero(), Vector3::zero()) } + + #[inline] + fn is_zero(&self) -> bool { + Quaternion::approx_eq(self, &Quaternion::zero()) + } +} + +impl VectorSpace for Quaternion { + type Scalar = S; } impl MetricSpace for Quaternion { diff --git a/src/structure.rs b/src/structure.rs index 03b0646..c1130de 100644 --- a/src/structure.rs +++ b/src/structure.rs @@ -15,7 +15,7 @@ //! Generic algebraic structures -use num_traits::{cast, Float, One, Zero}; +use num_traits::{cast, Float}; use std::cmp; use std::ops::*; @@ -24,6 +24,8 @@ use approx::ApproxEq; use angle::Rad; use num::{BaseNum, BaseFloat, PartialOrd}; +pub use num_traits::{One, Zero}; + /// An array containing elements of type `Element` pub trait Array where // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 @@ -120,6 +122,17 @@ pub trait ElementWise { /// let reversed_velocity0 = -velocity0; /// ``` /// +/// Vector spaces are also required to implement the additive identity trait, +/// `Zero`. Adding this to another vector should have no effect: +/// +/// ```rust +/// use cgmath::prelude::*; +/// use cgmath::Vector2; +/// +/// let v = Vector2::new(1, 2); +/// assert_eq!(v + Vector2::zero(), v); +/// ``` +/// /// ## Scalar multiplication /// /// Vectors can be multiplied or divided by their associated scalars via the @@ -139,6 +152,8 @@ pub trait ElementWise { /// let downscaled_translation = translation / scale_factor; /// ``` pub trait VectorSpace: Copy + Clone where + Self: Zero, + Self: Add, Self: Sub, @@ -149,19 +164,6 @@ pub trait VectorSpace: Copy + Clone where { /// 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 type with a distance function between values. @@ -452,6 +454,8 @@ pub trait Matrix: VectorSpace where pub trait SquareMatrix where Self::Scalar: BaseFloat, + Self: One, + Self: Matrix< // FIXME: Can be cleaned up once equality constraints in where clauses are implemented Column = ::ColumnRow, @@ -474,9 +478,18 @@ pub trait SquareMatrix where /// 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; + /// The [identity matrix]. Multiplying this matrix with another should have + /// no effect. + /// + /// Note that this is exactly the same as `One::one`. The term 'identity + /// matrix' is more common though, so we provide this method as an + /// alternative. + /// + /// [identity matrix]: https://en.wikipedia.org/wiki/Identity_matrix + #[inline] + fn identity() -> Self { + Self::one() + } /// Transpose this matrix in-place. fn transpose_self(&mut self); @@ -532,6 +545,8 @@ pub trait Angle where // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 Self: ApproxEq::Unitless>, + Self: Zero, + Self: Neg, Self: Add, Self: Sub, @@ -562,35 +577,36 @@ pub trait Angle where 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; + #[inline] + fn turn_div_2() -> Self { + let factor: Self::Unitless = cast(2).unwrap(); + Self::full_turn() / factor + } /// A third of a full rotation. - fn turn_div_3() -> Self; + #[inline] + fn turn_div_3() -> Self { + let factor: Self::Unitless = cast(3).unwrap(); + Self::full_turn() / factor + } /// A quarter of a full rotation. - fn turn_div_4() -> Self; + #[inline] + fn turn_div_4() -> Self { + let factor: Self::Unitless = cast(4).unwrap(); + Self::full_turn() / factor + } /// A sixth of a full rotation. - fn turn_div_6() -> Self; + #[inline] + fn turn_div_6() -> Self { + let factor: Self::Unitless = cast(6).unwrap(); + Self::full_turn() / factor + } /// Compute the sine of the angle, returning a unitless ratio. /// diff --git a/src/transform.rs b/src/transform.rs index 93ccb18..3bf6a1d 100644 --- a/src/transform.rs +++ b/src/transform.rs @@ -15,8 +15,6 @@ use std::fmt; -use num_traits::{Zero, One}; - use structure::*; use approx::ApproxEq; diff --git a/src/vector.rs b/src/vector.rs index 8bcffa6..b5ecf03 100644 --- a/src/vector.rs +++ b/src/vector.rs @@ -14,7 +14,7 @@ // limitations under the License. use rand::{Rand, Rng}; -use num_traits::{NumCast, Zero, One}; +use num_traits::NumCast; use std::fmt; use std::mem; use std::ops::*; @@ -140,15 +140,22 @@ macro_rules! impl_vector { } } - impl VectorSpace for $VectorN { - type Scalar = S; + impl Zero for $VectorN { + #[inline] + fn zero() -> $VectorN { + $VectorN::from_value(S::zero()) + } #[inline] - fn zero() -> Self { - Self::from_value(Self::Scalar::zero()) + fn is_zero(&self) -> bool { + *self == $VectorN::zero() } } + impl VectorSpace for $VectorN { + type Scalar = S; + } + impl> Neg for $VectorN { type Output = $VectorN;