ifc_spatial/authoring/
external.rs1use ifc_model::guid::Guid;
17use ifc_model::{Entity, EntityId, Transaction, Value};
18
19use super::{invalid, optional_text, SpatialAuthoringResult};
20
21const EXTERNAL_KIND: &[&str] = &[
26 "EXTERNAL",
27 "EXTERNAL_EARTH",
28 "EXTERNAL_FIRE",
29 "EXTERNAL_WATER",
30 "USERDEFINED",
31 "NOTDEFINED",
32];
33
34#[derive(Debug, Clone, Copy, Default)]
36pub struct ExternalSpatialDraft<'a> {
37 pub name: Option<&'a str>,
39 pub description: Option<&'a str>,
41 pub object_type: Option<&'a str>,
43 pub placement: Option<EntityId>,
45 pub representation: Option<EntityId>,
47 pub long_name: Option<&'a str>,
49 pub predefined_type: Option<&'a str>,
51}
52
53pub fn create_external_spatial_element(
66 tx: &mut Transaction,
67 global_id: &str,
68 draft: ExternalSpatialDraft<'_>,
69) -> SpatialAuthoringResult<EntityId> {
70 check_external(global_id, &draft)?;
71 let mut attributes = vec![Value::Null; 9];
72 attributes[0] = Value::Text(global_id.into());
73 attributes[2] = optional_text(draft.name);
74 attributes[3] = optional_text(draft.description);
75 attributes[4] = optional_text(draft.object_type);
76 attributes[5] = draft.placement.map_or(Value::Null, Value::Ref);
77 attributes[6] = draft.representation.map_or(Value::Null, Value::Ref);
78 attributes[7] = optional_text(draft.long_name);
79 attributes[8] = draft
80 .predefined_type
81 .map_or(Value::Null, |t| Value::Enum(t.into()));
82 Ok(tx.create(Entity::new(EXTERNAL, attributes)))
83}
84
85pub(super) const EXTERNAL: &str = "IFCEXTERNALSPATIALELEMENT";
86
87pub(super) fn check_external(
89 global_id: &str,
90 draft: &ExternalSpatialDraft<'_>,
91) -> SpatialAuthoringResult<()> {
92 if Guid::parse(global_id).is_none() {
93 return Err(invalid(EXTERNAL, "GlobalId", global_id));
94 }
95 if let Some(token) = draft.predefined_type {
96 if !EXTERNAL_KIND.contains(&token) {
97 return Err(invalid(EXTERNAL, "PredefinedType", token));
98 }
99 if token == "USERDEFINED"
100 && draft
101 .object_type
102 .is_none_or(|value| value.trim().is_empty())
103 {
104 return Err(invalid(EXTERNAL, "ObjectType", "required by USERDEFINED"));
105 }
106 }
107 Ok(())
108}
109
110#[derive(Debug, Clone, Copy, Default)]
112pub struct ProjectLibraryDraft<'a> {
113 pub name: Option<&'a str>,
115 pub description: Option<&'a str>,
117 pub object_type: Option<&'a str>,
119 pub long_name: Option<&'a str>,
121 pub phase: Option<&'a str>,
123 pub units: Option<EntityId>,
125}
126
127pub fn create_project_library(
146 tx: &mut Transaction,
147 global_id: &str,
148 draft: ProjectLibraryDraft<'_>,
149 representation_contexts: &[EntityId],
150) -> SpatialAuthoringResult<EntityId> {
151 const ENTITY: &str = "IFCPROJECTLIBRARY";
152 if Guid::parse(global_id).is_none() {
153 return Err(invalid(ENTITY, "GlobalId", global_id));
154 }
155 let mut attributes = vec![Value::Null; 9];
156 attributes[0] = Value::Text(global_id.into());
157 attributes[2] = optional_text(draft.name);
158 attributes[3] = optional_text(draft.description);
159 attributes[4] = optional_text(draft.object_type);
160 attributes[5] = optional_text(draft.long_name);
161 attributes[6] = optional_text(draft.phase);
162 if !representation_contexts.is_empty() {
163 attributes[7] = Value::List(
164 representation_contexts
165 .iter()
166 .copied()
167 .map(Value::Ref)
168 .collect(),
169 );
170 }
171 attributes[8] = draft.units.map_or(Value::Null, Value::Ref);
172 Ok(tx.create(Entity::new(ENTITY, attributes)))
173}