ui: Relax around worst element at the top of Mesh Quality; plain preview text (#398)

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-15 14:40:00 -04:00
1 parent 87af68f550
commit a6f1a6dbeb
3 files changed
+16 -14

No files matched your search

+4 -2
View File
@@ -374,7 +374,9 @@ pub(crate) fn weights(model: &Model, p: &Value) -> Result<(BTreeMap<u32, f64>, O
nodes.extend(el.nodes.iter().copied());
}
if listed == 0 {
return Err(EngineError::Params("say which nodes to relax: give one of `center` and `radius`, `around_element`, `nodes`, `elements` or `set`".into()));
return Err(EngineError::Params(
"say which nodes to relax: give one of `center` and `radius`, `around_element`, `nodes`, `elements` or `set`".into(),
));
}
if let Some(only) = &only {
nodes.retain(|n| only.contains(n));
@@ -450,7 +452,7 @@ fn relax_nodes(s: &mut Session, p: &Value) -> Result<Value> {
s.model.set_node(*n, *x)?;
}
let summary = format!(
"moved {} node{} (largest {:.3e}); scaled Jacobian min {:.3} → {:.3}{}",
"moved {} node{} (largest {:.3e}); scaled Jacobian min from {:.3} to {:.3}{}",
r.moved,
if r.moved == 1 { "" } else { "s" },
r.max_displacement,
+1 -1
View File
@@ -1179,7 +1179,7 @@ impl ModelApp {
let p = self.relax_preview()?;
let r = &p.relaxed;
Some(format!(
"Preview: {} nodes move (largest {:.3}); scaled Jacobian min {:.3} → {:.3}, edge ratio max {:.2} → {:.2}, {} → {} invalid",
"Preview: {} nodes move (largest {:.3}); scaled Jacobian min {:.3} to {:.3}, edge ratio max {:.2} to {:.2}, invalid {} to {}",
r.moved,
r.max_displacement,
r.before.min_quality,
+11 -11
View File
@@ -347,7 +347,8 @@ const METRICS: [(&str, &str, bool); 4] = [
const MAX_SELECT: usize = 10_000;
/// `mesh.quality`'s reply: the counts, then each metric's range, histogram and worst element (a
/// click selects and frames it), and buttons selecting the invalid and undetermined elements.
/// click selects and frames it), buttons selecting the invalid and undetermined elements, and
/// Relax around worst element (#398).
fn quality(ui: &mut egui::Ui, t: &Tokens, v: &Value, acts: &mut Vec<Act>) {
let n = |k: &str| v.get(k).and_then(Value::as_u64).unwrap_or(0);
let labels = |k: &str| -> Vec<u32> {
@@ -392,6 +393,15 @@ fn quality(ui: &mut egui::Ui, t: &Tokens, v: &Value, acts: &mut Vec<Act>) {
acts.push(Act::Elements(l));
}
}
if let Some(worst) = v.pointer("/metrics/scaled_jacobian/worst").and_then(Value::as_u64).and_then(|w| u32::try_from(w).ok()) {
if ui
.button("Relax around worst element")
.on_hover_text("Open Relax Nodes with its sphere round the element of smallest scaled Jacobian; preview, then OK")
.clicked()
{
acts.push(Act::Relax(worst));
}
}
for (key, label, low_bad) in METRICS {
let Some(m) = v.pointer(&format!("/metrics/{key}")).filter(|m| m.is_object()) else { continue };
let f = |k: &str| m.get(k).and_then(Value::as_f64);
@@ -419,16 +429,6 @@ fn quality(ui: &mut egui::Ui, t: &Tokens, v: &Value, acts: &mut Vec<Act>) {
}
}
}
if let Some(worst) = v.pointer("/metrics/scaled_jacobian/worst").and_then(Value::as_u64).and_then(|w| u32::try_from(w).ok()) {
ui.add_space(6.0);
if ui
.button("Relax around worst element")
.on_hover_text("Open Relax Nodes with its sphere round the element of smallest scaled Jacobian; preview, then OK")
.clicked()
{
acts.push(Act::Relax(worst));
}
}
if let Some(skipped) = v.get("skipped").and_then(Value::as_object).filter(|s| !s.is_empty()) {
ui.add_space(6.0);
let text: Vec<String> = skipped.iter().map(|(k, n)| format!("{k}: {}", n.as_u64().map_or_else(|| n.to_string(), count))).collect();