ifc_geometry/authoring/
profile.rs1use ifc_model::{Entity, EntityId, Transaction, Value};
7
8use crate::curve::polyline::polyline_slot;
9use crate::error::GeometryError;
10use crate::slots::profile_slot as slot;
11
12use super::{invalid, refs, require_finite};
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum ProfileType {
17 Area,
19 Curve,
21}
22
23impl ProfileType {
24 pub(super) fn token(self) -> &'static str {
26 match self {
27 Self::Area => "AREA",
28 Self::Curve => "CURVE",
29 }
30 }
31}
32
33pub fn polyline(tx: &mut Transaction, points: &[EntityId]) -> Result<EntityId, GeometryError> {
40 if points.len() < 2 {
41 return Err(invalid(
42 "IFCPOLYLINE",
43 "Points",
44 format!("expected at least 2 points, got {}", points.len()),
45 ));
46 }
47 let mut attrs = vec![Value::Null];
48 attrs[polyline_slot::POINTS] = refs(points);
49 Ok(tx.create(Entity::new("IFCPOLYLINE", attrs)))
50}
51
52pub fn rectangle_profile(
59 tx: &mut Transaction,
60 name: Option<&str>,
61 position: Option<EntityId>,
62 x_dim: f64,
63 y_dim: f64,
64) -> Result<EntityId, GeometryError> {
65 positive("IFCRECTANGLEPROFILEDEF", "XDim", x_dim)?;
66 positive("IFCRECTANGLEPROFILEDEF", "YDim", y_dim)?;
67 let mut attrs = vec![Value::Null; 5];
68 attrs[slot::PROFILE_TYPE] = Value::Enum(ProfileType::Area.token().into());
69 attrs[slot::PROFILE_NAME] = name.map_or(Value::Null, |n| Value::Text(n.into()));
70 attrs[slot::POSITION] = position.map_or(Value::Null, Value::Ref);
71 attrs[slot::X_DIM] = Value::Real(x_dim);
72 attrs[slot::Y_DIM] = Value::Real(y_dim);
73 Ok(tx.create(Entity::new("IFCRECTANGLEPROFILEDEF", attrs)))
74}
75
76pub fn circle_profile(
82 tx: &mut Transaction,
83 name: Option<&str>,
84 position: Option<EntityId>,
85 radius: f64,
86) -> Result<EntityId, GeometryError> {
87 positive("IFCCIRCLEPROFILEDEF", "Radius", radius)?;
88 let mut attrs = vec![Value::Null; 4];
89 attrs[slot::PROFILE_TYPE] = Value::Enum(ProfileType::Area.token().into());
90 attrs[slot::PROFILE_NAME] = name.map_or(Value::Null, |n| Value::Text(n.into()));
91 attrs[slot::POSITION] = position.map_or(Value::Null, Value::Ref);
92 attrs[slot::RADIUS] = Value::Real(radius);
93 Ok(tx.create(Entity::new("IFCCIRCLEPROFILEDEF", attrs)))
94}
95
96pub fn arbitrary_closed_profile(
102 tx: &mut Transaction,
103 name: Option<&str>,
104 outer_curve: EntityId,
105) -> EntityId {
106 let mut attrs = vec![Value::Null; 3];
107 attrs[slot::PROFILE_TYPE] = Value::Enum(ProfileType::Area.token().into());
108 attrs[slot::PROFILE_NAME] = name.map_or(Value::Null, |n| Value::Text(n.into()));
109 attrs[slot::OUTER_CURVE] = Value::Ref(outer_curve);
110 tx.create(Entity::new("IFCARBITRARYCLOSEDPROFILEDEF", attrs))
111}
112
113fn positive(
115 type_name: &'static str,
116 attribute: &'static str,
117 value: f64,
118) -> Result<(), GeometryError> {
119 require_finite(type_name, attribute, &[value])?;
120 if value <= 0.0 {
121 return Err(invalid(
122 type_name,
123 attribute,
124 format!("expected a positive length, got {value}"),
125 ));
126 }
127 Ok(())
128}