bimifc_parser/ifcx/
types.rs1use serde::Deserialize;
11use std::collections::HashMap;
12
13#[derive(Debug, Deserialize)]
15pub struct IfcxFile {
16 pub header: IfcxHeader,
17 #[serde(default)]
18 pub imports: Vec<ImportNode>,
19 #[serde(default)]
20 pub schemas: HashMap<String, serde_json::Value>,
21 pub data: Vec<IfcxNode>,
22}
23
24#[derive(Debug, Deserialize)]
26#[serde(rename_all = "camelCase")]
27pub struct IfcxHeader {
28 pub id: String,
29 pub ifcx_version: String,
30 pub data_version: String,
31 #[serde(default)]
32 pub author: String,
33 #[serde(default)]
34 pub timestamp: String,
35}
36
37#[derive(Debug, Deserialize)]
39pub struct ImportNode {
40 pub uri: String,
41 #[serde(default)]
42 pub integrity: Option<String>,
43}
44
45#[derive(Debug, Deserialize)]
47pub struct IfcxNode {
48 pub path: String,
49 #[serde(default)]
50 pub children: HashMap<String, Option<String>>,
51 #[serde(default)]
52 pub inherits: HashMap<String, Option<String>>,
53 #[serde(default)]
54 pub attributes: HashMap<String, serde_json::Value>,
55}
56
57#[derive(Debug, Clone)]
59pub struct ComposedNode {
60 pub path: String,
61 pub attributes: rustc_hash::FxHashMap<String, serde_json::Value>,
62 pub children: Vec<String>, pub parent: Option<String>, }
65
66pub mod attr {
68 pub const CLASS: &str = "bsi::ifc::class";
70 pub const MESH: &str = "usd::usdgeom::mesh";
72 pub const TRANSFORM: &str = "usd::xformop::transform";
74 pub const VISIBILITY: &str = "usd::usdgeom::visibility";
76 pub const DIFFUSE_COLOR: &str = "bsi::ifc::presentation::diffuseColor";
78 pub const OPACITY: &str = "bsi::ifc::presentation::opacity";
80 pub const MATERIAL: &str = "bsi::ifc::material";
82 pub const PROP_PREFIX: &str = "bsi::ifc::prop::";
84}
85
86#[derive(Debug, Clone, Default)]
88pub struct UsdMesh {
89 pub points: Vec<[f64; 3]>,
90 pub face_vertex_indices: Vec<u32>,
91 pub face_vertex_counts: Option<Vec<u32>>,
92 pub normals: Option<Vec<[f64; 3]>>,
93}
94
95impl UsdMesh {
96 pub fn from_value(value: &serde_json::Value) -> Option<Self> {
98 let obj = value.as_object()?;
99
100 let points_arr = obj.get("points")?.as_array()?;
102 let mut points = Vec::with_capacity(points_arr.len());
103 for p in points_arr {
104 let arr = p.as_array()?;
105 if arr.len() >= 3 {
106 points.push([arr[0].as_f64()?, arr[1].as_f64()?, arr[2].as_f64()?]);
107 }
108 }
109
110 let indices_arr = obj.get("faceVertexIndices")?.as_array()?;
112 let mut face_vertex_indices = Vec::with_capacity(indices_arr.len());
113 for i in indices_arr {
114 face_vertex_indices.push(i.as_u64()? as u32);
115 }
116
117 let face_vertex_counts = obj.get("faceVertexCounts").and_then(|v| {
119 let arr = v.as_array()?;
120 let mut counts = Vec::with_capacity(arr.len());
121 for c in arr {
122 counts.push(c.as_u64()? as u32);
123 }
124 Some(counts)
125 });
126
127 let normals = obj.get("normals").and_then(|v| {
129 let arr = v.as_array()?;
130 let mut norms = Vec::with_capacity(arr.len());
131 for n in arr {
132 let narr = n.as_array()?;
133 if narr.len() >= 3 {
134 norms.push([narr[0].as_f64()?, narr[1].as_f64()?, narr[2].as_f64()?]);
135 }
136 }
137 Some(norms)
138 });
139
140 Some(Self {
141 points,
142 face_vertex_indices,
143 face_vertex_counts,
144 normals,
145 })
146 }
147
148 pub fn is_triangulated(&self) -> bool {
150 match &self.face_vertex_counts {
151 None => true, Some(counts) => counts.iter().all(|&c| c == 3),
153 }
154 }
155
156 pub fn triangulate(&self) -> Vec<u32> {
158 if self.is_triangulated() {
159 return self.face_vertex_indices.clone();
160 }
161
162 let counts = self.face_vertex_counts.as_ref().unwrap();
163 let mut result = Vec::new();
164 let mut idx = 0usize;
165
166 for &count in counts {
167 let count = count as usize;
168 if count == 3 {
169 result.push(self.face_vertex_indices[idx]);
171 result.push(self.face_vertex_indices[idx + 1]);
172 result.push(self.face_vertex_indices[idx + 2]);
173 } else if count > 3 {
174 let v0 = self.face_vertex_indices[idx];
176 for i in 1..(count - 1) {
177 result.push(v0);
178 result.push(self.face_vertex_indices[idx + i]);
179 result.push(self.face_vertex_indices[idx + i + 1]);
180 }
181 }
182 idx += count;
183 }
184
185 result
186 }
187}
188
189#[derive(Debug, Clone)]
191pub struct IfcClass {
192 pub code: String,
193 pub uri: Option<String>,
194}
195
196impl IfcClass {
197 pub fn from_value(value: &serde_json::Value) -> Option<Self> {
199 let obj = value.as_object()?;
200 let code = obj.get("code")?.as_str()?.to_string();
201 let uri = obj.get("uri").and_then(|v| v.as_str()).map(String::from);
202 Some(Self { code, uri })
203 }
204}
205
206#[derive(Debug, Clone, Copy)]
208pub struct Transform4x4 {
209 pub matrix: [[f64; 4]; 4],
210}
211
212impl Default for Transform4x4 {
213 fn default() -> Self {
214 Self::identity()
215 }
216}
217
218impl Transform4x4 {
219 pub fn identity() -> Self {
220 Self {
221 matrix: [
222 [1.0, 0.0, 0.0, 0.0],
223 [0.0, 1.0, 0.0, 0.0],
224 [0.0, 0.0, 1.0, 0.0],
225 [0.0, 0.0, 0.0, 1.0],
226 ],
227 }
228 }
229
230 pub fn from_value(value: &serde_json::Value) -> Option<Self> {
232 let arr = if let Some(obj) = value.as_object() {
234 obj.get("transform")?.as_array()?
235 } else {
236 value.as_array()?
237 };
238
239 if arr.len() != 4 {
240 return None;
241 }
242
243 let mut matrix = [[0.0; 4]; 4];
244 for (i, row) in arr.iter().enumerate() {
245 let row_arr = row.as_array()?;
246 if row_arr.len() != 4 {
247 return None;
248 }
249 for (j, val) in row_arr.iter().enumerate() {
250 matrix[i][j] = val.as_f64()?;
251 }
252 }
253
254 Some(Self { matrix })
255 }
256
257 pub fn transform_point(&self, point: [f64; 3]) -> [f64; 3] {
259 let m = &self.matrix;
260 let w = m[3][0] * point[0] + m[3][1] * point[1] + m[3][2] * point[2] + m[3][3];
261 [
262 (m[0][0] * point[0] + m[0][1] * point[1] + m[0][2] * point[2] + m[0][3]) / w,
263 (m[1][0] * point[0] + m[1][1] * point[1] + m[1][2] * point[2] + m[1][3]) / w,
264 (m[2][0] * point[0] + m[2][1] * point[1] + m[2][2] * point[2] + m[2][3]) / w,
265 ]
266 }
267
268 pub fn multiply(&self, other: &Self) -> Self {
270 let mut result = [[0.0; 4]; 4];
271 #[allow(clippy::needless_range_loop)]
272 for i in 0..4 {
273 for j in 0..4 {
274 for k in 0..4 {
275 result[i][j] += self.matrix[i][k] * other.matrix[k][j];
276 }
277 }
278 }
279 Self { matrix: result }
280 }
281}