1use ifc_model::{EntityId, Model, Transaction, Value};
21
22use crate::PropertyResult;
23
24use super::owned::{stage_ifc4, stage_owned, Rooted};
25use super::predefined::{invalid, measure, ratio, require_guid, Measure};
26
27#[derive(Debug, Clone, Copy, Default)]
29pub struct DoorLiningDraft<'a> {
30 pub name: Option<&'a str>,
32 pub description: Option<&'a str>,
34 pub lining_depth: Option<f64>,
36 pub lining_thickness: Option<f64>,
38 pub threshold_depth: Option<f64>,
40 pub threshold_thickness: Option<f64>,
42 pub transom_thickness: Option<f64>,
44 pub transom_offset: Option<f64>,
46 pub lining_offset: Option<f64>,
48 pub threshold_offset: Option<f64>,
50 pub casing_thickness: Option<f64>,
52 pub casing_depth: Option<f64>,
54 pub shape_aspect_style: Option<EntityId>,
56 pub lining_to_panel_offset_x: Option<f64>,
58 pub lining_to_panel_offset_y: Option<f64>,
60}
61
62pub fn add_door_lining_properties(
79 tx: &mut Transaction,
80 global_id: &str,
81 draft: DoorLiningDraft<'_>,
82) -> PropertyResult<EntityId> {
83 stage_ifc4(tx, door_lining(global_id, draft)?)
84}
85
86pub fn add_door_lining_properties_with_owner_history(
101 tx: &mut Transaction,
102 model: &Model,
103 global_id: &str,
104 draft: DoorLiningDraft<'_>,
105 owner_history: EntityId,
106) -> PropertyResult<EntityId> {
107 stage_owned(tx, model, door_lining(global_id, draft)?, owner_history)
108}
109
110fn door_lining<'a>(global_id: &'a str, draft: DoorLiningDraft<'a>) -> PropertyResult<Rooted<'a>> {
111 const ENTITY: &str = "IFCDOORLININGPROPERTIES";
112 if draft.lining_depth.is_some() && draft.lining_thickness.is_none() {
113 return Err(invalid(
114 ENTITY,
115 "LiningThickness",
116 "WR31: a lining depth needs its thickness",
117 ));
118 }
119 if draft.threshold_depth.is_some() && draft.threshold_thickness.is_none() {
120 return Err(invalid(
121 ENTITY,
122 "ThresholdThickness",
123 "WR32: a threshold depth needs its thickness",
124 ));
125 }
126 if draft.transom_offset.is_some() != draft.transom_thickness.is_some() {
127 return Err(invalid(
128 ENTITY,
129 "TransomOffset",
130 "WR33: transom offset and thickness are all or nothing",
131 ));
132 }
133 if draft.casing_depth.is_some() != draft.casing_thickness.is_some() {
134 return Err(invalid(
135 ENTITY,
136 "CasingDepth",
137 "WR34: casing depth and thickness are all or nothing",
138 ));
139 }
140 require_guid(ENTITY, global_id)?;
141 let m = |attribute, value, kind| measure(ENTITY, attribute, value, kind);
142 let values = vec![
143 (
144 "LiningDepth",
145 m("LiningDepth", draft.lining_depth, Measure::Positive)?,
146 ),
147 (
148 "LiningThickness",
149 m(
150 "LiningThickness",
151 draft.lining_thickness,
152 Measure::NonNegative,
153 )?,
154 ),
155 (
156 "ThresholdDepth",
157 m("ThresholdDepth", draft.threshold_depth, Measure::Positive)?,
158 ),
159 (
160 "ThresholdThickness",
161 m(
162 "ThresholdThickness",
163 draft.threshold_thickness,
164 Measure::NonNegative,
165 )?,
166 ),
167 (
168 "TransomThickness",
169 m(
170 "TransomThickness",
171 draft.transom_thickness,
172 Measure::NonNegative,
173 )?,
174 ),
175 (
176 "TransomOffset",
177 m("TransomOffset", draft.transom_offset, Measure::Length)?,
178 ),
179 (
180 "LiningOffset",
181 m("LiningOffset", draft.lining_offset, Measure::Length)?,
182 ),
183 (
184 "ThresholdOffset",
185 m("ThresholdOffset", draft.threshold_offset, Measure::Length)?,
186 ),
187 (
188 "CasingThickness",
189 m("CasingThickness", draft.casing_thickness, Measure::Positive)?,
190 ),
191 (
192 "CasingDepth",
193 m("CasingDepth", draft.casing_depth, Measure::Positive)?,
194 ),
195 (
196 "ShapeAspectStyle",
197 draft.shape_aspect_style.map_or(Value::Null, Value::Ref),
198 ),
199 (
200 "LiningToPanelOffsetX",
201 m(
202 "LiningToPanelOffsetX",
203 draft.lining_to_panel_offset_x,
204 Measure::Length,
205 )?,
206 ),
207 (
208 "LiningToPanelOffsetY",
209 m(
210 "LiningToPanelOffsetY",
211 draft.lining_to_panel_offset_y,
212 Measure::Length,
213 )?,
214 ),
215 ];
216 Ok(Rooted {
217 entity: ENTITY,
218 global_id,
219 name: draft.name,
220 description: draft.description,
221 values,
222 })
223}
224
225#[derive(Debug, Clone, Copy, Default)]
227pub struct WindowLiningDraft<'a> {
228 pub name: Option<&'a str>,
230 pub description: Option<&'a str>,
232 pub lining_depth: Option<f64>,
234 pub lining_thickness: Option<f64>,
236 pub transom_thickness: Option<f64>,
238 pub mullion_thickness: Option<f64>,
240 pub first_transom_offset: Option<f64>,
242 pub second_transom_offset: Option<f64>,
244 pub first_mullion_offset: Option<f64>,
246 pub second_mullion_offset: Option<f64>,
248 pub shape_aspect_style: Option<EntityId>,
250 pub lining_offset: Option<f64>,
252 pub lining_to_panel_offset_x: Option<f64>,
254 pub lining_to_panel_offset_y: Option<f64>,
256}
257
258pub fn add_window_lining_properties(
276 tx: &mut Transaction,
277 global_id: &str,
278 draft: WindowLiningDraft<'_>,
279) -> PropertyResult<EntityId> {
280 stage_ifc4(tx, window_lining(global_id, draft)?)
281}
282
283pub fn add_window_lining_properties_with_owner_history(
294 tx: &mut Transaction,
295 model: &Model,
296 global_id: &str,
297 draft: WindowLiningDraft<'_>,
298 owner_history: EntityId,
299) -> PropertyResult<EntityId> {
300 stage_owned(tx, model, window_lining(global_id, draft)?, owner_history)
301}
302
303fn window_lining<'a>(
304 global_id: &'a str,
305 draft: WindowLiningDraft<'a>,
306) -> PropertyResult<Rooted<'a>> {
307 const ENTITY: &str = "IFCWINDOWLININGPROPERTIES";
308 if draft.lining_depth.is_some() && draft.lining_thickness.is_none() {
309 return Err(invalid(
310 ENTITY,
311 "LiningThickness",
312 "WR31: a lining depth needs its thickness",
313 ));
314 }
315 if draft.second_transom_offset.is_some() && draft.first_transom_offset.is_none() {
316 return Err(invalid(
317 ENTITY,
318 "SecondTransomOffset",
319 "WR32: a second transom offset needs the first",
320 ));
321 }
322 if draft.second_mullion_offset.is_some() && draft.first_mullion_offset.is_none() {
323 return Err(invalid(
324 ENTITY,
325 "SecondMullionOffset",
326 "WR33: a second mullion offset needs the first",
327 ));
328 }
329 require_guid(ENTITY, global_id)?;
330 let m = |attribute, value, kind| measure(ENTITY, attribute, value, kind);
331 let r = |attribute, value| ratio(ENTITY, attribute, value);
332 let values = vec![
333 (
334 "LiningDepth",
335 m("LiningDepth", draft.lining_depth, Measure::Positive)?,
336 ),
337 (
338 "LiningThickness",
339 m(
340 "LiningThickness",
341 draft.lining_thickness,
342 Measure::NonNegative,
343 )?,
344 ),
345 (
346 "TransomThickness",
347 m(
348 "TransomThickness",
349 draft.transom_thickness,
350 Measure::NonNegative,
351 )?,
352 ),
353 (
354 "MullionThickness",
355 m(
356 "MullionThickness",
357 draft.mullion_thickness,
358 Measure::NonNegative,
359 )?,
360 ),
361 (
362 "FirstTransomOffset",
363 r("FirstTransomOffset", draft.first_transom_offset)?,
364 ),
365 (
366 "SecondTransomOffset",
367 r("SecondTransomOffset", draft.second_transom_offset)?,
368 ),
369 (
370 "FirstMullionOffset",
371 r("FirstMullionOffset", draft.first_mullion_offset)?,
372 ),
373 (
374 "SecondMullionOffset",
375 r("SecondMullionOffset", draft.second_mullion_offset)?,
376 ),
377 (
378 "ShapeAspectStyle",
379 draft.shape_aspect_style.map_or(Value::Null, Value::Ref),
380 ),
381 (
382 "LiningOffset",
383 m("LiningOffset", draft.lining_offset, Measure::Length)?,
384 ),
385 (
386 "LiningToPanelOffsetX",
387 m(
388 "LiningToPanelOffsetX",
389 draft.lining_to_panel_offset_x,
390 Measure::Length,
391 )?,
392 ),
393 (
394 "LiningToPanelOffsetY",
395 m(
396 "LiningToPanelOffsetY",
397 draft.lining_to_panel_offset_y,
398 Measure::Length,
399 )?,
400 ),
401 ];
402 Ok(Rooted {
403 entity: ENTITY,
404 global_id,
405 name: draft.name,
406 description: draft.description,
407 values,
408 })
409}