1use crate::primitives::*;
31use crate::scalar::*;
32use crate::vector::*;
33use num_traits::{Zero, One};
34
35pub trait Distance<T, Other> {
39 fn distance(&self, other: &Other) -> Option<T>;
41}
42
43pub trait Intersect<T> {
45 fn intersect(&self, other: &T) -> bool;
47}
48
49pub trait Intersection<T, Other> {
51 fn intersection(&self, other: &Other) -> Option<T>;
53}
54
55impl<T: FloatScalar> Distance<T, Vector3<T>> for Plane<T> {
59 fn distance(&self, other: &Vector3<T>) -> Option<T> {
60 let n = self.normal();
61 let nom = Vector3::dot(other, &n) + self.constant();
62 let denom = Vector3::dot(&n, &n);
63 if denom <= T::epsilon() {
64 return None;
65 }
66 Some(T::tabs(nom) / denom)
67 }
68}
69
70impl<T: FloatScalar> Distance<T, Vector3<T>> for Segment<T, Vector3<T>> {
71 fn distance(&self, other: &Vector3<T>) -> Option<T> {
72 Segment::distance(self, other, T::epsilon())
73 }
74}
75
76impl<T: FloatScalar> Intersect<Ray<T, Vector3<T>>> for Box3<T> {
80 fn intersect(&self, other: &Ray<T, Vector3<T>>) -> bool {
81 let mut tmin = -T::infinity();
87 let mut tmax = T::infinity();
88
89 let mut t0 = (self.min.x - other.start.x) / other.direction.x;
90 let mut t1 = (self.max.x - other.start.x) / other.direction.x;
91
92 tmin = T::max(tmin, T::min(t0, t1));
93 tmax = T::min(tmax, T::max(t0, t1));
94
95 t0 = (self.min.y - other.start.y) / other.direction.y;
96 t1 = (self.max.y - other.start.y) / other.direction.y;
97
98 tmin = T::max(tmin, T::min(t0, t1));
99 tmax = T::min(tmax, T::max(t0, t1));
100
101 t0 = (self.min.z - other.start.z) / other.direction.z;
102 t1 = (self.max.z - other.start.z) / other.direction.z;
103
104 tmin = T::max(tmin, T::min(t0, t1));
105 tmax = T::min(tmax, T::max(t0, t1));
106
107 tmax > T::max(tmin, <T as Zero>::zero())
108 }
109}
110
111impl<T: FloatScalar> Intersect<Sphere3<T>> for Box3<T> {
112 fn intersect(&self, other: &Sphere3<T>) -> bool {
113 let mut dist = <T as Zero>::zero();
114
115 let c = other.center;
116 let r = other.radius;
117
118 if c.x < self.min.x {
119 dist += T::squared(c.x - self.min.x)
120 } else if c.x > self.max.x {
121 dist += T::squared(c.x - self.max.x)
122 }
123
124 if c.y < self.min.y {
125 dist += T::squared(c.y - self.min.y)
126 } else if c.y > self.max.y {
127 dist += T::squared(c.y - self.max.y)
128 }
129
130 if c.z < self.min.z {
131 dist += T::squared(c.z - self.min.z)
132 } else if c.z > self.max.z {
133 dist += T::squared(c.z - self.max.z)
134 }
135
136 r * r > dist
137 }
138}
139
140fn is_in_0_to_1_range<T: FloatScalar>(x: T) -> bool {
141 x >= <T as Zero>::zero() && x <= <T as One>::one()
142}
143
144impl<T: FloatScalar> Intersect<Tri3<T>> for Sphere3<T> {
145 fn intersect(&self, tri: &Tri3<T>) -> bool {
146 let uvw = tri.barycentric_coordinates(&self.center);
147 let verts = tri.vertices();
148 let v0 = verts[0];
149 let v1 = verts[1];
150 let v2 = verts[2];
151 if is_in_0_to_1_range(uvw.x) && is_in_0_to_1_range(uvw.y) && is_in_0_to_1_range(uvw.z) {
152 let p = Plane::from_tri(&v0, &v1, &v2);
153 if p.distance(&self.center)
154 .map_or(false, |dist| dist <= self.radius)
155 {
156 true
157 } else {
158 false
159 }
160 } else {
161 let d0 = Segment::new(&v0, &v1).distance(&self.center, T::epsilon());
162 let d1 = Segment::new(&v1, &v2).distance(&self.center, T::epsilon());
163 let d2 = Segment::new(&v2, &v0).distance(&self.center, T::epsilon());
164
165 match (d0, d1, d2) {
166 (Some(d0), Some(d1), Some(d2)) => {
167 let m = T::min(d0, T::min(d1, d2));
168 if m <= self.radius {
169 true
170 } else {
171 false
172 }
173 }
174 _ => false,
175 }
176 }
177 }
178}
179
180impl<T: FloatScalar> Intersection<(T, Vector3<T>), Tri3<T>> for Ray<T, Vector3<T>> {
188 fn intersection(&self, tri: &Tri3<T>) -> Option<(T, Vector3<T>)> {
189 let verts = tri.vertices();
190 let v0 = verts[0];
191 let v1 = verts[1];
192 let v2 = verts[2];
193 let edge1 = v1 - v0;
195 let edge2 = v2 - v0;
196
197 let pvec = Vector3::cross(&self.direction, &edge2);
199
200 let det = Vector3::dot(&edge1, &pvec);
202
203 if det > -T::epsilon() && det < T::epsilon() {
204 return None; }
206
207 let tvec = self.start - v0;
209
210 let qvec = Vector3::cross(&tvec, &edge1);
211
212 let u = Vector3::dot(&tvec, &pvec) / det;
213
214 if u < -T::epsilon() || u > <T as One>::one() + T::epsilon() {
215 return None; }
217
218 let v = Vector3::dot(&self.direction, &qvec) / det;
220 if v < -T::epsilon() || u + v > <T as One>::one() + T::two() * T::epsilon() {
221 return None; }
223
224 let t = Vector3::dot(&edge2, &qvec) / det;
225 let out = self.start + (self.direction * t);
226 Some((t, out)) }
228}
229
230pub fn basis_from_unit<T: FloatScalar>(unit: &Vector3<T>) -> [Vector3<T>; 3] {
240 let u = Vector3::normalize(unit);
241 let x = u.x;
242 let y = u.y;
243 let z = u.z;
244
245 let v = if x.tabs() <= y.tabs() && x.tabs() <= z.tabs() {
246 Vector3::new(<T as Zero>::zero(), -z, y)
247 } else if y.tabs() <= x.tabs() && y.tabs() <= z.tabs() {
248 Vector3::new(-z, <T as Zero>::zero(), x)
249 } else {
250 Vector3::new(-y, x, <T as Zero>::zero())
252 };
253 let v = Vector3::normalize(&v);
254 let w = Vector3::normalize(&Vector3::cross(&u, &v));
255 [u, w, v]
256}
257
258#[cfg(test)]
259mod tests {
260 use super::Intersect;
261 use crate::primitives::{Box3, Sphere3};
262 use crate::vector::Vector3;
263
264 #[test]
265 fn test_box3_sphere_intersect_z_axis() {
266 let b = Box3::new(
267 &Vector3::new(0.0f32, 0.0, 0.0),
268 &Vector3::new(1.0, 1.0, 1.0),
269 );
270
271 let outside_z = Sphere3::new(Vector3::new(0.5, 0.5, 2.0), 0.25);
272 assert!(!b.intersect(&outside_z));
273
274 let touching_z = Sphere3::new(Vector3::new(0.5, 0.5, 2.0), 1.1);
275 assert!(b.intersect(&touching_z));
276 }
277
278 #[test]
279 fn test_box3_sphere_intersect_on_edge() {
280 let b = Box3::new(
281 &Vector3::new(0.0f32, 0.0, 0.0),
282 &Vector3::new(1.0, 1.0, 1.0),
283 );
284
285 let touching = Sphere3::new(Vector3::new(2.0, 0.5, 0.5), 1.0);
286 assert!(!b.intersect(&touching));
287
288 let just_inside = Sphere3::new(Vector3::new(2.0, 0.5, 0.5), 1.0001);
289 assert!(b.intersect(&just_inside));
290 }
291}