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
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// 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;
|
use std::num::Zero;
|
||||||
|
|
||||||
#[deriving(Clone, Eq, Ord, Zero)] struct Rad<S> { s: S }
|
#[deriving(Clone, Eq, Ord, Zero)] pub struct Rad<S> { s: S }
|
||||||
#[deriving(Clone, Eq, Ord, Zero)] struct Deg<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 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 } }
|
#[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<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) } }
|
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
|
pub trait Angle
|
||||||
<
|
<
|
||||||
S: Clone + Float
|
S: Clone + Float
|
||||||
|
@ -43,21 +67,19 @@ pub trait Angle
|
||||||
+ Neg<Self>
|
+ Neg<Self>
|
||||||
+ ToRad<S>
|
+ ToRad<S>
|
||||||
+ ToDeg<S>
|
+ ToDeg<S>
|
||||||
|
+ ScalarConv<S>
|
||||||
{
|
{
|
||||||
fn from_s(s: S) -> Self;
|
|
||||||
fn from<A: Angle<S>>(theta: A) -> 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 neg_self(&mut self) { *self = -*self }
|
||||||
|
|
||||||
#[inline] fn add_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 { Angle::from_s(*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 div_a(&self, other: Self) -> S { *self.s() / *other.s() }
|
||||||
#[inline] fn rem_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 mul_s(&self, s: S) -> Self { ScalarConv::from(*self.s() * s) }
|
||||||
#[inline] fn div_s(&self, s: S) -> Self { Angle::from_s(*self.s() / s) }
|
#[inline] fn div_s(&self, s: S) -> Self { ScalarConv::from(*self.s() / s) }
|
||||||
#[inline] fn rem_s(&self, s: S) -> Self { Angle::from_s(*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 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() }
|
#[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 sin(&self) -> S { self.s().sin() }
|
||||||
#[inline] fn cos(&self) -> S { self.s().cos() }
|
#[inline] fn cos(&self) -> S { self.s().cos() }
|
||||||
#[inline] fn tan(&self) -> S { self.s().tan() }
|
#[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] pub 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] pub 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 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> {
|
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 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> {
|
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 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 {
|
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 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 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 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 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] pub 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] pub 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] pub 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 atan2<S: Clone + ScalarTrig, A: Angle<S>>(a: S, b: S) -> A { a.atan2_(&b) }
|
||||||
|
|
||||||
impl ScalarTrig for f32;
|
impl<S: Clone + Float> ScalarTrig for S;
|
||||||
impl ScalarTrig for f64;
|
|
||||||
impl ScalarTrig for float;
|
|
||||||
|
|
||||||
impl<S: Clone + Float> ToStr for Rad<S> { fn to_str(&self) -> ~str { fmt!("%? rad", self.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) } }
|
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.
|
//! 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 quaternion::{Quat, ToQuat};
|
||||||
use vector::*;
|
use vector::*;
|
||||||
use util::half;
|
use util::half;
|
||||||
|
@ -75,9 +76,9 @@ impl<S: Clone + Num> Mat2<S> {
|
||||||
|
|
||||||
impl<S: Clone + Float> Mat2<S> {
|
impl<S: Clone + Float> Mat2<S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_angle(radians: S) -> Mat2<S> {
|
pub fn from_angle(theta: Rad<S>) -> Mat2<S> {
|
||||||
let cos_theta = cos(radians.clone());
|
let cos_theta = cos(theta.clone());
|
||||||
let sin_theta = sin(radians.clone());
|
let sin_theta = sin(theta.clone());
|
||||||
|
|
||||||
Mat2::new(cos_theta.clone(), -sin_theta.clone(),
|
Mat2::new(cos_theta.clone(), -sin_theta.clone(),
|
||||||
sin_theta.clone(), cos_theta.clone())
|
sin_theta.clone(), cos_theta.clone())
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
use std::num::{zero, one};
|
use std::num::{zero, one};
|
||||||
|
|
||||||
|
use angle::{Angle, Rad, rad, tan};
|
||||||
use matrix::Mat4;
|
use matrix::Mat4;
|
||||||
use util::two;
|
use util::two;
|
||||||
|
|
||||||
|
@ -24,8 +25,8 @@ use util::two;
|
||||||
///
|
///
|
||||||
/// This is the equivalent of the gluPerspective function, the algorithm of which
|
/// This is the equivalent of the gluPerspective function, the algorithm of which
|
||||||
/// can be found [here](http://www.opengl.org/wiki/GluPerspective_code).
|
/// 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> {
|
pub fn perspective<S: Clone + Float>(fovy: Rad<S>, aspectRatio: S, near: S, far: S) -> Mat4<S> {
|
||||||
let ymax = near * (fovy / two::<S>()).to_radians().tan();
|
let ymax = near * tan(fovy.div_s(two::<S>()));
|
||||||
let xmax = ymax * aspectRatio;
|
let xmax = ymax * aspectRatio;
|
||||||
|
|
||||||
frustum(-xmax, xmax, -ymax, ymax, near, far)
|
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.
|
/// A perspective projection based on a vertical field-of-view angle.
|
||||||
#[deriving(Clone, Eq)]
|
#[deriving(Clone, Eq)]
|
||||||
pub struct PerspectiveFov<S> {
|
pub struct PerspectiveFov<S> {
|
||||||
fovy: S, //radians
|
fovy: Rad<S>,
|
||||||
aspect: S,
|
aspect: S,
|
||||||
near: S,
|
near: S,
|
||||||
far: S,
|
far: S,
|
||||||
|
@ -110,8 +111,8 @@ pub struct PerspectiveFov<S> {
|
||||||
impl<S: Clone + Float> PerspectiveFov<S> {
|
impl<S: Clone + Float> PerspectiveFov<S> {
|
||||||
pub fn to_perspective(&self) -> Result<Perspective<S>, ~str> {
|
pub fn to_perspective(&self) -> Result<Perspective<S>, ~str> {
|
||||||
do self.if_valid {
|
do self.if_valid {
|
||||||
let angle = self.fovy / two::<S>();
|
let angle = self.fovy.div_s(two::<S>());
|
||||||
let ymax = self.near * angle.tan();
|
let ymax = self.near * tan(angle);
|
||||||
let xmax = ymax * self.aspect;
|
let xmax = ymax * self.aspect;
|
||||||
|
|
||||||
Perspective {
|
Perspective {
|
||||||
|
@ -128,10 +129,10 @@ impl<S: Clone + Float> PerspectiveFov<S> {
|
||||||
|
|
||||||
impl<S: Clone + Float> Projection<S> for PerspectiveFov<S> {
|
impl<S: Clone + Float> Projection<S> for PerspectiveFov<S> {
|
||||||
fn if_valid<U:Clone>(&self, f: &fn() -> U) -> Result<U, ~str> {
|
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! (
|
cond! (
|
||||||
(self.fovy < zero()) { Err(fmt!("The vertical field of view cannot be below zero, found: %?", self.fovy)) }
|
(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.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.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)) }
|
(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 std::num::{zero, one, sqrt};
|
||||||
|
|
||||||
use util::two;
|
use angle::{Angle, Rad, acos, cos, sin};
|
||||||
use matrix::{Mat3, ToMat3};
|
use matrix::{Mat3, ToMat3};
|
||||||
use vector::{Vec3, Vector, EuclideanVector};
|
use vector::{Vec3, Vector, EuclideanVector};
|
||||||
|
use util::two;
|
||||||
|
|
||||||
/// A quaternion in scalar/vector form
|
/// A quaternion in scalar/vector form
|
||||||
#[deriving(Clone, Eq)]
|
#[deriving(Clone, Eq)]
|
||||||
|
@ -190,14 +191,14 @@ impl<S: Clone + Float> Quat<S> {
|
||||||
// stay within the domain of acos()
|
// stay within the domain of acos()
|
||||||
let robust_dot = dot.clamp(&-one::<S>(), &one::<S>());
|
let robust_dot = dot.clamp(&-one::<S>(), &one::<S>());
|
||||||
|
|
||||||
let theta_0 = robust_dot.acos(); // the angle between the quaternions
|
let theta: Rad<S> = acos(robust_dot.clone()); // the angle between the quaternions
|
||||||
let theta = theta_0 * amount; // the fraction of theta specified by `amount`
|
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))
|
let q = other.sub_q(&self.mul_s(robust_dot))
|
||||||
.normalize();
|
.normalize();
|
||||||
|
|
||||||
self.mul_s(theta.cos())
|
self.mul_s(cos(theta.clone()))
|
||||||
.add_q(&q.mul_s(theta.sin()))
|
.add_q(&q.mul_s(sin(theta)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,10 +13,10 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use std::num::{Zero, zero, One, one};
|
use std::num::{Zero, zero, One, one, sqrt};
|
||||||
use std::num::{sqrt, atan2};
|
|
||||||
|
|
||||||
use array::*;
|
use angle::{Rad, atan2};
|
||||||
|
use array::Array;
|
||||||
|
|
||||||
/// A 2-dimensional vector.
|
/// A 2-dimensional vector.
|
||||||
#[deriving(Eq, Clone, Zero)]
|
#[deriving(Eq, Clone, Zero)]
|
||||||
|
@ -193,7 +193,7 @@ pub trait EuclideanVector
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The angle between the vector and `other`.
|
/// 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
|
/// Returns a vector with the same direction, but with a `length` (or
|
||||||
/// `norm`) of `1`.
|
/// `norm`) of `1`.
|
||||||
|
@ -239,14 +239,14 @@ pub trait EuclideanVector
|
||||||
|
|
||||||
impl<S: Clone + Float> EuclideanVector<S, [S, ..2]> for Vec2<S> {
|
impl<S: Clone + Float> EuclideanVector<S, [S, ..2]> for Vec2<S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn angle(&self, other: &Vec2<S>) -> S {
|
fn angle(&self, other: &Vec2<S>) -> Rad<S> {
|
||||||
atan2(self.perp_dot(other), self.dot(other))
|
atan2(self.perp_dot(other), self.dot(other))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Clone + Float> EuclideanVector<S, [S, ..3]> for Vec3<S> {
|
impl<S: Clone + Float> EuclideanVector<S, [S, ..3]> for Vec3<S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn angle(&self, other: &Vec3<S>) -> S {
|
fn angle(&self, other: &Vec3<S>) -> Rad<S> {
|
||||||
atan2(self.cross(other).length(), self.dot(other))
|
atan2(self.cross(other).length(), self.dot(other))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue