Add Transform trait and implement for Sphere
This commit is contained in:
parent
fa43552c6f
commit
b13cbe316d
|
|
@ -1,4 +1,4 @@
|
|||
use nalgebra::{Point3, Vector3};
|
||||
use nalgebra::{Point3, Transform3, Vector3};
|
||||
|
||||
use super::materials::Material;
|
||||
use crate::Real;
|
||||
|
|
@ -68,6 +68,10 @@ pub trait HasBoundingBox<T: Real>: Send + Sync {
|
|||
fn bounding_box(&self) -> BoundingBox<T>;
|
||||
}
|
||||
|
||||
pub trait Transform<T: Real>: Send + Sync {
|
||||
fn transform(&mut self, transformation: &Transform3<T>) -> &Self;
|
||||
}
|
||||
|
||||
pub trait Primitive<T: Real>: Intersect<T> + HasBoundingBox<T> {}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
use nalgebra::{convert, Point3, Vector3};
|
||||
use nalgebra::{convert, Point3, Transform3, Vector3};
|
||||
|
||||
use crate::materials::Material;
|
||||
use crate::Real;
|
||||
|
||||
use super::{BoundingBox, HasBoundingBox, Intersect, IntersectionInfo, Primitive, Ray};
|
||||
use super::{BoundingBox, HasBoundingBox, Intersect, IntersectionInfo, Primitive, Ray, Transform};
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
|
|
@ -24,6 +24,18 @@ impl<T: Real> Sphere<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Real> Transform<T> for Sphere<T> {
|
||||
fn transform(&mut self, transformation: &Transform3<T>) -> &Self {
|
||||
self.centre = transformation.transform_point(&self.centre);
|
||||
// This is not the most efficient way of calculating the radius,
|
||||
//but will work as long as the resulting shape is still a sphere.
|
||||
self.radius = transformation
|
||||
.transform_vector(&Vector3::new(self.radius, T::zero(), T::zero()))
|
||||
.norm();
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Real> Intersect<T> for Sphere<T> {
|
||||
fn intersect<'a>(&'a self, ray: &Ray<T>) -> Option<IntersectionInfo<T>> {
|
||||
let two: T = convert(2.0);
|
||||
|
|
@ -93,6 +105,8 @@ mod tests {
|
|||
use quickcheck::TestResult;
|
||||
use quickcheck_macros::quickcheck;
|
||||
|
||||
use nalgebra::{Rotation3, Translation3};
|
||||
|
||||
use super::*;
|
||||
use crate::materials::LambertianMaterial;
|
||||
|
||||
|
|
@ -183,4 +197,69 @@ mod tests {
|
|||
let bounding_box = target_sphere.bounding_box();
|
||||
bounding_box.contains_point(sphere_centre + radius_vector)
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn translation_moves_centre(
|
||||
sphere_centre: Point3<f64>,
|
||||
radius: f64,
|
||||
translation_vector: Vector3<f64>,
|
||||
) -> TestResult {
|
||||
if radius <= 0.0 {
|
||||
return TestResult::discard();
|
||||
};
|
||||
let mut sphere = Sphere::new(
|
||||
sphere_centre,
|
||||
radius,
|
||||
Arc::new(LambertianMaterial::new_dummy()),
|
||||
);
|
||||
let expected_centre = sphere.centre + translation_vector;
|
||||
let mut transformation = Transform3::identity();
|
||||
transformation *= Translation3::from(translation_vector);
|
||||
sphere.transform(&transformation);
|
||||
TestResult::from_bool(expected_centre == sphere.centre)
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn translation_does_not_change_radius(
|
||||
sphere_centre: Point3<f64>,
|
||||
radius: f64,
|
||||
translation_vector: Vector3<f64>,
|
||||
) -> TestResult {
|
||||
if radius <= 0.0 {
|
||||
return TestResult::discard();
|
||||
};
|
||||
let mut sphere = Sphere::new(
|
||||
sphere_centre,
|
||||
radius,
|
||||
Arc::new(LambertianMaterial::new_dummy()),
|
||||
);
|
||||
let expected_radius = sphere.radius;
|
||||
let mut transformation = Transform3::identity();
|
||||
transformation *= Translation3::from(translation_vector);
|
||||
sphere.transform(&transformation);
|
||||
TestResult::from_bool(expected_radius == sphere.radius)
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn rotation_about_centre_does_not_move_centre(
|
||||
sphere_centre: Point3<f64>,
|
||||
radius: f64,
|
||||
rotation_vector: Vector3<f64>,
|
||||
) -> TestResult {
|
||||
if radius <= 0.0 {
|
||||
return TestResult::discard();
|
||||
};
|
||||
let mut sphere = Sphere::new(
|
||||
sphere_centre,
|
||||
radius,
|
||||
Arc::new(LambertianMaterial::new_dummy()),
|
||||
);
|
||||
let expected_centre = sphere.centre;
|
||||
let mut transformation = Transform3::identity();
|
||||
transformation *= Translation3::from(sphere.centre.coords)
|
||||
* Rotation3::new(rotation_vector)
|
||||
* Translation3::from(-sphere.centre.coords);
|
||||
sphere.transform(&transformation);
|
||||
TestResult::from_bool(dbg!((expected_centre - sphere.centre).norm() < 0.000000001))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue