use axiolid_model::{GeometryNode, Instance, NodeId};
use ifc_model::EntityId;
use crate::error::GeometryResult;
use crate::lower::session::LoweringSession;
use crate::resource::mapped::{MappedItem, RepresentationMap};
use crate::resource::operator::operator_transform;
use crate::resource::placement::axis_placement_transform;
use crate::transform::Transform;
const MAPPED: &str = "mapped-item";
const REPRESENTATION: &str = "representation";
const KIND: &str = "mapped item";
const REPRESENTATION_ITEMS: usize = 3;
pub fn lower_mapped_item_node(
session: &mut LoweringSession<'_>,
id: EntityId,
world: Transform,
) -> GeometryResult<NodeId> {
if let Some(node) = session.memoized(id, MAPPED, world) {
return Ok(node);
}
session.enter(id, KIND)?;
let node = lower_mapped_item_inner(session, id, world);
session.exit(id);
let node = node?;
session.memoize(id, MAPPED, world, node);
Ok(node)
}
fn lower_mapped_item_inner(
session: &mut LoweringSession<'_>,
id: EntityId,
world: Transform,
) -> GeometryResult<NodeId> {
let entity = session.entity(id, id)?;
let item = MappedItem::new(id, entity);
let source_ref = item.mapping_source()?;
let target_ref = item.mapping_target()?;
let map_entity = session.entity(id, source_ref)?;
let map = RepresentationMap::new(source_ref, map_entity);
let origin_ref = map.mapping_origin()?;
let representation = map.mapped_representation()?;
let target_entity = session.entity(id, target_ref)?;
let target =
operator_transform(session.model(), target_ref, target_entity)?.to_metres(session.units());
let origin_entity = session.entity(source_ref, origin_ref)?;
let origin = axis_placement_transform(session.model(), origin_ref, origin_entity)?
.to_metres(session.units());
let source = lower_representation(session, representation)?;
let placement = world.compose(&target).compose(&origin);
session.node_for(
id,
GeometryNode::Instance(Instance {
source,
transform: placement.to_geom(),
}),
)
}
pub fn lower_representation(
session: &mut LoweringSession<'_>,
id: EntityId,
) -> GeometryResult<NodeId> {
let frame = Transform::identity();
if let Some(node) = session.memoized(id, REPRESENTATION, frame) {
return Ok(node);
}
session.enter(id, KIND)?;
let node = lower_representation_inner(session, id);
session.exit(id);
let node = node?;
session.memoize(id, REPRESENTATION, frame, node);
Ok(node)
}
fn lower_representation_inner(
session: &mut LoweringSession<'_>,
id: EntityId,
) -> GeometryResult<NodeId> {
let slots = session.slots(id)?;
let items = slots.req_ref_list(REPRESENTATION_ITEMS, "Items")?;
let mut members = Vec::with_capacity(items.len());
for item in items {
members.push(session.lower_operand(item, Transform::identity())?);
}
session.node_for(id, GeometryNode::Collection(members))
}