Add angle calculation method to vectors, improve vector unit tests
This commit is contained in:
parent
965bade82c
commit
3d31797d8d
3 changed files with 71 additions and 12 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
50
src/vec.rs
50
src/vec.rs
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue