diff --git a/app-proto/full-interface/src/add_remove.rs b/app-proto/full-interface/src/add_remove.rs index 40b0e98..59220ae 100644 --- a/app-proto/full-interface/src/add_remove.rs +++ b/app-proto/full-interface/src/add_remove.rs @@ -1,227 +1,21 @@ -use std::collections::BTreeSet; /* DEBUG */ use sycamore::prelude::*; -use web_sys::{console, wasm_bindgen::JsValue}; +use web_sys::{MouseEvent, console, wasm_bindgen::JsValue}; -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], - rep: engine::sphere(0.5, 0.5, 0.0, 1.0), - constraints: BTreeSet::default() - } - ); - 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], - rep: engine::sphere(-0.5, -0.5, 0.0, 1.0), - constraints: BTreeSet::default() - } - ); - 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], - rep: engine::sphere(-0.5, 0.5, 0.0, 0.75), - constraints: BTreeSet::default() - } - ); - 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], - rep: engine::sphere(0.5, -0.5, 0.0, 0.5), - constraints: BTreeSet::default() - } - ); - 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], - rep: engine::sphere(0.0, 0.15, 1.0, 0.25), - constraints: BTreeSet::default() - } - ); - 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], - rep: engine::sphere(0.0, -0.15, -1.0, 0.25), - constraints: BTreeSet::default() - } - ); - assembly.insert_constraint( - Constraint { - args: ( - assembly.elements_by_id.with_untracked(|elts_by_id| elts_by_id["gemini_a"]), - assembly.elements_by_id.with_untracked(|elts_by_id| elts_by_id["gemini_b"]) - ), - rep: 0.5 - } - ); -} - -/* DEBUG */ -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], - rep: engine::sphere(0.0, 0.0, 0.0, 1.0), - constraints: BTreeSet::default() - } - ); - 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], - rep: engine::sphere_with_offset(0.0, 0.0, 1.0, 0.0, 0.0), - constraints: BTreeSet::default() - } - ); - 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], - rep: engine::sphere_with_offset(1.0, 0.0, 0.0, 1.0, 0.0), - constraints: BTreeSet::default() - } - ); - 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], - rep: engine::sphere_with_offset(-0.5, a, 0.0, 1.0, 0.0), - constraints: BTreeSet::default() - } - ); - 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], - rep: engine::sphere_with_offset(-0.5, -a, 0.0, 1.0, 0.0), - constraints: BTreeSet::default() - } - ); - 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], - rep: engine::sphere(-4.0/3.0, 0.0, 0.0, 1.0/3.0), - constraints: BTreeSet::default() - } - ); - 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], - rep: engine::sphere(2.0/3.0, -4.0/3.0 * a, 0.0, 1.0/3.0), - constraints: BTreeSet::default() - } - ); - 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], - rep: engine::sphere(2.0/3.0, 4.0/3.0 * a, 0.0, 1.0/3.0), - constraints: BTreeSet::default() - } - ); -} +use crate::AppState; +use crate::Constraint; #[component] pub fn AddRemove() -> View { - /* DEBUG */ - let assembly_name = create_signal("general".to_string()); - create_effect(move || { - // get name of chosen assembly - let name = assembly_name.get_clone(); - console::log_1( - &JsValue::from(format!("Showing assembly \"{}\"", name.clone())) - ); - - batch(|| { - let state = use_context::(); - let assembly = &state.assembly; - - // clear state - assembly.elements.update(|elts| elts.clear()); - assembly.elements_by_id.update(|elts_by_id| elts_by_id.clear()); - state.selection.update(|sel| sel.clear()); - - // load assembly - match name.as_str() { - "general" => load_gen_assemb(assembly), - "low-curv" => load_low_curv_assemb(assembly), - _ => () - }; - }); - }); + let state = use_context::(); view! { div(id="add-remove") { button( - on:click=|_| { - let state = use_context::(); - 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::(); - state.selection.with(|sel| sel.len() != 2) - }, - on:click=|_| { - let state = use_context::(); - 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 + on:click=move |event: MouseEvent| { console::log_1(&JsValue::from("constraints:")); state.assembly.constraints.with(|csts| { for (_, cst) in csts.into_iter() { - console::log_5( - &JsValue::from(" "), + console::log_4( &JsValue::from(cst.args.0), &JsValue::from(cst.args.1), &JsValue::from(":"), @@ -230,11 +24,32 @@ pub fn AddRemove() -> View { } }); } + ) { "+" } + button( + disabled={ + state.selection.with(|sel| sel.len() != 2) + }, + on:click=move |event: MouseEvent| { + 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()); + } ) { "🔗" } - select(bind:value=assembly_name) { /* DEBUG */ - option(value="general") { "General" } - option(value="low-curv") { "Low-curvature" } - } } } } \ No newline at end of file diff --git a/app-proto/full-interface/src/assembly.rs b/app-proto/full-interface/src/assembly.rs index c0c9959..6fac59f 100644 --- a/app-proto/full-interface/src/assembly.rs +++ b/app-proto/full-interface/src/assembly.rs @@ -1,7 +1,6 @@ use nalgebra::DVector; -use rustc_hash::FxHashMap; +use rustc_hash::FxHashSet; use slab::Slab; -use std::collections::BTreeSet; use sycamore::prelude::*; #[derive(Clone, PartialEq)] @@ -10,7 +9,7 @@ pub struct Element { pub label: String, pub color: [f32; 3], pub rep: DVector, - pub constraints: BTreeSet + pub constraints: FxHashSet } #[derive(Clone)] @@ -22,65 +21,18 @@ pub struct Constraint { // 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> + pub constraints: 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()) + constraints: create_signal(Slab::new()) } } - // 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)); diff --git a/app-proto/full-interface/src/display.rs b/app-proto/full-interface/src/display.rs index c32b470..52b2ae9 100644 --- a/app-proto/full-interface/src/display.rs +++ b/app-proto/full-interface/src/display.rs @@ -98,12 +98,10 @@ pub fn Display() -> View { let roll_cw = create_signal(0.0); let zoom_in = create_signal(0.0); let zoom_out = create_signal(0.0); - let turntable = create_signal(false); /* BENCHMARKING */ // change listener let scene_changed = create_signal(true); create_effect(move || { - state.assembly.elements.track(); state.selection.track(); scene_changed.set(true); }); @@ -121,7 +119,6 @@ pub fn Display() -> View { // viewpoint const ROT_SPEED: f64 = 0.4; // in radians per second const ZOOM_SPEED: f64 = 0.15; // multiplicative rate per second - const TURNTABLE_SPEED: f64 = 0.1; /* BENCHMARKING */ let mut orientation = DMatrix::::identity(5, 5); let mut rotation = DMatrix::::identity(5, 5); let mut location_z: f64 = 5.0; @@ -244,7 +241,6 @@ pub fn Display() -> View { let roll_cw_val = roll_cw.get(); let zoom_in_val = zoom_in.get(); let zoom_out_val = zoom_out.get(); - let turntable_val = turntable.get(); /* BENCHMARKING */ // update the assembly's orientation let ang_vel = { @@ -256,10 +252,6 @@ pub fn Display() -> View { } else { Vector3::zeros() } - } /* BENCHMARKING */ + if turntable_val { - Vector3::new(0.0, TURNTABLE_SPEED, 0.0) - } else { - Vector3::zeros() }; let mut rotation_sp = rotation.fixed_view_mut::<3, 3>(0, 0); rotation_sp.copy_from( @@ -359,7 +351,6 @@ pub fn Display() -> View { || roll_ccw_val != 0.0 || zoom_in_val != 0.0 || zoom_out_val != 0.0 - || turntable_val /* BENCHMARKING */ ); } else { frames_since_last_sample = 0; @@ -409,10 +400,6 @@ pub fn Display() -> View { pitch_up.set(0.0); pitch_down.set(0.0); } else { - if event.key() == "Enter" { /* BENCHMARKING */ - turntable.set_fn(|turn| !turn); - scene_changed.set(true); - } set_nav_signal(event, 1.0); } }, diff --git a/app-proto/full-interface/src/engine.rs b/app-proto/full-interface/src/engine.rs deleted file mode 100644 index 79668bb..0000000 --- a/app-proto/full-interface/src/engine.rs +++ /dev/null @@ -1,27 +0,0 @@ -use nalgebra::DVector; - -// the sphere with the given center and radius, with inward-pointing normals -pub fn sphere(center_x: f64, center_y: f64, center_z: f64, radius: f64) -> DVector { - let center_norm_sq = center_x * center_x + center_y * center_y + center_z * center_z; - DVector::from_column_slice(&[ - center_x / radius, - center_y / radius, - center_z / radius, - 0.5 / radius, - 0.5 * (center_norm_sq / radius - radius) - ]) -} - -// the sphere of curvature `curv` whose closest point to the origin has position -// `off * dir` and normal `dir`, where `dir` is a unit vector. setting the -// curvature to zero gives a plane -pub fn sphere_with_offset(dir_x: f64, dir_y: f64, dir_z: f64, off: f64, curv: f64) -> DVector { - let norm_sp = 1.0 + off * curv; - DVector::from_column_slice(&[ - norm_sp * dir_x, - norm_sp * dir_y, - norm_sp * dir_z, - 0.5 * curv, - off * (1.0 + 0.5 * off * curv) - ]) -} \ No newline at end of file diff --git a/app-proto/full-interface/src/main.rs b/app-proto/full-interface/src/main.rs index 2c71a83..2f31ada 100644 --- a/app-proto/full-interface/src/main.rs +++ b/app-proto/full-interface/src/main.rs @@ -1,14 +1,14 @@ mod add_remove; mod assembly; mod display; -mod engine; mod outline; +use nalgebra::DVector; use rustc_hash::FxHashSet; use sycamore::prelude::*; use add_remove::AddRemove; -use assembly::Assembly; +use assembly::{Assembly, Constraint, Element}; use display::Display; use outline::Outline; @@ -29,7 +29,45 @@ impl AppState { fn main() { sycamore::render(|| { - provide_context(AppState::new()); + let state = AppState::new(); + let key_a = state.assembly.elements.update( + |elts| elts.insert( + Element { + id: String::from("wing_a"), + label: String::from("Wing A"), + color: [1.00_f32, 0.25_f32, 0.00_f32], + rep: DVector::::from_column_slice(&[0.5, 0.5, 0.0, 0.5, -0.25]), + constraints: FxHashSet::default() + } + ) + ); + let key_b = state.assembly.elements.update( + |elts| elts.insert( + Element { + id: String::from("wing_b"), + label: String::from("Wing B"), + color: [0.00_f32, 0.25_f32, 1.00_f32], + rep: DVector::::from_column_slice(&[-0.5, -0.5, 0.0, 0.5, -0.25]), + constraints: FxHashSet::default() + }, + ) + ); + state.assembly.elements.update( + |elts| elts.insert( + Element { + id: String::from("central"), + label: String::from("Central"), + color: [0.75_f32, 0.75_f32, 0.75_f32], + rep: DVector::::from_column_slice(&[0.0, 0.0, 0.0, 0.4, -0.625]), + constraints: FxHashSet::default() + } + ) + ); + state.assembly.insert_constraint(Constraint { + args: (key_a, key_b), + rep: 0.5 + }); + provide_context(state); view! { div(id="sidebar") { diff --git a/app-proto/full-interface/src/outline.rs b/app-proto/full-interface/src/outline.rs index c980887..be5a9b1 100644 --- a/app-proto/full-interface/src/outline.rs +++ b/app-proto/full-interface/src/outline.rs @@ -148,12 +148,7 @@ pub fn Outline() -> View { } } }, - key=|(key, elt)| ( - key.clone(), - elt.id.clone(), - elt.label.clone(), - elt.constraints.clone() - ) + key=|(key, _)| key.clone() ) } }