Reduce the number of rotation types, shifting some of the functionality to the quaternion and matrix constructors.
This commit is contained in:
parent
ad275b43db
commit
e4e9b6909e
3 changed files with 142 additions and 229 deletions
|
@ -17,7 +17,7 @@
|
|||
|
||||
use std::num::{Zero, zero, One, one, cast, sqrt};
|
||||
|
||||
use angle::{Rad, sin, cos};
|
||||
use angle::{Angle, Rad, sin, cos, sin_cos};
|
||||
use array::{Array, build};
|
||||
use quaternion::{Quat, ToQuat};
|
||||
use vector::{Vector, EuclideanVector};
|
||||
|
@ -121,6 +121,69 @@ impl<S: Float> Mat3<S> {
|
|||
|
||||
Mat3::from_cols(up, side, dir)
|
||||
}
|
||||
|
||||
/// Create a matrix from a rotation around the `x` axis (pitch).
|
||||
pub fn from_angle_x<A: Angle<S>>(theta: A) -> 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<A: Angle<S>>(theta: A) -> 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<A: Angle<S>>(theta: A) -> 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<A: Angle<S>>(x: A, y: A, z: A) -> 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<A: Angle<S>>(axis: &Vec3<S>, angle: A) -> 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> {
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
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 matrix::{Mat3, ToMat3};
|
||||
use vector::{Vec3, Vector, EuclideanVector};
|
||||
|
@ -50,6 +50,51 @@ impl<S: Float> Quat<S> {
|
|||
Mat3::look_at(dir, up).to_quat()
|
||||
}
|
||||
|
||||
/// Create a matrix from a rotation around the `x` axis (pitch).
|
||||
#[inline]
|
||||
pub fn from_angle_x<A: Angle<S>>(theta: A) -> Quat<S> {
|
||||
Quat::new(cos(theta.mul_s(cast(0.5))), sin(theta), zero(), zero())
|
||||
}
|
||||
|
||||
/// Create a matrix from a rotation around the `y` axis (yaw).
|
||||
#[inline]
|
||||
pub fn from_angle_y<A: Angle<S>>(theta: A) -> Quat<S> {
|
||||
Quat::new(cos(theta.mul_s(cast(0.5))), zero(), sin(theta), zero())
|
||||
}
|
||||
|
||||
/// Create a matrix from a rotation around the `z` axis (roll).
|
||||
#[inline]
|
||||
pub fn from_angle_z<A: Angle<S>>(theta: A) -> Quat<S> {
|
||||
Quat::new(cos(theta.mul_s(cast(0.5))), 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<A: Angle<S>>(x: A, y: A, z: A) -> 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)));
|
||||
let (sy2, cy2) = sin_cos(y.mul_s(cast(0.5)));
|
||||
let (sz2, cz2) = sin_cos(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)
|
||||
}
|
||||
|
||||
/// Create a quaternion from a rotation around an arbitrary axis
|
||||
#[inline]
|
||||
pub fn from_axis_angle<A: Angle<S>>(axis: &Vec3<S>, angle: A) -> Quat<S> {
|
||||
let half = angle.mul_s(cast(0.5));
|
||||
Quat::from_sv(cos(half.clone()),
|
||||
axis.mul_s(sin(half)))
|
||||
}
|
||||
|
||||
/// The additive identity, ie: `q = 0 + 0i + 0j + 0i`
|
||||
#[inline]
|
||||
pub fn zero() -> Quat<S> {
|
||||
|
|
|
@ -13,10 +13,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::num::{cast, one};
|
||||
|
||||
use angle::{Angle, sin, cos, sin_cos};
|
||||
use array::Array;
|
||||
use angle::Angle;
|
||||
use matrix::Matrix;
|
||||
use matrix::{Mat2, ToMat2};
|
||||
use matrix::{Mat3, ToMat3};
|
||||
|
@ -156,6 +153,37 @@ impl<S: Float> Rot3<S> {
|
|||
Rot3 { mat: Mat3::look_at(dir, up) }
|
||||
}
|
||||
|
||||
/// Create a rotation matrix from a rotation around the `x` axis (pitch).
|
||||
pub fn from_angle_x<A: Angle<S>>(theta: A) -> Rot3<S> {
|
||||
Rot3 { mat: Mat3::from_angle_x(theta) }
|
||||
}
|
||||
|
||||
/// Create a rotation matrix from a rotation around the `y` axis (yaw).
|
||||
pub fn from_angle_y<A: Angle<S>>(theta: A) -> Rot3<S> {
|
||||
Rot3 { mat: Mat3::from_angle_y(theta) }
|
||||
}
|
||||
|
||||
/// Create a rotation matrix from a rotation around the `z` axis (roll).
|
||||
pub fn from_angle_z<A: Angle<S>>(theta: A) -> Rot3<S> {
|
||||
Rot3 { 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<A: Angle<S>>(x: A, y: A, z: A) -> Rot3<S> {
|
||||
Rot3 { mat: Mat3::from_euler(x, y ,z) }
|
||||
}
|
||||
|
||||
/// Create a rotation matrix from a rotation around an arbitrary axis.
|
||||
pub fn from_axis_angle<A: Angle<S>>(axis: &Vec3<S>, angle: A) -> Rot3<S> {
|
||||
Rot3 { mat: Mat3::from_axis_angle(axis, angle) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_mat3<'a>(&'a self) -> &'a Mat3<S> { &'a self.mat }
|
||||
}
|
||||
|
@ -258,226 +286,3 @@ impl<S: Float> Rotation3<S> for Quat<S> {
|
|||
#[inline]
|
||||
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);
|
||||
|
|
Loading…
Reference in a new issue