Add angle calculation method to vectors, improve vector unit tests

This commit is contained in:
Brendan Zabarauskas 2012-12-13 22:01:55 +10:00
parent 965bade82c
commit 3d31797d8d
3 changed files with 71 additions and 12 deletions

View file

@ -113,28 +113,33 @@ pub trait InvTrig {
pure fn asin(&self) -> Radians<self>;
pure fn acos(&self) -> Radians<self>;
pure fn atan(&self) -> Radians<self>;
pure fn atan2(&self, other: &self) -> Radians<self>;
}
#[inline(always)] pub pure fn asin<T:InvTrig>(x: &T) -> Radians<T> { x.asin() }
#[inline(always)] pub pure fn acos<T:InvTrig>(x: &T) -> Radians<T> { x.acos() }
#[inline(always)] pub pure fn atan<T:InvTrig>(x: &T) -> Radians<T> { x.atan() }
#[inline(always)] pub pure fn atan2<T:InvTrig>(a: &T, b: &T) -> Radians<T> { a.atan2(b) }
pub impl f32: InvTrig {
#[inline(always)] pure fn asin(&self) -> Radians<f32> { Radians(f32::asin(*self)) }
#[inline(always)] pure fn acos(&self) -> Radians<f32> { Radians(f32::acos(*self)) }
#[inline(always)] pure fn atan(&self) -> Radians<f32> { Radians(f32::atan(*self)) }
#[inline(always)] pure fn atan2(&self, other: &f32) -> Radians<f32> { Radians(f32::atan2(*self, *other)) }
}
pub impl f64: InvTrig {
#[inline(always)] pure fn asin(&self) -> Radians<f64> { Radians(f64::asin(*self)) }
#[inline(always)] pure fn acos(&self) -> Radians<f64> { Radians(f64::acos(*self)) }
#[inline(always)] pure fn atan(&self) -> Radians<f64> { Radians(f64::atan(*self)) }
#[inline(always)] pure fn atan2(&self, other: &f64) -> Radians<f64> { Radians(f64::atan2(*self, *other)) }
}
pub impl float: InvTrig {
#[inline(always)] pure fn asin(&self) -> Radians<float> { Radians(f64::asin(*self as f64) as float) }
#[inline(always)] pure fn acos(&self) -> Radians<float> { Radians(f64::acos(*self as f64) as float) }
#[inline(always)] pure fn atan(&self) -> Radians<float> { Radians(f64::atan(*self as f64) as float) }
#[inline(always)] pure fn atan2(&self, other: &float) -> Radians<float> { Radians(f64::atan2(*self as f64, *other as f64) as float) }
}
// TODO: figure out how to merge with InvTrig

View file

@ -1,4 +1,5 @@
use std::cmp::FuzzyEq;
use angle::*;
use vec::*;
// TODO
@ -81,8 +82,6 @@ fn test_Vec2_euclidean() {
let b0 = Vec2::new(3f, 4f); // (3, 4, 5) Pythagorean triple
let b = a.add_v(&b0);
// TODO: test normalize and normalize_self
assert a.length() == 13f;
assert a.length2() == 13f * 13f;
@ -92,6 +91,13 @@ fn test_Vec2_euclidean() {
assert a.distance(&b) == 5f;
assert a.distance2(&b) == 5f * 5f;
assert Vec2::new(1f, 0f).angle(&Vec2::new(0f, 1f)).fuzzy_eq(&Angle::quadrant());
assert Vec2::new(10f, 0f).angle(&Vec2::new(0f, 5f)).fuzzy_eq(&Angle::quadrant());
assert Vec2::new(-1f, 0f).angle(&Vec2::new(0f, 1f)).fuzzy_eq(&-Angle::quadrant());
assert Vec2::new(3f, 4f).normalize().fuzzy_eq(&Vec2::new(3f/5f, 4f/5f));
// TODO: test normalize_to, normalize_self, and normalize_self_to
let c = Vec2::new(-2.0f, -1.0f);
let d = Vec2::new( 1.0f, 0.0f);
@ -195,8 +201,6 @@ fn test_Vec3_euclidean() {
let b0 = Vec3::new(1f, 4f, 8f); // (1, 4, 8, 9) Pythagorean quadruple
let b = a.add_v(&b0);
// TODO: test normalize and normalize_self
assert a.length() == 7f;
assert a.length2() == 7f * 7f;
@ -206,6 +210,13 @@ fn test_Vec3_euclidean() {
assert a.distance(&b) == 9f;
assert a.distance2(&b) == 9f * 9f;
assert Vec3::new(1f, 0f, 1f).angle(&Vec3::new(1f, 1f, 0f)).fuzzy_eq(&Angle::sextant());
assert Vec3::new(10f, 0f, 10f).angle(&Vec3::new(5f, 5f, 0f)).fuzzy_eq(&Angle::sextant());
assert Vec3::new(-1f, 0f, -1f).angle(&Vec3::new(1f, -1f, 0f)).fuzzy_eq(&Radians(2f * Float::frac_pi_3()));
assert Vec3::new(2f, 3f, 6f).normalize().fuzzy_eq(&Vec3::new(2f/7f, 3f/7f, 6f/7f));
// TODO: test normalize_to, normalize_self, and normalize_self_to
let c = Vec3::new(-2.0f, -1.0f, 1.0f);
let d = Vec3::new( 1.0f, 0.0f, 0.5f);
@ -309,8 +320,6 @@ fn test_Vec4_euclidean() {
let b0 = Vec4::new(1f, 2f, 8f, 10f); // (1, 2, 8, 10, 13) Pythagorean quintuple
let b = a.add_v(&b0);
// TODO: test normalize and normalize_self
assert a.length() == 11f;
assert a.length2() == 11f * 11f;
@ -319,6 +328,13 @@ fn test_Vec4_euclidean() {
assert a.distance(&b) == 13f;
assert a.distance2(&b) == 13f * 13f;
assert Vec4::new(1f, 0f, 1f, 0f).angle(&Vec4::new(0f, 1f, 0f, 1f)).fuzzy_eq(&Angle::quadrant());
assert Vec4::new(10f, 0f, 10f, 0f).angle(&Vec4::new(0f, 5f, 0f, 5f)).fuzzy_eq(&Angle::quadrant());
assert Vec4::new(-1f, 0f, -1f, 0f).angle(&Vec4::new(0f, 1f, 0f, 1f)).fuzzy_eq(&Angle::quadrant());
assert Vec4::new(1f, 2f, 4f, 10f).normalize().fuzzy_eq(&Vec4::new(1f/11f, 2f/11f, 4f/11f, 10f/11f));
// TODO: test normalize_to, normalize_self, and normalize_self_to
let c = Vec4::new(-2.0f, -1.0f, 1.0f, 2.0f);
let d = Vec4::new( 1.0f, 0.0f, 0.5f, 1.0f);

View file

@ -6,7 +6,9 @@ use core::vec::raw::buf_as_slice;
use std::cmp::FuzzyEq;
use angle::Radians;
use funs::exponential::Exp;
use funs::triganomic::{InvTrig, acos, atan2};
use num::types::Number;
/**
@ -158,6 +160,13 @@ pub trait MutableNumericVector<T>: MutableVector<&self/T> NumericVector<T> {
pub trait NumericVector2<T>: NumericVector<T> {
// static pure fn unit_x() -> self;
// static pure fn unit_y() -> self;
/**
* # Return value
*
* The perp dot product of the vector and `other`
*/
pure fn perp_dot(&self, other: &self) -> T;
}
/**
@ -239,6 +248,13 @@ pub trait EuclideanVector<T>: NumericVector<T> {
*/
pure fn distance(&self, other: &self) -> T;
/**
* # Return value
*
* The angle between the vector and `other`
*/
pure fn angle(&self, other: &self) -> Radians<T>;
/**
* # Return value
*
@ -435,7 +451,14 @@ pub impl<T:Copy Number> Vec2<T>: MutableNumericVector<&self/T> {
}
}
pub impl<T:Copy Number Exp> Vec2<T>: EuclideanVector<T> {
pub impl<T:Copy Number> Vec2<T>: NumericVector2<T> {
#[inline(always)]
pure fn perp_dot(&self, other: &Vec2<T>) ->T {
(self[0] * other[1]) - (self[1] * other[0])
}
}
pub impl<T:Copy Number Exp InvTrig> Vec2<T>: EuclideanVector<T> {
#[inline(always)]
pure fn length2(&self) -> T {
self.dot(self)
@ -456,6 +479,11 @@ pub impl<T:Copy Number Exp> Vec2<T>: EuclideanVector<T> {
other.distance2(self).sqrt()
}
#[inline(always)]
pure fn angle(&self, other: &Vec2<T>) -> Radians<T> {
atan2(&self.perp_dot(other), &self.dot(other))
}
#[inline(always)]
pure fn normalize(&self) -> Vec2<T> {
let mut n: T = Number::from(1);
@ -475,7 +503,7 @@ pub impl<T:Copy Number Exp> Vec2<T>: EuclideanVector<T> {
}
}
pub impl<T:Copy Number Exp> Vec2<T>: MutableEuclideanVector<&self/T> {
pub impl<T:Copy Number Exp InvTrig> Vec2<T>: MutableEuclideanVector<&self/T> {
#[inline(always)]
fn normalize_self(&mut self) {
let mut n: T = Number::from(1);
@ -695,7 +723,7 @@ pub impl<T:Copy Number> Vec3<T>: MutableNumericVector3<&self/T> {
}
}
pub impl<T:Copy Number Exp> Vec3<T>: EuclideanVector<T> {
pub impl<T:Copy Number Exp InvTrig> Vec3<T>: EuclideanVector<T> {
#[inline(always)]
pure fn length2(&self) -> T {
self.dot(self)
@ -716,6 +744,11 @@ pub impl<T:Copy Number Exp> Vec3<T>: EuclideanVector<T> {
other.distance2(self).sqrt()
}
#[inline(always)]
pure fn angle(&self, other: &Vec3<T>) -> Radians<T> {
atan2(&self.cross(other).length(), &self.dot(other))
}
#[inline(always)]
pure fn normalize(&self) -> Vec3<T> {
let mut n: T = Number::from(1);
@ -735,7 +768,7 @@ pub impl<T:Copy Number Exp> Vec3<T>: EuclideanVector<T> {
}
}
pub impl<T:Copy Number Exp> Vec3<T>: MutableEuclideanVector<&self/T> {
pub impl<T:Copy Number Exp InvTrig> Vec3<T>: MutableEuclideanVector<&self/T> {
#[inline(always)]
fn normalize_self(&mut self) {
let mut n: T = Number::from(1);
@ -955,7 +988,7 @@ pub impl<T:Copy Number> Vec4<T>: MutableNumericVector<&self/T> {
}
}
pub impl<T:Copy Number Exp> Vec4<T>: EuclideanVector<T> {
pub impl<T:Copy Number Exp InvTrig> Vec4<T>: EuclideanVector<T> {
#[inline(always)]
pure fn length2(&self) -> T {
self.dot(self)
@ -976,6 +1009,11 @@ pub impl<T:Copy Number Exp> Vec4<T>: EuclideanVector<T> {
other.distance2(self).sqrt()
}
#[inline(always)]
pure fn angle(&self, other: &Vec4<T>) -> Radians<T> {
acos(&(self.dot(other) / (self.length() * other.length())))
}
#[inline(always)]
pure fn normalize(&self) -> Vec4<T> {
let mut n: T = Number::from(1);
@ -995,7 +1033,7 @@ pub impl<T:Copy Number Exp> Vec4<T>: EuclideanVector<T> {
}
}
pub impl<T:Copy Number Exp> Vec4<T>: MutableEuclideanVector<&self/T> {
pub impl<T:Copy Number Exp InvTrig> Vec4<T>: MutableEuclideanVector<&self/T> {
#[inline(always)]
fn normalize_self(&mut self) {
let mut n: T = Number::from(1);