From c2054e4993318b37cff2c660fd788a40f0cf56b3 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Fri, 24 Jan 2014 03:13:53 +1100 Subject: [PATCH] Reduce code duplication We can now have multiple definitions in macros! --- src/cgmath/vector.rs | 206 +++++++++++++++++++------------------------ 1 file changed, 92 insertions(+), 114 deletions(-) diff --git a/src/cgmath/vector.rs b/src/cgmath/vector.rs index c3bb245..59c5aa0 100644 --- a/src/cgmath/vector.rs +++ b/src/cgmath/vector.rs @@ -20,99 +20,6 @@ use angle::{Rad, atan2, acos}; use approx::ApproxEq; use array::{Array, build}; -/// A 2-dimensional vector. -#[deriving(Eq, Clone)] -pub struct Vec2 { x: S, y: S } - -/// A 3-dimensional vector. -#[deriving(Eq, Clone)] -pub struct Vec3 { x: S, y: S, z: S } - -/// A 4-dimensional vector. -#[deriving(Eq, Clone)] -pub struct Vec4 { x: S, y: S, z: S, w: S } - -// Conversion traits //FIXME: not used anywhere? -pub trait ToVec2 { fn to_vec2(&self) -> Vec2; } -pub trait ToVec3 { fn to_vec3(&self) -> Vec3; } -pub trait ToVec4 { fn to_vec4(&self) -> Vec4; } - -// Utility macro for generating associated functions for the vectors -macro_rules! vec( - (impl $Self:ident <$S:ident> { $($field:ident),+ }) => ( - impl<$S: Primitive> $Self<$S> { - #[inline] - pub fn new($($field: $S),+) -> $Self<$S> { - $Self { $($field: $field),+ } - } - - /// Construct a vector from a single value. - #[inline] - pub fn from_value(value: $S) -> $Self<$S> { - $Self { $($field: value.clone()),+ } - } - - /// The additive identity of the vector. - #[inline] - pub fn zero() -> $Self<$S> { $Self::from_value(zero()) } - - /// The multiplicative identity of the vector. - #[inline] - pub fn ident() -> $Self<$S> { $Self::from_value(one()) } - } - ) -) - -vec!(impl Vec2 { x, y }) -vec!(impl Vec3 { x, y, z }) -vec!(impl Vec4 { x, y, z, w }) - -impl Vec2 { - #[inline] pub fn unit_x() -> Vec2 { Vec2::new(one(), zero()) } - #[inline] pub fn unit_y() -> Vec2 { Vec2::new(zero(), one()) } -} -impl Vec2 { - #[inline] - pub fn extend(&self, z: S)-> Vec3 { - Vec3::new(self.x.clone(), self.y.clone(), z) - } -} - -impl Vec3 { - #[inline] pub fn unit_x() -> Vec3 { Vec3::new(one(), zero(), zero()) } - #[inline] pub fn unit_y() -> Vec3 { Vec3::new(zero(), one(), zero()) } - #[inline] pub fn unit_z() -> Vec3 { Vec3::new(zero(), zero(), one()) } -} -impl Vec3 { - #[inline] - pub fn extend(&self, w: S)-> Vec4 { - Vec4::new(self.x.clone(), self.y.clone(), self.z.clone(), w) - } - - #[inline] - pub fn truncate(&self)-> Vec2 { - Vec2::new(self.x.clone(), self.y.clone()) //ignore Z - } -} - -impl Vec4 { - #[inline] pub fn unit_x() -> Vec4 { Vec4::new(one(), zero(), zero(), zero()) } - #[inline] pub fn unit_y() -> Vec4 { Vec4::new(zero(), one(), zero(), zero()) } - #[inline] pub fn unit_z() -> Vec4 { Vec4::new(zero(), zero(), one(), zero()) } - #[inline] pub fn unit_w() -> Vec4 { Vec4::new(zero(), zero(), zero(), one()) } -} - -impl Vec4 { - #[inline] - pub fn truncate(&self)-> Vec3 { - Vec3::new(self.x.clone(), self.y.clone(), self.z.clone()) //ignore W - } -} - -array!(impl Vec2 -> [S, ..2] _2) -array!(impl Vec3 -> [S, ..3] _3) -array!(impl Vec4 -> [S, ..4] _4) - /// A trait that specifies a range of numeric operations for vectors. Not all /// of these make sense from a linear algebra point of view, but are included /// for pragmatic reasons. @@ -169,45 +76,93 @@ pub trait Vector #[inline] pub fn dot>(a: V, b: V) -> S { a.dot(&b) } -impl Add, Vec2> for Vec2 { #[inline] fn add(&self, other: &Vec2) -> Vec2 { self.add_v(other) } } -impl Add, Vec3> for Vec3 { #[inline] fn add(&self, other: &Vec3) -> Vec3 { self.add_v(other) } } -impl Add, Vec4> for Vec4 { #[inline] fn add(&self, other: &Vec4) -> Vec4 { self.add_v(other) } } +// Utility macro for generating associated functions for the vectors +macro_rules! vec( + ($Self:ident <$S:ident> { $($field:ident),+ }, $n:expr) => ( + #[deriving(Eq, Clone)] + pub struct $Self { $($field: S),+ } -impl Sub, Vec2> for Vec2 { #[inline] fn sub(&self, other: &Vec2) -> Vec2 { self.sub_v(other) } } -impl Sub, Vec3> for Vec3 { #[inline] fn sub(&self, other: &Vec3) -> Vec3 { self.sub_v(other) } } -impl Sub, Vec4> for Vec4 { #[inline] fn sub(&self, other: &Vec4) -> Vec4 { self.sub_v(other) } } + impl<$S: Primitive> $Self<$S> { + #[inline] + pub fn new($($field: $S),+) -> $Self<$S> { + $Self { $($field: $field),+ } + } -impl Zero for Vec2 { #[inline] fn zero() -> Vec2 { Vec2::from_value(zero()) } #[inline] fn is_zero(&self) -> bool { *self == zero() } } -impl Zero for Vec3 { #[inline] fn zero() -> Vec3 { Vec3::from_value(zero()) } #[inline] fn is_zero(&self) -> bool { *self == zero() } } -impl Zero for Vec4 { #[inline] fn zero() -> Vec4 { Vec4::from_value(zero()) } #[inline] fn is_zero(&self) -> bool { *self == zero() } } + /// Construct a vector from a single value. + #[inline] + pub fn from_value(value: $S) -> $Self<$S> { + $Self { $($field: value.clone()),+ } + } -impl Neg> for Vec2 { #[inline] fn neg(&self) -> Vec2 { build(|i| self.i(i).neg()) } } -impl Neg> for Vec3 { #[inline] fn neg(&self) -> Vec3 { build(|i| self.i(i).neg()) } } -impl Neg> for Vec4 { #[inline] fn neg(&self) -> Vec4 { build(|i| self.i(i).neg()) } } + /// The additive identity of the vector. + #[inline] + pub fn zero() -> $Self<$S> { $Self::from_value(zero()) } -impl Mul, Vec2> for Vec2 { #[inline] fn mul(&self, other: &Vec2) -> Vec2 { self.mul_v(other) } } -impl Mul, Vec3> for Vec3 { #[inline] fn mul(&self, other: &Vec3) -> Vec3 { self.mul_v(other) } } -impl Mul, Vec4> for Vec4 { #[inline] fn mul(&self, other: &Vec4) -> Vec4 { self.mul_v(other) } } + /// The multiplicative identity of the vector. + #[inline] + pub fn ident() -> $Self<$S> { $Self::from_value(one()) } + } -impl One for Vec2 { #[inline] fn one() -> Vec2 { Vec2::from_value(one()) } } -impl One for Vec3 { #[inline] fn one() -> Vec3 { Vec3::from_value(one()) } } -impl One for Vec4 { #[inline] fn one() -> Vec4 { Vec4::from_value(one()) } } + impl Add<$Self, $Self> for $Self { + #[inline] fn add(&self, other: &$Self) -> $Self { self.add_v(other) } + } -impl Vector for Vec2 {} -impl Vector for Vec3 {} -impl Vector for Vec4 {} + impl Sub<$Self, $Self> for $Self { + #[inline] fn sub(&self, other: &$Self) -> $Self { self.sub_v(other) } + } + + impl Zero for $Self { + #[inline] fn zero() -> $Self { $Self::from_value(zero()) } + #[inline] fn is_zero(&self) -> bool { *self == zero() } + } + + impl Neg<$Self> for $Self { + #[inline] fn neg(&self) -> $Self { build(|i| self.i(i).neg()) } + } + + impl Mul<$Self, $Self> for $Self { + #[inline] fn mul(&self, other: &$Self) -> $Self { self.mul_v(other) } + } + + impl One for $Self { + #[inline] fn one() -> $Self { $Self::from_value(one()) } + } + + impl Vector for $Self {} + ) +) + +vec!(Vec2 { x, y }, 2) +vec!(Vec3 { x, y, z }, 3) +vec!(Vec4 { x, y, z, w }, 4) + +array!(impl Vec2 -> [S, ..2] _2) +array!(impl Vec3 -> [S, ..3] _3) +array!(impl Vec4 -> [S, ..4] _4) /// Operations specific to numeric two-dimensional vectors. impl Vec2 { + #[inline] pub fn unit_x() -> Vec2 { Vec2::new(one(), zero()) } + #[inline] pub fn unit_y() -> Vec2 { Vec2::new(zero(), one()) } + /// The perpendicular dot product of the vector and `other`. #[inline] pub fn perp_dot(&self, other: &Vec2) -> S { (self.x * other.y) - (self.y * other.x) } + + #[inline] + pub fn extend(&self, z: S)-> Vec3 { + Vec3::new(self.x.clone(), self.y.clone(), z) + } } /// Operations specific to numeric three-dimensional vectors. impl Vec3 { + #[inline] pub fn unit_x() -> Vec3 { Vec3::new(one(), zero(), zero()) } + #[inline] pub fn unit_y() -> Vec3 { Vec3::new(zero(), one(), zero()) } + #[inline] pub fn unit_z() -> Vec3 { Vec3::new(zero(), zero(), one()) } + /// Returns the cross product of the vector and `other`. #[inline] pub fn cross(&self, other: &Vec3) -> Vec3 { @@ -222,6 +177,29 @@ impl Vec3 { pub fn cross_self(&mut self, other: &Vec3) { *self = self.cross(other) } + + #[inline] + pub fn extend(&self, w: S)-> Vec4 { + Vec4::new(self.x.clone(), self.y.clone(), self.z.clone(), w) + } + + #[inline] + pub fn truncate(&self)-> Vec2 { + Vec2::new(self.x.clone(), self.y.clone()) //ignore Z + } +} + +/// Operations specific to numeric four-dimensional vectors. +impl Vec4 { + #[inline] pub fn unit_x() -> Vec4 { Vec4::new(one(), zero(), zero(), zero()) } + #[inline] pub fn unit_y() -> Vec4 { Vec4::new(zero(), one(), zero(), zero()) } + #[inline] pub fn unit_z() -> Vec4 { Vec4::new(zero(), zero(), one(), zero()) } + #[inline] pub fn unit_w() -> Vec4 { Vec4::new(zero(), zero(), zero(), one()) } + + #[inline] + pub fn truncate(&self)-> Vec3 { + Vec3::new(self.x.clone(), self.y.clone(), self.z.clone()) //ignore W + } } /// Specifies geometric operations for vectors. This is only implemented for