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}