ifc_lite_processing/analytic_export/
definitions.rs1use std::collections::BTreeMap;
8use ifc_lite_geometry::analytic::{AnalyticCurveSegment, AnalyticStatus, AnalyticSweptDisk};
9use serde::Serialize;
10use sha2::{Digest, Sha256};
11use nalgebra::Matrix4;
12
13#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize)]
17#[serde(tag = "kind", rename_all = "snake_case")]
18pub enum AnalyticSourceContext {
19 Direct { representation_id: u32 },
20 Mapped { representation_map_path: Vec<u32> },
21}
22
23#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize)]
25pub struct AnalyticSourceKey {
26 pub model_sha256: String,
27 pub schema: Option<String>,
28 pub length_unit_scale_bits: String,
30 pub context: AnalyticSourceContext,
31 pub solid_id: u32,
32}
33
34pub type SweptDiskSourceKey = AnalyticSourceKey;
36pub type SweptDiskSourceContext = AnalyticSourceContext;
38
39#[derive(Debug, Clone, Serialize)]
41pub struct SweptDiskDefinition {
42 pub key: SweptDiskSourceKey,
43 pub directrix_id: u32,
44 #[serde(rename = "Radius")]
45 pub radius: f64,
46 #[serde(rename = "InnerRadius")]
47 pub inner_radius: Option<f64>,
48 #[serde(rename = "Directrix")]
49 pub directrix: Vec<AnalyticCurveSegment>,
50 pub status: AnalyticStatus,
51}
52
53#[derive(Debug, Clone, Serialize)]
57pub struct SweptDiskInstance {
58 pub ordinal: usize,
59 pub source: SweptDiskSourceKey,
60 pub product_id: u32,
61 pub solid_id: u32,
62 pub mapping_path: Vec<u32>,
63 pub source_modified: bool,
64 pub world_from_source: Option<[f64; 16]>,
65 pub status: AnalyticStatus,
66}
67
68#[derive(Debug, Clone, Serialize)]
70pub struct SweptDiskDefinitions {
71 pub up_axis: &'static str,
72 pub source_units: &'static str,
73 pub world_units: &'static str,
74 pub coordinate_space: &'static str,
75 pub model_sha256: String,
76 pub schema: Option<String>,
77 pub length_unit_scale: f64,
78 pub sources: Vec<SweptDiskDefinition>,
79 pub instances: BTreeMap<u32, Vec<SweptDiskInstance>>,
80 pub diagnostics: Vec<String>,
81}
82
83impl SweptDiskDefinitions {
84 pub(super) fn new(content: &[u8], unit_scale: f64) -> Self {
85 let model_sha256 = model_sha256(content);
86 let schema = ifc_lite_core::declared_schema_bounded(content);
87 Self { up_axis: "Z", source_units: "ifc_file_length_units",
88 world_units: "m", coordinate_space: "absolute_ifc_world",
89 model_sha256, schema, length_unit_scale: unit_scale,
90 sources: Vec::new(), instances: BTreeMap::new(), diagnostics: Vec::new() }
91 }
92
93 pub(super) fn key(&self, context: AnalyticSourceContext, solid_id: u32) -> AnalyticSourceKey {
94 source_key(&self.model_sha256, self.schema.as_deref(), self.length_unit_scale,
95 context, solid_id)
96 }
97}
98
99impl SweptDiskDefinition {
100 pub(super) fn from_disk(key: SweptDiskSourceKey, disk: &AnalyticSweptDisk) -> Self {
101 Self { key, directrix_id: disk.directrix_id, radius: disk.radius,
102 inner_radius: disk.inner_radius, directrix: disk.segments.clone(),
103 status: disk.status.clone() }
104 }
105}
106
107pub(super) fn model_sha256(content: &[u8]) -> String {
108 format!("{:x}", Sha256::digest(content))
109}
110
111pub(super) fn source_key(
112 model_sha256: &str, schema: Option<&str>, length_unit_scale: f64,
113 context: AnalyticSourceContext, solid_id: u32,
114) -> AnalyticSourceKey {
115 AnalyticSourceKey { model_sha256: model_sha256.to_owned(),
116 schema: schema.map(str::to_owned),
117 length_unit_scale_bits: format!("{:016x}", length_unit_scale.to_bits()),
118 context, solid_id }
119}
120
121pub(super) fn source_matrix(transform: &Matrix4<f64>, unit_scale: f64) -> Option<[f64; 16]> {
122 if !unit_scale.is_finite() || unit_scale <= 0.0 || transform.iter().any(|v| !v.is_finite()) {
123 return None;
124 }
125 let mut matrix = *transform;
126 for column in 0..3 {
127 for row in 0..3 { matrix[(row, column)] *= unit_scale; }
128 }
129 matrix.iter().all(|v| v.is_finite()).then(|| {
130 let mut values = [0.0; 16];
131 values.copy_from_slice(matrix.as_slice());
132 values
133 })
134}