Merge branch 'master' of https://github.com/bjz/cgmath-rs
This commit is contained in:
commit
af41b476da
12 changed files with 331 additions and 324 deletions
7
.travis.yml
Normal file
7
.travis.yml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
before_install:
|
||||||
|
- yes | sudo add-apt-repository ppa:hansjorg/rust
|
||||||
|
- sudo apt-get update
|
||||||
|
install:
|
||||||
|
- sudo apt-get install rust-nightly
|
||||||
|
script:
|
||||||
|
- rustpkg build cgmath
|
1
AUTHORS
1
AUTHORS
|
@ -11,6 +11,7 @@ Erick Tryzelaar
|
||||||
Luqman Aden
|
Luqman Aden
|
||||||
Maik Klein
|
Maik Klein
|
||||||
Mikko Perttunen
|
Mikko Perttunen
|
||||||
|
Tomasz Stachowiak
|
||||||
|
|
||||||
With thanks to:
|
With thanks to:
|
||||||
|
|
||||||
|
|
|
@ -15,11 +15,11 @@
|
||||||
|
|
||||||
//! Angle units for type-safe, self-documenting code.
|
//! Angle units for type-safe, self-documenting code.
|
||||||
|
|
||||||
pub use std::num::{cast, zero};
|
|
||||||
pub use std::num::{sinh, cosh, tanh};
|
pub use std::num::{sinh, cosh, tanh};
|
||||||
pub use std::num::{asinh, acosh, atanh};
|
pub use std::num::{asinh, acosh, atanh};
|
||||||
|
|
||||||
use std::num::Zero;
|
use std::fmt;
|
||||||
|
use std::num::{Zero, zero, cast};
|
||||||
|
|
||||||
#[deriving(Clone, Eq, Ord, Zero)] pub struct Rad<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 }
|
#[deriving(Clone, Eq, Ord, Zero)] pub struct Deg<S> { s: S }
|
||||||
|
@ -113,15 +113,15 @@ pub trait Angle
|
||||||
/// Returns the interior bisector of the two angles
|
/// Returns the interior bisector of the two angles
|
||||||
#[inline]
|
#[inline]
|
||||||
fn bisect(&self, other: Self) -> Self {
|
fn bisect(&self, other: Self) -> Self {
|
||||||
self.add_a(self.sub_a(other).mul_s(cast(0.5))).normalize()
|
self.add_a(self.sub_a(other).mul_s(cast(0.5).unwrap())).normalize()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn full_turn() -> Self;
|
fn full_turn() -> Self;
|
||||||
|
|
||||||
#[inline] fn turn_div_2() -> Self { let full_turn: Self = Angle::full_turn(); full_turn.div_s(cast(2)) }
|
#[inline] fn turn_div_2() -> Self { let full_turn: Self = Angle::full_turn(); full_turn.div_s(cast(2).unwrap()) }
|
||||||
#[inline] fn turn_div_3() -> Self { let full_turn: Self = Angle::full_turn(); full_turn.div_s(cast(3)) }
|
#[inline] fn turn_div_3() -> Self { let full_turn: Self = Angle::full_turn(); full_turn.div_s(cast(3).unwrap()) }
|
||||||
#[inline] fn turn_div_4() -> Self { let full_turn: Self = Angle::full_turn(); full_turn.div_s(cast(4)) }
|
#[inline] fn turn_div_4() -> Self { let full_turn: Self = Angle::full_turn(); full_turn.div_s(cast(4).unwrap()) }
|
||||||
#[inline] fn turn_div_6() -> Self { let full_turn: Self = Angle::full_turn(); full_turn.div_s(cast(6)) }
|
#[inline] fn turn_div_6() -> Self { let full_turn: Self = Angle::full_turn(); full_turn.div_s(cast(6).unwrap()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline] pub fn bisect<S: Float, A: Angle<S>>(a: A, b: A) -> A { a.bisect(b) }
|
#[inline] pub fn bisect<S: Float, A: Angle<S>>(a: A, b: A) -> A { a.bisect(b) }
|
||||||
|
@ -163,25 +163,25 @@ impl<S: Float> Angle<S> for Rad<S> {
|
||||||
|
|
||||||
impl<S: Float> Angle<S> for Deg<S> {
|
impl<S: Float> Angle<S> for 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 full_turn() -> Deg<S> { deg(cast(360)) }
|
#[inline] fn full_turn() -> Deg<S> { deg(cast(360).unwrap()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline] pub fn sin<S: Float, A: Angle<S>>(theta: A) -> S { theta.to_rad().s.sin() }
|
#[inline] pub fn sin<S: Float>(theta: Rad<S>) -> S { theta.s.sin() }
|
||||||
#[inline] pub fn cos<S: Float, A: Angle<S>>(theta: A) -> S { theta.to_rad().s.cos() }
|
#[inline] pub fn cos<S: Float>(theta: Rad<S>) -> S { theta.s.cos() }
|
||||||
#[inline] pub fn tan<S: Float, A: Angle<S>>(theta: A) -> S { theta.to_rad().s.tan() }
|
#[inline] pub fn tan<S: Float>(theta: Rad<S>) -> S { theta.s.tan() }
|
||||||
#[inline] pub fn sin_cos<S: Float, A: Angle<S>>(theta: A) -> (S, S) { theta.to_rad().s.sin_cos() }
|
#[inline] pub fn sin_cos<S: Float>(theta: Rad<S>) -> (S, S) { theta.s.sin_cos() }
|
||||||
|
|
||||||
#[inline] pub fn cot<S: Float, A: Angle<S>>(theta: A) -> S { tan(theta).recip() }
|
#[inline] pub fn cot<S: Float>(theta: Rad<S>) -> S { tan(theta).recip() }
|
||||||
#[inline] pub fn sec<S: Float, A: Angle<S>>(theta: A) -> S { cos(theta).recip() }
|
#[inline] pub fn sec<S: Float>(theta: Rad<S>) -> S { cos(theta).recip() }
|
||||||
#[inline] pub fn csc<S: Float, A: Angle<S>>(theta: A) -> S { sin(theta).recip() }
|
#[inline] pub fn csc<S: Float>(theta: Rad<S>) -> S { sin(theta).recip() }
|
||||||
|
|
||||||
#[inline] pub fn asin<S: Float, A: Angle<S>>(s: S) -> A { Angle::from(rad(s.asin())) }
|
#[inline] pub fn asin<S: Float>(s: S) -> Rad<S> { rad(s.asin()) }
|
||||||
#[inline] pub fn acos<S: Float, A: Angle<S>>(s: S) -> A { Angle::from(rad(s.acos())) }
|
#[inline] pub fn acos<S: Float>(s: S) -> Rad<S> { rad(s.acos()) }
|
||||||
#[inline] pub fn atan<S: Float, A: Angle<S>>(s: S) -> A { Angle::from(rad(s.atan())) }
|
#[inline] pub fn atan<S: Float>(s: S) -> Rad<S> { rad(s.atan()) }
|
||||||
#[inline] pub fn atan2<S: Float, A: Angle<S>>(a: S, b: S) -> A { Angle::from(rad(a.atan2(&b))) }
|
#[inline] pub fn atan2<S: Float>(a: S, b: S) -> Rad<S> { rad(a.atan2(&b)) }
|
||||||
|
|
||||||
impl<S: Float> ToStr for Rad<S> { fn to_str(&self) -> ~str { fmt!("%? rad", self.s) } }
|
impl<S: Float + fmt::Default> ToStr for Rad<S> { fn to_str(&self) -> ~str { format!("{} rad", self.s) } }
|
||||||
impl<S: Float> ToStr for Deg<S> { fn to_str(&self) -> ~str { fmt!("%?°", self.s) } }
|
impl<S: Float + fmt::Default> ToStr for Deg<S> { fn to_str(&self) -> ~str { format!("{}°", self.s) } }
|
||||||
|
|
||||||
impl<S: Float> ApproxEq<S> for Rad<S> {
|
impl<S: Float> ApproxEq<S> for Rad<S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -22,6 +22,9 @@
|
||||||
#[license = "ASL2"];
|
#[license = "ASL2"];
|
||||||
#[crate_type = "lib"];
|
#[crate_type = "lib"];
|
||||||
|
|
||||||
|
#[feature(globs)];
|
||||||
|
#[feature(macro_rules)];
|
||||||
|
|
||||||
pub mod array;
|
pub mod array;
|
||||||
pub mod matrix;
|
pub mod matrix;
|
||||||
pub mod quaternion;
|
pub mod quaternion;
|
||||||
|
@ -41,3 +44,5 @@ pub mod frustum;
|
||||||
pub mod intersect;
|
pub mod intersect;
|
||||||
pub mod obb;
|
pub mod obb;
|
||||||
pub mod sphere;
|
pub mod sphere;
|
||||||
|
|
||||||
|
pub mod ptr;
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
use std::num::{Zero, zero, One, one, cast, sqrt};
|
use std::num::{Zero, zero, One, one, cast, sqrt};
|
||||||
|
|
||||||
use angle::{Rad, sin, cos};
|
use angle::{Rad, sin, cos, sin_cos};
|
||||||
use array::{Array, build};
|
use array::{Array, build};
|
||||||
use quaternion::{Quat, ToQuat};
|
use quaternion::{Quat, ToQuat};
|
||||||
use vector::{Vector, EuclideanVector};
|
use vector::{Vector, EuclideanVector};
|
||||||
|
@ -121,6 +121,69 @@ impl<S: Float> Mat3<S> {
|
||||||
|
|
||||||
Mat3::from_cols(up, side, dir)
|
Mat3::from_cols(up, side, dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a matrix from a rotation around the `x` axis (pitch).
|
||||||
|
pub fn from_angle_x(theta: Rad<S>) -> Mat3<S> {
|
||||||
|
// http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
|
||||||
|
let (s, c) = sin_cos(theta);
|
||||||
|
Mat3::new(one(), zero(), zero(),
|
||||||
|
zero(), c.clone(), s.clone(),
|
||||||
|
zero(), -s.clone(), c.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a matrix from a rotation around the `y` axis (yaw).
|
||||||
|
pub fn from_angle_y(theta: Rad<S>) -> Mat3<S> {
|
||||||
|
// http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
|
||||||
|
let (s, c) = sin_cos(theta);
|
||||||
|
Mat3::new(c.clone(), zero(), -s.clone(),
|
||||||
|
zero(), one(), zero(),
|
||||||
|
s.clone(), zero(), c.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a matrix from a rotation around the `z` axis (roll).
|
||||||
|
pub fn from_angle_z(theta: Rad<S>) -> Mat3<S> {
|
||||||
|
// http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
|
||||||
|
let (s, c) = sin_cos(theta);
|
||||||
|
Mat3::new(c.clone(), s.clone(), zero(),
|
||||||
|
-s.clone(), c.clone(), zero(),
|
||||||
|
zero(), zero(), one())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a matrix from a set of euler angles.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// - `x`: the angular rotation around the `x` axis (pitch).
|
||||||
|
/// - `y`: the angular rotation around the `y` axis (yaw).
|
||||||
|
/// - `z`: the angular rotation around the `z` axis (roll).
|
||||||
|
pub fn from_euler(x: Rad<S>, y: Rad<S>, z: Rad<S>) -> Mat3<S> {
|
||||||
|
// http://en.wikipedia.org/wiki/Rotation_matrix#General_rotations
|
||||||
|
let (sx, cx) = sin_cos(x);
|
||||||
|
let (sy, cy) = sin_cos(y);
|
||||||
|
let (sz, cz) = sin_cos(z);
|
||||||
|
|
||||||
|
Mat3::new(cy * cz, cy * sz, -sy,
|
||||||
|
-cx * sz + sx * sy * cz, cx * cz + sx * sy * sz, sx * cy,
|
||||||
|
sx * sz + cx * sy * cz, -sx * cz + cx * sy * sz, cx * cy)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a matrix from a rotation around an arbitrary axis
|
||||||
|
pub fn from_axis_angle(axis: &Vec3<S>, angle: Rad<S>) -> Mat3<S> {
|
||||||
|
let (s, c) = sin_cos(angle);
|
||||||
|
let _1subc = one::<S>() - c;
|
||||||
|
|
||||||
|
Mat3::new(_1subc * axis.x * axis.x + c,
|
||||||
|
_1subc * axis.x * axis.y + s * axis.z,
|
||||||
|
_1subc * axis.x * axis.z - s * axis.y,
|
||||||
|
|
||||||
|
_1subc * axis.x * axis.y - s * axis.z,
|
||||||
|
_1subc * axis.y * axis.y + c,
|
||||||
|
_1subc * axis.y * axis.z + s * axis.x,
|
||||||
|
|
||||||
|
_1subc * axis.x * axis.z + s * axis.y,
|
||||||
|
_1subc * axis.y * axis.z - s * axis.x,
|
||||||
|
_1subc * axis.z * axis.z + c)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Primitive> Mat4<S> {
|
impl<S: Primitive> Mat4<S> {
|
||||||
|
@ -565,7 +628,7 @@ impl<S:Float> ToQuat<S> for Mat3<S> {
|
||||||
fn to_quat(&self) -> Quat<S> {
|
fn to_quat(&self) -> Quat<S> {
|
||||||
// http://www.cs.ucr.edu/~vbz/resources/Quatut.pdf
|
// http://www.cs.ucr.edu/~vbz/resources/Quatut.pdf
|
||||||
let trace = self.trace();
|
let trace = self.trace();
|
||||||
let half: S = cast(0.5);
|
let half: S = cast(0.5).unwrap();
|
||||||
match () {
|
match () {
|
||||||
() if trace >= zero::<S>() => {
|
() if trace >= zero::<S>() => {
|
||||||
let s = sqrt(one::<S>() + trace);
|
let s = sqrt(one::<S>() + trace);
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
//! disinguishes them from vectors, which have a length and direction, but do
|
//! disinguishes them from vectors, which have a length and direction, but do
|
||||||
//! not have a fixed position.
|
//! not have a fixed position.
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
use std::num::zero;
|
use std::num::zero;
|
||||||
|
|
||||||
use array::*;
|
use array::*;
|
||||||
|
@ -88,14 +89,14 @@ array!(impl<S> Point3<S> -> [S, ..3] _3)
|
||||||
impl<S: Primitive> Point<S, Vec2<S>, [S, ..2]> for Point2<S> {}
|
impl<S: Primitive> Point<S, Vec2<S>, [S, ..2]> for Point2<S> {}
|
||||||
impl<S: Primitive> Point<S, Vec3<S>, [S, ..3]> for Point3<S> {}
|
impl<S: Primitive> Point<S, Vec3<S>, [S, ..3]> for Point3<S> {}
|
||||||
|
|
||||||
impl<S> ToStr for Point2<S> {
|
impl<S: fmt::Default> ToStr for Point2<S> {
|
||||||
fn to_str(&self) -> ~str {
|
fn to_str(&self) -> ~str {
|
||||||
fmt!("[%?, %?]", self.x, self.y)
|
format!("[{}, {}]", self.x, self.y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> ToStr for Point3<S> {
|
impl<S: fmt::Default> ToStr for Point3<S> {
|
||||||
fn to_str(&self) -> ~str {
|
fn to_str(&self) -> ~str {
|
||||||
fmt!("[%?, %?, %?]", self.x, self.y, self.z)
|
format!("[{}, {}, {}]", self.x, self.y, self.z)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,8 +78,8 @@ pub struct PerspectiveFov<S, A> {
|
||||||
|
|
||||||
impl<S: Float, A: Angle<S>> PerspectiveFov<S, A> {
|
impl<S: Float, A: Angle<S>> PerspectiveFov<S, A> {
|
||||||
pub fn to_perspective(&self) -> Perspective<S> {
|
pub fn to_perspective(&self) -> Perspective<S> {
|
||||||
let angle = self.fovy.div_s(cast(2));
|
let angle = self.fovy.div_s(cast(2).unwrap());
|
||||||
let ymax = self.near * tan(angle);
|
let ymax = self.near * tan(angle.to_rad());
|
||||||
let xmax = ymax * self.aspect;
|
let xmax = ymax * self.aspect;
|
||||||
|
|
||||||
Perspective {
|
Perspective {
|
||||||
|
@ -104,15 +104,15 @@ impl<S: Float, A: Angle<S>> ToMat4<S> for PerspectiveFov<S, A> {
|
||||||
fn to_mat4(&self) -> Mat4<S> {
|
fn to_mat4(&self) -> Mat4<S> {
|
||||||
let half_turn: A = Angle::turn_div_2();
|
let half_turn: A = Angle::turn_div_2();
|
||||||
|
|
||||||
assert!(self.fovy > zero(), "The vertical field of view cannot be below zero, found: %?", self.fovy);
|
assert!(self.fovy > zero(), "The vertical field of view cannot be below zero, found: {:?}", self.fovy);
|
||||||
assert!(self.fovy < half_turn, "The vertical field of view cannot be greater than a half turn, found: %?", self.fovy);
|
assert!(self.fovy < half_turn, "The vertical field of view cannot be greater than a half turn, found: {:?}", self.fovy);
|
||||||
assert!(self.aspect > zero(), "The aspect ratio cannot be below zero, found: %?", self.aspect);
|
assert!(self.aspect > zero(), "The aspect ratio cannot be below zero, found: {:?}", self.aspect);
|
||||||
assert!(self.near > zero(), "The near plane distance cannot be below zero, found: %?", self.near);
|
assert!(self.near > zero(), "The near plane distance cannot be below zero, found: {:?}", self.near);
|
||||||
assert!(self.far > zero(), "The far plane distance cannot be below zero, found: %?", self.far);
|
assert!(self.far > zero(), "The far plane distance cannot be below zero, found: {:?}", self.far);
|
||||||
assert!(self.far > self.near, "The far plane cannot be closer than the near plane, found: far: %?, near: %?", self.far, self.near);
|
assert!(self.far > self.near, "The far plane cannot be closer than the near plane, found: far: {:?}, near: {:?}", self.far, self.near);
|
||||||
|
|
||||||
let f = cot(self.fovy.div_s(cast(2)));
|
let f = cot(self.fovy.div_s(cast(2).unwrap()).to_rad());
|
||||||
let two: S = cast(2);
|
let two: S = cast(2).unwrap();
|
||||||
|
|
||||||
let c0r0 = f / self.aspect;
|
let c0r0 = f / self.aspect;
|
||||||
let c0r1 = zero();
|
let c0r1 = zero();
|
||||||
|
@ -158,11 +158,11 @@ impl<S: Float> Projection<S> for Perspective<S> {
|
||||||
|
|
||||||
impl<S: Float> ToMat4<S> for Perspective<S> {
|
impl<S: Float> ToMat4<S> for Perspective<S> {
|
||||||
fn to_mat4(&self) -> Mat4<S> {
|
fn to_mat4(&self) -> Mat4<S> {
|
||||||
assert!(self.left > self.right, "`left` cannot be greater than `right`, found: left: %? right: %?", self.left, self.right);
|
assert!(self.left > self.right, "`left` cannot be greater than `right`, found: left: {:?} right: {:?}", self.left, self.right);
|
||||||
assert!(self.bottom > self.top, "`bottom` cannot be greater than `top`, found: bottom: %? top: %?", self.bottom, self.top);
|
assert!(self.bottom > self.top, "`bottom` cannot be greater than `top`, found: bottom: {:?} top: {:?}", self.bottom, self.top);
|
||||||
assert!(self.near > self.far, "`near` cannot be greater than `far`, found: near: %? far: %?", self.near, self.far);
|
assert!(self.near > self.far, "`near` cannot be greater than `far`, found: near: {:?} far: {:?}", self.near, self.far);
|
||||||
|
|
||||||
let two: S = cast(2);
|
let two: S = cast(2).unwrap();
|
||||||
|
|
||||||
let c0r0 = (two * self.near) / (self.right - self.left);
|
let c0r0 = (two * self.near) / (self.right - self.left);
|
||||||
let c0r1 = zero();
|
let c0r1 = zero();
|
||||||
|
@ -214,11 +214,11 @@ impl<S: Float> Projection<S> for Ortho<S> {
|
||||||
|
|
||||||
impl<S: Float> ToMat4<S> for Ortho<S> {
|
impl<S: Float> ToMat4<S> for Ortho<S> {
|
||||||
fn to_mat4(&self) -> Mat4<S> {
|
fn to_mat4(&self) -> Mat4<S> {
|
||||||
assert!(self.left > self.right, "`left` cannot be greater than `right`, found: left: %? right: %?", self.left, self.right);
|
assert!(self.left > self.right, "`left` cannot be greater than `right`, found: left: {:?} right: {:?}", self.left, self.right);
|
||||||
assert!(self.bottom > self.top, "`bottom` cannot be greater than `top`, found: bottom: %? top: %?", self.bottom, self.top);
|
assert!(self.bottom > self.top, "`bottom` cannot be greater than `top`, found: bottom: {:?} top: {:?}", self.bottom, self.top);
|
||||||
assert!(self.near > self.far, "`near` cannot be greater than `far`, found: near: %? far: %?", self.near, self.far);
|
assert!(self.near > self.far, "`near` cannot be greater than `far`, found: near: {:?} far: {:?}", self.near, self.far);
|
||||||
|
|
||||||
let two: S = cast(2);
|
let two: S = cast(2).unwrap();
|
||||||
|
|
||||||
let c0r0 = two / (self.right - self.left);
|
let c0r0 = two / (self.right - self.left);
|
||||||
let c0r1 = zero();
|
let c0r1 = zero();
|
||||||
|
|
38
src/cgmath/ptr.rs
Normal file
38
src/cgmath/ptr.rs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
// Copyright 2013 The CGMath Developers. For a full listing of the authors,
|
||||||
|
// refer to the AUTHORS file at the top-level directory of this distribution.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
use array::Array;
|
||||||
|
use matrix::{Mat2, Mat3, Mat4};
|
||||||
|
use point::{Point2, Point3};
|
||||||
|
use vector::{Vec2, Vec3, Vec4};
|
||||||
|
|
||||||
|
pub trait Ptr<T> {
|
||||||
|
fn ptr<'a>(&'a self) -> &'a T;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Clone> Ptr<S> for Vec2<S> { #[inline] fn ptr<'a>(&'a self) -> &'a S { self.i(0) } }
|
||||||
|
impl<S: Clone> Ptr<S> for Vec3<S> { #[inline] fn ptr<'a>(&'a self) -> &'a S { self.i(0) } }
|
||||||
|
impl<S: Clone> Ptr<S> for Vec4<S> { #[inline] fn ptr<'a>(&'a self) -> &'a S { self.i(0) } }
|
||||||
|
|
||||||
|
impl<S: Clone> Ptr<S> for Point2<S> { #[inline] fn ptr<'a>(&'a self) -> &'a S { self.i(0) } }
|
||||||
|
impl<S: Clone> Ptr<S> for Point3<S> { #[inline] fn ptr<'a>(&'a self) -> &'a S { self.i(0) } }
|
||||||
|
|
||||||
|
impl<S: Clone> Ptr<S> for Mat2<S> { #[inline] fn ptr<'a>(&'a self) -> &'a S { self.i(0).i(0) } }
|
||||||
|
impl<S: Clone> Ptr<S> for Mat3<S> { #[inline] fn ptr<'a>(&'a self) -> &'a S { self.i(0).i(0) } }
|
||||||
|
impl<S: Clone> Ptr<S> for Mat4<S> { #[inline] fn ptr<'a>(&'a self) -> &'a S { self.i(0).i(0) } }
|
||||||
|
|
||||||
|
impl<'self, T, P: Ptr<T>> Ptr<T> for &'self [P] {
|
||||||
|
#[inline] fn ptr<'a>(&'a self) -> &'a T { self[0].ptr() }
|
||||||
|
}
|
|
@ -13,9 +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::fmt;
|
||||||
use std::num::{zero, one, cast, sqrt};
|
use std::num::{zero, one, cast, sqrt};
|
||||||
|
|
||||||
use angle::{Angle, Rad, acos, cos, sin};
|
use angle::{Angle, Rad, acos, cos, sin, sin_cos};
|
||||||
use array::{Array, build};
|
use array::{Array, build};
|
||||||
use matrix::{Mat3, ToMat3};
|
use matrix::{Mat3, ToMat3};
|
||||||
use vector::{Vec3, Vector, EuclideanVector};
|
use vector::{Vec3, Vector, EuclideanVector};
|
||||||
|
@ -50,6 +51,51 @@ impl<S: Float> Quat<S> {
|
||||||
Mat3::look_at(dir, up).to_quat()
|
Mat3::look_at(dir, up).to_quat()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a matrix from a rotation around the `x` axis (pitch).
|
||||||
|
#[inline]
|
||||||
|
pub fn from_angle_x(theta: Rad<S>) -> Quat<S> {
|
||||||
|
Quat::new(cos(theta.mul_s(cast(0.5).unwrap())), sin(theta), zero(), zero())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a matrix from a rotation around the `y` axis (yaw).
|
||||||
|
#[inline]
|
||||||
|
pub fn from_angle_y(theta: Rad<S>) -> Quat<S> {
|
||||||
|
Quat::new(cos(theta.mul_s(cast(0.5).unwrap())), zero(), sin(theta), zero())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a matrix from a rotation around the `z` axis (roll).
|
||||||
|
#[inline]
|
||||||
|
pub fn from_angle_z(theta: Rad<S>) -> Quat<S> {
|
||||||
|
Quat::new(cos(theta.mul_s(cast(0.5).unwrap())), zero(), zero(), sin(theta))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a quaternion from a set of euler angles.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// - `x`: the angular rotation around the `x` axis (pitch).
|
||||||
|
/// - `y`: the angular rotation around the `y` axis (yaw).
|
||||||
|
/// - `z`: the angular rotation around the `z` axis (roll).
|
||||||
|
pub fn from_euler(x: Rad<S>, y: Rad<S>, z: Rad<S>) -> Quat<S> {
|
||||||
|
// http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles#Conversion
|
||||||
|
let (sx2, cx2) = sin_cos(x.mul_s(cast(0.5).unwrap()));
|
||||||
|
let (sy2, cy2) = sin_cos(y.mul_s(cast(0.5).unwrap()));
|
||||||
|
let (sz2, cz2) = sin_cos(z.mul_s(cast(0.5).unwrap()));
|
||||||
|
|
||||||
|
Quat::new(cz2 * cx2 * cy2 + sz2 * sx2 * sy2,
|
||||||
|
sz2 * cx2 * cy2 - cz2 * sx2 * sy2,
|
||||||
|
cz2 * sx2 * cy2 + sz2 * cx2 * sy2,
|
||||||
|
cz2 * cx2 * sy2 - sz2 * sx2 * cy2)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a quaternion from a rotation around an arbitrary axis
|
||||||
|
#[inline]
|
||||||
|
pub fn from_axis_angle(axis: &Vec3<S>, angle: Rad<S>) -> Quat<S> {
|
||||||
|
let half = angle.mul_s(cast(0.5).unwrap());
|
||||||
|
Quat::from_sv(cos(half.clone()),
|
||||||
|
axis.mul_s(sin(half)))
|
||||||
|
}
|
||||||
|
|
||||||
/// The additive identity, ie: `q = 0 + 0i + 0j + 0i`
|
/// The additive identity, ie: `q = 0 + 0i + 0j + 0i`
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn zero() -> Quat<S> {
|
pub fn zero() -> Quat<S> {
|
||||||
|
@ -78,7 +124,7 @@ impl<S: Float> Quat<S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn mul_v(&self, vec: &Vec3<S>) -> Vec3<S> {
|
pub fn mul_v(&self, vec: &Vec3<S>) -> Vec3<S> {
|
||||||
let tmp = self.v.cross(vec).add_v(&vec.mul_s(self.s.clone()));
|
let tmp = self.v.cross(vec).add_v(&vec.mul_s(self.s.clone()));
|
||||||
self.v.cross(&tmp).mul_s(cast(2)).add_v(vec)
|
self.v.cross(&tmp).mul_s(cast(2).unwrap()).add_v(vec)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The sum of this quaternion and `other`
|
/// The sum of this quaternion and `other`
|
||||||
|
@ -198,7 +244,7 @@ impl<S: Float> Quat<S> {
|
||||||
use std::num::cast;
|
use std::num::cast;
|
||||||
|
|
||||||
let dot = self.dot(other);
|
let dot = self.dot(other);
|
||||||
let dot_threshold = cast(0.9995);
|
let dot_threshold = cast(0.9995).unwrap();
|
||||||
|
|
||||||
// if quaternions are close together use `nlerp`
|
// if quaternions are close together use `nlerp`
|
||||||
if dot > dot_threshold {
|
if dot > dot_threshold {
|
||||||
|
@ -207,14 +253,14 @@ impl<S: 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: Rad<S> = acos(robust_dot.clone()); // the angle between the quaternions
|
let theta: Rad<S> = acos(robust_dot.clone());
|
||||||
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 scale1 = sin(theta.mul_s(one::<S>() - amount));
|
||||||
.normalize();
|
let scale2 = sin(theta.mul_s(amount));
|
||||||
|
|
||||||
self.mul_s(cos(theta.clone()))
|
self.mul_s(scale1)
|
||||||
.add_q(&q.mul_s(sin(theta)))
|
.add_q(&other.mul_s(scale2))
|
||||||
|
.mul_s(sin(theta).recip())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -251,8 +297,8 @@ impl<S: Float> Neg<Quat<S>> for Quat<S> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> ToStr for Quat<S> {
|
impl<S: fmt::Default> ToStr for Quat<S> {
|
||||||
fn to_str(&self) -> ~str {
|
fn to_str(&self) -> ~str {
|
||||||
fmt!("%? + %?i + %?j + %?k", self.s, self.v.x, self.v.y, self.v.z)
|
format!("{} + {}i + {}j + {}k", self.s, self.v.x, self.v.y, self.v.z)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,10 +13,7 @@
|
||||||
// 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::{cast, one};
|
use angle::Rad;
|
||||||
|
|
||||||
use angle::{Angle, sin, cos, sin_cos};
|
|
||||||
use array::Array;
|
|
||||||
use matrix::Matrix;
|
use matrix::Matrix;
|
||||||
use matrix::{Mat2, ToMat2};
|
use matrix::{Mat2, ToMat2};
|
||||||
use matrix::{Mat3, ToMat3};
|
use matrix::{Mat3, ToMat3};
|
||||||
|
@ -33,7 +30,7 @@ pub trait Rotation2
|
||||||
: Eq
|
: Eq
|
||||||
+ ApproxEq<S>
|
+ ApproxEq<S>
|
||||||
+ ToMat2<S>
|
+ ToMat2<S>
|
||||||
+ ToRot2<S>
|
+ ToBasis2<S>
|
||||||
{
|
{
|
||||||
fn rotate_point2(&self, point: &Point2<S>) -> Point2<S>;
|
fn rotate_point2(&self, point: &Point2<S>) -> Point2<S>;
|
||||||
fn rotate_vec2(&self, vec: &Vec2<S>) -> Vec2<S>;
|
fn rotate_vec2(&self, vec: &Vec2<S>) -> Vec2<S>;
|
||||||
|
@ -52,7 +49,7 @@ pub trait Rotation3
|
||||||
: Eq
|
: Eq
|
||||||
+ ApproxEq<S>
|
+ ApproxEq<S>
|
||||||
+ ToMat3<S>
|
+ ToMat3<S>
|
||||||
+ ToRot3<S>
|
+ ToBasis3<S>
|
||||||
+ ToQuat<S>
|
+ ToQuat<S>
|
||||||
{
|
{
|
||||||
fn rotate_point3(&self, point: &Point3<S>) -> Point3<S>;
|
fn rotate_point3(&self, point: &Point3<S>) -> Point3<S>;
|
||||||
|
@ -71,30 +68,30 @@ pub trait Rotation3
|
||||||
/// enforce orthogonality at the type level the operations have been restricted
|
/// enforce orthogonality at the type level the operations have been restricted
|
||||||
/// to a subeset of those implemented on `Mat2`.
|
/// to a subeset of those implemented on `Mat2`.
|
||||||
#[deriving(Eq, Clone)]
|
#[deriving(Eq, Clone)]
|
||||||
pub struct Rot2<S> {
|
pub struct Basis2<S> {
|
||||||
priv mat: Mat2<S>
|
priv mat: Mat2<S>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Float> Rot2<S> {
|
impl<S: Float> Basis2<S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_mat2<'a>(&'a self) -> &'a Mat2<S> { &'a self.mat }
|
pub fn as_mat2<'a>(&'a self) -> &'a Mat2<S> { &'a self.mat }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ToRot2<S: Float> {
|
pub trait ToBasis2<S: Float> {
|
||||||
fn to_rot2(&self) -> Rot2<S>;
|
fn to_rot2(&self) -> Basis2<S>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Float> ToRot2<S> for Rot2<S> {
|
impl<S: Float> ToBasis2<S> for Basis2<S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_rot2(&self) -> Rot2<S> { self.clone() }
|
fn to_rot2(&self) -> Basis2<S> { self.clone() }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Float> ToMat2<S> for Rot2<S> {
|
impl<S: Float> ToMat2<S> for Basis2<S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_mat2(&self) -> Mat2<S> { self.mat.clone() }
|
fn to_mat2(&self) -> Mat2<S> { self.mat.clone() }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Float> Rotation2<S> for Rot2<S> {
|
impl<S: Float> Rotation2<S> for Basis2<S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn rotate_point2(&self, _point: &Point2<S>) -> Point2<S> { fail!("Not yet implemented") }
|
fn rotate_point2(&self, _point: &Point2<S>) -> Point2<S> { fail!("Not yet implemented") }
|
||||||
|
|
||||||
|
@ -105,15 +102,15 @@ impl<S: Float> Rotation2<S> for Rot2<S> {
|
||||||
fn rotate_ray2(&self, _ray: &Ray2<S>) -> Ray2<S> { fail!("Not yet implemented") }
|
fn rotate_ray2(&self, _ray: &Ray2<S>) -> Ray2<S> { fail!("Not yet implemented") }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn concat(&self, other: &Rot2<S>) -> Rot2<S> { Rot2 { mat: self.mat.mul_m(&other.mat) } }
|
fn concat(&self, other: &Basis2<S>) -> Basis2<S> { Basis2 { mat: self.mat.mul_m(&other.mat) } }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn concat_self(&mut self, other: &Rot2<S>) { self.mat.mul_self_m(&other.mat); }
|
fn concat_self(&mut self, other: &Basis2<S>) { self.mat.mul_self_m(&other.mat); }
|
||||||
|
|
||||||
// TODO: we know the matrix is orthogonal, so this could be re-written
|
// TODO: we know the matrix is orthogonal, so this could be re-written
|
||||||
// to be faster
|
// to be faster
|
||||||
#[inline]
|
#[inline]
|
||||||
fn invert(&self) -> Rot2<S> { Rot2 { mat: self.mat.invert().unwrap() } }
|
fn invert(&self) -> Basis2<S> { Basis2 { mat: self.mat.invert().unwrap() } }
|
||||||
|
|
||||||
// TODO: we know the matrix is orthogonal, so this could be re-written
|
// TODO: we know the matrix is orthogonal, so this could be re-written
|
||||||
// to be faster
|
// to be faster
|
||||||
|
@ -121,7 +118,7 @@ impl<S: Float> Rotation2<S> for Rot2<S> {
|
||||||
fn invert_self(&mut self) { self.mat.invert_self(); }
|
fn invert_self(&mut self) { self.mat.invert_self(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Float> ApproxEq<S> for Rot2<S> {
|
impl<S: Float> ApproxEq<S> for Basis2<S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn approx_epsilon() -> S {
|
fn approx_epsilon() -> S {
|
||||||
// TODO: fix this after static methods are fixed in rustc
|
// TODO: fix this after static methods are fixed in rustc
|
||||||
|
@ -129,12 +126,12 @@ impl<S: Float> ApproxEq<S> for Rot2<S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn approx_eq(&self, other: &Rot2<S>) -> bool {
|
fn approx_eq(&self, other: &Basis2<S>) -> bool {
|
||||||
self.mat.approx_eq(&other.mat)
|
self.mat.approx_eq(&other.mat)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn approx_eq_eps(&self, other: &Rot2<S>, approx_epsilon: &S) -> bool {
|
fn approx_eq_eps(&self, other: &Basis2<S>, approx_epsilon: &S) -> bool {
|
||||||
self.mat.approx_eq_eps(&other.mat, approx_epsilon)
|
self.mat.approx_eq_eps(&other.mat, approx_epsilon)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,40 +143,71 @@ impl<S: Float> ApproxEq<S> for Rot2<S> {
|
||||||
/// `math::Mat3`. To ensure orthogonality is maintained, the operations have
|
/// `math::Mat3`. To ensure orthogonality is maintained, the operations have
|
||||||
/// been restricted to a subeset of those implemented on `Mat3`.
|
/// been restricted to a subeset of those implemented on `Mat3`.
|
||||||
#[deriving(Eq, Clone)]
|
#[deriving(Eq, Clone)]
|
||||||
pub struct Rot3<S> {
|
pub struct Basis3<S> {
|
||||||
priv mat: Mat3<S>
|
priv mat: Mat3<S>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Float> Rot3<S> {
|
impl<S: Float> Basis3<S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn look_at(dir: &Vec3<S>, up: &Vec3<S>) -> Rot3<S> {
|
pub fn look_at(dir: &Vec3<S>, up: &Vec3<S>) -> Basis3<S> {
|
||||||
Rot3 { mat: Mat3::look_at(dir, up) }
|
Basis3 { mat: Mat3::look_at(dir, up) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a rotation matrix from a rotation around the `x` axis (pitch).
|
||||||
|
pub fn from_angle_x(theta: Rad<S>) -> Basis3<S> {
|
||||||
|
Basis3 { mat: Mat3::from_angle_x(theta) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a rotation matrix from a rotation around the `y` axis (yaw).
|
||||||
|
pub fn from_angle_y(theta: Rad<S>) -> Basis3<S> {
|
||||||
|
Basis3 { mat: Mat3::from_angle_y(theta) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a rotation matrix from a rotation around the `z` axis (roll).
|
||||||
|
pub fn from_angle_z(theta: Rad<S>) -> Basis3<S> {
|
||||||
|
Basis3 { mat: Mat3::from_angle_z(theta) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a rotation matrix from a set of euler angles.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// - `x`: the angular rotation around the `x` axis (pitch).
|
||||||
|
/// - `y`: the angular rotation around the `y` axis (yaw).
|
||||||
|
/// - `z`: the angular rotation around the `z` axis (roll).
|
||||||
|
pub fn from_euler(x: Rad<S>, y: Rad<S>, z: Rad<S>) -> Basis3<S> {
|
||||||
|
Basis3 { mat: Mat3::from_euler(x, y ,z) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a rotation matrix from a rotation around an arbitrary axis.
|
||||||
|
pub fn from_axis_angle(axis: &Vec3<S>, angle: Rad<S>) -> Basis3<S> {
|
||||||
|
Basis3 { mat: Mat3::from_axis_angle(axis, angle) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_mat3<'a>(&'a self) -> &'a Mat3<S> { &'a self.mat }
|
pub fn as_mat3<'a>(&'a self) -> &'a Mat3<S> { &'a self.mat }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ToRot3<S: Float> {
|
pub trait ToBasis3<S: Float> {
|
||||||
fn to_rot3(&self) -> Rot3<S>;
|
fn to_rot3(&self) -> Basis3<S>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Float> ToRot3<S> for Rot3<S> {
|
impl<S: Float> ToBasis3<S> for Basis3<S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_rot3(&self) -> Rot3<S> { self.clone() }
|
fn to_rot3(&self) -> Basis3<S> { self.clone() }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Float> ToMat3<S> for Rot3<S> {
|
impl<S: Float> ToMat3<S> for Basis3<S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_mat3(&self) -> Mat3<S> { self.mat.clone() }
|
fn to_mat3(&self) -> Mat3<S> { self.mat.clone() }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Float> ToQuat<S> for Rot3<S> {
|
impl<S: Float> ToQuat<S> for Basis3<S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_quat(&self) -> Quat<S> { self.mat.to_quat() }
|
fn to_quat(&self) -> Quat<S> { self.mat.to_quat() }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Float> Rotation3<S> for Rot3<S> {
|
impl<S: Float> Rotation3<S> for Basis3<S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn rotate_point3(&self, _point: &Point3<S>) -> Point3<S> { fail!("Not yet implemented") }
|
fn rotate_point3(&self, _point: &Point3<S>) -> Point3<S> { fail!("Not yet implemented") }
|
||||||
|
|
||||||
|
@ -190,15 +218,15 @@ impl<S: Float> Rotation3<S> for Rot3<S> {
|
||||||
fn rotate_ray3(&self, _ray: &Ray3<S>) -> Ray3<S> { fail!("Not yet implemented") }
|
fn rotate_ray3(&self, _ray: &Ray3<S>) -> Ray3<S> { fail!("Not yet implemented") }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn concat(&self, other: &Rot3<S>) -> Rot3<S> { Rot3 { mat: self.mat.mul_m(&other.mat) } }
|
fn concat(&self, other: &Basis3<S>) -> Basis3<S> { Basis3 { mat: self.mat.mul_m(&other.mat) } }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn concat_self(&mut self, other: &Rot3<S>) { self.mat.mul_self_m(&other.mat); }
|
fn concat_self(&mut self, other: &Basis3<S>) { self.mat.mul_self_m(&other.mat); }
|
||||||
|
|
||||||
// TODO: we know the matrix is orthogonal, so this could be re-written
|
// TODO: we know the matrix is orthogonal, so this could be re-written
|
||||||
// to be faster
|
// to be faster
|
||||||
#[inline]
|
#[inline]
|
||||||
fn invert(&self) -> Rot3<S> { Rot3 { mat: self.mat.invert().unwrap() } }
|
fn invert(&self) -> Basis3<S> { Basis3 { mat: self.mat.invert().unwrap() } }
|
||||||
|
|
||||||
// TODO: we know the matrix is orthogonal, so this could be re-written
|
// TODO: we know the matrix is orthogonal, so this could be re-written
|
||||||
// to be faster
|
// to be faster
|
||||||
|
@ -206,7 +234,7 @@ impl<S: Float> Rotation3<S> for Rot3<S> {
|
||||||
fn invert_self(&mut self) { self.mat.invert_self(); }
|
fn invert_self(&mut self) { self.mat.invert_self(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Float> ApproxEq<S> for Rot3<S> {
|
impl<S: Float> ApproxEq<S> for Basis3<S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn approx_epsilon() -> S {
|
fn approx_epsilon() -> S {
|
||||||
// TODO: fix this after static methods are fixed in rustc
|
// TODO: fix this after static methods are fixed in rustc
|
||||||
|
@ -214,21 +242,21 @@ impl<S: Float> ApproxEq<S> for Rot3<S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn approx_eq(&self, other: &Rot3<S>) -> bool {
|
fn approx_eq(&self, other: &Basis3<S>) -> bool {
|
||||||
self.mat.approx_eq(&other.mat)
|
self.mat.approx_eq(&other.mat)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn approx_eq_eps(&self, other: &Rot3<S>, approx_epsilon: &S) -> bool {
|
fn approx_eq_eps(&self, other: &Basis3<S>, approx_epsilon: &S) -> bool {
|
||||||
self.mat.approx_eq_eps(&other.mat, approx_epsilon)
|
self.mat.approx_eq_eps(&other.mat, approx_epsilon)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Quaternion Rotation impls
|
// Quaternion Rotation impls
|
||||||
|
|
||||||
impl<S: Float> ToRot3<S> for Quat<S> {
|
impl<S: Float> ToBasis3<S> for Quat<S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_rot3(&self) -> Rot3<S> { Rot3 { mat: self.to_mat3() } }
|
fn to_rot3(&self) -> Basis3<S> { Basis3 { mat: self.to_mat3() } }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Float> ToQuat<S> for Quat<S> {
|
impl<S: Float> ToQuat<S> for Quat<S> {
|
||||||
|
@ -258,226 +286,3 @@ impl<S: Float> Rotation3<S> for Quat<S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn invert_self(&mut self) { *self = self.invert() }
|
fn invert_self(&mut self) { *self = self.invert() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Euler angles
|
|
||||||
///
|
|
||||||
/// # Fields
|
|
||||||
///
|
|
||||||
/// - `x`: the angular rotation around the `x` axis (pitch)
|
|
||||||
/// - `y`: the angular rotation around the `y` axis (yaw)
|
|
||||||
/// - `z`: the angular rotation around the `z` axis (roll)
|
|
||||||
///
|
|
||||||
/// # Notes
|
|
||||||
///
|
|
||||||
/// Whilst Euler angles are more intuitive to specify than quaternions,
|
|
||||||
/// they are not recommended for general use because they are prone to gimble
|
|
||||||
/// lock, and are hard to interpolate between.
|
|
||||||
#[deriving(Eq, Clone)]
|
|
||||||
pub struct Euler<A> { x: A, y: A, z: A }
|
|
||||||
|
|
||||||
array!(impl<A> Euler<A> -> [A, ..3] _3)
|
|
||||||
|
|
||||||
impl<S: Float, A: Angle<S>> Euler<A> {
|
|
||||||
#[inline]
|
|
||||||
pub fn new(x: A, y: A, z: A) -> Euler<A> {
|
|
||||||
Euler { x: x, y: y, z: z }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ToEuler<A> {
|
|
||||||
fn to_euler(&self) -> Euler<A>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: Float, A: Angle<S>> ToMat3<S> for Euler<A> {
|
|
||||||
fn to_mat3(&self) -> Mat3<S> {
|
|
||||||
// http://en.wikipedia.org/wiki/Rotation_matrix#General_rotations
|
|
||||||
let (sx, cx) = sin_cos(self.x.clone());
|
|
||||||
let (sy, cy) = sin_cos(self.y.clone());
|
|
||||||
let (sz, cz) = sin_cos(self.z.clone());
|
|
||||||
|
|
||||||
Mat3::new(cy * cz, cy * sz, -sy,
|
|
||||||
-cx * sz + sx * sy * cz, cx * cz + sx * sy * sz, sx * cy,
|
|
||||||
sx * sz + cx * sy * cz, -sx * cz + cx * sy * sz, cx * cy)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: Float, A: Angle<S>> ToRot3<S> for Euler<A> {
|
|
||||||
#[inline]
|
|
||||||
fn to_rot3(&self) -> Rot3<S> {
|
|
||||||
Rot3 { mat: self.to_mat3() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: Float, A: Angle<S>> ToQuat<S> for Euler<A> {
|
|
||||||
fn to_quat(&self) -> Quat<S> {
|
|
||||||
// http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles#Conversion
|
|
||||||
let (sx2, cx2) = sin_cos(self.x.mul_s(cast(0.5)));
|
|
||||||
let (sy2, cy2) = sin_cos(self.y.mul_s(cast(0.5)));
|
|
||||||
let (sz2, cz2) = sin_cos(self.z.mul_s(cast(0.5)));
|
|
||||||
|
|
||||||
Quat::new(cz2 * cx2 * cy2 + sz2 * sx2 * sy2,
|
|
||||||
sz2 * cx2 * cy2 - cz2 * sx2 * sy2,
|
|
||||||
cz2 * sx2 * cy2 + sz2 * cx2 * sy2,
|
|
||||||
cz2 * cx2 * sy2 - sz2 * sx2 * cy2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: Float, A: Angle<S>> Rotation3<S> for Euler<A> {
|
|
||||||
#[inline]
|
|
||||||
fn rotate_point3(&self, _point: &Point3<S>) -> Point3<S> { fail!("Not yet implemented") }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn rotate_vec3(&self, _vec: &Vec3<S>) -> Vec3<S> { fail!("Not yet implemented"); }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn rotate_ray3(&self, _ray: &Ray3<S>) -> Ray3<S> { fail!("Not yet implemented") }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn concat(&self, _other: &Euler<A>) -> Euler<A> { fail!("Not yet implemented") }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn concat_self(&mut self, _other: &Euler<A>) { fail!("Not yet implemented"); }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn invert(&self) -> Euler<A> { fail!("Not yet implemented") }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn invert_self(&mut self) { fail!("Not yet implemented"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: Float, A: Angle<S>> ApproxEq<S> for Euler<A> {
|
|
||||||
#[inline]
|
|
||||||
fn approx_epsilon() -> S {
|
|
||||||
// TODO: fix this after static methods are fixed in rustc
|
|
||||||
fail!(~"Doesn't work!");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn approx_eq(&self, other: &Euler<A>) -> bool {
|
|
||||||
self.x.approx_eq(&other.x) &&
|
|
||||||
self.y.approx_eq(&other.y) &&
|
|
||||||
self.z.approx_eq(&other.z)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn approx_eq_eps(&self, other: &Euler<A>, approx_epsilon: &S) -> bool {
|
|
||||||
self.x.approx_eq_eps(&other.x, approx_epsilon) &&
|
|
||||||
self.y.approx_eq_eps(&other.y, approx_epsilon) &&
|
|
||||||
self.z.approx_eq_eps(&other.z, approx_epsilon)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A rotation about an arbitrary axis
|
|
||||||
///
|
|
||||||
/// # Fields
|
|
||||||
///
|
|
||||||
/// - `v`: the axis of rotation
|
|
||||||
/// - `a`: the angular rotation
|
|
||||||
#[deriving(Eq, Clone)]
|
|
||||||
pub struct AxisAngle<S, A> { v: Vec3<S>, a: A }
|
|
||||||
|
|
||||||
pub trait ToAxisAngle<S, A> {
|
|
||||||
fn to_axis_angle(&self) -> AxisAngle<S, A>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: Float, A: Angle<S>> AxisAngle<S, A> {
|
|
||||||
#[inline]
|
|
||||||
pub fn new(v: Vec3<S>, a: A) -> AxisAngle<S, A> {
|
|
||||||
AxisAngle { v: v, a: a }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: Float, A: Angle<S>> ToMat3<S> for AxisAngle<S, A> {
|
|
||||||
fn to_mat3(&self) -> Mat3<S> {
|
|
||||||
let (s, c) = sin_cos(self.a.clone());
|
|
||||||
let _1subc = one::<S>() - c;
|
|
||||||
|
|
||||||
Mat3::new(_1subc * self.v.x * self.v.x + c,
|
|
||||||
_1subc * self.v.x * self.v.y + s * self.v.z,
|
|
||||||
_1subc * self.v.x * self.v.z - s * self.v.y,
|
|
||||||
|
|
||||||
_1subc * self.v.x * self.v.y - s * self.v.z,
|
|
||||||
_1subc * self.v.y * self.v.y + c,
|
|
||||||
_1subc * self.v.y * self.v.z + s * self.v.x,
|
|
||||||
|
|
||||||
_1subc * self.v.x * self.v.z + s * self.v.y,
|
|
||||||
_1subc * self.v.y * self.v.z - s * self.v.x,
|
|
||||||
_1subc * self.v.z * self.v.z + c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: Float, A: Angle<S>> ToRot3<S> for AxisAngle<S, A> {
|
|
||||||
#[inline]
|
|
||||||
fn to_rot3(&self) -> Rot3<S> {
|
|
||||||
Rot3 { mat: self.to_mat3() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: Float, A: Angle<S>> ToQuat<S> for AxisAngle<S, A> {
|
|
||||||
fn to_quat(&self) -> Quat<S> {
|
|
||||||
let half = self.a.mul_s(cast(0.5));
|
|
||||||
Quat::from_sv(
|
|
||||||
cos(half.clone()),
|
|
||||||
self.v.mul_s(sin(half.clone()))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: Float, A: Angle<S>> Rotation3<S> for AxisAngle<S, A> {
|
|
||||||
#[inline]
|
|
||||||
fn rotate_point3(&self, _point: &Point3<S>) -> Point3<S> { fail!("Not yet implemented") }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn rotate_vec3(&self, _vec: &Vec3<S>) -> Vec3<S> { fail!("Not yet implemented"); }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn rotate_ray3(&self, _ray: &Ray3<S>) -> Ray3<S> { fail!("Not yet implemented") }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn concat(&self, _other: &AxisAngle<S, A>) -> AxisAngle<S, A> { fail!("Not yet implemented") }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn concat_self(&mut self, _other: &AxisAngle<S, A>) { fail!("Not yet implemented"); }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn invert(&self) -> AxisAngle<S, A> {
|
|
||||||
AxisAngle::new(self.v.clone(), (-self.a).normalize())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn invert_self(&mut self) {
|
|
||||||
self.a = (-self.a).normalize()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: Float, A: Angle<S>> ApproxEq<S> for AxisAngle<S, A> {
|
|
||||||
#[inline]
|
|
||||||
fn approx_epsilon() -> S {
|
|
||||||
// TODO: fix this after static methods are fixed in rustc
|
|
||||||
fail!(~"Doesn't work!");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn approx_eq(&self, other: &AxisAngle<S, A>) -> bool {
|
|
||||||
self.v.approx_eq(&other.v) &&
|
|
||||||
self.a.approx_eq(&other.a)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn approx_eq_eps(&self, other: &AxisAngle<S, A>, approx_epsilon: &S) -> bool {
|
|
||||||
self.v.approx_eq_eps(&other.v, approx_epsilon) &&
|
|
||||||
self.a.approx_eq_eps(&other.a, approx_epsilon)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An angle around the X axis (pitch).
|
|
||||||
#[deriving(Eq, Ord, Clone)]
|
|
||||||
pub struct AngleX<A>(A);
|
|
||||||
|
|
||||||
/// An angle around the X axis (yaw).
|
|
||||||
#[deriving(Eq, Ord, Clone)]
|
|
||||||
pub struct AngleY<A>(A);
|
|
||||||
|
|
||||||
/// An angle around the Z axis (roll).
|
|
||||||
#[deriving(Eq, Ord, Clone)]
|
|
||||||
pub struct AngleZ<A>(A);
|
|
||||||
|
|
40
src/cgmath/transform.rs
Normal file
40
src/cgmath/transform.rs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
// Copyright 2013 The CGMath Developers. For a full listing of the authors,
|
||||||
|
// refer to the AUTHORS file at the top-level directory of this distribution.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
pub trait Transform<S> {
|
||||||
|
fn transform_vec(&self, point: Point3<S>) -> Point3<S>;
|
||||||
|
fn transform_point(&self, point: Point3<S>) -> Point3<S>;
|
||||||
|
fn transform_ray(&self, ray: Ray3<S>) -> Ray3<S>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A homogeneous transformation matrix.
|
||||||
|
pub struct AffineMatrix3<S> {
|
||||||
|
mat: Mat4<S>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A transformation in three dimensions consisting of a rotation,
|
||||||
|
/// displacement vector and scale amount.
|
||||||
|
pub struct Transform3<S, R> {
|
||||||
|
rot: R,
|
||||||
|
disp: Vec3<S>,
|
||||||
|
scale: S,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Float, R: Rotation3<S>> Transform3<S, R> {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(rot: R, disp: Vec3<S>, scale: S) -> Transform3<S, R> {
|
||||||
|
Transform3 { rot: rot, disp: disp, scale: S }
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,6 +13,7 @@
|
||||||
// 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::fmt;
|
||||||
use std::num::{Zero, zero, One, one, sqrt};
|
use std::num::{Zero, zero, One, one, sqrt};
|
||||||
|
|
||||||
use angle::{Rad, atan2, acos};
|
use angle::{Rad, atan2, acos};
|
||||||
|
@ -282,20 +283,20 @@ impl<S: Float> EuclideanVector<S, [S, ..4]> for Vec4<S> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> ToStr for Vec2<S> {
|
impl<S: fmt::Default> ToStr for Vec2<S> {
|
||||||
fn to_str(&self) -> ~str {
|
fn to_str(&self) -> ~str {
|
||||||
fmt!("[%?, %?]", self.x, self.y)
|
format!("[{}, {}]", self.x, self.y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> ToStr for Vec3<S> {
|
impl<S: fmt::Default> ToStr for Vec3<S> {
|
||||||
fn to_str(&self) -> ~str {
|
fn to_str(&self) -> ~str {
|
||||||
fmt!("[%?, %?, %?]", self.x, self.y, self.z)
|
format!("[{}, {}, {}]", self.x, self.y, self.z)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> ToStr for Vec4<S> {
|
impl<S: fmt::Default> ToStr for Vec4<S> {
|
||||||
fn to_str(&self) -> ~str {
|
fn to_str(&self) -> ~str {
|
||||||
fmt!("[%?, %?, %?, %?]", self.x, self.y, self.z, self.w)
|
format!("[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue