lib3mf_core/model/core.rs
1use super::units::Unit;
2use crate::model::{Build, ResourceCollection};
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6/// Root element of a 3MF document.
7///
8/// The `Model` contains all information required to describe a 3D model, including:
9/// - Resources (Meshes, Materials, Textures)
10/// - Build instructions (Item positioning)
11/// - Metadata (Authors, Copyright, etc.)
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct Model {
14 /// The unit of measurement for geometry coordinates.
15 #[serde(default)]
16 pub unit: Unit,
17
18 /// The language of the model content (e.g., "en-US").
19 #[serde(skip_serializing_if = "Option::is_none")]
20 pub language: Option<String>,
21
22 /// Arbitrary metadata key-value pairs.
23 #[serde(default)]
24 pub metadata: HashMap<String, String>,
25
26 /// Collection of all resources (objects, materials) used in the build.
27 #[serde(default)]
28 pub resources: ResourceCollection,
29
30 /// The build definition, containing instances of objects to be printed.
31 #[serde(default)]
32 pub build: Build,
33
34 /// Binary attachments (Textures, Thumbnails, etc.) stored by package path.
35 /// Key: Path in archive (e.g., "Metadata/thumbnail.png", "3D/Textures/diffuse.png")
36 /// Value: Binary content
37 #[serde(skip)]
38 pub attachments: HashMap<String, Vec<u8>>,
39
40 /// Existing OPC relationships loaded from the archive.
41 /// Key: Relationship file path (e.g., "3D/_rels/3dmodel.model.rels")
42 /// Value: Parsed relationships
43 #[serde(skip)]
44 pub existing_relationships: HashMap<String, Vec<crate::archive::opc::Relationship>>,
45}
46
47impl Model {
48 /// Validates the 3MF model at the specified validation level.
49 ///
50 /// The validation system is progressive, with four levels of increasing strictness:
51 ///
52 /// - **Minimal**: Basic structural checks (required attributes, valid XML structure)
53 /// - **Standard**: Reference integrity checks (resource IDs exist, build references valid objects)
54 /// - **Strict**: Full spec compliance (metadata presence, no unknown attributes)
55 /// - **Paranoid**: Deep geometry analysis (manifoldness, self-intersection, orientation consistency)
56 ///
57 /// # Parameters
58 ///
59 /// - `level`: The [`ValidationLevel`](crate::validation::ValidationLevel) to apply. Higher levels
60 /// include all checks from lower levels.
61 ///
62 /// # Returns
63 ///
64 /// A [`ValidationReport`](crate::validation::ValidationReport) containing all errors, warnings,
65 /// and info messages found during validation. Check [`has_errors()`](crate::validation::ValidationReport::has_errors)
66 /// to determine if the model passed validation.
67 ///
68 /// # Examples
69 ///
70 /// ```
71 /// use lib3mf_core::{Model, validation::ValidationLevel};
72 ///
73 /// let model = Model::default();
74 ///
75 /// // Quick structural check
76 /// let report = model.validate(ValidationLevel::Minimal);
77 /// assert!(!report.has_errors());
78 ///
79 /// // Recommended for production use
80 /// let report = model.validate(ValidationLevel::Standard);
81 /// if report.has_errors() {
82 /// for item in &report.items {
83 /// eprintln!("Error: {}", item.message);
84 /// }
85 /// }
86 ///
87 /// // Deep inspection (expensive, for critical applications)
88 /// let report = model.validate(ValidationLevel::Paranoid);
89 /// ```
90 ///
91 /// # Performance
92 ///
93 /// - **Minimal**: Very fast, suitable for quick checks
94 /// - **Standard**: Fast, recommended for most use cases
95 /// - **Strict**: Moderate, includes metadata and attribute checks
96 /// - **Paranoid**: Slow, performs O(n²) geometry checks with BVH acceleration
97 pub fn validate(
98 &self,
99 level: crate::validation::ValidationLevel,
100 ) -> crate::validation::ValidationReport {
101 use crate::validation::{ValidationLevel, displacement, geometry, schema, semantic};
102
103 let mut report = crate::validation::ValidationReport::new();
104
105 // Minimal: Schema validation (placeholders usually checked by parser, but explicit invariants here)
106 if level >= ValidationLevel::Minimal {
107 schema::validate_schema(self, &mut report);
108 }
109
110 // Standard: Semantic validation (integrity)
111 if level >= ValidationLevel::Standard {
112 semantic::validate_semantic(self, &mut report);
113 }
114
115 // All levels: Displacement validation (progressive checks)
116 displacement::validate_displacement(self, level, &mut report);
117
118 // Paranoid: Geometry validation
119 if level >= ValidationLevel::Paranoid {
120 geometry::validate_geometry(self, level, &mut report);
121 }
122
123 report
124 }
125}
126
127impl Default for Model {
128 fn default() -> Self {
129 Self {
130 unit: Unit::Millimeter,
131 language: None,
132 metadata: HashMap::new(),
133 resources: ResourceCollection::default(),
134 build: Build::default(),
135 attachments: HashMap::new(),
136 existing_relationships: HashMap::new(),
137 }
138 }
139}
140
141// Unit enum moved to definition in units.rs