diff --git a/app-proto/index.html b/app-proto/index.html
index 92238f4..941a153 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 204c8c8..ba8a20b 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: 'Fira Sans', sans-serif;
+ font-family: 'Lato';
}
/* sidebar */
@@ -36,7 +36,7 @@ body {
/* KLUDGE */
#add-remove > button.emoji {
- font-family: 'Noto Emoji', sans-serif;
+ font-family: 'Noto Emoji';
}
/* outline */
@@ -102,7 +102,6 @@ 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;
}
diff --git a/app-proto/src/add_remove.rs b/app-proto/src/add_remove.rs
index d135449..ead66dd 100644
--- a/app-proto/src/add_remove.rs
+++ b/app-proto/src/add_remove.rs
@@ -1,3 +1,4 @@
+use std::collections::BTreeSet; /* DEBUG */
use sycamore::prelude::*;
use web_sys::{console, wasm_bindgen::JsValue};
@@ -6,52 +7,64 @@ use crate::{engine, AppState, assembly::{Assembly, Constraint, Element}};
/* DEBUG */
fn load_gen_assemb(assembly: &Assembly) {
let _ = assembly.try_insert_element(
- 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)
- )
+ Element {
+ id: String::from("gemini_a"),
+ label: String::from("Castor"),
+ color: [1.00_f32, 0.25_f32, 0.00_f32],
+ rep: engine::sphere(0.5, 0.5, 0.0, 1.0),
+ constraints: BTreeSet::default(),
+ index: 0
+ }
);
let _ = assembly.try_insert_element(
- 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)
- )
+ Element {
+ id: String::from("gemini_b"),
+ label: String::from("Pollux"),
+ color: [0.00_f32, 0.25_f32, 1.00_f32],
+ rep: engine::sphere(-0.5, -0.5, 0.0, 1.0),
+ constraints: BTreeSet::default(),
+ index: 0
+ }
);
let _ = assembly.try_insert_element(
- 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)
- )
+ Element {
+ id: String::from("ursa_major"),
+ label: String::from("Ursa major"),
+ color: [0.25_f32, 0.00_f32, 1.00_f32],
+ rep: engine::sphere(-0.5, 0.5, 0.0, 0.75),
+ constraints: BTreeSet::default(),
+ index: 0
+ }
);
let _ = assembly.try_insert_element(
- 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)
- )
+ Element {
+ id: String::from("ursa_minor"),
+ label: String::from("Ursa minor"),
+ color: [0.25_f32, 1.00_f32, 0.00_f32],
+ rep: engine::sphere(0.5, -0.5, 0.0, 0.5),
+ constraints: BTreeSet::default(),
+ index: 0
+ }
);
let _ = assembly.try_insert_element(
- 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)
- )
+ Element {
+ id: String::from("moon_deimos"),
+ label: String::from("Deimos"),
+ color: [0.75_f32, 0.75_f32, 0.00_f32],
+ rep: engine::sphere(0.0, 0.15, 1.0, 0.25),
+ constraints: BTreeSet::default(),
+ index: 0
+ }
);
let _ = assembly.try_insert_element(
- 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)
- )
+ Element {
+ id: String::from("moon_phobos"),
+ label: String::from("Phobos"),
+ color: [0.00_f32, 0.75_f32, 0.50_f32],
+ rep: engine::sphere(0.0, -0.15, -1.0, 0.25),
+ constraints: BTreeSet::default(),
+ index: 0
+ }
);
}
@@ -59,68 +72,84 @@ 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::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)
- )
+ Element {
+ id: "central".to_string(),
+ label: "Central".to_string(),
+ color: [0.75_f32, 0.75_f32, 0.75_f32],
+ rep: engine::sphere(0.0, 0.0, 0.0, 1.0),
+ constraints: BTreeSet::default(),
+ index: 0
+ }
);
let _ = assembly.try_insert_element(
- 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)
- )
+ Element {
+ id: "assemb_plane".to_string(),
+ label: "Assembly plane".to_string(),
+ color: [0.75_f32, 0.75_f32, 0.75_f32],
+ rep: engine::sphere_with_offset(0.0, 0.0, 1.0, 0.0, 0.0),
+ constraints: BTreeSet::default(),
+ index: 0
+ }
);
let _ = assembly.try_insert_element(
- 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)
- )
+ Element {
+ id: "side1".to_string(),
+ label: "Side 1".to_string(),
+ color: [1.00_f32, 0.00_f32, 0.25_f32],
+ rep: engine::sphere_with_offset(1.0, 0.0, 0.0, 1.0, 0.0),
+ constraints: BTreeSet::default(),
+ index: 0
+ }
);
let _ = assembly.try_insert_element(
- 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)
- )
+ Element {
+ id: "side2".to_string(),
+ label: "Side 2".to_string(),
+ color: [0.25_f32, 1.00_f32, 0.00_f32],
+ rep: engine::sphere_with_offset(-0.5, a, 0.0, 1.0, 0.0),
+ constraints: BTreeSet::default(),
+ index: 0
+ }
);
let _ = assembly.try_insert_element(
- 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)
- )
+ Element {
+ id: "side3".to_string(),
+ label: "Side 3".to_string(),
+ color: [0.00_f32, 0.25_f32, 1.00_f32],
+ rep: engine::sphere_with_offset(-0.5, -a, 0.0, 1.0, 0.0),
+ constraints: BTreeSet::default(),
+ index: 0
+ }
);
let _ = assembly.try_insert_element(
- 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)
- )
+ Element {
+ id: "corner1".to_string(),
+ label: "Corner 1".to_string(),
+ color: [0.75_f32, 0.75_f32, 0.75_f32],
+ rep: engine::sphere(-4.0/3.0, 0.0, 0.0, 1.0/3.0),
+ constraints: BTreeSet::default(),
+ index: 0
+ }
);
let _ = assembly.try_insert_element(
- 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)
- )
+ Element {
+ id: "corner2".to_string(),
+ label: "Corner 2".to_string(),
+ color: [0.75_f32, 0.75_f32, 0.75_f32],
+ rep: engine::sphere(2.0/3.0, -4.0/3.0 * a, 0.0, 1.0/3.0),
+ constraints: BTreeSet::default(),
+ index: 0
+ }
);
let _ = assembly.try_insert_element(
- 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)
- )
+ Element {
+ id: String::from("corner3"),
+ label: String::from("Corner 3"),
+ color: [0.75_f32, 0.75_f32, 0.75_f32],
+ rep: engine::sphere(2.0/3.0, 4.0/3.0 * a, 0.0, 1.0/3.0),
+ constraints: BTreeSet::default(),
+ index: 0
+ }
);
}
@@ -187,15 +216,15 @@ pub fn AddRemove() -> View {
}
);
let rep = create_signal(0.0);
- let rep_valid = create_signal(false);
let active = create_signal(true);
state.assembly.insert_constraint(Constraint {
args: args,
rep: rep,
rep_text: create_signal(String::new()),
- rep_valid: rep_valid,
+ rep_valid: create_signal(false),
active: active,
});
+ state.assembly.realize();
state.selection.update(|sel| sel.clear());
/* DEBUG */
@@ -213,14 +242,15 @@ pub fn AddRemove() -> View {
}
});
- // update the realization when the constraint becomes active
- // and valid, or is edited while active and valid
+ // update the realization when the constraint activated, or
+ // edited while active
create_effect(move || {
- console::log_1(&JsValue::from(
- format!("Constraint ({}, {}) updated", args.0, args.1)
- ));
rep.track();
- if active.get() && rep_valid.get() {
+ console::log_2(
+ &JsValue::from("Lorentz product updated to"),
+ &JsValue::from(rep.get_untracked())
+ );
+ if active.get() {
state.assembly.realize();
}
});
diff --git a/app-proto/src/assembly.rs b/app-proto/src/assembly.rs
index 7b7c015..0970932 100644
--- a/app-proto/src/assembly.rs
+++ b/app-proto/src/assembly.rs
@@ -12,32 +12,13 @@ pub struct Element {
pub id: String,
pub label: String,
pub color: [f32; 3],
- pub rep: Signal>,
- pub constraints: Signal>,
+ pub rep: DVector,
+ pub constraints: BTreeSet,
// internal properties, not reflected in any view
pub index: usize
}
-impl Element {
- pub fn new(
- id: String,
- label: String,
- color: [f32; 3],
- rep: DVector
- ) -> Element {
- Element {
- id: id,
- label: label,
- color: color,
- rep: create_signal(rep),
- constraints: create_signal(BTreeSet::default()),
- index: 0
- }
- }
-}
-
-
#[derive(Clone)]
pub struct Constraint {
pub args: (usize, usize),
@@ -101,23 +82,24 @@ impl Assembly {
// create and insert a new element
self.insert_element_unchecked(
- 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])
- )
+ Element {
+ id: id,
+ label: format!("Sphere {}", id_num),
+ color: [0.75_f32, 0.75_f32, 0.75_f32],
+ rep: DVector::::from_column_slice(&[0.0, 0.0, 0.0, 0.5, -0.5]),
+ constraints: BTreeSet::default(),
+ index: 0
+ }
);
}
pub fn insert_constraint(&self, constraint: Constraint) {
let args = constraint.args;
let key = self.constraints.update(|csts| csts.insert(constraint));
- let arg_constraints = self.elements.with(
- |elts| (elts[args.0].constraints, elts[args.1].constraints)
- );
- arg_constraints.0.update(|csts| csts.insert(key));
- arg_constraints.1.update(|csts| csts.insert(key));
+ self.elements.update(|elts| {
+ elts[args.0].constraints.insert(key);
+ elts[args.1].constraints.insert(key);
+ });
}
// --- realization ---
@@ -151,7 +133,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.rep.get_clone_untracked());
+ guess_to_be.set_column(index, &elt.rep);
}
(gram_to_be, guess_to_be)
@@ -193,11 +175,11 @@ impl Assembly {
if success {
// read out the solution
- for (_, elt) in self.elements.get_clone_untracked() {
- elt.rep.update(
- |rep| rep.set_column(0, &config.column(elt.index))
- );
- }
+ self.elements.update(|elts| {
+ for (_, elt) in elts.iter_mut() {
+ elt.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 ce1655d..c32b470 100644
--- a/app-proto/src/display.rs
+++ b/app-proto/src/display.rs
@@ -103,11 +103,7 @@ pub fn Display() -> View {
// change listener
let scene_changed = create_signal(true);
create_effect(move || {
- state.assembly.elements.with(|elts| {
- for (_, elt) in elts {
- elt.rep.track();
- }
- });
+ state.assembly.elements.track();
state.selection.track();
scene_changed.set(true);
});
@@ -299,40 +295,23 @@ pub fn Display() -> View {
let assembly_to_world = &location * &orientation;
// get the assembly
- 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.rep.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::>()
- )
- });
+ 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.rep).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();
// set the resolution
let width = canvas.width() as f32;
@@ -341,7 +320,7 @@ pub fn Display() -> View {
ctx.uniform1f(shortdim_loc.as_ref(), width.min(height));
// pass the assembly
- ctx.uniform1i(sphere_cnt_loc.as_ref(), elt_cnt);
+ ctx.uniform1i(sphere_cnt_loc.as_ref(), elements.len() as i32);
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 11cc061..4a2b36a 100644
--- a/app-proto/src/outline.rs
+++ b/app-proto/src/outline.rs
@@ -1,5 +1,5 @@
use itertools::Itertools;
-use sycamore::prelude::*;
+use sycamore::{prelude::*, web::tags::div};
use web_sys::{
Event,
HtmlInputElement,
@@ -43,9 +43,13 @@ fn ConstraintOutlineItem(constraint_key: usize, element_key: usize) -> View {
constraint.args.0
};
let other_arg_label = assembly.elements.with(|elts| elts[other_arg].label.clone());
- let class = constraint.rep_valid.map(
- |&rep_valid| if rep_valid { "cst" } else { "cst invalid" }
- );
+ let class = create_memo(move || {
+ if constraint.rep_valid.get() {
+ "cst"
+ } else {
+ "cst invalid"
+ }
+ });
view! {
li(class=class.get()) {
input(r#type="checkbox", bind:checked=constraint.active)
@@ -60,19 +64,19 @@ fn ConstraintOutlineItem(constraint_key: usize, element_key: usize) -> View {
#[component(inline_props)]
fn ElementOutlineItem(key: usize, element: assembly::Element) -> View {
let state = use_context::();
- let class = state.selection.map(
- move |sel| if sel.contains(&key) { "selected" } else { "" }
- );
+ let class = create_memo(move || {
+ if state.selection.with(|sel| sel.contains(&key)) {
+ "selected"
+ } else {
+ ""
+ }
+ });
let label = element.label.clone();
- let rep_components = element.rep.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()
- );
+ let rep_components = element.rep.iter().map(|u| {
+ let u_coord = format!("{:.3}", u).replace("-", "\u{2212}");
+ View::from(div().children(u_coord))
+ }).collect::>();
+ let constrained = element.constraints.len() > 0;
let details_node = create_node_ref();
view! {
li {
@@ -97,7 +101,7 @@ fn ElementOutlineItem(key: usize, element: assembly::Element) -> View {
}
event.prevent_default();
},
- "ArrowRight" if constrained.get() => {
+ "ArrowRight" if constrained => {
let _ = details_node
.get()
.unchecked_into::()
@@ -140,20 +144,13 @@ fn ElementOutlineItem(key: usize, element: assembly::Element) -> View {
}
) {
div(class="elt-label") { (label) }
- div(class="elt-rep") {
- Indexed(
- list=rep_components,
- view=|coord_str| view! {
- div { (coord_str) }
- }
- )
- }
+ div(class="elt-rep") { (rep_components) }
div(class="status")
}
}
ul(class="constraints") {
Keyed(
- list=constraint_list,
+ list=element.constraints.into_iter().collect::>(),
view=move |cst_key| view! {
ConstraintOutlineItem(
constraint_key=cst_key,
@@ -176,16 +173,15 @@ fn ElementOutlineItem(key: usize, element: assembly::Element) -> View {
//
#[component]
pub fn Outline() -> View {
- let state = use_context::();
-
- // list the elements alphabetically by ID
- let element_list = state.assembly.elements.map(
- |elts| elts
- .clone()
+ // sort the elements alphabetically by ID
+ let elements_sorted = create_memo(|| {
+ let state = use_context::();
+ state.assembly.elements
+ .get_clone()
.into_iter()
.sorted_by_key(|(_, elt)| elt.id.clone())
.collect()
- );
+ });
view! {
ul(
@@ -196,11 +192,16 @@ pub fn Outline() -> View {
}
) {
Keyed(
- list=element_list,
+ list=elements_sorted,
view=|(key, elt)| view! {
ElementOutlineItem(key=key, element=elt)
},
- key=|(key, _)| key.clone()
+ key=|(key, elt)| (
+ key.clone(),
+ elt.id.clone(),
+ elt.label.clone(),
+ elt.constraints.clone()
+ )
)
}
}