parry3d_f64/transformation/convex_hull3/
validation.rs

1#[cfg(feature = "std")]
2use super::ConvexHullError;
3use super::TriangleFacet;
4#[cfg(feature = "std")]
5use crate::math::Vector3;
6
7pub fn check_facet_links(ifacet: usize, facets: &[TriangleFacet]) {
8    let facet = &facets[ifacet];
9
10    for i in 0..3 {
11        assert!(facets[facet.adj[i]].valid);
12    }
13
14    for i in 0..3 {
15        let adj_facet = &facets[facet.adj[i]];
16
17        assert_eq!(adj_facet.adj[facet.indirect_adj_id[i]], ifacet);
18        assert_eq!(adj_facet.indirect_adj_id[facet.indirect_adj_id[i]], i);
19        assert_eq!(
20            adj_facet.first_point_from_edge(facet.indirect_adj_id[i]),
21            facet.second_point_from_edge(i)
22        );
23        assert_eq!(
24            adj_facet.second_point_from_edge(facet.indirect_adj_id[i]),
25            facet.first_point_from_edge(i)
26        );
27    }
28}
29
30/// Checks if a convex-hull is properly formed.
31#[cfg(feature = "std")]
32pub fn check_convex_hull(
33    points: &[Vector3],
34    triangles: &[[u32; 3]],
35) -> Result<(), ConvexHullError> {
36    use crate::utils::hashmap::{Entry, HashMap};
37    use crate::utils::SortedPair;
38    let mut edges = HashMap::default();
39
40    struct EdgeData {
41        adjacent_triangles: [usize; 2],
42    }
43
44    // println!(
45    //     "Investigating with {} triangles, and {} points.",
46    //     triangles.len(),
47    //     points.len()
48    // );
49    // print_buildable_vec("vertices", points);
50    // print_buildable_vec("indices", triangles);
51
52    for i in 0..points.len() {
53        for j in i + 1..points.len() {
54            if points[i] == points[j] {
55                return Err(ConvexHullError::DuplicatePoints(i, j));
56            }
57        }
58    }
59
60    for (itri, tri) in triangles.iter().enumerate() {
61        assert!(tri[0] != tri[1]);
62        assert!(tri[0] != tri[2]);
63        assert!(tri[2] != tri[1]);
64
65        for i in 0..3 {
66            let ivtx1 = tri[i as usize];
67            let ivtx2 = tri[(i as usize + 1) % 3];
68            let edge_key = SortedPair::new(ivtx1, ivtx2);
69
70            match edges.entry(edge_key) {
71                Entry::Vacant(e) => {
72                    let _ = e.insert(EdgeData {
73                        adjacent_triangles: [itri, usize::MAX],
74                    });
75                }
76                Entry::Occupied(mut e) => {
77                    if e.get().adjacent_triangles[1] != usize::MAX {
78                        return Err(ConvexHullError::TJunction(itri, ivtx1, ivtx2));
79                    }
80
81                    e.get_mut().adjacent_triangles[1] = itri;
82                }
83            }
84        }
85    }
86
87    for edge in &edges {
88        if edge.1.adjacent_triangles[1] == usize::MAX {
89            return Err(ConvexHullError::UnfinishedTriangle);
90        }
91    }
92
93    // Check Euler characteristic.
94    assert_eq!(points.len() + triangles.len() - edges.len(), 2);
95
96    Ok(())
97}
98
99// fn print_buildable_vec<T: core::fmt::Display + na::Scalar>(desc: &str, elts: &[Vector3<T>]) {
100//     print!("let {} = vec![", desc);
101//     for elt in elts {
102//         print!("Vector::new({},{},{}),", elt.x, elt.y, elt.z);
103//     }
104//     println!("];")
105// }