Results: a static step first shows its contours undeformed

The first look at a solved static step draws the von Mises contours on the
true geometry; the deformed shape comes when asked for (Deformed,
results.deformed, results.animate), at the automatic scale. Frequency steps
still open on mode 1 deformed and explicit steps at true scale, as the
owner's notes in #77 ask; a 0.24 mm deflection drawn as 10 mm no longer
reads as a failed part.

Fixes #77

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
This commit is contained in:
jyvikoandClaude Opus 5.5 authored and Irakli Kourtis committed 2026-10-14 22:29:44 -04:00
1 parent 29af2aef91
commit 5758dc7911
6 files changed
+15 -11

No files matched your search

+3 -3
View File
@@ -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();
+6 -4
View File
@@ -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,
+2 -1
View File
@@ -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);
+2 -1
View File
@@ -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();
+1 -1
View File
@@ -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,
+1 -1
View File
@@ -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