///|
/// Immutable three-dimensional coordinates. Geometry constructors validate finiteness.
pub struct Vec3 {
x : Double
y : Double
z : Double
} derive(Debug, Eq)
///|
pub fn Vec3::new(x : Double, y : Double, z : Double) -> Vec3 {
{ x, y, z, }
}
///|
pub fn Vec3::origin() -> Vec3 {
{ x: 0.0, y: 0.0, z: 0.0, }
}
///|
pub(all) suberror GeometryError {
NonFinite(String)
InvertedBounds
InvalidRoot
ZeroDirection
InvalidInterval
} derive(Debug, Eq)
///|
fn finite(x : Double) -> Bool {
x >= -@double.max_value && x <= @double.max_value
}
///|
fn Vec3::finite(self : Vec3) -> Bool {
finite(self.x) && finite(self.y) && finite(self.z)
}
///|
/// Validated, closed AABB. Touching counts as intersection; zero extent is legal.
pub struct Aabb {
min : Vec3
max : Vec3
} derive(Debug, Eq)
///|
pub fn Aabb::new(min : Vec3, max : Vec3) -> Aabb raise GeometryError {
guard min.finite() && max.finite() else { raise NonFinite("aabb") }
guard min.x <= max.x && min.y <= max.y && min.z <= max.z else {
raise InvertedBounds
}
{ min, max, }
}
///|
/// A fixed root specified by center and positive half extent.
pub struct Cube {
center : Vec3
half_extent : Double
bounds : Aabb
} derive(Debug, Eq)
///|
pub fn Cube::new(
center : Vec3,
half_extent : Double,
) -> Cube raise GeometryError {
guard center.finite() && finite(half_extent) && half_extent > 0.0 else {
raise InvalidRoot
}
let lo = Vec3::new(
center.x - half_extent,
center.y - half_extent,
center.z - half_extent,
)
let hi = Vec3::new(
center.x + half_extent,
center.y + half_extent,
center.z + half_extent,
)
guard lo.finite() && hi.finite() && lo.x < hi.x && lo.y < hi.y && lo.z < hi.z else {
raise InvalidRoot
}
{ center, half_extent, bounds: { min: lo, max: hi, }, }
}
///|
/// Ray positions are origin + t * direction, for the finite closed parameter interval.
/// Direction need not be normalized; only a unit direction makes t a distance.
pub struct Ray {
origin : Vec3
direction : Vec3
t_min : Double
t_max : Double
} derive(Debug, Eq)
///|
pub fn Ray::new(
origin : Vec3,
direction : Vec3,
t_min~ : Double,
t_max~ : Double,
) -> Ray raise GeometryError {
guard origin.finite() && direction.finite() else { raise NonFinite("ray") }
guard direction.x != 0.0 || direction.y != 0.0 || direction.z != 0.0 else {
raise ZeroDirection
}
guard finite(t_min) && finite(t_max) && t_min >= 0.0 && t_min <= t_max else {
raise InvalidInterval
}
{ origin, direction, t_min, t_max, }
}
///|
pub extend Vec3 with @debug.Debug::{to_repr}
///|
pub extend Vec3 with Eq::{equal, not_equal}
///|
pub extend GeometryError with @debug.Debug::{to_repr}
///|
pub extend GeometryError with Eq::{equal, not_equal}
///|
pub extend Aabb with @debug.Debug::{to_repr}
///|
pub extend Aabb with Eq::{equal, not_equal}
///|
pub extend Cube with @debug.Debug::{to_repr}
///|
pub extend Cube with Eq::{equal, not_equal}
///|
pub extend Ray with @debug.Debug::{to_repr}
///|
pub extend Ray with Eq::{equal, not_equal}