3MF: export, and 3MF/STL import as mesh bodies
Export: ExportCommand/CLI --out/MCP export with .3mf write a 3MF Core package ([Content_Types].xml, _rels/.rels, 3D/3dmodel.model; millimetres), one mesh object and build item per body, named after it, vertices shared and welded watertight (T-junctions between faces split), base-material colours when bodies carry one (STEP colours now ride on bodies). Tessellation as for STL. File > Export 3MF. Import: doc.open/drag-drop/CLI/MCP open accept .3mf and .stl; Insert Mesh (ParaMeshInsertAlignCommand) adds them to a design as a MeshImport feature. Kernel mesh bodies render, measure exactly, move and export; solid features refuse them with a clear error. 3MF reading flattens components and build transforms, converts units, reads colours; sizes, entries, nesting and element counts are capped. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
This commit is contained in:
1 parent
043a542e29
commit
ea3dd0ed6e
30 files changed
+1361
-47
No files matched your search
@@ -170,7 +170,7 @@ impl SolveApp {
|
||||
/// that have them, otherwise run it with defaults.
|
||||
pub fn start(&mut self, id: &str) {
|
||||
self.tool = None;
|
||||
if id == "FusionImportCommandFromToolbar" {
|
||||
if matches!(id, "FusionImportCommandFromToolbar" | "ParaMeshInsertAlignCommand") {
|
||||
if let Some(p) = self.services.pick_open.as_ref().and_then(|f| f()) {
|
||||
self.insert_path(&p);
|
||||
}
|
||||
@@ -250,9 +250,11 @@ impl SolveApp {
|
||||
}
|
||||
}
|
||||
|
||||
/// Insert a STEP file's bodies into the current design (an Import base feature).
|
||||
/// Insert a STEP file's bodies (an Import base feature) or a 3MF/STL file's meshes into the
|
||||
/// current design.
|
||||
pub fn insert_path(&mut self, path: &str) {
|
||||
if let Ok(r) = self.run("FusionImportCommandFromToolbar", json!({ "path": path })) {
|
||||
let cmd = if solvecraft_engine::io::is_mesh_path(path) { "ParaMeshInsertAlignCommand" } else { "FusionImportCommandFromToolbar" };
|
||||
if let Ok(r) = self.run(cmd, json!({ "path": path })) {
|
||||
self.fit_view();
|
||||
if let Some(w) = r["warnings"].as_array().filter(|w| !w.is_empty()) {
|
||||
self.set_status(format!("imported with {} warning(s): {}", w.len(), w.first().and_then(Value::as_str).unwrap_or("")), false);
|
||||
@@ -260,9 +262,11 @@ impl SolveApp {
|
||||
}
|
||||
}
|
||||
|
||||
/// A dropped file: a STEP file joins a design that has features, anything else opens.
|
||||
/// A dropped file: a STEP, 3MF or STL file joins a design that has features, anything else
|
||||
/// opens.
|
||||
pub fn drop_path(&mut self, path: &str) {
|
||||
if solvecraft_engine::io::is_step_path(path) && !self.session.doc.features.is_empty() {
|
||||
let import = solvecraft_engine::io::is_step_path(path) || solvecraft_engine::io::is_mesh_path(path);
|
||||
if import && !self.session.doc.features.is_empty() {
|
||||
self.insert_path(path);
|
||||
} else {
|
||||
self.open_path(path);
|
||||
|
||||
@@ -30,7 +30,7 @@ fn icon_of(k: &FeatureKind) -> &'static str {
|
||||
FeatureKind::Draft { .. } => "draft",
|
||||
FeatureKind::Split { .. } => "split",
|
||||
FeatureKind::Move { .. } => "move",
|
||||
FeatureKind::Import { .. } => "import",
|
||||
FeatureKind::Import { .. } | FeatureKind::MeshImport { .. } => "import",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -131,6 +131,10 @@ fn file_menu(app: &mut SolveApp, ctx: &egui::Context) {
|
||||
app.start("FusionImportCommandFromToolbar");
|
||||
close = true;
|
||||
}
|
||||
if item(ui, "Insert Mesh…", "") {
|
||||
app.start("ParaMeshInsertAlignCommand");
|
||||
close = true;
|
||||
}
|
||||
if item(ui, "Save", "Ctrl+S") {
|
||||
save(app);
|
||||
close = true;
|
||||
@@ -148,6 +152,10 @@ fn file_menu(app: &mut SolveApp, ctx: &egui::Context) {
|
||||
export(app, "step");
|
||||
close = true;
|
||||
}
|
||||
if item(ui, "Export 3MF…", "") {
|
||||
export(app, "3mf");
|
||||
close = true;
|
||||
}
|
||||
if item(ui, "Export OBJ…", "") {
|
||||
export(app, "obj");
|
||||
close = true;
|
||||
|
||||
Reference in new issue
Block a user