use crate::{Error, Result, TessellationQuality};
use ifc_lite_core::{DecodedEntity, EntityDecoder};
mod bspline;
mod conics;
mod curves;
mod edge_loop;
mod polyline;
mod revolution;
mod surfaces;
pub(super) use bspline::parse_rational_weights;
pub(super) use surfaces::process_bspline_face;
use revolution::process_surface_of_revolution_face;
use surfaces::{process_cylindrical_face, process_planar_face};
pub(super) fn process_advanced_face(
face: &DecodedEntity,
decoder: &mut EntityDecoder,
quality: TessellationQuality,
) -> Result<(Vec<f32>, Vec<u32>)> {
let surface_attr = face
.get(1)
.ok_or_else(|| Error::geometry("AdvancedFace missing FaceSurface".to_string()))?;
let surface = decoder
.resolve_ref(surface_attr)?
.ok_or_else(|| Error::geometry("Failed to resolve FaceSurface".to_string()))?;
let surface_type = surface.ifc_type.as_str().to_uppercase();
let same_sense = face
.get(2)
.and_then(|a| a.as_enum())
.map(|e| e == "T" || e == "TRUE")
.unwrap_or(true);
let result = if surface_type == "IFCPLANE" {
process_planar_face(face, decoder, quality)
} else if surface_type == "IFCBSPLINESURFACEWITHKNOTS" {
process_bspline_face(&surface, decoder, None, quality)
} else if surface_type == "IFCRATIONALBSPLINESURFACEWITHKNOTS" {
let weights = parse_rational_weights(&surface);
process_bspline_face(&surface, decoder, weights.as_deref(), quality)
} else if surface_type == "IFCCYLINDRICALSURFACE" {
process_cylindrical_face(face, &surface, decoder, quality)
} else if surface_type == "IFCSURFACEOFREVOLUTION" {
process_surface_of_revolution_face(face, &surface, decoder, quality)
} else if surface_type == "IFCSURFACEOFLINEAREXTRUSION"
|| surface_type == "IFCCONICALSURFACE"
|| surface_type == "IFCSPHERICALSURFACE"
|| surface_type == "IFCTOROIDALSURFACE"
{
process_planar_face(face, decoder, quality)
} else {
crate::diag::diag_debug!(
{ face_id = face.id, surface = %surface_type,
"advanced_face: unsupported surface type, emitting empty geometry" }
else {
#[cfg(feature = "debug_geometry")]
eprintln!(
"[ifc-lite][advanced_face] face #{} unsupported surface {}",
face.id, surface_type
);
}
);
Ok((Vec::new(), Vec::new()))
};
#[cfg(any(feature = "debug_geometry", feature = "observability"))]
if let Ok((ref pos, ref idx)) = result {
if pos.is_empty() || idx.is_empty() {
crate::diag::diag_debug!(
{ face_id = face.id, surface = %surface_type,
verts = pos.len() / 3, indices = idx.len() / 3,
"advanced_face: face produced zero triangles" }
else {
#[cfg(feature = "debug_geometry")]
eprintln!(
"[ifc-lite][advanced_face] face #{} surface={} produced 0 tris (verts={}, idx={})",
face.id,
surface_type,
pos.len() / 3,
idx.len() / 3,
);
}
);
}
}
if !same_sense {
result.map(|(positions, mut indices)| {
for tri in indices.chunks_exact_mut(3) {
tri.swap(0, 2);
}
(positions, indices)
})
} else {
result
}
}