forked from StudioInfinity/dyna3
Generalize constraints to observables (#48)
Unifies the interface elements for measuring and constraining real-valued observables, as proposed in issue #47. The resulting combination is called a "Regulator," at least in the code. They are presented as text inputs in the table view. When a Regulatore is in measurement mode (has no "set point"), the text field displays its value. Entering a desired value into the text field creates a set point, and then the Regulator acts to (attempt to) constrain the value. Setting the desired value to the empty string switches the observable back to measurement mode. If you enter a desired value that can't be parsed as a floating point number, the regulator input is flagged as invalid and it has no effect on the state of the regulator. The set point can in this case be restored to its previous value (or to no set point if that was its prior state) by pressing the "Esc" key. Co-authored-by: Aaron Fenyes <aaron.fenyes@fareycircles.ooo> Co-authored-by: glen <glen@studioinfinity.org> Reviewed-on: glen/dyna3#48 Co-authored-by: Vectornaut <vectornaut@nobody@nowhere.net> Co-committed-by: Vectornaut <vectornaut@nobody@nowhere.net>
This commit is contained in:
parent
46324fecc6
commit
da28bc99d2
7 changed files with 249 additions and 126 deletions
|
@ -5,11 +5,14 @@ use std::{collections::BTreeSet, sync::atomic::{AtomicU64, Ordering}};
|
|||
use sycamore::prelude::*;
|
||||
use web_sys::{console, wasm_bindgen::JsValue}; /* DEBUG */
|
||||
|
||||
use crate::engine::{realize_gram, local_unif_to_std, ConfigSubspace, PartialMatrix};
|
||||
use crate::{
|
||||
engine::{Q, local_unif_to_std, realize_gram, ConfigSubspace, PartialMatrix},
|
||||
specified::SpecifiedValue
|
||||
};
|
||||
|
||||
// the types of the keys we use to access an assembly's elements and constraints
|
||||
// the types of the keys we use to access an assembly's elements and regulators
|
||||
pub type ElementKey = usize;
|
||||
pub type ConstraintKey = usize;
|
||||
pub type RegulatorKey = usize;
|
||||
|
||||
pub type ElementColor = [f32; 3];
|
||||
|
||||
|
@ -26,8 +29,11 @@ pub struct Element {
|
|||
pub label: String,
|
||||
pub color: ElementColor,
|
||||
pub representation: Signal<DVector<f64>>,
|
||||
pub constraints: Signal<BTreeSet<ConstraintKey>>,
|
||||
|
||||
|
||||
// All regulators with this element as a subject. The assembly owning
|
||||
// this element is responsible for keeping this set up to date.
|
||||
pub regulators: Signal<BTreeSet<RegulatorKey>>,
|
||||
|
||||
// a serial number, assigned by `Element::new`, that uniquely identifies
|
||||
// each element
|
||||
pub serial: u64,
|
||||
|
@ -61,7 +67,7 @@ impl Element {
|
|||
label: label,
|
||||
color: color,
|
||||
representation: create_signal(representation),
|
||||
constraints: create_signal(BTreeSet::default()),
|
||||
regulators: create_signal(BTreeSet::default()),
|
||||
serial: serial,
|
||||
column_index: None
|
||||
}
|
||||
|
@ -111,13 +117,11 @@ impl Element {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Constraint {
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Regulator {
|
||||
pub subjects: (ElementKey, ElementKey),
|
||||
pub lorentz_prod: Signal<f64>,
|
||||
pub lorentz_prod_text: Signal<String>,
|
||||
pub lorentz_prod_valid: Signal<bool>,
|
||||
pub active: Signal<bool>
|
||||
pub measurement: ReadSignal<f64>,
|
||||
pub set_point: Signal<SpecifiedValue>
|
||||
}
|
||||
|
||||
// the velocity is expressed in uniform coordinates
|
||||
|
@ -131,9 +135,9 @@ type AssemblyMotion<'a> = Vec<ElementMotion<'a>>;
|
|||
// a complete, view-independent description of an assembly
|
||||
#[derive(Clone)]
|
||||
pub struct Assembly {
|
||||
// elements and constraints
|
||||
// elements and regulators
|
||||
pub elements: Signal<Slab<Element>>,
|
||||
pub constraints: Signal<Slab<Constraint>>,
|
||||
pub regulators: Signal<Slab<Regulator>>,
|
||||
|
||||
// solution variety tangent space. the basis vectors are stored in
|
||||
// configuration matrix format, ordered according to the elements' column
|
||||
|
@ -155,13 +159,13 @@ impl Assembly {
|
|||
pub fn new() -> Assembly {
|
||||
Assembly {
|
||||
elements: create_signal(Slab::new()),
|
||||
constraints: create_signal(Slab::new()),
|
||||
regulators: create_signal(Slab::new()),
|
||||
tangent: create_signal(ConfigSubspace::zero(0)),
|
||||
elements_by_id: create_signal(FxHashMap::default())
|
||||
}
|
||||
}
|
||||
|
||||
// --- inserting elements and constraints ---
|
||||
// --- inserting elements and regulators ---
|
||||
|
||||
// insert an element into the assembly without checking whether we already
|
||||
// have an element with the same identifier. any element that does have the
|
||||
|
@ -204,14 +208,61 @@ impl Assembly {
|
|||
);
|
||||
}
|
||||
|
||||
pub fn insert_constraint(&self, constraint: Constraint) {
|
||||
let subjects = constraint.subjects;
|
||||
let key = self.constraints.update(|csts| csts.insert(constraint));
|
||||
let subject_constraints = self.elements.with(
|
||||
|elts| (elts[subjects.0].constraints, elts[subjects.1].constraints)
|
||||
fn insert_regulator(&self, regulator: Regulator) {
|
||||
let subjects = regulator.subjects;
|
||||
let key = self.regulators.update(|regs| regs.insert(regulator));
|
||||
let subject_regulators = self.elements.with(
|
||||
|elts| (elts[subjects.0].regulators, elts[subjects.1].regulators)
|
||||
);
|
||||
subject_constraints.0.update(|csts| csts.insert(key));
|
||||
subject_constraints.1.update(|csts| csts.insert(key));
|
||||
subject_regulators.0.update(|regs| regs.insert(key));
|
||||
subject_regulators.1.update(|regs| regs.insert(key));
|
||||
}
|
||||
|
||||
pub fn insert_new_regulator(self, subjects: (ElementKey, ElementKey)) {
|
||||
// create and insert a new regulator
|
||||
let measurement = self.elements.map(
|
||||
move |elts| {
|
||||
let reps = (
|
||||
elts[subjects.0].representation.get_clone(),
|
||||
elts[subjects.1].representation.get_clone()
|
||||
);
|
||||
reps.0.dot(&(&*Q * reps.1))
|
||||
}
|
||||
);
|
||||
let set_point = create_signal(SpecifiedValue::from_empty_spec());
|
||||
self.insert_regulator(Regulator {
|
||||
subjects: subjects,
|
||||
measurement: measurement,
|
||||
set_point: set_point
|
||||
});
|
||||
|
||||
/* DEBUG */
|
||||
// print an updated list of regulators
|
||||
console::log_1(&JsValue::from("Regulators:"));
|
||||
self.regulators.with(|regs| {
|
||||
for (_, reg) in regs.into_iter() {
|
||||
console::log_5(
|
||||
&JsValue::from(" "),
|
||||
&JsValue::from(reg.subjects.0),
|
||||
&JsValue::from(reg.subjects.1),
|
||||
&JsValue::from(":"),
|
||||
®.set_point.with_untracked(
|
||||
|set_pt| JsValue::from(set_pt.spec.as_str())
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// update the realization when the regulator becomes a constraint, or is
|
||||
// edited while acting as a constraint
|
||||
create_effect(move || {
|
||||
console::log_1(&JsValue::from(
|
||||
format!("Updated constraint with subjects ({}, {})", subjects.0, subjects.1)
|
||||
));
|
||||
if set_point.with(|set_pt| set_pt.is_present()) {
|
||||
self.realize();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// --- realization ---
|
||||
|
@ -228,14 +279,16 @@ impl Assembly {
|
|||
let (gram, guess) = self.elements.with_untracked(|elts| {
|
||||
// set up the off-diagonal part of the Gram matrix
|
||||
let mut gram_to_be = PartialMatrix::new();
|
||||
self.constraints.with_untracked(|csts| {
|
||||
for (_, cst) in csts {
|
||||
if cst.active.get_untracked() && cst.lorentz_prod_valid.get_untracked() {
|
||||
let subjects = cst.subjects;
|
||||
let row = elts[subjects.0].column_index.unwrap();
|
||||
let col = elts[subjects.1].column_index.unwrap();
|
||||
gram_to_be.push_sym(row, col, cst.lorentz_prod.get_untracked());
|
||||
}
|
||||
self.regulators.with_untracked(|regs| {
|
||||
for (_, reg) in regs {
|
||||
reg.set_point.with_untracked(|set_pt| {
|
||||
if let Some(val) = set_pt.value {
|
||||
let subjects = reg.subjects;
|
||||
let row = elts[subjects.0].column_index.unwrap();
|
||||
let col = elts[subjects.1].column_index.unwrap();
|
||||
gram_to_be.push_sym(row, col, val);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue