Skip to main content

ifc_material/
types.rs

1//! MaterialResource defined types and selects.
2
3use ifc_model::EntityId;
4
5/// Complete IFC4 ADD2 TC1 MaterialResource entity inventory, including abstracts.
6pub const IFC4_MATERIAL_RESOURCE_ENTITIES: &[&str] = &[
7    "IFCMATERIAL",
8    "IFCMATERIALCLASSIFICATIONRELATIONSHIP",
9    "IFCMATERIALCONSTITUENT",
10    "IFCMATERIALCONSTITUENTSET",
11    "IFCMATERIALDEFINITION",
12    "IFCMATERIALDEFINITIONREPRESENTATION",
13    "IFCMATERIALLAYER",
14    "IFCMATERIALLAYERSET",
15    "IFCMATERIALLAYERSETUSAGE",
16    "IFCMATERIALLAYERWITHOFFSETS",
17    "IFCMATERIALLIST",
18    "IFCMATERIALPROFILE",
19    "IFCMATERIALPROFILESET",
20    "IFCMATERIALPROFILESETUSAGE",
21    "IFCMATERIALPROFILESETUSAGETAPERING",
22    "IFCMATERIALPROFILEWITHOFFSETS",
23    "IFCMATERIALPROPERTIES",
24    "IFCMATERIALRELATIONSHIP",
25    "IFCMATERIALUSAGEDEFINITION",
26];
27
28/// Complete IFC4 ADD2 TC1 MaterialResource defined/select type inventory.
29pub const IFC4_MATERIAL_RESOURCE_TYPES: &[&str] = &[
30    "IFCCARDINALPOINTREFERENCE",
31    "IFCDIRECTIONSENSEENUM",
32    "IFCLAYERSETDIRECTIONENUM",
33    "IFCMATERIALSELECT",
34];
35
36/// IFC direction along or opposite an axis.
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
38pub enum DirectionSense {
39    /// `POSITIVE`: the layer/profile direction runs along the reference axis.
40    Positive,
41    /// `NEGATIVE`: the layer/profile direction runs opposite the reference axis.
42    Negative,
43}
44
45impl DirectionSense {
46    /// Parses an `IfcDirectionSenseEnum` token (case-insensitively). Returns
47    /// `None` for any string that is not `POSITIVE` or `NEGATIVE`.
48    pub fn parse(token: &str) -> Option<Self> {
49        match token {
50            token if token.eq_ignore_ascii_case("POSITIVE") => Some(Self::Positive),
51            token if token.eq_ignore_ascii_case("NEGATIVE") => Some(Self::Negative),
52            _ => None,
53        }
54    }
55
56    /// The `IfcDirectionSenseEnum` token for this value.
57    ///
58    /// Inverse of [`Self::parse`]; kept adjacent so the two cannot drift.
59    pub fn as_token(self) -> &'static str {
60        match self {
61            Self::Positive => "POSITIVE",
62            Self::Negative => "NEGATIVE",
63        }
64    }
65}
66
67/// Axis used to measure a material layer set.
68#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
69pub enum LayerSetDirection {
70    /// `AXIS1`: layer set thickness is measured along the first local axis.
71    Axis1,
72    /// `AXIS2`: layer set thickness is measured along the second local axis.
73    Axis2,
74    /// `AXIS3`: layer set thickness is measured along the third local axis.
75    Axis3,
76}
77
78impl LayerSetDirection {
79    /// Parses an `IfcLayerSetDirectionEnum` token (case-insensitively).
80    /// Returns `None` for any string that is not `AXIS1`, `AXIS2`, or `AXIS3`.
81    pub fn parse(token: &str) -> Option<Self> {
82        match token {
83            token if token.eq_ignore_ascii_case("AXIS1") => Some(Self::Axis1),
84            token if token.eq_ignore_ascii_case("AXIS2") => Some(Self::Axis2),
85            token if token.eq_ignore_ascii_case("AXIS3") => Some(Self::Axis3),
86            _ => None,
87        }
88    }
89
90    /// The `IfcLayerSetDirectionEnum` token for this value.
91    ///
92    /// Inverse of [`Self::parse`]; kept adjacent so the two cannot drift.
93    pub fn as_token(self) -> &'static str {
94        match self {
95            Self::Axis1 => "AXIS1",
96            Self::Axis2 => "AXIS2",
97            Self::Axis3 => "AXIS3",
98        }
99    }
100}
101
102/// IFC's three-state logical value.
103#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
104pub enum LogicalValue {
105    /// `.F.`: the logical value is definitely false.
106    False,
107    /// `.T.`: the logical value is definitely true.
108    True,
109    /// `.U.`: the logical value is unknown or not applicable.
110    Unknown,
111}
112
113/// Positive `IfcCardinalPointReference` value.
114///
115/// IFC4 constrains this defined type to values greater than zero. Values 1-19
116/// have standardized placement meanings; larger positive values remain valid
117/// schema values and are preserved.
118#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
119pub struct CardinalPointReference(u64);
120
121impl CardinalPointReference {
122    /// Builds a `CardinalPointReference` from a raw `IfcCardinalPointReference`
123    /// integer. Returns `None` if `value` is not strictly positive, per the
124    /// IFC4 WHERE rule on this defined type.
125    pub fn new(value: i64) -> Option<Self> {
126        u64::try_from(value)
127            .ok()
128            .filter(|value| *value > 0)
129            .map(Self)
130    }
131
132    /// Returns the underlying positive integer value.
133    pub fn get(self) -> u64 {
134        self.0
135    }
136
137    /// Resolves this value to its standardized placement meaning, if it
138    /// falls in the reserved 1-19 range; otherwise `None`.
139    pub fn standard(self) -> Option<StandardCardinalPoint> {
140        StandardCardinalPoint::from_number(self.0)
141    }
142}
143
144/// Standard placement meanings assigned to cardinal values 1-19.
145#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
146#[repr(u8)]
147pub enum StandardCardinalPoint {
148    /// Value 1: bottom-left corner.
149    BottomLeft = 1,
150    /// Value 2: bottom-center.
151    BottomCenter = 2,
152    /// Value 3: bottom-right corner.
153    BottomRight = 3,
154    /// Value 4: mid-depth, left side.
155    MidDepthLeft = 4,
156    /// Value 5: mid-depth, center.
157    MidDepthCenter = 5,
158    /// Value 6: mid-depth, right side.
159    MidDepthRight = 6,
160    /// Value 7: top-left corner.
161    TopLeft = 7,
162    /// Value 8: top-center.
163    TopCenter = 8,
164    /// Value 9: top-right corner.
165    TopRight = 9,
166    /// Value 10: geometric centroid of the profile.
167    GeometricCentroid = 10,
168    /// Value 11: bottom edge, at the geometric centroid's horizontal position.
169    BottomAtGeometricCentroid = 11,
170    /// Value 12: left edge, at the geometric centroid's vertical position.
171    LeftAtGeometricCentroid = 12,
172    /// Value 13: right edge, at the geometric centroid's vertical position.
173    RightAtGeometricCentroid = 13,
174    /// Value 14: top edge, at the geometric centroid's horizontal position.
175    TopAtGeometricCentroid = 14,
176    /// Value 15: the profile's shear center.
177    ShearCenter = 15,
178    /// Value 16: bottom edge, at the shear center's horizontal position.
179    BottomAtShearCenter = 16,
180    /// Value 17: left edge, at the shear center's vertical position.
181    LeftAtShearCenter = 17,
182    /// Value 18: right edge, at the shear center's vertical position.
183    RightAtShearCenter = 18,
184    /// Value 19: top edge, at the shear center's horizontal position.
185    TopAtShearCenter = 19,
186}
187
188impl StandardCardinalPoint {
189    fn from_number(value: u64) -> Option<Self> {
190        Some(match value {
191            1 => Self::BottomLeft,
192            2 => Self::BottomCenter,
193            3 => Self::BottomRight,
194            4 => Self::MidDepthLeft,
195            5 => Self::MidDepthCenter,
196            6 => Self::MidDepthRight,
197            7 => Self::TopLeft,
198            8 => Self::TopCenter,
199            9 => Self::TopRight,
200            10 => Self::GeometricCentroid,
201            11 => Self::BottomAtGeometricCentroid,
202            12 => Self::LeftAtGeometricCentroid,
203            13 => Self::RightAtGeometricCentroid,
204            14 => Self::TopAtGeometricCentroid,
205            15 => Self::ShearCenter,
206            16 => Self::BottomAtShearCenter,
207            17 => Self::LeftAtShearCenter,
208            18 => Self::RightAtShearCenter,
209            19 => Self::TopAtShearCenter,
210            _ => return None,
211        })
212    }
213}
214
215/// Resolved branch of `IfcMaterialSelect`.
216#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
217pub enum MaterialSelect {
218    /// Resolves to an `IfcMaterialDefinition` (material, layer set, profile
219    /// set, or constituent set) by its entity id.
220    Definition(EntityId),
221    /// Resolves to an `IfcMaterialList` by its entity id.
222    List(EntityId),
223    /// Resolves to an `IfcMaterialUsageDefinition` (a layer/profile set
224    /// usage) by its entity id.
225    Usage(EntityId),
226}