Merge PR #1083: implement solid shell workflow

This commit is contained in:
Hakan Seven committed 2026-09-08 21:02:01 +03:00
commit c5503e4758
19 files changed
+851 -115

No files matched your search

+87 -1
View File
@@ -982,7 +982,7 @@ impl OpenCADStudio {
"area":planar.curve.is_closed().then(|| planar.curve.enclosed_area().abs())
})
});
out.push(json!({"handle":format!("{:X}",handle.value()),"type":crate::entities::names::ui_name(entity),"bounds":{"min":[bb.min.x,bb.min.y,bb.min.z],"max":[bb.max.x,bb.max.y,bb.max.z]},"curve":curve,"mesh":metrics.map(|m|json!({"vertices":m.metrics.vertices,"triangles":m.metrics.triangles,"surface_area":m.metrics.surface_area,"volume":m.metrics.volume,"centroid":m.metrics.centroid}))}));
out.push(json!({"handle":format!("{:X}",handle.value()),"type":crate::entities::names::ui_name(entity),"bounds":{"min":[bb.min.x,bb.min.y,bb.min.z],"max":[bb.max.x,bb.max.y,bb.max.z]},"curve":curve,"mesh":metrics.map(|m|json!({"vertices":m.metrics.vertices,"triangles":m.metrics.triangles,"surface_area":m.metrics.surface_area,"volume":m.metrics.volume,"centroid":m.metrics.centroid,"moment_of_inertia":m.metrics.moment_of_inertia,"principal_directions":m.metrics.principal_directions,"principal_moments":m.metrics.principal_moments,"product_of_inertia":m.metrics.product_of_inertia,"radii_of_gyration":m.metrics.radii_of_gyration}))}));
}
json!({"ok":true,"document_id":tab.id,"geometry_revision":tab.scene.geometry_epoch,"measurements":out})
}
@@ -1222,6 +1222,92 @@ mod tests {
assert!((curve["length"].as_f64().unwrap() - std::f64::consts::TAU * 2.0).abs() < 1e-9);
assert!((curve["area"].as_f64().unwrap() - std::f64::consts::PI * 4.0).abs() < 1e-9);
}
#[test]
fn control_shell_roundtrips_with_kernel_mass_properties() {
let mut app = OpenCADStudio::new_for_test();
request(&mut app, json!({"op":"new"}));
request(&mut app, json!({"op":"start","cmd":"BOX"}));
request(
&mut app,
json!({"op":"input","kind":"point","point":[0.0,0.0,0.0]}),
);
request(
&mut app,
json!({"op":"input","kind":"point","point":[6.0,5.0,0.0]}),
);
assert_eq!(
request(&mut app, json!({"op":"input","kind":"token","text":"4"}))["status"],
"completed"
);
let handle = app.tabs[app.active_tab]
.scene
.document
.entities()
.find_map(|entity| {
matches!(entity, acadrust::EntityType::Solid3D(_)).then(|| entity.common().handle)
})
.unwrap();
let handle_text = format!("{:X}", handle.value());
request(&mut app, json!({"op":"select","handles":[handle_text]}));
request(&mut app, json!({"op":"start","cmd":"SHELL"}));
request(
&mut app,
json!({"op":"input","kind":"entity","handle":handle_text,"point":[3.0,2.5,4.0]}),
);
request(&mut app, json!({"op":"input","kind":"enter"}));
assert_eq!(
request(&mut app, json!({"op":"input","kind":"token","text":"0.5"}))["status"],
"completed"
);
let measured = app.control_measure(&json!({"handles":[handle_text]}));
let mesh = &measured["measurements"][0]["mesh"];
assert!((mesh["volume"].as_f64().unwrap() - 50.0).abs() < 1e-9);
assert_eq!(mesh["principal_moments"].as_array().unwrap().len(), 3);
assert!(matches!(
app.tabs[app.active_tab]
.scene
.document
.solid_history_operation(handle),
Some(acadrust::objects::SolidHistoryOperation::Brep(_))
));
assert_eq!(request(&mut app, json!({"op":"undo"}))["ok"], true);
let restored = app.control_measure(&json!({"handles":[handle_text]}));
assert!(
(restored["measurements"][0]["mesh"]["volume"]
.as_f64()
.unwrap()
- 120.0)
.abs()
< 1e-9
);
assert_eq!(request(&mut app, json!({"op":"redo"}))["ok"], true);
let path = std::env::temp_dir().join(format!("ocs-shell-{}.dwg", session_id()));
assert_eq!(
request(&mut app, json!({"op":"save","path":path}))["ok"],
true
);
request(&mut app, json!({"op":"new"}));
assert_eq!(
request(&mut app, json!({"op":"open","path":path}))["status"],
"completed"
);
let reopened = app.control_measure(&json!({"handles":[handle_text]}));
assert!(
(reopened["measurements"][0]["mesh"]["volume"]
.as_f64()
.unwrap()
- 50.0)
.abs()
< 1e-9
);
let _ = std::fs::remove_file(path);
}
#[test]
fn control_retry_is_idempotent_and_stale_state_rejected() {
let mut app = OpenCADStudio::new_for_test();