ifc_lite_geometry/processors/
advanced.rs1use crate::{Error, Mesh, Result, TessellationQuality};
11use ifc_lite_core::{DecodedEntity, EntityDecoder, IfcSchema, IfcType};
12
13use crate::router::GeometryProcessor;
14use super::advanced_face::{parse_rational_weights, process_advanced_face, process_bspline_face};
15
16pub struct AdvancedBrepProcessor;
20
21impl AdvancedBrepProcessor {
22 pub fn new() -> Self {
23 Self
24 }
25}
26
27impl GeometryProcessor for AdvancedBrepProcessor {
28 fn process(
29 &self,
30 entity: &DecodedEntity,
31 decoder: &mut EntityDecoder,
32 _schema: &IfcSchema,
33 quality: TessellationQuality,
34 ) -> Result<Mesh> {
35 let shell_attr = entity
40 .get(0)
41 .ok_or_else(|| Error::geometry("AdvancedBrep missing Outer shell".to_string()))?;
42
43 let shell = decoder
44 .resolve_ref(shell_attr)?
45 .ok_or_else(|| Error::geometry("Failed to resolve Outer shell".to_string()))?;
46
47 let faces_attr = shell
49 .get(0)
50 .ok_or_else(|| Error::geometry("ClosedShell missing CfsFaces".to_string()))?;
51
52 let faces = faces_attr
53 .as_list()
54 .ok_or_else(|| Error::geometry("Expected face list".to_string()))?;
55
56 let mut all_positions = Vec::new();
57 let mut all_indices = Vec::new();
58
59 #[cfg(any(feature = "debug_geometry", feature = "observability"))]
60 let mut empty_faces: Vec<(u32, String)> = Vec::new();
61
62 for face_ref in faces {
63 if let Some(face_id) = face_ref.as_entity_ref() {
64 let face = decoder.decode_by_id(face_id)?;
65
66 let (positions, indices) = process_advanced_face(&face, decoder, quality)?;
68
69 if !positions.is_empty() {
70 let base_idx = (all_positions.len() / 3) as u32;
72 all_positions.extend(positions);
73 for idx in indices {
74 all_indices.push(base_idx + idx);
75 }
76 } else {
77 #[cfg(any(feature = "debug_geometry", feature = "observability"))]
78 {
79 let surface_kind = face
80 .get(1)
81 .and_then(|a| decoder.resolve_ref(a).ok().flatten())
82 .map(|s| s.ifc_type.as_str().to_string())
83 .unwrap_or_else(|| "<unknown>".to_string());
84 empty_faces.push((face_id, surface_kind));
85 }
86 }
87 }
88 }
89
90 #[cfg(any(feature = "debug_geometry", feature = "observability"))]
94 if !empty_faces.is_empty() {
95 crate::diag::diag_warn!(
96 { entity_id = entity.id, empty_faces = empty_faces.len(),
97 faces = ?empty_faces, "advanced_brep: entity produced empty faces" }
98 else {
99 #[cfg(feature = "debug_geometry")]
100 eprintln!(
101 "[ifc-lite][advanced_brep] entity #{} produced {} empty face(s): {:?}",
102 entity.id,
103 empty_faces.len(),
104 empty_faces
105 );
106 }
107 );
108 }
109
110 Ok(Mesh {
111 positions: all_positions,
112 normals: Vec::new(),
113 indices: all_indices,
114 rtc_applied: false,
115 origin: [0.0; 3], instance_meta: None, local_bounds: None, local_to_world: None })
116 }
117
118 fn supported_types(&self) -> Vec<IfcType> {
119 vec![IfcType::IfcAdvancedBrep, IfcType::IfcAdvancedBrepWithVoids]
120 }
121}
122
123impl Default for AdvancedBrepProcessor {
124 fn default() -> Self {
125 Self::new()
126 }
127}
128
129pub struct BSplineSurfaceProcessor;
135
136impl BSplineSurfaceProcessor {
137 pub fn new() -> Self {
138 Self
139 }
140}
141
142impl Default for BSplineSurfaceProcessor {
143 fn default() -> Self {
144 Self::new()
145 }
146}
147
148impl GeometryProcessor for BSplineSurfaceProcessor {
149 fn process(
150 &self,
151 entity: &DecodedEntity,
152 decoder: &mut EntityDecoder,
153 _schema: &IfcSchema,
154 quality: TessellationQuality,
155 ) -> Result<Mesh> {
156 let weights = if entity.ifc_type == IfcType::IfcRationalBSplineSurfaceWithKnots {
157 parse_rational_weights(entity)
158 } else {
159 None
160 };
161
162 let (positions, indices) =
163 process_bspline_face(entity, decoder, weights.as_deref(), quality)?;
164
165 Ok(Mesh {
166 positions,
167 normals: Vec::new(),
168 indices,
169 rtc_applied: false,
170 origin: [0.0; 3], instance_meta: None, local_bounds: None, local_to_world: None })
171 }
172
173 fn supported_types(&self) -> Vec<IfcType> {
174 vec![
175 IfcType::IfcBSplineSurfaceWithKnots,
176 IfcType::IfcRationalBSplineSurfaceWithKnots,
177 ]
178 }
179}