ifc_geometry/lower/
boolean.rs1use axiolid_core::BooleanOperator;
12use axiolid_model::{GeometryNode, NodeId, SolidOperation};
13use ifc_model::EntityId;
14
15use crate::error::{GeometryError, GeometryResult};
16use crate::lower::session::LoweringSession;
17use crate::transform::Transform;
18
19pub(crate) mod slot {
20 pub const OPERATOR: usize = 0;
21 pub const FIRST_OPERAND: usize = 1;
22 pub const SECOND_OPERAND: usize = 2;
23}
24
25const BOOLEAN: &str = "boolean";
27
28fn operator(entity: EntityId, token: &str) -> GeometryResult<BooleanOperator> {
34 match token.trim_matches('.').to_ascii_uppercase().as_str() {
35 "UNION" => Ok(BooleanOperator::Union),
36 "INTERSECTION" => Ok(BooleanOperator::Intersection),
37 "DIFFERENCE" => Ok(BooleanOperator::Difference),
38 _ => Err(GeometryError::Degenerate {
39 entity,
40 type_name: "IFCBOOLEANRESULT".to_string(),
41 detail: format!("unknown boolean operator {token}"),
42 }),
43 }
44}
45
46pub fn lower_boolean_result_node(
52 session: &mut LoweringSession<'_>,
53 id: EntityId,
54 frame: Transform,
55) -> GeometryResult<NodeId> {
56 if let Some(node) = session.memoized(id, BOOLEAN, frame) {
57 return Ok(node);
58 }
59
60 session.enter(id, "boolean")?;
61 let result = lower_operands(session, id, frame);
62 session.exit(id);
63 let node = result?;
64
65 session.memoize(id, BOOLEAN, frame, node);
66 Ok(node)
67}
68
69fn lower_operands(
70 session: &mut LoweringSession<'_>,
71 id: EntityId,
72 frame: Transform,
73) -> GeometryResult<NodeId> {
74 let slots = session.slots(id)?;
75 let operator_token = slots
76 .opt_enum(slot::OPERATOR)
77 .ok_or(GeometryError::MissingAttribute {
78 entity: id,
79 type_name: slots.type_name().to_string(),
80 attribute: "Operator",
81 })?
82 .to_string();
83 let operator = operator(id, &operator_token)?;
84 let first = slots.req_ref(slot::FIRST_OPERAND, "FirstOperand")?;
85 let second = slots.req_ref(slot::SECOND_OPERAND, "SecondOperand")?;
86
87 let left = session.lower_operand(first, frame)?;
88 let right = session.lower_operand(second, frame)?;
89
90 session.node_for(
91 id,
92 GeometryNode::SolidOperation(SolidOperation::Boolean {
93 left,
94 right,
95 operator,
96 }),
97 )
98}