cg_math/validation/
mod.rs1extern crate nalgebra as na;
2use crate::geometry::{TriangleLogic, WeightedTriangle, WeightedVertex, Triangulation};
3use na::Point2;
4extern crate parry2d_f64 as parry;
5
6#[derive(PartialEq)]
8pub struct TriangulationMetrics {
9 pub area: f64,
10 pub area3d: f64,
11 pub c_hull: f64,
12 pub epsilon: f64,
13 pub num_simplices: usize,
14 pub regularity: f64,
15 pub runtime: f64,
16}
17
18#[derive(Debug, PartialEq)]
20pub struct EqualTriangleMetric {
21 pub equal_triangles: Vec<WeightedTriangle>,
22 pub different_triangles: Vec<WeightedTriangle>,
23 pub true_triangle_ratio: f64,
24
25}
26
27impl EqualTriangleMetric {
28 pub fn new(triangulation: &Triangulation, baseline_triangulation: &Triangulation) -> Self {
30 let mut equal_triangles: Vec<WeightedTriangle> = vec![];
31 let mut different_triangles: Vec<WeightedTriangle> = vec![];
32
33 for triangle in triangulation.triangles() {
34 let mut not_in_baseline = true;
35 for base_triangle in baseline_triangulation.triangles() {
36 if triangle == base_triangle {
37 equal_triangles.push(*triangle);
38 not_in_baseline = false;
39 break;
40 }
41 }
42 if not_in_baseline {
43 different_triangles.push(*triangle);
44 }
45 }
46
47 let true_triangle_ratio = equal_triangles.len() as f64 / baseline_triangulation.triangles().len() as f64 * 100.0;
48
49 Self {
50 equal_triangles,
51 different_triangles,
52 true_triangle_ratio,
53 }
54 }
55
56 pub fn empty() -> Self {
58 Self {
59 equal_triangles: vec![],
60 different_triangles: vec![],
61 true_triangle_ratio: 0.0,
62 }
63 }
64}
65
66pub fn compute_metrics(
68 vertices: &Vec<WeightedVertex>,
69 triangles: &Vec<WeightedTriangle>,
70 epsilon: f64,
71 runtime: f64,
72) -> TriangulationMetrics {
73 let regularity = all_globally_regular(vertices, triangles);
74 let is_c_hull = is_c_hull(vertices, triangles);
75 let area = summed_area(triangles);
76 let area3d = summed_area3d(triangles);
77
78 TriangulationMetrics {
79 epsilon,
80 num_simplices: triangles.len(),
81 c_hull: is_c_hull as i32 as f64,
82 regularity,
83 area,
84 area3d,
85 runtime,
86 }
87}
88
89pub fn all_globally_regular(
93 vertices: &Vec<WeightedVertex>,
94 triangles: &Vec<WeightedTriangle>,
95) -> f64 {
96 let mut n_invalid_triangles = 0.0;
97
98 for triangle in triangles.iter() {
99 for vertex in vertices {
100 if !triangle.has_vertex(vertex) && !triangle.is_regular(vertex) {
101 n_invalid_triangles += 1.0;
102 break;
103 }
104 }
105 }
106 1.0 - n_invalid_triangles / triangles.len() as f64
107}
108
109pub fn is_c_hull(vertices: &[WeightedVertex], triangles: &[WeightedTriangle]) -> bool {
112 let input_points2d: Vec<Point2<f64>> =
113 vertices.iter().map(|v| Point2::new(v.x(), v.y())).collect();
114 let input_points_hull = parry::transformation::convex_hull(&input_points2d);
115
116 let triangulation_border_points2d: Vec<Point2<f64>> = get_boundary_points(triangles);
117
118 triangulation_border_points2d
123 .iter()
124 .all(|item| input_points_hull.contains(item))
125}
126
127fn get_boundary_points(triangulation: &[WeightedTriangle]) -> Vec<Point2<f64>> {
130 let copied_triangulation1 = triangulation.to_owned();
132 let mut border_points: Vec<Point2<f64>> = vec![]; for triangle1 in copied_triangulation1 {
135 for edge1 in triangle1.edges() {
136 let mut is_border_edge = true;
137
138 let copied_triangulation2 = triangulation.to_owned();
139 for triangle2 in copied_triangulation2 {
140 if triangle1 != triangle2 {
141 for edge2 in triangle2.edges() {
143 if edge1 == edge2 {
144 is_border_edge = false;
145 }
146 }
147 }
148 }
149
150 if is_border_edge {
151 let mut a_unique = true;
152 let mut b_unique = true;
153 for point in border_points.clone() {
154 if point == Point2::new(edge1.a.x(), edge1.a.y()) {
155 a_unique = false;
156 }
157 if point == Point2::new(edge1.b.x(), edge1.b.y()) {
158 b_unique = false;
159 }
160 }
161
162 if a_unique {
163 border_points.push(Point2::new(edge1.a.x(), edge1.a.y()));
164 }
165 if b_unique {
166 border_points.push(Point2::new(edge1.b.x(), edge1.b.y()))
167 }
168 }
169 }
170 }
171 border_points
172}
173
174pub fn summed_area(triangulation: &[WeightedTriangle]) -> f64 {
177 triangulation
178 .iter()
179 .fold(0.0, |sum, triangle| sum + triangle.area())
180}
181
182
183pub fn summed_area3d(triangulation: &[WeightedTriangle]) -> f64 {
186 triangulation
187 .iter()
188 .fold(0.0, |sum, triangle| sum + triangle.area3d())
189}