Merge pull request #293 from bitshifter/scalarops
Support for scalar on the lhs of arithmetic operators
This commit is contained in:
commit
58cde94eb7
7 changed files with 310 additions and 1 deletions
|
@ -95,6 +95,26 @@ macro_rules! impl_operator {
|
|||
}
|
||||
}
|
||||
};
|
||||
// When the left operand is a scalar
|
||||
($Op:ident<$Rhs:ident<$S:ident>> for $Lhs:ty {
|
||||
fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr }
|
||||
}) => {
|
||||
impl $Op<$Rhs<$S>> for $Lhs {
|
||||
type Output = $Output;
|
||||
#[inline]
|
||||
fn $op(self, other: $Rhs<$S>) -> $Output {
|
||||
let ($lhs, $rhs) = (self, other); $body
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> $Op<&'a $Rhs<$S>> for $Lhs {
|
||||
type Output = $Output;
|
||||
#[inline]
|
||||
fn $op(self, other: &'a $Rhs<$S>) -> $Output {
|
||||
let ($lhs, $rhs) = (self, other); $body
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_assignment_operator {
|
||||
|
|
27
src/point.rs
27
src/point.rs
|
@ -172,6 +172,19 @@ macro_rules! impl_point {
|
|||
fn rem_assign(&mut self, scalar) { $(self.$field %= scalar);+ }
|
||||
});
|
||||
|
||||
impl_scalar_ops!($PointN<usize> { $($field),+ });
|
||||
impl_scalar_ops!($PointN<u8> { $($field),+ });
|
||||
impl_scalar_ops!($PointN<u16> { $($field),+ });
|
||||
impl_scalar_ops!($PointN<u32> { $($field),+ });
|
||||
impl_scalar_ops!($PointN<u64> { $($field),+ });
|
||||
impl_scalar_ops!($PointN<isize> { $($field),+ });
|
||||
impl_scalar_ops!($PointN<i8> { $($field),+ });
|
||||
impl_scalar_ops!($PointN<i16> { $($field),+ });
|
||||
impl_scalar_ops!($PointN<i32> { $($field),+ });
|
||||
impl_scalar_ops!($PointN<i64> { $($field),+ });
|
||||
impl_scalar_ops!($PointN<f32> { $($field),+ });
|
||||
impl_scalar_ops!($PointN<f64> { $($field),+ });
|
||||
|
||||
impl_index_operators!($PointN<S>, $n, S, usize);
|
||||
impl_index_operators!($PointN<S>, $n, [S], Range<usize>);
|
||||
impl_index_operators!($PointN<S>, $n, [S], RangeTo<usize>);
|
||||
|
@ -180,6 +193,20 @@ macro_rules! impl_point {
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_scalar_ops {
|
||||
($PointN:ident<$S:ident> { $($field:ident),+ }) => {
|
||||
impl_operator!(Mul<$PointN<$S>> for $S {
|
||||
fn mul(scalar, vector) -> $PointN<$S> { $PointN::new($(scalar * vector.$field),+) }
|
||||
});
|
||||
impl_operator!(Div<$PointN<$S>> for $S {
|
||||
fn div(scalar, vector) -> $PointN<$S> { $PointN::new($(scalar / vector.$field),+) }
|
||||
});
|
||||
impl_operator!(Rem<$PointN<$S>> for $S {
|
||||
fn rem(scalar, vector) -> $PointN<$S> { $PointN::new($(scalar % vector.$field),+) }
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
impl_point!(Point2 { x, y }, Vector2, 2);
|
||||
impl_point!(Point3 { x, y, z }, Vector3, 3);
|
||||
|
||||
|
|
|
@ -167,6 +167,31 @@ impl_operator!(<S: BaseFloat> Mul<Quaternion<S> > for Quaternion<S> {
|
|||
}
|
||||
});
|
||||
|
||||
macro_rules! impl_scalar_mul {
|
||||
($S:ident) => {
|
||||
impl_operator!(Mul<Quaternion<$S>> for $S {
|
||||
fn mul(scalar, quat) -> Quaternion<$S> {
|
||||
Quaternion::from_sv(scalar * quat.s, scalar * quat.v)
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_scalar_div {
|
||||
($S:ident) => {
|
||||
impl_operator!(Div<Quaternion<$S>> for $S {
|
||||
fn div(scalar, quat) -> Quaternion<$S> {
|
||||
Quaternion::from_sv(scalar / quat.s, scalar / quat.v)
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
impl_scalar_mul!(f32);
|
||||
impl_scalar_mul!(f64);
|
||||
impl_scalar_div!(f32);
|
||||
impl_scalar_div!(f64);
|
||||
|
||||
impl<S: BaseFloat> ApproxEq for Quaternion<S> {
|
||||
type Epsilon = S;
|
||||
|
||||
|
|
|
@ -244,6 +244,7 @@ macro_rules! impl_vector {
|
|||
impl_operator!(<S: BaseNum> Mul<$VectorN<S> > for $VectorN<S> {
|
||||
fn mul(lhs, rhs) -> $VectorN<S> { $VectorN::new($(lhs.$field * rhs.$field),+) }
|
||||
});
|
||||
|
||||
impl_assignment_operator!(<S: BaseNum> MulAssign<S> for $VectorN<S> {
|
||||
fn mul_assign(&mut self, scalar) { $(self.$field *= scalar);+ }
|
||||
});
|
||||
|
@ -277,6 +278,19 @@ macro_rules! impl_vector {
|
|||
fn rem_assign(&mut self, other) { $(self.$field %= other.$field);+ }
|
||||
});
|
||||
|
||||
impl_scalar_ops!($VectorN<usize> { $($field),+ });
|
||||
impl_scalar_ops!($VectorN<u8> { $($field),+ });
|
||||
impl_scalar_ops!($VectorN<u16> { $($field),+ });
|
||||
impl_scalar_ops!($VectorN<u32> { $($field),+ });
|
||||
impl_scalar_ops!($VectorN<u64> { $($field),+ });
|
||||
impl_scalar_ops!($VectorN<isize> { $($field),+ });
|
||||
impl_scalar_ops!($VectorN<i8> { $($field),+ });
|
||||
impl_scalar_ops!($VectorN<i16> { $($field),+ });
|
||||
impl_scalar_ops!($VectorN<i32> { $($field),+ });
|
||||
impl_scalar_ops!($VectorN<i64> { $($field),+ });
|
||||
impl_scalar_ops!($VectorN<f32> { $($field),+ });
|
||||
impl_scalar_ops!($VectorN<f64> { $($field),+ });
|
||||
|
||||
impl_index_operators!($VectorN<S>, $n, S, usize);
|
||||
impl_index_operators!($VectorN<S>, $n, [S], Range<usize>);
|
||||
impl_index_operators!($VectorN<S>, $n, [S], RangeTo<usize>);
|
||||
|
@ -285,6 +299,26 @@ macro_rules! impl_vector {
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_scalar_ops {
|
||||
($VectorN:ident<$S:ident> { $($field:ident),+ }) => {
|
||||
impl_operator!(Add<$VectorN<$S>> for $S {
|
||||
fn add(scalar, vector) -> $VectorN<$S> { $VectorN::new($(scalar + vector.$field),+) }
|
||||
});
|
||||
impl_operator!(Sub<$VectorN<$S>> for $S {
|
||||
fn sub(scalar, vector) -> $VectorN<$S> { $VectorN::new($(scalar - vector.$field),+) }
|
||||
});
|
||||
impl_operator!(Mul<$VectorN<$S>> for $S {
|
||||
fn mul(scalar, vector) -> $VectorN<$S> { $VectorN::new($(scalar * vector.$field),+) }
|
||||
});
|
||||
impl_operator!(Div<$VectorN<$S>> for $S {
|
||||
fn div(scalar, vector) -> $VectorN<$S> { $VectorN::new($(scalar / vector.$field),+) }
|
||||
});
|
||||
impl_operator!(Rem<$VectorN<$S>> for $S {
|
||||
fn rem(scalar, vector) -> $VectorN<$S> { $VectorN::new($(scalar % vector.$field),+) }
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
impl_vector!(Vector2<S> { x, y }, 2, vec2);
|
||||
impl_vector!(Vector3<S> { x, y, z }, 3, vec3);
|
||||
impl_vector!(Vector4<S> { x, y, z, w }, 4, vec4);
|
||||
|
|
|
@ -16,11 +16,62 @@
|
|||
|
||||
extern crate cgmath;
|
||||
|
||||
use cgmath::Point3;
|
||||
use cgmath::{Point2, Point3};
|
||||
use cgmath::ApproxEq;
|
||||
|
||||
macro_rules! impl_test_mul {
|
||||
($PointN:ident { $($field:ident),+ }, $s:expr, $v:expr) => (
|
||||
// point * scalar ops
|
||||
assert_eq!($v * $s, $PointN::new($($v.$field * $s),+));
|
||||
assert_eq!($s * $v, $PointN::new($($s * $v.$field),+));
|
||||
assert_eq!(&$v * $s, $v * $s);
|
||||
assert_eq!($s * &$v, $s * $v);
|
||||
// commutativity
|
||||
assert_eq!($v * $s, $s * $v);
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! impl_test_div {
|
||||
($PointN:ident { $($field:ident),+ }, $s:expr, $v:expr) => (
|
||||
// point / scalar ops
|
||||
assert_eq!($v / $s, $PointN::new($($v.$field / $s),+));
|
||||
assert_eq!($s / $v, $PointN::new($($s / $v.$field),+));
|
||||
assert_eq!(&$v / $s, $v / $s);
|
||||
assert_eq!($s / &$v, $s / $v);
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! impl_test_rem {
|
||||
($PointN:ident { $($field:ident),+ }, $s:expr, $v:expr) => (
|
||||
// point % scalar ops
|
||||
assert_eq!($v % $s, $PointN::new($($v.$field % $s),+));
|
||||
assert_eq!($s % $v, $PointN::new($($s % $v.$field),+));
|
||||
assert_eq!(&$v % $s, $v % $s);
|
||||
assert_eq!($s % &$v, $s % $v);
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_homogeneous() {
|
||||
let p = Point3::new(1.0f64, 2.0f64, 3.0f64);
|
||||
assert!(p.approx_eq(&Point3::from_homogeneous(p.to_homogeneous())));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mul() {
|
||||
impl_test_mul!(Point3 { x, y, z }, 2.0f32, Point3::new(2.0f32, 4.0, 6.0));
|
||||
impl_test_mul!(Point2 { x, y }, 2.0f32, Point2::new(2.0f32, 4.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_div() {
|
||||
impl_test_div!(Point3 { x, y, z }, 2.0f32, Point3::new(2.0f32, 4.0, 6.0));
|
||||
impl_test_div!(Point2 { x, y }, 2.0f32, Point2::new(2.0f32, 4.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rem() {
|
||||
impl_test_rem!(Point3 { x, y, z }, 2.0f32, Point3::new(2.0f32, 4.0, 6.0));
|
||||
impl_test_rem!(Point2 { x, y }, 2.0f32, Point2::new(2.0f32, 4.0));
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,42 @@
|
|||
#[macro_use]
|
||||
extern crate cgmath;
|
||||
|
||||
macro_rules! impl_test_mul {
|
||||
($s:expr, $v:expr) => (
|
||||
// point * scalar ops
|
||||
assert_eq!($v * $s, Quaternion::from_sv($v.s * $s, $v.v * $s));
|
||||
assert_eq!($s * $v, Quaternion::from_sv($s * $v.s, $s * $v.v));
|
||||
assert_eq!(&$v * $s, $v * $s);
|
||||
assert_eq!($s * &$v, $s * $v);
|
||||
// commutativity
|
||||
assert_eq!($v * $s, $s * $v);
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! impl_test_div {
|
||||
($s:expr, $v:expr) => (
|
||||
// point / scalar ops
|
||||
assert_eq!($v / $s, Quaternion::from_sv($v.s / $s, $v.v / $s));
|
||||
assert_eq!($s / $v, Quaternion::from_sv($s / $v.s, $s / $v.v));
|
||||
assert_eq!(&$v / $s, $v / $s);
|
||||
assert_eq!($s / &$v, $s / $v);
|
||||
)
|
||||
}
|
||||
|
||||
mod operators {
|
||||
use cgmath::*;
|
||||
|
||||
#[test]
|
||||
fn test_mul() {
|
||||
impl_test_mul!(2.0f32, Quaternion::from_euler(rad(1f32), rad(1f32), rad(1f32)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_div() {
|
||||
impl_test_div!(2.0f32, Quaternion::from_euler(rad(1f32), rad(1f32), rad(1f32)));
|
||||
}
|
||||
}
|
||||
|
||||
mod to_from_euler {
|
||||
use std::f32;
|
||||
|
||||
|
|
116
tests/vector.rs
116
tests/vector.rs
|
@ -33,6 +33,122 @@ fn test_from_value() {
|
|||
assert_eq!(Vector4::from_value(76.5f64), Vector4::new(76.5f64, 76.5f64, 76.5f64, 76.5f64));
|
||||
}
|
||||
|
||||
macro_rules! impl_test_add {
|
||||
($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => (
|
||||
// vector + vector ops
|
||||
assert_eq!($v + $v, $VectorN::new($($v.$field + $v.$field),+));
|
||||
assert_eq!(&$v + &$v, $v + $v);
|
||||
assert_eq!(&$v + $v, $v + $v);
|
||||
assert_eq!($v + &$v, $v + $v);
|
||||
// vector + scalar ops
|
||||
assert_eq!($v + $s, $VectorN::new($($v.$field + $s),+));
|
||||
assert_eq!($s + $v, $VectorN::new($($s + $v.$field),+));
|
||||
assert_eq!(&$v + $s, $v + $s);
|
||||
assert_eq!($s + &$v, $s + $v);
|
||||
// commutativity
|
||||
assert_eq!($v + $s, $s + $v);
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! impl_test_sub {
|
||||
($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => (
|
||||
// vector - vector ops
|
||||
assert_eq!($v - $v, $VectorN::new($($v.$field - $v.$field),+));
|
||||
assert_eq!(&$v - &$v, $v - $v);
|
||||
assert_eq!(&$v - $v, $v - $v);
|
||||
assert_eq!($v - &$v, $v - $v);
|
||||
// vector - scalar ops
|
||||
assert_eq!($v - $s, $VectorN::new($($v.$field - $s),+));
|
||||
assert_eq!($s - $v, $VectorN::new($($s - $v.$field),+));
|
||||
assert_eq!(&$v - $s, $v - $s);
|
||||
assert_eq!($s - &$v, $s - $v);
|
||||
// commutativity
|
||||
assert_eq!($v - $s, -($s - $v));
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! impl_test_mul {
|
||||
($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => (
|
||||
// vector * vector ops
|
||||
assert_eq!($v * $v, $VectorN::new($($v.$field * $v.$field),+));
|
||||
assert_eq!(&$v * &$v, $v * $v);
|
||||
assert_eq!(&$v * $v, $v * $v);
|
||||
assert_eq!($v * &$v, $v * $v);
|
||||
// vector * scalar ops
|
||||
assert_eq!($v * $s, $VectorN::new($($v.$field * $s),+));
|
||||
assert_eq!($s * $v, $VectorN::new($($s * $v.$field),+));
|
||||
assert_eq!(&$v * $s, $v * $s);
|
||||
assert_eq!($s * &$v, $s * $v);
|
||||
// commutativity
|
||||
assert_eq!($v * $s, $s * $v);
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! impl_test_div {
|
||||
($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => (
|
||||
// vector / vector ops
|
||||
assert_eq!($v / $v, $VectorN::new($($v.$field / $v.$field),+));
|
||||
assert_eq!(&$v / &$v, $v / $v);
|
||||
assert_eq!(&$v / $v, $v / $v);
|
||||
assert_eq!($v / &$v, $v / $v);
|
||||
// vector / scalar ops
|
||||
assert_eq!($v / $s, $VectorN::new($($v.$field / $s),+));
|
||||
assert_eq!($s / $v, $VectorN::new($($s / $v.$field),+));
|
||||
assert_eq!(&$v / $s, $v / $s);
|
||||
assert_eq!($s / &$v, $s / $v);
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! impl_test_rem {
|
||||
($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => (
|
||||
// vector % vector ops
|
||||
assert_eq!($v % $v, $VectorN::new($($v.$field % $v.$field),+));
|
||||
assert_eq!(&$v % &$v, $v % $v);
|
||||
assert_eq!(&$v % $v, $v % $v);
|
||||
assert_eq!($v % &$v, $v % $v);
|
||||
// vector % scalar ops
|
||||
assert_eq!($v % $s, $VectorN::new($($v.$field % $s),+));
|
||||
assert_eq!($s % $v, $VectorN::new($($s % $v.$field),+));
|
||||
assert_eq!(&$v % $s, $v % $s);
|
||||
assert_eq!($s % &$v, $s % $v);
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_add() {
|
||||
impl_test_add!(Vector4 { x, y, z, w }, 2.0f32, vec4(2.0f32, 4.0, 6.0, 8.0));
|
||||
impl_test_add!(Vector3 { x, y, z }, 2.0f32, vec3(2.0f32, 4.0, 6.0));
|
||||
impl_test_add!(Vector2 { x, y }, 2.0f32, vec2(2.0f32, 4.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sub() {
|
||||
impl_test_sub!(Vector4 { x, y, z, w }, 2.0f32, vec4(2.0f32, 4.0, 6.0, 8.0));
|
||||
impl_test_sub!(Vector3 { x, y, z }, 2.0f32, vec3(2.0f32, 4.0, 6.0));
|
||||
impl_test_sub!(Vector2 { x, y }, 2.0f32, vec2(2.0f32, 4.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mul() {
|
||||
impl_test_mul!(Vector4 { x, y, z, w }, 2.0f32, vec4(2.0f32, 4.0, 6.0, 8.0));
|
||||
impl_test_mul!(Vector3 { x, y, z }, 2.0f32, vec3(2.0f32, 4.0, 6.0));
|
||||
impl_test_mul!(Vector2 { x, y }, 2.0f32, vec2(2.0f32, 4.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_div() {
|
||||
impl_test_div!(Vector4 { x, y, z, w }, 2.0f32, vec4(2.0f32, 4.0, 6.0, 8.0));
|
||||
impl_test_div!(Vector3 { x, y, z }, 2.0f32, vec3(2.0f32, 4.0, 6.0));
|
||||
impl_test_div!(Vector2 { x, y }, 2.0f32, vec2(2.0f32, 4.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rem() {
|
||||
impl_test_rem!(Vector4 { x, y, z, w }, 2.0f32, vec4(2.0f32, 4.0, 6.0, 8.0));
|
||||
impl_test_rem!(Vector3 { x, y, z }, 2.0f32, vec3(2.0f32, 4.0, 6.0));
|
||||
impl_test_rem!(Vector2 { x, y }, 2.0f32, vec2(2.0f32, 4.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dot() {
|
||||
assert_eq!(Vector2::new(1isize, 2isize).dot(Vector2::new(3isize, 4isize)), 11isize);
|
||||
|
|
Loading…
Reference in a new issue