ruby_math/geometry/
bounds3.rs1#![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}