1use crate::select::is_a;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
19#[non_exhaustive]
20pub enum BodyKind {
21 Extrusion,
23 TaperedExtrusion,
25 Revolution,
27 TaperedRevolution,
29 DirectrixSweep,
32 SweptDisk,
35 SectionedSpine,
37 Brep,
39 Csg,
42 CsgPrimitive,
45 HalfSpace,
47 BoundingBox,
49 Tessellated,
51 SurfaceModel,
54 Face,
57 GeometricSet,
59 Curve,
61 Surface,
63 Point,
65}
66
67const FAMILIES: &[(&str, BodyKind)] = &[
70 ("IFCEXTRUDEDAREASOLID", BodyKind::Extrusion),
71 ("IFCEXTRUDEDAREASOLIDTAPERED", BodyKind::TaperedExtrusion),
72 ("IFCREVOLVEDAREASOLID", BodyKind::Revolution),
73 ("IFCREVOLVEDAREASOLIDTAPERED", BodyKind::TaperedRevolution),
74 ("IFCFIXEDREFERENCESWEPTAREASOLID", BodyKind::DirectrixSweep),
75 (
77 "IFCDIRECTRIXDERIVEDREFERENCESWEPTAREASOLID",
78 BodyKind::DirectrixSweep,
79 ),
80 ("IFCSURFACECURVESWEPTAREASOLID", BodyKind::DirectrixSweep),
81 ("IFCSWEPTDISKSOLID", BodyKind::SweptDisk),
82 ("IFCSWEPTDISKSOLIDPOLYGONAL", BodyKind::SweptDisk),
83 ("IFCSECTIONEDSPINE", BodyKind::SectionedSpine),
84 ("IFCFACETEDBREP", BodyKind::Brep),
85 ("IFCFACETEDBREPWITHVOIDS", BodyKind::Brep),
86 ("IFCADVANCEDBREP", BodyKind::Brep),
87 ("IFCADVANCEDBREPWITHVOIDS", BodyKind::Brep),
88 ("IFCCSGSOLID", BodyKind::Csg),
89 ("IFCBOOLEANRESULT", BodyKind::Csg),
90 ("IFCBOOLEANCLIPPINGRESULT", BodyKind::Csg),
91 ("IFCBLOCK", BodyKind::CsgPrimitive),
92 ("IFCSPHERE", BodyKind::CsgPrimitive),
93 ("IFCRIGHTCIRCULARCYLINDER", BodyKind::CsgPrimitive),
94 ("IFCRIGHTCIRCULARCONE", BodyKind::CsgPrimitive),
95 ("IFCRECTANGULARPYRAMID", BodyKind::CsgPrimitive),
96 ("IFCHALFSPACESOLID", BodyKind::HalfSpace),
97 ("IFCBOXEDHALFSPACE", BodyKind::HalfSpace),
98 ("IFCPOLYGONALBOUNDEDHALFSPACE", BodyKind::HalfSpace),
99 ("IFCBOUNDINGBOX", BodyKind::BoundingBox),
100 ("IFCTRIANGULATEDFACESET", BodyKind::Tessellated),
101 ("IFCTRIANGULATEDIRREGULARNETWORK", BodyKind::Tessellated),
103 ("IFCPOLYGONALFACESET", BodyKind::Tessellated),
104 ("IFCSHELLBASEDSURFACEMODEL", BodyKind::SurfaceModel),
105 ("IFCFACEBASEDSURFACEMODEL", BodyKind::SurfaceModel),
106 ("IFCFACESURFACE", BodyKind::Face),
107 ("IFCADVANCEDFACE", BodyKind::Face),
108 ("IFCGEOMETRICSET", BodyKind::GeometricSet),
109 ("IFCGEOMETRICCURVESET", BodyKind::GeometricSet),
110 ("IFCPOINTONCURVE", BodyKind::Point),
111 ("IFCPOINTONSURFACE", BodyKind::Point),
112 ("IFCCURVESEGMENT", BodyKind::Curve),
115];
116
117impl BodyKind {
118 pub fn classify(type_name: &str) -> Option<Self> {
123 let upper = type_name.to_ascii_uppercase();
124 if is_a(&upper, "IFCCURVE") {
127 return Some(Self::Curve);
128 }
129 if is_a(&upper, "IFCSURFACE") {
130 return Some(Self::Surface);
131 }
132 FAMILIES
133 .iter()
134 .find(|(name, _)| *name == upper)
135 .map(|(_, kind)| *kind)
136 }
137
138 pub fn is_swept_area(self) -> bool {
141 matches!(
142 self,
143 Self::Extrusion
144 | Self::TaperedExtrusion
145 | Self::Revolution
146 | Self::TaperedRevolution
147 | Self::DirectrixSweep
148 )
149 }
150}
151
152#[cfg(test)]
153mod tests {
154 use super::*;
155 use crate::solid::SolidKind;
156
157 #[test]
159 fn body_kinds_refine_solid_kinds() {
160 for (name, kind) in FAMILIES {
161 let Some(solid) = SolidKind::classify(name) else {
162 continue;
163 };
164 let expected = match kind {
165 BodyKind::Extrusion
166 | BodyKind::TaperedExtrusion
167 | BodyKind::Revolution
168 | BodyKind::TaperedRevolution
169 | BodyKind::DirectrixSweep
170 | BodyKind::SweptDisk => SolidKind::Swept,
171 BodyKind::SectionedSpine => SolidKind::SectionedSpine,
172 BodyKind::Brep => SolidKind::Brep,
173 BodyKind::Csg if *name == "IFCCSGSOLID" => SolidKind::Csg,
174 BodyKind::Csg => SolidKind::Boolean,
175 BodyKind::CsgPrimitive => SolidKind::Csg,
176 BodyKind::HalfSpace => SolidKind::HalfSpace,
177 BodyKind::BoundingBox => SolidKind::BoundingBox,
178 BodyKind::Tessellated => SolidKind::Tessellated,
179 BodyKind::SurfaceModel | BodyKind::GeometricSet => SolidKind::SurfaceModel,
180 other => panic!("{name} classified {other:?} is not a solid family"),
181 };
182 assert_eq!(solid, expected, "{name}");
183 }
184 }
185
186 #[test]
187 fn curves_and_surfaces_classify_by_inheritance() {
188 assert_eq!(BodyKind::classify("IfcTrimmedCurve"), Some(BodyKind::Curve));
189 assert_eq!(BodyKind::classify("IFCPLANE"), Some(BodyKind::Surface));
190 assert_eq!(BodyKind::classify("IfcFaceSurface"), Some(BodyKind::Face));
192 assert_eq!(BodyKind::classify("IFCADVANCEDFACE"), Some(BodyKind::Face));
193 assert_eq!(BodyKind::classify("IFCMAPPEDITEM"), None);
194 assert_eq!(BodyKind::classify("IFCWALL"), None);
195 }
196
197 #[test]
200 fn ifc4x3_curves_and_surfaces_classify_by_inheritance() {
201 for curve in [
202 "IFCCLOTHOID",
203 "IFCCOSINESPIRAL",
204 "IFCSINESPIRAL",
205 "IFCSECONDORDERPOLYNOMIALSPIRAL",
206 "IFCTHIRDORDERPOLYNOMIALSPIRAL",
207 "IFCSEVENTHORDERPOLYNOMIALSPIRAL",
208 "IFCPOLYNOMIALCURVE",
209 "IFCOFFSETCURVEBYDISTANCES",
210 "IFCSEGMENTEDREFERENCECURVE",
211 "IFCGRADIENTCURVE",
212 ] {
213 assert_eq!(BodyKind::classify(curve), Some(BodyKind::Curve), "{curve}");
214 }
215 assert_eq!(
216 BodyKind::classify("IFCSECTIONEDSURFACE"),
217 Some(BodyKind::Surface)
218 );
219 assert_eq!(BodyKind::classify("IFCCURVESEGMENT"), Some(BodyKind::Curve));
222 assert!(!crate::select::is_a("IFCCURVESEGMENT", "IFCCURVE"));
223 }
224}