ifc_lite_server/services/data_model/
classifications.rs1use super::types::{ClassificationAssociation, EntityJob};
8use ifc_lite_core::EntityDecoder;
9use rayon::prelude::*;
10use std::sync::Arc;
11
12fn resolve_classification(
16 decoder: &mut EntityDecoder,
17 id: u32,
18) -> (
19 Option<String>,
20 Option<String>,
21 Option<String>,
22 Option<String>,
23) {
24 let Ok(entity) = decoder.decode_by_id(id) else {
25 return (None, None, None, None);
26 };
27
28 if entity
29 .ifc_type
30 .as_str()
31 .eq_ignore_ascii_case("IFCCLASSIFICATION")
32 {
33 return (
35 None,
36 None,
37 None,
38 entity.get_string(3).map(|s| s.to_string()),
39 );
40 }
41
42 let location = entity.get_string(0).map(|s| s.to_string());
45 let identification = entity.get_string(1).map(|s| s.to_string());
46 let name = entity.get_string(2).map(|s| s.to_string());
47
48 let mut system_name = None;
50 let mut source = entity.get_ref(3);
51 let mut depth = 0;
52 while let Some(src_id) = source {
53 if depth >= 8 {
54 break;
55 }
56 depth += 1;
57 let Ok(src) = decoder.decode_by_id(src_id) else {
58 break;
59 };
60 if src
61 .ifc_type
62 .as_str()
63 .eq_ignore_ascii_case("IFCCLASSIFICATION")
64 {
65 system_name = src.get_string(3).map(|s| s.to_string());
66 break;
67 }
68 source = src.get_ref(3);
70 }
71
72 (identification, name, location, system_name)
73}
74
75pub(super) fn extract_classifications(
77 jobs: &[EntityJob],
78 content: &Arc<Vec<u8>>,
79 entity_index: &Arc<ifc_lite_core::EntityIndex>,
80) -> Vec<ClassificationAssociation> {
81 let rel_jobs: Vec<_> = jobs
82 .iter()
83 .filter(|job| {
84 job.type_name
85 .eq_ignore_ascii_case("IFCRELASSOCIATESCLASSIFICATION")
86 })
87 .collect();
88
89 tracing::debug!(count = rel_jobs.len(), "Extracting classifications");
90
91 rel_jobs
92 .par_iter()
93 .flat_map(|job| {
94 let mut decoder =
95 EntityDecoder::with_arc_index(content.as_slice(), entity_index.clone());
96 let Ok(rel) = decoder.decode_at(job.start, job.end) else {
97 return Vec::new();
98 };
99 let related = super::related_object_ids(&rel);
100 let Some(class_id) = rel.get_ref(5) else {
102 return Vec::new();
103 };
104 let (identification, name, location, system_name) =
105 resolve_classification(&mut decoder, class_id);
106
107 related
108 .into_iter()
109 .map(|element_id| ClassificationAssociation {
110 element_id,
111 system_name: system_name.clone(),
112 identification: identification.clone(),
113 name: name.clone(),
114 location: location.clone(),
115 })
116 .collect()
117 })
118 .collect()
119}