use axiolid_core::{Aabb, Point3};
use axiolid_model::GeometryNode;
use ifc_model::EntityId;
use crate::error::GeometryResult;
use crate::lower::session::LoweringSession;
use crate::resource::point::CartesianPoint;
use crate::solid::bbox::BoundingBox;
use crate::transform::Transform;
const KIND: &str = "bounding box";
pub fn lower_bounding_box_node(
session: &mut LoweringSession<'_>,
id: EntityId,
frame: Transform,
) -> GeometryResult<axiolid_model::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<axiolid_model::NodeId> {
let entity = session.entity(id, id)?;
let view = BoundingBox::new(id, entity);
let corner_ref = view.corner()?;
let corner_entity = session.entity(id, corner_ref)?;
let raw = CartesianPoint::new(corner_ref, corner_entity).coordinates_3d()?;
let min_local = raw.map(|value| session.units().length(value));
let dims = view.checked_dimensions()?;
let dims = dims.map(|value| session.units().length(value));
let mut bounds = Aabb::empty();
for xi in [0.0, dims[0]] {
for yi in [0.0, dims[1]] {
for zi in [0.0, dims[2]] {
let local = [min_local[0] + xi, min_local[1] + yi, min_local[2] + zi];
bounds.extend(Point3::from_array(frame.apply(local)));
}
}
}
session.node_for(id, GeometryNode::BoundingBox(bounds))
}