use std::rc::Rc;
use crate::intersection::Intersection;
use crate::material::Material;
use crate::matrix::Matrix;
use crate::ray::Ray;
use crate::tuple::Tuple;
use super::Shape;
#[derive(Default, Clone)]
pub struct Sphere {
transform: Matrix,
transform_inverse: Matrix,
material: Material,
}
impl Sphere {
pub fn new() -> Self {
Self::default()
}
}
impl Shape for Sphere {
fn local_intersect(&self, ray: &Ray) -> Vec<Intersection> {
let oc = ray.origin() - Tuple::point(0.0, 0.0, 0.0);
let a = ray.direction().norm_squared();
let b = ray.direction().dot(oc);
let c = oc.norm_squared() - 1.0;
let d = b * b - a * c;
if d < 0.0 {
return Vec::new();
}
let sqrtd = d.sqrt();
let t1 = (-b - sqrtd) / a;
let t2 = (-b + sqrtd) / a;
vec![
Intersection::new(t1, Rc::new(self.clone())),
Intersection::new(t2, Rc::new(self.clone())),
]
}
fn local_normal_at(&self, point: Tuple) -> Tuple {
(point - Tuple::point(0.0, 0.0, 0.0)).normalized()
}
fn set_transform(&mut self, transform: Matrix) {
self.transform_inverse = transform.inverse();
self.transform = transform;
}
fn transform(&self) -> &Matrix {
&self.transform
}
fn transform_inverse(&self) -> &Matrix {
&self.transform_inverse
}
fn material(&self) -> &Material {
&self.material
}
fn set_material(&mut self, material: Material) {
self.material = material;
}
}