Skip to content

Commit 84da664

Browse files
authored
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
1 parent 816c043 commit 84da664

File tree

6 files changed

+152
-58
lines changed

6 files changed

+152
-58
lines changed

src/matrix.rs

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1038,10 +1038,6 @@ impl<S: BaseFloat> approx::UlpsEq for Matrix4<S> {
10381038
}
10391039

10401040
impl<S: BaseFloat> Transform<Point2<S>> for Matrix3<S> {
1041-
fn one() -> Matrix3<S> {
1042-
One::one()
1043-
}
1044-
10451041
fn look_at(eye: Point2<S>, center: Point2<S>, up: Vector2<S>) -> Matrix3<S> {
10461042
let dir = center - eye;
10471043
Matrix3::from(Matrix2::look_at(dir, up))
@@ -1065,10 +1061,6 @@ impl<S: BaseFloat> Transform<Point2<S>> for Matrix3<S> {
10651061
}
10661062

10671063
impl<S: BaseFloat> Transform<Point3<S>> for Matrix3<S> {
1068-
fn one() -> Matrix3<S> {
1069-
One::one()
1070-
}
1071-
10721064
fn look_at(eye: Point3<S>, center: Point3<S>, up: Vector3<S>) -> Matrix3<S> {
10731065
let dir = center - eye;
10741066
Matrix3::look_at(dir, up)
@@ -1092,10 +1084,6 @@ impl<S: BaseFloat> Transform<Point3<S>> for Matrix3<S> {
10921084
}
10931085

10941086
impl<S: BaseFloat> Transform<Point3<S>> for Matrix4<S> {
1095-
fn one() -> Matrix4<S> {
1096-
One::one()
1097-
}
1098-
10991087
fn look_at(eye: Point3<S>, center: Point3<S>, up: Vector3<S>) -> Matrix4<S> {
11001088
Matrix4::look_at(eye, center, up)
11011089
}
@@ -1117,11 +1105,17 @@ impl<S: BaseFloat> Transform<Point3<S>> for Matrix4<S> {
11171105
}
11181106
}
11191107

1120-
impl<S: BaseFloat> Transform2<S> for Matrix3<S> {}
1108+
impl<S: BaseFloat> Transform2 for Matrix3<S> {
1109+
type Scalar = S;
1110+
}
11211111

1122-
impl<S: BaseFloat> Transform3<S> for Matrix3<S> {}
1112+
impl<S: BaseFloat> Transform3 for Matrix3<S> {
1113+
type Scalar = S;
1114+
}
11231115

1124-
impl<S: BaseFloat> Transform3<S> for Matrix4<S> {}
1116+
impl<S: BaseFloat> Transform3 for Matrix4<S> {
1117+
type Scalar = S;
1118+
}
11251119

11261120
macro_rules! impl_matrix {
11271121
($MatrixN:ident, $VectorN:ident { $($field:ident : $row_index:expr),+ }) => {

src/quaternion.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,9 @@ impl<S: BaseFloat> From<Quaternion<S>> for Basis3<S> {
480480
}
481481
}
482482

483-
impl<S: BaseFloat> Rotation<Point3<S>> for Quaternion<S> {
483+
impl<S: BaseFloat> Rotation for Quaternion<S> {
484+
type Space = Point3<S>;
485+
484486
#[inline]
485487
fn look_at(dir: Vector3<S>, up: Vector3<S>) -> Quaternion<S> {
486488
Matrix3::look_at(dir, up).into()
@@ -526,7 +528,9 @@ impl<S: BaseFloat> Rotation<Point3<S>> for Quaternion<S> {
526528
}
527529
}
528530

529-
impl<S: BaseFloat> Rotation3<S> for Quaternion<S> {
531+
impl<S: BaseFloat> Rotation3 for Quaternion<S> {
532+
type Scalar = S;
533+
530534
#[inline]
531535
fn from_axis_angle<A: Into<Rad<S>>>(axis: Vector3<S>, angle: A) -> Quaternion<S> {
532536
let (s, c) = Rad::sin_cos(angle.into() * cast(0.5f64).unwrap());

src/rotation.rs

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -30,30 +30,41 @@ use vector::{Vector2, Vector3};
3030

3131
/// A trait for a generic rotation. A rotation is a transformation that
3232
/// creates a circular motion, and preserves at least one point in the space.
33-
pub trait Rotation<P: EuclideanSpace>: Sized + Copy + One
33+
pub trait Rotation: Sized + Copy + One
3434
where
3535
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
36-
Self: approx::AbsDiffEq<Epsilon = P::Scalar>,
37-
Self: approx::RelativeEq<Epsilon = P::Scalar>,
38-
Self: approx::UlpsEq<Epsilon = P::Scalar>,
39-
P::Scalar: BaseFloat,
36+
Self: approx::AbsDiffEq<Epsilon = <<Self as Rotation>::Space as EuclideanSpace>::Scalar>,
37+
Self: approx::RelativeEq<Epsilon = <<Self as Rotation>::Space as EuclideanSpace>::Scalar>,
38+
Self: approx::UlpsEq<Epsilon = <<Self as Rotation>::Space as EuclideanSpace>::Scalar>,
39+
<Self::Space as EuclideanSpace>::Scalar: BaseFloat,
4040
Self: iter::Product<Self>,
4141
{
42+
type Space: EuclideanSpace;
43+
4244
/// Create a rotation to a given direction with an 'up' vector.
43-
fn look_at(dir: P::Diff, up: P::Diff) -> Self;
45+
fn look_at(
46+
dir: <Self::Space as EuclideanSpace>::Diff,
47+
up: <Self::Space as EuclideanSpace>::Diff,
48+
) -> Self;
4449

4550
/// Create a shortest rotation to transform vector 'a' into 'b'.
4651
/// Both given vectors are assumed to have unit length.
47-
fn between_vectors(a: P::Diff, b: P::Diff) -> Self;
52+
fn between_vectors(
53+
a: <Self::Space as EuclideanSpace>::Diff,
54+
b: <Self::Space as EuclideanSpace>::Diff,
55+
) -> Self;
4856

4957
/// Rotate a vector using this rotation.
50-
fn rotate_vector(&self, vec: P::Diff) -> P::Diff;
58+
fn rotate_vector(
59+
&self,
60+
vec: <Self::Space as EuclideanSpace>::Diff,
61+
) -> <Self::Space as EuclideanSpace>::Diff;
5162

5263
/// Rotate a point using this rotation, by converting it to its
5364
/// representation as a vector.
5465
#[inline]
55-
fn rotate_point(&self, point: P) -> P {
56-
P::from_vec(self.rotate_vector(point.to_vec()))
66+
fn rotate_point(&self, point: Self::Space) -> Self::Space {
67+
Self::Space::from_vec(self.rotate_vector(point.to_vec()))
5768
}
5869

5970
/// Create a new rotation which "un-does" this rotation. That is,
@@ -62,38 +73,48 @@ where
6273
}
6374

6475
/// A two-dimensional rotation.
65-
pub trait Rotation2<S: BaseFloat>:
66-
Rotation<Point2<S>> + Into<Matrix2<S>> + Into<Basis2<S>>
76+
pub trait Rotation2:
77+
Rotation<Space = Point2<<Self as Rotation2>::Scalar>>
78+
+ Into<Matrix2<<Self as Rotation2>::Scalar>>
79+
+ Into<Basis2<<Self as Rotation2>::Scalar>>
6780
{
81+
type Scalar: BaseFloat;
82+
6883
/// Create a rotation by a given angle. Thus is a redundant case of both
6984
/// from_axis_angle() and from_euler() for 2D space.
70-
fn from_angle<A: Into<Rad<S>>>(theta: A) -> Self;
85+
fn from_angle<A: Into<Rad<Self::Scalar>>>(theta: A) -> Self;
7186
}
7287

7388
/// A three-dimensional rotation.
74-
pub trait Rotation3<S: BaseFloat>:
75-
Rotation<Point3<S>> + Into<Matrix3<S>> + Into<Basis3<S>> + Into<Quaternion<S>> + From<Euler<Rad<S>>>
89+
pub trait Rotation3:
90+
Rotation<Space = Point3<<Self as Rotation3>::Scalar>>
91+
+ Into<Matrix3<<Self as Rotation3>::Scalar>>
92+
+ Into<Basis3<<Self as Rotation3>::Scalar>>
93+
+ Into<Quaternion<<Self as Rotation3>::Scalar>>
94+
+ From<Euler<Rad<<Self as Rotation3>::Scalar>>>
7695
{
96+
type Scalar: BaseFloat;
97+
7798
/// Create a rotation using an angle around a given axis.
7899
///
79100
/// The specified axis **must be normalized**, or it represents an invalid rotation.
80-
fn from_axis_angle<A: Into<Rad<S>>>(axis: Vector3<S>, angle: A) -> Self;
101+
fn from_axis_angle<A: Into<Rad<Self::Scalar>>>(axis: Vector3<Self::Scalar>, angle: A) -> Self;
81102

82103
/// Create a rotation from an angle around the `x` axis (pitch).
83104
#[inline]
84-
fn from_angle_x<A: Into<Rad<S>>>(theta: A) -> Self {
105+
fn from_angle_x<A: Into<Rad<Self::Scalar>>>(theta: A) -> Self {
85106
Rotation3::from_axis_angle(Vector3::unit_x(), theta)
86107
}
87108

88109
/// Create a rotation from an angle around the `y` axis (yaw).
89110
#[inline]
90-
fn from_angle_y<A: Into<Rad<S>>>(theta: A) -> Self {
111+
fn from_angle_y<A: Into<Rad<Self::Scalar>>>(theta: A) -> Self {
91112
Rotation3::from_axis_angle(Vector3::unit_y(), theta)
92113
}
93114

94115
/// Create a rotation from an angle around the `z` axis (roll).
95116
#[inline]
96-
fn from_angle_z<A: Into<Rad<S>>>(theta: A) -> Self {
117+
fn from_angle_z<A: Into<Rad<Self::Scalar>>>(theta: A) -> Self {
97118
Rotation3::from_axis_angle(Vector3::unit_z(), theta)
98119
}
99120
}
@@ -183,7 +204,9 @@ impl<'a, S: 'a + BaseFloat> iter::Product<&'a Basis2<S>> for Basis2<S> {
183204
}
184205
}
185206

186-
impl<S: BaseFloat> Rotation<Point2<S>> for Basis2<S> {
207+
impl<S: BaseFloat> Rotation for Basis2<S> {
208+
type Space = Point2<S>;
209+
187210
#[inline]
188211
fn look_at(dir: Vector2<S>, up: Vector2<S>) -> Basis2<S> {
189212
Basis2 {
@@ -262,7 +285,9 @@ impl<S: BaseFloat> approx::UlpsEq for Basis2<S> {
262285
}
263286
}
264287

265-
impl<S: BaseFloat> Rotation2<S> for Basis2<S> {
288+
impl<S: BaseFloat> Rotation2 for Basis2<S> {
289+
type Scalar = S;
290+
266291
fn from_angle<A: Into<Rad<S>>>(theta: A) -> Basis2<S> {
267292
Basis2 {
268293
mat: Matrix2::from_angle(theta),
@@ -334,7 +359,9 @@ impl<'a, S: 'a + BaseFloat> iter::Product<&'a Basis3<S>> for Basis3<S> {
334359
}
335360
}
336361

337-
impl<S: BaseFloat> Rotation<Point3<S>> for Basis3<S> {
362+
impl<S: BaseFloat> Rotation for Basis3<S> {
363+
type Space = Point3<S>;
364+
338365
#[inline]
339366
fn look_at(dir: Vector3<S>, up: Vector3<S>) -> Basis3<S> {
340367
Basis3 {
@@ -414,7 +441,9 @@ impl<S: BaseFloat> approx::UlpsEq for Basis3<S> {
414441
}
415442
}
416443

417-
impl<S: BaseFloat> Rotation3<S> for Basis3<S> {
444+
impl<S: BaseFloat> Rotation3 for Basis3<S> {
445+
type Scalar = S;
446+
418447
fn from_axis_angle<A: Into<Rad<S>>>(axis: Vector3<S>, angle: A) -> Basis3<S> {
419448
Basis3 {
420449
mat: Matrix3::from_axis_angle(axis, angle),

src/transform.rs

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,12 @@ use point::{Point2, Point3};
2222
use rotation::*;
2323
use vector::{Vector2, Vector3};
2424

25+
use std::ops::Mul;
26+
2527
/// A trait representing an [affine
2628
/// transformation](https://en.wikipedia.org/wiki/Affine_transformation) that
2729
/// can be applied to points or vectors. An affine transformation is one which
28-
pub trait Transform<P: EuclideanSpace>: Sized {
29-
/// Create an identity transformation. That is, a transformation which
30-
/// does nothing.
31-
fn one() -> Self;
32-
30+
pub trait Transform<P: EuclideanSpace>: Sized + One {
3331
/// Create a transformation that rotates a vector to look at `center` from
3432
/// `eye`, using `up` for orientation.
3533
fn look_at(eye: P, center: P, up: P::Diff) -> Self;
@@ -69,21 +67,41 @@ pub struct Decomposed<V: VectorSpace, R> {
6967
pub disp: V,
7068
}
7169

72-
impl<P: EuclideanSpace, R: Rotation<P>> Transform<P> for Decomposed<P::Diff, R>
70+
impl<P: EuclideanSpace, R: Rotation<Space = P>> One for Decomposed<P::Diff, R>
7371
where
7472
P::Scalar: BaseFloat,
75-
// FIXME: Investigate why this is needed!
76-
P::Diff: VectorSpace,
7773
{
78-
#[inline]
79-
fn one() -> Decomposed<P::Diff, R> {
74+
fn one() -> Self {
8075
Decomposed {
8176
scale: P::Scalar::one(),
8277
rot: R::one(),
8378
disp: P::Diff::zero(),
8479
}
8580
}
81+
}
82+
83+
impl<P: EuclideanSpace, R: Rotation<Space = P>> Mul for Decomposed<P::Diff, R>
84+
where
85+
P::Scalar: BaseFloat,
86+
P::Diff: VectorSpace,
87+
{
88+
type Output = Self;
89+
90+
/// Multiplies the two transforms together.
91+
/// The result should be as if the two transforms were converted
92+
/// to matrices, then multiplied, then converted back with
93+
/// a (currently nonexistent) function that tries to convert
94+
/// a matrix into a `Decomposed`.
95+
fn mul(self, rhs: Decomposed<P::Diff, R>) -> Self::Output {
96+
self.concat(&rhs)
97+
}
98+
}
8699

100+
impl<P: EuclideanSpace, R: Rotation<Space = P>> Transform<P> for Decomposed<P::Diff, R>
101+
where
102+
P::Scalar: BaseFloat,
103+
P::Diff: VectorSpace,
104+
{
87105
#[inline]
88106
fn look_at(eye: P, center: P, up: P::Diff) -> Decomposed<P::Diff, R> {
89107
let rot = R::look_at(center - eye, up);
@@ -138,10 +156,18 @@ where
138156
}
139157
}
140158

141-
pub trait Transform2<S: BaseNum>: Transform<Point2<S>> + Into<Matrix3<S>> {}
142-
pub trait Transform3<S: BaseNum>: Transform<Point3<S>> + Into<Matrix4<S>> {}
159+
pub trait Transform2:
160+
Transform<Point2<<Self as Transform2>::Scalar>> + Into<Matrix3<<Self as Transform2>::Scalar>>
161+
{
162+
type Scalar: BaseNum;
163+
}
164+
pub trait Transform3:
165+
Transform<Point3<<Self as Transform3>::Scalar>> + Into<Matrix4<<Self as Transform3>::Scalar>>
166+
{
167+
type Scalar: BaseNum;
168+
}
143169

144-
impl<S: BaseFloat, R: Rotation2<S>> From<Decomposed<Vector2<S>, R>> for Matrix3<S> {
170+
impl<S: BaseFloat, R: Rotation2<Scalar = S>> From<Decomposed<Vector2<S>, R>> for Matrix3<S> {
145171
fn from(dec: Decomposed<Vector2<S>, R>) -> Matrix3<S> {
146172
let m: Matrix2<_> = dec.rot.into();
147173
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<
150176
}
151177
}
152178

153-
impl<S: BaseFloat, R: Rotation3<S>> From<Decomposed<Vector3<S>, R>> for Matrix4<S> {
179+
impl<S: BaseFloat, R: Rotation3<Scalar = S>> From<Decomposed<Vector3<S>, R>> for Matrix4<S> {
154180
fn from(dec: Decomposed<Vector3<S>, R>) -> Matrix4<S> {
155181
let m: Matrix3<_> = dec.rot.into();
156182
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<
159185
}
160186
}
161187

162-
impl<S: BaseFloat, R: Rotation2<S>> Transform2<S> for Decomposed<Vector2<S>, R> {}
188+
impl<S: BaseFloat, R: Rotation2<Scalar = S>> Transform2 for Decomposed<Vector2<S>, R> {
189+
type Scalar = S;
190+
}
163191

164-
impl<S: BaseFloat, R: Rotation3<S>> Transform3<S> for Decomposed<Vector3<S>, R> {}
192+
impl<S: BaseFloat, R: Rotation3<Scalar = S>> Transform3 for Decomposed<Vector3<S>, R> {
193+
type Scalar = S;
194+
}
165195

166196
impl<S: VectorSpace, R, E: BaseFloat> approx::AbsDiffEq for Decomposed<S, R>
167197
where

tests/rotation.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ use cgmath::*;
2020
mod rotation {
2121
use super::cgmath::*;
2222

23-
pub fn a2<R: Rotation2<f64>>() -> R {
23+
pub fn a2<R: Rotation2<Scalar = f64>>() -> R {
2424
Rotation2::from_angle(Deg(30.0))
2525
}
2626

27-
pub fn a3<R: Rotation3<f64>>() -> R {
27+
pub fn a3<R: Rotation3<Scalar = f64>>() -> R {
2828
let axis = Vector3::new(1.0, 1.0, 0.0).normalize();
2929
Rotation3::from_axis_angle(axis, Deg(30.0))
3030
}

tests/transform.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,43 @@ extern crate serde_json;
2121

2222
use cgmath::*;
2323

24+
#[test]
25+
fn test_mul() {
26+
let t1 = Decomposed {
27+
scale: 2.0f64,
28+
rot: Quaternion::new(0.5f64.sqrt(), 0.5f64.sqrt(), 0.0, 0.0),
29+
disp: Vector3::new(1.0f64, 2.0, 3.0),
30+
};
31+
let t2 = Decomposed {
32+
scale: 3.0f64,
33+
rot: Quaternion::new(0.5f64.sqrt(), 0.0, 0.5f64.sqrt(), 0.0),
34+
disp: Vector3::new(-2.0, 1.0, 0.0),
35+
};
36+
37+
let actual = t1 * t2;
38+
39+
let expected = Decomposed {
40+
scale: 6.0f64,
41+
rot: Quaternion::new(0.5, 0.5, 0.5, 0.5),
42+
disp: Vector3::new(-3.0, 2.0, 5.0),
43+
};
44+
45+
assert_ulps_eq!(actual, expected);
46+
}
47+
48+
#[test]
49+
fn test_mul_one() {
50+
let t = Decomposed {
51+
scale: 2.0f64,
52+
rot: Quaternion::new(0.5f64.sqrt(), 0.5f64.sqrt(), 0.0, 0.0),
53+
disp: Vector3::new(1.0f64, 2.0, 3.0),
54+
};
55+
let one = Decomposed::one();
56+
57+
assert_ulps_eq!(t * one, t);
58+
assert_ulps_eq!(one * t, t);
59+
}
60+
2461
#[test]
2562
fn test_invert() {
2663
let v = Vector3::new(1.0f64, 2.0, 3.0);

0 commit comments

Comments
 (0)