1use ifc_model::{EntityId, Model, Transaction, Value};
18
19use super::{invalid, optional_text, refs, require_accepts, require_exists, require_type};
20use crate::error::MaterialResult;
21use crate::release::Release;
22
23pub fn create_material_properties(
41 tx: &mut Transaction,
42 model: &Model,
43 name: Option<&str>,
44 description: Option<&str>,
45 properties: &[EntityId],
46 material: EntityId,
47) -> MaterialResult<EntityId> {
48 const ENTITY: &str = "IFCMATERIALPROPERTIES";
49 let release = Release::of(model);
50 release.require_entity(ENTITY, None)?;
51 if properties.is_empty() {
52 return Err(invalid(
53 ENTITY,
54 "Properties",
55 "expected at least one property",
56 ));
57 }
58 for property in properties {
59 require_exists(tx, model, *property)?;
60 }
61 require_accepts(tx, model, release, ENTITY, "Material", material)?;
62 let record = release.record(
63 ENTITY,
64 vec![
65 ("Name", optional_text(name)),
66 ("Description", optional_text(description)),
67 ("Properties", refs(properties)),
68 ("Material", Value::Ref(material)),
69 ],
70 )?;
71 Ok(tx.create(record))
72}
73
74pub fn create_material_relationship(
87 tx: &mut Transaction,
88 model: &Model,
89 name: Option<&str>,
90 description: Option<&str>,
91 relating: EntityId,
92 related: &[EntityId],
93 expression: Option<&str>,
94) -> MaterialResult<EntityId> {
95 const ENTITY: &str = "IFCMATERIALRELATIONSHIP";
96 let release = Release::of(model);
97 release.require_entity(ENTITY, None)?;
98 if related.is_empty() {
99 return Err(invalid(
100 ENTITY,
101 "RelatedMaterials",
102 "expected at least one related material",
103 ));
104 }
105 if related.contains(&relating) {
106 return Err(invalid(
107 ENTITY,
108 "RelatedMaterials",
109 "a material cannot be derived from itself",
110 ));
111 }
112 require_type(tx, model, release, relating, &["IFCMATERIAL"])?;
113 for material in related {
114 require_type(tx, model, release, *material, &["IFCMATERIAL"])?;
115 }
116 let record = release.record(
117 ENTITY,
118 vec![
119 ("Name", optional_text(name)),
120 ("Description", optional_text(description)),
121 ("RelatingMaterial", Value::Ref(relating)),
122 ("RelatedMaterials", refs(related)),
123 ("Expression", optional_text(expression)),
124 ],
125 )?;
126 Ok(tx.create(record))
127}
128
129pub fn create_material_classification_relationship(
141 tx: &mut Transaction,
142 model: &Model,
143 classifications: &[EntityId],
144 material: EntityId,
145) -> MaterialResult<EntityId> {
146 const ENTITY: &str = "IFCMATERIALCLASSIFICATIONRELATIONSHIP";
147 let release = Release::of(model);
148 release.require_entity(ENTITY, None)?;
149 if classifications.is_empty() {
150 return Err(invalid(
151 ENTITY,
152 "MaterialClassifications",
153 "expected at least one classification",
154 ));
155 }
156 for classification in classifications {
157 require_exists(tx, model, *classification)?;
158 }
159 require_type(tx, model, release, material, &["IFCMATERIAL"])?;
160 let record = release.record(
161 ENTITY,
162 vec![
163 ("MaterialClassifications", refs(classifications)),
164 ("ClassifiedMaterial", Value::Ref(material)),
165 ],
166 )?;
167 Ok(tx.create(record))
168}
169
170pub fn create_material_definition_representation(
184 tx: &mut Transaction,
185 model: &Model,
186 name: Option<&str>,
187 description: Option<&str>,
188 representations: &[EntityId],
189 material: EntityId,
190) -> MaterialResult<EntityId> {
191 const ENTITY: &str = "IFCMATERIALDEFINITIONREPRESENTATION";
192 let release = Release::of(model);
193 release.require_entity(ENTITY, None)?;
194 if representations.is_empty() {
195 return Err(invalid(
196 ENTITY,
197 "Representations",
198 "expected at least one styled representation",
199 ));
200 }
201 for representation in representations {
202 require_type(
203 tx,
204 model,
205 release,
206 *representation,
207 &["IFCSTYLEDREPRESENTATION"],
208 )?;
209 }
210 require_type(tx, model, release, material, &["IFCMATERIAL"])?;
211 let record = release.record(
212 ENTITY,
213 vec![
214 ("Name", optional_text(name)),
215 ("Description", optional_text(description)),
216 ("Representations", refs(representations)),
217 ("RepresentedMaterial", Value::Ref(material)),
218 ],
219 )?;
220 Ok(tx.create(record))
221}