ifc_lite_geometry/router/
processing.rs1use super::GeometryRouter;
8use crate::{Error, Mesh, Result, SubMeshCollection};
9use ifc_lite_core::{DecodedEntity, EntityDecoder, GeometryCategory, IfcType};
10use nalgebra::Matrix4;
11use std::sync::Arc;
12
13impl GeometryRouter {
14 pub fn detect_rtc_offset_from_first_element(
18 &self,
19 content: &str,
20 decoder: &mut EntityDecoder,
21 ) -> (f64, f64, f64) {
22 use ifc_lite_core::EntityScanner;
23
24 let mut scanner = EntityScanner::new(content);
25
26 let mut translations: Vec<(f64, f64, f64)> = Vec::new();
28 const MAX_SAMPLES: usize = 50; const BUILDING_ELEMENT_TYPES: &[&str] = &[
32 "IFCWALL", "IFCWALLSTANDARDCASE", "IFCSLAB", "IFCBEAM", "IFCCOLUMN",
33 "IFCPLATE", "IFCROOF", "IFCCOVERING", "IFCFOOTING", "IFCRAILING",
34 "IFCSTAIR", "IFCSTAIRFLIGHT", "IFCRAMP", "IFCRAMPFLIGHT",
35 "IFCDOOR", "IFCWINDOW", "IFCFURNISHINGELEMENT", "IFCBUILDINGELEMENTPROXY",
36 "IFCMEMBER", "IFCCURTAINWALL", "IFCPILE", "IFCSHADINGDEVICE",
37 ];
38
39 while let Some((_id, type_name, start, end)) = scanner.next_entity() {
41 if translations.len() >= MAX_SAMPLES {
42 break;
43 }
44
45 if !BUILDING_ELEMENT_TYPES.iter().any(|&t| t == type_name) {
47 continue;
48 }
49
50 if let Ok(entity) = decoder.decode_at(start, end) {
52 let has_rep = entity.get(6).map(|a| !a.is_null()).unwrap_or(false);
54 if !has_rep {
55 continue;
56 }
57
58 if let Ok(mut transform) = self.get_placement_transform_from_element(&entity, decoder) {
61 self.scale_transform(&mut transform);
62 let tx = transform[(0, 3)];
63 let ty = transform[(1, 3)];
64 let tz = transform[(2, 3)];
65
66 if tx.is_finite() && ty.is_finite() && tz.is_finite() {
68 translations.push((tx, ty, tz));
69 }
70 }
71 }
72 }
73
74 if translations.is_empty() {
75 return (0.0, 0.0, 0.0);
76 }
77
78 let mut x_coords: Vec<f64> = translations.iter().map(|(x, _, _)| *x).collect();
81 let mut y_coords: Vec<f64> = translations.iter().map(|(_, y, _)| *y).collect();
82 let mut z_coords: Vec<f64> = translations.iter().map(|(_, _, z)| *z).collect();
83
84 x_coords.sort_by(|a, b| a.partial_cmp(b).unwrap());
85 y_coords.sort_by(|a, b| a.partial_cmp(b).unwrap());
86 z_coords.sort_by(|a, b| a.partial_cmp(b).unwrap());
87
88 let median_idx = x_coords.len() / 2;
89 let centroid = (
90 x_coords[median_idx],
91 y_coords[median_idx],
92 z_coords[median_idx],
93 );
94
95 const THRESHOLD: f64 = 10000.0;
97 if centroid.0.abs() > THRESHOLD || centroid.1.abs() > THRESHOLD || centroid.2.abs() > THRESHOLD {
98 return centroid;
99 }
100
101 (0.0, 0.0, 0.0)
102 }
103
104 #[inline]
108 pub fn process_element(
109 &self,
110 element: &DecodedEntity,
111 decoder: &mut EntityDecoder,
112 ) -> Result<Mesh> {
113 let representation_attr = element.get(6).ok_or_else(|| {
116 Error::geometry(format!(
117 "Element #{} has no representation attribute",
118 element.id
119 ))
120 })?;
121
122 if representation_attr.is_null() {
123 return Ok(Mesh::new()); }
125
126 let representation = decoder
127 .resolve_ref(representation_attr)?
128 .ok_or_else(|| Error::geometry("Failed to resolve representation".to_string()))?;
129
130 if representation.ifc_type != IfcType::IfcProductDefinitionShape {
132 return Err(Error::geometry(format!(
133 "Expected IfcProductDefinitionShape, got {}",
134 representation.ifc_type
135 )));
136 }
137
138 let representations_attr = representation.get(2).ok_or_else(|| {
140 Error::geometry("IfcProductDefinitionShape missing Representations".to_string())
141 })?;
142
143 let representations = decoder.resolve_ref_list(representations_attr)?;
144
145 let mut combined_mesh = Mesh::new();
147
148 let has_direct_geometry = representations.iter().any(|rep| {
151 if rep.ifc_type != IfcType::IfcShapeRepresentation {
152 return false;
153 }
154 if let Some(rep_type_attr) = rep.get(2) {
155 if let Some(rep_type) = rep_type_attr.as_string() {
156 matches!(
157 rep_type,
158 "Body"
159 | "SweptSolid"
160 | "Brep"
161 | "CSG"
162 | "Clipping"
163 | "SurfaceModel"
164 | "Tessellation"
165 | "AdvancedSweptSolid"
166 | "AdvancedBrep"
167 )
168 } else {
169 false
170 }
171 } else {
172 false
173 }
174 });
175
176 for shape_rep in representations {
177 if shape_rep.ifc_type != IfcType::IfcShapeRepresentation {
178 continue;
179 }
180
181 if let Some(rep_type_attr) = shape_rep.get(2) {
184 if let Some(rep_type) = rep_type_attr.as_string() {
185 if rep_type == "MappedRepresentation" && has_direct_geometry {
188 continue;
189 }
190
191 if !matches!(
193 rep_type,
194 "Body"
195 | "SweptSolid"
196 | "Brep"
197 | "CSG"
198 | "Clipping"
199 | "SurfaceModel"
200 | "Tessellation"
201 | "MappedRepresentation"
202 | "AdvancedSweptSolid"
203 | "AdvancedBrep"
204 ) {
205 continue; }
207 }
208 }
209
210 let items_attr = shape_rep.get(3).ok_or_else(|| {
212 Error::geometry("IfcShapeRepresentation missing Items".to_string())
213 })?;
214
215 let items = decoder.resolve_ref_list(items_attr)?;
216
217 for item in items {
219 let mesh = self.process_representation_item(&item, decoder)?;
220 combined_mesh.merge(&mesh);
221 }
222 }
223
224 self.apply_placement(element, decoder, &mut combined_mesh)?;
226
227 Ok(combined_mesh)
228 }
229
230 pub fn process_element_with_submeshes(
236 &self,
237 element: &DecodedEntity,
238 decoder: &mut EntityDecoder,
239 ) -> Result<SubMeshCollection> {
240 let representation_attr = element.get(6).ok_or_else(|| {
242 Error::geometry(format!(
243 "Element #{} has no representation attribute",
244 element.id
245 ))
246 })?;
247
248 if representation_attr.is_null() {
249 return Ok(SubMeshCollection::new()); }
251
252 let representation = decoder
253 .resolve_ref(representation_attr)?
254 .ok_or_else(|| Error::geometry("Failed to resolve representation".to_string()))?;
255
256 if representation.ifc_type != IfcType::IfcProductDefinitionShape {
257 return Err(Error::geometry(format!(
258 "Expected IfcProductDefinitionShape, got {}",
259 representation.ifc_type
260 )));
261 }
262
263 let representations_attr = representation.get(2).ok_or_else(|| {
265 Error::geometry("IfcProductDefinitionShape missing Representations".to_string())
266 })?;
267
268 let representations = decoder.resolve_ref_list(representations_attr)?;
269
270 let mut sub_meshes = SubMeshCollection::new();
271
272 let has_direct_geometry = representations.iter().any(|rep| {
274 if rep.ifc_type != IfcType::IfcShapeRepresentation {
275 return false;
276 }
277 if let Some(rep_type_attr) = rep.get(2) {
278 if let Some(rep_type) = rep_type_attr.as_string() {
279 matches!(
280 rep_type,
281 "Body"
282 | "SweptSolid"
283 | "Brep"
284 | "CSG"
285 | "Clipping"
286 | "SurfaceModel"
287 | "Tessellation"
288 | "AdvancedSweptSolid"
289 | "AdvancedBrep"
290 )
291 } else {
292 false
293 }
294 } else {
295 false
296 }
297 });
298
299 for shape_rep in representations {
300 if shape_rep.ifc_type != IfcType::IfcShapeRepresentation {
301 continue;
302 }
303
304 if let Some(rep_type_attr) = shape_rep.get(2) {
305 if let Some(rep_type) = rep_type_attr.as_string() {
306 if rep_type == "MappedRepresentation" && has_direct_geometry {
308 continue;
309 }
310
311 if !matches!(
313 rep_type,
314 "Body"
315 | "SweptSolid"
316 | "Brep"
317 | "CSG"
318 | "Clipping"
319 | "SurfaceModel"
320 | "Tessellation"
321 | "MappedRepresentation"
322 | "AdvancedSweptSolid"
323 | "AdvancedBrep"
324 ) {
325 continue;
326 }
327 }
328 }
329
330 let items_attr = shape_rep.get(3).ok_or_else(|| {
332 Error::geometry("IfcShapeRepresentation missing Items".to_string())
333 })?;
334
335 let items = decoder.resolve_ref_list(items_attr)?;
336
337 for item in items {
339 self.collect_submeshes_from_item(&item, decoder, &mut sub_meshes)?;
340 }
341 }
342
343 if let Some(placement_attr) = element.get(5) {
347 if !placement_attr.is_null() {
348 if let Some(placement) = decoder.resolve_ref(placement_attr)? {
349 let mut transform = self.get_placement_transform(&placement, decoder)?;
350 self.scale_transform(&mut transform);
351 for sub in &mut sub_meshes.sub_meshes {
352 self.transform_mesh(&mut sub.mesh, &transform);
353 }
354 }
355 }
356 }
357
358 Ok(sub_meshes)
359 }
360
361 fn collect_submeshes_from_item(
363 &self,
364 item: &DecodedEntity,
365 decoder: &mut EntityDecoder,
366 sub_meshes: &mut SubMeshCollection,
367 ) -> Result<()> {
368 if item.ifc_type == IfcType::IfcMappedItem {
370 let source_attr = item
372 .get(0)
373 .ok_or_else(|| Error::geometry("MappedItem missing MappingSource".to_string()))?;
374
375 let source_entity = decoder
376 .resolve_ref(source_attr)?
377 .ok_or_else(|| Error::geometry("Failed to resolve MappingSource".to_string()))?;
378
379 let mapped_repr_attr = source_entity
381 .get(1)
382 .ok_or_else(|| Error::geometry("RepresentationMap missing MappedRepresentation".to_string()))?;
383
384 let mapped_repr = decoder
385 .resolve_ref(mapped_repr_attr)?
386 .ok_or_else(|| Error::geometry("Failed to resolve MappedRepresentation".to_string()))?;
387
388 let mapping_transform = if let Some(target_attr) = item.get(1) {
390 if !target_attr.is_null() {
391 if let Some(target_entity) = decoder.resolve_ref(target_attr)? {
392 Some(self.parse_cartesian_transformation_operator(&target_entity, decoder)?)
393 } else {
394 None
395 }
396 } else {
397 None
398 }
399 } else {
400 None
401 };
402
403 if let Some(items_attr) = mapped_repr.get(3) {
405 let items = decoder.resolve_ref_list(items_attr)?;
406 for nested_item in items {
407 let count_before = sub_meshes.len();
409 self.collect_submeshes_from_item(&nested_item, decoder, sub_meshes)?;
410
411 if let Some(mut transform) = mapping_transform.clone() {
413 self.scale_transform(&mut transform);
414 for sub in &mut sub_meshes.sub_meshes[count_before..] {
415 self.transform_mesh(&mut sub.mesh, &transform);
416 }
417 }
418 }
419 }
420 } else {
421 let mesh = self.process_representation_item(item, decoder)?;
423 if !mesh.is_empty() {
424 sub_meshes.add(item.id, mesh);
425 }
426 }
427
428 Ok(())
429 }
430
431 #[inline]
434 pub fn process_element_with_transform(
435 &self,
436 element: &DecodedEntity,
437 decoder: &mut EntityDecoder,
438 ) -> Result<(Mesh, Matrix4<f64>)> {
439 let representation_attr = element.get(6).ok_or_else(|| {
441 Error::geometry(format!(
442 "Element #{} has no representation attribute",
443 element.id
444 ))
445 })?;
446
447 if representation_attr.is_null() {
448 return Ok((Mesh::new(), Matrix4::identity())); }
450
451 let representation = decoder
452 .resolve_ref(representation_attr)?
453 .ok_or_else(|| Error::geometry("Failed to resolve representation".to_string()))?;
454
455 if representation.ifc_type != IfcType::IfcProductDefinitionShape {
456 return Err(Error::geometry(format!(
457 "Expected IfcProductDefinitionShape, got {}",
458 representation.ifc_type
459 )));
460 }
461
462 let representations_attr = representation.get(2).ok_or_else(|| {
464 Error::geometry("IfcProductDefinitionShape missing Representations".to_string())
465 })?;
466
467 let representations = decoder.resolve_ref_list(representations_attr)?;
468
469 let mut combined_mesh = Mesh::new();
471
472 let has_direct_geometry = representations.iter().any(|rep| {
474 if rep.ifc_type != IfcType::IfcShapeRepresentation {
475 return false;
476 }
477 if let Some(rep_type_attr) = rep.get(2) {
478 if let Some(rep_type) = rep_type_attr.as_string() {
479 matches!(
480 rep_type,
481 "Body"
482 | "SweptSolid"
483 | "Brep"
484 | "CSG"
485 | "Clipping"
486 | "SurfaceModel"
487 | "Tessellation"
488 | "AdvancedSweptSolid"
489 | "AdvancedBrep"
490 )
491 } else {
492 false
493 }
494 } else {
495 false
496 }
497 });
498
499 for shape_rep in representations {
500 if shape_rep.ifc_type != IfcType::IfcShapeRepresentation {
501 continue;
502 }
503
504 if let Some(rep_type_attr) = shape_rep.get(2) {
505 if let Some(rep_type) = rep_type_attr.as_string() {
506 if rep_type == "MappedRepresentation" && has_direct_geometry {
507 continue;
508 }
509
510 if !matches!(
511 rep_type,
512 "Body"
513 | "SweptSolid"
514 | "Brep"
515 | "CSG"
516 | "Clipping"
517 | "SurfaceModel"
518 | "Tessellation"
519 | "MappedRepresentation"
520 | "AdvancedSweptSolid"
521 | "AdvancedBrep"
522 ) {
523 continue;
524 }
525 }
526 }
527
528 let items_attr = shape_rep.get(3).ok_or_else(|| {
529 Error::geometry("IfcShapeRepresentation missing Items".to_string())
530 })?;
531
532 let items = decoder.resolve_ref_list(items_attr)?;
533
534 for item in items {
535 let mesh = self.process_representation_item(&item, decoder)?;
536 combined_mesh.merge(&mesh);
537 }
538 }
539
540 let transform = self.get_placement_transform_from_element(element, decoder)?;
542
543 Ok((combined_mesh, transform))
544 }
545
546 #[inline]
549 pub fn process_representation_item(
550 &self,
551 item: &DecodedEntity,
552 decoder: &mut EntityDecoder,
553 ) -> Result<Mesh> {
554 if item.ifc_type == IfcType::IfcMappedItem {
556 return self.process_mapped_item_cached(item, decoder);
557 }
558
559 if item.ifc_type == IfcType::IfcFacetedBrep {
561 if let Some(mut mesh) = self.take_cached_faceted_brep(item.id) {
562 self.scale_mesh(&mut mesh);
563 let cached = self.get_or_cache_by_hash(mesh);
564 return Ok((*cached).clone());
565 }
566 }
567
568 if let Some(processor) = self.processors.get(&item.ifc_type) {
570 let mut mesh = processor.process(item, decoder, &self.schema)?;
571 self.scale_mesh(&mut mesh);
572
573 if !mesh.positions.is_empty() {
575 let cached = self.get_or_cache_by_hash(mesh);
576 return Ok((*cached).clone());
577 }
578 return Ok(mesh);
579 }
580
581 match self.schema.geometry_category(&item.ifc_type) {
583 Some(GeometryCategory::SweptSolid) => {
584 Ok(Mesh::new())
586 }
587 Some(GeometryCategory::ExplicitMesh) => {
588 Ok(Mesh::new())
590 }
591 Some(GeometryCategory::Boolean) => {
592 Ok(Mesh::new())
594 }
595 Some(GeometryCategory::MappedItem) => {
596 Ok(Mesh::new())
598 }
599 _ => Err(Error::geometry(format!(
600 "Unsupported representation type: {}",
601 item.ifc_type
602 ))),
603 }
604 }
605
606 #[inline]
608 fn process_mapped_item_cached(
609 &self,
610 item: &DecodedEntity,
611 decoder: &mut EntityDecoder,
612 ) -> Result<Mesh> {
613 let source_attr = item
619 .get(0)
620 .ok_or_else(|| Error::geometry("MappedItem missing MappingSource".to_string()))?;
621
622 let source_entity = decoder
623 .resolve_ref(source_attr)?
624 .ok_or_else(|| Error::geometry("Failed to resolve MappingSource".to_string()))?;
625
626 let source_id = source_entity.id;
627
628 let mapping_transform = if let Some(target_attr) = item.get(1) {
630 if !target_attr.is_null() {
631 if let Some(target_entity) = decoder.resolve_ref(target_attr)? {
632 Some(self.parse_cartesian_transformation_operator(&target_entity, decoder)?)
633 } else {
634 None
635 }
636 } else {
637 None
638 }
639 } else {
640 None
641 };
642
643 {
645 let cache = self.mapped_item_cache.borrow();
646 if let Some(cached_mesh) = cache.get(&source_id) {
647 let mut mesh = cached_mesh.as_ref().clone();
648 if let Some(mut transform) = mapping_transform {
649 self.scale_transform(&mut transform);
650 self.transform_mesh(&mut mesh, &transform);
651 }
652 return Ok(mesh);
653 }
654 }
655
656 let mapped_rep_attr = source_entity.get(1).ok_or_else(|| {
662 Error::geometry("RepresentationMap missing MappedRepresentation".to_string())
663 })?;
664
665 let mapped_rep = decoder
666 .resolve_ref(mapped_rep_attr)?
667 .ok_or_else(|| Error::geometry("Failed to resolve MappedRepresentation".to_string()))?;
668
669 let items_attr = mapped_rep
671 .get(3)
672 .ok_or_else(|| Error::geometry("Representation missing Items".to_string()))?;
673
674 let items = decoder.resolve_ref_list(items_attr)?;
675
676 let mut mesh = Mesh::new();
678 for sub_item in items {
679 if sub_item.ifc_type == IfcType::IfcMappedItem {
680 continue; }
682 if let Some(processor) = self.processors.get(&sub_item.ifc_type) {
683 if let Ok(mut sub_mesh) = processor.process(&sub_item, decoder, &self.schema) {
684 self.scale_mesh(&mut sub_mesh);
685 mesh.merge(&sub_mesh);
686 }
687 }
688 }
689
690 {
692 let mut cache = self.mapped_item_cache.borrow_mut();
693 cache.insert(source_id, Arc::new(mesh.clone()));
694 }
695
696 if let Some(mut transform) = mapping_transform {
698 self.scale_transform(&mut transform);
699 self.transform_mesh(&mut mesh, &transform);
700 }
701
702 Ok(mesh)
703 }
704}