diff --git a/src/transform/rotation.rs b/src/transform/rotation.rs index 1fa879a..434f9fd 100644 --- a/src/transform/rotation.rs +++ b/src/transform/rotation.rs @@ -13,8 +13,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Various three-dimensional rotation types that are useful for constructing -//! matricies and quaternions. +//! Various three-dimensional rotation types and impls. +//! +//! Some of these are more useful for constructing matricies and quaternions. +//! than for general use. For example due to issues with gimble lock, it is +//! not reccomended that Euler rotations be used for translations, but +//! they _are_ useful for intuitively specifying rotations. //! //! # Examples //! @@ -32,8 +36,18 @@ use math::*; use math::{Point3, Ray3}; -/// A generic rotation -pub trait Rotation: Eq +/// A two-dimensional rotation +pub trait Rotation2: Eq + + ApproxEq + + ToMat2 { + pub fn rotate_point2(&self, point: Point2) -> Point2; + pub fn rotate_vec2(&self, vec: Vec2) -> Point2; + pub fn rotate_ray2(&self, vec: Ray2) -> Ray2; + pub fn to_rotation_mat2(&self) -> RotationMat2; +} + +/// A three-dimensional rotation +pub trait Rotation3: Eq + ApproxEq + ToMat3 + ToMat4 @@ -41,99 +55,193 @@ pub trait Rotation: Eq pub fn rotate_point3(&self, point: Point3) -> Point3; pub fn rotate_vec3(&self, vec: Vec3) -> Point3; pub fn rotate_ray3(&self, vec: Ray3) -> Ray3; + pub fn to_rotation_mat3(&self) -> RotationMat3; } -impl Rotation for Quat { - pub fn rotate_point3(&self, _point: Point3) -> Point3 { - fail!("Not yet implemented.") - } - - pub fn rotate_vec3(&self, _vec: Vec3) -> Point3 { - fail!("Not yet implemented.") - } - - pub fn rotate_ray3(&self, _vec: Ray3) -> Ray3 { - fail!("Not yet implemented.") - } -} - -/// A rotation matrix +/// A two-dimensional rotation matrix. +/// +/// The matrix is guaranteed to be orthogonal, so some operations can be +/// implemented more efficiently than the implementations for `math::Mat2`. To +/// enforce orthogonality at the type level the operations have been restricted +/// to a subeset of those implemented on `Mat3`. #[deriving(Eq, Clone)] -pub struct RotationMat { - priv mat: Mat3 +pub struct RotationMat2 { + priv mat: Mat2 } -impl RotationMat { +impl RotationMat2 { #[inline] - pub fn as_mat3<'a>(&'a self) -> & 'a Mat3 { + pub fn as_mat2<'a>(&'a self) -> & 'a Mat2 { unsafe { cast::transmute(self) } } } -impl Rotation for RotationMat { - pub fn rotate_point3(&self, _point: Point3) -> Point3 { +impl Rotation2 for RotationMat2 { + pub fn rotate_point2(&self, _point: Point2) -> Point2 { fail!("Not yet implemented.") } - pub fn rotate_vec3(&self, _vec: Vec3) -> Point3 { + pub fn rotate_vec2(&self, _vec: Vec2) -> Point2 { fail!("Not yet implemented.") } - pub fn rotate_ray3(&self, _vec: Ray3) -> Ray3 { + pub fn rotate_ray2(&self, _vec: Ray2) -> Ray2 { fail!("Not yet implemented.") } -} -impl ToQuat for RotationMat { - #[inline] pub fn to_quat(&self) -> Quat { self.mat.to_quat() } -} - -impl ToMat3 for RotationMat { - #[inline] pub fn to_mat3(&self) -> Mat3 { self.mat.clone() } -} - -impl ToMat4 for RotationMat { - #[inline] pub fn to_mat4(&self) -> Mat4 { self.mat.to_mat4() } -} - -impl RotationMat { #[inline] - pub fn identity() -> RotationMat { - RotationMat { mat: Mat3::identity() } + pub fn to_rotation_mat2(&self) -> RotationMat2 { + RotationMat2 { mat: self.to_mat2() } + } +} + +impl ToMat2 for RotationMat2 { + #[inline] pub fn to_mat2(&self) -> Mat2 { self.mat.clone() } +} + +impl RotationMat2 { + #[inline] + pub fn identity() -> RotationMat2 { + RotationMat2 { mat: Mat2::identity() } } #[inline] - pub fn zero() -> RotationMat { - RotationMat { mat: Mat3::zero() } + pub fn zero() -> RotationMat2 { + RotationMat2 { mat: Mat2::zero() } } } -impl Neg> for RotationMat { +impl Neg> for RotationMat2 { #[inline] - pub fn neg(&self) -> RotationMat { - RotationMat { mat: -self.mat } + pub fn neg(&self) -> RotationMat2 { + RotationMat2 { mat: -self.mat } } } -impl RotationMat { - pub fn look_at(dir: &Vec3, up: &Vec3) -> RotationMat { - RotationMat { mat: Mat3::look_at(dir, up) } - } -} - -impl> ApproxEq for RotationMat { +impl> ApproxEq for RotationMat2 { #[inline] pub fn approx_epsilon() -> T { ApproxEq::approx_epsilon::() } #[inline] - pub fn approx_eq(&self, other: &RotationMat) -> bool { + pub fn approx_eq(&self, other: &RotationMat2) -> bool { self.approx_eq_eps(other, &ApproxEq::approx_epsilon::()) } #[inline] - pub fn approx_eq_eps(&self, other: &RotationMat, epsilon: &T) -> bool { + pub fn approx_eq_eps(&self, other: &RotationMat2, epsilon: &T) -> bool { + self.mat.approx_eq_eps(&other.mat, epsilon) + } +} + + +impl Rotation3 for Quat { + pub fn rotate_point3(&self, _point: Point3) -> Point3 { + fail!("Not yet implemented.") + } + + pub fn rotate_vec3(&self, _vec: Vec3) -> Point3 { + fail!("Not yet implemented.") + } + + pub fn rotate_ray3(&self, _vec: Ray3) -> Ray3 { + fail!("Not yet implemented.") + } + + #[inline] + pub fn to_rotation_mat3(&self) -> RotationMat3 { + RotationMat3 { mat: self.to_mat3() } + } +} + +/// A three-dimensional rotation matrix. +/// +/// The matrix is guaranteed to be orthogonal, so some operations, specifically +/// inversion, can be implemented more efficiently than the implementations for +/// `math::Mat3`. To enforce orthogonality at the type level the operations have +/// been restricted to a subeset of those implemented on `Mat3`. +#[deriving(Eq, Clone)] +pub struct RotationMat3 { + priv mat: Mat3 +} + +impl RotationMat3 { + #[inline] + pub fn as_mat3<'a>(&'a self) -> & 'a Mat3 { + unsafe { cast::transmute(self) } + } +} + +impl Rotation3 for RotationMat3 { + pub fn rotate_point3(&self, _point: Point3) -> Point3 { + fail!("Not yet implemented.") + } + + pub fn rotate_vec3(&self, _vec: Vec3) -> Point3 { + fail!("Not yet implemented.") + } + + pub fn rotate_ray3(&self, _vec: Ray3) -> Ray3 { + fail!("Not yet implemented.") + } + + #[inline] + pub fn to_rotation_mat3(&self) -> RotationMat3 { + RotationMat3 { mat: self.to_mat3() } + } +} + +impl ToQuat for RotationMat3 { + #[inline] pub fn to_quat(&self) -> Quat { self.mat.to_quat() } +} + +impl ToMat3 for RotationMat3 { + #[inline] pub fn to_mat3(&self) -> Mat3 { self.mat.clone() } +} + +impl ToMat4 for RotationMat3 { + #[inline] pub fn to_mat4(&self) -> Mat4 { self.mat.to_mat4() } +} + +impl RotationMat3 { + #[inline] + pub fn identity() -> RotationMat3 { + RotationMat3 { mat: Mat3::identity() } + } + + #[inline] + pub fn zero() -> RotationMat3 { + RotationMat3 { mat: Mat3::zero() } + } +} + +impl Neg> for RotationMat3 { + #[inline] + pub fn neg(&self) -> RotationMat3 { + RotationMat3 { mat: -self.mat } + } +} + +impl RotationMat3 { + pub fn look_at(dir: &Vec3, up: &Vec3) -> RotationMat3 { + RotationMat3 { mat: Mat3::look_at(dir, up) } + } +} + +impl> ApproxEq for RotationMat3 { + #[inline] + pub fn approx_epsilon() -> T { + ApproxEq::approx_epsilon::() + } + + #[inline] + pub fn approx_eq(&self, other: &RotationMat3) -> bool { + self.approx_eq_eps(other, &ApproxEq::approx_epsilon::()) + } + + #[inline] + pub fn approx_eq_eps(&self, other: &RotationMat3, epsilon: &T) -> bool { self.mat.approx_eq_eps(&other.mat, epsilon) } } @@ -165,7 +273,7 @@ impl Euler { } } -impl Rotation for Euler { +impl Rotation3 for Euler { pub fn rotate_point3(&self, _point: Point3) -> Point3 { fail!("Not yet implemented.") } @@ -177,6 +285,11 @@ impl Rotation for Euler { pub fn rotate_ray3(&self, _vec: Ray3) -> Ray3 { fail!("Not yet implemented.") } + + #[inline] + pub fn to_rotation_mat3(&self) -> RotationMat3 { + RotationMat3 { mat: self.to_mat3() } + } } impl ToQuat for Euler { @@ -254,7 +367,7 @@ impl AxisAngle { } } -impl Rotation for AxisAngle { +impl Rotation3 for AxisAngle { pub fn rotate_point3(&self, _point: Point3) -> Point3 { fail!("Not yet implemented.") } @@ -266,6 +379,11 @@ impl Rotation for AxisAngle { pub fn rotate_ray3(&self, _vec: Ray3) -> Ray3 { fail!("Not yet implemented.") } + + #[inline] + pub fn to_rotation_mat3(&self) -> RotationMat3 { + RotationMat3 { mat: self.to_mat3() } + } } impl ToQuat for AxisAngle { @@ -346,7 +464,7 @@ pub struct AngleX(T); impl_approx!(AngleX) -impl Rotation for AngleX { +impl Rotation3 for AngleX { pub fn rotate_point3(&self, _point: Point3) -> Point3 { fail!("Not yet implemented.") } @@ -358,6 +476,11 @@ impl Rotation for AngleX { pub fn rotate_ray3(&self, _vec: Ray3) -> Ray3 { fail!("Not yet implemented.") } + + #[inline] + pub fn to_rotation_mat3(&self) -> RotationMat3 { + RotationMat3 { mat: self.to_mat3() } + } } impl ToQuat for AngleX { @@ -402,7 +525,7 @@ pub struct AngleY(T); impl_approx!(AngleY) -impl Rotation for AngleY { +impl Rotation3 for AngleY { pub fn rotate_point3(&self, _point: Point3) -> Point3 { fail!("Not yet implemented.") } @@ -414,6 +537,11 @@ impl Rotation for AngleY { pub fn rotate_ray3(&self, _vec: Ray3) -> Ray3 { fail!("Not yet implemented.") } + + #[inline] + pub fn to_rotation_mat3(&self) -> RotationMat3 { + RotationMat3 { mat: self.to_mat3() } + } } impl ToQuat for AngleY { @@ -458,7 +586,26 @@ pub struct AngleZ(T); impl_approx!(AngleZ) -impl Rotation for AngleZ { +impl Rotation2 for AngleZ { + pub fn rotate_point2(&self, _point: Point2) -> Point2 { + fail!("Not yet implemented.") + } + + pub fn rotate_vec2(&self, _vec: Vec2) -> Point2 { + fail!("Not yet implemented.") + } + + pub fn rotate_ray2(&self, _vec: Ray2) -> Ray2 { + fail!("Not yet implemented.") + } + + #[inline] + pub fn to_rotation_mat2(&self) -> RotationMat2 { + RotationMat2 { mat: self.to_mat2() } + } +} + +impl Rotation3 for AngleZ { pub fn rotate_point3(&self, _point: Point3) -> Point3 { fail!("Not yet implemented.") } @@ -470,6 +617,11 @@ impl Rotation for AngleZ { pub fn rotate_ray3(&self, _vec: Ray3) -> Ray3 { fail!("Not yet implemented.") } + + #[inline] + pub fn to_rotation_mat3(&self) -> RotationMat3 { + RotationMat3 { mat: self.to_mat3() } + } } impl ToQuat for AngleZ { diff --git a/src/transform/transform.rs b/src/transform/transform.rs index 8d0a113..a2e68f6 100644 --- a/src/transform/transform.rs +++ b/src/transform/transform.rs @@ -14,7 +14,7 @@ // limitations under the License. pub use self::projection::{Projection, Perspective, PerspectiveFOV, Ortho}; -pub use self::rotation::Rotation; +pub use self::rotation::{Rotation2, Rotation3}; pub use self::rotation::{Euler, ToEuler}; pub use self::rotation::{AxisAngle, ToAxisAngle}; pub use self::rotation::{AngleX, AngleY, AngleZ};