1#![allow(dead_code)]
4
5#[allow(dead_code)]
9#[derive(Debug, Clone, Copy)]
10pub struct CollisionTriangle {
11 pub v0: [f32; 3],
12 pub v1: [f32; 3],
13 pub v2: [f32; 3],
14 pub material_id: u32,
15}
16
17#[allow(dead_code)]
19#[derive(Debug, Clone)]
20pub struct CollisionTriangleExport {
21 pub triangles: Vec<CollisionTriangle>,
22}
23
24#[allow(dead_code)]
26pub fn from_mesh(
27 positions: &[[f32; 3]],
28 indices: &[u32],
29 material_id: u32,
30) -> CollisionTriangleExport {
31 let tri_count = indices.len() / 3;
32 let mut triangles = Vec::with_capacity(tri_count);
33 for t in 0..tri_count {
34 let i0 = indices[t * 3] as usize;
35 let i1 = indices[t * 3 + 1] as usize;
36 let i2 = indices[t * 3 + 2] as usize;
37 if i0 < positions.len() && i1 < positions.len() && i2 < positions.len() {
38 triangles.push(CollisionTriangle {
39 v0: positions[i0],
40 v1: positions[i1],
41 v2: positions[i2],
42 material_id,
43 });
44 }
45 }
46 CollisionTriangleExport { triangles }
47}
48
49#[allow(dead_code)]
51pub fn collision_tri_count(export: &CollisionTriangleExport) -> usize {
52 export.triangles.len()
53}
54
55#[allow(dead_code)]
57pub fn triangle_area_ct(tri: &CollisionTriangle) -> f32 {
58 let e1 = [
59 tri.v1[0] - tri.v0[0],
60 tri.v1[1] - tri.v0[1],
61 tri.v1[2] - tri.v0[2],
62 ];
63 let e2 = [
64 tri.v2[0] - tri.v0[0],
65 tri.v2[1] - tri.v0[1],
66 tri.v2[2] - tri.v0[2],
67 ];
68 let cross = [
69 e1[1] * e2[2] - e1[2] * e2[1],
70 e1[2] * e2[0] - e1[0] * e2[2],
71 e1[0] * e2[1] - e1[1] * e2[0],
72 ];
73 (cross[0] * cross[0] + cross[1] * cross[1] + cross[2] * cross[2]).sqrt() * 0.5
74}
75
76#[allow(dead_code)]
78pub fn total_collision_area(export: &CollisionTriangleExport) -> f32 {
79 export.triangles.iter().map(triangle_area_ct).sum()
80}
81
82#[allow(dead_code)]
84pub fn triangles_for_material(export: &CollisionTriangleExport, material_id: u32) -> usize {
85 export
86 .triangles
87 .iter()
88 .filter(|t| t.material_id == material_id)
89 .count()
90}
91
92#[allow(dead_code)]
94pub fn collision_triangle_to_json(export: &CollisionTriangleExport) -> String {
95 format!(
96 "{{\"triangle_count\":{},\"total_area\":{:.4}}}",
97 export.triangles.len(),
98 total_collision_area(export)
99 )
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105
106 fn unit_tri_export() -> CollisionTriangleExport {
107 from_mesh(
108 &[[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]],
109 &[0, 1, 2],
110 0,
111 )
112 }
113
114 #[test]
115 fn test_from_mesh_count() {
116 assert_eq!(collision_tri_count(&unit_tri_export()), 1);
117 }
118
119 #[test]
120 fn test_triangle_area_positive() {
121 let t = CollisionTriangle {
122 v0: [0.0, 0.0, 0.0],
123 v1: [1.0, 0.0, 0.0],
124 v2: [0.0, 1.0, 0.0],
125 material_id: 0,
126 };
127 assert!(triangle_area_ct(&t) > 0.0);
128 }
129
130 #[test]
131 fn test_total_area_positive() {
132 let e = unit_tri_export();
133 assert!(total_collision_area(&e) > 0.0);
134 }
135
136 #[test]
137 fn test_triangles_for_material() {
138 let e = unit_tri_export();
139 assert_eq!(triangles_for_material(&e, 0), 1);
140 }
141
142 #[test]
143 fn test_triangles_for_wrong_material() {
144 let e = unit_tri_export();
145 assert_eq!(triangles_for_material(&e, 1), 0);
146 }
147
148 #[test]
149 fn test_empty_export() {
150 let e = from_mesh(&[], &[], 0);
151 assert_eq!(collision_tri_count(&e), 0);
152 }
153
154 #[test]
155 fn test_collision_triangle_to_json() {
156 let e = unit_tri_export();
157 let j = collision_triangle_to_json(&e);
158 assert!(j.contains("triangle_count"));
159 }
160
161 #[test]
162 fn test_oob_indices_skipped() {
163 let pos = vec![[0.0, 0.0, 0.0], [1.0, 0.0, 0.0]];
164 let idx = vec![0u32, 1, 99];
165 let e = from_mesh(&pos, &idx, 0);
166 assert_eq!(collision_tri_count(&e), 0);
167 }
168
169 #[test]
170 fn test_area_unit_right_triangle() {
171 let t = CollisionTriangle {
172 v0: [0.0, 0.0, 0.0],
173 v1: [2.0, 0.0, 0.0],
174 v2: [0.0, 2.0, 0.0],
175 material_id: 0,
176 };
177 assert!((triangle_area_ct(&t) - 2.0).abs() < 1e-5);
178 }
179
180 #[test]
181 fn test_total_area_two_tris() {
182 let pos = vec![
183 [0.0, 0.0, 0.0],
184 [1.0, 0.0, 0.0],
185 [0.0, 1.0, 0.0],
186 [2.0, 0.0, 0.0],
187 [3.0, 0.0, 0.0],
188 [2.0, 1.0, 0.0],
189 ];
190 let idx = vec![0u32, 1, 2, 3, 4, 5];
191 let e = from_mesh(&pos, &idx, 0);
192 assert!(total_collision_area(&e) > 0.5);
193 }
194}