diff --git a/app-proto/src/add_remove.rs b/app-proto/src/add_remove.rs index 4972d3c..deac2bb 100644 --- a/app-proto/src/add_remove.rs +++ b/app-proto/src/add_remove.rs @@ -4,7 +4,7 @@ use web_sys::{console, wasm_bindgen::JsValue}; use crate::{ engine, AppState, - assembly::{Assembly, Element} + assembly::{Assembly, Element, ProductRegulator} }; /* DEBUG */ @@ -189,7 +189,9 @@ pub fn AddRemove() -> View { .try_into() .unwrap() ); - state.assembly.insert_new_product_regulator(subjects); + state.assembly.insert_regulator( + ProductRegulator::new(subjects, &state.assembly) + ); state.selection.update(|sel| sel.clear()); } ) { "🔗" } diff --git a/app-proto/src/assembly.rs b/app-proto/src/assembly.rs index 055b9a2..f14f0c4 100644 --- a/app-proto/src/assembly.rs +++ b/app-proto/src/assembly.rs @@ -58,6 +58,8 @@ pub struct Element { } impl Element { + const CURVATURE_COMPONENT: usize = 3; + pub fn new( id: String, label: String, @@ -145,6 +147,8 @@ pub trait Regulator: ProblemPoser + OutlineItem { fn subjects(&self) -> Vec; fn measurement(&self) -> ReadSignal; fn set_point(&self) -> Signal; + + fn activate(&self, _assembly: &Assembly) {} } pub struct ProductRegulator { @@ -153,6 +157,29 @@ pub struct ProductRegulator { pub set_point: Signal } +impl ProductRegulator { + pub fn new(subjects: [ElementKey; 2], assembly: &Assembly) -> ProductRegulator { + let measurement = assembly.elements.map( + move |elts| { + let representations = subjects.map(|subj| elts[subj].representation); + representations[0].with(|rep_0| + representations[1].with(|rep_1| + rep_0.dot(&(&*Q * rep_1)) + ) + ) + } + ); + + let set_point = create_signal(SpecifiedValue::from_empty_spec()); + + ProductRegulator { + subjects: subjects, + measurement: measurement, + set_point: set_point + } + } +} + impl Regulator for ProductRegulator { fn subjects(&self) -> Vec { self.subjects.into() @@ -190,6 +217,24 @@ pub struct HalfCurvatureRegulator { pub set_point: Signal } +impl HalfCurvatureRegulator { + pub fn new(subject: ElementKey, assembly: &Assembly) -> HalfCurvatureRegulator { + let measurement = assembly.elements.map( + move |elts| elts[subject].representation.with( + |rep| rep[Element::CURVATURE_COMPONENT] + ) + ); + + let set_point = create_signal(SpecifiedValue::from_empty_spec()); + + HalfCurvatureRegulator { + subject: subject, + measurement: measurement, + set_point: set_point + } + } +} + impl Regulator for HalfCurvatureRegulator { fn subjects(&self) -> Vec { vec![self.subject] @@ -202,6 +247,17 @@ impl Regulator for HalfCurvatureRegulator { fn set_point(&self) -> Signal { self.set_point } + + fn activate(&self, assembly: &Assembly) { + if let Some(half_curv) = self.set_point.with_untracked(|set_pt| set_pt.value) { + let representation = assembly.elements.with_untracked( + |elts| elts[self.subject].representation + ); + representation.update( + |rep| change_half_curvature(rep, half_curv) + ); + } + } } impl ProblemPoser for HalfCurvatureRegulator { @@ -209,8 +265,7 @@ impl ProblemPoser for HalfCurvatureRegulator { self.set_point.with_untracked(|set_pt| { if let Some(val) = set_pt.value { if let Some(col) = elts[self.subject].column_index { - const CURVATURE_COMPONENT: usize = 3; - problem.frozen.push(CURVATURE_COMPONENT, col, val); + problem.frozen.push(Element::CURVATURE_COMPONENT, col, val); } else { panic!("Tried to write problem data from a regulator with an unindexed subject"); } @@ -272,7 +327,7 @@ impl Assembly { self.elements_by_id.update(|elts_by_id| elts_by_id.insert(id, key)); // regulate the sphere's curvature - self.insert_new_half_curvature_regulator(key); + self.insert_regulator(HalfCurvatureRegulator::new(key, &self)); key } @@ -310,11 +365,15 @@ impl Assembly { ); } - fn insert_regulator(&self, regulator: Rc) { - let subjects = regulator.subjects(); + pub fn insert_regulator(&self, regulator: T) { + // add the regulator to the assembly's regulator list + let regulator_rc = Rc::new(regulator); let key = self.regulators.update( - |regs| regs.insert(regulator) + |regs| regs.insert(regulator_rc.clone()) ); + + // add the regulator to each subject's regulator list + let subjects = regulator_rc.subjects(); let subject_regulators: Vec<_> = self.elements.with_untracked( |elts| subjects.into_iter().map( |subj| elts[subj].regulators @@ -324,6 +383,19 @@ impl Assembly { regulators.update(|regs| regs.insert(key)); } + // update the realization when the regulator becomes a constraint, or is + // edited while acting as a constraint + let self_for_effect = self.clone(); + create_effect(move || { + console::log_1(&JsValue::from( + format!("Updated regulator with subjects {:?}", regulator_rc.subjects()) + )); + if regulator_rc.set_point().with(|set_pt| set_pt.is_present()) { + regulator_rc.activate(&self_for_effect); + self_for_effect.realize(); + } + }); + /* DEBUG */ // print an updated list of regulators console::log_1(&JsValue::from("Regulators:")); @@ -347,69 +419,6 @@ impl Assembly { }); } - pub fn insert_new_product_regulator(&self, subjects: [ElementKey; 2]) { - // create and insert a new product regulator - let measurement = self.elements.map( - move |elts| { - let representations = subjects.map(|subj| elts[subj].representation); - representations[0].with(|rep_0| - representations[1].with(|rep_1| - rep_0.dot(&(&*Q * rep_1)) - ) - ) - } - ); - let set_point = create_signal(SpecifiedValue::from_empty_spec()); - self.insert_regulator(Rc::new(ProductRegulator { - subjects: subjects, - measurement: measurement, - set_point: set_point - })); - - // update the realization when the regulator becomes a constraint, or is - // edited while acting as a constraint - let self_for_effect = self.clone(); - create_effect(move || { - console::log_1(&JsValue::from( - format!("Updated regulator with subjects {:?}", subjects) - )); - if set_point.with(|set_pt| set_pt.is_present()) { - self_for_effect.realize(); - } - }); - } - - pub fn insert_new_half_curvature_regulator(&self, subject: ElementKey) { - // create and insert a new half-curvature regulator - let measurement = self.elements.map( - move |elts| elts[subject].representation.with(|rep| rep[3]) - ); - let set_point = create_signal(SpecifiedValue::from_empty_spec()); - self.insert_regulator(Rc::new(HalfCurvatureRegulator { - subject: subject, - measurement: measurement, - set_point: set_point - })); - - // update the realization when the regulator becomes a constraint, or is - // edited while acting as a constraint - let self_for_effect = self.clone(); - create_effect(move || { - console::log_1(&JsValue::from( - format!("Updated regulator with subjects [{}]", subject) - )); - if let Some(half_curv) = set_point.with(|set_pt| set_pt.value) { - let representation = self_for_effect.elements.with_untracked( - |elts| elts[subject].representation - ); - representation.update( - |rep| change_half_curvature(rep, half_curv) - ); - self_for_effect.realize(); - } - }); - } - // --- realization --- pub fn realize(&self) {