ifc_geometry/surface/
mod.rs1pub mod basis;
37pub mod bounded;
38pub mod bspline;
39pub mod elementary;
40pub mod swept;
41
42pub use bounded::{
43 CurveBoundedPlane, CurveBoundedSurface, RectangularTrimmedSurface, TrimRectangle,
44};
45pub use bspline::{BSplineSurface, BSplineSurfaceForm, ControlPointGrid};
46pub use elementary::{CylindricalSurface, ParameterKind, Plane, SphericalSurface, ToroidalSurface};
47pub use swept::{SurfaceOfLinearExtrusion, SurfaceOfRevolution};
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub enum SurfaceKind {
56 Plane,
58 CylindricalSurface,
60 SphericalSurface,
62 ToroidalSurface,
64 SurfaceOfLinearExtrusion,
66 SurfaceOfRevolution,
68 CurveBoundedPlane,
70 CurveBoundedSurface,
72 RectangularTrimmedSurface,
74 BSplineSurface,
76 BSplineSurfaceWithKnots,
78 RationalBSplineSurfaceWithKnots,
80}
81
82impl SurfaceKind {
83 pub fn classify(type_name: &str) -> Option<Self> {
85 match type_name.to_ascii_uppercase().as_str() {
86 "IFCPLANE" => Some(Self::Plane),
87 "IFCCYLINDRICALSURFACE" => Some(Self::CylindricalSurface),
88 "IFCSPHERICALSURFACE" => Some(Self::SphericalSurface),
89 "IFCTOROIDALSURFACE" => Some(Self::ToroidalSurface),
90 "IFCSURFACEOFLINEAREXTRUSION" => Some(Self::SurfaceOfLinearExtrusion),
91 "IFCSURFACEOFREVOLUTION" => Some(Self::SurfaceOfRevolution),
92 "IFCCURVEBOUNDEDPLANE" => Some(Self::CurveBoundedPlane),
93 "IFCCURVEBOUNDEDSURFACE" => Some(Self::CurveBoundedSurface),
94 "IFCRECTANGULARTRIMMEDSURFACE" => Some(Self::RectangularTrimmedSurface),
95 "IFCBSPLINESURFACE" => Some(Self::BSplineSurface),
96 "IFCBSPLINESURFACEWITHKNOTS" => Some(Self::BSplineSurfaceWithKnots),
97 "IFCRATIONALBSPLINESURFACEWITHKNOTS" => Some(Self::RationalBSplineSurfaceWithKnots),
98 _ => None,
99 }
100 }
101
102 pub fn is_elementary(self) -> bool {
107 matches!(
108 self,
109 Self::Plane | Self::CylindricalSurface | Self::SphericalSurface | Self::ToroidalSurface
110 )
111 }
112
113 pub fn is_bounded(self) -> bool {
118 matches!(
119 self,
120 Self::CurveBoundedPlane
121 | Self::CurveBoundedSurface
122 | Self::RectangularTrimmedSurface
123 | Self::BSplineSurface
124 | Self::BSplineSurfaceWithKnots
125 | Self::RationalBSplineSurfaceWithKnots
126 )
127 }
128
129 pub fn is_swept(self) -> bool {
131 matches!(
132 self,
133 Self::SurfaceOfLinearExtrusion | Self::SurfaceOfRevolution
134 )
135 }
136
137 pub fn has_basis_surface(self) -> bool {
143 matches!(
144 self,
145 Self::CurveBoundedPlane | Self::CurveBoundedSurface | Self::RectangularTrimmedSurface
146 )
147 }
148}
149
150#[cfg(test)]
151mod tests {
152 use super::*;
153
154 #[test]
155 fn every_surface_entity_in_the_schema_is_classified() {
156 let names = [
157 "IFCPLANE",
158 "IFCCYLINDRICALSURFACE",
159 "IFCSPHERICALSURFACE",
160 "IFCTOROIDALSURFACE",
161 "IFCSURFACEOFLINEAREXTRUSION",
162 "IFCSURFACEOFREVOLUTION",
163 "IFCCURVEBOUNDEDPLANE",
164 "IFCCURVEBOUNDEDSURFACE",
165 "IFCRECTANGULARTRIMMEDSURFACE",
166 "IFCBSPLINESURFACE",
167 "IFCBSPLINESURFACEWITHKNOTS",
168 "IFCRATIONALBSPLINESURFACEWITHKNOTS",
169 ];
170 for name in names {
171 assert!(
172 SurfaceKind::classify(name).is_some(),
173 "{name} is unclassified"
174 );
175 }
176 }
177
178 #[test]
181 fn non_surface_entities_are_not_classified_as_surfaces() {
182 for name in ["IFCPOLYLINE", "IFCCIRCLE", "IFCWALL", "IFCBSPLINECURVE"] {
183 assert_eq!(SurfaceKind::classify(name), None, "{name}");
184 }
185 }
186
187 #[test]
188 fn type_names_are_matched_case_insensitively() {
189 assert_eq!(SurfaceKind::classify("IfcPlane"), Some(SurfaceKind::Plane));
190 }
191
192 #[test]
195 fn elementary_surfaces_are_never_self_bounding() {
196 for kind in [
197 SurfaceKind::Plane,
198 SurfaceKind::CylindricalSurface,
199 SurfaceKind::SphericalSurface,
200 SurfaceKind::ToroidalSurface,
201 ] {
202 assert!(kind.is_elementary(), "{kind:?}");
203 assert!(!kind.is_bounded(), "{kind:?}");
204 assert!(!kind.is_swept(), "{kind:?}");
205 }
206 }
207
208 #[test]
209 fn bounded_surfaces_include_the_bspline_patches() {
210 for kind in [
211 SurfaceKind::CurveBoundedPlane,
212 SurfaceKind::CurveBoundedSurface,
213 SurfaceKind::RectangularTrimmedSurface,
214 SurfaceKind::BSplineSurfaceWithKnots,
215 SurfaceKind::RationalBSplineSurfaceWithKnots,
216 ] {
217 assert!(kind.is_bounded(), "{kind:?}");
218 assert!(!kind.is_elementary(), "{kind:?}");
219 }
220 }
221
222 #[test]
223 fn swept_surfaces_are_the_two_profile_driven_kinds() {
224 assert!(SurfaceKind::SurfaceOfLinearExtrusion.is_swept());
225 assert!(SurfaceKind::SurfaceOfRevolution.is_swept());
226 assert!(!SurfaceKind::Plane.is_swept());
227 }
228
229 #[test]
231 fn only_the_wrapping_surfaces_report_a_basis_surface() {
232 assert!(SurfaceKind::RectangularTrimmedSurface.has_basis_surface());
233 assert!(SurfaceKind::CurveBoundedPlane.has_basis_surface());
234 assert!(SurfaceKind::CurveBoundedSurface.has_basis_surface());
235 assert!(!SurfaceKind::BSplineSurfaceWithKnots.has_basis_surface());
236 assert!(!SurfaceKind::Plane.has_basis_surface());
237 }
238}