use axiolid_model::NodeId;
use ifc_model::EntityId;
use crate::constraint::connection::slot;
use crate::error::{GeometryError, GeometryResult};
use crate::lower::brep::lower_face_surface_node;
use crate::lower::collection::lower_collection_node;
use crate::lower::session::LoweringSession;
use crate::lower::surface::lower_surface_node;
use crate::select::SurfaceOrFaceSurface;
use crate::transform::Transform;
const SURFACE_CONNECTION: &str = "IFCCONNECTIONSURFACEGEOMETRY";
const REFUSED: &[(&str, &str)] = &[
(
"IFCCONNECTIONPOINTGEOMETRY",
"a point connection carries a point or vertex point, not a surface",
),
(
"IFCCONNECTIONPOINTECCENTRICITY",
"an eccentric point connection carries a point or vertex point, not a surface",
),
(
"IFCCONNECTIONCURVEGEOMETRY",
"a curve connection carries a curve or edge curve, not a surface",
),
(
"IFCCONNECTIONVOLUMEGEOMETRY",
"a volume connection carries a solid or shell, not a surface",
),
(
"IFCCONNECTIONPORTGEOMETRY",
"an IFC2X3 port connection carries a placement and a profile, not a surface",
),
];
pub fn lower_connection_surface(
session: &mut LoweringSession<'_>,
id: EntityId,
frame: Transform,
) -> GeometryResult<NodeId> {
check_connection(session, id)?;
let target = session
.slots(id)?
.req_ref(slot::AT_RELATING, "SurfaceOnRelatingElement")?;
lower_surface_or_face_surface(session, id, target, frame)
}
pub fn lower_related_connection_surface(
session: &mut LoweringSession<'_>,
id: EntityId,
frame: Transform,
) -> GeometryResult<Option<NodeId>> {
check_connection(session, id)?;
let slots = session.slots(id)?;
if slots.opt(slot::AT_RELATED).is_none() {
return Ok(None);
}
let target = slots.req_ref(slot::AT_RELATED, "SurfaceOnRelatedElement")?;
lower_surface_or_face_surface(session, id, target, frame).map(Some)
}
fn check_connection(session: &LoweringSession<'_>, id: EntityId) -> GeometryResult<()> {
let type_name = session.type_name(id)?;
if type_name == SURFACE_CONNECTION {
return Ok(());
}
if let Some((_, reason)) = REFUSED.iter().find(|(name, _)| *name == type_name) {
return Err(session.unsupported(id, &type_name, reason));
}
Err(GeometryError::WrongEntityType {
entity: id,
actual: type_name,
expected: "IfcConnectionSurfaceGeometry",
})
}
fn lower_surface_or_face_surface(
session: &mut LoweringSession<'_>,
referrer: EntityId,
target: EntityId,
frame: Transform,
) -> GeometryResult<NodeId> {
match SurfaceOrFaceSurface::resolve(session.model(), referrer, target)? {
SurfaceOrFaceSurface::Surface(surface) => lower_surface_node(session, surface, frame),
SurfaceOrFaceSurface::FaceSurface(face) => lower_face_surface_node(session, face, frame),
SurfaceOrFaceSurface::FaceBasedSurfaceModel(model) => {
lower_collection_node(session, model, frame)
}
}
}