ifc_lite_server/services/data_model/
quantities.rs1use super::types::{EntityJob, Quantity, QuantitySet};
8use ifc_lite_core::{DecodedEntity, EntityDecoder};
9use rayon::prelude::*;
10use std::sync::Arc;
11
12pub(super) fn extract_quantities(
14 jobs: &[EntityJob],
15 content: &Arc<Vec<u8>>,
16 entity_index: &Arc<ifc_lite_core::EntityIndex>,
17) -> Vec<QuantitySet> {
18 let qset_jobs: Vec<_> = jobs
21 .iter()
22 .filter(|job| job.type_name.eq_ignore_ascii_case("IFCELEMENTQUANTITY"))
23 .collect();
24
25 tracing::debug!(count = qset_jobs.len(), "Extracting quantity sets");
26
27 qset_jobs
28 .par_iter()
29 .filter_map(|job| {
30 let mut local_decoder =
31 EntityDecoder::with_arc_index(content.as_slice(), entity_index.clone());
32 let entity = local_decoder.decode_at(job.start, job.end).ok()?;
33
34 let qset_name = entity.get_string(2)?.to_string();
36 let method_of_measurement = entity.get_string(4).map(|s| s.to_string());
37 let has_quantities = entity.get_list(5)?;
38
39 let mut quantities = Vec::new();
40
41 for quant_ref in has_quantities.iter() {
43 if let Some(quant_id) = quant_ref.as_entity_ref() {
44 if let Ok(quant_entity) = local_decoder.decode_by_id(quant_id) {
45 if let Some(quant) = extract_quantity_value(&quant_entity) {
46 quantities.push(quant);
47 }
48 }
49 }
50 }
51
52 if quantities.is_empty() {
53 return None;
54 }
55
56 Some(QuantitySet {
57 qset_id: job.id,
58 qset_name,
59 method_of_measurement,
60 quantities,
61 })
62 })
63 .collect()
64}
65
66fn extract_quantity_value(entity: &DecodedEntity) -> Option<Quantity> {
71 let ifc_type = entity.ifc_type.as_str();
73
74 let quantity_type = if ifc_type.eq_ignore_ascii_case("IFCQUANTITYLENGTH") {
76 "length"
77 } else if ifc_type.eq_ignore_ascii_case("IFCQUANTITYAREA") {
78 "area"
79 } else if ifc_type.eq_ignore_ascii_case("IFCQUANTITYVOLUME") {
80 "volume"
81 } else if ifc_type.eq_ignore_ascii_case("IFCQUANTITYCOUNT") {
82 "count"
83 } else if ifc_type.eq_ignore_ascii_case("IFCQUANTITYWEIGHT") {
84 "weight"
85 } else if ifc_type.eq_ignore_ascii_case("IFCQUANTITYTIME") {
86 "time"
87 } else if ifc_type.eq_ignore_ascii_case("IFCQUANTITYNUMBER") {
88 "number"
89 } else {
90 return None; };
92
93 let quantity_name = entity.get_string(0)?.to_string();
96
97 let quantity_value = entity.get_float(3)?;
99
100 Some(Quantity {
101 quantity_name,
102 quantity_value,
103 quantity_type: quantity_type.to_string(),
104 })
105}