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) -> MaterialResult<Option<f64>> {
39    let value = optional_number(entity_type, id, entity, 2, "ReferenceExtent")?;
40    if value.is_some_and(|value| value <= 0.0) {
41        return Err(MaterialError::InvalidValue {
42            entity: entity_type,
43            id,
44            attribute: "ReferenceExtent",
45            value: "expected a positive length".to_owned(),
46        });
47    }
48    Ok(value)
49}
50
51macro_rules! usage_accessors {
52    ($type:ident, $ifc_name:literal) => {
53        impl $type<'_> {
54            /// `ForProfileSet`. Required.
55            pub fn profile_set_id(self) -> MaterialResult<EntityId> {
56                required_ref($ifc_name, self.id(), self.entity(), 0, "ForProfileSet")
57            }
58
59            /// `CardinalPoint`, if given. Must decode to a positive
60            /// `IfcCardinalPointReference`.
61            pub fn cardinal_point(self) -> MaterialResult<Option<CardinalPointReference>> {
62                cardinal($ifc_name, self.id(), self.entity(), 1, "CardinalPoint")
63            }
64
65            /// `ReferenceExtent`, if given. Must be strictly positive when
66            /// present.
67            pub fn reference_extent(self) -> MaterialResult<Option<f64>> {
68                positive_extent($ifc_name, self.id(), self.entity())
69            }
70        }
71    };
72}
73usage_accessors!(MaterialProfileSetUsage, "IFCMATERIALPROFILESETUSAGE");
74usage_accessors!(
75    MaterialProfileSetUsageTapering,
76    "IFCMATERIALPROFILESETUSAGETAPERING"
77);
78
79impl MaterialProfileSetUsageTapering<'_> {
80    /// `IfcMaterialProfileSetUsageTapering.ForProfileEndSet`. Required.
81    pub fn end_profile_set_id(self) -> MaterialResult<EntityId> {
82        required_ref(
83            "IFCMATERIALPROFILESETUSAGETAPERING",
84            self.id(),
85            self.entity(),
86            3,
87            "ForProfileEndSet",
88        )
89    }
90
91    /// `IfcMaterialProfileSetUsageTapering.CardinalEndPoint`, if given.
92    /// Must decode to a positive `IfcCardinalPointReference`.
93    pub fn cardinal_end_point(self) -> MaterialResult<Option<CardinalPointReference>> {
94        cardinal(
95            "IFCMATERIALPROFILESETUSAGETAPERING",
96            self.id(),
97            self.entity(),
98            4,
99            "CardinalEndPoint",
100        )
101    }
102}
103
104impl<'m> MaterialView<'m> {
105    /// Iterates every `IfcMaterialProfileSetUsage` instance in the model.
106    pub fn profile_set_usages(self) -> impl Iterator<Item = MaterialProfileSetUsage<'m>> + 'm {
107        self.model()
108            .of_type("IFCMATERIALPROFILESETUSAGE")
109            .map(|(id, entity)| MaterialProfileSetUsage::from_known(id, entity))
110    }
111
112    /// Iterates every `IfcMaterialProfileSetUsageTapering` instance in the
113    /// model.
114    pub fn tapering_profile_set_usages(
115        self,
116    ) -> impl Iterator<Item = MaterialProfileSetUsageTapering<'m>> + 'm {
117        self.model()
118            .of_type("IFCMATERIALPROFILESETUSAGETAPERING")
119            .map(|(id, entity)| MaterialProfileSetUsageTapering::from_known(id, entity))
120    }
121}