ifc_style/assignment/
resolution.rs1use ifc_model::EntityId;
4
5use crate::assignment::StyledItem;
6use crate::error::{StyleError, StyleResult};
7use crate::layer::PresentationLayer;
8use crate::StyleView;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum StyleSource {
13 None,
16 DirectStyledItem(EntityId),
19 PresentationLayer(EntityId),
23}
24
25#[derive(Debug, Clone, PartialEq, Eq)]
28pub struct ResolvedStyle {
29 source: StyleSource,
30 effective_styles: Vec<EntityId>,
31 direct_styles: Vec<EntityId>,
32 layer_styles: Vec<(EntityId, Vec<EntityId>)>,
33}
34
35impl ResolvedStyle {
36 pub fn source(&self) -> StyleSource {
38 self.source
39 }
40
41 pub fn effective_styles(&self) -> &[EntityId] {
45 &self.effective_styles
46 }
47
48 pub fn direct_styles(&self) -> &[EntityId] {
51 &self.direct_styles
52 }
53
54 pub fn layer_styles(&self) -> &[(EntityId, Vec<EntityId>)] {
58 &self.layer_styles
59 }
60}
61
62impl<'m, 's> StyleView<'m, 's> {
63 pub fn resolve_item_style(&self, item: EntityId) -> StyleResult<ResolvedStyle> {
70 let mut direct = Vec::new();
71 for (id, entity) in self.model.iter() {
72 if !self.schema.is_a(&entity.type_name, "IfcStyledItem") {
73 continue;
74 }
75 let styled = StyledItem::from_record(self.record(id, "IfcStyledItem")?);
76 if styled.item()? == Some(item) {
77 direct.push((id, self.flatten_assignments(styled.styles()?)?));
78 }
79 }
80 direct.sort_by_key(|(id, _)| *id);
81 if direct.len() > 1 {
82 return Err(StyleError::AmbiguousStyleAssignment {
83 item,
84 count: direct.len(),
85 });
86 }
87
88 let mut layer_styles = Vec::new();
89 for (id, entity) in self.model.iter() {
90 if !self
91 .schema
92 .is_a(&entity.type_name, "IfcPresentationLayerAssignment")
93 {
94 continue;
95 }
96 let layer =
97 PresentationLayer::from_record(self.record(id, "IfcPresentationLayerAssignment")?);
98 if layer.assigned_items()?.contains(&item) {
99 let mut styles = self.flatten_assignments(layer.layer_styles()?)?;
100 styles.sort_unstable();
101 styles.dedup();
102 layer_styles.push((id, styles));
103 }
104 }
105 layer_styles.sort_by_key(|(id, _)| *id);
106
107 let (source, direct_styles, effective_styles) = if let Some((id, styles)) = direct.pop() {
108 (StyleSource::DirectStyledItem(id), styles.clone(), styles)
109 } else {
110 let mut styles: Vec<_> = layer_styles
111 .iter()
112 .flat_map(|(_, styles)| styles.iter().copied())
113 .collect();
114 styles.sort_unstable();
115 styles.dedup();
116 let source = layer_styles
117 .iter()
118 .find(|(_, styles)| !styles.is_empty())
119 .map_or(StyleSource::None, |(id, _)| {
120 StyleSource::PresentationLayer(*id)
121 });
122 (source, Vec::new(), styles)
123 };
124
125 Ok(ResolvedStyle {
126 source,
127 effective_styles,
128 direct_styles,
129 layer_styles,
130 })
131 }
132
133 fn flatten_assignments(&self, ids: Vec<EntityId>) -> StyleResult<Vec<EntityId>> {
137 let mut out = Vec::new();
138 for id in ids {
139 let entity = self.model.get(id).ok_or(StyleError::UnknownEntity { id })?;
140 if entity.is_type("IfcPresentationStyleAssignment") {
141 out.extend(self.presentation_style_assignment(id)?.styles()?);
142 } else {
143 out.push(id);
144 }
145 }
146 Ok(out)
147 }
148}