Use angle types in appropriate locations
This commit is contained in:
parent
9c65b38231
commit
6117fef58b
5 changed files with 70 additions and 49 deletions
|
@ -13,10 +13,15 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Angle units for type-safe, self-documenting code.
|
||||
|
||||
pub use std::num::{sinh, cosh, tanh};
|
||||
pub use std::num::{asinh, acosh, atanh};
|
||||
|
||||
use std::num::Zero;
|
||||
|
||||
#[deriving(Clone, Eq, Ord, Zero)] struct Rad<S> { s: S }
|
||||
#[deriving(Clone, Eq, Ord, Zero)] struct Deg<S> { s: S }
|
||||
#[deriving(Clone, Eq, Ord, Zero)] pub struct Rad<S> { s: S }
|
||||
#[deriving(Clone, Eq, Ord, Zero)] pub struct Deg<S> { s: S }
|
||||
|
||||
#[inline] pub fn rad<S: Clone + Float>(s: S) -> Rad<S> { Rad { s: s } }
|
||||
#[inline] pub fn deg<S: Clone + Float>(s: S) -> Deg<S> { Deg { s: s } }
|
||||
|
@ -33,6 +38,25 @@ impl<S: Clone + Float> ToDeg<S> for Deg<S> { #[inline] fn to_deg(&self) -> Deg<S
|
|||
impl<S: Clone + Float> Neg<Rad<S>> for Rad<S> { #[inline] fn neg(&self) -> Rad<S> { rad(-self.s) } }
|
||||
impl<S: Clone + Float> Neg<Deg<S>> for Deg<S> { #[inline] fn neg(&self) -> Deg<S> { deg(-self.s) } }
|
||||
|
||||
/// Private utility functions for converting to/from scalars
|
||||
trait ScalarConv<S> {
|
||||
fn from(s: S) -> Self;
|
||||
fn s<'a>(&'a self) -> &'a S;
|
||||
fn mut_s<'a>(&'a mut self) -> &'a mut S;
|
||||
}
|
||||
|
||||
impl<S: Clone + Float> ScalarConv<S> for Rad<S> {
|
||||
#[inline] fn from(s: S) -> Rad<S> { rad(s) }
|
||||
#[inline] fn s<'a>(&'a self) -> &'a S { &'a self.s }
|
||||
#[inline] fn mut_s<'a>(&'a mut self) -> &'a mut S { &'a mut self.s }
|
||||
}
|
||||
|
||||
impl<S: Clone + Float> ScalarConv<S> for Deg<S> {
|
||||
#[inline] fn from(s: S) -> Deg<S> { deg(s) }
|
||||
#[inline] fn s<'a>(&'a self) -> &'a S { &'a self.s }
|
||||
#[inline] fn mut_s<'a>(&'a mut self) -> &'a mut S { &'a mut self.s }
|
||||
}
|
||||
|
||||
pub trait Angle
|
||||
<
|
||||
S: Clone + Float
|
||||
|
@ -43,21 +67,19 @@ pub trait Angle
|
|||
+ Neg<Self>
|
||||
+ ToRad<S>
|
||||
+ ToDeg<S>
|
||||
+ ScalarConv<S>
|
||||
{
|
||||
fn from_s(s: S) -> Self;
|
||||
fn from<A: Angle<S>>(theta: A) -> Self;
|
||||
fn s<'a>(&'a self) -> &'a S;
|
||||
fn mut_s<'a>(&'a mut self) -> &'a mut S;
|
||||
|
||||
#[inline] fn neg_self(&mut self) { *self = -*self }
|
||||
|
||||
#[inline] fn add_a(&self, other: Self) -> Self { Angle::from_s(*self.s() + *other.s()) }
|
||||
#[inline] fn sub_a(&self, other: Self) -> Self { Angle::from_s(*self.s() - *other.s()) }
|
||||
#[inline] fn add_a(&self, other: Self) -> Self { ScalarConv::from(*self.s() + *other.s()) }
|
||||
#[inline] fn sub_a(&self, other: Self) -> Self { ScalarConv::from(*self.s() - *other.s()) }
|
||||
#[inline] fn div_a(&self, other: Self) -> S { *self.s() / *other.s() }
|
||||
#[inline] fn rem_a(&self, other: Self) -> S { *self.s() % *other.s() }
|
||||
#[inline] fn mul_s(&self, s: S) -> Self { Angle::from_s(*self.s() * s) }
|
||||
#[inline] fn div_s(&self, s: S) -> Self { Angle::from_s(*self.s() / s) }
|
||||
#[inline] fn rem_s(&self, s: S) -> Self { Angle::from_s(*self.s() % s) }
|
||||
#[inline] fn mul_s(&self, s: S) -> Self { ScalarConv::from(*self.s() * s) }
|
||||
#[inline] fn div_s(&self, s: S) -> Self { ScalarConv::from(*self.s() / s) }
|
||||
#[inline] fn rem_s(&self, s: S) -> Self { ScalarConv::from(*self.s() % s) }
|
||||
|
||||
#[inline] fn add_self_a(&mut self, other: Self) { *self.mut_s() = *self.s() + *other.s() }
|
||||
#[inline] fn sub_self_a(&mut self, other: Self) { *self.mut_s() = *self.s() - *other.s() }
|
||||
|
@ -68,41 +90,37 @@ pub trait Angle
|
|||
#[inline] fn sin(&self) -> S { self.s().sin() }
|
||||
#[inline] fn cos(&self) -> S { self.s().cos() }
|
||||
#[inline] fn tan(&self) -> S { self.s().tan() }
|
||||
#[inline] fn sin_cos(&self) -> (S, S) { self.s().sin_cos() }
|
||||
}
|
||||
|
||||
#[inline] fn sin<S: Clone + Float, A: Angle<S>>(theta: A) -> S { theta.sin() }
|
||||
#[inline] fn cos<S: Clone + Float, A: Angle<S>>(theta: A) -> S { theta.cos() }
|
||||
#[inline] fn tan<S: Clone + Float, A: Angle<S>>(theta: A) -> S { theta.tan() }
|
||||
#[inline] pub fn sin<S: Clone + Float, A: Angle<S>>(theta: A) -> S { theta.sin() }
|
||||
#[inline] pub fn cos<S: Clone + Float, A: Angle<S>>(theta: A) -> S { theta.cos() }
|
||||
#[inline] pub fn tan<S: Clone + Float, A: Angle<S>>(theta: A) -> S { theta.tan() }
|
||||
#[inline] pub fn sin_cos<S: Clone + Float, A: Angle<S>>(theta: A) -> (S, S) { theta.sin_cos() }
|
||||
|
||||
impl<S: Clone + Float> Angle<S> for Rad<S> {
|
||||
#[inline] fn from_s(s: S) -> Rad<S> { rad(s) }
|
||||
#[inline] fn from<A: Angle<S>>(theta: A) -> Rad<S> { theta.to_rad() }
|
||||
#[inline] fn s<'a>(&'a self) -> &'a S { &'a self.s }
|
||||
#[inline] fn mut_s<'a>(&'a mut self) -> &'a mut S { &'a mut self.s }
|
||||
}
|
||||
|
||||
impl<S: Clone + Float> Angle<S> for Deg<S> {
|
||||
#[inline] fn from_s(s: S) -> Deg<S> { deg(s) }
|
||||
#[inline] fn from<A: Angle<S>>(theta: A) -> Deg<S> { theta.to_deg() }
|
||||
#[inline] fn s<'a>(&'a self) -> &'a S { &'a self.s }
|
||||
#[inline] fn mut_s<'a>(&'a mut self) -> &'a mut S { &'a mut self.s }
|
||||
}
|
||||
|
||||
pub trait ScalarTrig: Clone + Float {
|
||||
// These need underscores so that they don't conflict with the methods
|
||||
// defined in the `std::num::Trigonometric` trait.
|
||||
#[inline] fn asin_<A: Angle<Self>>(&self) -> A { Angle::from(rad(self.asin())) }
|
||||
#[inline] fn acos_<A: Angle<Self>>(&self) -> A { Angle::from(rad(self.acos())) }
|
||||
#[inline] fn atan_<A: Angle<Self>>(&self) -> A { Angle::from(rad(self.atan())) }
|
||||
#[inline] fn atan2_<A: Angle<Self>>(&self, other: &Self) -> A { Angle::from(rad(self.atan2(other))) }
|
||||
}
|
||||
|
||||
#[inline] fn asin<S: Clone + ScalarTrig, A: Angle<S>>(s: S) -> A { s.asin_() }
|
||||
#[inline] fn acos<S: Clone + ScalarTrig, A: Angle<S>>(s: S) -> A { s.acos_() }
|
||||
#[inline] fn atan<S: Clone + ScalarTrig, A: Angle<S>>(s: S) -> A { s.atan_() }
|
||||
#[inline] fn atan2<S: Clone + ScalarTrig, A: Angle<S>>(a: S, b: S) -> A { a.atan2_(&b) }
|
||||
#[inline] pub fn asin<S: Clone + ScalarTrig, A: Angle<S>>(s: S) -> A { s.asin_() }
|
||||
#[inline] pub fn acos<S: Clone + ScalarTrig, A: Angle<S>>(s: S) -> A { s.acos_() }
|
||||
#[inline] pub fn atan<S: Clone + ScalarTrig, A: Angle<S>>(s: S) -> A { s.atan_() }
|
||||
#[inline] pub fn atan2<S: Clone + ScalarTrig, A: Angle<S>>(a: S, b: S) -> A { a.atan2_(&b) }
|
||||
|
||||
impl ScalarTrig for f32;
|
||||
impl ScalarTrig for f64;
|
||||
impl ScalarTrig for float;
|
||||
impl<S: Clone + Float> ScalarTrig for S;
|
||||
|
||||
impl<S: Clone + Float> ToStr for Rad<S> { fn to_str(&self) -> ~str { fmt!("%? rad", self.s) } }
|
||||
impl<S: Clone + Float> ToStr for Deg<S> { fn to_str(&self) -> ~str { fmt!("%?°", self.s) } }
|
||||
|
|
|
@ -15,9 +15,10 @@
|
|||
|
||||
//! Column major, square matrix types and traits.
|
||||
|
||||
use std::num::{Zero, zero, One, one, sin, cos};
|
||||
use std::num::{Zero, zero, One, one};
|
||||
|
||||
use array::*;
|
||||
use angle::{Rad, sin, cos};
|
||||
use array::Array;
|
||||
use quaternion::{Quat, ToQuat};
|
||||
use vector::*;
|
||||
use util::half;
|
||||
|
@ -75,9 +76,9 @@ impl<S: Clone + Num> Mat2<S> {
|
|||
|
||||
impl<S: Clone + Float> Mat2<S> {
|
||||
#[inline]
|
||||
pub fn from_angle(radians: S) -> Mat2<S> {
|
||||
let cos_theta = cos(radians.clone());
|
||||
let sin_theta = sin(radians.clone());
|
||||
pub fn from_angle(theta: Rad<S>) -> Mat2<S> {
|
||||
let cos_theta = cos(theta.clone());
|
||||
let sin_theta = sin(theta.clone());
|
||||
|
||||
Mat2::new(cos_theta.clone(), -sin_theta.clone(),
|
||||
sin_theta.clone(), cos_theta.clone())
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
use std::num::{zero, one};
|
||||
|
||||
use angle::{Angle, Rad, rad, tan};
|
||||
use matrix::Mat4;
|
||||
use util::two;
|
||||
|
||||
|
@ -24,8 +25,8 @@ use util::two;
|
|||
///
|
||||
/// This is the equivalent of the gluPerspective function, the algorithm of which
|
||||
/// can be found [here](http://www.opengl.org/wiki/GluPerspective_code).
|
||||
pub fn perspective<S: Clone + Float>(fovy: S, aspectRatio: S, near: S, far: S) -> Mat4<S> {
|
||||
let ymax = near * (fovy / two::<S>()).to_radians().tan();
|
||||
pub fn perspective<S: Clone + Float>(fovy: Rad<S>, aspectRatio: S, near: S, far: S) -> Mat4<S> {
|
||||
let ymax = near * tan(fovy.div_s(two::<S>()));
|
||||
let xmax = ymax * aspectRatio;
|
||||
|
||||
frustum(-xmax, xmax, -ymax, ymax, near, far)
|
||||
|
@ -101,7 +102,7 @@ pub trait Projection<S> {
|
|||
/// A perspective projection based on a vertical field-of-view angle.
|
||||
#[deriving(Clone, Eq)]
|
||||
pub struct PerspectiveFov<S> {
|
||||
fovy: S, //radians
|
||||
fovy: Rad<S>,
|
||||
aspect: S,
|
||||
near: S,
|
||||
far: S,
|
||||
|
@ -110,8 +111,8 @@ pub struct PerspectiveFov<S> {
|
|||
impl<S: Clone + Float> PerspectiveFov<S> {
|
||||
pub fn to_perspective(&self) -> Result<Perspective<S>, ~str> {
|
||||
do self.if_valid {
|
||||
let angle = self.fovy / two::<S>();
|
||||
let ymax = self.near * angle.tan();
|
||||
let angle = self.fovy.div_s(two::<S>());
|
||||
let ymax = self.near * tan(angle);
|
||||
let xmax = ymax * self.aspect;
|
||||
|
||||
Perspective {
|
||||
|
@ -128,10 +129,10 @@ impl<S: Clone + Float> PerspectiveFov<S> {
|
|||
|
||||
impl<S: Clone + Float> Projection<S> for PerspectiveFov<S> {
|
||||
fn if_valid<U:Clone>(&self, f: &fn() -> U) -> Result<U, ~str> {
|
||||
let frac_pi_2: S = Real::frac_pi_2();
|
||||
let half_turn: Rad<S> = rad(Real::frac_pi_2());
|
||||
cond! (
|
||||
(self.fovy < zero()) { Err(fmt!("The vertical field of view cannot be below zero, found: %?", self.fovy)) }
|
||||
(self.fovy > frac_pi_2) { Err(fmt!("The vertical field of view cannot be greater than a half turn, found: %?", self.fovy)) }
|
||||
(self.fovy > half_turn) { Err(fmt!("The vertical field of view cannot be greater than a half turn, found: %?", self.fovy)) }
|
||||
(self.aspect < zero()) { Err(fmt!("The aspect ratio cannot be below zero, found: %?", self.aspect)) }
|
||||
(self.near < zero()) { Err(fmt!("The near plane distance cannot be below zero, found: %?", self.near)) }
|
||||
(self.far < zero()) { Err(fmt!("The far plane distance cannot be below zero, found: %?", self.far)) }
|
||||
|
|
|
@ -15,9 +15,10 @@
|
|||
|
||||
use std::num::{zero, one, sqrt};
|
||||
|
||||
use util::two;
|
||||
use angle::{Angle, Rad, acos, cos, sin};
|
||||
use matrix::{Mat3, ToMat3};
|
||||
use vector::{Vec3, Vector, EuclideanVector};
|
||||
use util::two;
|
||||
|
||||
/// A quaternion in scalar/vector form
|
||||
#[deriving(Clone, Eq)]
|
||||
|
@ -190,14 +191,14 @@ impl<S: Clone + Float> Quat<S> {
|
|||
// stay within the domain of acos()
|
||||
let robust_dot = dot.clamp(&-one::<S>(), &one::<S>());
|
||||
|
||||
let theta_0 = robust_dot.acos(); // the angle between the quaternions
|
||||
let theta = theta_0 * amount; // the fraction of theta specified by `amount`
|
||||
let theta: Rad<S> = acos(robust_dot.clone()); // the angle between the quaternions
|
||||
let theta: Rad<S> = theta.mul_s(amount); // the fraction of theta specified by `amount`
|
||||
|
||||
let q = other.sub_q(&self.mul_s(robust_dot))
|
||||
.normalize();
|
||||
|
||||
self.mul_s(theta.cos())
|
||||
.add_q(&q.mul_s(theta.sin()))
|
||||
self.mul_s(cos(theta.clone()))
|
||||
.add_q(&q.mul_s(sin(theta)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,10 +13,10 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::num::{Zero, zero, One, one};
|
||||
use std::num::{sqrt, atan2};
|
||||
use std::num::{Zero, zero, One, one, sqrt};
|
||||
|
||||
use array::*;
|
||||
use angle::{Rad, atan2};
|
||||
use array::Array;
|
||||
|
||||
/// A 2-dimensional vector.
|
||||
#[deriving(Eq, Clone, Zero)]
|
||||
|
@ -193,7 +193,7 @@ pub trait EuclideanVector
|
|||
}
|
||||
|
||||
/// The angle between the vector and `other`.
|
||||
fn angle(&self, other: &Self) -> S;
|
||||
fn angle(&self, other: &Self) -> Rad<S>;
|
||||
|
||||
/// Returns a vector with the same direction, but with a `length` (or
|
||||
/// `norm`) of `1`.
|
||||
|
@ -239,14 +239,14 @@ pub trait EuclideanVector
|
|||
|
||||
impl<S: Clone + Float> EuclideanVector<S, [S, ..2]> for Vec2<S> {
|
||||
#[inline]
|
||||
fn angle(&self, other: &Vec2<S>) -> S {
|
||||
fn angle(&self, other: &Vec2<S>) -> Rad<S> {
|
||||
atan2(self.perp_dot(other), self.dot(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Clone + Float> EuclideanVector<S, [S, ..3]> for Vec3<S> {
|
||||
#[inline]
|
||||
fn angle(&self, other: &Vec3<S>) -> S {
|
||||
fn angle(&self, other: &Vec3<S>) -> Rad<S> {
|
||||
atan2(self.cross(other).length(), self.dot(other))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue