Skip to main content

ifc_material/profile/
usage.rs

1//! `IfcMaterialProfileSetUsage` and tapering authored fields.
2
3use ifc_model::EntityId;
4
5use crate::view::{borrowed_entity, optional_integer, optional_number, required_ref, MaterialView};
6use crate::{CardinalPointReference, MaterialError, MaterialResult};
7
8borrowed_entity!(MaterialProfileSetUsage, "IFCMATERIALPROFILESETUSAGE");
9borrowed_entity!(
10    MaterialProfileSetUsageTapering,
11    "IFCMATERIALPROFILESETUSAGETAPERING"
12);
13
14fn cardinal(
15    entity_type: &'static str,
16    id: EntityId,
17    entity: &ifc_model::Entity,
18    slot: usize,
19    attribute: &'static str,
20) -> MaterialResult<Option<CardinalPointReference>> {
21    let Some(value) = optional_integer(entity_type, id, entity, slot, attribute)? else {
22        return Ok(None);
23    };
24    CardinalPointReference::new(value)
25        .map(Some)
26        .ok_or_else(|| MaterialError::InvalidValue {
27            entity: entity_type,
28            id,
29            attribute,
30            value: value.to_string(),
31        })
32}
33
34fn positive_extent(
35    entity_type: &'static str,
36    id: EntityId,
37    entity: &ifc_model::Entity,
38    slot: usize,
39) -> MaterialResult<Option<f64>> {
40    let value = optional_number(entity_type, id, entity, slot, "ReferenceExtent")?;
41    if value.is_some_and(|value| value <= 0.0) {
42        return Err(MaterialError::InvalidValue {
43            entity: entity_type,
44            id,
45            attribute: "ReferenceExtent",
46            value: "expected a positive length".to_owned(),
47        });
48    }
49    Ok(value)
50}
51
52macro_rules! usage_accessors {
53    ($type:ident, $ifc_name:literal) => {
54        impl $type<'_> {
55            /// `ForProfileSet`. Required.
56            pub fn profile_set_id(self) -> MaterialResult<EntityId> {
57                required_ref(
58                    $ifc_name,
59                    self.id(),
60                    self.entity(),
61                    self.slot("ForProfileSet")?,
62                    "ForProfileSet",
63                )
64            }
65
66            /// `CardinalPoint`, if given. Must decode to a positive
67            /// `IfcCardinalPointReference`.
68            pub fn cardinal_point(self) -> MaterialResult<Option<CardinalPointReference>> {
69                cardinal(
70                    $ifc_name,
71                    self.id(),
72                    self.entity(),
73                    self.slot("CardinalPoint")?,
74                    "CardinalPoint",
75                )
76            }
77
78            /// `ReferenceExtent`, if given. Must be strictly positive when
79            /// present.
80            pub fn reference_extent(self) -> MaterialResult<Option<f64>> {
81                positive_extent(
82                    $ifc_name,
83                    self.id(),
84                    self.entity(),
85                    self.slot("ReferenceExtent")?,
86                )
87            }
88        }
89    };
90}
91usage_accessors!(MaterialProfileSetUsage, "IFCMATERIALPROFILESETUSAGE");
92usage_accessors!(
93    MaterialProfileSetUsageTapering,
94    "IFCMATERIALPROFILESETUSAGETAPERING"
95);
96
97impl MaterialProfileSetUsageTapering<'_> {
98    /// `IfcMaterialProfileSetUsageTapering.ForProfileEndSet`. Required.
99    pub fn end_profile_set_id(self) -> MaterialResult<EntityId> {
100        required_ref(
101            "IFCMATERIALPROFILESETUSAGETAPERING",
102            self.id(),
103            self.entity(),
104            self.slot("ForProfileEndSet")?,
105            "ForProfileEndSet",
106        )
107    }
108
109    /// `IfcMaterialProfileSetUsageTapering.CardinalEndPoint`, if given.
110    /// Must decode to a positive `IfcCardinalPointReference`.
111    pub fn cardinal_end_point(self) -> MaterialResult<Option<CardinalPointReference>> {
112        cardinal(
113            "IFCMATERIALPROFILESETUSAGETAPERING",
114            self.id(),
115            self.entity(),
116            self.slot("CardinalEndPoint")?,
117            "CardinalEndPoint",
118        )
119    }
120}
121
122impl<'m> MaterialView<'m> {
123    /// Iterates every `IfcMaterialProfileSetUsage` instance in the model.
124    pub fn profile_set_usages(self) -> impl Iterator<Item = MaterialProfileSetUsage<'m>> + 'm {
125        let release = self.release();
126        self.model()
127            .of_type("IFCMATERIALPROFILESETUSAGE")
128            .map(move |(id, entity)| MaterialProfileSetUsage::from_known(id, entity, release))
129    }
130
131    /// Iterates every `IfcMaterialProfileSetUsageTapering` instance in the
132    /// model.
133    pub fn tapering_profile_set_usages(
134        self,
135    ) -> impl Iterator<Item = MaterialProfileSetUsageTapering<'m>> + 'm {
136        let release = self.release();
137        self.model()
138            .of_type("IFCMATERIALPROFILESETUSAGETAPERING")
139            .map(move |(id, entity)| {
140                MaterialProfileSetUsageTapering::from_known(id, entity, release)
141            })
142    }
143}