#![macro_use] macro_rules! new_impl( ($t: ident, $($compN: ident),+) => ( impl $t { /// Creates a new vector. #[inline] pub fn new($($compN: N ),+) -> $t { $t { $($compN: $compN ),+ } } } ); ); macro_rules! conversion_impl( ($t: ident, $dim: expr) => ( impl AsRef<[N; $dim]> for $t { #[inline] fn as_ref(&self) -> &[N; $dim] { unsafe { mem::transmute(self) } } } impl AsMut<[N; $dim]> for $t { #[inline] fn as_mut(&mut self) -> &mut [N; $dim] { unsafe { mem::transmute(self) } } } impl<'a, N> From<&'a [N; $dim]> for &'a $t { #[inline] fn from(arr: &'a [N; $dim]) -> &'a $t { unsafe { mem::transmute(arr) } } } impl<'a, N> From<&'a mut [N; $dim]> for &'a mut $t { #[inline] fn from(arr: &'a mut [N; $dim]) -> &'a mut $t { unsafe { mem::transmute(arr) } } } ) ); macro_rules! at_fast_impl( ($t: ident, $dim: expr) => ( impl $t { /// Unsafe read access to a vector element by index. #[inline] pub unsafe fn at_fast(&self, i: usize) -> N { (*self.as_ref().get_unchecked(i)) } /// Unsafe write access to a vector element by index. #[inline] pub unsafe fn set_fast(&mut self, i: usize, val: N) { (*self.as_mut().get_unchecked_mut(i)) = val } } ) ); // FIXME: N should be bounded by Ord instead of BaseFloat… // However, f32/f64 does not implement Ord… macro_rules! pord_impl( ($t: ident, $comp0: ident, $($compN: ident),*) => ( impl POrd for $t { #[inline] fn inf(&self, other: &$t) -> $t { $t::new(self.$comp0.min(other.$comp0) $(, self.$compN.min(other.$compN))*) } #[inline] fn sup(&self, other: &$t) -> $t { $t::new(self.$comp0.max(other.$comp0) $(, self.$compN.max(other.$compN))*) } #[inline] #[allow(unused_mut)] // otherwise there will be a warning for is_eq or Vec1. fn partial_cmp(&self, other: &$t) -> POrdering { let is_lt = self.$comp0 < other.$comp0; let mut is_eq = self.$comp0 == other.$comp0; if is_lt { // < $( if self.$compN > other.$compN { return POrdering::NotComparable } )* POrdering::PartialLess } else { // >= $( if self.$compN < other.$compN { return POrdering::NotComparable } else if self.$compN > other.$compN { is_eq = false; } )* if is_eq { POrdering::PartialEqual } else { POrdering::PartialGreater } } } #[inline] fn partial_lt(&self, other: &$t) -> bool { self.$comp0 < other.$comp0 $(&& self.$compN < other.$compN)* } #[inline] fn partial_le(&self, other: &$t) -> bool { self.$comp0 <= other.$comp0 $(&& self.$compN <= other.$compN)* } #[inline] fn partial_gt(&self, other: &$t) -> bool { self.$comp0 > other.$comp0 $(&& self.$compN > other.$compN)* } #[inline] fn partial_ge(&self, other: &$t) -> bool { self.$comp0 >= other.$comp0 $(&& self.$compN >= other.$compN)* } } ) ); macro_rules! vec_axis_impl( ($t: ident, $($compN: ident),+) => ( impl $t { $( /// Create a unit vector with its `$compN` component equal to 1.0. #[inline] pub fn $compN() -> $t { let mut res: $t = ::zero(); res.$compN = ::one(); res } )+ } ) ); macro_rules! vec_cast_impl( ($t: ident, $($compN: ident),+) => ( impl> Cast<$t> for $t { #[inline] fn from(v: $t) -> $t { $t::new($(Cast::from(v.$compN)),+) } } ) ); macro_rules! indexable_impl( ($t: ident, $dim: expr) => ( impl Shape for $t { #[inline] fn shape(&self) -> usize { $dim } } impl Indexable for $t { #[inline] fn swap(&mut self, i1: usize, i2: usize) { unsafe { mem::transmute::<&mut $t, &mut [N; $dim]>(self).swap(i1, i2) } } #[inline] unsafe fn unsafe_at(&self, i: usize) -> N { (*mem::transmute::<&$t, &[N; $dim]>(self).get_unchecked(i)) } #[inline] unsafe fn unsafe_set(&mut self, i: usize, val: N) { (*mem::transmute::<&mut $t, &mut [N; $dim]>(self).get_unchecked_mut(i)) = val } } ) ); macro_rules! index_impl( ($t: ident) => ( impl Index for $t where [N]: Index { type Output = <[N] as Index>::Output; fn index(&self, i: T) -> &<[N] as Index>::Output { &self.as_ref()[i] } } impl IndexMut for $t where [N]: IndexMut { fn index_mut(&mut self, i: T) -> &mut <[N] as Index>::Output { &mut self.as_mut()[i] } } ) ); macro_rules! repeat_impl( ($t: ident, $param: ident, $($compN: ident),+) => ( impl Repeat for $t { /// Creates a new vector with all its components equal to a given value. #[inline] fn repeat($param: N) -> $t { $t{ $($compN: $param ),+ } } } ) ); macro_rules! iterable_impl( ($t: ident, $dim: expr) => ( impl Iterable for $t { #[inline] fn iter<'l>(&'l self) -> Iter<'l, N> { unsafe { mem::transmute::<&'l $t, &'l [N; $dim]>(self).iter() } } } ) ); macro_rules! iterable_mut_impl( ($t: ident, $dim: expr) => ( impl IterableMut for $t { #[inline] fn iter_mut<'l>(&'l mut self) -> IterMut<'l, N> { unsafe { mem::transmute::<&'l mut $t, &'l mut [N; $dim]>(self).iter_mut() } } } ) ); macro_rules! dim_impl( ($t: ident, $dim: expr) => ( impl Dim for $t { #[inline] fn dim(_: Option<$t>) -> usize { $dim } } ) ); macro_rules! container_impl( ($t: ident) => ( impl $t { /// The dimension of this entity. #[inline] pub fn len(&self) -> usize { Dim::dim(None::<$t>) } } ) ); macro_rules! basis_impl( ($t: ident, $dim: expr) => ( impl> Basis for $t { #[inline] fn canonical_basis) -> bool>(mut f: F) { for i in 0 .. $dim { if !f(Basis::canonical_basis_element(i).unwrap()) { return } } } #[inline] fn orthonormal_subspace_basis) -> bool>(n: &$t, mut f: F) { // Compute the basis of the orthogonal subspace using Gram-Schmidt // orthogonalization algorithm. let mut basis: Vec<$t> = Vec::new(); for i in 0 .. $dim { let mut basis_element : $t = ::zero(); unsafe { basis_element.set_fast(i, ::one()); } if basis.len() == $dim - 1 { break; } let mut elt = basis_element; elt = elt - *n * Dot::dot(&basis_element, n); for v in basis.iter() { elt = elt - *v * Dot::dot(&elt, v) }; if !ApproxEq::approx_eq(&Norm::sqnorm(&elt), &::zero()) { let new_element = Norm::normalize(&elt); if !f(new_element) { return }; basis.push(new_element); } } } #[inline] fn canonical_basis_element(i: usize) -> Option<$t> { if i < $dim { let mut basis_element : $t = ::zero(); unsafe { basis_element.set_fast(i, ::one()); } Some(basis_element) } else { None } } } ) ); macro_rules! axpy_impl( ($t: ident, $($compN: ident),+) => ( impl> Axpy for $t { #[inline] fn axpy(&mut self, a: &N, x: &$t) { $( self.$compN.axpy(a, &x.$compN); )+ } } ) ); macro_rules! add_impl( ($t: ident, $($compN: ident),+) => ( impl> Add<$t> for $t { type Output = $t; #[inline] fn add(self, right: $t) -> $t { $t::new($(self.$compN + right.$compN),+) } } impl> AddAssign<$t> for $t { #[inline] fn add_assign(&mut self, right: $t) { $( self.$compN += right.$compN; )+ } } ) ); macro_rules! scalar_add_impl( ($t: ident, $($compN: ident),+) => ( // $t against scalar impl> Add for $t { type Output = $t; #[inline] fn add(self, right: N) -> $t { $t::new($(self.$compN + right),+) } } impl> AddAssign for $t { #[inline] fn add_assign(&mut self, right: N) { $( self.$compN += right; )+ } } impl Add<$t> for f32 { type Output = $t; #[inline] fn add(self, right: $t) -> $t { $t::new($(self + right.$compN),+) } } impl Add<$t> for f64 { type Output = $t; #[inline] fn add(self, right: $t) -> $t { $t::new($(self + right.$compN),+) } } ) ); macro_rules! sub_impl( ($t: ident, $($compN: ident),+) => ( impl> Sub<$t> for $t { type Output = $t; #[inline] fn sub(self, right: $t) -> $t { $t::new($(self.$compN - right.$compN),+) } } impl> SubAssign<$t> for $t { #[inline] fn sub_assign(&mut self, right: $t) { $( self.$compN -= right.$compN; )+ } } ) ); macro_rules! scalar_sub_impl( ($t: ident, $($compN: ident),+) => ( impl> Sub for $t { type Output = $t; #[inline] fn sub(self, right: N) -> $t { $t::new($(self.$compN - right),+) } } impl> SubAssign for $t { #[inline] fn sub_assign(&mut self, right: N) { $( self.$compN -= right; )+ } } impl Sub<$t> for f32 { type Output = $t; #[inline] fn sub(self, right: $t) -> $t { $t::new($(self - right.$compN),+) } } impl Sub<$t> for f64 { type Output = $t; #[inline] fn sub(self, right: $t) -> $t { $t::new($(self - right.$compN),+) } } ) ); macro_rules! mul_impl( ($t: ident, $($compN: ident),+) => ( impl> Mul<$t> for $t { type Output = $t; #[inline] fn mul(self, right: $t) -> $t { $t::new($(self.$compN * right.$compN),+) } } impl> MulAssign<$t> for $t { #[inline] fn mul_assign(&mut self, right: $t) { $( self.$compN *= right.$compN; )+ } } ) ); macro_rules! scalar_mul_impl( ($t: ident, $($compN: ident),+) => ( impl> Mul for $t { type Output = $t; #[inline] fn mul(self, right: N) -> $t { $t::new($(self.$compN * right),+) } } impl> MulAssign for $t { #[inline] fn mul_assign(&mut self, right: N) { $( self.$compN *= right; )+ } } impl Mul<$t> for f32 { type Output = $t; #[inline] fn mul(self, right: $t) -> $t { $t::new($(self * right.$compN),+) } } impl Mul<$t> for f64 { type Output = $t; #[inline] fn mul(self, right: $t) -> $t { $t::new($(self * right.$compN),+) } } ) ); macro_rules! div_impl( ($t: ident, $($compN: ident),+) => ( impl> Div<$t> for $t { type Output = $t; #[inline] fn div(self, right: $t) -> $t { $t::new($(self.$compN / right.$compN),+) } } impl> DivAssign<$t> for $t { #[inline] fn div_assign(&mut self, right: $t) { $( self.$compN /= right.$compN; )+ } } ) ); macro_rules! scalar_div_impl( ($t: ident, $($compN: ident),+) => ( impl> Div for $t { type Output = $t; #[inline] fn div(self, right: N) -> $t { $t::new($(self.$compN / right),+) } } impl> DivAssign for $t { #[inline] fn div_assign(&mut self, right: N) { $( self.$compN /= right; )+ } } ) ); macro_rules! neg_impl( ($t: ident, $($compN: ident),+) => ( impl + Copy> Neg for $t { type Output = $t; #[inline] fn neg(self) -> $t { $t::new($(-self.$compN ),+) } } ) ); macro_rules! add ( // base case ($x:expr) => { $x }; // `$x` followed by at least one `$y,` ($x:expr, $($y:expr),+) => { // call min! on the tail `$y` Add::add($x, add!($($y),+)) } ); macro_rules! dot_impl( ($t: ident, $($compN: ident),+) => ( impl Dot for $t { #[inline] fn dot(&self, other: &$t) -> N { add!($(self.$compN * other.$compN ),+) } } ) ); macro_rules! translation_impl( ($t: ident) => ( impl + Neg> Translation<$t> for $t { #[inline] fn translation(&self) -> $t { *self } #[inline] fn inv_translation(&self) -> $t { -*self } #[inline] fn append_translation_mut(&mut self, t: &$t) { *self = *t + *self; } #[inline] fn append_translation(&self, t: &$t) -> $t { *t + *self } #[inline] fn prepend_translation_mut(&mut self, t: &$t) { *self = *self + *t; } #[inline] fn prepend_translation(&self, t: &$t) -> $t { *self + *t } #[inline] fn set_translation(&mut self, t: $t) { *self = t } } ) ); macro_rules! norm_impl( ($t: ident, $($compN: ident),+) => ( impl Norm for $t { #[inline] fn sqnorm(&self) -> N { Dot::dot(self, self) } #[inline] fn normalize(&self) -> $t { let mut res : $t = *self; let _ = res.normalize_mut(); res } #[inline] fn normalize_mut(&mut self) -> N { let l = Norm::norm(self); $(self.$compN = self.$compN / l;)* l } } ) ); macro_rules! approx_eq_impl( ($t: ident, $($compN: ident),+) => ( impl> ApproxEq for $t { #[inline] fn approx_epsilon(_: Option<$t>) -> N { ApproxEq::approx_epsilon(None::) } #[inline] fn approx_ulps(_: Option<$t>) -> u32 { ApproxEq::approx_ulps(None::) } #[inline] fn approx_eq(&self, other: &$t) -> bool { $(ApproxEq::approx_eq(&self.$compN, &other.$compN))&&+ } #[inline] fn approx_eq_eps(&self, other: &$t, eps: &N) -> bool { $(ApproxEq::approx_eq_eps(&self.$compN, &other.$compN, eps))&&+ } #[inline] fn approx_eq_ulps(&self, other: &$t, ulps: u32) -> bool { $(ApproxEq::approx_eq_ulps(&self.$compN, &other.$compN, ulps))&&+ } } ) ); macro_rules! zero_one_impl( ($t: ident, $($compN: ident),+) => ( impl One for $t where N: Copy + One + Sub + Add { #[inline] fn one() -> $t { $t { $($compN: ::one() ),+ } } } impl Zero for $t { #[inline] fn zero() -> $t { $t { $($compN: ::zero() ),+ } } #[inline] fn is_zero(&self) -> bool { $(self.$compN.is_zero() )&&+ } } ) ); macro_rules! from_iterator_impl( ($t: ident, $param0: ident) => ( impl FromIterator for $t { #[inline] fn from_iter>($param0: I) -> $t { let mut $param0 = $param0.into_iter(); $t::new($param0.next().unwrap()) } } ); ($t: ident, $param0: ident, $($paramN: ident),+) => ( impl FromIterator for $t { #[inline] fn from_iter>($param0: I) -> $t { let mut $param0 = $param0.into_iter(); $t::new($param0.next().unwrap(), $($paramN.next().unwrap()),+) } } ) ); macro_rules! bounded_impl( ($t: ident, $($compN: ident),+) => ( impl Bounded for $t { #[inline] fn max_value() -> $t { $t { $($compN: Bounded::max_value() ),+ } } #[inline] fn min_value() -> $t { $t { $($compN: Bounded::min_value() ),+ } } } ) ); macro_rules! vec_to_homogeneous_impl( ($t: ident, $t2: ident, $extra: ident, $($compN: ident),+) => ( impl ToHomogeneous<$t2> for $t { fn to_homogeneous(&self) -> $t2 { let mut res: $t2 = ::zero(); $( res.$compN = self.$compN; )+ res } } ) ); macro_rules! vec_from_homogeneous_impl( ($t: ident, $t2: ident, $extra: ident, $($compN: ident),+) => ( impl + One + Zero> FromHomogeneous<$t2> for $t { fn from(v: &$t2) -> $t { let mut res: $t = ::zero(); $( res.$compN = v.$compN; )+ res } } ) ); macro_rules! translate_impl( ($tv: ident, $t: ident) => ( impl + Sub> Translate<$t> for $tv { fn translate(&self, other: &$t) -> $t { *other + *self } fn inv_translate(&self, other: &$t) -> $t { *other - *self } } ) ); macro_rules! rotate_impl( ($t: ident) => ( impl Rotate for $t { fn rotate(&self, other: &O) -> O { *other } fn inv_rotate(&self, other: &O) -> O { *other } } ) ); macro_rules! transform_impl( ($tv: ident, $t: ident) => ( impl + Sub> Transform<$t> for $tv { fn transform(&self, other: &$t) -> $t { self.translate(other) } fn inv_transform(&self, other: &$t) -> $t { self.inv_translate(other) } } ) ); macro_rules! vec_as_pnt_impl( ($tv: ident, $t: ident, $($compN: ident),+) => ( impl $tv { /// Converts this vector to a point. #[inline] pub fn to_pnt(self) -> $t { $t::new( $(self.$compN),+ ) } /// Reinterprets this vector as a point. #[inline] pub fn as_pnt(&self) -> &$t { unsafe { mem::transmute(self) } } } ) ); macro_rules! num_float_vec_impl( ($t: ident) => ( impl NumVec for $t where N: BaseNum { } impl FloatVec for $t where N: BaseFloat + ApproxEq { } ) ); macro_rules! absolute_vec_impl( ($t: ident, $($compN: ident),+) => ( impl> Absolute<$t> for $t { #[inline] fn abs(m: &$t) -> $t { $t::new($(::abs(&m.$compN) ),+) } } ) ); macro_rules! arbitrary_impl( ($t: ident, $($compN: ident),*) => ( #[cfg(feature="arbitrary")] impl Arbitrary for $t { #[inline] fn arbitrary(g: &mut G) -> $t { $t { $($compN: Arbitrary::arbitrary(g),)* } } } ) ); macro_rules! rand_impl( ($t: ident, $($compN: ident),*) => ( impl Rand for $t { #[inline] fn rand(rng: &mut R) -> $t { $t { $($compN: Rand::rand(rng), )* } } } ) ); macro_rules! mean_impl( ($t: ident) => ( impl> Mean for $t { #[inline] fn mean(&self) -> N { let normalizer = ::cast(1.0f64 / self.len() as f64); self.iter().fold(::zero(), |acc, x| acc + *x * normalizer) } } ) ); macro_rules! vec_display_impl( ($t: ident) => ( impl fmt::Display for $t { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { try!(write!(f, "(")); let mut it = self.iter(); let precision = f.precision().unwrap_or(8); try!(write!(f, "{:.*}", precision, *it.next().unwrap())); for comp in it { try!(write!(f, ", {:.*}", precision, *comp)); } write!(f, ")") } } ) );