diff --git a/crates/engine/src/cmd/results.rs b/crates/engine/src/cmd/results.rs index 92b9c05..55a3407 100644 --- a/crates/engine/src/cmd/results.rs +++ b/crates/engine/src/cmd/results.rs @@ -346,8 +346,8 @@ mod tests { fn the_display_follows_the_commands_and_is_not_an_edit() { let mut s = solved(); let (journal, revision) = (s.journal.len(), s.revision()); - // Solving showed the first solved step. - assert_eq!(s.results_view.as_ref().map(|v| (v.step.as_str(), v.contour)), Some(("Bend", Some(Field::VonMises)))); + // Solving showed the first solved step, a static one: contours on the undeformed shape. + assert_eq!(s.results_view.as_ref().map(|v| (v.step.as_str(), v.contour, v.deformed)), Some(("Bend", Some(Field::VonMises), false))); s.execute("results.clear", &json!({})).unwrap(); let r = s.execute("results.contour", &json!({"field": "von_mises"})).unwrap(); assert_eq!(r["view"]["step"], "Bend", "{r}"); @@ -364,7 +364,7 @@ mod tests { let r = s.execute("results.modes", &json!({"mode": 3})).unwrap(); assert_eq!((r["view"]["step"].as_str(), r["view"]["mode"].as_u64()), (Some("Modes"), Some(3))); assert_eq!(r["modes"].as_array().map(Vec::len), Some(4)); - assert_eq!(s.results_view.as_ref().and_then(|v| v.contour), Some(Field::Displacement)); + assert_eq!(s.results_view.as_ref().map(|v| (v.contour, v.deformed)), Some((Some(Field::Displacement), true)), "a mode shape is deformed"); assert!(s.execute("results.contour", &json!({"field": "von_mises"})).is_err()); s.execute("results.contour", &json!({"field": "displacement", "bands": 6})).unwrap(); s.execute("results.animate", &json!({})).unwrap(); diff --git a/crates/engine/src/results.rs b/crates/engine/src/results.rs index 0528316..6f8738a 100644 --- a/crates/engine/src/results.rs +++ b/crates/engine/src/results.rs @@ -268,9 +268,11 @@ pub struct ResultsView { } impl ResultsView { - /// How a step's result is shown first: deformed, with von Mises contours for a static step - /// (and an explicit step that kept stresses), the first mode with displacement contours for - /// a frequency step; an explicit step at its last frame, to true scale. + /// How a step's result is shown first: a static step undeformed with von Mises contours, so + /// they are read on the true geometry (`results.deformed` shows the deformed shape, at the + /// automatic scale); a frequency step's first mode deformed with displacement contours (a + /// mode shape is a deformation); an explicit step at its last frame, deformed to true scale + /// (with von Mises contours when it kept stresses); a heat step undeformed. pub fn for_result(r: &StepResult) -> ResultsView { let heat = matches!(r.kind(), Kind::Heat(_)); let contour = if heat { @@ -283,7 +285,7 @@ impl ResultsView { let scale = matches!(r.kind(), Kind::Explicit(_)).then_some(1.0); ResultsView { step: r.step().to_string(), - deformed: !heat, + deformed: matches!(r.kind(), Kind::Frequency(_) | Kind::Explicit(_)), scale, contour: Some(contour), bands: DEFAULT_BANDS, diff --git a/crates/engine/src/view.rs b/crates/engine/src/view.rs index f8dec2d..694db90 100644 --- a/crates/engine/src/view.rs +++ b/crates/engine/src/view.rs @@ -266,7 +266,8 @@ mod tests { s.execute("solve.static", &json!({})).unwrap(); let (plot, shown) = render_png(&s, &iso, 64, 48, &Palette::LIGHT).unwrap(); assert_ne!(model, plot); - assert!(shown.scale > 0.0 && shown.step.is_some(), "{shown:?}"); + // A static step first shows its contours on the undeformed shape. + assert!(shown.scale == 0.0 && shown.step.is_some(), "{shown:?}"); let (field, min, max) = shown.contour.unwrap(); assert_eq!(field, "von_mises"); assert!(max.1 > min.1); diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index 5f5a3c6..cc3fc55 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -1693,7 +1693,8 @@ mod tests { app.start("solve.static").unwrap(); app.run_dialog().unwrap(); let view = app.session.results_view.clone().unwrap(); - assert_eq!((view.step.as_str(), view.contour, view.deformed), ("Load", Some(fieldcraft_engine::results::Field::VonMises), true)); + // A static step first shows its contours on the undeformed shape (#77). + assert_eq!((view.step.as_str(), view.contour, view.deformed), ("Load", Some(fieldcraft_engine::results::Field::VonMises), false)); app.logic(&egui::Context::default()); assert_eq!(app.ui.tab, Tab::Results); app.run("solve.frequency", json!({})).unwrap(); diff --git a/docs/control-protocol.md b/docs/control-protocol.md index 7926731..568782e 100644 --- a/docs/control-protocol.md +++ b/docs/control-protocol.md @@ -30,7 +30,7 @@ checked and clamped (drag steps, wheel lines, window size); `ui.render` refuses Commands never open forms or file pickers when run this way. `fieldcraft-cli commands` prints the same registry. `file.sample {name}` opens a sample (`parts`, `cantilever`, `impact`) and -`solve.run {}` solves every step; the Results workspace comes up when a result appears. The +`solve.run {}` solves every step; the Results workspace comes up when a result appears (a static step with its contours on the undeformed shape: `results.deformed {}` shows the deformed shape). The ribbon follows the commands run here, as it does for scripts, MCP, the command search and the browser: a command that changes the model or the results display brings the tab where its toolbar entry lives (Mesh for `mesh.*`, Properties, Steps, Loads & BCs… for `model.*`, Solve, diff --git a/docs/examples.md b/docs/examples.md index 6de3373..302699e 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -105,7 +105,7 @@ foot's end. Linear static: about 2 s to open (the cells are rebuilt from the scr solve. **Look at:** the mesh (Prepare ▸ Mesh) — mapped blocks meeting face to face with no pyramids or -tets — and the von Mises contours on the deformed shape: the stress runs round the fillet and +tets — and the von Mises contours (tick Deformed for the deformed shape): the stress runs round the fillet and peaks at 295 MPa at the upright's hole. **Check:** the tip of the foot moves 0.509 mm down, within 1 % of a 48 016-element tet10