Skip to content

Commit 339c99a

Browse files
committed
Add tests for Matrix2D and Matrix4D.
1 parent eac3c43 commit 339c99a

File tree

3 files changed

+231
-2
lines changed

3 files changed

+231
-2
lines changed

src/matrix2d.rs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use std::ops::{Add, Mul, Div, Sub};
1616
use std::marker::PhantomData;
1717
use approxeq::ApproxEq;
1818
use trig::Trig;
19+
use std::fmt;
1920

2021
define_matrix! {
2122
/// A 2d transform stored as a 2 by 3 matrix in row-major order in memory,
@@ -293,12 +294,77 @@ impl<T: ApproxEq<T>, Src, Dst> TypedMatrix2D<T, Src, Dst> {
293294
}
294295
}
295296

297+
impl<T: Copy + fmt::Debug, Src, Dst> fmt::Debug for TypedMatrix2D<T, Src, Dst> {
298+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
299+
self.to_row_major_array().fmt(f)
300+
}
301+
}
302+
296303
#[cfg(test)]
297304
mod test {
298305
use super::*;
306+
use approxeq::ApproxEq;
307+
use point::Point2D;
308+
use Radians;
309+
310+
use std::f32::consts::FRAC_PI_2;
299311

300312
type Mat = Matrix2D<f32>;
301313

314+
fn rad(v: f32) -> Radians<f32> { Radians::new(v) }
315+
316+
#[test]
317+
pub fn test_translation() {
318+
let t1 = Mat::create_translation(1.0, 2.0);
319+
let t2 = Mat::identity().pre_translated(1.0, 2.0);
320+
let t3 = Mat::identity().post_translated(1.0, 2.0);
321+
assert_eq!(t1, t2);
322+
assert_eq!(t1, t3);
323+
324+
assert_eq!(t1.transform_point(&Point2D::new(1.0, 1.0)), Point2D::new(2.0, 3.0));
325+
326+
assert_eq!(t1.post_mul(&t1), Mat::create_translation(2.0, 4.0));
327+
}
328+
329+
#[test]
330+
pub fn test_rotation() {
331+
let r1 = Mat::create_rotation(rad(FRAC_PI_2));
332+
let r2 = Mat::identity().pre_rotated(rad(FRAC_PI_2));
333+
let r3 = Mat::identity().post_rotated(rad(FRAC_PI_2));
334+
assert_eq!(r1, r2);
335+
assert_eq!(r1, r3);
336+
337+
assert!(r1.transform_point(&Point2D::new(1.0, 2.0)).approx_eq(&Point2D::new(2.0, -1.0)));
338+
339+
assert!(r1.post_mul(&r1).approx_eq(&Mat::create_rotation(rad(FRAC_PI_2*2.0))));
340+
}
341+
342+
#[test]
343+
pub fn test_scale() {
344+
let s1 = Mat::create_scale(2.0, 3.0);
345+
let s2 = Mat::identity().pre_scaled(2.0, 3.0);
346+
let s3 = Mat::identity().post_scaled(2.0, 3.0);
347+
assert_eq!(s1, s2);
348+
assert_eq!(s1, s3);
349+
350+
assert!(s1.transform_point(&Point2D::new(2.0, 2.0)).approx_eq(&Point2D::new(4.0, 6.0)));
351+
}
352+
353+
#[test]
354+
fn test_column_major() {
355+
assert_eq!(
356+
Mat::row_major(
357+
1.0, 2.0,
358+
3.0, 4.0,
359+
5.0, 6.0
360+
),
361+
Mat::column_major(
362+
1.0, 3.0, 5.0,
363+
2.0, 4.0, 6.0,
364+
)
365+
);
366+
}
367+
302368
#[test]
303369
pub fn test_inverse_simple() {
304370
let m1 = Mat::identity();
@@ -320,10 +386,36 @@ mod test {
320386
assert!(m1.pre_mul(&m2).approx_eq(&Mat::identity()));
321387
}
322388

389+
#[test]
390+
fn test_inverse_none() {
391+
assert!(Mat::create_scale(2.0, 0.0).inverse().is_none());
392+
assert!(Mat::create_scale(2.0, 2.0).inverse().is_some());
393+
}
394+
323395
#[test]
324396
pub fn test_pre_post() {
325397
let m1 = Matrix2D::identity().post_scaled(1.0, 2.0).post_translated(1.0, 2.0);
326398
let m2 = Matrix2D::identity().pre_translated(1.0, 2.0).pre_scaled(1.0, 2.0);
327399
assert!(m1.approx_eq(&m2));
400+
401+
let r = Mat::create_rotation(rad(FRAC_PI_2));
402+
let t = Mat::create_translation(2.0, 3.0);
403+
404+
let a = Point2D::new(1.0, 1.0);
405+
406+
assert!(r.post_mul(&t).transform_point(&a).approx_eq(&Point2D::new(3.0, 2.0)));
407+
assert!(t.post_mul(&r).transform_point(&a).approx_eq(&Point2D::new(4.0, -3.0)));
408+
assert!(t.post_mul(&r).transform_point(&a).approx_eq(&r.transform_point(&t.transform_point(&a))));
409+
410+
assert!(r.pre_mul(&t).transform_point(&a).approx_eq(&Point2D::new(4.0, -3.0)));
411+
assert!(t.pre_mul(&r).transform_point(&a).approx_eq(&Point2D::new(3.0, 2.0)));
412+
assert!(t.pre_mul(&r).transform_point(&a).approx_eq(&t.transform_point(&r.transform_point(&a))));
413+
}
414+
415+
#[test]
416+
fn test_size_of() {
417+
use std::mem::size_of;
418+
assert_eq!(size_of::<Matrix2D<f32>>(), 6*size_of::<f32>());
419+
assert_eq!(size_of::<Matrix2D<f64>>(), 6*size_of::<f64>());
328420
}
329421
}

src/matrix4d.rs

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -553,15 +553,70 @@ impl<T: Copy + fmt::Debug, Src, Dst> fmt::Debug for TypedMatrix4D<T, Src, Dst> {
553553

554554
#[cfg(test)]
555555
mod tests {
556-
use point::Point2D;
556+
use point::{Point2D, Point3D};
557+
use matrix2d::Matrix2D;
557558
use Radians;
558559
use super::*;
560+
use approxeq::ApproxEq;
561+
562+
use std::f32::consts::FRAC_PI_2;
559563

560564
type Mf32 = Matrix4D<f32>;
561565

562566
// For convenience.
563567
fn rad(v: f32) -> Radians<f32> { Radians::new(v) }
564568

569+
#[test]
570+
pub fn test_translation() {
571+
let t1 = Mf32::create_translation(1.0, 2.0, 3.0);
572+
let t2 = Mf32::identity().pre_translated(1.0, 2.0, 3.0);
573+
let t3 = Mf32::identity().post_translated(1.0, 2.0, 3.0);
574+
assert_eq!(t1, t2);
575+
assert_eq!(t1, t3);
576+
577+
assert_eq!(t1.transform_point3d(&Point3D::new(1.0, 1.0, 1.0)), Point3D::new(2.0, 3.0, 4.0));
578+
assert_eq!(t1.transform_point(&Point2D::new(1.0, 1.0)), Point2D::new(2.0, 3.0));
579+
580+
assert_eq!(t1.post_mul(&t1), Mf32::create_translation(2.0, 4.0, 6.0));
581+
582+
assert!(!t1.is_2d());
583+
assert_eq!(Mf32::create_translation(1.0, 2.0, 3.0).to_2d(), Matrix2D::create_translation(1.0, 2.0));
584+
}
585+
586+
#[test]
587+
pub fn test_rotation() {
588+
let r1 = Mf32::create_rotation(0.0, 0.0, 1.0, rad(FRAC_PI_2));
589+
let r2 = Mf32::identity().pre_rotated(0.0, 0.0, 1.0, rad(FRAC_PI_2));
590+
let r3 = Mf32::identity().post_rotated(0.0, 0.0, 1.0, rad(FRAC_PI_2));
591+
assert_eq!(r1, r2);
592+
assert_eq!(r1, r3);
593+
594+
assert!(r1.transform_point3d(&Point3D::new(1.0, 2.0, 3.0)).approx_eq(&Point3D::new(2.0, -1.0, 3.0)));
595+
assert!(r1.transform_point(&Point2D::new(1.0, 2.0)).approx_eq(&Point2D::new(2.0, -1.0)));
596+
597+
assert!(r1.post_mul(&r1).approx_eq(&Mf32::create_rotation(0.0, 0.0, 1.0, rad(FRAC_PI_2*2.0))));
598+
599+
assert!(r1.is_2d());
600+
assert!(r1.to_2d().approx_eq(&Matrix2D::create_rotation(rad(FRAC_PI_2))));
601+
}
602+
603+
#[test]
604+
pub fn test_scale() {
605+
let s1 = Mf32::create_scale(2.0, 3.0, 4.0);
606+
let s2 = Mf32::identity().pre_scaled(2.0, 3.0, 4.0);
607+
let s3 = Mf32::identity().post_scaled(2.0, 3.0, 4.0);
608+
assert_eq!(s1, s2);
609+
assert_eq!(s1, s3);
610+
611+
assert!(s1.transform_point3d(&Point3D::new(2.0, 2.0, 2.0)).approx_eq(&Point3D::new(4.0, 6.0, 8.0)));
612+
assert!(s1.transform_point(&Point2D::new(2.0, 2.0)).approx_eq(&Point2D::new(4.0, 6.0)));
613+
614+
assert_eq!(s1.post_mul(&s1), Mf32::create_scale(4.0, 9.0, 16.0));
615+
616+
assert!(!s1.is_2d());
617+
assert_eq!(Mf32::create_scale(2.0, 3.0, 0.0).to_2d(), Matrix2D::create_scale(2.0, 3.0));
618+
}
619+
565620
#[test]
566621
pub fn test_ortho() {
567622
let (left, right, bottom, top) = (0.0f32, 1.0f32, 0.1f32, 1.0f32);
@@ -596,6 +651,24 @@ mod tests {
596651
assert_eq!(m1, m2);
597652
}
598653

654+
#[test]
655+
fn test_column_major() {
656+
assert_eq!(
657+
Mf32::row_major(
658+
1.0, 2.0, 3.0, 4.0,
659+
5.0, 6.0, 7.0, 8.0,
660+
9.0, 10.0, 11.0, 12.0,
661+
13.0, 14.0, 15.0, 16.0,
662+
),
663+
Mf32::column_major(
664+
1.0, 5.0, 9.0, 13.0,
665+
2.0, 6.0, 10.0, 14.0,
666+
3.0, 7.0, 11.0, 15.0,
667+
4.0, 8.0, 12.0, 16.0,
668+
)
669+
);
670+
}
671+
599672
#[test]
600673
pub fn test_inverse_simple() {
601674
let m1 = Mf32::identity();
@@ -638,10 +711,36 @@ mod tests {
638711
assert!(p3.eq(&p1));
639712
}
640713

714+
#[test]
715+
fn test_inverse_none() {
716+
assert!(Mf32::create_scale(2.0, 0.0, 2.0).inverse().is_none());
717+
assert!(Mf32::create_scale(2.0, 2.0, 2.0).inverse().is_some());
718+
}
719+
641720
#[test]
642721
pub fn test_pre_post() {
643722
let m1 = Matrix4D::identity().post_scaled(1.0, 2.0, 3.0).post_translated(1.0, 2.0, 3.0);
644723
let m2 = Matrix4D::identity().pre_translated(1.0, 2.0, 3.0).pre_scaled(1.0, 2.0, 3.0);
645724
assert!(m1.approx_eq(&m2));
725+
726+
let r = Mf32::create_rotation(0.0, 0.0, 1.0, rad(FRAC_PI_2));
727+
let t = Mf32::create_translation(2.0, 3.0, 0.0);
728+
729+
let a = Point3D::new(1.0, 1.0, 1.0);
730+
731+
assert!(r.post_mul(&t).transform_point3d(&a).approx_eq(&Point3D::new(3.0, 2.0, 1.0)));
732+
assert!(t.post_mul(&r).transform_point3d(&a).approx_eq(&Point3D::new(4.0, -3.0, 1.0)));
733+
assert!(t.post_mul(&r).transform_point3d(&a).approx_eq(&r.transform_point3d(&t.transform_point3d(&a))));
734+
735+
assert!(r.pre_mul(&t).transform_point3d(&a).approx_eq(&Point3D::new(4.0, -3.0, 1.0)));
736+
assert!(t.pre_mul(&r).transform_point3d(&a).approx_eq(&Point3D::new(3.0, 2.0, 1.0)));
737+
assert!(t.pre_mul(&r).transform_point3d(&a).approx_eq(&t.transform_point3d(&r.transform_point3d(&a))));
738+
}
739+
740+
#[test]
741+
fn test_size_of() {
742+
use std::mem::size_of;
743+
assert_eq!(size_of::<Matrix4D<f32>>(), 16*size_of::<f32>());
744+
assert_eq!(size_of::<Matrix4D<f64>>(), 16*size_of::<f64>());
646745
}
647746
}

src/point.rs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use length::Length;
1212
use scale_factor::ScaleFactor;
1313
use size::TypedSize2D;
1414
use num::*;
15-
15+
use approxeq::ApproxEq;
1616
use num_traits::{Float, NumCast};
1717
use std::fmt;
1818
use std::ops::{Add, Neg, Mul, Sub, Div};
@@ -261,6 +261,23 @@ impl<T: NumCast + Copy, U> TypedPoint2D<T, U> {
261261
}
262262
}
263263

264+
impl<T: Copy+ApproxEq<T>, U> ApproxEq<TypedPoint2D<T, U>> for TypedPoint2D<T, U> {
265+
#[inline]
266+
fn approx_epsilon() -> Self {
267+
TypedPoint2D::new(T::approx_epsilon(), T::approx_epsilon())
268+
}
269+
270+
#[inline]
271+
fn approx_eq(&self, other: &Self) -> bool {
272+
self.x.approx_eq(&other.x) && self.y.approx_eq(&other.y)
273+
}
274+
275+
#[inline]
276+
fn approx_eq_eps(&self, other: &Self, eps: &Self) -> bool {
277+
self.x.approx_eq_eps(&other.x, &eps.x) && self.y.approx_eq_eps(&other.y, &eps.y)
278+
}
279+
}
280+
264281
define_matrix! {
265282
/// A 3d Point tagged with a unit.
266283
#[derive(RustcDecodable, RustcEncodable)]
@@ -475,6 +492,27 @@ impl<T: NumCast + Copy, U> TypedPoint3D<T, U> {
475492
}
476493
}
477494

495+
impl<T: Copy+ApproxEq<T>, U> ApproxEq<TypedPoint3D<T, U>> for TypedPoint3D<T, U> {
496+
#[inline]
497+
fn approx_epsilon() -> Self {
498+
TypedPoint3D::new(T::approx_epsilon(), T::approx_epsilon(), T::approx_epsilon())
499+
}
500+
501+
#[inline]
502+
fn approx_eq(&self, other: &Self) -> bool {
503+
self.x.approx_eq(&other.x)
504+
&& self.y.approx_eq(&other.y)
505+
&& self.z.approx_eq(&other.z)
506+
}
507+
508+
#[inline]
509+
fn approx_eq_eps(&self, other: &Self, eps: &Self) -> bool {
510+
self.x.approx_eq_eps(&other.x, &eps.x)
511+
&& self.y.approx_eq_eps(&other.y, &eps.y)
512+
&& self.z.approx_eq_eps(&other.z, &eps.z)
513+
}
514+
}
515+
478516
define_matrix! {
479517
/// A 4d Point tagged with a unit.
480518
#[derive(RustcDecodable, RustcEncodable)]

0 commit comments

Comments
 (0)