component.list: a compact form for large assemblies (#1305)
component.list {compact: true} gives counts of bodies, features, sketches and construction planes instead of their names, lists occurrences without identity transforms and children as occurrence ids; bodies: true keeps body names. The default form is unchanged.
This commit is contained in:
1 parent
9eddb1cbd3
commit
fd19efc6fc
2 files changed
+49
-6
No files matched your search
@@ -30,7 +30,10 @@ pub static COMMANDS: &[CommandSpec] = &[
|
||||
.icon("component")
|
||||
.params("bodies: [names] → one new component per body, named after it"),
|
||||
CommandSpec::new("component.activate", "Activate Component", activate).noundo().params("component: id or name (0 or \"root\" for the design); occurrence?, path?: exact placement used to author shared geometry"),
|
||||
CommandSpec::new("component.list", "List Components", list).noundo(),
|
||||
CommandSpec::new("component.list", "List Components", list).noundo().params(
|
||||
"compact?: bool (counts of bodies, features, sketches and construction planes instead of their names; occurrences leave out \
|
||||
identity transforms; children as occurrence ids); bodies?: bool (with compact: body names, not their count)",
|
||||
),
|
||||
CommandSpec::new("component.properties", "Component Physical Properties", properties::component)
|
||||
.icon("measure").noundo()
|
||||
.params("component?: id or name (default active); descendants?: bool (default true). Measures the first placement, or all placements for root, including pending moves; material-aware mass and center of mass in world coordinates"),
|
||||
@@ -156,9 +159,23 @@ fn activate(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
Ok(json!({ "active": id }))
|
||||
}
|
||||
|
||||
fn list(s: &mut Session, _p: &Value) -> Result<Value> {
|
||||
fn list(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let st = s.model.state();
|
||||
let doc = &s.doc;
|
||||
// Compact: what a large assembly needs to be found around in, without every name and matrix.
|
||||
let compact = bool_(p, "compact").unwrap_or(false);
|
||||
let names = |v: Vec<&str>| if compact { json!(v.len()) } else { json!(v) };
|
||||
let body_names = !compact || bool_(p, "bodies").unwrap_or(false);
|
||||
let placement = |o: &Occurrence| {
|
||||
if !compact {
|
||||
return json!(o);
|
||||
}
|
||||
let mut v = json!({"id": o.id, "name": o.name, "parent": o.parent, "grounded": o.grounded});
|
||||
if o.transform.iter().flatten().zip(solidcraft_doc::IDENTITY.iter().flatten()).any(|(a, b)| (a - b).abs() > 1e-12) {
|
||||
v["transform"] = json!(o.transform);
|
||||
}
|
||||
v
|
||||
};
|
||||
let node = |id: u64, name: &str, parent: Option<u64>| {
|
||||
let bodies: Vec<&str> = st.bodies.iter().filter(|b| doc.model_body_component(b) == id).map(|b| b.name.as_str()).collect();
|
||||
let features: Vec<&str> = doc
|
||||
@@ -175,10 +192,11 @@ fn list(s: &mut Session, _p: &Value) -> Result<Value> {
|
||||
.filter(|f| f.component == id && matches!(f.kind, FeatureKind::ConstructionPlane { .. }))
|
||||
.map(|f| f.name.as_str())
|
||||
.collect();
|
||||
let occurrences: Vec<&Occurrence> = doc.occurrences.iter().filter(|o| o.component == id).collect();
|
||||
let children: Vec<&Occurrence> = doc.occurrences.iter().filter(|o| o.parent == id).collect();
|
||||
json!({"id": id, "name": name, "parent": parent, "bodies": bodies, "features": features, "sketches": sketches,
|
||||
"construction": construction, "occurrences": occurrences, "children": children})
|
||||
let occurrences: Vec<Value> = doc.occurrences.iter().filter(|o| o.component == id).map(placement).collect();
|
||||
let children: Vec<Value> = doc.occurrences.iter().filter(|o| o.parent == id).map(|o| if compact { json!(o.id) } else { json!(o) }).collect();
|
||||
let bodies = if body_names { json!(bodies) } else { json!(bodies.len()) };
|
||||
json!({"id": id, "name": name, "parent": parent, "bodies": bodies, "features": names(features), "sketches": names(sketches),
|
||||
"construction": names(construction), "occurrences": occurrences, "children": children})
|
||||
};
|
||||
let mut out = vec![node(0, &doc.name, None)];
|
||||
for c in &doc.components {
|
||||
|
||||
@@ -539,3 +539,28 @@ fn a_linked_design_brings_its_bodies_in_and_follows_edits_to_the_part_file() {
|
||||
near(&measured["total"]["center_of_mass"][0], 55.0);
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
/// The compact list counts what a component holds and leaves out identity transforms; the full
|
||||
/// list stays as it was.
|
||||
#[test]
|
||||
fn compact_component_list_counts_and_skips_identity_transforms() {
|
||||
let mut s = Session::default();
|
||||
let (component, first) = created(&mut s, "Block");
|
||||
run(&mut s, "solid.box", json!({"length": 1, "width": 1, "height": 1, "body_name": "Cube"}));
|
||||
run(&mut s, "component.activate", json!({"component": "root"}));
|
||||
let second = run(&mut s, "occurrence.copy", json!({"component": component, "translate": [20, 0, 0]}))["occurrence"].as_u64().unwrap();
|
||||
let full = run(&mut s, "component.list", json!({}));
|
||||
let block = |l: &Value| l["components"].as_array().unwrap().iter().find(|c| c["id"] == component).unwrap().clone();
|
||||
assert_eq!(block(&full)["bodies"], json!(["Cube"]));
|
||||
assert!(block(&full)["occurrences"].as_array().unwrap().iter().all(|o| o["transform"].is_array()));
|
||||
let compact = run(&mut s, "component.list", json!({"compact": true}));
|
||||
let b = block(&compact);
|
||||
assert_eq!((&b["bodies"], &b["features"], &b["sketches"]), (&json!(1), &json!(1), &json!(0)), "{b}");
|
||||
let placed = |id: u64| b["occurrences"].as_array().unwrap().iter().find(|o| o["id"] == id).unwrap().clone();
|
||||
assert!(placed(first).get("transform").is_none(), "{b}");
|
||||
assert_eq!(placed(second)["transform"][3][0], 20.0, "{b}");
|
||||
let root = compact["components"].as_array().unwrap().iter().find(|c| c["id"] == 0).unwrap().clone();
|
||||
assert_eq!(root["children"], json!([first, second]), "{root}");
|
||||
// Body names on request.
|
||||
assert_eq!(block(&run(&mut s, "component.list", json!({"compact": true, "bodies": true})))["bodies"], json!(["Cube"]));
|
||||
}
|
||||
Reference in new issue
Block a user