-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmesh_analysis.rs
More file actions
203 lines (179 loc) · 7.84 KB
/
Copy pathmesh_analysis.rs
File metadata and controls
203 lines (179 loc) · 7.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
//! Example: Mesh Operations and Build Volume Analysis
//!
//! This example demonstrates the triangle mesh operations using parry3d:
//! - Computing mesh volume for validation
//! - Calculating bounding boxes
//! - Applying affine transformations
//! - Analyzing overall build volume
//!
//! These capabilities help with:
//! - Detecting inverted meshes (negative volume)
//! - Validating build item placements (N_XXX_0421)
//! - Computing spatial extents for manufacturing constraints
use lib3mf::{Model, mesh_ops};
use std::env;
use std::fs::File;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let args: Vec<String> = env::args().collect();
if args.len() != 2 {
eprintln!("Usage: {} <3mf_file>", args[0]);
eprintln!();
eprintln!("Example: {} test_files/core/box.3mf", args[0]);
std::process::exit(1);
}
let filename = &args[1];
println!("Analyzing 3MF file: {}", filename);
println!();
// Load the 3MF model
let file = File::open(filename)?;
let model = Model::from_reader(file)?;
println!("Model Information:");
println!(" Unit: {}", model.unit);
println!(" Objects: {}", model.resources.objects.len());
println!(" Build Items: {}", model.build.items.len());
println!();
// Analyze each object
for object in &model.resources.objects {
println!("Object ID: {}", object.id);
if let Some(ref mesh) = object.mesh {
println!(" Vertices: {}", mesh.vertices.len());
println!(" Triangles: {}", mesh.triangles.len());
// Compute signed volume
match mesh_ops::compute_mesh_signed_volume(mesh) {
Ok(signed_volume) => {
println!(" Signed Volume: {:.6} cubic units", signed_volume);
if signed_volume < 0.0 {
println!(
" ⚠️ WARNING: Negative volume detected - mesh may be inverted!"
);
} else {
println!(" ✓ Positive volume - mesh orientation is correct");
}
}
Err(e) => {
println!(" Error computing volume: {}", e);
}
}
// Compute unsigned volume using parry3d
match mesh_ops::compute_mesh_volume(mesh) {
Ok(volume) => {
println!(" Absolute Volume: {:.6} cubic units", volume);
}
Err(e) => {
println!(" Error computing absolute volume: {}", e);
}
}
// Compute bounding box
match mesh_ops::compute_mesh_aabb(mesh) {
Ok((min, max)) => {
println!(" Bounding Box:");
println!(" Min: ({:.2}, {:.2}, {:.2})", min.0, min.1, min.2);
println!(" Max: ({:.2}, {:.2}, {:.2})", max.0, max.1, max.2);
println!(
" Dimensions: {:.2} x {:.2} x {:.2}",
max.0 - min.0,
max.1 - min.1,
max.2 - min.2
);
}
Err(e) => {
println!(" Error computing bounding box: {}", e);
}
}
} else {
println!(" No mesh data");
}
println!();
}
// Analyze build items and their transformations
if !model.build.items.is_empty() {
println!("Build Items Analysis:");
println!();
for (idx, item) in model.build.items.iter().enumerate() {
println!(" Build Item {}: Object {}", idx + 1, item.objectid);
// Find the referenced object
let object = model
.resources
.objects
.iter()
.find(|obj| obj.id == item.objectid);
if let Some(object) = object {
if let Some(ref mesh) = object.mesh {
// Show transform if present
if let Some(ref transform) = item.transform {
println!(" Transform:");
println!(
" [ {:.2} {:.2} {:.2} {:.2} ]",
transform[0], transform[1], transform[2], transform[3]
);
println!(
" [ {:.2} {:.2} {:.2} {:.2} ]",
transform[4], transform[5], transform[6], transform[7]
);
println!(
" [ {:.2} {:.2} {:.2} {:.2} ]",
transform[8], transform[9], transform[10], transform[11]
);
// Extract translation component
let tx = transform[3];
let ty = transform[7];
let tz = transform[11];
println!(" Translation: ({:.2}, {:.2}, {:.2})", tx, ty, tz);
// Compute transformed bounding box
match mesh_ops::compute_transformed_aabb(mesh, Some(transform)) {
Ok((min, max)) => {
println!(" Transformed Bounding Box:");
println!(" Min: ({:.2}, {:.2}, {:.2})", min.0, min.1, min.2);
println!(" Max: ({:.2}, {:.2}, {:.2})", max.0, max.1, max.2);
// Check for potential issues (N_XXX_0421)
if max.0 < 0.0 && max.1 < 0.0 && max.2 < 0.0 {
println!(
" ⚠️ WARNING: Entire mesh is in negative coordinate space!"
);
println!(
" This may indicate an incorrect transformation."
);
}
}
Err(e) => {
println!(" Error computing transformed AABB: {}", e);
}
}
} else {
println!(" No transform (using identity)");
// Show original bounding box
if let Ok((min, max)) = mesh_ops::compute_mesh_aabb(mesh) {
println!(" Bounding Box:");
println!(" Min: ({:.2}, {:.2}, {:.2})", min.0, min.1, min.2);
println!(" Max: ({:.2}, {:.2}, {:.2})", max.0, max.1, max.2);
}
}
}
} else {
println!(" ⚠️ Referenced object not found!");
}
println!();
}
// Compute overall build volume
println!("Overall Build Volume:");
match mesh_ops::compute_build_volume(&model) {
Some((min, max)) => {
println!(" Min: ({:.2}, {:.2}, {:.2})", min.0, min.1, min.2);
println!(" Max: ({:.2}, {:.2}, {:.2})", max.0, max.1, max.2);
println!(
" Dimensions: {:.2} x {:.2} x {:.2} {}",
max.0 - min.0,
max.1 - min.1,
max.2 - min.2,
model.unit
);
let volume = (max.0 - min.0) * (max.1 - min.1) * (max.2 - min.2);
println!(" Bounding Volume: {:.2} cubic {}", volume, model.unit);
}
None => {
println!(" Could not compute build volume (no meshes or build items)");
}
}
}
Ok(())
}