From 27edbfb01089a1b3407dcc4094a66ba10567919a Mon Sep 17 00:00:00 2001 From: Aaron Fenyes Date: Tue, 7 Oct 2025 15:36:12 -0700 Subject: [PATCH 1/2] Streamline axis naming This makes it simpler, from the programmer's perspective, to get the name of an axis as a string slice and to format an axis name into a string. To me, the matching method `Axis::name` seems more direct than the explicit lookup table that it replaces, and I'm hoping that it will be about as easy for the compiler to inline, or even easier. Implementing `Display` enables us to hand an `Axis` to a string formatter without any explicit conversion. It adds extra code in the short run, but I'd expect it to simplify our code in the long run by fitting into the conventions set by the Rust standard library. --- app-proto/src/assembly.rs | 14 +++++++++++--- app-proto/src/components/outline.rs | 3 +-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/app-proto/src/assembly.rs b/app-proto/src/assembly.rs index 8e4b96f..4da9422 100644 --- a/app-proto/src/assembly.rs +++ b/app-proto/src/assembly.rs @@ -127,7 +127,7 @@ pub trait Element: Serial + ProblemPoser + DisplayItem { } impl Debug for dyn Element { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { self.id().fmt(f) } } @@ -511,10 +511,18 @@ impl ProblemPoser for HalfCurvatureRegulator { } #[derive(Clone, Copy, Sequence)] -pub enum Axis {X = 0, Y = 1, Z = 2} +pub enum Axis { X = 0, Y = 1, Z = 2 } impl Axis { - pub const NAME: [&str; Axis::CARDINALITY] = ["X", "Y", "Z"]; + fn name(&self) -> &'static str { + match self { Axis::X => "X", Axis::Y => "Y", Axis::Z => "Z" } + } +} + +impl fmt::Display for Axis { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.name()) + } } pub struct PointCoordinateRegulator { diff --git a/app-proto/src/components/outline.rs b/app-proto/src/components/outline.rs index d9ab71d..547b73b 100644 --- a/app-proto/src/components/outline.rs +++ b/app-proto/src/components/outline.rs @@ -6,7 +6,6 @@ use web_sys::{KeyboardEvent, MouseEvent, wasm_bindgen::JsCast}; use crate::{ AppState, assembly::{ - Axis, Element, HalfCurvatureRegulator, InversiveDistanceRegulator, @@ -123,7 +122,7 @@ impl OutlineItem for HalfCurvatureRegulator { impl OutlineItem for PointCoordinateRegulator { fn outline_item(self: Rc, _element: &Rc) -> View { - let name = format!("{} coordinate", Axis::NAME[self.axis as usize]); + let name = format!("{} coordinate", self.axis); view! { li(class = "regulator") { div(class = "regulator-label") // for spacing From adc60ac5c160ceee11ee205352a1665b29fc6e94 Mon Sep 17 00:00:00 2001 From: Aaron Fenyes Date: Tue, 7 Oct 2025 16:19:14 -0700 Subject: [PATCH 2/2] Spruce up formatting and error messages Make the new code's formatting and error messages more consistent with the previous code. I don't necessarily have a strong preference for the previous conventions, but I do like stuff to be consistent. --- app-proto/src/assembly.rs | 63 +++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/app-proto/src/assembly.rs b/app-proto/src/assembly.rs index 4da9422..b1e5d7c 100644 --- a/app-proto/src/assembly.rs +++ b/app-proto/src/assembly.rs @@ -305,13 +305,14 @@ impl Element for Point { point(0.0, 0.0, 0.0), ) } - + fn default_regulators(self: Rc) -> Vec> { all::() - .map(|axis| { - Rc::new(PointCoordinateRegulator::new(self.clone(), axis)) - as Rc:: - }) + .map( + |axis| Rc::new( + PointCoordinateRegulator::new(self.clone(), axis) + ) as Rc:: + ) .collect() } @@ -538,19 +539,32 @@ impl PointCoordinateRegulator { let measurement = subject.representation().map( move |rep| rep[axis as usize] ); + let set_point = create_signal(SpecifiedValue::from_empty_spec()); - Self { subject, axis, measurement, set_point, serial: Self::next_serial() } + let serial = Self::next_serial(); + + Self { subject, axis, measurement, set_point, serial } } } impl Serial for PointCoordinateRegulator { - fn serial(&self) -> u64 { self.serial } + fn serial(&self) -> u64 { + self.serial + } } impl Regulator for PointCoordinateRegulator { - fn subjects(&self) -> Vec> { vec![self.subject.clone()] } - fn measurement(&self) -> ReadSignal { self.measurement } - fn set_point(&self) -> Signal { self.set_point } + fn subjects(&self) -> Vec> { + vec![self.subject.clone()] + } + + fn measurement(&self) -> ReadSignal { + self.measurement + } + + fn set_point(&self) -> Signal { + self.set_point + } } impl ProblemPoser for PointCoordinateRegulator { @@ -558,22 +572,25 @@ impl ProblemPoser for PointCoordinateRegulator { self.set_point.with_untracked(|set_pt| { if let Some(val) = set_pt.value { let col = self.subject.column_index().expect( - "Subject must be indexed before point-coordinate regulator poses."); + "Subject should be indexed before point coordinate regulator writes problem data" + ); problem.frozen.push(self.axis as usize, col, val); - // Check if all three spatial coordinates have been frozen, and if so, - // freeze the norm component as well - let mut coords = [0.0; Axis::CARDINALITY]; - let mut nset: usize = 0; - for &MatrixEntry {index, value} in &(problem.frozen) { - if index.1 == col && index.0 < Axis::CARDINALITY { - nset += 1; - coords[index.0] = value + + // if all three of the subject's spatial coordinates have been + // frozen, then freeze its norm component too + let mut coords_frozen = [0.0; Axis::CARDINALITY]; + let mut n_set: usize = 0; + for &MatrixEntry { index, value } in &(problem.frozen) { + let (row_frozen, col_frozen) = index; + if col_frozen == col && row_frozen < Axis::CARDINALITY { + n_set += 1; + coords_frozen[row_frozen] = value } } - if nset == Axis::CARDINALITY { - let [x, y, z] = coords; - problem.frozen.push( - Point::NORM_COMPONENT, col, point(x,y,z)[Point::NORM_COMPONENT]); + if n_set == Axis::CARDINALITY { + let [x, y, z] = coords_frozen; + let norm = point(x, y, z)[Point::NORM_COMPONENT]; + problem.frozen.push(Point::NORM_COMPONENT, col, norm); } } });