1use ifc_model::{Entity, EntityId, Transaction, Value};
20
21use crate::error::GeometryError;
22use crate::solid::csg::{csg_solid_slot, primitive_slot};
23use crate::solid::halfspace::slot as half_slot;
24
25use super::std_profile::positive;
26
27fn primitive(
31 tx: &mut Transaction,
32 type_name: &'static str,
33 names: &[&'static str],
34 position: EntityId,
35 dims: &[f64],
36) -> Result<EntityId, GeometryError> {
37 debug_assert_eq!(names.len(), dims.len());
38 for (name, value) in names.iter().zip(dims) {
39 positive(type_name, name, *value)?;
40 }
41 let mut attrs = vec![Value::Null; 1 + dims.len()];
42 attrs[primitive_slot::POSITION] = Value::Ref(position);
43 for (offset, value) in dims.iter().enumerate() {
44 attrs[primitive_slot::DIM_0 + offset] = Value::Real(*value);
45 }
46 Ok(tx.create(Entity::new(type_name, attrs)))
47}
48
49pub fn block(
55 tx: &mut Transaction,
56 position: EntityId,
57 x_length: f64,
58 y_length: f64,
59 z_length: f64,
60) -> Result<EntityId, GeometryError> {
61 primitive(
62 tx,
63 "IFCBLOCK",
64 &["XLength", "YLength", "ZLength"],
65 position,
66 &[x_length, y_length, z_length],
67 )
68}
69
70pub fn sphere(
76 tx: &mut Transaction,
77 position: EntityId,
78 radius: f64,
79) -> Result<EntityId, GeometryError> {
80 primitive(tx, "IFCSPHERE", &["Radius"], position, &[radius])
81}
82
83pub fn cylinder(
89 tx: &mut Transaction,
90 position: EntityId,
91 height: f64,
92 radius: f64,
93) -> Result<EntityId, GeometryError> {
94 primitive(
95 tx,
96 "IFCRIGHTCIRCULARCYLINDER",
97 &["Height", "Radius"],
98 position,
99 &[height, radius],
100 )
101}
102
103pub fn cone(
109 tx: &mut Transaction,
110 position: EntityId,
111 height: f64,
112 bottom_radius: f64,
113) -> Result<EntityId, GeometryError> {
114 primitive(
115 tx,
116 "IFCRIGHTCIRCULARCONE",
117 &["Height", "BottomRadius"],
118 position,
119 &[height, bottom_radius],
120 )
121}
122
123pub fn rectangular_pyramid(
129 tx: &mut Transaction,
130 position: EntityId,
131 x_length: f64,
132 y_length: f64,
133 height: f64,
134) -> Result<EntityId, GeometryError> {
135 primitive(
136 tx,
137 "IFCRECTANGULARPYRAMID",
138 &["XLength", "YLength", "Height"],
139 position,
140 &[x_length, y_length, height],
141 )
142}
143
144pub fn csg_solid(tx: &mut Transaction, tree_root: EntityId) -> EntityId {
151 let mut attrs = vec![Value::Null; 1];
152 attrs[csg_solid_slot::TREE_ROOT_EXPRESSION] = Value::Ref(tree_root);
153 tx.create(Entity::new("IFCCSGSOLID", attrs))
154}
155
156pub fn half_space(tx: &mut Transaction, base_surface: EntityId, agreement: bool) -> EntityId {
161 let mut attrs = vec![Value::Null; 2];
162 attrs[half_slot::BASE_SURFACE] = Value::Ref(base_surface);
163 attrs[half_slot::AGREEMENT_FLAG] = Value::Bool(agreement);
164 tx.create(Entity::new("IFCHALFSPACESOLID", attrs))
165}
166
167pub fn boxed_half_space(
174 tx: &mut Transaction,
175 base_surface: EntityId,
176 agreement: bool,
177 enclosure: EntityId,
178) -> EntityId {
179 let mut attrs = vec![Value::Null; 3];
180 attrs[half_slot::BASE_SURFACE] = Value::Ref(base_surface);
181 attrs[half_slot::AGREEMENT_FLAG] = Value::Bool(agreement);
182 attrs[half_slot::ENCLOSURE] = Value::Ref(enclosure);
183 tx.create(Entity::new("IFCBOXEDHALFSPACE", attrs))
184}
185
186pub fn polygonal_bounded_half_space(
199 tx: &mut Transaction,
200 base_surface: EntityId,
201 agreement: bool,
202 position: EntityId,
203 polygonal_boundary: EntityId,
204) -> EntityId {
205 let mut attrs = vec![Value::Null; 4];
206 attrs[half_slot::BASE_SURFACE] = Value::Ref(base_surface);
207 attrs[half_slot::AGREEMENT_FLAG] = Value::Bool(agreement);
208 attrs[half_slot::POSITION] = Value::Ref(position);
209 attrs[half_slot::POLYGONAL_BOUNDARY] = Value::Ref(polygonal_boundary);
210 tx.create(Entity::new("IFCPOLYGONALBOUNDEDHALFSPACE", attrs))
211}
212
213pub fn bounding_box(
220 tx: &mut Transaction,
221 corner: EntityId,
222 x_dim: f64,
223 y_dim: f64,
224 z_dim: f64,
225) -> Result<EntityId, GeometryError> {
226 const T: &str = "IFCBOUNDINGBOX";
227 positive(T, "XDim", x_dim)?;
228 positive(T, "YDim", y_dim)?;
229 positive(T, "ZDim", z_dim)?;
230 let attrs = vec![
231 Value::Ref(corner),
232 Value::Real(x_dim),
233 Value::Real(y_dim),
234 Value::Real(z_dim),
235 ];
236 Ok(tx.create(Entity::new(T, attrs)))
237}