oxihuman_export/
threedxml_export.rs1#![allow(dead_code)]
4
5#[derive(Debug, Clone)]
11pub struct ThreeDXmlOccurrence {
12 pub id: u32,
13 pub name: String,
14 pub matrix: [[f32; 4]; 4],
15}
16
17#[derive(Debug, Clone)]
19pub struct ThreeDXmlRep {
20 pub id: u32,
21 pub verts: Vec<[f32; 3]>,
22 pub tris: Vec<[u32; 3]>,
23}
24
25#[derive(Debug, Clone, Default)]
27pub struct ThreeDXmlExport {
28 pub schema_version: String,
29 pub occurrences: Vec<ThreeDXmlOccurrence>,
30 pub reps: Vec<ThreeDXmlRep>,
31}
32
33pub fn new_threedxml_export(schema_version: &str) -> ThreeDXmlExport {
35 ThreeDXmlExport {
36 schema_version: schema_version.to_string(),
37 occurrences: Vec::new(),
38 reps: Vec::new(),
39 }
40}
41
42pub fn add_threedxml_occurrence(export: &mut ThreeDXmlExport, name: &str) -> u32 {
44 let id = export.occurrences.len() as u32 + 1;
45 let matrix = [
46 [1.0, 0.0, 0.0, 0.0],
47 [0.0, 1.0, 0.0, 0.0],
48 [0.0, 0.0, 1.0, 0.0],
49 [0.0, 0.0, 0.0, 1.0],
50 ];
51 export.occurrences.push(ThreeDXmlOccurrence {
52 id,
53 name: name.to_string(),
54 matrix,
55 });
56 id
57}
58
59pub fn add_threedxml_rep(
61 export: &mut ThreeDXmlExport,
62 verts: Vec<[f32; 3]>,
63 tris: Vec<[u32; 3]>,
64) -> u32 {
65 let id = export.reps.len() as u32 + 1;
66 export.reps.push(ThreeDXmlRep { id, verts, tris });
67 id
68}
69
70pub fn threedxml_occurrence_count(export: &ThreeDXmlExport) -> usize {
72 export.occurrences.len()
73}
74
75pub fn threedxml_rep_count(export: &ThreeDXmlExport) -> usize {
77 export.reps.len()
78}
79
80pub fn threedxml_xml_header(export: &ThreeDXmlExport) -> String {
82 format!(
83 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<XPDMRoot schemaVersion=\"{}\">",
84 export.schema_version
85 )
86}
87
88pub fn validate_threedxml(export: &ThreeDXmlExport) -> bool {
90 export.reps.iter().all(|rep| {
91 let n = rep.verts.len() as u32;
92 rep.tris.iter().all(|t| t[0] < n && t[1] < n && t[2] < n)
93 })
94}
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99
100 #[test]
101 fn test_new_export_empty() {
102 let exp = new_threedxml_export("4.0");
103 assert_eq!(threedxml_occurrence_count(&exp), 0);
104 assert_eq!(threedxml_rep_count(&exp), 0);
105 }
106
107 #[test]
108 fn test_add_occurrence() {
109 let mut exp = new_threedxml_export("4.0");
110 let id = add_threedxml_occurrence(&mut exp, "Part1");
111 assert_eq!(id, 1);
112 assert_eq!(threedxml_occurrence_count(&exp), 1);
113 }
114
115 #[test]
116 fn test_add_rep() {
117 let mut exp = new_threedxml_export("4.0");
118 let v = vec![[0.0f32; 3]; 3];
119 let t = vec![[0u32, 1, 2]];
120 let id = add_threedxml_rep(&mut exp, v, t);
121 assert_eq!(id, 1);
122 }
123
124 #[test]
125 fn test_xml_header_contains_schema() {
126 let exp = new_threedxml_export("4.0");
127 assert!(threedxml_xml_header(&exp).contains("4.0"));
128 }
129
130 #[test]
131 fn test_validate_valid() {
132 let mut exp = new_threedxml_export("4.0");
133 let v = vec![[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]];
134 let t = vec![[0u32, 1, 2]];
135 add_threedxml_rep(&mut exp, v, t);
136 assert!(validate_threedxml(&exp));
137 }
138
139 #[test]
140 fn test_occurrence_name_stored() {
141 let mut exp = new_threedxml_export("4.0");
142 add_threedxml_occurrence(&mut exp, "MyPart");
143 assert_eq!(exp.occurrences[0].name, "MyPart");
144 }
145
146 #[test]
147 fn test_identity_matrix() {
148 let mut exp = new_threedxml_export("4.0");
149 add_threedxml_occurrence(&mut exp, "X");
150 let m = exp.occurrences[0].matrix;
151 #[allow(clippy::needless_range_loop)]
152 for i in 0..4 {
153 assert!((m[i][i] - 1.0).abs() < 1e-6);
154 }
155 }
156
157 #[test]
158 fn test_schema_version_stored() {
159 let exp = new_threedxml_export("5.0");
160 assert_eq!(exp.schema_version, "5.0");
161 }
162
163 #[test]
164 fn test_validate_empty() {
165 assert!(validate_threedxml(&new_threedxml_export("4.0")));
166 }
167
168 #[test]
169 fn test_multiple_occurrences() {
170 let mut exp = new_threedxml_export("4.0");
171 for name in ["A", "B", "C"] {
172 add_threedxml_occurrence(&mut exp, name);
173 }
174 assert_eq!(threedxml_occurrence_count(&exp), 3);
175 }
176}