Now there is only one one (#513)
* Now there is only one one * Rotation no longer has a parameter * Moved some type parameters to associated types * Relaxed some bounds and simplified a bound * Removed unnecessary bound in * Deduplicated multiplication code
This commit is contained in:
parent
816c043223
commit
84da664455
6 changed files with 152 additions and 58 deletions
|
@ -1038,10 +1038,6 @@ impl<S: BaseFloat> approx::UlpsEq for Matrix4<S> {
|
|||
}
|
||||
|
||||
impl<S: BaseFloat> Transform<Point2<S>> for Matrix3<S> {
|
||||
fn one() -> Matrix3<S> {
|
||||
One::one()
|
||||
}
|
||||
|
||||
fn look_at(eye: Point2<S>, center: Point2<S>, up: Vector2<S>) -> Matrix3<S> {
|
||||
let dir = center - eye;
|
||||
Matrix3::from(Matrix2::look_at(dir, up))
|
||||
|
@ -1065,10 +1061,6 @@ impl<S: BaseFloat> Transform<Point2<S>> for Matrix3<S> {
|
|||
}
|
||||
|
||||
impl<S: BaseFloat> Transform<Point3<S>> for Matrix3<S> {
|
||||
fn one() -> Matrix3<S> {
|
||||
One::one()
|
||||
}
|
||||
|
||||
fn look_at(eye: Point3<S>, center: Point3<S>, up: Vector3<S>) -> Matrix3<S> {
|
||||
let dir = center - eye;
|
||||
Matrix3::look_at(dir, up)
|
||||
|
@ -1092,10 +1084,6 @@ impl<S: BaseFloat> Transform<Point3<S>> for Matrix3<S> {
|
|||
}
|
||||
|
||||
impl<S: BaseFloat> Transform<Point3<S>> for Matrix4<S> {
|
||||
fn one() -> Matrix4<S> {
|
||||
One::one()
|
||||
}
|
||||
|
||||
fn look_at(eye: Point3<S>, center: Point3<S>, up: Vector3<S>) -> Matrix4<S> {
|
||||
Matrix4::look_at(eye, center, up)
|
||||
}
|
||||
|
@ -1117,11 +1105,17 @@ impl<S: BaseFloat> Transform<Point3<S>> for Matrix4<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: BaseFloat> Transform2<S> for Matrix3<S> {}
|
||||
impl<S: BaseFloat> Transform2 for Matrix3<S> {
|
||||
type Scalar = S;
|
||||
}
|
||||
|
||||
impl<S: BaseFloat> Transform3<S> for Matrix3<S> {}
|
||||
impl<S: BaseFloat> Transform3 for Matrix3<S> {
|
||||
type Scalar = S;
|
||||
}
|
||||
|
||||
impl<S: BaseFloat> Transform3<S> for Matrix4<S> {}
|
||||
impl<S: BaseFloat> Transform3 for Matrix4<S> {
|
||||
type Scalar = S;
|
||||
}
|
||||
|
||||
macro_rules! impl_matrix {
|
||||
($MatrixN:ident, $VectorN:ident { $($field:ident : $row_index:expr),+ }) => {
|
||||
|
|
|
@ -480,7 +480,9 @@ impl<S: BaseFloat> From<Quaternion<S>> for Basis3<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: BaseFloat> Rotation<Point3<S>> for Quaternion<S> {
|
||||
impl<S: BaseFloat> Rotation for Quaternion<S> {
|
||||
type Space = Point3<S>;
|
||||
|
||||
#[inline]
|
||||
fn look_at(dir: Vector3<S>, up: Vector3<S>) -> Quaternion<S> {
|
||||
Matrix3::look_at(dir, up).into()
|
||||
|
@ -526,7 +528,9 @@ impl<S: BaseFloat> Rotation<Point3<S>> for Quaternion<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: BaseFloat> Rotation3<S> for Quaternion<S> {
|
||||
impl<S: BaseFloat> Rotation3 for Quaternion<S> {
|
||||
type Scalar = S;
|
||||
|
||||
#[inline]
|
||||
fn from_axis_angle<A: Into<Rad<S>>>(axis: Vector3<S>, angle: A) -> Quaternion<S> {
|
||||
let (s, c) = Rad::sin_cos(angle.into() * cast(0.5f64).unwrap());
|
||||
|
|
|
@ -30,30 +30,41 @@ use vector::{Vector2, Vector3};
|
|||
|
||||
/// A trait for a generic rotation. A rotation is a transformation that
|
||||
/// creates a circular motion, and preserves at least one point in the space.
|
||||
pub trait Rotation<P: EuclideanSpace>: Sized + Copy + One
|
||||
pub trait Rotation: Sized + Copy + One
|
||||
where
|
||||
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
|
||||
Self: approx::AbsDiffEq<Epsilon = P::Scalar>,
|
||||
Self: approx::RelativeEq<Epsilon = P::Scalar>,
|
||||
Self: approx::UlpsEq<Epsilon = P::Scalar>,
|
||||
P::Scalar: BaseFloat,
|
||||
Self: approx::AbsDiffEq<Epsilon = <<Self as Rotation>::Space as EuclideanSpace>::Scalar>,
|
||||
Self: approx::RelativeEq<Epsilon = <<Self as Rotation>::Space as EuclideanSpace>::Scalar>,
|
||||
Self: approx::UlpsEq<Epsilon = <<Self as Rotation>::Space as EuclideanSpace>::Scalar>,
|
||||
<Self::Space as EuclideanSpace>::Scalar: BaseFloat,
|
||||
Self: iter::Product<Self>,
|
||||
{
|
||||
type Space: EuclideanSpace;
|
||||
|
||||
/// Create a rotation to a given direction with an 'up' vector.
|
||||
fn look_at(dir: P::Diff, up: P::Diff) -> Self;
|
||||
fn look_at(
|
||||
dir: <Self::Space as EuclideanSpace>::Diff,
|
||||
up: <Self::Space as EuclideanSpace>::Diff,
|
||||
) -> Self;
|
||||
|
||||
/// Create a shortest rotation to transform vector 'a' into 'b'.
|
||||
/// Both given vectors are assumed to have unit length.
|
||||
fn between_vectors(a: P::Diff, b: P::Diff) -> Self;
|
||||
fn between_vectors(
|
||||
a: <Self::Space as EuclideanSpace>::Diff,
|
||||
b: <Self::Space as EuclideanSpace>::Diff,
|
||||
) -> Self;
|
||||
|
||||
/// Rotate a vector using this rotation.
|
||||
fn rotate_vector(&self, vec: P::Diff) -> P::Diff;
|
||||
fn rotate_vector(
|
||||
&self,
|
||||
vec: <Self::Space as EuclideanSpace>::Diff,
|
||||
) -> <Self::Space as EuclideanSpace>::Diff;
|
||||
|
||||
/// Rotate a point using this rotation, by converting it to its
|
||||
/// representation as a vector.
|
||||
#[inline]
|
||||
fn rotate_point(&self, point: P) -> P {
|
||||
P::from_vec(self.rotate_vector(point.to_vec()))
|
||||
fn rotate_point(&self, point: Self::Space) -> Self::Space {
|
||||
Self::Space::from_vec(self.rotate_vector(point.to_vec()))
|
||||
}
|
||||
|
||||
/// Create a new rotation which "un-does" this rotation. That is,
|
||||
|
@ -62,38 +73,48 @@ where
|
|||
}
|
||||
|
||||
/// A two-dimensional rotation.
|
||||
pub trait Rotation2<S: BaseFloat>:
|
||||
Rotation<Point2<S>> + Into<Matrix2<S>> + Into<Basis2<S>>
|
||||
pub trait Rotation2:
|
||||
Rotation<Space = Point2<<Self as Rotation2>::Scalar>>
|
||||
+ Into<Matrix2<<Self as Rotation2>::Scalar>>
|
||||
+ Into<Basis2<<Self as Rotation2>::Scalar>>
|
||||
{
|
||||
type Scalar: BaseFloat;
|
||||
|
||||
/// Create a rotation by a given angle. Thus is a redundant case of both
|
||||
/// from_axis_angle() and from_euler() for 2D space.
|
||||
fn from_angle<A: Into<Rad<S>>>(theta: A) -> Self;
|
||||
fn from_angle<A: Into<Rad<Self::Scalar>>>(theta: A) -> Self;
|
||||
}
|
||||
|
||||
/// A three-dimensional rotation.
|
||||
pub trait Rotation3<S: BaseFloat>:
|
||||
Rotation<Point3<S>> + Into<Matrix3<S>> + Into<Basis3<S>> + Into<Quaternion<S>> + From<Euler<Rad<S>>>
|
||||
pub trait Rotation3:
|
||||
Rotation<Space = Point3<<Self as Rotation3>::Scalar>>
|
||||
+ Into<Matrix3<<Self as Rotation3>::Scalar>>
|
||||
+ Into<Basis3<<Self as Rotation3>::Scalar>>
|
||||
+ Into<Quaternion<<Self as Rotation3>::Scalar>>
|
||||
+ From<Euler<Rad<<Self as Rotation3>::Scalar>>>
|
||||
{
|
||||
type Scalar: BaseFloat;
|
||||
|
||||
/// Create a rotation using an angle around a given axis.
|
||||
///
|
||||
/// The specified axis **must be normalized**, or it represents an invalid rotation.
|
||||
fn from_axis_angle<A: Into<Rad<S>>>(axis: Vector3<S>, angle: A) -> Self;
|
||||
fn from_axis_angle<A: Into<Rad<Self::Scalar>>>(axis: Vector3<Self::Scalar>, angle: A) -> Self;
|
||||
|
||||
/// Create a rotation from an angle around the `x` axis (pitch).
|
||||
#[inline]
|
||||
fn from_angle_x<A: Into<Rad<S>>>(theta: A) -> Self {
|
||||
fn from_angle_x<A: Into<Rad<Self::Scalar>>>(theta: A) -> Self {
|
||||
Rotation3::from_axis_angle(Vector3::unit_x(), theta)
|
||||
}
|
||||
|
||||
/// Create a rotation from an angle around the `y` axis (yaw).
|
||||
#[inline]
|
||||
fn from_angle_y<A: Into<Rad<S>>>(theta: A) -> Self {
|
||||
fn from_angle_y<A: Into<Rad<Self::Scalar>>>(theta: A) -> Self {
|
||||
Rotation3::from_axis_angle(Vector3::unit_y(), theta)
|
||||
}
|
||||
|
||||
/// Create a rotation from an angle around the `z` axis (roll).
|
||||
#[inline]
|
||||
fn from_angle_z<A: Into<Rad<S>>>(theta: A) -> Self {
|
||||
fn from_angle_z<A: Into<Rad<Self::Scalar>>>(theta: A) -> Self {
|
||||
Rotation3::from_axis_angle(Vector3::unit_z(), theta)
|
||||
}
|
||||
}
|
||||
|
@ -183,7 +204,9 @@ impl<'a, S: 'a + BaseFloat> iter::Product<&'a Basis2<S>> for Basis2<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: BaseFloat> Rotation<Point2<S>> for Basis2<S> {
|
||||
impl<S: BaseFloat> Rotation for Basis2<S> {
|
||||
type Space = Point2<S>;
|
||||
|
||||
#[inline]
|
||||
fn look_at(dir: Vector2<S>, up: Vector2<S>) -> Basis2<S> {
|
||||
Basis2 {
|
||||
|
@ -262,7 +285,9 @@ impl<S: BaseFloat> approx::UlpsEq for Basis2<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: BaseFloat> Rotation2<S> for Basis2<S> {
|
||||
impl<S: BaseFloat> Rotation2 for Basis2<S> {
|
||||
type Scalar = S;
|
||||
|
||||
fn from_angle<A: Into<Rad<S>>>(theta: A) -> Basis2<S> {
|
||||
Basis2 {
|
||||
mat: Matrix2::from_angle(theta),
|
||||
|
@ -334,7 +359,9 @@ impl<'a, S: 'a + BaseFloat> iter::Product<&'a Basis3<S>> for Basis3<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: BaseFloat> Rotation<Point3<S>> for Basis3<S> {
|
||||
impl<S: BaseFloat> Rotation for Basis3<S> {
|
||||
type Space = Point3<S>;
|
||||
|
||||
#[inline]
|
||||
fn look_at(dir: Vector3<S>, up: Vector3<S>) -> Basis3<S> {
|
||||
Basis3 {
|
||||
|
@ -414,7 +441,9 @@ impl<S: BaseFloat> approx::UlpsEq for Basis3<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: BaseFloat> Rotation3<S> for Basis3<S> {
|
||||
impl<S: BaseFloat> Rotation3 for Basis3<S> {
|
||||
type Scalar = S;
|
||||
|
||||
fn from_axis_angle<A: Into<Rad<S>>>(axis: Vector3<S>, angle: A) -> Basis3<S> {
|
||||
Basis3 {
|
||||
mat: Matrix3::from_axis_angle(axis, angle),
|
||||
|
|
|
@ -22,14 +22,12 @@ use point::{Point2, Point3};
|
|||
use rotation::*;
|
||||
use vector::{Vector2, Vector3};
|
||||
|
||||
use std::ops::Mul;
|
||||
|
||||
/// A trait representing an [affine
|
||||
/// transformation](https://en.wikipedia.org/wiki/Affine_transformation) that
|
||||
/// can be applied to points or vectors. An affine transformation is one which
|
||||
pub trait Transform<P: EuclideanSpace>: Sized {
|
||||
/// Create an identity transformation. That is, a transformation which
|
||||
/// does nothing.
|
||||
fn one() -> Self;
|
||||
|
||||
pub trait Transform<P: EuclideanSpace>: Sized + One {
|
||||
/// Create a transformation that rotates a vector to look at `center` from
|
||||
/// `eye`, using `up` for orientation.
|
||||
fn look_at(eye: P, center: P, up: P::Diff) -> Self;
|
||||
|
@ -69,21 +67,41 @@ pub struct Decomposed<V: VectorSpace, R> {
|
|||
pub disp: V,
|
||||
}
|
||||
|
||||
impl<P: EuclideanSpace, R: Rotation<P>> Transform<P> for Decomposed<P::Diff, R>
|
||||
impl<P: EuclideanSpace, R: Rotation<Space = P>> One for Decomposed<P::Diff, R>
|
||||
where
|
||||
P::Scalar: BaseFloat,
|
||||
// FIXME: Investigate why this is needed!
|
||||
P::Diff: VectorSpace,
|
||||
{
|
||||
#[inline]
|
||||
fn one() -> Decomposed<P::Diff, R> {
|
||||
fn one() -> Self {
|
||||
Decomposed {
|
||||
scale: P::Scalar::one(),
|
||||
rot: R::one(),
|
||||
disp: P::Diff::zero(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: EuclideanSpace, R: Rotation<Space = P>> Mul for Decomposed<P::Diff, R>
|
||||
where
|
||||
P::Scalar: BaseFloat,
|
||||
P::Diff: VectorSpace,
|
||||
{
|
||||
type Output = Self;
|
||||
|
||||
/// Multiplies the two transforms together.
|
||||
/// The result should be as if the two transforms were converted
|
||||
/// to matrices, then multiplied, then converted back with
|
||||
/// a (currently nonexistent) function that tries to convert
|
||||
/// a matrix into a `Decomposed`.
|
||||
fn mul(self, rhs: Decomposed<P::Diff, R>) -> Self::Output {
|
||||
self.concat(&rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: EuclideanSpace, R: Rotation<Space = P>> Transform<P> for Decomposed<P::Diff, R>
|
||||
where
|
||||
P::Scalar: BaseFloat,
|
||||
P::Diff: VectorSpace,
|
||||
{
|
||||
#[inline]
|
||||
fn look_at(eye: P, center: P, up: P::Diff) -> Decomposed<P::Diff, R> {
|
||||
let rot = R::look_at(center - eye, up);
|
||||
|
@ -138,10 +156,18 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub trait Transform2<S: BaseNum>: Transform<Point2<S>> + Into<Matrix3<S>> {}
|
||||
pub trait Transform3<S: BaseNum>: Transform<Point3<S>> + Into<Matrix4<S>> {}
|
||||
pub trait Transform2:
|
||||
Transform<Point2<<Self as Transform2>::Scalar>> + Into<Matrix3<<Self as Transform2>::Scalar>>
|
||||
{
|
||||
type Scalar: BaseNum;
|
||||
}
|
||||
pub trait Transform3:
|
||||
Transform<Point3<<Self as Transform3>::Scalar>> + Into<Matrix4<<Self as Transform3>::Scalar>>
|
||||
{
|
||||
type Scalar: BaseNum;
|
||||
}
|
||||
|
||||
impl<S: BaseFloat, R: Rotation2<S>> From<Decomposed<Vector2<S>, R>> for Matrix3<S> {
|
||||
impl<S: BaseFloat, R: Rotation2<Scalar = S>> From<Decomposed<Vector2<S>, R>> for Matrix3<S> {
|
||||
fn from(dec: Decomposed<Vector2<S>, R>) -> Matrix3<S> {
|
||||
let m: Matrix2<_> = dec.rot.into();
|
||||
let mut m: Matrix3<_> = (&m * dec.scale).into();
|
||||
|
@ -150,7 +176,7 @@ impl<S: BaseFloat, R: Rotation2<S>> From<Decomposed<Vector2<S>, R>> for Matrix3<
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: BaseFloat, R: Rotation3<S>> From<Decomposed<Vector3<S>, R>> for Matrix4<S> {
|
||||
impl<S: BaseFloat, R: Rotation3<Scalar = S>> From<Decomposed<Vector3<S>, R>> for Matrix4<S> {
|
||||
fn from(dec: Decomposed<Vector3<S>, R>) -> Matrix4<S> {
|
||||
let m: Matrix3<_> = dec.rot.into();
|
||||
let mut m: Matrix4<_> = (&m * dec.scale).into();
|
||||
|
@ -159,9 +185,13 @@ impl<S: BaseFloat, R: Rotation3<S>> From<Decomposed<Vector3<S>, R>> for Matrix4<
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: BaseFloat, R: Rotation2<S>> Transform2<S> for Decomposed<Vector2<S>, R> {}
|
||||
impl<S: BaseFloat, R: Rotation2<Scalar = S>> Transform2 for Decomposed<Vector2<S>, R> {
|
||||
type Scalar = S;
|
||||
}
|
||||
|
||||
impl<S: BaseFloat, R: Rotation3<S>> Transform3<S> for Decomposed<Vector3<S>, R> {}
|
||||
impl<S: BaseFloat, R: Rotation3<Scalar = S>> Transform3 for Decomposed<Vector3<S>, R> {
|
||||
type Scalar = S;
|
||||
}
|
||||
|
||||
impl<S: VectorSpace, R, E: BaseFloat> approx::AbsDiffEq for Decomposed<S, R>
|
||||
where
|
||||
|
|
|
@ -20,11 +20,11 @@ use cgmath::*;
|
|||
mod rotation {
|
||||
use super::cgmath::*;
|
||||
|
||||
pub fn a2<R: Rotation2<f64>>() -> R {
|
||||
pub fn a2<R: Rotation2<Scalar = f64>>() -> R {
|
||||
Rotation2::from_angle(Deg(30.0))
|
||||
}
|
||||
|
||||
pub fn a3<R: Rotation3<f64>>() -> R {
|
||||
pub fn a3<R: Rotation3<Scalar = f64>>() -> R {
|
||||
let axis = Vector3::new(1.0, 1.0, 0.0).normalize();
|
||||
Rotation3::from_axis_angle(axis, Deg(30.0))
|
||||
}
|
||||
|
|
|
@ -21,6 +21,43 @@ extern crate serde_json;
|
|||
|
||||
use cgmath::*;
|
||||
|
||||
#[test]
|
||||
fn test_mul() {
|
||||
let t1 = Decomposed {
|
||||
scale: 2.0f64,
|
||||
rot: Quaternion::new(0.5f64.sqrt(), 0.5f64.sqrt(), 0.0, 0.0),
|
||||
disp: Vector3::new(1.0f64, 2.0, 3.0),
|
||||
};
|
||||
let t2 = Decomposed {
|
||||
scale: 3.0f64,
|
||||
rot: Quaternion::new(0.5f64.sqrt(), 0.0, 0.5f64.sqrt(), 0.0),
|
||||
disp: Vector3::new(-2.0, 1.0, 0.0),
|
||||
};
|
||||
|
||||
let actual = t1 * t2;
|
||||
|
||||
let expected = Decomposed {
|
||||
scale: 6.0f64,
|
||||
rot: Quaternion::new(0.5, 0.5, 0.5, 0.5),
|
||||
disp: Vector3::new(-3.0, 2.0, 5.0),
|
||||
};
|
||||
|
||||
assert_ulps_eq!(actual, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mul_one() {
|
||||
let t = Decomposed {
|
||||
scale: 2.0f64,
|
||||
rot: Quaternion::new(0.5f64.sqrt(), 0.5f64.sqrt(), 0.0, 0.0),
|
||||
disp: Vector3::new(1.0f64, 2.0, 3.0),
|
||||
};
|
||||
let one = Decomposed::one();
|
||||
|
||||
assert_ulps_eq!(t * one, t);
|
||||
assert_ulps_eq!(one * t, t);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invert() {
|
||||
let v = Vector3::new(1.0f64, 2.0, 3.0);
|
||||
|
|
Loading…
Reference in a new issue