forked from 1b-agent/fieldcraft-upstream
UI: datum planes and axes in the viewport, datums and partitions in the browser
Datum planes draw as a hatched square around the model, axes as a line through it, each with its name, in the desktop viewport and the headless render. The browser's Geometry node lists the datums and the partitions with the datum each cuts by. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
This commit is contained in:
1 parent
22f1006f71
commit
f6d227d8cb
6 files changed
+112
-4
No files matched your search
@@ -1,4 +1,5 @@
|
||||
//! The browser (left): the model as a tree. Geometry and Mesh with eye toggles, then the model's
|
||||
//! The browser (left): the model as a tree. Geometry (the design's bodies, datums and
|
||||
//! partitions) and Mesh with eye toggles, then the model's
|
||||
//! definitions (sets, materials, sections, steps, loads and boundary conditions, interactions)
|
||||
//! with counts (Loads & BCs and Interactions with eye toggles for their viewport symbols), and
|
||||
//! the solved steps' results. Clicking a definition selects it (its properties show on the
|
||||
@@ -388,6 +389,26 @@ fn rows(app: &mut ModelApp, ui: &mut egui::Ui, acts: &mut Vec<Act>) {
|
||||
&Row { depth: 2, icon: Some("geometry.import.mesh"), label: s, ..Default::default() },
|
||||
);
|
||||
}
|
||||
// Datum planes and axes, then the partitions in the order they cut.
|
||||
let datums: Vec<(String, &'static str)> =
|
||||
app.session.model.datums().iter().map(|(n, d)| (n.clone(), if d.plane().is_some() { "plane" } else { "axis" })).collect();
|
||||
for (i, (n, kind)) in datums.iter().enumerate() {
|
||||
draw_row(
|
||||
app,
|
||||
ui,
|
||||
egui::Id::new(("fc_row_datum", i)),
|
||||
&Row { depth: 2, icon: Some("geometry.datum"), label: n, note: Some((*kind).into()), ..Default::default() },
|
||||
);
|
||||
}
|
||||
let partitions: Vec<(String, String)> = app.session.model.partitions().iter().map(|p| (p.name.clone(), p.datum.clone())).collect();
|
||||
for (i, (n, datum)) in partitions.iter().enumerate() {
|
||||
draw_row(
|
||||
app,
|
||||
ui,
|
||||
egui::Id::new(("fc_row_partition", i)),
|
||||
&Row { depth: 2, icon: Some("geometry.partition"), label: n, note: Some(format!("by {datum}")), ..Default::default() },
|
||||
);
|
||||
}
|
||||
if design.is_none() && surfaces.is_empty() {
|
||||
draw_row(
|
||||
app,
|
||||
|
||||
@@ -750,7 +750,10 @@ impl ModelApp {
|
||||
};
|
||||
// Symbols follow the drawn nodes: the deformed shape of a results plot.
|
||||
let drawn = self.plot.1.as_ref().map_or(&self.display.1, |p| &p.display);
|
||||
let symbols = scene::symbols(&mut s, &self.glyphs, |n| drawn.node_position(n), show, self.plot.1.is_some(), &t);
|
||||
let mut symbols = scene::symbols(&mut s, &self.glyphs, |n| drawn.node_position(n), show, self.plot.1.is_some(), &t);
|
||||
if show.geometry && self.plot.1.is_none() {
|
||||
symbols.union(scene::datums(&mut s, &self.session.model, &self.display.1.bounds, &t));
|
||||
}
|
||||
self.scene = (Some(key), s, symbols);
|
||||
}
|
||||
let mut bounds = self.display.1.bounds;
|
||||
|
||||
@@ -69,6 +69,11 @@ pub fn symbols(s: &mut Scene, glyphs: &Glyphs, pos: impl Fn(u32) -> Option<Vec3>
|
||||
glyphs.draw(pos, GlyphShow { loads: show.loads, interactions: show.interactions }, &colors, s)
|
||||
}
|
||||
|
||||
/// Draw the model's datum planes and axes around `bounds` into `s`; returns the box around them.
|
||||
pub fn datums(s: &mut Scene, model: &fieldcraft_model::Model, bounds: &Aabb3, t: &Tokens) -> Aabb3 {
|
||||
fieldcraft_render::glyphs::datums(model, bounds, &t.glyph_colors(), s)
|
||||
}
|
||||
|
||||
/// The scene for `display` drawn in `style`.
|
||||
pub fn build(display: &DisplayMesh, style: Style, show: Show, t: &Tokens) -> Scene {
|
||||
let mut s = Scene { background: Some((rgb(t.viewport_top), rgb(t.viewport_bottom))), ..Default::default() };
|
||||
|
||||
@@ -82,6 +82,8 @@ pub struct Tokens {
|
||||
pub glyph_interaction: Color32,
|
||||
/// Temperatures, heat fluxes, convection and heat sources.
|
||||
pub glyph_thermal: Color32,
|
||||
/// Datum planes and axes.
|
||||
pub glyph_datum: Color32,
|
||||
// ---- selection ----
|
||||
/// What is selected in the viewport, and what a click would pick under the pointer.
|
||||
pub pick_selected: Color32,
|
||||
@@ -159,6 +161,7 @@ impl Tokens {
|
||||
glyph_load: Color32::from_rgb(0xd0, 0x24, 0x24),
|
||||
glyph_interaction: Color32::from_rgb(0x9a, 0x30, 0xc0),
|
||||
glyph_thermal: Color32::from_rgb(0xe8, 0x4c, 0x00),
|
||||
glyph_datum: Color32::from_rgb(0x1e, 0x8c, 0x6e),
|
||||
pick_selected: Color32::from_rgb(0xd6, 0x00, 0x7f),
|
||||
pick_hover: Color32::from_rgb(0xf0, 0x7c, 0xc0),
|
||||
}
|
||||
@@ -221,6 +224,7 @@ impl Tokens {
|
||||
t.glyph_load = Color32::from_rgb(0xff, 0x5a, 0x4c);
|
||||
t.glyph_interaction = Color32::from_rgb(0xd2, 0x82, 0xff);
|
||||
t.glyph_thermal = Color32::from_rgb(0xff, 0x8c, 0x00);
|
||||
t.glyph_datum = Color32::from_rgb(0x5a, 0xd8, 0xaa);
|
||||
t.pick_selected = Color32::from_rgb(0xff, 0x3f, 0xb4);
|
||||
t.pick_hover = Color32::from_rgb(0xff, 0xa6, 0xdc);
|
||||
t
|
||||
@@ -239,6 +243,7 @@ impl Tokens {
|
||||
interaction: rgb(self.glyph_interaction),
|
||||
thermal: rgb(self.glyph_thermal),
|
||||
label: rgb(self.overlay_text),
|
||||
datum: rgb(self.glyph_datum),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user