use sycamore::prelude::*; use web_sys::{console, wasm_bindgen::JsValue}; use crate::{ engine, AppState, assembly::{ Assembly, Constraint, ConstraintRole, Element }, engine::Q }; /* DEBUG */ // load an example assembly for testing. this code will be removed once we've // built a more formal test assembly system 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) ) ); 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) ) ); 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) ) ); 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) ) ); 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) ) ); 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) ) ); } /* DEBUG */ // load an example assembly for testing. this code will be removed once we've // built a more formal test assembly system 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) ) ); 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) ) ); 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) ) ); 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) ) ); 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) ) ); 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) ) ); 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) ) ); 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) ) ); } #[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), _ => () }; }); }); 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( class="emoji", /* KLUDGE */ // for convenience, we're using an emoji as a temporary icon for this button disabled={ let state = use_context::(); state.selection.with(|sel| sel.len() != 2) }, on:click=|_| { let state = use_context::(); let subjects = state.selection.with( |sel| { let subject_vec: Vec<_> = sel.into_iter().collect(); (subject_vec[0].clone(), subject_vec[1].clone()) } ); let measured = state.assembly.elements.map( move |elts| { let reps = ( elts[subjects.0].representation.get_clone(), elts[subjects.1].representation.get_clone() ); reps.0.dot(&(&*Q * reps.1)) } ); let desired = create_signal(0.0); let role = create_signal(ConstraintRole::Measure); state.assembly.insert_constraint(Constraint { subjects: subjects, measured: measured, desired: desired, desired_text: create_signal(String::new()), role: role, }); state.selection.update(|sel| sel.clear()); /* DEBUG */ // print updated constraint list console::log_1(&JsValue::from("Constraints:")); state.assembly.constraints.with(|csts| { for (_, cst) in csts.into_iter() { console::log_5( &JsValue::from(" "), &JsValue::from(cst.subjects.0), &JsValue::from(cst.subjects.1), &JsValue::from(":"), &JsValue::from(cst.desired.get_untracked()) ); } }); // update the realization when the observable becomes // constrained, or is edited while constrained create_effect(move || { console::log_1(&JsValue::from( format!("Constraint ({}, {}) updated", subjects.0, subjects.1) )); desired.track(); if role.with(|r| matches!(r, ConstraintRole::Constrain)) { state.assembly.realize(); } }); } ) { "🔗" } select(bind:value=assembly_name) { /* DEBUG */ // example assembly chooser option(value="general") { "General" } option(value="low-curv") { "Low-curvature" } option(value="empty") { "Empty" } } } } }