From 70978c640b412536fac48976f22775bee7178e66 Mon Sep 17 00:00:00 2001 From: Aaron Fenyes Date: Thu, 31 Oct 2024 01:23:22 -0700 Subject: [PATCH 01/10] Include vector representation in element diff key --- app-proto/src/outline.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/app-proto/src/outline.rs b/app-proto/src/outline.rs index aff3673..e1bc3ab 100644 --- a/app-proto/src/outline.rs +++ b/app-proto/src/outline.rs @@ -200,6 +200,7 @@ pub fn Outline() -> View { key.clone(), elt.id.clone(), elt.label.clone(), + elt.rep.into_iter().map(|u| u.to_bits()).collect::>(), elt.constraints.clone() ) ) From cc126fc5272516b6d4784784f250384d80ae3951 Mon Sep 17 00:00:00 2001 From: Aaron Fenyes Date: Thu, 31 Oct 2024 01:24:06 -0700 Subject: [PATCH 02/10] Correct typo in comment --- app-proto/src/add_remove.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app-proto/src/add_remove.rs b/app-proto/src/add_remove.rs index 31e11e6..5595b03 100644 --- a/app-proto/src/add_remove.rs +++ b/app-proto/src/add_remove.rs @@ -242,8 +242,8 @@ pub fn AddRemove() -> View { } }); - // update the realization when the constraint activated, or - // edited while active + // update the realization when the constraint is activated, + // or edited while active create_effect(move || { lorentz_prod.track(); console::log_2( From ce9b114dd60c105d6ad66340a93210d4fc80f65b Mon Sep 17 00:00:00 2001 From: Aaron Fenyes Date: Fri, 1 Nov 2024 04:25:03 -0700 Subject: [PATCH 03/10] Render constraint lists dynamically --- app-proto/src/add_remove.rs | 28 ++++++++++++++-------------- app-proto/src/assembly.rs | 13 +++++++------ app-proto/src/outline.rs | 12 +++++++----- 3 files changed, 28 insertions(+), 25 deletions(-) diff --git a/app-proto/src/add_remove.rs b/app-proto/src/add_remove.rs index 5595b03..fce4c37 100644 --- a/app-proto/src/add_remove.rs +++ b/app-proto/src/add_remove.rs @@ -12,7 +12,7 @@ fn load_gen_assemb(assembly: &Assembly) { label: String::from("Castor"), color: [1.00_f32, 0.25_f32, 0.00_f32], representation: engine::sphere(0.5, 0.5, 0.0, 1.0), - constraints: BTreeSet::default(), + constraints: create_signal(BTreeSet::default()), index: 0 } ); @@ -22,7 +22,7 @@ fn load_gen_assemb(assembly: &Assembly) { label: String::from("Pollux"), color: [0.00_f32, 0.25_f32, 1.00_f32], representation: engine::sphere(-0.5, -0.5, 0.0, 1.0), - constraints: BTreeSet::default(), + constraints: create_signal(BTreeSet::default()), index: 0 } ); @@ -32,7 +32,7 @@ fn load_gen_assemb(assembly: &Assembly) { label: String::from("Ursa major"), color: [0.25_f32, 0.00_f32, 1.00_f32], representation: engine::sphere(-0.5, 0.5, 0.0, 0.75), - constraints: BTreeSet::default(), + constraints: create_signal(BTreeSet::default()), index: 0 } ); @@ -42,7 +42,7 @@ fn load_gen_assemb(assembly: &Assembly) { label: String::from("Ursa minor"), color: [0.25_f32, 1.00_f32, 0.00_f32], representation: engine::sphere(0.5, -0.5, 0.0, 0.5), - constraints: BTreeSet::default(), + constraints: create_signal(BTreeSet::default()), index: 0 } ); @@ -52,7 +52,7 @@ fn load_gen_assemb(assembly: &Assembly) { label: String::from("Deimos"), color: [0.75_f32, 0.75_f32, 0.00_f32], representation: engine::sphere(0.0, 0.15, 1.0, 0.25), - constraints: BTreeSet::default(), + constraints: create_signal(BTreeSet::default()), index: 0 } ); @@ -62,7 +62,7 @@ fn load_gen_assemb(assembly: &Assembly) { label: String::from("Phobos"), color: [0.00_f32, 0.75_f32, 0.50_f32], representation: engine::sphere(0.0, -0.15, -1.0, 0.25), - constraints: BTreeSet::default(), + constraints: create_signal(BTreeSet::default()), index: 0 } ); @@ -77,7 +77,7 @@ fn load_low_curv_assemb(assembly: &Assembly) { label: "Central".to_string(), color: [0.75_f32, 0.75_f32, 0.75_f32], representation: engine::sphere(0.0, 0.0, 0.0, 1.0), - constraints: BTreeSet::default(), + constraints: create_signal(BTreeSet::default()), index: 0 } ); @@ -87,7 +87,7 @@ fn load_low_curv_assemb(assembly: &Assembly) { label: "Assembly plane".to_string(), color: [0.75_f32, 0.75_f32, 0.75_f32], representation: engine::sphere_with_offset(0.0, 0.0, 1.0, 0.0, 0.0), - constraints: BTreeSet::default(), + constraints: create_signal(BTreeSet::default()), index: 0 } ); @@ -97,7 +97,7 @@ fn load_low_curv_assemb(assembly: &Assembly) { label: "Side 1".to_string(), color: [1.00_f32, 0.00_f32, 0.25_f32], representation: engine::sphere_with_offset(1.0, 0.0, 0.0, 1.0, 0.0), - constraints: BTreeSet::default(), + constraints: create_signal(BTreeSet::default()), index: 0 } ); @@ -107,7 +107,7 @@ fn load_low_curv_assemb(assembly: &Assembly) { label: "Side 2".to_string(), color: [0.25_f32, 1.00_f32, 0.00_f32], representation: engine::sphere_with_offset(-0.5, a, 0.0, 1.0, 0.0), - constraints: BTreeSet::default(), + constraints: create_signal(BTreeSet::default()), index: 0 } ); @@ -117,7 +117,7 @@ fn load_low_curv_assemb(assembly: &Assembly) { label: "Side 3".to_string(), color: [0.00_f32, 0.25_f32, 1.00_f32], representation: engine::sphere_with_offset(-0.5, -a, 0.0, 1.0, 0.0), - constraints: BTreeSet::default(), + constraints: create_signal(BTreeSet::default()), index: 0 } ); @@ -127,7 +127,7 @@ fn load_low_curv_assemb(assembly: &Assembly) { label: "Corner 1".to_string(), color: [0.75_f32, 0.75_f32, 0.75_f32], representation: engine::sphere(-4.0/3.0, 0.0, 0.0, 1.0/3.0), - constraints: BTreeSet::default(), + constraints: create_signal(BTreeSet::default()), index: 0 } ); @@ -137,7 +137,7 @@ fn load_low_curv_assemb(assembly: &Assembly) { label: "Corner 2".to_string(), color: [0.75_f32, 0.75_f32, 0.75_f32], representation: engine::sphere(2.0/3.0, -4.0/3.0 * a, 0.0, 1.0/3.0), - constraints: BTreeSet::default(), + constraints: create_signal(BTreeSet::default()), index: 0 } ); @@ -147,7 +147,7 @@ fn load_low_curv_assemb(assembly: &Assembly) { label: String::from("Corner 3"), color: [0.75_f32, 0.75_f32, 0.75_f32], representation: engine::sphere(2.0/3.0, 4.0/3.0 * a, 0.0, 1.0/3.0), - constraints: BTreeSet::default(), + constraints: create_signal(BTreeSet::default()), index: 0 } ); diff --git a/app-proto/src/assembly.rs b/app-proto/src/assembly.rs index 0cdf61b..2763ae1 100644 --- a/app-proto/src/assembly.rs +++ b/app-proto/src/assembly.rs @@ -19,7 +19,7 @@ pub struct Element { pub label: String, pub color: ElementColor, pub representation: DVector, - pub constraints: BTreeSet, + pub constraints: Signal>, // the configuration matrix column index that was assigned to this element // last time the assembly was realized @@ -97,7 +97,7 @@ impl Assembly { label: format!("Sphere {}", id_num), color: [0.75_f32, 0.75_f32, 0.75_f32], representation: DVector::::from_column_slice(&[0.0, 0.0, 0.0, 0.5, -0.5]), - constraints: BTreeSet::default(), + constraints: create_signal(BTreeSet::default()), index: 0 } ); @@ -106,10 +106,11 @@ impl Assembly { pub fn insert_constraint(&self, constraint: Constraint) { let subjects = constraint.subjects; let key = self.constraints.update(|csts| csts.insert(constraint)); - self.elements.update(|elts| { - elts[subjects.0].constraints.insert(key); - elts[subjects.1].constraints.insert(key); - }); + let subject_constraints = self.elements.with( + |elts| (elts[subjects.0].constraints, elts[subjects.1].constraints) + ); + subject_constraints.0.update(|csts| csts.insert(key)); + subject_constraints.1.update(|csts| csts.insert(key)); } // --- realization --- diff --git a/app-proto/src/outline.rs b/app-proto/src/outline.rs index e1bc3ab..329fc58 100644 --- a/app-proto/src/outline.rs +++ b/app-proto/src/outline.rs @@ -76,7 +76,10 @@ fn ElementOutlineItem(key: ElementKey, element: assembly::Element) -> View { let u_coord = format!("{:.3}", u).replace("-", "\u{2212}"); View::from(div().children(u_coord)) }).collect::>(); - let constrained = element.constraints.len() > 0; + let constrained = element.constraints.map(|csts| csts.len() > 0); + let constraint_list = element.constraints.map( + |csts| csts.clone().into_iter().collect() + ); let details_node = create_node_ref(); view! { li { @@ -101,7 +104,7 @@ fn ElementOutlineItem(key: ElementKey, element: assembly::Element) -> View { } event.prevent_default(); }, - "ArrowRight" if constrained => { + "ArrowRight" if constrained.get() => { let _ = details_node .get() .unchecked_into::() @@ -150,7 +153,7 @@ fn ElementOutlineItem(key: ElementKey, element: assembly::Element) -> View { } ul(class="constraints") { Keyed( - list=element.constraints.into_iter().collect::>(), + list=constraint_list, view=move |cst_key| view! { ConstraintOutlineItem( constraint_key=cst_key, @@ -200,8 +203,7 @@ pub fn Outline() -> View { key.clone(), elt.id.clone(), elt.label.clone(), - elt.rep.into_iter().map(|u| u.to_bits()).collect::>(), - elt.constraints.clone() + elt.representation.into_iter().map(|u| u.to_bits()).collect::>() ) ) } From ec1911b8899c4f925e47c59ded71aa8f259ae3d0 Mon Sep 17 00:00:00 2001 From: Aaron Fenyes Date: Fri, 1 Nov 2024 04:43:30 -0700 Subject: [PATCH 04/10] Simplify memos --- app-proto/src/outline.rs | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/app-proto/src/outline.rs b/app-proto/src/outline.rs index 329fc58..65e440f 100644 --- a/app-proto/src/outline.rs +++ b/app-proto/src/outline.rs @@ -43,13 +43,9 @@ fn ConstraintOutlineItem(constraint_key: ConstraintKey, element_key: ElementKey) constraint.subjects.0 }; let other_subject_label = assembly.elements.with(|elts| elts[other_subject].label.clone()); - let class = create_memo(move || { - if constraint.lorentz_prod_valid.get() { - "cst" - } else { - "cst invalid" - } - }); + let class = constraint.lorentz_prod_valid.map( + |&lorentz_prod_valid| if lorentz_prod_valid { "cst" } else { "cst invalid" } + ); view! { li(class=class.get()) { input(r#type="checkbox", bind:checked=constraint.active) @@ -64,13 +60,9 @@ fn ConstraintOutlineItem(constraint_key: ConstraintKey, element_key: ElementKey) #[component(inline_props)] fn ElementOutlineItem(key: ElementKey, element: assembly::Element) -> View { let state = use_context::(); - let class = create_memo(move || { - if state.selection.with(|sel| sel.contains(&key)) { - "selected" - } else { - "" - } - }); + let class = state.selection.map( + move |sel| if sel.contains(&key) { "selected" } else { "" } + ); let label = element.label.clone(); let rep_components = element.representation.iter().map(|u| { let u_coord = format!("{:.3}", u).replace("-", "\u{2212}"); @@ -176,15 +168,16 @@ fn ElementOutlineItem(key: ElementKey, element: assembly::Element) -> View { // #[component] pub fn Outline() -> View { - // sort the elements alphabetically by ID - let elements_sorted = create_memo(|| { - let state = use_context::(); - state.assembly.elements - .get_clone() + let state = use_context::(); + + // list the elements alphabetically by ID + let element_list = state.assembly.elements.map( + |elts| elts + .clone() .into_iter() .sorted_by_key(|(_, elt)| elt.id.clone()) .collect() - }); + ); view! { ul( @@ -195,7 +188,7 @@ pub fn Outline() -> View { } ) { Keyed( - list=elements_sorted, + list=element_list, view=|(key, elt)| view! { ElementOutlineItem(key=key, element=elt) }, From 037a0c376f3806d2dbde540433d7deff811a3869 Mon Sep 17 00:00:00 2001 From: Aaron Fenyes Date: Fri, 1 Nov 2024 05:07:34 -0700 Subject: [PATCH 05/10] Add an element constructor --- app-proto/src/add_remove.rs | 197 +++++++++++++++--------------------- app-proto/src/assembly.rs | 33 ++++-- 2 files changed, 109 insertions(+), 121 deletions(-) diff --git a/app-proto/src/add_remove.rs b/app-proto/src/add_remove.rs index fce4c37..7ee20aa 100644 --- a/app-proto/src/add_remove.rs +++ b/app-proto/src/add_remove.rs @@ -1,4 +1,3 @@ -use std::collections::BTreeSet; /* DEBUG */ use sycamore::prelude::*; use web_sys::{console, wasm_bindgen::JsValue}; @@ -7,64 +6,52 @@ use crate::{engine, AppState, assembly::{Assembly, Constraint, Element}}; /* DEBUG */ fn load_gen_assemb(assembly: &Assembly) { let _ = assembly.try_insert_element( - Element { - id: String::from("gemini_a"), - label: String::from("Castor"), - color: [1.00_f32, 0.25_f32, 0.00_f32], - representation: engine::sphere(0.5, 0.5, 0.0, 1.0), - constraints: create_signal(BTreeSet::default()), - index: 0 - } + Element::new( + String::from("gemini_a"), + String::from("Castor"), + [1.00_f32, 0.25_f32, 0.00_f32], + engine::sphere(0.5, 0.5, 0.0, 1.0) + ) ); let _ = assembly.try_insert_element( - Element { - id: String::from("gemini_b"), - label: String::from("Pollux"), - color: [0.00_f32, 0.25_f32, 1.00_f32], - representation: engine::sphere(-0.5, -0.5, 0.0, 1.0), - constraints: create_signal(BTreeSet::default()), - index: 0 - } + Element::new( + String::from("gemini_b"), + String::from("Pollux"), + [0.00_f32, 0.25_f32, 1.00_f32], + engine::sphere(-0.5, -0.5, 0.0, 1.0) + ) ); let _ = assembly.try_insert_element( - Element { - id: String::from("ursa_major"), - label: String::from("Ursa major"), - color: [0.25_f32, 0.00_f32, 1.00_f32], - representation: engine::sphere(-0.5, 0.5, 0.0, 0.75), - constraints: create_signal(BTreeSet::default()), - index: 0 - } + Element::new( + String::from("ursa_major"), + String::from("Ursa major"), + [0.25_f32, 0.00_f32, 1.00_f32], + engine::sphere(-0.5, 0.5, 0.0, 0.75) + ) ); let _ = assembly.try_insert_element( - Element { - id: String::from("ursa_minor"), - label: String::from("Ursa minor"), - color: [0.25_f32, 1.00_f32, 0.00_f32], - representation: engine::sphere(0.5, -0.5, 0.0, 0.5), - constraints: create_signal(BTreeSet::default()), - index: 0 - } + Element::new( + String::from("ursa_minor"), + String::from("Ursa minor"), + [0.25_f32, 1.00_f32, 0.00_f32], + engine::sphere(0.5, -0.5, 0.0, 0.5) + ) ); let _ = assembly.try_insert_element( - Element { - id: String::from("moon_deimos"), - label: String::from("Deimos"), - color: [0.75_f32, 0.75_f32, 0.00_f32], - representation: engine::sphere(0.0, 0.15, 1.0, 0.25), - constraints: create_signal(BTreeSet::default()), - index: 0 - } + Element::new( + String::from("moon_deimos"), + String::from("Deimos"), + [0.75_f32, 0.75_f32, 0.00_f32], + engine::sphere(0.0, 0.15, 1.0, 0.25) + ) ); let _ = assembly.try_insert_element( - Element { - id: String::from("moon_phobos"), - label: String::from("Phobos"), - color: [0.00_f32, 0.75_f32, 0.50_f32], - representation: engine::sphere(0.0, -0.15, -1.0, 0.25), - constraints: create_signal(BTreeSet::default()), - index: 0 - } + Element::new( + String::from("moon_phobos"), + String::from("Phobos"), + [0.00_f32, 0.75_f32, 0.50_f32], + engine::sphere(0.0, -0.15, -1.0, 0.25) + ) ); } @@ -72,84 +59,68 @@ fn load_gen_assemb(assembly: &Assembly) { fn load_low_curv_assemb(assembly: &Assembly) { let a = 0.75_f64.sqrt(); let _ = assembly.try_insert_element( - Element { - id: "central".to_string(), - label: "Central".to_string(), - color: [0.75_f32, 0.75_f32, 0.75_f32], - representation: engine::sphere(0.0, 0.0, 0.0, 1.0), - constraints: create_signal(BTreeSet::default()), - index: 0 - } + Element::new( + "central".to_string(), + "Central".to_string(), + [0.75_f32, 0.75_f32, 0.75_f32], + engine::sphere(0.0, 0.0, 0.0, 1.0) + ) ); let _ = assembly.try_insert_element( - Element { - id: "assemb_plane".to_string(), - label: "Assembly plane".to_string(), - color: [0.75_f32, 0.75_f32, 0.75_f32], - representation: engine::sphere_with_offset(0.0, 0.0, 1.0, 0.0, 0.0), - constraints: create_signal(BTreeSet::default()), - index: 0 - } + Element::new( + "assemb_plane".to_string(), + "Assembly plane".to_string(), + [0.75_f32, 0.75_f32, 0.75_f32], + engine::sphere_with_offset(0.0, 0.0, 1.0, 0.0, 0.0) + ) ); let _ = assembly.try_insert_element( - Element { - id: "side1".to_string(), - label: "Side 1".to_string(), - color: [1.00_f32, 0.00_f32, 0.25_f32], - representation: engine::sphere_with_offset(1.0, 0.0, 0.0, 1.0, 0.0), - constraints: create_signal(BTreeSet::default()), - index: 0 - } + Element::new( + "side1".to_string(), + "Side 1".to_string(), + [1.00_f32, 0.00_f32, 0.25_f32], + engine::sphere_with_offset(1.0, 0.0, 0.0, 1.0, 0.0) + ) ); let _ = assembly.try_insert_element( - Element { - id: "side2".to_string(), - label: "Side 2".to_string(), - color: [0.25_f32, 1.00_f32, 0.00_f32], - representation: engine::sphere_with_offset(-0.5, a, 0.0, 1.0, 0.0), - constraints: create_signal(BTreeSet::default()), - index: 0 - } + Element::new( + "side2".to_string(), + "Side 2".to_string(), + [0.25_f32, 1.00_f32, 0.00_f32], + engine::sphere_with_offset(-0.5, a, 0.0, 1.0, 0.0) + ) ); let _ = assembly.try_insert_element( - Element { - id: "side3".to_string(), - label: "Side 3".to_string(), - color: [0.00_f32, 0.25_f32, 1.00_f32], - representation: engine::sphere_with_offset(-0.5, -a, 0.0, 1.0, 0.0), - constraints: create_signal(BTreeSet::default()), - index: 0 - } + Element::new( + "side3".to_string(), + "Side 3".to_string(), + [0.00_f32, 0.25_f32, 1.00_f32], + engine::sphere_with_offset(-0.5, -a, 0.0, 1.0, 0.0) + ) ); let _ = assembly.try_insert_element( - Element { - id: "corner1".to_string(), - label: "Corner 1".to_string(), - color: [0.75_f32, 0.75_f32, 0.75_f32], - representation: engine::sphere(-4.0/3.0, 0.0, 0.0, 1.0/3.0), - constraints: create_signal(BTreeSet::default()), - index: 0 - } + Element::new( + "corner1".to_string(), + "Corner 1".to_string(), + [0.75_f32, 0.75_f32, 0.75_f32], + engine::sphere(-4.0/3.0, 0.0, 0.0, 1.0/3.0) + ) ); let _ = assembly.try_insert_element( - Element { - id: "corner2".to_string(), - label: "Corner 2".to_string(), - color: [0.75_f32, 0.75_f32, 0.75_f32], - representation: engine::sphere(2.0/3.0, -4.0/3.0 * a, 0.0, 1.0/3.0), - constraints: create_signal(BTreeSet::default()), - index: 0 - } + Element::new( + "corner2".to_string(), + "Corner 2".to_string(), + [0.75_f32, 0.75_f32, 0.75_f32], + engine::sphere(2.0/3.0, -4.0/3.0 * a, 0.0, 1.0/3.0) + ) ); let _ = assembly.try_insert_element( - Element { - id: String::from("corner3"), - label: String::from("Corner 3"), - color: [0.75_f32, 0.75_f32, 0.75_f32], - representation: engine::sphere(2.0/3.0, 4.0/3.0 * a, 0.0, 1.0/3.0), - constraints: create_signal(BTreeSet::default()), - index: 0 - } + Element::new( + String::from("corner3"), + String::from("Corner 3"), + [0.75_f32, 0.75_f32, 0.75_f32], + engine::sphere(2.0/3.0, 4.0/3.0 * a, 0.0, 1.0/3.0) + ) ); } diff --git a/app-proto/src/assembly.rs b/app-proto/src/assembly.rs index 2763ae1..eb850d8 100644 --- a/app-proto/src/assembly.rs +++ b/app-proto/src/assembly.rs @@ -29,6 +29,25 @@ pub struct Element { pub index: usize } +impl Element { + pub fn new( + id: String, + label: String, + color: ElementColor, + representation: DVector + ) -> Element { + Element { + id: id, + label: label, + color: color, + representation: representation, + constraints: create_signal(BTreeSet::default()), + index: 0 + } + } +} + + #[derive(Clone)] pub struct Constraint { pub subjects: (ElementKey, ElementKey), @@ -92,14 +111,12 @@ impl Assembly { // create and insert a new element self.insert_element_unchecked( - Element { - id: id, - label: format!("Sphere {}", id_num), - color: [0.75_f32, 0.75_f32, 0.75_f32], - representation: DVector::::from_column_slice(&[0.0, 0.0, 0.0, 0.5, -0.5]), - constraints: create_signal(BTreeSet::default()), - index: 0 - } + Element::new( + id, + format!("Sphere {}", id_num), + [0.75_f32, 0.75_f32, 0.75_f32], + DVector::::from_column_slice(&[0.0, 0.0, 0.0, 0.5, -0.5]) + ) ); } From 33dd5dbe82bf7bd05bb99a55ca0710f205c7b3ee Mon Sep 17 00:00:00 2001 From: Aaron Fenyes Date: Fri, 1 Nov 2024 19:01:14 -0700 Subject: [PATCH 06/10] Make element vectors reactive --- app-proto/src/assembly.rs | 16 +++++----- app-proto/src/display.rs | 61 +++++++++++++++++++++++++-------------- app-proto/src/outline.rs | 27 +++++++++-------- 3 files changed, 63 insertions(+), 41 deletions(-) diff --git a/app-proto/src/assembly.rs b/app-proto/src/assembly.rs index eb850d8..78228cc 100644 --- a/app-proto/src/assembly.rs +++ b/app-proto/src/assembly.rs @@ -18,7 +18,7 @@ pub struct Element { pub id: String, pub label: String, pub color: ElementColor, - pub representation: DVector, + pub representation: Signal>, pub constraints: Signal>, // the configuration matrix column index that was assigned to this element @@ -40,7 +40,7 @@ impl Element { id: id, label: label, color: color, - representation: representation, + representation: create_signal(representation), constraints: create_signal(BTreeSet::default()), index: 0 } @@ -161,7 +161,7 @@ impl Assembly { for (_, elt) in elts { let index = elt.index; gram_to_be.push_sym(index, index, 1.0); - guess_to_be.set_column(index, &elt.representation); + guess_to_be.set_column(index, &elt.representation.get_clone()); } (gram_to_be, guess_to_be) @@ -203,11 +203,11 @@ impl Assembly { if success { // read out the solution - self.elements.update(|elts| { - for (_, elt) in elts.iter_mut() { - elt.representation.set_column(0, &config.column(elt.index)); - } - }); + for (_, elt) in self.elements.get_clone() { + elt.representation.update( + |rep| rep.set_column(0, &config.column(elt.index)) + ); + } } } } \ No newline at end of file diff --git a/app-proto/src/display.rs b/app-proto/src/display.rs index 79199ec..ee0af47 100644 --- a/app-proto/src/display.rs +++ b/app-proto/src/display.rs @@ -103,7 +103,11 @@ pub fn Display() -> View { // change listener let scene_changed = create_signal(true); create_effect(move || { - state.assembly.elements.track(); + state.assembly.elements.with(|elts| { + for (_, elt) in elts { + elt.representation.track(); + } + }); state.selection.track(); scene_changed.set(true); }); @@ -295,25 +299,40 @@ pub fn Display() -> View { let assembly_to_world = &location * &orientation; // get the assembly - let elements = state.assembly.elements.get_clone(); - let element_iter = (&elements).into_iter(); - let reps_world: Vec<_> = element_iter.clone().map( - |(_, elt)| &assembly_to_world * &elt.representation - ).collect(); - let colors: Vec<_> = element_iter.clone().map(|(key, elt)| - if state.selection.with(|sel| sel.contains(&key)) { - elt.color.map(|ch| 0.2 + 0.8*ch) - } else { - elt.color - } - ).collect(); - let highlights: Vec<_> = element_iter.map(|(key, _)| - if state.selection.with(|sel| sel.contains(&key)) { - 1.0_f32 - } else { - HIGHLIGHT - } - ).collect(); + let ( + elt_cnt, + reps_world, + colors, + highlights + ) = state.assembly.elements.with(|elts| { + ( + // number of elements + elts.len() as i32, + + // representation vectors in world coordinates + elts.iter().map( + |(_, elt)| elt.representation.with(|rep| &assembly_to_world * rep) + ).collect::>(), + + // colors + elts.iter().map(|(key, elt)| { + if state.selection.with(|sel| sel.contains(&key)) { + elt.color.map(|ch| 0.2 + 0.8*ch) + } else { + elt.color + } + }).collect::>(), + + // highlight levels + elts.iter().map(|(key, _)| { + if state.selection.with(|sel| sel.contains(&key)) { + 1.0_f32 + } else { + HIGHLIGHT + } + }).collect::>() + ) + }); // set the resolution let width = canvas.width() as f32; @@ -322,7 +341,7 @@ pub fn Display() -> View { ctx.uniform1f(shortdim_loc.as_ref(), width.min(height)); // pass the assembly - ctx.uniform1i(sphere_cnt_loc.as_ref(), elements.len() as i32); + ctx.uniform1i(sphere_cnt_loc.as_ref(), elt_cnt); for n in 0..reps_world.len() { let v = &reps_world[n]; ctx.uniform3f( diff --git a/app-proto/src/outline.rs b/app-proto/src/outline.rs index 65e440f..f3951b5 100644 --- a/app-proto/src/outline.rs +++ b/app-proto/src/outline.rs @@ -1,5 +1,5 @@ use itertools::Itertools; -use sycamore::{prelude::*, web::tags::div}; +use sycamore::prelude::*; use web_sys::{ Event, HtmlInputElement, @@ -64,10 +64,11 @@ fn ElementOutlineItem(key: ElementKey, element: assembly::Element) -> View { move |sel| if sel.contains(&key) { "selected" } else { "" } ); let label = element.label.clone(); - let rep_components = element.representation.iter().map(|u| { - let u_coord = format!("{:.3}", u).replace("-", "\u{2212}"); - View::from(div().children(u_coord)) - }).collect::>(); + let rep_components = element.representation.map( + |rep| rep.iter().map( + |u| format!("{:.3}", u).replace("-", "\u{2212}") + ).collect() + ); let constrained = element.constraints.map(|csts| csts.len() > 0); let constraint_list = element.constraints.map( |csts| csts.clone().into_iter().collect() @@ -139,7 +140,14 @@ fn ElementOutlineItem(key: ElementKey, element: assembly::Element) -> View { } ) { div(class="elt-label") { (label) } - div(class="elt-rep") { (rep_components) } + div(class="elt-rep") { + Indexed( + list=rep_components, + view=|coord_str| view! { + div { (coord_str) } + } + ) + } div(class="status") } } @@ -192,12 +200,7 @@ pub fn Outline() -> View { view=|(key, elt)| view! { ElementOutlineItem(key=key, element=elt) }, - key=|(key, elt)| ( - key.clone(), - elt.id.clone(), - elt.label.clone(), - elt.representation.into_iter().map(|u| u.to_bits()).collect::>() - ) + key=|(key, _)| key.clone() ) } } From 92b91df4357caf5abe8b396131c3ce15f7c7f5c0 Mon Sep 17 00:00:00 2001 From: Aaron Fenyes Date: Fri, 1 Nov 2024 19:11:33 -0700 Subject: [PATCH 07/10] Use tabular numbers for element vectors --- app-proto/main.css | 1 + 1 file changed, 1 insertion(+) diff --git a/app-proto/main.css b/app-proto/main.css index ba8a20b..80b55f2 100644 --- a/app-proto/main.css +++ b/app-proto/main.css @@ -102,6 +102,7 @@ details[open]:has(li) .elt-switch::after { .elt-rep > div { padding: 2px 0px 0px 0px; font-size: 10pt; + font-variant-numeric: tabular-nums; text-align: right; width: 56px; } From b94280c456402700252f0c51fb92598f41fa68b8 Mon Sep 17 00:00:00 2001 From: Aaron Fenyes Date: Fri, 1 Nov 2024 20:40:25 -0700 Subject: [PATCH 08/10] Test representation validity in realization effect --- app-proto/src/add_remove.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/app-proto/src/add_remove.rs b/app-proto/src/add_remove.rs index 7ee20aa..bea20f9 100644 --- a/app-proto/src/add_remove.rs +++ b/app-proto/src/add_remove.rs @@ -187,15 +187,15 @@ pub fn AddRemove() -> View { } ); let lorentz_prod = create_signal(0.0); + let lorentz_prod_valid = create_signal(false); let active = create_signal(true); state.assembly.insert_constraint(Constraint { subjects: subjects, lorentz_prod: lorentz_prod, lorentz_prod_text: create_signal(String::new()), - lorentz_prod_valid: create_signal(false), + lorentz_prod_valid: lorentz_prod_valid, active: active, }); - state.assembly.realize(); state.selection.update(|sel| sel.clear()); /* DEBUG */ @@ -213,15 +213,14 @@ pub fn AddRemove() -> View { } }); - // update the realization when the constraint is activated, - // or edited while active + // update the realization when the constraint becomes active + // and valid, or is edited while active and valid create_effect(move || { + console::log_1(&JsValue::from( + format!("Constraint ({}, {}) updated", subjects.0, subjects.1) + )); lorentz_prod.track(); - console::log_2( - &JsValue::from("Lorentz product updated to"), - &JsValue::from(lorentz_prod.get_untracked()) - ); - if active.get() { + if active.get() && lorentz_prod_valid.get() { state.assembly.realize(); } }); From d223df869cc928769ac848665bc35d3bf8b29adf Mon Sep 17 00:00:00 2001 From: Aaron Fenyes Date: Fri, 1 Nov 2024 20:49:00 -0700 Subject: [PATCH 09/10] Stop `Assembly::realize` from reacting to itself Previously, `realize` both tracked and updated the element vectors, so calling it in a reactive context could start a feedback loop. --- app-proto/src/assembly.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app-proto/src/assembly.rs b/app-proto/src/assembly.rs index 78228cc..b119d5b 100644 --- a/app-proto/src/assembly.rs +++ b/app-proto/src/assembly.rs @@ -161,7 +161,7 @@ impl Assembly { for (_, elt) in elts { let index = elt.index; gram_to_be.push_sym(index, index, 1.0); - guess_to_be.set_column(index, &elt.representation.get_clone()); + guess_to_be.set_column(index, &elt.representation.get_clone_untracked()); } (gram_to_be, guess_to_be) @@ -203,7 +203,7 @@ impl Assembly { if success { // read out the solution - for (_, elt) in self.elements.get_clone() { + for (_, elt) in self.elements.get_clone_untracked() { elt.representation.update( |rep| rep.set_column(0, &config.column(elt.index)) ); From 102f40055391e27956b05d2607bd67c00884d328 Mon Sep 17 00:00:00 2001 From: Aaron Fenyes Date: Fri, 1 Nov 2024 23:58:45 -0700 Subject: [PATCH 10/10] Switch font to Fira Sans It has tabular numbers, and it's nice and big too. --- app-proto/index.html | 2 +- app-proto/main.css | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app-proto/index.html b/app-proto/index.html index 941a153..92238f4 100644 --- a/app-proto/index.html +++ b/app-proto/index.html @@ -4,7 +4,7 @@ dyna3 - + diff --git a/app-proto/main.css b/app-proto/main.css index 80b55f2..204c8c8 100644 --- a/app-proto/main.css +++ b/app-proto/main.css @@ -2,7 +2,7 @@ body { margin: 0px; color: #fcfcfc; background-color: #222; - font-family: 'Lato'; + font-family: 'Fira Sans', sans-serif; } /* sidebar */ @@ -36,7 +36,7 @@ body { /* KLUDGE */ #add-remove > button.emoji { - font-family: 'Noto Emoji'; + font-family: 'Noto Emoji', sans-serif; } /* outline */