///|
/// Cylinder geometry aligned along the Y-axis.
pub(all) struct Cylinder {
center : Vec3
radius : Double
height : Double
material : Material
} derive(Debug)
pub fn Cylinder::new(center~ : Vec3, radius~ : Double, height~ : Double, material~ : Material) -> Cylinder {
{ center, radius, height, material }
}
pub fn Cylinder::hit_cylinder(self : Cylinder, r : Ray, t_min~ : Double, t_max~ : Double) -> HitRecord? {
let half_h = self.height / 2.0
let y_min = self.center.y - half_h
let y_max = self.center.y + half_h
let a = r.dir.x * r.dir.x + r.dir.z * r.dir.z
if a.abs() < 1.0e-8 {
return None
}
let oc = { x: r.orig.x - self.center.x, y: 0.0, z: r.orig.z - self.center.z }
let half_b = r.dir.x * oc.x + r.dir.z * oc.z
let c = oc.x * oc.x + oc.z * oc.z - self.radius * self.radius
let discriminant = half_b * half_b - a * c
if discriminant < 0.0 {
return None
}
let sqrtd = discriminant.sqrt()
let mut t = (-half_b - sqrtd) / a
let mut y_at_t = r.orig.y + t * r.dir.y
let mut hit = false
if t >= t_min && t <= t_max && y_at_t >= y_min && y_at_t <= y_max {
hit = true
} else {
t = (-half_b + sqrtd) / a
y_at_t = r.orig.y + t * r.dir.y
if t >= t_min && t <= t_max && y_at_t >= y_min && y_at_t <= y_max {
hit = true
}
}
if !hit {
return None
}
let p = r.at(t)
let outward_normal = { x: (p.x - self.center.x) / self.radius, y: 0.0, z: (p.z - self.center.z) / self.radius }
let rec = { p, normal: outward_normal, t, front_face: false, material: self.material }
Some(rec.set_face_normal(r, outward_normal))
}