use std::collections::BTreeMap;
use ifc_model::{EntityId, Model};
use super::build::SpatialTree;
use crate::relation::{link, slots};
impl SpatialTree {
pub(super) fn apply_references(&mut self, model: &Model) {
let rel = slots::REFERENCED_IN;
for &relationship in model.ids_of_type(rel.type_name) {
let Some(structure) = link::refs_in_slot(model, relationship, rel.relating)
.into_iter()
.next()
else {
continue;
};
if model.get(structure).is_none() {
self.dangling.push((relationship, structure));
continue;
}
if self.node(structure).is_none() {
self.anomalies
.push(super::SpatialAnomaly::ReferencedInNonContainer {
relation: relationship,
structure,
});
continue;
}
for element in link::refs_in_slot(model, relationship, rel.related) {
if model.get(element).is_none() {
self.dangling.push((relationship, element));
continue;
}
push_unique(&mut self.referenced, structure, element);
push_unique(&mut self.referenced_in, element, structure);
}
}
}
#[must_use]
pub fn referenced_elements(&self, container: EntityId) -> &[EntityId] {
self.referenced.get(&container).map_or(&[], Vec::as_slice)
}
#[must_use]
pub fn referencing_structures(&self, element: EntityId) -> &[EntityId] {
self.referenced_in.get(&element).map_or(&[], Vec::as_slice)
}
}
fn push_unique(map: &mut BTreeMap<EntityId, Vec<EntityId>>, key: EntityId, value: EntityId) {
let list = map.entry(key).or_default();
if !list.contains(&value) {
list.push(value);
}
}