ncollide3d/shape/
tetrahedron.rs

1//! Definition of the tetrahedron shape.
2
3use crate::math::{Matrix, Point};
4use crate::shape::{Segment, Triangle};
5use na::RealField;
6use std::mem;
7
8/// A tetrahedron with 4 vertices.
9#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
10#[repr(C)]
11#[derive(Copy, Clone, Debug)]
12pub struct Tetrahedron<N: RealField + Copy> {
13    /// The tetrahedron first point.
14    pub a: Point<N>,
15    /// The tetrahedron first point.
16    pub b: Point<N>,
17    /// The tetrahedron first point.
18    pub c: Point<N>,
19    /// The tetrahedron first point.
20    pub d: Point<N>,
21}
22
23/// Logical description of the location of a point on a triangle.
24#[derive(Copy, Clone, Debug)]
25pub enum TetrahedronPointLocation<N: RealField + Copy> {
26    /// The point lies on a vertex.
27    OnVertex(usize),
28    /// The point lies on an edge.
29    ///
30    /// The 0-st edge is the segment AB.
31    /// The 1-st edge is the segment AC.
32    /// The 2-nd edge is the segment AD.
33    /// The 3-rd edge is the segment BC.
34    /// The 4-th edge is the segment BD.
35    /// The 5-th edge is the segment CD.
36    OnEdge(usize, [N; 2]),
37    /// The point lies on a triangular face interior.
38    ///
39    /// The first face is the triangle ABC.
40    /// The second face is the triangle ABD.
41    /// The third face is the triangle ACD.
42    /// The fourth face is the triangle BDC.
43    OnFace(usize, [N; 3]),
44    /// The point lies inside of the tetrahedron.
45    OnSolid,
46}
47
48impl<N: RealField + Copy> TetrahedronPointLocation<N> {
49    /// The barycentric coordinates corresponding to this point location.
50    ///
51    /// Returns `None` if the location is `TetrahedronPointLocation::OnSolid`.
52    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    /// Returns `true` if both `self` and `other` correspond to points on the same feature of a tetrahedron.
77    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    /// Creates a tetrahedron from three points.
96    #[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    /// Creates the reference to a tetrahedron from the reference to an array of four points.
102    pub fn from_array(arr: &[Point<N>; 4]) -> &Tetrahedron<N> {
103        unsafe { mem::transmute(arr) }
104    }
105
106    /// The fist point of this tetrahedron.
107    #[inline]
108    #[deprecated(note = "use the `self.a` public field directly.")]
109    pub fn a(&self) -> &Point<N> {
110        &self.a
111    }
112
113    /// The second point of this tetrahedron.
114    #[inline]
115    #[deprecated(note = "use the `self.b` public field directly.")]
116    pub fn b(&self) -> &Point<N> {
117        &self.b
118    }
119
120    /// The third point of this tetrahedron.
121    #[inline]
122    #[deprecated(note = "use the `self.c` public field directly.")]
123    pub fn c(&self) -> &Point<N> {
124        &self.c
125    }
126
127    /// The fourth point of this tetrahedron.
128    #[inline]
129    #[deprecated(note = "use the `self.d` public field directly.")]
130    pub fn d(&self) -> &Point<N> {
131        &self.d
132    }
133
134    /// Returns the i-th face of this tetrahedron.
135    ///
136    /// The 0-th face is the triangle ABC.
137    /// The 1-st face is the triangle ABD.
138    /// The 2-nd face is the triangle ACD.
139    /// The 3-rd face is the triangle BCD.
140    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    /// Returns the i-th face of this tetrahedron.
151    ///
152    /// The 0-th face is the triangle ABC.
153    /// The 1-st face is the triangle ABD.
154    /// The 2-nd face is the triangle ACD.
155    /// The 3-rd face is the triangle BCD.
156    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    /// Returns the i-th edge of this tetrahedron.
167    ///
168    /// The 0-st edge is the segment AB.
169    /// The 1-st edge is the segment AC.
170    /// The 2-nd edge is the segment AD.
171    /// The 3-rd edge is the segment BC.
172    /// The 4-th edge is the segment BD.
173    /// The 5-th edge is the segment CD.
174    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    /// Returns the indices of the vertices of the i-th edge of this tetrahedron.
187    ///
188    /// The 0-st edge is the segment AB.
189    /// The 1-st edge is the segment AC.
190    /// The 2-nd edge is the segment AD.
191    /// The 3-rd edge is the segment BC.
192    /// The 4-th edge is the segment BD.
193    /// The 5-th edge is the segment CD.
194    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    /// Computes the barycentric coordinates of the given point in the coordinate system of this tetrahedron.
207    ///
208    /// Returns `None` if this tetrahedron is degenerate.
209    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}