* Imports become components: a STEP assembly's tree as nested components (#1386) Every imported file (STEP, IGES, 3MF, STL, OBJ: inserted, dropped, opened as a design, or file.insert_step / file.insert_mesh / doc.open from scripts, the CLI and MCP) now comes in as a new component named after the file, with its Import feature inside it. A STEP assembly's products become nested components; a part placed more than once is one component with an occurrence per placement, and the Import feature skips the file's later copies (`skip`, format 21 note). The contents are held as one rigid group (rigid joints, glyphs hidden); moving an inner part is refused until component.unlock ("Unlock Contents") releases it. Y up turns the import's component. Replies report component, component_name and occurrence. Undo is one step; designs with loose imports are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Keep an import's rigid group hidden when the window loads the file in the background Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Import instances' skip list is format 22: format 21 ships in 0.12.0 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Catalog entries for Unlock Contents Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d43c414b7b
commit
27529d9742
37 files changed
+968
-103
No files matched your search
@@ -42,6 +42,10 @@ pub static COMMANDS: &[CommandSpec] = &[
|
||||
.params("occurrence: id or name; path?: [occurrence ids] (required if nested under multiple instances); descendants?: bool (default true). Physical properties of this placement in world coordinates, including pending moves"),
|
||||
CommandSpec::new("component.rename", "Rename Component", rename).params("component, name"),
|
||||
CommandSpec::new("component.delete", "Delete Component", delete).params("component: deletes it, its subcomponents, occurrences and features"),
|
||||
CommandSpec::new("component.unlock", "Unlock Contents", unlock).icon("rigid_group").params(
|
||||
"component: removes the rigid joints that hold its contents together (an imported assembly's rigid group), so its parts \
|
||||
move and take joints one by one → joints (the ids removed)",
|
||||
),
|
||||
CommandSpec::new("component.move_bodies", "Move Bodies to Component", move_bodies).params("bodies: [names], component"),
|
||||
CommandSpec::new("component.move_sketches", "Move Sketches to Component", move_sketches).params("sketches: [ids or names], component"),
|
||||
CommandSpec::new("occurrence.copy", "Paste (Instance)", copy_occurrence)
|
||||
@@ -251,6 +255,23 @@ fn delete(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
Ok(json!({"deleted": gone, "features": feats}))
|
||||
}
|
||||
|
||||
fn unlock(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let cmd = "component.unlock";
|
||||
let id = component(s, p, "component", cmd)?;
|
||||
if id == 0 {
|
||||
return Err(bad(cmd, "pick a component, not the design"));
|
||||
}
|
||||
let gone = s.contents_joints(id);
|
||||
if gone.is_empty() {
|
||||
return Err(bad(cmd, "nothing holds this component's contents together"));
|
||||
}
|
||||
let doc = s.doc_mut();
|
||||
doc.assembly.joints.retain(|j| !gone.contains(&j.id));
|
||||
doc.assembly.links.retain(|l| !gone.contains(&l.a) && !gone.contains(&l.b));
|
||||
s.visibility.hidden_joints.retain(|h| !gone.contains(h));
|
||||
Ok(json!({"component": id, "joints": gone}))
|
||||
}
|
||||
|
||||
fn move_bodies(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
transfer::move_bodies(s, p)
|
||||
}
|
||||
@@ -376,6 +397,17 @@ fn move_occurrence(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
if o.grounded {
|
||||
return Err(bad(cmd, format!("{} is grounded", o.name)));
|
||||
}
|
||||
if let Some(mut group) = s.held_by_rigid_group(id) {
|
||||
// The outermost component the group holds it in moves it.
|
||||
for _ in 0..64 {
|
||||
match s.doc.occurrence_of(group).and_then(|o| s.held_by_rigid_group(o.id)) {
|
||||
Some(up) => group = up,
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
let name = s.doc.components.iter().find(|c| c.id == group).map(|c| c.name.clone()).unwrap_or_default();
|
||||
return Err(bad(cmd, format!("{} is held in {name} by a rigid group: move {name}, or Unlock Contents (component.unlock) first", o.name)));
|
||||
}
|
||||
let t = move_vector(p, "translate", Vec3::ZERO, true, cmd)?;
|
||||
let axis = move_vector(p, "axis", Vec3::Z, false, cmd)?;
|
||||
let angle = match p.get("angle") {
|
||||
|
||||
Reference in new issue
Block a user