use ifc_model::{Entity, EntityId, Transaction, Value};
use crate::error::GeometryError;
use crate::solid::csg::{csg_solid_slot, primitive_slot};
use crate::solid::halfspace::slot as half_slot;
use super::std_profile::positive;
fn primitive(
tx: &mut Transaction,
type_name: &'static str,
names: &[&'static str],
position: EntityId,
dims: &[f64],
) -> Result<EntityId, GeometryError> {
debug_assert_eq!(names.len(), dims.len());
for (name, value) in names.iter().zip(dims) {
positive(type_name, name, *value)?;
}
let mut attrs = vec![Value::Null; 1 + dims.len()];
attrs[primitive_slot::POSITION] = Value::Ref(position);
for (offset, value) in dims.iter().enumerate() {
attrs[primitive_slot::DIM_0 + offset] = Value::Real(*value);
}
Ok(tx.create(Entity::new(type_name, attrs)))
}
pub fn block(
tx: &mut Transaction,
position: EntityId,
x_length: f64,
y_length: f64,
z_length: f64,
) -> Result<EntityId, GeometryError> {
primitive(
tx,
"IFCBLOCK",
&["XLength", "YLength", "ZLength"],
position,
&[x_length, y_length, z_length],
)
}
pub fn sphere(
tx: &mut Transaction,
position: EntityId,
radius: f64,
) -> Result<EntityId, GeometryError> {
primitive(tx, "IFCSPHERE", &["Radius"], position, &[radius])
}
pub fn cylinder(
tx: &mut Transaction,
position: EntityId,
height: f64,
radius: f64,
) -> Result<EntityId, GeometryError> {
primitive(
tx,
"IFCRIGHTCIRCULARCYLINDER",
&["Height", "Radius"],
position,
&[height, radius],
)
}
pub fn cone(
tx: &mut Transaction,
position: EntityId,
height: f64,
bottom_radius: f64,
) -> Result<EntityId, GeometryError> {
primitive(
tx,
"IFCRIGHTCIRCULARCONE",
&["Height", "BottomRadius"],
position,
&[height, bottom_radius],
)
}
pub fn rectangular_pyramid(
tx: &mut Transaction,
position: EntityId,
x_length: f64,
y_length: f64,
height: f64,
) -> Result<EntityId, GeometryError> {
primitive(
tx,
"IFCRECTANGULARPYRAMID",
&["XLength", "YLength", "Height"],
position,
&[x_length, y_length, height],
)
}
pub fn csg_solid(tx: &mut Transaction, tree_root: EntityId) -> EntityId {
let mut attrs = vec![Value::Null; 1];
attrs[csg_solid_slot::TREE_ROOT_EXPRESSION] = Value::Ref(tree_root);
tx.create(Entity::new("IFCCSGSOLID", attrs))
}
pub fn half_space(tx: &mut Transaction, base_surface: EntityId, agreement: bool) -> EntityId {
let mut attrs = vec![Value::Null; 2];
attrs[half_slot::BASE_SURFACE] = Value::Ref(base_surface);
attrs[half_slot::AGREEMENT_FLAG] = Value::Bool(agreement);
tx.create(Entity::new("IFCHALFSPACESOLID", attrs))
}
pub fn boxed_half_space(
tx: &mut Transaction,
base_surface: EntityId,
agreement: bool,
enclosure: EntityId,
) -> EntityId {
let mut attrs = vec![Value::Null; 3];
attrs[half_slot::BASE_SURFACE] = Value::Ref(base_surface);
attrs[half_slot::AGREEMENT_FLAG] = Value::Bool(agreement);
attrs[half_slot::ENCLOSURE] = Value::Ref(enclosure);
tx.create(Entity::new("IFCBOXEDHALFSPACE", attrs))
}
pub fn polygonal_bounded_half_space(
tx: &mut Transaction,
base_surface: EntityId,
agreement: bool,
position: EntityId,
polygonal_boundary: EntityId,
) -> EntityId {
let mut attrs = vec![Value::Null; 4];
attrs[half_slot::BASE_SURFACE] = Value::Ref(base_surface);
attrs[half_slot::AGREEMENT_FLAG] = Value::Bool(agreement);
attrs[half_slot::POSITION] = Value::Ref(position);
attrs[half_slot::POLYGONAL_BOUNDARY] = Value::Ref(polygonal_boundary);
tx.create(Entity::new("IFCPOLYGONALBOUNDEDHALFSPACE", attrs))
}
pub fn bounding_box(
tx: &mut Transaction,
corner: EntityId,
x_dim: f64,
y_dim: f64,
z_dim: f64,
) -> Result<EntityId, GeometryError> {
const T: &str = "IFCBOUNDINGBOX";
positive(T, "XDim", x_dim)?;
positive(T, "YDim", y_dim)?;
positive(T, "ZDim", z_dim)?;
let attrs = vec![
Value::Ref(corner),
Value::Real(x_dim),
Value::Real(y_dim),
Value::Real(z_dim),
];
Ok(tx.create(Entity::new(T, attrs)))
}