1use serde::{Deserialize, Serialize};
17use serde_json::{Map, Value};
18
19pub const REQUIRED_META_FIELDS: [&str; 10] = [
21 "meta_version",
22 "normal_exposure_ms",
23 "bottom_exposure_ms",
24 "bottom_layer_count",
25 "transition_layer_count",
26 "layer_height_um",
27 "lift_slow_distance_um",
28 "lift_slow_speed_um_min",
29 "retract_fast_distance_um",
30 "retract_fast_speed_um_min",
31];
32
33#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
41pub struct Timing {
42 #[serde(skip_serializing_if = "Option::is_none", default)]
44 pub layer_height_um: Option<u32>,
45 #[serde(skip_serializing_if = "Option::is_none", default)]
47 pub normal_exposure_ms: Option<u32>,
48 #[serde(skip_serializing_if = "Option::is_none", default)]
50 pub bottom_exposure_ms: Option<u32>,
51 #[serde(skip_serializing_if = "Option::is_none", default)]
53 pub bottom_layer_count: Option<u32>,
54 #[serde(skip_serializing_if = "Option::is_none", default)]
56 pub transition_layer_count: Option<u32>,
57
58 #[serde(skip_serializing_if = "Option::is_none", default)]
60 pub lift_slow_distance_um: Option<u32>,
61 #[serde(skip_serializing_if = "Option::is_none", default)]
63 pub lift_slow_speed_um_min: Option<u32>,
64 #[serde(skip_serializing_if = "Option::is_none", default)]
66 pub lift_fast_distance_um: Option<u32>,
67 #[serde(skip_serializing_if = "Option::is_none", default)]
69 pub lift_fast_speed_um_min: Option<u32>,
70 #[serde(skip_serializing_if = "Option::is_none", default)]
72 pub retract_fast_distance_um: Option<u32>,
73 #[serde(skip_serializing_if = "Option::is_none", default)]
75 pub retract_fast_speed_um_min: Option<u32>,
76 #[serde(skip_serializing_if = "Option::is_none", default)]
78 pub retract_slow_distance_um: Option<u32>,
79 #[serde(skip_serializing_if = "Option::is_none", default)]
81 pub retract_slow_speed_um_min: Option<u32>,
82
83 #[serde(skip_serializing_if = "Option::is_none", default)]
85 pub bottom_lift_slow_distance_um: Option<u32>,
86 #[serde(skip_serializing_if = "Option::is_none", default)]
88 pub bottom_lift_slow_speed_um_min: Option<u32>,
89 #[serde(skip_serializing_if = "Option::is_none", default)]
91 pub bottom_lift_fast_distance_um: Option<u32>,
92 #[serde(skip_serializing_if = "Option::is_none", default)]
94 pub bottom_lift_fast_speed_um_min: Option<u32>,
95 #[serde(skip_serializing_if = "Option::is_none", default)]
97 pub bottom_retract_fast_distance_um: Option<u32>,
98 #[serde(skip_serializing_if = "Option::is_none", default)]
100 pub bottom_retract_fast_speed_um_min: Option<u32>,
101 #[serde(skip_serializing_if = "Option::is_none", default)]
103 pub bottom_retract_slow_distance_um: Option<u32>,
104 #[serde(skip_serializing_if = "Option::is_none", default)]
106 pub bottom_retract_slow_speed_um_min: Option<u32>,
107
108 #[serde(skip_serializing_if = "Option::is_none", default)]
110 pub wait_time_before_cure_ms: Option<u32>,
111 #[serde(skip_serializing_if = "Option::is_none", default)]
113 pub wait_time_after_cure_ms: Option<u32>,
114 #[serde(skip_serializing_if = "Option::is_none", default)]
116 pub wait_time_after_lift_ms: Option<u32>,
117 #[serde(skip_serializing_if = "Option::is_none", default)]
119 pub bottom_wait_time_before_cure_ms: Option<u32>,
120 #[serde(skip_serializing_if = "Option::is_none", default)]
122 pub bottom_wait_time_after_cure_ms: Option<u32>,
123 #[serde(skip_serializing_if = "Option::is_none", default)]
125 pub bottom_wait_time_after_lift_ms: Option<u32>,
126
127 #[serde(skip_serializing_if = "Option::is_none", default)]
129 pub light_pwm: Option<u32>,
130 #[serde(skip_serializing_if = "Option::is_none", default)]
132 pub bottom_light_pwm: Option<u32>,
133
134 #[serde(skip_serializing_if = "Option::is_none", default)]
136 pub chamber_temperature_c: Option<f64>,
137 #[serde(skip_serializing_if = "Option::is_none", default)]
139 pub vat_temperature_c: Option<f64>,
140
141 #[serde(skip_serializing_if = "Option::is_none", default)]
143 pub cure_curve: Option<CureCurve>,
144
145 #[serde(flatten)]
150 pub extra: Map<String, Value>,
151}
152
153impl Timing {
154 pub fn vendor_extra(&self) -> Option<&Value> {
156 self.extra.get("extra")
157 }
158
159 pub fn field_names() -> &'static [&'static str] {
161 &[
162 "layer_height_um",
163 "normal_exposure_ms",
164 "bottom_exposure_ms",
165 "bottom_layer_count",
166 "transition_layer_count",
167 "lift_slow_distance_um",
168 "lift_slow_speed_um_min",
169 "lift_fast_distance_um",
170 "lift_fast_speed_um_min",
171 "retract_fast_distance_um",
172 "retract_fast_speed_um_min",
173 "retract_slow_distance_um",
174 "retract_slow_speed_um_min",
175 "bottom_lift_slow_distance_um",
176 "bottom_lift_slow_speed_um_min",
177 "bottom_lift_fast_distance_um",
178 "bottom_lift_fast_speed_um_min",
179 "bottom_retract_fast_distance_um",
180 "bottom_retract_fast_speed_um_min",
181 "bottom_retract_slow_distance_um",
182 "bottom_retract_slow_speed_um_min",
183 "wait_time_before_cure_ms",
184 "wait_time_after_cure_ms",
185 "wait_time_after_lift_ms",
186 "bottom_wait_time_before_cure_ms",
187 "bottom_wait_time_after_cure_ms",
188 "bottom_wait_time_after_lift_ms",
189 "light_pwm",
190 "bottom_light_pwm",
191 "chamber_temperature_c",
192 "vat_temperature_c",
193 "cure_curve",
194 ]
195 }
196
197 pub fn missing_from(object: &Map<String, Value>, names: &[&str]) -> Vec<String> {
203 names
204 .iter()
205 .filter(|name| !object.contains_key(**name))
206 .map(|name| (*name).to_string())
207 .collect()
208 }
209}
210
211#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
213pub struct CureCurve {
214 pub dp_um: f64,
216 pub ec_mj_cm2: f64,
218 pub e0_mj_cm2: f64,
220}
221
222#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
224pub struct Material {
225 #[serde(default)]
227 pub name: String,
228 #[serde(skip_serializing_if = "Option::is_none", default)]
230 pub brand: Option<String>,
231 #[serde(skip_serializing_if = "Option::is_none", default)]
233 pub family: Option<String>,
234 #[serde(skip_serializing_if = "Option::is_none", default)]
236 pub density_g_ml: Option<f64>,
237 #[serde(skip_serializing_if = "Option::is_none", default)]
239 pub color_rgba: Option<[u8; 4]>,
240 #[serde(skip_serializing_if = "Option::is_none", default)]
242 pub bottle_price: Option<f64>,
243 #[serde(skip_serializing_if = "Option::is_none", default)]
245 pub bottle_capacity_ml: Option<f64>,
246 #[serde(flatten)]
248 pub extra: Map<String, Value>,
249}
250
251#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
253pub struct Printer {
254 #[serde(skip_serializing_if = "Option::is_none", default)]
256 pub name: Option<String>,
257 #[serde(skip_serializing_if = "Option::is_none", default)]
259 pub manufacturer: Option<String>,
260 #[serde(skip_serializing_if = "Option::is_none", default)]
262 pub firmware_version: Option<String>,
263 #[serde(skip_serializing_if = "Option::is_none", default)]
265 pub serial: Option<String>,
266 #[serde(skip_serializing_if = "Option::is_none", default)]
268 pub display_width_px: Option<u32>,
269 #[serde(skip_serializing_if = "Option::is_none", default)]
271 pub display_height_px: Option<u32>,
272 #[serde(skip_serializing_if = "Option::is_none", default)]
274 pub pixel_size_um: Option<u32>,
275 #[serde(skip_serializing_if = "Option::is_none", default)]
277 pub build_width_um: Option<u32>,
278 #[serde(skip_serializing_if = "Option::is_none", default)]
280 pub build_depth_um: Option<u32>,
281 #[serde(skip_serializing_if = "Option::is_none", default)]
283 pub build_height_um: Option<u32>,
284 #[serde(skip_serializing_if = "Option::is_none", default)]
286 pub bit_depth: Option<u32>,
287 #[serde(flatten)]
289 pub extra: Map<String, Value>,
290}
291
292#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
294pub struct CompatiblePrinter {
295 #[serde(skip_serializing_if = "Option::is_none", default)]
297 pub manufacturer: Option<String>,
298 #[serde(skip_serializing_if = "Option::is_none", default)]
300 pub model_pattern: Option<String>,
301 #[serde(skip_serializing_if = "Option::is_none", default)]
303 pub display_width_px: Option<u32>,
304 #[serde(skip_serializing_if = "Option::is_none", default)]
306 pub display_height_px: Option<u32>,
307 #[serde(skip_serializing_if = "Option::is_none", default)]
309 pub pixel_size_um: Option<u32>,
310 #[serde(flatten)]
312 pub extra: Map<String, Value>,
313}
314
315#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
317pub struct AntiAliasing {
318 #[serde(skip_serializing_if = "Option::is_none", default)]
320 pub enabled: Option<bool>,
321 #[serde(skip_serializing_if = "Option::is_none", default)]
323 pub level: Option<u32>,
324 #[serde(skip_serializing_if = "Option::is_none", default)]
326 pub mode: Option<String>,
327 #[serde(skip_serializing_if = "Option::is_none", default)]
329 pub minimum_alpha_percent: Option<f64>,
330 #[serde(skip_serializing_if = "Option::is_none", default)]
332 pub blur_brush_radius_px: Option<u32>,
333 #[serde(skip_serializing_if = "Option::is_none", default)]
335 pub blur_brush_kernel: Option<String>,
336 #[serde(skip_serializing_if = "Option::is_none", default)]
338 pub blur_brush_sigma_x: Option<f64>,
339 #[serde(skip_serializing_if = "Option::is_none", default)]
341 pub blur_brush_sigma_y: Option<f64>,
342 #[serde(skip_serializing_if = "Option::is_none", default)]
344 pub z_blend_look_back: Option<u32>,
345 #[serde(skip_serializing_if = "Option::is_none", default)]
347 pub z_blend_fade_px: Option<u32>,
348 #[serde(skip_serializing_if = "Option::is_none", default)]
350 pub dither_enabled: Option<bool>,
351 #[serde(flatten)]
353 pub extra: Map<String, Value>,
354}
355
356#[derive(Debug, Clone, Copy, Default, PartialEq, Serialize, Deserialize)]
358pub struct ScaleCompensation {
359 #[serde(default)]
361 pub x: f64,
362 #[serde(default)]
364 pub y: f64,
365 #[serde(default)]
367 pub z: f64,
368}
369
370#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
372pub struct Slicer {
373 #[serde(skip_serializing_if = "Option::is_none", default)]
375 pub name: Option<String>,
376 #[serde(skip_serializing_if = "Option::is_none", default)]
378 pub version: Option<String>,
379 #[serde(skip_serializing_if = "Option::is_none", default)]
381 pub url: Option<String>,
382 #[serde(flatten)]
384 pub extra: Map<String, Value>,
385}
386
387#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
392pub struct Meta {
393 #[serde(skip_serializing_if = "Option::is_none", default)]
395 pub meta_version: Option<u32>,
396 #[serde(flatten)]
398 pub timing: Timing,
399 #[serde(skip_serializing_if = "Option::is_none", default)]
401 pub materials: Option<Vec<Material>>,
402 #[serde(skip_serializing_if = "Option::is_none", default)]
405 pub sectors: Option<Vec<Sector>>,
406 #[serde(skip_serializing_if = "Option::is_none", default)]
408 pub printer: Option<Printer>,
409 #[serde(skip_serializing_if = "Option::is_none", default)]
411 pub anti_aliasing: Option<AntiAliasing>,
412 #[serde(skip_serializing_if = "Option::is_none", default)]
414 pub scale_compensation_pct: Option<ScaleCompensation>,
415 #[serde(skip_serializing_if = "Option::is_none", default)]
417 pub estimated_print_time_sec: Option<u32>,
418 #[serde(skip_serializing_if = "Option::is_none", default)]
420 pub estimated_resin_volume_ml: Option<f64>,
421 #[serde(skip_serializing_if = "Option::is_none", default)]
423 pub slicer: Option<Slicer>,
424}
425
426impl Meta {
427 pub fn extra(&self) -> Option<&Value> {
429 self.timing.vendor_extra()
430 }
431}
432
433#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
435pub struct Profile {
436 #[serde(default)]
438 pub profile_name: String,
439 #[serde(default)]
441 pub profile_version: String,
442 #[serde(skip_serializing_if = "Option::is_none", default)]
444 pub profile_type: Option<String>,
445 #[serde(skip_serializing_if = "Option::is_none", default)]
447 pub profile_uuid: Option<String>,
448 #[serde(skip_serializing_if = "Option::is_none", default)]
450 pub author: Option<String>,
451 #[serde(skip_serializing_if = "Option::is_none", default)]
453 pub created_unix_sec: Option<u64>,
454 #[serde(skip_serializing_if = "Option::is_none", default)]
456 pub description: Option<String>,
457 #[serde(skip_serializing_if = "Option::is_none", default)]
459 pub compatible_printers: Option<Vec<CompatiblePrinter>>,
460 #[serde(skip_serializing_if = "Option::is_none", default)]
462 pub printer: Option<Printer>,
463 #[serde(default)]
465 pub settings: Timing,
466 #[serde(skip_serializing_if = "Option::is_none", default)]
468 pub anti_aliasing: Option<AntiAliasing>,
469 #[serde(skip_serializing_if = "Option::is_none", default)]
471 pub materials: Option<Vec<Material>>,
472 #[serde(skip_serializing_if = "Option::is_none", default)]
474 pub scale_compensation_pct: Option<ScaleCompensation>,
475 #[serde(skip_serializing_if = "Option::is_none", default)]
477 pub extra: Option<Value>,
478}
479
480#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
488pub struct Sector {
489 #[serde(default)]
492 pub sector_id: u32,
493 #[serde(skip_serializing_if = "Option::is_none", default)]
495 pub name: Option<String>,
496 #[serde(skip_serializing_if = "Option::is_none", default)]
498 pub material_index: Option<u32>,
499 #[serde(skip_serializing_if = "Option::is_none", default)]
501 pub color_rgba: Option<[u8; 4]>,
502 #[serde(flatten)]
504 pub timing: Timing,
505}