Application prototype #14

Merged
glen merged 101 commits from app-proto into main 2024-10-21 23:38:28 +00:00
4 changed files with 74 additions and 33 deletions
Showing only changes of commit bd0982f821 - Show all commits

View File

@ -11,6 +11,7 @@ default = ["console_error_panic_hook"]
itertools = "0.13.0" itertools = "0.13.0"
js-sys = "0.3.70" js-sys = "0.3.70"
nalgebra = "0.33.0" nalgebra = "0.33.0"
rustc-hash = "2.0.0"
slab = "0.4.9" slab = "0.4.9"
sycamore = "0.9.0-beta.3" sycamore = "0.9.0-beta.3"

View File

@ -6,16 +6,51 @@ use crate::Constraint;
#[component] #[component]
pub fn AddRemove() -> View { pub fn AddRemove() -> View {
let state = use_context::<AppState>();
view! { view! {
div(id="add-remove") { div(id="add-remove") {
button( button(
on:click=move |_| { on:click=|_| {
let state = use_context::<AppState>();
state.assembly.insert_new_element();
/* DEBUG */
// print updated list of elements by identifier
console::log_1(&JsValue::from("elements by identifier:"));
for (id, key) in state.assembly.elements_by_id.get_clone().iter() {
console::log_3(
&JsValue::from(" "),
&JsValue::from(id),
&JsValue::from(*key)
);
}
}
) { "+" }
button(
disabled={
let state = use_context::<AppState>();
state.selection.with(|sel| sel.len() != 2)
},
on:click=|_| {
let state = use_context::<AppState>();
let args = state.selection.with(
|sel| {
let arg_vec: Vec<_> = sel.into_iter().collect();
(arg_vec[0].clone(), arg_vec[1].clone())
}
);
state.assembly.insert_constraint(Constraint {
args: args,
rep: 0.0
});
state.selection.update(|sel| sel.clear());
/* DEBUG */
// print updated constraint list
console::log_1(&JsValue::from("constraints:")); console::log_1(&JsValue::from("constraints:"));
state.assembly.constraints.with(|csts| { state.assembly.constraints.with(|csts| {
for (_, cst) in csts.into_iter() { for (_, cst) in csts.into_iter() {
console::log_4( console::log_5(
&JsValue::from(" "),
&JsValue::from(cst.args.0), &JsValue::from(cst.args.0),
&JsValue::from(cst.args.1), &JsValue::from(cst.args.1),
&JsValue::from(":"), &JsValue::from(":"),
@ -24,31 +59,6 @@ pub fn AddRemove() -> View {
} }
}); });
} }
) { "+" }
button(
disabled={
state.selection.with(|sel| sel.len() != 2)
},
on:click=move |_| {
let args = state.selection.with(
|sel| {
let arg_vec: Vec<_> = sel.into_iter().collect();
(arg_vec[0].clone(), arg_vec[1].clone())
}
);
console::log_5(
&JsValue::from("add constraint"),
&JsValue::from(args.0),
&JsValue::from(args.1),
&JsValue::from(":"),
&JsValue::from(0.0)
);
state.assembly.insert_constraint(Constraint {
args: args,
rep: 0.0
});
state.selection.update(|sel| sel.clear());
}
) { "🔗" } ) { "🔗" }
} }
} }

View File

@ -1,4 +1,5 @@
use nalgebra::DVector; use nalgebra::DVector;
use rustc_hash::FxHashMap;
use slab::Slab; use slab::Slab;
use std::collections::BTreeSet; use std::collections::BTreeSet;
use sycamore::prelude::*; use sycamore::prelude::*;
@ -21,18 +22,46 @@ pub struct Constraint {
// a complete, view-independent description of an assembly // a complete, view-independent description of an assembly
#[derive(Clone)] #[derive(Clone)]
pub struct Assembly { pub struct Assembly {
// elements and constraints
pub elements: Signal<Slab<Element>>, pub elements: Signal<Slab<Element>>,
pub constraints: Signal<Slab<Constraint>> pub constraints: Signal<Slab<Constraint>>,
// indexing
pub elements_by_id: Signal<FxHashMap<String, usize>>
} }
impl Assembly { impl Assembly {
pub fn new() -> Assembly { pub fn new() -> Assembly {
Assembly { Assembly {
elements: create_signal(Slab::new()), elements: create_signal(Slab::new()),
constraints: create_signal(Slab::new()) constraints: create_signal(Slab::new()),
elements_by_id: create_signal(FxHashMap::default())
} }
} }
pub fn insert_new_element(&self) {
// find the next unused identifier in the default sequence
let mut id_num = 1;
let mut id = format!("sphere{}", id_num);
while self.elements_by_id.with(
|elts_by_id| elts_by_id.contains_key(&id)
) {
id_num += 1;
id = format!("sphere{}", id_num);
}
// create and insert a new element
let elt = Element {
id: id.clone(),
label: format!("Sphere {}", id_num),
color: [0.75_f32, 0.75_f32, 0.75_f32],
rep: DVector::<f64>::from_column_slice(&[0.0, 0.0, 0.0, 0.5, -0.5]),
constraints: BTreeSet::default()
};
let key = self.elements.update(|elts| elts.insert(elt));
self.elements_by_id.update(|elts_by_id| elts_by_id.insert(id, key));
}
pub fn insert_constraint(&self, constraint: Constraint) { pub fn insert_constraint(&self, constraint: Constraint) {
let args = constraint.args; let args = constraint.args;
let key = self.constraints.update(|csts| csts.insert(constraint)); let key = self.constraints.update(|csts| csts.insert(constraint));

View File

@ -4,6 +4,7 @@ mod display;
mod outline; mod outline;
use nalgebra::DVector; use nalgebra::DVector;
use rustc_hash::FxHashSet;
use std::collections::BTreeSet; use std::collections::BTreeSet;
use sycamore::prelude::*; use sycamore::prelude::*;
@ -15,14 +16,14 @@ use outline::Outline;
#[derive(Clone)] #[derive(Clone)]
struct AppState { struct AppState {
assembly: Assembly, assembly: Assembly,
selection: Signal<BTreeSet<usize>> selection: Signal<FxHashSet<usize>>
} }
impl AppState { impl AppState {
fn new() -> AppState { fn new() -> AppState {
AppState { AppState {
assembly: Assembly::new(), assembly: Assembly::new(),
selection: create_signal(BTreeSet::default()) selection: create_signal(FxHashSet::default())
} }
} }
} }