diff --git a/crates/engine/src/view.rs b/crates/engine/src/view.rs index c5b62a5..50a2442 100644 --- a/crates/engine/src/view.rs +++ b/crates/engine/src/view.rs @@ -32,6 +32,8 @@ pub struct Palette { pub mesh_edge: Rgb, pub geometry: Rgb, pub geometry_edge: Rgb, + /// The bodies of a design with several, in turn. + pub bodies: [Rgb; 8], /// Faces of nodes without a value in a contour plot. pub no_result: Rgb, /// The contour colour scale, low to high. @@ -52,6 +54,16 @@ impl Palette { mesh_edge: Rgb(0x1e, 0x23, 0x2a), geometry: Rgb(0xb4, 0xba, 0xc4), geometry_edge: Rgb(0x2a, 0x30, 0x3a), + bodies: [ + Rgb(0x8f, 0xb4, 0xd9), + Rgb(0xe0, 0xa4, 0x6c), + Rgb(0x8c, 0xc4, 0x8a), + Rgb(0xd6, 0x8c, 0x96), + Rgb(0xb0, 0x9c, 0xd8), + Rgb(0xd8, 0xc8, 0x70), + Rgb(0x7c, 0xc4, 0xc0), + Rgb(0xc0, 0xa0, 0x84), + ], no_result: Rgb(0x9a, 0xa0, 0xaa), contour: [Rgb(0x2b, 0x4f, 0xd8), Rgb(0x2f, 0xb8, 0xe0), Rgb(0x3c, 0xc8, 0x64), Rgb(0xf0, 0xd2, 0x3c), Rgb(0xe0, 0x40, 0x2e)], glyphs: GlyphColors { @@ -125,7 +137,7 @@ fn model_scene(d: &DisplayMesh, p: &Palette) -> Scene { s.tris = d.tris.iter().map(|t| SceneTri { p: t.p, normal: t.normal, color: p.element(t.kind) }).collect(); let faces_drawn = d.tris.is_empty(); if faces_drawn { - s.tris.extend(d.surface_tris.iter().map(|t| SceneTri { p: t.p, normal: t.normal, color: p.geometry })); + s.tris.extend(d.surface_tris.iter().map(|t| SceneTri { p: t.p, normal: t.normal, color: d.body_color(t, p.geometry, &p.bodies) })); } s.lines = d.edges.iter().map(|e| SceneLine { a: e.p[0], b: e.p[1], color: p.mesh_edge, width: EDGE_WIDTH }).collect(); let edge = if faces_drawn { p.mesh_edge } else { p.geometry_edge }; diff --git a/crates/render/src/display.rs b/crates/render/src/display.rs index ac0fad4..c71130f 100644 --- a/crates/render/src/display.rs +++ b/crates/render/src/display.rs @@ -55,6 +55,8 @@ pub struct DisplayNode { pub struct SurfaceTri { pub p: [Vec3; 3], pub normal: Vec3, + /// Which surface (body) it belongs to: the order [`DisplayMesh::add_surface`] got them in. + pub body: u32, } /// Display data for a model and its geometry. @@ -72,6 +74,8 @@ pub struct DisplayMesh { pub surface_tris: Vec, /// Geometry edges: where two faces meet, and open boundaries. pub surface_edges: Vec<[Vec3; 2]>, + /// Geometry surfaces (bodies) added. + pub bodies: u32, pub bounds: Aabb3, } @@ -225,7 +229,7 @@ impl DisplayMesh { for p in [a, b, c] { self.bounds.add(p); } - self.surface_tris.push(SurfaceTri { p: [a, b, c], normal }); + self.surface_tris.push(SurfaceTri { p: [a, b, c], normal, body: self.bodies }); let face = tri_face.get(t).copied().unwrap_or(u32::MAX); let [v0, v1, v2] = [vertex(i0), vertex(i1), vertex(i2)]; for (u, v) in [(v0, v1), (v1, v2), (v2, v0)] { @@ -241,6 +245,17 @@ impl DisplayMesh { self.surface_edges.push([a, b]); } } + self.bodies = self.bodies.saturating_add(1); + } + + /// The colour of a geometry triangle: `single` when there is one body, else body `k`'s + /// colour from `palette` (cycling), so the bodies of a design, such as the cells of a + /// partitioned part, tell apart. + pub fn body_color(&self, tri: &SurfaceTri, single: C, palette: &[C]) -> C { + if self.bodies <= 1 || palette.is_empty() { + return single; + } + palette.get(tri.body as usize % palette.len()).copied().unwrap_or(single) } /// Where node `label` is drawn, if it is (nodes are kept in label order). @@ -401,6 +416,13 @@ mod tests { welded.add_surface(&soup, &[[0, 1, 2], [3, 4, 5]], &[0, 0]); assert_eq!(welded.surface_edges.len(), 4); let mut hostile = DisplayMesh::default(); + let mut two = DisplayMesh::default(); + two.add_surface(&p, &[[0, 1, 2]], &[0]); + two.add_surface(&p, &[[0, 2, 3]], &[0]); + assert_eq!(two.bodies, 2); + let colors: Vec = two.surface_tris.iter().map(|t| two.body_color(t, 0u8, &[7, 8])).collect(); + assert_eq!(colors, vec![7, 8]); + assert_eq!(one_face.body_color(&one_face.surface_tris[0], 0u8, &[7, 8]), 0); hostile.add_surface(&[[f64::NAN, 0., 0.], [1., 0., 0.], [0., 1., 0.]], &[[0, 1, 2], [u32::MAX, 0, 1]], &[]); assert!(hostile.surface_tris.is_empty() && hostile.surface_edges.is_empty()); } diff --git a/crates/ui-egui/src/scene.rs b/crates/ui-egui/src/scene.rs index edd5749..d749944 100644 --- a/crates/ui-egui/src/scene.rs +++ b/crates/ui-egui/src/scene.rs @@ -79,7 +79,11 @@ pub fn build(display: &DisplayMesh, style: Style, show: Show, t: &Tokens) -> Sce s.tris = display.tris.iter().map(|d| SceneTri { p: d.p, normal: d.normal, color: rgb(t.element(d.kind)) }).collect(); } if !mesh_faces && show.geometry { - s.tris.extend(display.surface_tris.iter().map(|d| SceneTri { p: d.p, normal: d.normal, color: rgb(t.geometry) })); + s.tris.extend(display.surface_tris.iter().map(|d| SceneTri { + p: d.p, + normal: d.normal, + color: rgb(display.body_color(d, t.geometry, &t.bodies)), + })); } } if style != Style::Shaded && show.mesh { diff --git a/crates/ui-egui/src/theme.rs b/crates/ui-egui/src/theme.rs index bf3ec16..20240d2 100644 --- a/crates/ui-egui/src/theme.rs +++ b/crates/ui-egui/src/theme.rs @@ -66,6 +66,8 @@ pub struct Tokens { pub geometry: Color32, /// Their face boundaries. pub geometry_edge: Color32, + /// The bodies of a design with several (the cells of a partitioned part), in turn. + pub bodies: [Color32; 8], // ---- results ---- /// The contour colour scale, low to high (the same in both themes). pub contour: [Color32; 5], @@ -137,6 +139,16 @@ impl Tokens { node: Color32::from_rgb(0xb4, 0x3c, 0x8c), geometry: Color32::from_rgb(176, 186, 198), geometry_edge: Color32::from_rgb(40, 44, 52), + bodies: [ + Color32::from_rgb(0x8f, 0xb4, 0xd9), + Color32::from_rgb(0xe0, 0xa4, 0x6c), + Color32::from_rgb(0x8c, 0xc4, 0x8a), + Color32::from_rgb(0xd6, 0x8c, 0x96), + Color32::from_rgb(0xb0, 0x9c, 0xd8), + Color32::from_rgb(0xd8, 0xc8, 0x70), + Color32::from_rgb(0x7c, 0xc4, 0xc0), + Color32::from_rgb(0xc0, 0xa0, 0x84), + ], contour: CONTOUR, no_result: Color32::from_rgb(0x9a, 0xa0, 0xaa), glyph_constraint: Color32::from_rgb(0x00, 0x8a, 0xa8), @@ -188,6 +200,16 @@ impl Tokens { t.node = Color32::from_rgb(0xf2, 0xe6, 0x6e); t.geometry = Color32::from_rgb(152, 156, 162); t.geometry_edge = Color32::from_rgb(16, 16, 18); + t.bodies = [ + Color32::from_rgb(0x6c, 0x92, 0xb8), + Color32::from_rgb(0xbc, 0x84, 0x50), + Color32::from_rgb(0x6c, 0xa2, 0x6a), + Color32::from_rgb(0xb4, 0x6e, 0x78), + Color32::from_rgb(0x90, 0x7e, 0xb6), + Color32::from_rgb(0xb6, 0xa6, 0x54), + Color32::from_rgb(0x5c, 0xa2, 0x9e), + Color32::from_rgb(0xa0, 0x82, 0x66), + ]; t.no_result = Color32::from_rgb(0x70, 0x76, 0x80); t.glyph_constraint = Color32::from_rgb(0x3c, 0xdc, 0xf0); t.glyph_load = Color32::from_rgb(0xff, 0x5a, 0x4c);