added new_nonuniform_scaling_wrt_point to Matrix3 & Matrix4

This commit is contained in:
Adam Nemecek 2020-07-02 10:16:18 -07:00
parent 6cd0007354
commit 4653f772bd
3 changed files with 84 additions and 2 deletions

View File

@ -11,11 +11,11 @@ use crate::base::allocator::Allocator;
use crate::base::dimension::{DimName, DimNameDiff, DimNameSub, U1}; use crate::base::dimension::{DimName, DimNameDiff, DimNameSub, U1};
use crate::base::storage::{Storage, StorageMut}; use crate::base::storage::{Storage, StorageMut};
use crate::base::{ use crate::base::{
DefaultAllocator, Matrix3, Matrix4, MatrixN, Scalar, SquareMatrix, Unit, Vector, Vector3, DefaultAllocator, Matrix3, Matrix4, MatrixN, Scalar, SquareMatrix, Unit, Vector, Vector2, Vector3,
VectorN, VectorN,
}; };
use crate::geometry::{ use crate::geometry::{
Isometry, IsometryMatrix3, Orthographic3, Perspective3, Point, Point3, Rotation2, Rotation3, Isometry, IsometryMatrix3, Orthographic3, Perspective3, Point, Point2, Point3, Rotation2, Rotation3, Translation2, Translation3,
}; };
use simba::scalar::{ClosedAdd, ClosedMul, RealField}; use simba::scalar::{ClosedAdd, ClosedMul, RealField};
@ -70,6 +70,17 @@ impl<N: RealField> Matrix3<N> {
pub fn new_rotation(angle: N) -> Self { pub fn new_rotation(angle: N) -> Self {
Rotation2::new(angle).to_homogeneous() Rotation2::new(angle).to_homogeneous()
} }
/// Creates a new homogeneous matrix that applies a scaling factor for each dimension with respect to point.
///
/// Can be used to implement "zoom_to" functionality.
#[inline]
pub fn new_nonuniform_scaling_wrt_point(scaling: Vector2<N>, pt: Point2<N>) -> Self {
let translate = Translation2::new(pt.x, pt.y).to_homogeneous();
let scale = Matrix3::new_nonuniform_scaling(&scaling);
let translate_inv = Translation2::new(-pt.x, -pt.y).to_homogeneous();
translate * scale * translate_inv
}
} }
impl<N: RealField> Matrix4<N> { impl<N: RealField> Matrix4<N> {
@ -90,6 +101,17 @@ impl<N: RealField> Matrix4<N> {
Isometry::rotation_wrt_point(rot, pt).to_homogeneous() Isometry::rotation_wrt_point(rot, pt).to_homogeneous()
} }
/// Creates a new homogeneous matrix that applies a scaling factor for each dimension with respect to point.
///
/// Can be used to implement "zoom_to" functionality.
#[inline]
pub fn new_nonuniform_scaling_wrt_point(scaling: Vector3<N>, pt: Point3<N>) -> Self {
let translate = Translation3::new(pt.x, pt.y, pt.z).to_homogeneous();
let scale = Matrix4::new_nonuniform_scaling(&scaling);
let translate_inv = Translation3::new(-pt.x, -pt.y, -pt.z).to_homogeneous();
translate * scale * translate_inv
}
/// Builds a 3D homogeneous rotation matrix from an axis and an angle (multiplied together). /// Builds a 3D homogeneous rotation matrix from an axis and an angle (multiplied together).
/// ///
/// Returns the identity matrix if the given argument is zero. /// Returns the identity matrix if the given argument is zero.

59
tests/core/cg.rs Normal file
View File

@ -0,0 +1,59 @@
use na::{Vector2, Vector3, Matrix3, Matrix4, Point2, Point3};
/// See Example 3.4 of "Graphics and Visualization: Principles & Algorithms"
/// by Theoharis, Papaioannou, Platis, Patrikalakis.
#[test]
fn test_scaling_wrt_point_1() {
let a = Point2::new(0.0, 0.0);
let b = Point2::new(1.0, 1.0);
let c = Point2::new(5.0, 2.0);
let scaling = Vector2::new(2.0, 2.0);
let scale_about = Matrix3::new_nonuniform_scaling_wrt_point(scaling, c);
let expected_a = Point2::new(-5.0, -2.0);
let expected_b = Point2::new(-3.0, 0.0);
let result_a = scale_about.transform_point(&a);
let result_b = scale_about.transform_point(&b);
let result_c = scale_about.transform_point(&c);
assert!(expected_a == result_a);
assert!(expected_b == result_b);
assert!(c == result_c);
}
/// Based on the same example as the test above.
#[test]
fn test_scaling_wrt_point_2() {
let a = Point3::new(0.0, 0.0, 1.0);
let b = Point3::new(1.0, 1.0, 1.0);
let c = Point3::new(5.0, 2.0, 1.0);
let scaling = Vector3::new(2.0, 2.0, 1.0);
let scale_about = Matrix4::new_nonuniform_scaling_wrt_point(scaling, c);
let expected_a = Point3::new(-5.0, -2.0, 1.0);
let expected_b = Point3::new(-3.0, 0.0, 1.0);
let result_a = scale_about.transform_point(&a);
let result_b = scale_about.transform_point(&b);
let result_c = scale_about.transform_point(&c);
assert!(expected_a == result_a);
assert!(expected_b == result_b);
assert!(c == result_c);
}
/// Based on https://github.com/emlowry/AiE/blob/50bae4068edb686cf8ffacdf6fab8e7cb22e7eb1/Year%201%20Classwork/MathTest/Matrix4x4TestGroup.cpp#L145
#[test]
fn test_scaling_wrt_point_3() {
let about = Point3::new(2.0, 1.0, -2.0);
let scale = Vector3::new(2.0, 0.5, -1.0);
let pt = Point3::new(1.0, 2.0, 3.0);
let scale_about = Matrix4::new_nonuniform_scaling_wrt_point(scale, about);
let expected = Point3::new(0.0, 1.5, -7.0);
let result = scale_about.transform_point(&pt);
assert!(result == expected);
}

View File

@ -1,6 +1,7 @@
#[cfg(feature = "abomonation-serialize")] #[cfg(feature = "abomonation-serialize")]
mod abomonation; mod abomonation;
mod blas; mod blas;
mod cg;
mod conversion; mod conversion;
mod edition; mod edition;
mod empty; mod empty;