pub mod basis;
pub mod bounded;
pub mod bspline;
pub mod elementary;
pub mod swept;
pub use bounded::{
CurveBoundedPlane, CurveBoundedSurface, RectangularTrimmedSurface, TrimRectangle,
};
pub use bspline::{BSplineSurface, BSplineSurfaceForm, ControlPointGrid};
pub use elementary::{CylindricalSurface, ParameterKind, Plane, SphericalSurface, ToroidalSurface};
pub use swept::{SurfaceOfLinearExtrusion, SurfaceOfRevolution};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SurfaceKind {
Plane,
CylindricalSurface,
SphericalSurface,
ToroidalSurface,
SurfaceOfLinearExtrusion,
SurfaceOfRevolution,
CurveBoundedPlane,
CurveBoundedSurface,
RectangularTrimmedSurface,
BSplineSurface,
BSplineSurfaceWithKnots,
RationalBSplineSurfaceWithKnots,
}
impl SurfaceKind {
pub fn classify(type_name: &str) -> Option<Self> {
match type_name.to_ascii_uppercase().as_str() {
"IFCPLANE" => Some(Self::Plane),
"IFCCYLINDRICALSURFACE" => Some(Self::CylindricalSurface),
"IFCSPHERICALSURFACE" => Some(Self::SphericalSurface),
"IFCTOROIDALSURFACE" => Some(Self::ToroidalSurface),
"IFCSURFACEOFLINEAREXTRUSION" => Some(Self::SurfaceOfLinearExtrusion),
"IFCSURFACEOFREVOLUTION" => Some(Self::SurfaceOfRevolution),
"IFCCURVEBOUNDEDPLANE" => Some(Self::CurveBoundedPlane),
"IFCCURVEBOUNDEDSURFACE" => Some(Self::CurveBoundedSurface),
"IFCRECTANGULARTRIMMEDSURFACE" => Some(Self::RectangularTrimmedSurface),
"IFCBSPLINESURFACE" => Some(Self::BSplineSurface),
"IFCBSPLINESURFACEWITHKNOTS" => Some(Self::BSplineSurfaceWithKnots),
"IFCRATIONALBSPLINESURFACEWITHKNOTS" => Some(Self::RationalBSplineSurfaceWithKnots),
_ => None,
}
}
pub fn is_elementary(self) -> bool {
matches!(
self,
Self::Plane | Self::CylindricalSurface | Self::SphericalSurface | Self::ToroidalSurface
)
}
pub fn is_bounded(self) -> bool {
matches!(
self,
Self::CurveBoundedPlane
| Self::CurveBoundedSurface
| Self::RectangularTrimmedSurface
| Self::BSplineSurface
| Self::BSplineSurfaceWithKnots
| Self::RationalBSplineSurfaceWithKnots
)
}
pub fn is_swept(self) -> bool {
matches!(
self,
Self::SurfaceOfLinearExtrusion | Self::SurfaceOfRevolution
)
}
pub fn has_basis_surface(self) -> bool {
matches!(
self,
Self::CurveBoundedPlane | Self::CurveBoundedSurface | Self::RectangularTrimmedSurface
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn every_surface_entity_in_the_schema_is_classified() {
let names = [
"IFCPLANE",
"IFCCYLINDRICALSURFACE",
"IFCSPHERICALSURFACE",
"IFCTOROIDALSURFACE",
"IFCSURFACEOFLINEAREXTRUSION",
"IFCSURFACEOFREVOLUTION",
"IFCCURVEBOUNDEDPLANE",
"IFCCURVEBOUNDEDSURFACE",
"IFCRECTANGULARTRIMMEDSURFACE",
"IFCBSPLINESURFACE",
"IFCBSPLINESURFACEWITHKNOTS",
"IFCRATIONALBSPLINESURFACEWITHKNOTS",
];
for name in names {
assert!(
SurfaceKind::classify(name).is_some(),
"{name} is unclassified"
);
}
}
#[test]
fn non_surface_entities_are_not_classified_as_surfaces() {
for name in ["IFCPOLYLINE", "IFCCIRCLE", "IFCWALL", "IFCBSPLINECURVE"] {
assert_eq!(SurfaceKind::classify(name), None, "{name}");
}
}
#[test]
fn type_names_are_matched_case_insensitively() {
assert_eq!(SurfaceKind::classify("IfcPlane"), Some(SurfaceKind::Plane));
}
#[test]
fn elementary_surfaces_are_never_self_bounding() {
for kind in [
SurfaceKind::Plane,
SurfaceKind::CylindricalSurface,
SurfaceKind::SphericalSurface,
SurfaceKind::ToroidalSurface,
] {
assert!(kind.is_elementary(), "{kind:?}");
assert!(!kind.is_bounded(), "{kind:?}");
assert!(!kind.is_swept(), "{kind:?}");
}
}
#[test]
fn bounded_surfaces_include_the_bspline_patches() {
for kind in [
SurfaceKind::CurveBoundedPlane,
SurfaceKind::CurveBoundedSurface,
SurfaceKind::RectangularTrimmedSurface,
SurfaceKind::BSplineSurfaceWithKnots,
SurfaceKind::RationalBSplineSurfaceWithKnots,
] {
assert!(kind.is_bounded(), "{kind:?}");
assert!(!kind.is_elementary(), "{kind:?}");
}
}
#[test]
fn swept_surfaces_are_the_two_profile_driven_kinds() {
assert!(SurfaceKind::SurfaceOfLinearExtrusion.is_swept());
assert!(SurfaceKind::SurfaceOfRevolution.is_swept());
assert!(!SurfaceKind::Plane.is_swept());
}
#[test]
fn only_the_wrapping_surfaces_report_a_basis_surface() {
assert!(SurfaceKind::RectangularTrimmedSurface.has_basis_surface());
assert!(SurfaceKind::CurveBoundedPlane.has_basis_surface());
assert!(SurfaceKind::CurveBoundedSurface.has_basis_surface());
assert!(!SurfaceKind::BSplineSurfaceWithKnots.has_basis_surface());
assert!(!SurfaceKind::Plane.has_basis_surface());
}
}