use ifc_model::{Entity, EntityId, Model};
use crate::error::{GeometryError, GeometryResult};
use crate::slots::Slots;
pub mod slot {
pub const POLYGON: usize = 0;
pub const BOUND: usize = 0;
pub const ORIENTATION: usize = 1;
pub const BOUNDS: usize = 0;
pub const CFS_FACES: usize = 0;
pub const OUTER: usize = 0;
pub const VOIDS: usize = 1;
pub const VERTEX_GEOMETRY: usize = 0;
pub const EDGE_START: usize = 0;
pub const EDGE_END: usize = 1;
pub const EDGE_GEOMETRY: usize = 2;
pub const EDGE_SAME_SENSE: usize = 3;
pub const EDGE_ELEMENT: usize = 2;
pub const EDGE_ORIENTATION: usize = 3;
pub const PARENT_EDGE: usize = 2;
pub const EDGE_LIST: usize = 0;
pub const FACE_SURFACE: usize = 1;
pub const FACE_SAME_SENSE: usize = 2;
}
#[derive(Debug, Clone, Copy)]
pub struct PolyLoop<'m> {
slots: Slots<'m>,
}
impl<'m> PolyLoop<'m> {
pub fn new(id: EntityId, entity: &'m Entity) -> Self {
Self {
slots: Slots::new(id, entity),
}
}
pub fn id(&self) -> EntityId {
self.slots.id()
}
pub fn polygon(&self) -> GeometryResult<Vec<EntityId>> {
let points = self.slots.req_ref_list(slot::POLYGON, "Polygon")?;
if points.len() < 3 {
return Err(self.slots.degenerate(format!(
"polygon has {} points; a loop needs at least 3",
points.len()
)));
}
Ok(points)
}
}
#[derive(Debug, Clone, Copy)]
pub struct FaceBound<'m> {
slots: Slots<'m>,
}
impl<'m> FaceBound<'m> {
pub fn new(id: EntityId, entity: &'m Entity) -> Self {
Self {
slots: Slots::new(id, entity),
}
}
pub fn id(&self) -> EntityId {
self.slots.id()
}
pub fn bound(&self) -> GeometryResult<EntityId> {
self.slots.req_ref(slot::BOUND, "Bound")
}
pub fn orientation(&self) -> GeometryResult<bool> {
self.slots.req_bool(slot::ORIENTATION, "Orientation")
}
pub fn is_outer(&self) -> bool {
self.slots
.type_name()
.eq_ignore_ascii_case("IFCFACEOUTERBOUND")
}
}
#[derive(Debug, Clone, Copy)]
pub struct Face<'m> {
slots: Slots<'m>,
}
impl<'m> Face<'m> {
pub fn new(id: EntityId, entity: &'m Entity) -> Self {
Self {
slots: Slots::new(id, entity),
}
}
pub fn id(&self) -> EntityId {
self.slots.id()
}
pub fn bounds(&self) -> GeometryResult<Vec<EntityId>> {
let bounds = self.slots.req_ref_list(slot::BOUNDS, "Bounds")?;
if bounds.is_empty() {
return Err(self.slots.degenerate("face has no bounds"));
}
Ok(bounds)
}
}
#[derive(Debug, Clone, Copy)]
pub struct ConnectedFaceSet<'m> {
slots: Slots<'m>,
}
impl<'m> ConnectedFaceSet<'m> {
pub fn new(id: EntityId, entity: &'m Entity) -> Self {
Self {
slots: Slots::new(id, entity),
}
}
pub fn id(&self) -> EntityId {
self.slots.id()
}
pub fn faces(&self) -> GeometryResult<Vec<EntityId>> {
let faces = self.slots.req_ref_list(slot::CFS_FACES, "CfsFaces")?;
if faces.is_empty() {
return Err(self.slots.degenerate("face set has no faces"));
}
Ok(faces)
}
pub fn is_closed(&self) -> bool {
self.slots
.type_name()
.eq_ignore_ascii_case("IFCCLOSEDSHELL")
}
}
#[derive(Debug, Clone, Copy)]
pub struct ManifoldSolidBrep<'m> {
slots: Slots<'m>,
}
impl<'m> ManifoldSolidBrep<'m> {
pub fn new(id: EntityId, entity: &'m Entity) -> Self {
Self {
slots: Slots::new(id, entity),
}
}
pub fn id(&self) -> EntityId {
self.slots.id()
}
pub fn outer(&self) -> GeometryResult<EntityId> {
self.slots.req_ref(slot::OUTER, "Outer")
}
pub fn voids(&self) -> GeometryResult<Vec<EntityId>> {
if !self
.slots
.type_name()
.eq_ignore_ascii_case("IFCFACETEDBREPWITHVOIDS")
{
return Ok(Vec::new());
}
let voids = self.slots.req_ref_list(slot::VOIDS, "Voids")?;
if voids.is_empty() {
return Err(self
.slots
.degenerate("IfcFacetedBrepWithVoids declares no voids"));
}
Ok(voids)
}
}
pub fn expect_type<'m>(
model: &'m Model,
referrer: EntityId,
id: EntityId,
accepted: &[&str],
expected: &'static str,
) -> GeometryResult<&'m Entity> {
let entity = model.get(id).ok_or(GeometryError::MissingEntity {
referrer,
missing: id,
})?;
if accepted
.iter()
.any(|name| entity.type_name.eq_ignore_ascii_case(name))
{
return Ok(entity);
}
Err(GeometryError::WrongEntityType {
entity: id,
actual: entity.type_name.to_string(),
expected,
})
}
#[derive(Debug, Clone, Copy)]
pub struct VertexPoint<'m> {
slots: Slots<'m>,
}
impl<'m> VertexPoint<'m> {
pub fn new(id: EntityId, entity: &'m Entity) -> Self {
Self {
slots: Slots::new(id, entity),
}
}
pub fn id(&self) -> EntityId {
self.slots.id()
}
pub fn vertex_geometry(&self) -> GeometryResult<EntityId> {
self.slots.req_ref(slot::VERTEX_GEOMETRY, "VertexGeometry")
}
}
#[derive(Debug, Clone, Copy)]
pub struct Subedge<'m> {
slots: Slots<'m>,
}
impl<'m> Subedge<'m> {
pub fn new(id: EntityId, entity: &'m Entity) -> Self {
Self {
slots: Slots::new(id, entity),
}
}
pub fn id(&self) -> EntityId {
self.slots.id()
}
pub fn start(&self) -> GeometryResult<EntityId> {
self.slots.req_ref(slot::EDGE_START, "EdgeStart")
}
pub fn end(&self) -> GeometryResult<EntityId> {
self.slots.req_ref(slot::EDGE_END, "EdgeEnd")
}
pub fn parent_edge(&self) -> GeometryResult<EntityId> {
self.slots.req_ref(slot::PARENT_EDGE, "ParentEdge")
}
}
#[derive(Debug, Clone, Copy)]
pub struct EdgeCurve<'m> {
slots: Slots<'m>,
}
impl<'m> EdgeCurve<'m> {
pub fn new(id: EntityId, entity: &'m Entity) -> Self {
Self {
slots: Slots::new(id, entity),
}
}
pub fn id(&self) -> EntityId {
self.slots.id()
}
pub fn start(&self) -> GeometryResult<EntityId> {
self.slots.req_ref(slot::EDGE_START, "EdgeStart")
}
pub fn end(&self) -> GeometryResult<EntityId> {
self.slots.req_ref(slot::EDGE_END, "EdgeEnd")
}
pub fn edge_geometry(&self) -> Option<EntityId> {
self.slots.opt_ref(slot::EDGE_GEOMETRY)
}
pub fn same_sense(&self) -> bool {
self.slots.opt_bool(slot::EDGE_SAME_SENSE).unwrap_or(true)
}
}
#[derive(Debug, Clone, Copy)]
pub struct OrientedEdge<'m> {
slots: Slots<'m>,
}
impl<'m> OrientedEdge<'m> {
pub fn new(id: EntityId, entity: &'m Entity) -> Self {
Self {
slots: Slots::new(id, entity),
}
}
pub fn edge_element(&self) -> GeometryResult<EntityId> {
self.slots.req_ref(slot::EDGE_ELEMENT, "EdgeElement")
}
pub fn orientation(&self) -> bool {
self.slots.opt_bool(slot::EDGE_ORIENTATION).unwrap_or(true)
}
}
#[derive(Debug, Clone, Copy)]
pub struct EdgeLoop<'m> {
slots: Slots<'m>,
}
impl<'m> EdgeLoop<'m> {
pub fn new(id: EntityId, entity: &'m Entity) -> Self {
Self {
slots: Slots::new(id, entity),
}
}
pub fn edge_list(&self) -> GeometryResult<Vec<EntityId>> {
let edges = self.slots.req_ref_list(slot::EDGE_LIST, "EdgeList")?;
if edges.is_empty() {
return Err(self.slots.degenerate("edge loop has no edges"));
}
Ok(edges)
}
}
#[derive(Debug, Clone, Copy)]
pub struct FaceSurface<'m> {
slots: Slots<'m>,
}
impl<'m> FaceSurface<'m> {
pub fn new(id: EntityId, entity: &'m Entity) -> Self {
Self {
slots: Slots::new(id, entity),
}
}
pub fn face_surface(&self) -> GeometryResult<EntityId> {
self.slots.req_ref(slot::FACE_SURFACE, "FaceSurface")
}
pub fn same_sense(&self) -> bool {
self.slots.opt_bool(slot::FACE_SAME_SENSE).unwrap_or(true)
}
}