ifc_lite_core/decoder/
precision.rs1use super::EntityDecoder;
8use crate::{Error, Result};
9use crate::parser::{keyword_eq, EntityScanner};
10
11impl EntityDecoder<'_> {
12 pub fn geometric_context_precision_range(&mut self) -> Result<Option<(f64, f64)>> {
22 if self.geometric_precision_cache.is_none() {
23 self.geometric_precision_cache = Some(self.scan_geometric_context_precision());
24 }
25 self.geometric_precision_cache.as_ref().unwrap().clone()
26 .map_err(|message| Error::parse(0, message))
27 }
28
29 fn scan_geometric_context_precision(&self) -> std::result::Result<Option<(f64, f64)>, String> {
30 let mut scanner = EntityScanner::new(self.content);
31 let mut range: Option<(f64, f64)> = None;
32 while let Some((id, type_name, start, end)) = scanner.next_entity() {
33 if !keyword_eq(type_name, "IFCGEOMETRICREPRESENTATIONCONTEXT")
34 && !keyword_eq(type_name, "IFCGEOMETRICREPRESENTATIONSUBCONTEXT") {
35 continue;
36 }
37 let entity = self.decode_at_uncached(start, end)
38 .map_err(|error| format!("geometric context #{id}: {error}"))?;
39 let attribute = entity.get(3)
40 .ok_or_else(|| format!("geometric context #{id} has no Precision attribute"))?;
41 if attribute.is_null() { continue; }
42 let precision = attribute.as_float()
43 .filter(|value| value.is_finite() && *value > 0.0)
44 .ok_or_else(|| format!("geometric context #{id} has invalid Precision"))?;
45 range = Some(range.map_or((precision, precision), |(min, max)| {
46 (min.min(precision), max.max(precision))
47 }));
48 }
49 Ok(range)
50 }
51}
52
53#[cfg(test)]
54#[path = "precision_tests.rs"]
55mod tests;