Merge pull request #345 from bjz/inherit-one-zero

Integrate One and Zero traits into the algebraic trait heirachy
This commit is contained in:
Brendan Zabarauskas 2016-04-25 20:21:52 +10:00
commit f8f10daaae
9 changed files with 139 additions and 86 deletions

View file

@ -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<S: BaseFloat> Angle for $Angle<S> {
type Unitless = S;
impl<S: BaseFloat> Zero for $Angle<S> {
#[inline]
fn zero() -> $Angle<S> {
$Angle::new(S::zero())
}
#[inline]
fn is_zero(&self) -> bool {
$Angle::approx_eq(self, &$Angle::zero())
}
}
impl<S: BaseFloat> Angle for $Angle<S> {
type Unitless = S;
#[inline] fn full_turn() -> $Angle<S> { $Angle::new(cast($full_turn).unwrap()) }
#[inline] fn turn_div_2() -> $Angle<S> { let factor: S = cast(2).unwrap(); $Angle::full_turn() / factor }
#[inline] fn turn_div_3() -> $Angle<S> { let factor: S = cast(3).unwrap(); $Angle::full_turn() / factor }
#[inline] fn turn_div_4() -> $Angle<S> { let factor: S = cast(4).unwrap(); $Angle::full_turn() / factor }
#[inline] fn turn_div_6() -> $Angle<S> { 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() }

View file

@ -14,7 +14,7 @@
// limitations under the License.
use rand::{Rand, Rng};
use num_traits::{cast, Zero};
use num_traits::cast;
use structure::*;

View file

@ -72,8 +72,6 @@ pub use transform::*;
pub use projection::*;
pub use num_traits::{One, Zero};
// Modules
pub mod conv;

View file

@ -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<S: BaseFloat> Matrix4<S> {
}
}
impl<S: BaseFloat> VectorSpace for Matrix2<S> {
type Scalar = S;
impl<S: BaseFloat> Zero for Matrix2<S> {
#[inline]
fn zero() -> Matrix2<S> {
Matrix2::new(S::zero(), S::zero(),
S::zero(), S::zero())
}
#[inline]
fn is_zero(&self) -> bool {
Matrix2::approx_eq(self, &Matrix2::zero())
}
}
impl<S: BaseFloat> VectorSpace for Matrix3<S> {
type Scalar = S;
impl<S: BaseFloat> Zero for Matrix3<S> {
#[inline]
fn zero() -> Matrix3<S> {
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<S: BaseFloat> VectorSpace for Matrix4<S> {
type Scalar = S;
impl<S: BaseFloat> Zero for Matrix4<S> {
#[inline]
fn zero() -> Matrix4<S> {
Matrix4::new(S::zero(), S::zero(), S::zero(), S::zero(),
@ -298,6 +301,44 @@ impl<S: BaseFloat> VectorSpace for Matrix4<S> {
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<S: BaseFloat> One for Matrix2<S> {
#[inline]
fn one() -> Matrix2<S> {
Matrix2::from_value(S::one())
}
}
impl<S: BaseFloat> One for Matrix3<S> {
#[inline]
fn one() -> Matrix3<S> {
Matrix3::from_value(S::one())
}
}
impl<S: BaseFloat> One for Matrix4<S> {
#[inline]
fn one() -> Matrix4<S> {
Matrix4::from_value(S::one())
}
}
impl<S: BaseFloat> VectorSpace for Matrix2<S> {
type Scalar = S;
}
impl<S: BaseFloat> VectorSpace for Matrix3<S> {
type Scalar = S;
}
impl<S: BaseFloat> VectorSpace for Matrix4<S> {
type Scalar = S;
}
impl<S: BaseFloat> Matrix for Matrix2<S> {
@ -350,11 +391,6 @@ impl<S: BaseFloat> SquareMatrix for Matrix2<S> {
S::zero(), value.y)
}
#[inline]
fn identity() -> Matrix2<S> {
Matrix2::from_value(S::one())
}
#[inline]
fn transpose_self(&mut self) {
self.swap_elements((0, 1), (1, 0));
@ -451,11 +487,6 @@ impl<S: BaseFloat> SquareMatrix for Matrix3<S> {
S::zero(), S::zero(), value.z)
}
#[inline]
fn identity() -> Matrix3<S> {
Matrix3::from_value(S::one())
}
#[inline]
fn transpose_self(&mut self) {
self.swap_elements((0, 1), (1, 0));
@ -568,11 +599,6 @@ impl<S: BaseFloat> SquareMatrix for Matrix4<S> {
S::zero(), S::zero(), S::zero(), value.w)
}
#[inline]
fn identity() -> Matrix4<S> {
Matrix4::from_value(S::one())
}
fn transpose_self(&mut self) {
self.swap_elements((0, 1), (1, 0));
self.swap_elements((0, 2), (2, 0));

View file

@ -21,8 +21,6 @@ use std::fmt;
use std::mem;
use std::ops::*;
use num_traits::{One, Zero};
use structure::*;
use approx::ApproxEq;

View file

@ -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<S: BaseFloat> Quaternion<S> {
}
}
impl<S: BaseFloat> VectorSpace for Quaternion<S> {
type Scalar = S;
impl<S: BaseFloat> Zero for Quaternion<S> {
#[inline]
fn zero() -> Quaternion<S> {
Quaternion::from_sv(S::zero(), Vector3::zero())
}
#[inline]
fn is_zero(&self) -> bool {
Quaternion::approx_eq(self, &Quaternion::zero())
}
}
impl<S: BaseFloat> VectorSpace for Quaternion<S> {
type Scalar = S;
}
impl<S: BaseFloat> MetricSpace for Quaternion<S> {

View file

@ -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<Rhs = Self> {
/// 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<Rhs = Self> {
/// let downscaled_translation = translation / scale_factor;
/// ```
pub trait VectorSpace: Copy + Clone where
Self: Zero,
Self: Add<Self, Output = Self>,
Self: Sub<Self, Output = Self>,
@ -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 = <Self as SquareMatrix>::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<Epsilon = <Self as Angle>::Unitless>,
Self: Zero,
Self: Neg<Output = Self>,
Self: Add<Self, Output = Self>,
Self: Sub<Self, Output = Self>,
@ -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.
///

View file

@ -15,8 +15,6 @@
use std::fmt;
use num_traits::{Zero, One};
use structure::*;
use approx::ApproxEq;

View file

@ -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<S: BaseNum> VectorSpace for $VectorN<S> {
type Scalar = S;
impl<S: BaseNum> Zero for $VectorN<S> {
#[inline]
fn zero() -> $VectorN<S> {
$VectorN::from_value(S::zero())
}
#[inline]
fn zero() -> Self {
Self::from_value(Self::Scalar::zero())
fn is_zero(&self) -> bool {
*self == $VectorN::zero()
}
}
impl<S: BaseNum> VectorSpace for $VectorN<S> {
type Scalar = S;
}
impl<S: Neg<Output = S>> Neg for $VectorN<S> {
type Output = $VectorN<S>;