ruby_math/geometry/
bounds3.rs

1#![allow(dead_code)]
2
3use std::{
4    fmt::Display,
5    mem::swap,
6    ops::{Index, IndexMut},
7};
8
9use crate::{
10    algebra::{vec3d, Mat4d, Transform, Transformable, Vec2d, Vec3d},
11    geometry::Ray,
12};
13
14#[derive(Clone, Copy, PartialEq, Debug)]
15pub struct Bounds3 {
16    min: Vec3d,
17    max: Vec3d,
18}
19
20impl Display for Bounds3 {
21    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22        write!(f, "Bounds3(min: {}, max: {})", self.min, self.max)
23    }
24}
25
26impl Default for Bounds3 {
27    fn default() -> Self {
28        Self {
29            min: Vec3d::default(),
30            max: Vec3d::default(),
31        }
32    }
33}
34
35impl Index<usize> for Bounds3 {
36    type Output = Vec3d;
37
38    fn index(&self, index: usize) -> &Self::Output {
39        match index {
40            0 => &self.min,
41            1 => &self.max,
42            _ => panic!("`rmath::geometry::Bounds3::index`: index out of bounds."),
43        }
44    }
45}
46
47impl IndexMut<usize> for Bounds3 {
48    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
49        match index {
50            0 => &mut self.min,
51            1 => &mut self.max,
52            _ => panic!("`rmath::geometry::Bounds3::index`: index out of bounds."),
53        }
54    }
55}
56
57impl Bounds3 {
58    pub fn new(p1: Vec3d, p2: Vec3d) -> Self {
59        Self {
60            min: vec3d(p1.x().min(p2.x()), p1.y().min(p2.y()), p1.z().min(p2.z())),
61            max: vec3d(p1.x().max(p2.x()), p1.y().max(p2.y()), p1.z().max(p2.z())),
62        }
63    }
64
65    pub fn corner(&self, index: usize) -> Vec3d {
66        vec3d(
67            (*self)[index & 1].x(),
68            (*self)[((index & 2) != 0) as usize].y(),
69            (*self)[((index & 4) != 0) as usize].z(),
70        )
71    }
72
73    pub fn union_point(&self, point: Vec3d) -> Self {
74        Self::new(self.min.min(point), self.max.max(point))
75    }
76
77    pub fn union_bounds(&self, bounds: Bounds3) -> Self {
78        Self::new(self.min.min(bounds.min), self.max.max(bounds.max))
79    }
80
81    pub fn is_overlapped(&self, bounds: Bounds3) -> bool {
82        let x = self.max.x() >= bounds.min.x() && self.min.x() <= bounds.max.x();
83        let y = self.max.y() >= bounds.min.y() && self.min.y() <= bounds.max.y();
84        let z = self.max.z() >= bounds.min.z() && self.min.z() <= bounds.max.z();
85        x && y && z
86    }
87
88    pub fn is_inside(&self, point: Vec3d) -> bool {
89        (point.x() >= self.min.x() && point.x() <= self.max.x())
90            && (point.y() >= self.min.y() && point.y() <= self.max.y())
91            && (point.z() >= self.min.z() && point.z() <= self.max.z())
92    }
93
94    pub fn expand(&self, delta: f64) -> Self {
95        Self::new(
96            self.min - vec3d(delta, delta, delta),
97            self.max + vec3d(delta, delta, delta),
98        )
99    }
100
101    pub fn diagonal(&self) -> Vec3d {
102        self.max - self.min
103    }
104
105    pub fn surface_area(&self) -> f64 {
106        let diag = self.diagonal();
107        2.0 * diag.xyz().dot(diag.zxy())
108    }
109
110    pub fn volume(&self) -> f64 {
111        let diag = self.diagonal();
112        diag.x() * diag.y() * diag.z()
113    }
114
115    pub fn lerp(&self, t: Vec3d) -> Vec3d {
116        (1.0 - t) * self.min + t * self.max
117    }
118
119    pub fn offset(&self, point: Vec3d) -> Vec3d {
120        let mut o = point - self.min;
121        for i in 0..3 {
122            if self.max[i] > self.min[i] {
123                o[i] /= self.max[i] - self.min[i];
124            }
125        }
126        o
127    }
128
129    pub fn intersect(&self, ray: Ray, range: Vec2d) -> bool {
130        let (mut tmin, mut tmax) = range.to_tuple();
131        let inv_dir = ray.direction().recip();
132        for i in 0..3 {
133            let inv = inv_dir[i];
134            let mut t0 = (self.min[i] - ray.origin()[i]) * inv;
135            let mut t1 = (self.max[i] - ray.origin()[i]) * inv;
136            if inv < 0.0 {
137                swap(&mut t0, &mut t1);
138            }
139            tmin = t0.max(tmin);
140            tmax = t1.min(tmax);
141            if tmax <= tmin {
142                return false;
143            }
144        }
145        return true;
146    }
147
148    pub fn min(&self) -> Vec3d {
149        self.min
150    }
151
152    pub fn max(&self) -> Vec3d {
153        self.max
154    }
155}
156
157impl Transformable for Bounds3 {
158    fn apply(&self, transform: Transform) -> Self {
159        let p = transform.transform_point3d(self.corner(0));
160        Self::new(p, p)
161            .union_point(transform.transform_point3d(self.corner(1)))
162            .union_point(transform.transform_point3d(self.corner(2)))
163            .union_point(transform.transform_point3d(self.corner(3)))
164            .union_point(transform.transform_point3d(self.corner(4)))
165            .union_point(transform.transform_point3d(self.corner(5)))
166            .union_point(transform.transform_point3d(self.corner(6)))
167            .union_point(transform.transform_point3d(self.corner(7)))
168    }
169
170    fn apply_matrix4d(&self, matrix: Mat4d) -> Self {
171        let t = Transform::from_matrix4d(matrix);
172        self.apply(t)
173    }
174}