1use crate::model::Unit;
2use crate::utils::hardware::HardwareCapabilities;
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12pub struct ModelStats {
13 pub unit: Unit,
15 pub generator: Option<String>,
17 pub metadata: HashMap<String, String>,
19 pub geometry: GeometryStats,
21 pub materials: MaterialsStats,
23 pub production: ProductionStats,
25 pub displacement: DisplacementStats,
27 pub vendor: VendorData,
29 pub system_info: HardwareCapabilities,
31 pub thumbnails: ThumbnailStats,
33}
34
35#[derive(Debug, Clone, Default, Serialize, Deserialize)]
36pub struct ThumbnailStats {
37 pub package_thumbnail_present: bool,
38 pub object_thumbnail_count: usize,
39}
40
41#[derive(Debug, Clone, Default, Serialize, Deserialize)]
42pub struct MaterialsStats {
43 pub base_materials_count: usize,
44 pub color_groups_count: usize,
45 pub texture_2d_groups_count: usize,
46 pub composite_materials_count: usize,
47 pub multi_properties_count: usize,
48}
49
50#[derive(Debug, Clone, Default, Serialize, Deserialize)]
55pub struct GeometryStats {
56 pub object_count: usize,
58 pub instance_count: usize,
60 pub triangle_count: u64,
62 pub vertex_count: u64,
64 pub bounding_box: Option<BoundingBox>,
66 pub surface_area: f64,
68 pub volume: f64,
70 pub is_manifold: bool,
72 #[serde(default)]
74 pub type_counts: HashMap<String, usize>,
75}
76
77#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
83pub struct BoundingBox {
84 pub min: [f32; 3],
86 pub max: [f32; 3],
88}
89
90impl BoundingBox {
91 pub fn transform(&self, matrix: glam::Mat4) -> Self {
92 let corners = [
93 glam::Vec3::new(self.min[0], self.min[1], self.min[2]),
94 glam::Vec3::new(self.min[0], self.min[1], self.max[2]),
95 glam::Vec3::new(self.min[0], self.max[1], self.min[2]),
96 glam::Vec3::new(self.min[0], self.max[1], self.max[2]),
97 glam::Vec3::new(self.max[0], self.min[1], self.min[2]),
98 glam::Vec3::new(self.max[0], self.min[1], self.max[2]),
99 glam::Vec3::new(self.max[0], self.max[1], self.min[2]),
100 glam::Vec3::new(self.max[0], self.max[1], self.max[2]),
101 ];
102
103 let mut transformed_min = glam::Vec3::splat(f32::INFINITY);
104 let mut transformed_max = glam::Vec3::splat(f32::NEG_INFINITY);
105
106 for corner in corners {
107 let transformed = matrix.transform_point3(corner);
108 transformed_min = transformed_min.min(transformed);
109 transformed_max = transformed_max.max(transformed);
110 }
111
112 Self {
113 min: [transformed_min.x, transformed_min.y, transformed_min.z],
114 max: [transformed_max.x, transformed_max.y, transformed_max.z],
115 }
116 }
117}
118
119#[derive(Debug, Clone, Default, Serialize, Deserialize)]
120pub struct ProductionStats {
121 pub uuid_count: usize,
122}
123
124#[derive(Debug, Clone, Default, Serialize, Deserialize)]
125pub struct DisplacementStats {
126 pub mesh_count: usize,
127 pub texture_count: usize,
128 pub normal_count: u64,
129 pub gradient_count: u64,
130 pub displaced_triangle_count: u64,
131 pub total_triangle_count: u64,
132}
133
134#[derive(Debug, Clone, Default, Serialize, Deserialize)]
135pub struct VendorData {
136 pub printer_model: Option<String>,
137 pub filaments: Vec<FilamentInfo>,
138 pub plates: Vec<PlateInfo>,
139 pub print_time_estimate: Option<String>,
140 pub slicer_version: Option<String>,
141 pub nozzle_diameter: Option<f32>,
142 pub slicer_warnings: Vec<SlicerWarning>,
143 pub object_metadata: Vec<BambuObjectMetadata>,
144 pub project_settings: Option<BambuProjectSettings>,
145 pub profile_configs: Vec<BambuProfileConfig>,
146 pub assembly_info: Vec<AssemblyItem>,
147 pub bambu_cover_thumbnail: Option<String>,
149 pub bambu_gcode: Option<String>,
151}
152
153#[derive(Debug, Clone, Default, Serialize, Deserialize)]
154pub struct FilamentInfo {
155 pub id: u32,
156 pub tray_info_idx: Option<String>,
157 pub type_: String,
158 pub color: Option<String>,
159 pub used_m: Option<f32>,
160 pub used_g: Option<f32>,
161}
162
163#[derive(Debug, Clone, Default, Serialize, Deserialize)]
164pub struct PlateInfo {
165 pub id: u32,
166 pub name: Option<String>,
167 pub locked: bool,
168 pub gcode_file: Option<String>,
169 pub thumbnail_file: Option<String>,
170 pub items: Vec<PlateModelInstance>,
171}
172
173#[derive(Debug, Clone, Default, Serialize, Deserialize)]
174pub struct PlateModelInstance {
175 pub object_id: u32,
176 pub instance_id: u32,
177 pub identify_id: Option<u32>,
178}
179
180#[derive(Debug, Clone, Default, Serialize, Deserialize)]
181pub struct SlicerWarning {
182 pub msg: String,
183 pub level: Option<String>,
184 pub error_code: Option<String>,
185}
186
187#[derive(Debug, Clone, Default, Serialize, Deserialize)]
188pub struct BambuObjectMetadata {
189 pub id: u32,
190 pub name: Option<String>,
191 pub extruder: Option<u32>,
192 pub face_count: Option<u64>,
193 pub parts: Vec<BambuPartMetadata>,
194}
195
196#[derive(Debug, Clone, Default, Serialize, Deserialize)]
197pub struct BambuPartMetadata {
198 pub id: u32,
199 pub subtype: PartSubtype,
200 pub name: Option<String>,
201 pub matrix: Option<String>,
202 pub source: Option<BambuPartSource>,
203 pub mesh_stat: Option<BambuMeshStat>,
204 pub print_overrides: HashMap<String, String>,
205}
206
207#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
208pub enum PartSubtype {
209 #[default]
210 NormalPart,
211 ModifierPart,
212 SupportBlocker,
213 SupportEnforcer,
214 Other(String),
215}
216
217impl PartSubtype {
218 pub fn parse(s: &str) -> Self {
220 match s {
221 "normal_part" => Self::NormalPart,
222 "modifier_part" => Self::ModifierPart,
223 "support_blocker" => Self::SupportBlocker,
224 "support_enforcer" => Self::SupportEnforcer,
225 other => Self::Other(other.to_string()),
226 }
227 }
228}
229
230#[derive(Debug, Clone, Default, Serialize, Deserialize)]
231pub struct BambuPartSource {
232 pub volume_id: Option<u32>,
233 pub offset_x: Option<f64>,
234 pub offset_y: Option<f64>,
235 pub offset_z: Option<f64>,
236}
237
238#[derive(Debug, Clone, Default, Serialize, Deserialize)]
239pub struct BambuMeshStat {
240 pub edges_fixed: Option<u32>,
241 pub degenerate_facets: Option<u32>,
242 pub facets_removed: Option<u32>,
243 pub facets_reversed: Option<u32>,
244 pub backwards_edges: Option<u32>,
245}
246
247#[derive(Debug, Clone, Default, Serialize, Deserialize)]
248pub struct BambuProjectSettings {
249 pub printer_model: Option<String>,
250 pub printer_inherits: Option<String>,
251 pub bed_type: Option<String>,
252 pub layer_height: Option<f32>,
253 pub first_layer_height: Option<f32>,
254 pub filament_type: Vec<String>,
255 pub filament_colour: Vec<String>,
256 pub nozzle_diameter: Vec<f32>,
257 pub print_sequence: Option<String>,
258 pub wall_loops: Option<u32>,
259 pub infill_density: Option<String>,
260 pub support_type: Option<String>,
261 pub extras: HashMap<String, serde_json::Value>,
262}
263
264#[derive(Debug, Clone, Default, Serialize, Deserialize)]
265pub struct BambuProfileConfig {
266 pub config_type: String, pub index: u32, pub inherits: Option<String>,
269 pub name: Option<String>,
270 pub extras: HashMap<String, serde_json::Value>,
271}
272
273#[derive(Debug, Clone, Default, Serialize, Deserialize)]
274pub struct AssemblyItem {
275 pub object_id: u32,
276 pub instance_count: u32,
277 pub transform: Option<String>,
278 pub offset: Option<String>,
279}