#![cfg(all(feature = "spatial", feature = "properties"))]
mod members;
use ifc_model::{EntityId, Model};
use ifc_properties::{
exact_properties, exact_properties_where, exact_schema, ExactPropertyEntry, ExactPropertyError,
SchemaVersion,
};
use ifc_spatial::{SpatialKind, SpatialTree};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[non_exhaustive]
pub enum SpatialMembership {
Contained,
Part {
whole: EntityId,
},
Referenced,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum ContainerName<'v> {
Unset,
Text(&'v str),
Malformed,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub struct SpatialContainer<'v> {
pub id: EntityId,
pub kind: SpatialKind,
pub type_name: &'v str,
pub name: ContainerName<'v>,
pub parent: Option<EntityId>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub struct ElementMember<'v> {
pub element: EntityId,
pub type_name: &'v str,
pub membership: SpatialMembership,
}
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub struct ElementProperties<'v> {
pub element: EntityId,
pub type_name: &'v str,
pub membership: SpatialMembership,
pub properties: Result<Vec<ExactPropertyEntry>, ExactPropertyError>,
}
#[derive(Debug, Clone)]
pub struct SpatialProperties<'m> {
model: &'m Model,
schema: SchemaVersion,
tree: SpatialTree,
containers: Vec<members::Slot<'m>>,
dangling_parts: Vec<(EntityId, EntityId)>,
}
#[derive(Debug, Clone, Copy)]
pub struct ContainerElements<'v> {
pub container: SpatialContainer<'v>,
members: &'v [ElementMember<'v>],
model: &'v Model,
}
pub fn spatial_properties(model: &Model) -> Result<SpatialProperties<'_>, ExactPropertyError> {
let schema = exact_schema(model)?;
let tree = SpatialTree::build(model);
let (containers, dangling_parts) = members::collect(model, &tree);
Ok(SpatialProperties {
model,
schema,
tree,
containers,
dangling_parts,
})
}
impl<'m> SpatialProperties<'m> {
#[must_use]
pub fn schema(&self) -> SchemaVersion {
self.schema
}
#[must_use]
pub fn tree(&self) -> &SpatialTree {
&self.tree
}
#[must_use]
pub fn dangling_parts(&self) -> &[(EntityId, EntityId)] {
&self.dangling_parts
}
pub fn containers(&self) -> impl Iterator<Item = ContainerElements<'_>> + '_ {
self.containers.iter().map(|slot| self.view(slot))
}
#[must_use]
pub fn container(&self, id: EntityId) -> Option<ContainerElements<'_>> {
let slot = self
.containers
.iter()
.find(|slot| slot.container.id == id)?;
Some(self.view(slot))
}
fn view<'v>(&'v self, slot: &'v members::Slot<'m>) -> ContainerElements<'v> {
ContainerElements {
container: slot.container,
members: &slot.members,
model: self.model,
}
}
}
impl<'v> ContainerElements<'v> {
#[must_use]
pub fn members(&self) -> &'v [ElementMember<'v>] {
self.members
}
pub fn elements(&self) -> impl Iterator<Item = ElementProperties<'v>> + 'v {
let model = self.model;
self.members
.iter()
.map(move |member| resolved(member, exact_properties(model, member.element)))
}
pub fn elements_where<S, P>(
&self,
mut select_set: S,
mut select_property: P,
) -> impl Iterator<Item = ElementProperties<'v>> + 'v
where
S: FnMut(&str) -> bool + 'v,
P: FnMut(&str) -> bool + 'v,
{
let model = self.model;
self.members.iter().map(move |member| {
let properties = exact_properties_where(
model,
member.element,
&mut select_set,
&mut select_property,
);
resolved(member, properties)
})
}
}
fn resolved<'v>(
member: &ElementMember<'v>,
properties: Result<Vec<ExactPropertyEntry>, ExactPropertyError>,
) -> ElementProperties<'v> {
ElementProperties {
element: member.element,
type_name: member.type_name,
membership: member.membership,
properties,
}
}