parry3d/transformation/convex_hull3/
validation.rs

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