1use crate::math::{Matrix, Point};
4use crate::shape::{Segment, Triangle};
5use na::RealField;
6use std::mem;
7
8#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
10#[repr(C)]
11#[derive(Copy, Clone, Debug)]
12pub struct Tetrahedron<N: RealField + Copy> {
13 pub a: Point<N>,
15 pub b: Point<N>,
17 pub c: Point<N>,
19 pub d: Point<N>,
21}
22
23#[derive(Copy, Clone, Debug)]
25pub enum TetrahedronPointLocation<N: RealField + Copy> {
26 OnVertex(usize),
28 OnEdge(usize, [N; 2]),
37 OnFace(usize, [N; 3]),
44 OnSolid,
46}
47
48impl<N: RealField + Copy> TetrahedronPointLocation<N> {
49 pub fn barycentric_coordinates(&self) -> Option<[N; 4]> {
53 let mut bcoords = [N::zero(); 4];
54
55 match self {
56 TetrahedronPointLocation::OnVertex(i) => bcoords[*i] = N::one(),
57 TetrahedronPointLocation::OnEdge(i, uv) => {
58 let idx = Tetrahedron::<N>::edge_ids(*i);
59 bcoords[idx.0] = uv[0];
60 bcoords[idx.1] = uv[1];
61 }
62 TetrahedronPointLocation::OnFace(i, uvw) => {
63 let idx = Tetrahedron::<N>::face_ids(*i);
64 bcoords[idx.0] = uvw[0];
65 bcoords[idx.1] = uvw[1];
66 bcoords[idx.2] = uvw[2];
67 }
68 TetrahedronPointLocation::OnSolid => {
69 return None;
70 }
71 }
72
73 Some(bcoords)
74 }
75
76 pub fn same_feature_as(&self, other: &TetrahedronPointLocation<N>) -> bool {
78 match (*self, *other) {
79 (TetrahedronPointLocation::OnVertex(i), TetrahedronPointLocation::OnVertex(j)) => {
80 i == j
81 }
82 (TetrahedronPointLocation::OnEdge(i, _), TetrahedronPointLocation::OnEdge(j, _)) => {
83 i == j
84 }
85 (TetrahedronPointLocation::OnFace(i, _), TetrahedronPointLocation::OnFace(j, _)) => {
86 i == j
87 }
88 (TetrahedronPointLocation::OnSolid, TetrahedronPointLocation::OnSolid) => true,
89 _ => false,
90 }
91 }
92}
93
94impl<N: RealField + Copy> Tetrahedron<N> {
95 #[inline]
97 pub fn new(a: Point<N>, b: Point<N>, c: Point<N>, d: Point<N>) -> Tetrahedron<N> {
98 Tetrahedron { a, b, c, d }
99 }
100
101 pub fn from_array(arr: &[Point<N>; 4]) -> &Tetrahedron<N> {
103 unsafe { mem::transmute(arr) }
104 }
105
106 #[inline]
108 #[deprecated(note = "use the `self.a` public field directly.")]
109 pub fn a(&self) -> &Point<N> {
110 &self.a
111 }
112
113 #[inline]
115 #[deprecated(note = "use the `self.b` public field directly.")]
116 pub fn b(&self) -> &Point<N> {
117 &self.b
118 }
119
120 #[inline]
122 #[deprecated(note = "use the `self.c` public field directly.")]
123 pub fn c(&self) -> &Point<N> {
124 &self.c
125 }
126
127 #[inline]
129 #[deprecated(note = "use the `self.d` public field directly.")]
130 pub fn d(&self) -> &Point<N> {
131 &self.d
132 }
133
134 pub fn face(&self, i: usize) -> Triangle<N> {
141 match i {
142 0 => Triangle::new(self.a, self.b, self.c),
143 1 => Triangle::new(self.a, self.b, self.d),
144 2 => Triangle::new(self.a, self.c, self.d),
145 3 => Triangle::new(self.b, self.c, self.d),
146 _ => panic!("Tetrahedron face index out of bounds (must be < 4."),
147 }
148 }
149
150 pub fn face_ids(i: usize) -> (usize, usize, usize) {
157 match i {
158 0 => (0, 1, 2),
159 1 => (0, 1, 3),
160 2 => (0, 2, 3),
161 3 => (1, 2, 3),
162 _ => panic!("Tetrahedron face index out of bounds (must be < 4."),
163 }
164 }
165
166 pub fn edge(&self, i: usize) -> Segment<N> {
175 match i {
176 0 => Segment::new(self.a, self.b),
177 1 => Segment::new(self.a, self.c),
178 2 => Segment::new(self.a, self.d),
179 3 => Segment::new(self.b, self.c),
180 4 => Segment::new(self.b, self.d),
181 5 => Segment::new(self.c, self.d),
182 _ => panic!("Tetrahedron edge index out of bounds (must be < 6)."),
183 }
184 }
185
186 pub fn edge_ids(i: usize) -> (usize, usize) {
195 match i {
196 0 => (0, 1),
197 1 => (0, 2),
198 2 => (0, 3),
199 3 => (1, 2),
200 4 => (1, 3),
201 5 => (2, 3),
202 _ => panic!("Tetrahedron edge index out of bounds (must be < 6)."),
203 }
204 }
205
206 pub fn barycentric_coordinates(&self, p: &Point<N>) -> Option<[N; 4]> {
210 let ab = self.b - self.a;
211 let ac = self.c - self.a;
212 let ad = self.d - self.a;
213 let m = Matrix::new(ab.x, ac.x, ad.x, ab.y, ac.y, ad.y, ab.z, ac.z, ad.z);
214
215 m.try_inverse().map(|im| {
216 let bcoords = im * (p - self.a);
217 [
218 N::one() - bcoords.x - bcoords.y - bcoords.z,
219 bcoords.x,
220 bcoords.y,
221 bcoords.z,
222 ]
223 })
224 }
225}