use nalgebra::DVector; use rustc_hash::FxHashMap; use slab::Slab; use std::collections::BTreeSet; use sycamore::prelude::*; #[derive(Clone, PartialEq)] pub struct Element { pub id: String, pub label: String, pub color: [f32; 3], pub rep: DVector, pub constraints: BTreeSet } #[derive(Clone)] pub struct Constraint { pub args: (usize, usize), pub rep: f64, pub active: Signal } // a complete, view-independent description of an assembly #[derive(Clone)] pub struct Assembly { // elements and constraints pub elements: Signal>, pub constraints: Signal>, // indexing pub elements_by_id: Signal> } impl Assembly { pub fn new() -> Assembly { Assembly { elements: create_signal(Slab::new()), constraints: create_signal(Slab::new()), elements_by_id: create_signal(FxHashMap::default()) } } // insert an element into the assembly without checking whether we already // have an element with the same identifier. any element that does have the // same identifier will get kicked out of the `elements_by_id` index fn insert_element_unchecked(&self, elt: Element) { let id = elt.id.clone(); 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 try_insert_element(&self, elt: Element) -> bool { let can_insert = self.elements_by_id.with_untracked( |elts_by_id| !elts_by_id.contains_key(&elt.id) ); if can_insert { self.insert_element_unchecked(elt); } can_insert } 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_untracked( |elts_by_id| elts_by_id.contains_key(&id) ) { id_num += 1; id = format!("sphere{}", id_num); } // 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], rep: DVector::::from_column_slice(&[0.0, 0.0, 0.0, 0.5, -0.5]), constraints: BTreeSet::default() } ); } pub fn insert_constraint(&self, constraint: Constraint) { let args = constraint.args; let key = self.constraints.update(|csts| csts.insert(constraint)); self.elements.update(|elts| { elts[args.0].constraints.insert(key); elts[args.1].constraints.insert(key); }) } }