feat: Point coordinate regulators #118

Merged
Vectornaut merged 9 commits from glen/dyna3:pointCoordRegulators into main 2025-10-13 22:52:03 +00:00
5 changed files with 117 additions and 5 deletions
Showing only changes of commit ecbbe2068c - Show all commits

21
app-proto/Cargo.lock generated
View file

@ -255,6 +255,7 @@ dependencies = [
"charming",
"console_error_panic_hook",
"dyna3",
"enum-iterator",
"itertools",
"js-sys",
"lazy_static",
@ -271,6 +272,26 @@ version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "enum-iterator"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4549325971814bda7a44061bf3fe7e487d447cba01e4220a4b454d630d7a016"
dependencies = [
"enum-iterator-derive",
]
[[package]]
name = "enum-iterator-derive"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "685adfa4d6f3d765a26bc5dbc936577de9abf756c1feeb3089b01dd395034842"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "equivalent"
version = "1.0.1"

View file

@ -10,6 +10,7 @@ default = ["console_error_panic_hook"]
dev = []
[dependencies]
enum-iterator = "2.3.0"
itertools = "0.13.0"
js-sys = "0.3.70"
lazy_static = "1.5.0"

View file

@ -1,3 +1,4 @@
use enum_iterator::{all, Sequence};
use nalgebra::{DMatrix, DVector, DVectorView};
use std::{
cell::Cell,
@ -26,6 +27,7 @@ use crate::{
ConfigSubspace,
ConstraintProblem,
DescentHistory,
MatrixEntry,
Realization,
},
specified::SpecifiedValue,
@ -269,6 +271,7 @@ pub struct Point {
impl Point {
const WEIGHT_COMPONENT: usize = 3;
const NORM_COMPONENT: usize = 4;
pub fn new(
id: String,
@ -302,6 +305,15 @@ impl Element for Point {
point(0.0, 0.0, 0.0),
)
}
fn default_regulators(self: Rc<Self>) -> Vec<Rc<dyn Regulator>> {
all::<Axis>()
.map(|axis| {
Rc::new(PointCoordinateRegulator::new(self.clone(), axis))
as Rc::<dyn Regulator>
})
.collect()
}
fn id(&self) -> &String {
&self.id
@ -446,14 +458,14 @@ impl ProblemPoser for InversiveDistanceRegulator {
}
pub struct HalfCurvatureRegulator {
pub subject: Rc<dyn Element>,
pub subject: Rc<Sphere>,
pub measurement: ReadSignal<f64>,
pub set_point: Signal<SpecifiedValue>,
serial: u64,
}
impl HalfCurvatureRegulator {
pub fn new(subject: Rc<dyn Element>) -> Self {
pub fn new(subject: Rc<Sphere>) -> Self {
let measurement = subject.representation().map(
|rep| rep[Sphere::CURVATURE_COMPONENT]
);
@ -498,6 +510,69 @@ impl ProblemPoser for HalfCurvatureRegulator {
}
}
#[derive(Clone, Copy, Sequence)]
pub enum Axis {X = 0, Y = 1, Z = 2}
impl Axis {
pub const N_AXIS: usize = (Axis::Z as usize) + 1;
pub const NAME: [&str; Axis::N_AXIS] = ["X", "Y", "Z"];
}
pub struct PointCoordinateRegulator {
pub subject: Rc<Point>,
pub axis: Axis,
pub measurement: ReadSignal<f64>,
pub set_point: Signal<SpecifiedValue>,
serial: u64
}
impl PointCoordinateRegulator {
pub fn new(subject: Rc<Point>, axis: Axis) -> Self {
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() }
}
}
impl Serial for PointCoordinateRegulator {
fn serial(&self) -> u64 { self.serial }
}
impl Regulator for PointCoordinateRegulator {
fn subjects(&self) -> Vec<Rc<dyn Element>> { vec![self.subject.clone()] }
fn measurement(&self) -> ReadSignal<f64> { self.measurement }
fn set_point(&self) -> Signal<SpecifiedValue> { self.set_point }
}
impl ProblemPoser for PointCoordinateRegulator {
fn pose(&self, problem: &mut ConstraintProblem) {
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.");
problem.frozen.push(self.axis as usize, col, val);
// Check if all three coordinates have been frozen, and if so,
// freeze the coradius as well
let mut coords = [0.0; Axis::N_AXIS];
let mut nset: usize = 0;
for &MatrixEntry {index, value} in &(problem.frozen) {
if index.1 == col && index.0 < Axis::N_AXIS {
nset += 1;
coords[index.0] = value
}
}
if nset == Axis::N_AXIS {
let [x, y, z] = coords;
problem.frozen.push(
Point::NORM_COMPONENT, col, point(x,y,z)[Point::NORM_COMPONENT]);
}
}
});
}
}
Vectornaut marked this conversation as resolved

Flagging the inconsistent bracket formatting for later. Right now, this would be formatted as { index, value } elsewhere, but during review we discussed potentially changing this convention in the future.

Flagging the inconsistent bracket formatting for later. Right now, this would be formatted as `{ index, value }` elsewhere, but during review we discussed potentially changing this convention in the future.

It might shock you to know that I don't actually particularly care whether the braces-on-one-line spacing is uniform. If we both agree not to change them unless we touch a line, we could each just write this one the way we're comfortable writing. It's not like either way is particularly hard to read... Or we could decide to be uniform. It's all cool.

It might shock you to know that I don't actually particularly care whether the braces-on-one-line spacing is uniform. If we both agree not to change them unless we touch a line, we could each just write this one the way we're comfortable writing. It's not like either way is particularly hard to read... Or we could decide to be uniform. It's all cool.
// the velocity is expressed in uniform coordinates
pub struct ElementMotion<'a> {
pub element: Rc<dyn Element>,

View file

@ -6,9 +6,11 @@ use web_sys::{KeyboardEvent, MouseEvent, wasm_bindgen::JsCast};
use crate::{
AppState,
assembly::{
Axis,
Element,
HalfCurvatureRegulator,
InversiveDistanceRegulator,
PointCoordinateRegulator,
Regulator,
},
specified::SpecifiedValue
@ -119,6 +121,19 @@ impl OutlineItem for HalfCurvatureRegulator {
}
}
impl OutlineItem for PointCoordinateRegulator {
fn outline_item(self: Rc<Self>, _element: &Rc<dyn Element>) -> View {
view! {
li(class = "regulator") {
div(class = "regulator-label") { (Axis::NAME[self.axis as usize]) }
div(class = "regulator-type") { "Coordinate" }
RegulatorInput(regulator = self)
div(class = "status")
}
}
}
}
// a list item that shows an element in an outline view of an assembly
#[component(inline_props)]
fn ElementOutlineItem(element: Rc<dyn Element>) -> View {

View file

@ -46,14 +46,14 @@ pub fn project_sphere_to_normalized(rep: &mut DVector<f64>) {
// normalize a point's representation vector by scaling
pub fn project_point_to_normalized(rep: &mut DVector<f64>) {
rep.scale_mut(0.5 / rep[3]);
rep.scale_mut(0.5 / rep[3]); //FIXME: This 3 should be Point::WEIGHT_COMPONENT
}
// --- partial matrices ---
pub struct MatrixEntry {
index: (usize, usize),
value: f64,
pub index: (usize, usize),
pub value: f64,
}
pub struct PartialMatrix(Vec<MatrixEntry>);