1use crate::error::{Error, Result};
11use crate::mesh::Mesh;
12use ifc_lite_core::{DecodedEntity, EntityDecoder, IfcType};
13use nalgebra::{Matrix4, Point3, Vector3};
14
15pub fn parse_axis2_placement_3d(
25 placement: &DecodedEntity,
26 decoder: &mut EntityDecoder,
27) -> Result<Matrix4<f64>> {
28 let location = parse_cartesian_point(placement, decoder, 0)?;
30
31 let z_axis = if let Some(axis_attr) = placement.get(1) {
33 if !axis_attr.is_null() {
34 if let Some(axis_entity) = decoder.resolve_ref(axis_attr)? {
35 parse_direction(&axis_entity)?
36 } else {
37 Vector3::new(0.0, 0.0, 1.0)
38 }
39 } else {
40 Vector3::new(0.0, 0.0, 1.0)
41 }
42 } else {
43 Vector3::new(0.0, 0.0, 1.0)
44 };
45
46 let x_axis = if let Some(ref_dir_attr) = placement.get(2) {
48 if !ref_dir_attr.is_null() {
49 if let Some(ref_dir_entity) = decoder.resolve_ref(ref_dir_attr)? {
50 parse_direction(&ref_dir_entity)?
51 } else {
52 Vector3::new(1.0, 0.0, 0.0)
53 }
54 } else {
55 Vector3::new(1.0, 0.0, 0.0)
56 }
57 } else {
58 Vector3::new(1.0, 0.0, 0.0)
59 };
60
61 let z_axis_final = z_axis.normalize();
63 let x_axis_normalized = x_axis.normalize();
64
65 let dot_product = x_axis_normalized.dot(&z_axis_final);
67 let x_axis_orthogonal = x_axis_normalized - z_axis_final * dot_product;
68 let x_axis_final = if x_axis_orthogonal.norm() > 1e-6 {
69 x_axis_orthogonal.normalize()
70 } else {
71 if z_axis_final.z.abs() < 0.9 {
73 Vector3::new(0.0, 0.0, 1.0).cross(&z_axis_final).normalize()
74 } else {
75 Vector3::new(1.0, 0.0, 0.0).cross(&z_axis_final).normalize()
76 }
77 };
78
79 let y_axis = z_axis_final.cross(&x_axis_final).normalize();
81
82 let mut transform = Matrix4::identity();
85 transform[(0, 0)] = x_axis_final.x;
86 transform[(1, 0)] = x_axis_final.y;
87 transform[(2, 0)] = x_axis_final.z;
88 transform[(0, 1)] = y_axis.x;
89 transform[(1, 1)] = y_axis.y;
90 transform[(2, 1)] = y_axis.z;
91 transform[(0, 2)] = z_axis_final.x;
92 transform[(1, 2)] = z_axis_final.y;
93 transform[(2, 2)] = z_axis_final.z;
94 transform[(0, 3)] = location.x;
95 transform[(1, 3)] = location.y;
96 transform[(2, 3)] = location.z;
97
98 Ok(transform)
99}
100
101pub fn parse_cartesian_point(
105 parent: &DecodedEntity,
106 decoder: &mut EntityDecoder,
107 attr_index: usize,
108) -> Result<Point3<f64>> {
109 let point_attr = parent
110 .get(attr_index)
111 .ok_or_else(|| Error::geometry("Missing cartesian point".to_string()))?;
112
113 if let Some(point_id) = point_attr.as_entity_ref() {
115 if let Some((x, y, z)) = decoder.get_cartesian_point_fast(point_id) {
116 return Ok(Point3::new(x, y, z));
117 }
118 }
119
120 let point_entity = decoder
122 .resolve_ref(point_attr)?
123 .ok_or_else(|| Error::geometry("Failed to resolve cartesian point".to_string()))?;
124
125 if point_entity.ifc_type != IfcType::IfcCartesianPoint {
126 return Err(Error::geometry(format!(
127 "Expected IfcCartesianPoint, got {}",
128 point_entity.ifc_type
129 )));
130 }
131
132 let coords_attr = point_entity
134 .get(0)
135 .ok_or_else(|| Error::geometry("IfcCartesianPoint missing coordinates".to_string()))?;
136
137 let coords = coords_attr
138 .as_list()
139 .ok_or_else(|| Error::geometry("Expected coordinate list".to_string()))?;
140
141 let x = coords.first().and_then(|v| v.as_float()).unwrap_or(0.0);
142 let y = coords.get(1).and_then(|v| v.as_float()).unwrap_or(0.0);
143 let z = coords.get(2).and_then(|v| v.as_float()).unwrap_or(0.0);
144
145 Ok(Point3::new(x, y, z))
146}
147
148pub fn parse_cartesian_point_from_id(
152 point_id: u32,
153 decoder: &mut EntityDecoder,
154) -> Result<Point3<f64>> {
155 if let Some((x, y, z)) = decoder.get_cartesian_point_fast(point_id) {
157 return Ok(Point3::new(x, y, z));
158 }
159
160 let point_entity = decoder.decode_by_id(point_id)?;
162
163 if point_entity.ifc_type != IfcType::IfcCartesianPoint {
164 return Err(Error::geometry(format!(
165 "Expected IfcCartesianPoint, got {}",
166 point_entity.ifc_type
167 )));
168 }
169
170 let coords_attr = point_entity
172 .get(0)
173 .ok_or_else(|| Error::geometry("IfcCartesianPoint missing coordinates".to_string()))?;
174
175 let coords = coords_attr
176 .as_list()
177 .ok_or_else(|| Error::geometry("Expected coordinate list".to_string()))?;
178
179 let x = coords.first().and_then(|v| v.as_float()).unwrap_or(0.0);
180 let y = coords.get(1).and_then(|v| v.as_float()).unwrap_or(0.0);
181 let z = coords.get(2).and_then(|v| v.as_float()).unwrap_or(0.0);
182
183 Ok(Point3::new(x, y, z))
184}
185
186pub fn parse_direction_from_id(dir_id: u32, decoder: &mut EntityDecoder) -> Result<Vector3<f64>> {
190 let dir = decoder.decode_by_id(dir_id)?;
191 parse_direction(&dir)
192}
193
194pub fn parse_axis2_placement_3d_from_id(
198 placement_id: u32,
199 decoder: &mut EntityDecoder,
200) -> Result<Matrix4<f64>> {
201 let placement = decoder.decode_by_id(placement_id)?;
202
203 let location = if let Some(loc_attr) = placement.get(0) {
205 if let Some(loc_id) = loc_attr.as_entity_ref() {
206 parse_cartesian_point_from_id(loc_id, decoder)?
207 } else {
208 Point3::new(0.0, 0.0, 0.0)
209 }
210 } else {
211 Point3::new(0.0, 0.0, 0.0)
212 };
213
214 let z_axis = if let Some(axis_attr) = placement.get(1) {
216 if !axis_attr.is_null() {
217 if let Some(axis_id) = axis_attr.as_entity_ref() {
218 parse_direction_from_id(axis_id, decoder)?
219 } else {
220 Vector3::new(0.0, 0.0, 1.0)
221 }
222 } else {
223 Vector3::new(0.0, 0.0, 1.0)
224 }
225 } else {
226 Vector3::new(0.0, 0.0, 1.0)
227 };
228
229 let x_axis = if let Some(ref_dir_attr) = placement.get(2) {
231 if !ref_dir_attr.is_null() {
232 if let Some(ref_dir_id) = ref_dir_attr.as_entity_ref() {
233 parse_direction_from_id(ref_dir_id, decoder)?
234 } else {
235 Vector3::new(1.0, 0.0, 0.0)
236 }
237 } else {
238 Vector3::new(1.0, 0.0, 0.0)
239 }
240 } else {
241 Vector3::new(1.0, 0.0, 0.0)
242 };
243
244 let z_axis_final = z_axis.normalize();
246 let x_axis_normalized = x_axis.normalize();
247
248 let dot_product = x_axis_normalized.dot(&z_axis_final);
250 let x_axis_orthogonal = x_axis_normalized - z_axis_final * dot_product;
251 let x_axis_final = if x_axis_orthogonal.norm() > 1e-6 {
252 x_axis_orthogonal.normalize()
253 } else {
254 if z_axis_final.z.abs() < 0.9 {
256 Vector3::new(0.0, 0.0, 1.0).cross(&z_axis_final).normalize()
257 } else {
258 Vector3::new(1.0, 0.0, 0.0).cross(&z_axis_final).normalize()
259 }
260 };
261
262 let y_axis = z_axis_final.cross(&x_axis_final).normalize();
264
265 Ok(Matrix4::new(
267 x_axis_final.x,
268 y_axis.x,
269 z_axis_final.x,
270 location.x,
271 x_axis_final.y,
272 y_axis.y,
273 z_axis_final.y,
274 location.y,
275 x_axis_final.z,
276 y_axis.z,
277 z_axis_final.z,
278 location.z,
279 0.0,
280 0.0,
281 0.0,
282 1.0,
283 ))
284}
285
286pub fn parse_direction(direction_entity: &DecodedEntity) -> Result<Vector3<f64>> {
290 if direction_entity.ifc_type != IfcType::IfcDirection {
291 return Err(Error::geometry(format!(
292 "Expected IfcDirection, got {}",
293 direction_entity.ifc_type
294 )));
295 }
296
297 let ratios_attr = direction_entity
299 .get(0)
300 .ok_or_else(|| Error::geometry("IfcDirection missing ratios".to_string()))?;
301
302 let ratios = ratios_attr
303 .as_list()
304 .ok_or_else(|| Error::geometry("Expected ratio list".to_string()))?;
305
306 let x = ratios.first().and_then(|v| v.as_float()).unwrap_or(0.0);
307 let y = ratios.get(1).and_then(|v| v.as_float()).unwrap_or(0.0);
308 let z = ratios.get(2).and_then(|v| v.as_float()).unwrap_or(0.0);
309
310 Ok(Vector3::new(x, y, z))
311}
312
313pub fn apply_rtc_offset(mesh: &mut Mesh, rtc: (f64, f64, f64)) {
318 let (rtc_x, rtc_y, rtc_z) = rtc;
319 mesh.positions.chunks_exact_mut(3).for_each(|chunk| {
320 chunk[0] = (chunk[0] as f64 - rtc_x) as f32;
321 chunk[1] = (chunk[1] as f64 - rtc_y) as f32;
322 chunk[2] = (chunk[2] as f64 - rtc_z) as f32;
323 });
324}
325
326#[cfg(test)]
327mod tests {
328 use super::*;
329
330 #[test]
331 fn test_parse_direction() {
332 }
335}