Surface Revolve: sheets turned from open curves and profiles (#824)

Surface Revolve turns open curves and closed profile boundaries about a sketch axis into surface bodies, with cone apexes and sphere poles where a chain ends on the axis, and a closed shell made solid. Adds the SurfaceRevolve feature (format 18 note), the surface.revolve command, a dialog with Edit Feature support and analytic kernel and engine tests.

Part of #757.
This commit is contained in:
Irakli Kourtis authored and GitHub committed 2026-10-13 20:30:41 -04:00
1 parent b41ad23e3f
commit 2eb292dd4a
16 files changed
+411 -83

No files matched your search

+28
View File
@@ -854,6 +854,34 @@ fn unstitch_and_reverse_normal_dialogs_take_a_body_or_faces() {
app.session.execute(&id, &p).unwrap();
}
#[test]
fn surface_revolve_dialog_takes_curves_and_an_axis() {
// A line beside the sketch's y axis, turned a quarter round: a quarter cylinder. Edit
// Feature brings back the curve and the axis.
let mut app = app_with(json!([
{"command": "sketch.create", "params": {"plane": "XY"}},
{"command": "sketch.line", "params": {"points": [[3, 0], [3, 4]], "ids": ["side"]}},
{"command": "sketch.finish", "params": {}}
]));
let mut d = start(&mut app, vec![], "surface.revolve");
d.inputs[0].items = vec![Sel::SketchCurve { id: "side".into() }];
assert!(apply_commands(&app, &d).is_err(), "no axis yet");
d.inputs[1].items = vec![Sel::Axis { name: "y".into() }];
if let Kind::Surface(crate::dialogs_surface::Surf::Revolve { angle, .. }) = &mut d.kind {
*angle = "90 deg".into();
}
let (id, p) = apply_commands(&app, &d).unwrap().remove(0);
assert_eq!((id.as_str(), &p["axis"], &p["curves"]), ("surface.revolve", &json!("y"), &json!(["side"])), "{p}");
app.session.execute(&id, &p).unwrap();
let area = app.session.model.state().bodies.last().unwrap().mesh().measure().area;
let want = std::f64::consts::FRAC_PI_2 * 3.0 * 4.0;
assert!((area - want).abs() < want * 2e-3, "{area} vs {want}");
let fid = app.session.doc.features.last().unwrap().id;
let back = crate::dialogs::for_feature(&app, fid, None).unwrap();
assert_eq!(back.inputs[0].items, vec![Sel::SketchCurve { id: "side".into() }]);
assert_eq!(back.inputs[1].items, vec![Sel::Axis { name: "y".into() }]);
}
#[test]
fn patch_dialog_fills_a_loop_of_edges_that_is_not_planar() {
// A box with its top cut away by a sideways cylinder: its rim is a closed loop of four