parry3d/shape/
convex_polyhedron.rs

1use crate::math::{Point, Real, Vector, DIM};
2use crate::shape::{FeatureId, PackedFeatureId, PolygonalFeature, PolygonalFeatureMap, SupportMap};
3// use crate::transformation;
4use crate::utils::hashmap::{Entry, HashMap};
5use crate::utils::{self, SortedPair};
6#[cfg(feature = "alloc")]
7use alloc::vec::Vec;
8use core::f64;
9#[cfg(not(feature = "std"))]
10use na::ComplexField; // for .abs(), .sqrt(), and .sin_cos()
11use na::{self, Point2, Unit};
12
13#[cfg(feature = "rkyv")]
14use rkyv::{bytecheck, CheckBytes};
15
16#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
17#[cfg_attr(
18    feature = "rkyv",
19    derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes),
20    archive(as = "Self")
21)]
22#[derive(PartialEq, Debug, Copy, Clone)]
23pub struct Vertex {
24    pub first_adj_face_or_edge: u32,
25    pub num_adj_faces_or_edge: u32,
26}
27
28#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
29#[cfg_attr(
30    feature = "rkyv",
31    derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes),
32    archive(as = "Self")
33)]
34#[derive(PartialEq, Debug, Copy, Clone)]
35pub struct Edge {
36    pub vertices: Point2<u32>,
37    pub faces: Point2<u32>,
38    pub dir: Unit<Vector<Real>>,
39    deleted: bool,
40}
41
42impl Edge {
43    fn other_triangle(&self, id: u32) -> u32 {
44        if id == self.faces[0] {
45            self.faces[1]
46        } else {
47            self.faces[0]
48        }
49    }
50}
51
52#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
53#[cfg_attr(
54    feature = "rkyv",
55    derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes),
56    archive(as = "Self")
57)]
58#[derive(PartialEq, Debug, Copy, Clone)]
59pub struct Face {
60    pub first_vertex_or_edge: u32,
61    pub num_vertices_or_edges: u32,
62    pub normal: Unit<Vector<Real>>,
63}
64
65#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
66#[cfg_attr(
67    feature = "rkyv",
68    derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize),
69    archive(check_bytes)
70)]
71#[derive(PartialEq, Debug, Copy, Clone)]
72struct Triangle {
73    vertices: [u32; 3],
74    edges: [u32; 3],
75    normal: Vector<Real>,
76    parent_face: Option<u32>,
77    is_degenerate: bool,
78}
79
80impl Triangle {
81    fn next_edge_id(&self, id: u32) -> u32 {
82        for i in 0..3 {
83            if self.edges[i] == id {
84                return (i as u32 + 1) % 3;
85            }
86        }
87
88        unreachable!()
89    }
90}
91
92#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
93#[cfg_attr(
94    feature = "rkyv",
95    derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize),
96    archive(check_bytes)
97)]
98#[derive(PartialEq, Debug, Clone)]
99/// A convex polyhedron without degenerate faces.
100pub struct ConvexPolyhedron {
101    points: Vec<Point<Real>>,
102    vertices: Vec<Vertex>,
103    faces: Vec<Face>,
104    edges: Vec<Edge>,
105    // Faces adjacent to a vertex.
106    faces_adj_to_vertex: Vec<u32>,
107    // Edges adjacent to a vertex.
108    edges_adj_to_vertex: Vec<u32>,
109    // Edges adjacent to a face.
110    edges_adj_to_face: Vec<u32>,
111    // Vertices adjacent to a face.
112    vertices_adj_to_face: Vec<u32>,
113}
114
115impl ConvexPolyhedron {
116    /// Creates a new convex polyhedron from an arbitrary set of points.
117    ///
118    /// This explicitly computes the convex hull of the given set of points. Use
119    /// Returns `None` if the convex hull computation failed.
120    pub fn from_convex_hull(points: &[Point<Real>]) -> Option<ConvexPolyhedron> {
121        crate::transformation::try_convex_hull(points)
122            .ok()
123            .and_then(|(vertices, indices)| Self::from_convex_mesh(vertices, &indices))
124    }
125
126    /// Attempts to create a new solid assumed to be convex from the set of points and indices.
127    ///
128    /// The given points and index information are assumed to describe a convex polyhedron.
129    /// It it is not, weird results may be produced.
130    ///
131    /// # Return
132    ///
133    /// Returns `None` if the given solid is not manifold (contains t-junctions, not closed, etc.)
134    pub fn from_convex_mesh(
135        points: Vec<Point<Real>>,
136        indices: &[[u32; DIM]],
137    ) -> Option<ConvexPolyhedron> {
138        let eps = crate::math::DEFAULT_EPSILON.sqrt();
139
140        let mut vertices = Vec::new();
141        let mut edges = Vec::<Edge>::new();
142        let mut faces = Vec::<Face>::new();
143        let mut triangles = Vec::new();
144        let mut edge_map = HashMap::default();
145
146        let mut faces_adj_to_vertex = Vec::new();
147        let mut edges_adj_to_vertex = Vec::new();
148        let mut edges_adj_to_face = Vec::new();
149        let mut vertices_adj_to_face = Vec::new();
150
151        if points.len() + indices.len() <= 2 {
152            return None;
153        }
154
155        //// Euler characteristic.
156        let nedges = points.len() + indices.len() - 2;
157        edges.reserve(nedges);
158
159        /*
160         *  Initialize triangles and edges adjacency information.
161         */
162        for idx in indices {
163            let mut edges_id = [u32::MAX; DIM];
164            let face_id = triangles.len();
165
166            if idx[0] == idx[1] || idx[0] == idx[2] || idx[1] == idx[2] {
167                return None;
168            }
169
170            for i1 in 0..3 {
171                // Deal with edges.
172                let i2 = (i1 + 1) % 3;
173                let key = SortedPair::new(idx[i1], idx[i2]);
174
175                match edge_map.entry(key) {
176                    Entry::Occupied(e) => {
177                        let edge = &mut edges[*e.get() as usize];
178                        let out_face_id = &mut edge.faces[1];
179
180                        if *out_face_id == u32::MAX {
181                            edges_id[i1] = *e.get();
182                            *out_face_id = face_id as u32
183                        } else {
184                            // We have a t-junction.
185                            return None;
186                        }
187                    }
188                    Entry::Vacant(e) => {
189                        edges_id[i1] = *e.insert(edges.len() as u32);
190
191                        let dir = Unit::try_new(
192                            points[idx[i2] as usize] - points[idx[i1] as usize],
193                            crate::math::DEFAULT_EPSILON,
194                        );
195
196                        edges.push(Edge {
197                            vertices: Point2::new(idx[i1], idx[i2]),
198                            faces: Point2::new(face_id as u32, u32::MAX),
199                            dir: dir.unwrap_or(Vector::x_axis()),
200                            deleted: dir.is_none(),
201                        });
202                    }
203                }
204            }
205
206            let normal = utils::ccw_face_normal([
207                &points[idx[0] as usize],
208                &points[idx[1] as usize],
209                &points[idx[2] as usize],
210            ]);
211            let triangle = Triangle {
212                vertices: *idx,
213                edges: edges_id,
214                normal: normal.map(|n| *n).unwrap_or(Vector::zeros()),
215                parent_face: None,
216                is_degenerate: normal.is_none(),
217            };
218
219            triangles.push(triangle);
220        }
221
222        // Find edges that must be deleted.
223
224        for e in &mut edges {
225            let tri1 = triangles.get(e.faces[0] as usize)?;
226            let tri2 = triangles.get(e.faces[1] as usize)?;
227            if tri1.normal.dot(&tri2.normal) > 1.0 - eps {
228                e.deleted = true;
229            }
230        }
231
232        /*
233         * Extract faces by following  contours.
234         */
235        for i in 0..triangles.len() {
236            if triangles[i].parent_face.is_none() {
237                for j1 in 0..3 {
238                    if !edges[triangles[i].edges[j1] as usize].deleted {
239                        // Create a new face, setup its first edge/vertex and construct it.
240                        let new_face_id = faces.len();
241                        let mut new_face = Face {
242                            first_vertex_or_edge: edges_adj_to_face.len() as u32,
243                            num_vertices_or_edges: 1,
244                            normal: Unit::new_unchecked(triangles[i].normal),
245                        };
246
247                        edges_adj_to_face.push(triangles[i].edges[j1]);
248                        vertices_adj_to_face.push(triangles[i].vertices[j1]);
249
250                        let j2 = (j1 + 1) % 3;
251                        let start_vertex = triangles[i].vertices[j1];
252
253                        // NOTE: variables ending with _id are identifier on the
254                        // fields of a triangle. Other variables are identifier on
255                        // the triangles/edges/vertices arrays.
256                        let mut curr_triangle = i;
257                        let mut curr_edge_id = j2;
258
259                        while triangles[curr_triangle].vertices[curr_edge_id] != start_vertex {
260                            let curr_edge = triangles[curr_triangle].edges[curr_edge_id];
261                            let curr_vertex = triangles[curr_triangle].vertices[curr_edge_id];
262                            // NOTE: we should use this assertion. However, it can currently
263                            // happen if there are some isolated non-deleted edges due to
264                            // rounding errors.
265                            //
266                            // assert!(triangles[curr_triangle].parent_face.is_none());
267                            triangles[curr_triangle].parent_face = Some(new_face_id as u32);
268
269                            if !edges[curr_edge as usize].deleted {
270                                edges_adj_to_face.push(curr_edge);
271                                vertices_adj_to_face.push(curr_vertex);
272                                new_face.num_vertices_or_edges += 1;
273
274                                curr_edge_id = (curr_edge_id + 1) % 3;
275                            } else {
276                                // Find adjacent edge on the next triangle.
277                                curr_triangle = edges[curr_edge as usize]
278                                    .other_triangle(curr_triangle as u32)
279                                    as usize;
280                                curr_edge_id =
281                                    triangles[curr_triangle].next_edge_id(curr_edge) as usize;
282                                assert!(
283                                    triangles[curr_triangle].vertices[curr_edge_id] == curr_vertex
284                                );
285                            }
286                        }
287
288                        if new_face.num_vertices_or_edges > 2 {
289                            // Sometimes degenerate faces may be generated
290                            // due to numerical errors resulting in an isolated
291                            // edge not being deleted.
292                            //
293                            // This kind of degenerate faces are not valid.
294                            faces.push(new_face);
295                        }
296                        break;
297                    }
298                }
299            }
300        }
301
302        // Update face ids inside edges so that they point to the faces instead of the triangles.
303        for e in &mut edges {
304            if let Some(fid) = triangles.get(e.faces[0] as usize)?.parent_face {
305                e.faces[0] = fid;
306            }
307
308            if let Some(fid) = triangles.get(e.faces[1] as usize)?.parent_face {
309                e.faces[1] = fid;
310            }
311        }
312
313        /*
314         * Initialize vertices
315         */
316        let empty_vertex = Vertex {
317            first_adj_face_or_edge: 0,
318            num_adj_faces_or_edge: 0,
319        };
320
321        vertices.resize(points.len(), empty_vertex);
322
323        // First, find their multiplicities.
324        for face in &faces {
325            let first_vid = face.first_vertex_or_edge;
326            let last_vid = face.first_vertex_or_edge + face.num_vertices_or_edges;
327
328            for i in &vertices_adj_to_face[first_vid as usize..last_vid as usize] {
329                vertices[*i as usize].num_adj_faces_or_edge += 1;
330            }
331        }
332
333        // Now, find their starting id.
334        let mut total_num_adj_faces = 0;
335        for v in &mut vertices {
336            v.first_adj_face_or_edge = total_num_adj_faces;
337            total_num_adj_faces += v.num_adj_faces_or_edge;
338        }
339        faces_adj_to_vertex.resize(total_num_adj_faces as usize, 0);
340        edges_adj_to_vertex.resize(total_num_adj_faces as usize, 0);
341
342        // Reset the number of adjacent faces.
343        // It will be set again to the right value as
344        // the adjacent face list is filled.
345        for v in &mut vertices {
346            v.num_adj_faces_or_edge = 0;
347        }
348
349        for (face_id, face) in faces.iter().enumerate() {
350            let first_vid = face.first_vertex_or_edge;
351            let last_vid = face.first_vertex_or_edge + face.num_vertices_or_edges;
352
353            for vid in first_vid..last_vid {
354                let v = &mut vertices[vertices_adj_to_face[vid as usize] as usize];
355                faces_adj_to_vertex
356                    [(v.first_adj_face_or_edge + v.num_adj_faces_or_edge) as usize] =
357                    face_id as u32;
358                edges_adj_to_vertex
359                    [(v.first_adj_face_or_edge + v.num_adj_faces_or_edge) as usize] =
360                    edges_adj_to_face[vid as usize];
361                v.num_adj_faces_or_edge += 1;
362            }
363        }
364
365        // Note numerical errors may throw off the Euler characteristic.
366        // So we don't check it right now.
367
368        let res = ConvexPolyhedron {
369            points,
370            vertices,
371            faces,
372            edges,
373            faces_adj_to_vertex,
374            edges_adj_to_vertex,
375            edges_adj_to_face,
376            vertices_adj_to_face,
377        };
378
379        // TODO: for debug.
380        // res.check_geometry();
381
382        Some(res)
383    }
384
385    /// Verify if this convex polyhedron is actually convex.
386    #[inline]
387    pub fn check_geometry(&self) {
388        for face in &self.faces {
389            let p0 =
390                self.points[self.vertices_adj_to_face[face.first_vertex_or_edge as usize] as usize];
391
392            for v in &self.points {
393                assert!((v - p0).dot(face.normal.as_ref()) <= crate::math::DEFAULT_EPSILON);
394            }
395        }
396    }
397
398    /// The set of vertices of this convex polyhedron.
399    #[inline]
400    pub fn points(&self) -> &[Point<Real>] {
401        &self.points[..]
402    }
403
404    /// The topology of the vertices of this convex polyhedron.
405    #[inline]
406    pub fn vertices(&self) -> &[Vertex] {
407        &self.vertices[..]
408    }
409
410    /// The topology of the edges of this convex polyhedron.
411    #[inline]
412    pub fn edges(&self) -> &[Edge] {
413        &self.edges[..]
414    }
415
416    /// The topology of the faces of this convex polyhedron.
417    #[inline]
418    pub fn faces(&self) -> &[Face] {
419        &self.faces[..]
420    }
421
422    /// The array containing the indices of the vertices adjacent to each face.
423    #[inline]
424    pub fn vertices_adj_to_face(&self) -> &[u32] {
425        &self.vertices_adj_to_face[..]
426    }
427
428    /// The array containing the indices of the edges adjacent to each face.
429    #[inline]
430    pub fn edges_adj_to_face(&self) -> &[u32] {
431        &self.edges_adj_to_face[..]
432    }
433
434    /// The array containing the indices of the faces adjacent to each vertex.
435    #[inline]
436    pub fn faces_adj_to_vertex(&self) -> &[u32] {
437        &self.faces_adj_to_vertex[..]
438    }
439
440    /// Computes a scaled version of this convex polygon.
441    ///
442    /// Returns `None` if the result had degenerate normals (for example if
443    /// the scaling factor along one axis is zero).
444    pub fn scaled(mut self, scale: &Vector<Real>) -> Option<Self> {
445        self.points
446            .iter_mut()
447            .for_each(|pt| pt.coords.component_mul_assign(scale));
448
449        for f in &mut self.faces {
450            f.normal = Unit::try_new(f.normal.component_mul(scale), 0.0).unwrap_or(f.normal);
451        }
452
453        for e in &mut self.edges {
454            e.dir = Unit::try_new(e.dir.component_mul(scale), 0.0).unwrap_or(e.dir);
455        }
456
457        Some(self)
458    }
459
460    fn support_feature_id_toward_eps(
461        &self,
462        local_dir: &Unit<Vector<Real>>,
463        eps: Real,
464    ) -> FeatureId {
465        let (seps, ceps) = eps.sin_cos();
466        let support_pt_id = utils::point_cloud_support_point_id(local_dir.as_ref(), &self.points);
467        let vertex = &self.vertices[support_pt_id];
468
469        // Check faces.
470        for i in 0..vertex.num_adj_faces_or_edge {
471            let face_id = self.faces_adj_to_vertex[(vertex.first_adj_face_or_edge + i) as usize];
472            let face = &self.faces[face_id as usize];
473
474            if face.normal.dot(local_dir.as_ref()) >= ceps {
475                return FeatureId::Face(face_id);
476            }
477        }
478
479        // Check edges.
480        for i in 0..vertex.num_adj_faces_or_edge {
481            let edge_id = self.edges_adj_to_vertex[(vertex.first_adj_face_or_edge + i) as usize];
482            let edge = &self.edges[edge_id as usize];
483
484            if edge.dir.dot(local_dir.as_ref()).abs() <= seps {
485                return FeatureId::Edge(edge_id);
486            }
487        }
488
489        // The vertex is the support feature.
490        FeatureId::Vertex(support_pt_id as u32)
491    }
492
493    /// Computes the ID of the features with a normal that maximize the dot-product with `local_dir`.
494    pub fn support_feature_id_toward(&self, local_dir: &Unit<Vector<Real>>) -> FeatureId {
495        let eps: Real = na::convert::<f64, Real>(f64::consts::PI / 180.0);
496        self.support_feature_id_toward_eps(local_dir, eps)
497    }
498
499    /// The normal of the given feature.
500    pub fn feature_normal(&self, feature: FeatureId) -> Option<Unit<Vector<Real>>> {
501        match feature {
502            FeatureId::Face(id) => Some(self.faces[id as usize].normal),
503            FeatureId::Edge(id) => {
504                let edge = &self.edges[id as usize];
505                Some(Unit::new_normalize(
506                    *self.faces[edge.faces[0] as usize].normal
507                        + *self.faces[edge.faces[1] as usize].normal,
508                ))
509            }
510            FeatureId::Vertex(id) => {
511                let vertex = &self.vertices[id as usize];
512                let first = vertex.first_adj_face_or_edge;
513                let last = vertex.first_adj_face_or_edge + vertex.num_adj_faces_or_edge;
514                let mut normal = Vector::zeros();
515
516                for face in &self.faces_adj_to_vertex[first as usize..last as usize] {
517                    normal += *self.faces[*face as usize].normal
518                }
519
520                Some(Unit::new_normalize(normal))
521            }
522            FeatureId::Unknown => None,
523        }
524    }
525}
526
527impl SupportMap for ConvexPolyhedron {
528    #[inline]
529    fn local_support_point(&self, dir: &Vector<Real>) -> Point<Real> {
530        utils::point_cloud_support_point(dir, self.points())
531    }
532}
533
534impl PolygonalFeatureMap for ConvexPolyhedron {
535    fn local_support_feature(&self, dir: &Unit<Vector<Real>>, out_feature: &mut PolygonalFeature) {
536        let mut best_fid = 0;
537        let mut best_dot = self.faces[0].normal.dot(dir);
538
539        for (fid, face) in self.faces[1..].iter().enumerate() {
540            let new_dot = face.normal.dot(dir);
541
542            if new_dot > best_dot {
543                best_fid = fid + 1;
544                best_dot = new_dot;
545            }
546        }
547
548        let face = &self.faces[best_fid];
549        let i1 = face.first_vertex_or_edge;
550        // TODO: if there are more than 4 vertices, we need to select four vertices that maximize the area.
551        let num_vertices = face.num_vertices_or_edges.min(4);
552        let i2 = i1 + num_vertices;
553
554        for (i, (vid, eid)) in self.vertices_adj_to_face[i1 as usize..i2 as usize]
555            .iter()
556            .zip(self.edges_adj_to_face[i1 as usize..i2 as usize].iter())
557            .enumerate()
558        {
559            out_feature.vertices[i] = self.points[*vid as usize];
560            out_feature.vids[i] = PackedFeatureId::vertex(*vid);
561            out_feature.eids[i] = PackedFeatureId::edge(*eid);
562        }
563
564        out_feature.fid = PackedFeatureId::face(best_fid as u32);
565        out_feature.num_vertices = num_vertices as usize;
566    }
567
568    fn is_convex_polyhedron(&self) -> bool {
569        true
570    }
571}
572
573/*
574impl ConvexPolyhedron for ConvexPolyhedron {
575    fn vertex(&self, id: FeatureId) -> Point<Real> {
576        self.points[id.unwrap_vertex() as usize]
577    }
578
579    fn edge(&self, id: FeatureId) -> (Point<Real>, Point<Real>, FeatureId, FeatureId) {
580        let edge = &self.edges[id.unwrap_edge() as usize];
581        let v1 = edge.vertices[0];
582        let v2 = edge.vertices[1];
583
584        (
585            self.points[v1 as usize],
586            self.points[v2 as usize],
587            FeatureId::Vertex(v1),
588            FeatureId::Vertex(v2),
589        )
590    }
591
592    fn face(&self, id: FeatureId, out: &mut ConvexPolygonalFeature) {
593        out.clear();
594
595        let face = &self.faces[id.unwrap_face() as usize];
596        let first_vertex = face.first_vertex_or_edge;
597        let last_vertex = face.first_vertex_or_edge + face.num_vertices_or_edges;
598
599        for i in first_vertex..last_vertex {
600            let vid = self.vertices_adj_to_face[i];
601            let eid = self.edges_adj_to_face[i];
602            out.push(self.points[vid], FeatureId::Vertex(vid));
603            out.push_edge_feature_id(FeatureId::Edge(eid));
604        }
605
606        out.set_normal(face.normal);
607        out.set_feature_id(id);
608        out.recompute_edge_normals();
609    }
610
611    fn support_face_toward(
612        &self,
613        m: &Isometry<Real>,
614        dir: &Unit<Vector<Real>>,
615        out: &mut ConvexPolygonalFeature,
616    ) {
617        let ls_dir = m.inverse_transform_vector(dir);
618        let mut best_face = 0;
619        let mut max_dot = self.faces[0].normal.dot(&ls_dir);
620
621        for i in 1..self.faces.len() {
622            let face = &self.faces[i];
623            let dot = face.normal.dot(&ls_dir);
624
625            if dot > max_dot {
626                max_dot = dot;
627                best_face = i;
628            }
629        }
630
631        self.face(FeatureId::Face(best_face), out);
632        out.transform_by(m);
633    }
634
635    fn support_feature_toward(
636        &self,
637        transform: &Isometry<Real>,
638        dir: &Unit<Vector<Real>>,
639        angle: Real,
640        out: &mut ConvexPolygonalFeature,
641    ) {
642        out.clear();
643        let local_dir = transform.inverse_transform_unit_vector(dir);
644        let fid = self.support_feature_id_toward_eps(&local_dir, angle);
645
646        match fid {
647            FeatureId::Vertex(_) => {
648                let v = self.vertex(fid);
649                out.push(v, fid);
650                out.set_feature_id(fid);
651            }
652            FeatureId::Edge(_) => {
653                let edge = self.edge(fid);
654                out.push(edge.0, edge.2);
655                out.push(edge.1, edge.3);
656                out.set_feature_id(fid);
657                out.push_edge_feature_id(fid);
658            }
659            FeatureId::Face(_) => self.face(fid, out),
660            FeatureId::Unknown => unreachable!(),
661        }
662
663        out.transform_by(transform);
664    }
665}
666*/