use ifc_model::EntityId;
use crate::layer::definition::layer_thickness;
use crate::view::{borrowed_entity, optional_text, required_refs, MaterialView};
use crate::{MaterialError, MaterialResult};
borrowed_entity!(MaterialLayerSet, "IFCMATERIALLAYERSET");
impl<'m> MaterialLayerSet<'m> {
pub fn layer_ids(self) -> MaterialResult<Vec<EntityId>> {
required_refs(
"IFCMATERIALLAYERSET",
self.id(),
self.entity(),
self.slot("MaterialLayers")?,
"MaterialLayers",
1,
)
}
pub fn name(self) -> MaterialResult<Option<&'m str>> {
optional_text(
"IFCMATERIALLAYERSET",
self.id(),
self.entity(),
self.slot("LayerSetName")?,
"LayerSetName",
)
}
pub fn description(self) -> MaterialResult<Option<&'m str>> {
optional_text(
"IFCMATERIALLAYERSET",
self.id(),
self.entity(),
self.slot("Description")?,
"Description",
)
}
}
impl<'m> MaterialView<'m> {
pub fn layer_sets(self) -> impl Iterator<Item = MaterialLayerSet<'m>> + 'm {
let release = self.release();
self.model()
.of_type("IFCMATERIALLAYERSET")
.map(move |(id, entity)| MaterialLayerSet::from_known(id, entity, release))
}
pub fn total_thickness(self, set: MaterialLayerSet<'m>) -> MaterialResult<f64> {
let mut total = 0.0;
for layer_id in set.layer_ids()? {
let layer = self.entity(set.id(), layer_id)?;
let entity_type = if layer.is_type("IFCMATERIALLAYER") {
"IFCMATERIALLAYER"
} else if layer.is_type("IFCMATERIALLAYERWITHOFFSETS") {
"IFCMATERIALLAYERWITHOFFSETS"
} else {
return Err(MaterialError::ReferenceType {
source_id: set.id(),
target: layer_id,
expected: "IFCMATERIALLAYER",
actual: layer.type_name.to_string(),
});
};
total += layer_thickness(entity_type, layer_id, layer, set.release())?;
if !total.is_finite() {
return Err(MaterialError::InvalidValue {
entity: "IFCMATERIALLAYERSET",
id: set.id(),
attribute: "TotalThickness",
value: "finite layer thicknesses overflowed the aggregate".to_owned(),
});
}
}
Ok(total)
}
}