use ifc_model::{EntityId, Model};
use super::enumerate::{collect, list_sets, Selector};
use super::refs::{ref_at, require_ref};
use super::release::{validate_model, Release};
use super::set::find_property;
use super::{
ExactPropertyEntry, ExactPropertyError, ExactPropertySetEntry, ExactResolution, ExactSource,
};
fn material_sets(
model: &Model,
release: Release,
material: EntityId,
) -> Result<Vec<EntityId>, ExactPropertyError> {
let schema = release.schema;
let entity = model
.get(material)
.ok_or(ExactPropertyError::MissingReference {
from: material,
to: material,
})?;
if schema.entity(entity.type_name.as_ref()).is_none() {
return Err(release.not_in_schema(material, entity.type_name.clone()));
}
let (material_slot, _) = release
.attribute("IFCMATERIALPROPERTIES", "Material")
.expect("IfcMaterialProperties.Material is declared in every bundled release");
if !release.slot_accepts(
"IFCMATERIALPROPERTIES",
material_slot,
entity.type_name.as_ref(),
) {
return Err(ExactPropertyError::InvalidQueryObject {
object: material,
type_name: entity.type_name.clone(),
});
}
release.require_exact_slots(material, entity)?;
let mut ids: Vec<EntityId> = model
.type_histogram()
.into_iter()
.filter(|(type_name, _)| {
schema.entity(type_name).is_some() && schema.is_a(type_name, "IFCMATERIALPROPERTIES")
})
.flat_map(|(type_name, _)| model.ids_of_type(type_name).iter().copied())
.collect();
ids.sort_unstable();
let mut sets = Vec::new();
for id in ids {
let set = model.get(id).expect("type index is current");
release.require_exact_slots(id, set)?;
let target = ref_at(id, set.attributes.get(material_slot), "Material")?;
require_ref(model, id, target)?;
if target == material {
sets.push(id);
}
}
Ok(sets)
}
pub fn exact_material_property(
model: &Model,
material: EntityId,
set_name: Option<&str>,
property_name: &str,
) -> Result<ExactResolution, ExactPropertyError> {
let release = validate_model(model)?;
let sets = material_sets(model, release, material)?;
Ok(find_property(
model,
release,
&sets,
ExactSource::Material(material),
set_name,
property_name,
)?
.map_or(ExactResolution::Absent, ExactResolution::Present))
}
pub fn exact_material_properties_where<S, P>(
model: &Model,
material: EntityId,
mut select_set: S,
mut select_property: P,
) -> Result<Vec<ExactPropertyEntry>, ExactPropertyError>
where
S: FnMut(&str) -> bool,
P: FnMut(&str) -> bool,
{
let release = validate_model(model)?;
let sets = material_sets(model, release, material)?;
let mut selector = Selector {
set: &mut select_set,
property: &mut select_property,
};
collect(
model,
release,
&sets,
ExactSource::Material(material),
&mut selector,
)
}
pub fn exact_material_property_sets_where<S>(
model: &Model,
material: EntityId,
mut select_set: S,
) -> Result<Vec<ExactPropertySetEntry>, ExactPropertyError>
where
S: FnMut(&str) -> bool,
{
let release = validate_model(model)?;
let sets = material_sets(model, release, material)?;
list_sets(
model,
release,
&sets,
ExactSource::Material(material),
&mut select_set,
)
}