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 ("IFCSURFACECURVESWEPTAREASOLID", BodyKind::DirectrixSweep),
76 ("IFCSWEPTDISKSOLID", BodyKind::SweptDisk),
77 ("IFCSWEPTDISKSOLIDPOLYGONAL", BodyKind::SweptDisk),
78 ("IFCSECTIONEDSPINE", BodyKind::SectionedSpine),
79 ("IFCFACETEDBREP", BodyKind::Brep),
80 ("IFCFACETEDBREPWITHVOIDS", BodyKind::Brep),
81 ("IFCADVANCEDBREP", BodyKind::Brep),
82 ("IFCADVANCEDBREPWITHVOIDS", BodyKind::Brep),
83 ("IFCCSGSOLID", BodyKind::Csg),
84 ("IFCBOOLEANRESULT", BodyKind::Csg),
85 ("IFCBOOLEANCLIPPINGRESULT", BodyKind::Csg),
86 ("IFCBLOCK", BodyKind::CsgPrimitive),
87 ("IFCSPHERE", BodyKind::CsgPrimitive),
88 ("IFCRIGHTCIRCULARCYLINDER", BodyKind::CsgPrimitive),
89 ("IFCRIGHTCIRCULARCONE", BodyKind::CsgPrimitive),
90 ("IFCRECTANGULARPYRAMID", BodyKind::CsgPrimitive),
91 ("IFCHALFSPACESOLID", BodyKind::HalfSpace),
92 ("IFCBOXEDHALFSPACE", BodyKind::HalfSpace),
93 ("IFCPOLYGONALBOUNDEDHALFSPACE", BodyKind::HalfSpace),
94 ("IFCBOUNDINGBOX", BodyKind::BoundingBox),
95 ("IFCTRIANGULATEDFACESET", BodyKind::Tessellated),
96 ("IFCPOLYGONALFACESET", BodyKind::Tessellated),
97 ("IFCSHELLBASEDSURFACEMODEL", BodyKind::SurfaceModel),
98 ("IFCFACEBASEDSURFACEMODEL", BodyKind::SurfaceModel),
99 ("IFCFACESURFACE", BodyKind::Face),
100 ("IFCADVANCEDFACE", BodyKind::Face),
101 ("IFCGEOMETRICSET", BodyKind::GeometricSet),
102 ("IFCGEOMETRICCURVESET", BodyKind::GeometricSet),
103 ("IFCPOINTONCURVE", BodyKind::Point),
104 ("IFCPOINTONSURFACE", BodyKind::Point),
105];
106
107impl BodyKind {
108 pub fn classify(type_name: &str) -> Option<Self> {
113 let upper = type_name.to_ascii_uppercase();
114 if is_a(&upper, "IFCCURVE") {
117 return Some(Self::Curve);
118 }
119 if is_a(&upper, "IFCSURFACE") {
120 return Some(Self::Surface);
121 }
122 FAMILIES
123 .iter()
124 .find(|(name, _)| *name == upper)
125 .map(|(_, kind)| *kind)
126 }
127
128 pub fn is_swept_area(self) -> bool {
131 matches!(
132 self,
133 Self::Extrusion
134 | Self::TaperedExtrusion
135 | Self::Revolution
136 | Self::TaperedRevolution
137 | Self::DirectrixSweep
138 )
139 }
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145 use crate::solid::SolidKind;
146
147 #[test]
149 fn body_kinds_refine_solid_kinds() {
150 for (name, kind) in FAMILIES {
151 let Some(solid) = SolidKind::classify(name) else {
152 continue;
153 };
154 let expected = match kind {
155 BodyKind::Extrusion
156 | BodyKind::TaperedExtrusion
157 | BodyKind::Revolution
158 | BodyKind::TaperedRevolution
159 | BodyKind::DirectrixSweep
160 | BodyKind::SweptDisk => SolidKind::Swept,
161 BodyKind::SectionedSpine => SolidKind::SectionedSpine,
162 BodyKind::Brep => SolidKind::Brep,
163 BodyKind::Csg if *name == "IFCCSGSOLID" => SolidKind::Csg,
164 BodyKind::Csg => SolidKind::Boolean,
165 BodyKind::CsgPrimitive => SolidKind::Csg,
166 BodyKind::HalfSpace => SolidKind::HalfSpace,
167 BodyKind::BoundingBox => SolidKind::BoundingBox,
168 BodyKind::Tessellated => SolidKind::Tessellated,
169 BodyKind::SurfaceModel | BodyKind::GeometricSet => SolidKind::SurfaceModel,
170 other => panic!("{name} classified {other:?} is not a solid family"),
171 };
172 assert_eq!(solid, expected, "{name}");
173 }
174 }
175
176 #[test]
177 fn curves_and_surfaces_classify_by_inheritance() {
178 assert_eq!(BodyKind::classify("IfcTrimmedCurve"), Some(BodyKind::Curve));
179 assert_eq!(BodyKind::classify("IFCPLANE"), Some(BodyKind::Surface));
180 assert_eq!(BodyKind::classify("IfcFaceSurface"), Some(BodyKind::Face));
182 assert_eq!(BodyKind::classify("IFCADVANCEDFACE"), Some(BodyKind::Face));
183 assert_eq!(BodyKind::classify("IFCMAPPEDITEM"), None);
184 assert_eq!(BodyKind::classify("IFCWALL"), None);
185 }
186}