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 super::materials::Material;
|
||||||
use crate::Real;
|
use crate::Real;
|
||||||
|
|
@ -68,6 +68,10 @@ pub trait HasBoundingBox<T: Real>: Send + Sync {
|
||||||
fn bounding_box(&self) -> BoundingBox<T>;
|
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> {}
|
pub trait Primitive<T: Real>: Intersect<T> + HasBoundingBox<T> {}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
use nalgebra::{convert, Point3, Vector3};
|
use nalgebra::{convert, Point3, Transform3, Vector3};
|
||||||
|
|
||||||
use crate::materials::Material;
|
use crate::materials::Material;
|
||||||
use crate::Real;
|
use crate::Real;
|
||||||
|
|
||||||
use super::{BoundingBox, HasBoundingBox, Intersect, IntersectionInfo, Primitive, Ray};
|
use super::{BoundingBox, HasBoundingBox, Intersect, IntersectionInfo, Primitive, Ray, Transform};
|
||||||
|
|
||||||
use std::sync::Arc;
|
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> {
|
impl<T: Real> Intersect<T> for Sphere<T> {
|
||||||
fn intersect<'a>(&'a self, ray: &Ray<T>) -> Option<IntersectionInfo<T>> {
|
fn intersect<'a>(&'a self, ray: &Ray<T>) -> Option<IntersectionInfo<T>> {
|
||||||
let two: T = convert(2.0);
|
let two: T = convert(2.0);
|
||||||
|
|
@ -93,6 +105,8 @@ mod tests {
|
||||||
use quickcheck::TestResult;
|
use quickcheck::TestResult;
|
||||||
use quickcheck_macros::quickcheck;
|
use quickcheck_macros::quickcheck;
|
||||||
|
|
||||||
|
use nalgebra::{Rotation3, Translation3};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::materials::LambertianMaterial;
|
use crate::materials::LambertianMaterial;
|
||||||
|
|
||||||
|
|
@ -183,4 +197,69 @@ mod tests {
|
||||||
let bounding_box = target_sphere.bounding_box();
|
let bounding_box = target_sphere.bounding_box();
|
||||||
bounding_box.contains_point(sphere_centre + radius_vector)
|
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