Use pointers to refer to elements and regulators #84
5 changed files with 74 additions and 50 deletions
12
app-proto/Cargo.lock
generated
12
app-proto/Cargo.lock
generated
|
@ -1,6 +1,6 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
|
@ -90,7 +90,6 @@ dependencies = [
|
|||
"nalgebra",
|
||||
"readonly",
|
||||
"rustc-hash",
|
||||
"slab",
|
||||
"sycamore",
|
||||
"wasm-bindgen-test",
|
||||
"web-sys",
|
||||
|
@ -414,15 +413,6 @@ dependencies = [
|
|||
"wide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slotmap"
|
||||
version = "1.0.7"
|
||||
|
|
|
@ -16,7 +16,6 @@ lazy_static = "1.5.0"
|
|||
nalgebra = "0.33.0"
|
||||
readonly = "0.2.12"
|
||||
rustc-hash = "2.0.0"
|
||||
slab = "0.4.9"
|
||||
sycamore = "0.9.0-beta.3"
|
||||
|
||||
# The `console_error_panic_hook` crate provides better debugging of panics by
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
use nalgebra::{DMatrix, DVector, DVectorView};
|
||||
use rustc_hash::FxHashMap;
|
||||
use slab::Slab;
|
||||
use std::{
|
||||
any::{Any, TypeId},
|
||||
cell::Cell,
|
||||
collections::BTreeSet,
|
||||
cmp::Ordering,
|
||||
fmt,
|
||||
fmt::{Debug, Formatter},
|
||||
hash::{Hash, Hasher},
|
||||
rc::Rc,
|
||||
sync::atomic::{AtomicU64, Ordering}
|
||||
sync::{atomic, atomic::AtomicU64}
|
||||
};
|
||||
use sycamore::prelude::*;
|
||||
use web_sys::{console, wasm_bindgen::JsValue}; /* DEBUG */
|
||||
|
@ -29,9 +30,6 @@ use crate::{
|
|||
specified::SpecifiedValue
|
||||
};
|
||||
|
||||
// the types of the keys we use to access an assembly's elements
|
||||
pub type ElementKey = usize;
|
||||
|
||||
pub type ElementColor = [f32; 3];
|
||||
|
||||
/* KLUDGE */
|
||||
|
@ -53,7 +51,7 @@ pub trait Serial {
|
|||
// https://marabos.nl/atomics/atomics.html#example-handle-overflow
|
||||
//
|
||||
NEXT_SERIAL.fetch_update(
|
||||
Ordering::SeqCst, Ordering::SeqCst,
|
||||
atomic::Ordering::SeqCst, atomic::Ordering::SeqCst,
|
||||
|serial| serial.checked_add(1)
|
||||
).expect("Out of serial numbers for elements")
|
||||
}
|
||||
|
@ -73,6 +71,18 @@ impl PartialEq for dyn Serial {
|
|||
|
||||
impl Eq for dyn Serial {}
|
||||
|
||||
impl PartialOrd for dyn Serial {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for dyn Serial {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.serial().cmp(&other.serial())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ProblemPoser {
|
||||
fn pose(&self, problem: &mut ConstraintProblem);
|
||||
}
|
||||
|
@ -95,7 +105,7 @@ pub trait Element: Serial + ProblemPoser + DisplayItem {
|
|||
|
||||
// the regulators the element is subject to. the assembly that owns the
|
||||
// element is responsible for keeping this set up to date
|
||||
fn regulators(&self) -> Signal<Vec<Rc<dyn Regulator>>>;
|
||||
fn regulators(&self) -> Signal<BTreeSet<Rc<dyn Regulator>>>;
|
||||
|
||||
// the configuration matrix column index that was assigned to the element
|
||||
// last time the assembly was realized, or `None` if the element has never
|
||||
|
@ -128,12 +138,24 @@ impl PartialEq for dyn Element {
|
|||
|
||||
impl Eq for dyn Element {}
|
||||
|
||||
impl PartialOrd for dyn Element {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
<dyn Serial>::partial_cmp(self, other)
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for dyn Element {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
<dyn Serial>::cmp(self, other)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Sphere {
|
||||
pub id: String,
|
||||
pub label: String,
|
||||
pub color: ElementColor,
|
||||
pub representation: Signal<DVector<f64>>,
|
||||
pub regulators: Signal<Vec<Rc<dyn Regulator>>>,
|
||||
pub regulators: Signal<BTreeSet<Rc<dyn Regulator>>>,
|
||||
serial: u64,
|
||||
column_index: Cell<Option<usize>>
|
||||
}
|
||||
|
@ -152,7 +174,7 @@ impl Sphere {
|
|||
label: label,
|
||||
color: color,
|
||||
representation: create_signal(representation),
|
||||
regulators: create_signal(Vec::new()),
|
||||
regulators: create_signal(BTreeSet::new()),
|
||||
serial: Self::next_serial(),
|
||||
column_index: None.into()
|
||||
}
|
||||
|
@ -189,7 +211,7 @@ impl Element for Sphere {
|
|||
self.representation
|
||||
}
|
||||
|
||||
fn regulators(&self) -> Signal<Vec<Rc<dyn Regulator>>> {
|
||||
fn regulators(&self) -> Signal<BTreeSet<Rc<dyn Regulator>>> {
|
||||
self.regulators
|
||||
}
|
||||
|
||||
|
@ -223,7 +245,7 @@ pub struct Point {
|
|||
pub label: String,
|
||||
pub color: ElementColor,
|
||||
pub representation: Signal<DVector<f64>>,
|
||||
pub regulators: Signal<Vec<Rc<dyn Regulator>>>,
|
||||
pub regulators: Signal<BTreeSet<Rc<dyn Regulator>>>,
|
||||
serial: u64,
|
||||
column_index: Cell<Option<usize>>
|
||||
}
|
||||
|
@ -242,7 +264,7 @@ impl Point {
|
|||
label,
|
||||
color,
|
||||
representation: create_signal(representation),
|
||||
regulators: create_signal(Vec::new()),
|
||||
regulators: create_signal(BTreeSet::new()),
|
||||
serial: Self::next_serial(),
|
||||
column_index: None.into()
|
||||
}
|
||||
|
@ -275,7 +297,7 @@ impl Element for Point {
|
|||
self.representation
|
||||
}
|
||||
|
||||
fn regulators(&self) -> Signal<Vec<Rc<dyn Regulator>>> {
|
||||
fn regulators(&self) -> Signal<BTreeSet<Rc<dyn Regulator>>> {
|
||||
self.regulators
|
||||
}
|
||||
|
||||
|
@ -335,6 +357,18 @@ impl PartialEq for dyn Regulator {
|
|||
|
||||
impl Eq for dyn Regulator {}
|
||||
|
||||
impl PartialOrd for dyn Regulator {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
<dyn Serial>::partial_cmp(self, other)
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for dyn Regulator {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
<dyn Serial>::cmp(self, other)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct InversiveDistanceRegulator {
|
||||
pub subjects: [Rc<dyn Element>; 2],
|
||||
pub measurement: ReadSignal<f64>,
|
||||
|
@ -472,8 +506,8 @@ type AssemblyMotion<'a> = Vec<ElementMotion<'a>>;
|
|||
#[derive(Clone)]
|
||||
pub struct Assembly {
|
||||
// elements and regulators
|
||||
pub elements: Signal<Slab<Rc<dyn Element>>>,
|
||||
pub regulators: Signal<Slab<Rc<dyn Regulator>>>,
|
||||
pub elements: Signal<BTreeSet<Rc<dyn Element>>>,
|
||||
pub regulators: Signal<BTreeSet<Rc<dyn Regulator>>>,
|
||||
|
||||
// solution variety tangent space. the basis vectors are stored in
|
||||
// configuration matrix format, ordered according to the elements' column
|
||||
|
@ -494,8 +528,8 @@ pub struct Assembly {
|
|||
impl Assembly {
|
||||
pub fn new() -> Assembly {
|
||||
Assembly {
|
||||
elements: create_signal(Slab::new()),
|
||||
regulators: create_signal(Slab::new()),
|
||||
elements: create_signal(BTreeSet::new()),
|
||||
regulators: create_signal(BTreeSet::new()),
|
||||
tangent: create_signal(ConfigSubspace::zero(0)),
|
||||
elements_by_id: create_signal(FxHashMap::default())
|
||||
}
|
||||
|
@ -506,30 +540,27 @@ impl Assembly {
|
|||
// 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: impl Element + 'static) -> ElementKey {
|
||||
fn insert_element_unchecked(&self, elt: impl Element + 'static) {
|
||||
// insert the element
|
||||
let id = elt.id().clone();
|
||||
let elt_rc = Rc::new(elt);
|
||||
let key = self.elements.update(|elts| elts.insert(elt_rc.clone()));
|
||||
self.elements.update(|elts| elts.insert(elt_rc.clone()));
|
||||
self.elements_by_id.update(|elts_by_id| elts_by_id.insert(id, elt_rc.clone()));
|
||||
|
||||
// create and insert the element's default regulators
|
||||
for reg in elt_rc.default_regulators() {
|
||||
self.insert_regulator(reg);
|
||||
}
|
||||
|
||||
key
|
||||
}
|
||||
|
||||
pub fn try_insert_element(&self, elt: impl Element + 'static) -> Option<ElementKey> {
|
||||
pub fn try_insert_element(&self, elt: impl Element + 'static) -> bool {
|
||||
let can_insert = self.elements_by_id.with_untracked(
|
||||
|elts_by_id| !elts_by_id.contains_key(elt.id())
|
||||
);
|
||||
if can_insert {
|
||||
Some(self.insert_element_unchecked(elt))
|
||||
} else {
|
||||
None
|
||||
self.insert_element_unchecked(elt);
|
||||
}
|
||||
can_insert
|
||||
}
|
||||
|
||||
pub fn insert_element_default<T: Element + 'static>(&self) {
|
||||
|
@ -559,7 +590,7 @@ impl Assembly {
|
|||
|subj| subj.regulators()
|
||||
).collect();
|
||||
for regulators in subject_regulators {
|
||||
regulators.update(|regs| regs.push(regulator.clone()));
|
||||
regulators.update(|regs| regs.insert(regulator.clone()));
|
||||
}
|
||||
|
||||
// update the realization when the regulator becomes a constraint, or is
|
||||
|
@ -581,7 +612,7 @@ impl Assembly {
|
|||
// print an updated list of regulators
|
||||
console::log_1(&JsValue::from("Regulators:"));
|
||||
self.regulators.with_untracked(|regs| {
|
||||
for (_, reg) in regs.into_iter() {
|
||||
for reg in regs.into_iter() {
|
||||
console::log_1(&JsValue::from(format!(
|
||||
" {:?}: {}",
|
||||
reg.subjects(),
|
||||
|
@ -605,7 +636,7 @@ impl Assembly {
|
|||
pub fn realize(&self) {
|
||||
// index the elements
|
||||
self.elements.update_silent(|elts| {
|
||||
for (index, (_, elt)) in elts.into_iter().enumerate() {
|
||||
for (index, elt) in elts.iter().enumerate() {
|
||||
elt.set_column_index(index);
|
||||
}
|
||||
});
|
||||
|
@ -613,11 +644,11 @@ impl Assembly {
|
|||
// set up the constraint problem
|
||||
let problem = self.elements.with_untracked(|elts| {
|
||||
let mut problem = ConstraintProblem::new(elts.len());
|
||||
for (_, elt) in elts {
|
||||
for elt in elts {
|
||||
elt.pose(&mut problem);
|
||||
}
|
||||
self.regulators.with_untracked(|regs| {
|
||||
for (_, reg) in regs {
|
||||
for reg in regs {
|
||||
reg.pose(&mut problem);
|
||||
}
|
||||
});
|
||||
|
@ -660,7 +691,7 @@ impl Assembly {
|
|||
|
||||
if success {
|
||||
// read out the solution
|
||||
for (_, elt) in self.elements.get_clone_untracked() {
|
||||
for elt in self.elements.get_clone_untracked() {
|
||||
elt.representation().update(
|
||||
|rep| rep.set_column(0, &config.column(elt.column_index().unwrap()))
|
||||
);
|
||||
|
@ -741,7 +772,7 @@ impl Assembly {
|
|||
// normalizations, so we restore those afterward
|
||||
/* KLUDGE */
|
||||
// for now, we only restore the normalizations of spheres
|
||||
for (_, elt) in self.elements.get_clone_untracked() {
|
||||
for elt in self.elements.get_clone_untracked() {
|
||||
elt.representation().update_silent(|rep| {
|
||||
match elt.column_index() {
|
||||
Some(column_index) => {
|
||||
|
|
|
@ -363,7 +363,7 @@ pub fn Display() -> View {
|
|||
let scene_changed = create_signal(true);
|
||||
create_effect(move || {
|
||||
state.assembly.elements.with(|elts| {
|
||||
for (_, elt) in elts {
|
||||
for elt in elts {
|
||||
elt.representation().track();
|
||||
}
|
||||
});
|
||||
|
@ -616,7 +616,7 @@ pub fn Display() -> View {
|
|||
|
||||
// set up the scene
|
||||
state.assembly.elements.with_untracked(
|
||||
|elts| for (_, elt) in elts {
|
||||
|elts| for elt in elts {
|
||||
let selected = state.selection.with(|sel| sel.contains(elt));
|
||||
elt.show(&mut scene, selected);
|
||||
}
|
||||
|
@ -851,7 +851,7 @@ pub fn Display() -> View {
|
|||
let (dir, pixel_size) = event_dir(&event);
|
||||
console::log_1(&JsValue::from(dir.to_string()));
|
||||
let mut clicked: Option<(Rc<dyn Element>, f64)> = None;
|
||||
for (_, elt) in state.assembly.elements.get_clone_untracked() {
|
||||
for elt in state.assembly.elements.get_clone_untracked() {
|
||||
match assembly_to_world.with(|asm_to_world| elt.cast(dir, asm_to_world, pixel_size)) {
|
||||
Some(depth) => match clicked {
|
||||
Some((_, best_depth)) => {
|
||||
|
|
|
@ -228,11 +228,15 @@ pub fn Outline() -> View {
|
|||
let state = use_context::<AppState>();
|
||||
|
||||
// list the elements alphabetically by ID
|
||||
/* TO DO */
|
||||
// this code is designed to generalize easily to other sort keys. if we only
|
||||
// ever wanted to sort by ID, we could do that more simply using the
|
||||
// `elements_by_id` index
|
||||
let element_list = state.assembly.elements.map(
|
||||
|elts| elts
|
||||
.clone()
|
||||
.into_iter()
|
||||
.sorted_by_key(|(_, elt)| elt.id().clone())
|
||||
.sorted_by_key(|elt| elt.id().clone())
|
||||
.collect()
|
||||
);
|
||||
|
||||
|
@ -246,10 +250,10 @@ pub fn Outline() -> View {
|
|||
) {
|
||||
Keyed(
|
||||
list=element_list,
|
||||
view=|(_, elt)| view! {
|
||||
view=|elt| view! {
|
||||
ElementOutlineItem(element=elt)
|
||||
},
|
||||
key=|(_, elt)| elt.serial()
|
||||
key=|elt| elt.serial()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue