use axiolid_model::{GeometryNode, NodeId};
use ifc_model::EntityId;
use crate::error::GeometryResult;
use crate::lower::curve::lower_curve_node;
use crate::lower::session::LoweringSession;
use crate::lower::surface::lower_surface_node;
use crate::select::is_a;
use crate::solid::surface_model::{FaceBasedSurfaceModel, GeometricSet, ShellBasedSurfaceModel};
use crate::transform::Transform;
const KIND: &str = "geometric collection";
pub fn lower_collection_node(
session: &mut LoweringSession<'_>,
id: EntityId,
frame: Transform,
) -> GeometryResult<NodeId> {
if let Some(node) = session.memoized(id, KIND, frame) {
return Ok(node);
}
session.enter(id, KIND)?;
let result = build(session, id, frame);
session.exit(id);
let node = result?;
session.memoize(id, KIND, frame, node);
Ok(node)
}
fn build(
session: &mut LoweringSession<'_>,
id: EntityId,
frame: Transform,
) -> GeometryResult<NodeId> {
let entity = session.entity(id, id)?;
let type_name = session.type_name(id)?.to_ascii_uppercase();
let members = match type_name.as_str() {
"IFCSHELLBASEDSURFACEMODEL" => ShellBasedSurfaceModel::new(id, entity).shells()?,
"IFCFACEBASEDSURFACEMODEL" => FaceBasedSurfaceModel::new(id, entity).face_sets()?,
"IFCGEOMETRICSET" | "IFCGEOMETRICCURVESET" => GeometricSet::new(id, entity).elements()?,
other => return Err(session.unsupported(id, other, "geometric collection family")),
};
let mut nodes = Vec::with_capacity(members.len());
for member in members {
nodes.push(member_node(session, id, member, frame)?);
}
session.node_for(id, GeometryNode::Collection(nodes))
}
fn member_node(
session: &mut LoweringSession<'_>,
referrer: EntityId,
id: EntityId,
frame: Transform,
) -> GeometryResult<NodeId> {
let member_type = session.type_name(id)?.to_ascii_uppercase();
if matches!(
member_type.as_str(),
"IFCCLOSEDSHELL" | "IFCOPENSHELL" | "IFCCONNECTEDFACESET"
) {
return crate::lower::brep::lower_shell_node(session, referrer, id, frame);
}
if is_a(&member_type, "IFCCURVE") {
return lower_curve_node(session, id, frame);
}
if is_a(&member_type, "IFCSURFACE") {
return lower_surface_node(session, id, frame);
}
crate::lower::dispatch::lower_representation_item(session, id, frame)
}