forked from StudioInfinity/dyna3
258 lines
No EOL
9 KiB
Rust
258 lines
No EOL
9 KiB
Rust
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::<AppState>();
|
|
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::<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(
|
|
class="emoji", /* KLUDGE */ // for convenience, we're using an emoji as a temporary icon for this button
|
|
disabled={
|
|
let state = use_context::<AppState>();
|
|
state.selection.with(|sel| sel.len() != 2)
|
|
},
|
|
on:click=|_| {
|
|
let state = use_context::<AppState>();
|
|
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" }
|
|
}
|
|
}
|
|
}
|
|
} |