ncollide3d/shape/
convex.rs

1use crate::math::{Isometry, Point, Vector};
2use crate::shape::{ConvexPolygonalFeature, ConvexPolyhedron, FeatureId, SupportMap};
3use crate::transformation;
4use crate::utils::{self, SortedPair};
5use na::{self, Point2, Point3, RealField, Unit};
6use std::collections::hash_map::Entry;
7use std::collections::HashMap;
8use std::f64;
9
10#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
11#[derive(PartialEq, Debug, Copy, Clone)]
12struct Vertex {
13    first_adj_face_or_edge: usize,
14    num_adj_faces_or_edge: usize,
15}
16
17#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
18#[derive(PartialEq, Debug, Copy, Clone)]
19struct Edge<N: RealField + Copy> {
20    vertices: Point2<usize>,
21    faces: Point2<usize>,
22    dir: Unit<Vector<N>>,
23    deleted: bool,
24}
25
26impl<N: RealField + Copy> Edge<N> {
27    fn other_triangle(&self, id: usize) -> usize {
28        if id == self.faces[0] {
29            self.faces[1]
30        } else {
31            self.faces[0]
32        }
33    }
34}
35
36#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
37#[derive(PartialEq, Debug, Copy, Clone)]
38struct Face<N: RealField + Copy> {
39    first_vertex_or_edge: usize,
40    num_vertices_or_edges: usize,
41    normal: Unit<Vector<N>>,
42}
43
44#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
45#[derive(PartialEq, Debug, Copy, Clone)]
46struct Triangle<N: RealField + Copy> {
47    vertices: Point3<usize>,
48    edges: Point3<usize>,
49    normal: Unit<Vector<N>>,
50    parent_face: Option<usize>,
51}
52
53impl<N: RealField + Copy> Triangle<N> {
54    fn next_edge_id(&self, id: usize) -> usize {
55        for i in 0..3 {
56            if self.edges[i] == id {
57                return (i + 1) % 3;
58            }
59        }
60
61        unreachable!()
62    }
63}
64
65#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
66#[derive(PartialEq, Debug, Clone)]
67/// A convex polyhedron without degenerate faces.
68pub struct ConvexHull<N: RealField + Copy> {
69    points: Vec<Point<N>>,
70    vertices: Vec<Vertex>,
71    faces: Vec<Face<N>>,
72    edges: Vec<Edge<N>>,
73    // Faces adjascent to a vertex.
74    faces_adj_to_vertex: Vec<usize>,
75    // Edges adjascent to a vertex.
76    edges_adj_to_vertex: Vec<usize>,
77    // Edges adjascent to a face.
78    edges_adj_to_face: Vec<usize>,
79    // Vertices adjascent to a face.
80    vertices_adj_to_face: Vec<usize>,
81}
82
83impl<N: RealField + Copy> ConvexHull<N> {
84    /// Creates a new 2D convex polyhedron from an arbitrary set of points.
85    ///
86    /// This explicitly computes the convex hull of the given set of points. Use
87    /// Returns `None` if the convex hull computation failed.
88    pub fn try_from_points(points: &[Point<N>]) -> Option<ConvexHull<N>> {
89        let hull = transformation::convex_hull(points);
90        let indices: Vec<usize> = hull
91            .flat_indices()
92            .into_iter()
93            .map(|i| i as usize)
94            .collect();
95
96        Self::try_new(hull.coords, &indices)
97    }
98    /// Attempts to create a new solid assumed to be convex from the set of points and indices.
99    ///
100    /// The given points and index information are assumed to describe a convex polyhedron.
101    /// It it is not, weird results may be produced.
102    ///
103    /// # Return
104    ///
105    /// Retruns `None` if:
106    ///
107    ///   1. The given solid does not satisfy the euler characteristic.
108    ///   2. The given solid contains degenerate edges/triangles.
109    pub fn try_new(points: Vec<Point<N>>, indices: &[usize]) -> Option<ConvexHull<N>> {
110        let eps = N::default_epsilon().sqrt();
111
112        let mut vertices = Vec::new();
113        let mut edges = Vec::<Edge<N>>::new();
114        let mut faces = Vec::<Face<N>>::new();
115        let mut triangles = Vec::new();
116        let mut edge_map = HashMap::<SortedPair<usize>, usize>::new();
117
118        let mut faces_adj_to_vertex = Vec::new();
119        let mut edges_adj_to_vertex = Vec::new();
120        let mut edges_adj_to_face = Vec::new();
121        let mut vertices_adj_to_face = Vec::new();
122
123        //// Euler characteristic.
124        let nedges = points.len() + (indices.len() / 3) - 2;
125        edges.reserve(nedges);
126
127        /*
128         *  Initialize triangles and edges adjascency information.
129         */
130        for vtx in indices.chunks(3) {
131            let mut edges_id = Point3::origin();
132            let face_id = triangles.len();
133
134            for i1 in 0..3 {
135                // Deal with edges.
136                let i2 = (i1 + 1) % 3;
137                let key = SortedPair::new(vtx[i1], vtx[i2]);
138
139                match edge_map.entry(key) {
140                    Entry::Occupied(e) => {
141                        edges_id[i1] = *e.get();
142                        edges[*e.get()].faces[1] = face_id
143                    }
144                    Entry::Vacant(e) => {
145                        edges_id[i1] = *e.insert(edges.len());
146
147                        if let Some(dir) =
148                            Unit::try_new(points[vtx[i2]] - points[vtx[i1]], N::default_epsilon())
149                        {
150                            edges.push(Edge {
151                                vertices: Point2::new(vtx[i1], vtx[i2]),
152                                faces: Point2::new(face_id, 0),
153                                dir,
154                                deleted: false,
155                            })
156                        } else {
157                            return None;
158                        }
159                    }
160                }
161            }
162
163            let vertices = Point3::new(vtx[0], vtx[1], vtx[2]);
164            let normal =
165                utils::ccw_face_normal([&points[vtx[0]], &points[vtx[1]], &points[vtx[2]]])?;
166            let triangle = Triangle {
167                vertices,
168                edges: edges_id,
169                normal,
170                parent_face: None,
171            };
172
173            triangles.push(triangle);
174        }
175
176        // Find edges that must be deleted.
177        let mut num_valid_edges = 0;
178
179        for e in &mut edges {
180            let n1 = triangles[e.faces[0]].normal;
181            let n2 = triangles[e.faces[1]].normal;
182            if n1.dot(&*n2) > N::one() - eps {
183                e.deleted = true;
184            } else {
185                num_valid_edges += 1;
186            }
187        }
188
189        /*
190         * Extract faces by following  contours.
191         */
192        for i in 0..triangles.len() {
193            if triangles[i].parent_face.is_none() {
194                for j1 in 0..3 {
195                    if !edges[triangles[i].edges[j1]].deleted {
196                        // Create a new face, setup its first edge/vertex and construct it.
197                        let new_face_id = faces.len();
198                        let mut new_face = Face {
199                            first_vertex_or_edge: edges_adj_to_face.len(),
200                            num_vertices_or_edges: 1,
201                            normal: triangles[i].normal,
202                        };
203
204                        edges_adj_to_face.push(triangles[i].edges[j1]);
205                        vertices_adj_to_face.push(triangles[i].vertices[j1]);
206
207                        let j2 = (j1 + 1) % 3;
208                        let start_vertex = triangles[i].vertices[j1];
209
210                        // NOTE: variables ending with _id are identifier on the
211                        // fields of a triangle. Other variables are identifier on
212                        // the triangles/edges/vertices arrays.
213                        let mut curr_triangle = i;
214                        let mut curr_edge_id = j2;
215
216                        while triangles[curr_triangle].vertices[curr_edge_id] != start_vertex {
217                            let curr_edge = triangles[curr_triangle].edges[curr_edge_id];
218                            let curr_vertex = triangles[curr_triangle].vertices[curr_edge_id];
219                            triangles[curr_triangle].parent_face = Some(new_face_id);
220
221                            if !edges[curr_edge].deleted {
222                                edges_adj_to_face.push(curr_edge);
223                                vertices_adj_to_face.push(curr_vertex);
224                                new_face.num_vertices_or_edges += 1;
225
226                                curr_edge_id = (curr_edge_id + 1) % 3;
227                            } else {
228                                // Find adjascent edge on the next triange.
229                                curr_triangle = edges[curr_edge].other_triangle(curr_triangle);
230                                curr_edge_id = triangles[curr_triangle].next_edge_id(curr_edge);
231                                assert!(
232                                    triangles[curr_triangle].vertices[curr_edge_id] == curr_vertex
233                                );
234                            }
235                        }
236
237                        if new_face.num_vertices_or_edges > 2 {
238                            faces.push(new_face);
239                        }
240                        break;
241                    }
242                }
243            }
244        }
245
246        // Update face ids inside edges so that they point to the faces instead of the triangles.
247        for e in &mut edges {
248            if let Some(fid) = triangles[e.faces[0]].parent_face {
249                e.faces[0] = fid;
250            }
251
252            if let Some(fid) = triangles[e.faces[1]].parent_face {
253                e.faces[1] = fid;
254            }
255        }
256
257        /*
258         * Initialize vertices
259         */
260        let empty_vertex = Vertex {
261            first_adj_face_or_edge: 0,
262            num_adj_faces_or_edge: 0,
263        };
264
265        vertices.resize(points.len(), empty_vertex);
266
267        // First, find their multiplicities.
268        for face in &faces {
269            let first_vid = face.first_vertex_or_edge;
270            let last_vid = face.first_vertex_or_edge + face.num_vertices_or_edges;
271
272            for i in &vertices_adj_to_face[first_vid..last_vid] {
273                vertices[*i].num_adj_faces_or_edge += 1;
274            }
275        }
276
277        // Now, find their starting id.
278        let mut total_num_adj_faces = 0;
279        for v in &mut vertices {
280            v.first_adj_face_or_edge = total_num_adj_faces;
281            total_num_adj_faces += v.num_adj_faces_or_edge;
282        }
283        faces_adj_to_vertex.resize(total_num_adj_faces, 0);
284        edges_adj_to_vertex.resize(total_num_adj_faces, 0);
285
286        // Reset the number of adjascent faces.
287        // It will be set againt to the right value as
288        // the adjascent face list is filled.
289        for v in &mut vertices {
290            v.num_adj_faces_or_edge = 0;
291        }
292
293        for face_id in 0..faces.len() {
294            let face = &faces[face_id];
295            let first_vid = face.first_vertex_or_edge;
296            let last_vid = face.first_vertex_or_edge + face.num_vertices_or_edges;
297
298            for vid in first_vid..last_vid {
299                let v = &mut vertices[vertices_adj_to_face[vid]];
300                faces_adj_to_vertex[v.first_adj_face_or_edge + v.num_adj_faces_or_edge] = face_id;
301                edges_adj_to_vertex[v.first_adj_face_or_edge + v.num_adj_faces_or_edge] =
302                    edges_adj_to_face[vid];
303                v.num_adj_faces_or_edge += 1;
304            }
305        }
306
307        let mut num_valid_vertices = 0;
308
309        for v in &vertices {
310            if v.num_adj_faces_or_edge != 0 {
311                num_valid_vertices += 1;
312            }
313        }
314
315        // Check that the Euler characteristic is respected.
316        if num_valid_vertices + faces.len() - num_valid_edges != 2 {
317            None
318        } else {
319            let res = ConvexHull {
320                points,
321                vertices,
322                faces,
323                edges,
324                faces_adj_to_vertex,
325                edges_adj_to_vertex,
326                edges_adj_to_face,
327                vertices_adj_to_face,
328            };
329
330            // FIXME: for debug.
331            // res.check_geometry();
332
333            Some(res)
334        }
335    }
336
337    /// Verify if this convex polyhedron is actually convex.
338    #[inline]
339    pub fn check_geometry(&self) {
340        for face in &self.faces {
341            let p0 = self.points[self.vertices_adj_to_face[face.first_vertex_or_edge]];
342
343            for v in &self.points {
344                assert!((v - p0).dot(face.normal.as_ref()) <= N::default_epsilon());
345            }
346        }
347    }
348
349    /// The set of vertices of this convex polyhedron.
350    #[inline]
351    pub fn points(&self) -> &[Point<N>] {
352        &self.points[..]
353    }
354
355    /// Checks that the given direction in world-space is on the tangent cone of the given `feature`.
356    pub fn tangent_cone_contains_dir(
357        &self,
358        feature: FeatureId,
359        m: &Isometry<N>,
360        dir: &Unit<Vector<N>>,
361    ) -> bool {
362        let ls_dir = m.inverse_transform_unit_vector(dir);
363
364        match feature {
365            FeatureId::Face(id) => ls_dir.dot(&self.faces[id].normal) <= N::zero(),
366            FeatureId::Edge(id) => {
367                let edge = &self.edges[id];
368                ls_dir.dot(&self.faces[edge.faces[0]].normal) <= N::zero()
369                    && ls_dir.dot(&self.faces[edge.faces[1]].normal) <= N::zero()
370            }
371            FeatureId::Vertex(id) => {
372                let vertex = &self.vertices[id];
373                let first = vertex.first_adj_face_or_edge;
374                let last = vertex.first_adj_face_or_edge + vertex.num_adj_faces_or_edge;
375
376                for face in &self.faces_adj_to_vertex[first..last] {
377                    if ls_dir.dot(&self.faces[*face].normal) > N::zero() {
378                        return false;
379                    }
380                }
381
382                true
383            }
384            FeatureId::Unknown => false,
385        }
386    }
387
388    fn support_feature_id_toward_eps(&self, local_dir: &Unit<Vector<N>>, eps: N) -> FeatureId {
389        let (seps, ceps) = eps.sin_cos();
390        let support_pt_id = utils::point_cloud_support_point_id(local_dir.as_ref(), &self.points);
391        let vertex = &self.vertices[support_pt_id];
392
393        // Check faces.
394        for i in 0..vertex.num_adj_faces_or_edge {
395            let face_id = self.faces_adj_to_vertex[vertex.first_adj_face_or_edge + i];
396            let face = &self.faces[face_id];
397
398            if face.normal.dot(local_dir.as_ref()) >= ceps {
399                return FeatureId::Face(face_id);
400            }
401        }
402
403        // Check edges.
404        for i in 0..vertex.num_adj_faces_or_edge {
405            let edge_id = self.edges_adj_to_vertex[vertex.first_adj_face_or_edge + i];
406            let edge = &self.edges[edge_id];
407
408            if edge.dir.dot(local_dir.as_ref()).abs() <= seps {
409                return FeatureId::Edge(edge_id);
410            }
411        }
412
413        // The vertex is the support feature.
414        FeatureId::Vertex(support_pt_id)
415    }
416}
417
418impl<N: RealField + Copy> SupportMap<N> for ConvexHull<N> {
419    #[inline]
420    fn local_support_point(&self, dir: &Vector<N>) -> Point<N> {
421        utils::point_cloud_support_point(dir, self.points())
422    }
423}
424
425impl<N: RealField + Copy> ConvexPolyhedron<N> for ConvexHull<N> {
426    fn vertex(&self, id: FeatureId) -> Point<N> {
427        self.points[id.unwrap_vertex()]
428    }
429
430    fn edge(&self, id: FeatureId) -> (Point<N>, Point<N>, FeatureId, FeatureId) {
431        let edge = &self.edges[id.unwrap_edge()];
432        let v1 = edge.vertices[0];
433        let v2 = edge.vertices[1];
434
435        (
436            self.points[v1],
437            self.points[v2],
438            FeatureId::Vertex(v1),
439            FeatureId::Vertex(v2),
440        )
441    }
442
443    fn face(&self, id: FeatureId, out: &mut ConvexPolygonalFeature<N>) {
444        out.clear();
445
446        let face = &self.faces[id.unwrap_face()];
447        let first_vertex = face.first_vertex_or_edge;
448        let last_vertex = face.first_vertex_or_edge + face.num_vertices_or_edges;
449
450        for i in first_vertex..last_vertex {
451            let vid = self.vertices_adj_to_face[i];
452            let eid = self.edges_adj_to_face[i];
453            out.push(self.points[vid], FeatureId::Vertex(vid));
454            out.push_edge_feature_id(FeatureId::Edge(eid));
455        }
456
457        out.set_normal(face.normal);
458        out.set_feature_id(id);
459        out.recompute_edge_normals();
460    }
461
462    fn feature_normal(&self, feature: FeatureId) -> Unit<Vector<N>> {
463        match feature {
464            FeatureId::Face(id) => self.faces[id].normal,
465            FeatureId::Edge(id) => {
466                let edge = &self.edges[id];
467                Unit::new_normalize(
468                    *self.faces[edge.faces[0]].normal + *self.faces[edge.faces[1]].normal,
469                )
470            }
471            FeatureId::Vertex(id) => {
472                let vertex = &self.vertices[id];
473                let first = vertex.first_adj_face_or_edge;
474                let last = vertex.first_adj_face_or_edge + vertex.num_adj_faces_or_edge;
475                let mut normal = Vector::zeros();
476
477                for face in &self.faces_adj_to_vertex[first..last] {
478                    normal += *self.faces[*face].normal
479                }
480
481                Unit::new_normalize(normal)
482            }
483            FeatureId::Unknown => panic!("Invalid feature ID: {:?}", feature),
484        }
485    }
486
487    fn support_face_toward(
488        &self,
489        m: &Isometry<N>,
490        dir: &Unit<Vector<N>>,
491        out: &mut ConvexPolygonalFeature<N>,
492    ) {
493        let ls_dir = m.inverse_transform_vector(dir);
494        let mut best_face = 0;
495        let mut max_dot = self.faces[0].normal.dot(&ls_dir);
496
497        for i in 1..self.faces.len() {
498            let face = &self.faces[i];
499            let dot = face.normal.dot(&ls_dir);
500
501            if dot > max_dot {
502                max_dot = dot;
503                best_face = i;
504            }
505        }
506
507        self.face(FeatureId::Face(best_face), out);
508        out.transform_by(m);
509    }
510
511    fn support_feature_toward(
512        &self,
513        transform: &Isometry<N>,
514        dir: &Unit<Vector<N>>,
515        angle: N,
516        out: &mut ConvexPolygonalFeature<N>,
517    ) {
518        out.clear();
519        let local_dir = transform.inverse_transform_unit_vector(dir);
520        let fid = self.support_feature_id_toward_eps(&local_dir, angle);
521
522        match fid {
523            FeatureId::Vertex(_) => {
524                let v = self.vertex(fid);
525                out.push(v, fid);
526                out.set_feature_id(fid);
527            }
528            FeatureId::Edge(_) => {
529                let edge = self.edge(fid);
530                out.push(edge.0, edge.2);
531                out.push(edge.1, edge.3);
532                out.set_feature_id(fid);
533                out.push_edge_feature_id(fid);
534            }
535            FeatureId::Face(_) => self.face(fid, out),
536            FeatureId::Unknown => unreachable!(),
537        }
538
539        out.transform_by(transform);
540    }
541
542    fn support_feature_id_toward(&self, local_dir: &Unit<Vector<N>>) -> FeatureId {
543        let eps: N = na::convert(f64::consts::PI / 180.0);
544        self.support_feature_id_toward_eps(local_dir, eps)
545    }
546}