feat: Application prototype (#14)
Creates a prototype user interface for dyna3 in the `app-proto` folder. The interface is dynamically constructed using [Sycamore](https://sycamore.dev). The prototype includes: * An application state model (the `AppState` type) * A constraint problem model (the `Assembly` type), used in the application state * Two views * A 3D rendering of the assembly (the `Display` component) * A list of elements and constraints (the `Outline` component) The following features confirm that the views can reflect and send input to the model: * You can select elements by clicking and shift-clicking them in the outline. The selected elements are highlighted in the display. * You can add elements using a button above the outline. The new elements appear in the display. Co-authored-by: Aaron Fenyes <aaron.fenyes@fareycircles.ooo> Reviewed-on: glen/dyna3#14 Co-authored-by: Vectornaut <vectornaut@nobody@nowhere.net> Co-committed-by: Vectornaut <vectornaut@nobody@nowhere.net>
This commit is contained in:
parent
b92be312e8
commit
86fa682b31
12 changed files with 1428 additions and 0 deletions
242
app-proto/src/add_remove.rs
Normal file
242
app-proto/src/add_remove.rs
Normal file
|
@ -0,0 +1,242 @@
|
|||
use std::collections::BTreeSet; /* DEBUG */
|
||||
use sycamore::prelude::*;
|
||||
use web_sys::{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,
|
||||
active: create_signal(true)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/* 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()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[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(
|
||||
disabled={
|
||||
let state = use_context::<AppState>();
|
||||
state.selection.with(|sel| sel.len() != 2)
|
||||
},
|
||||
on:click=|_| {
|
||||
let state = use_context::<AppState>();
|
||||
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,
|
||||
active: create_signal(true)
|
||||
});
|
||||
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.args.0),
|
||||
&JsValue::from(cst.args.1),
|
||||
&JsValue::from(":"),
|
||||
&JsValue::from(cst.rep)
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
) { "🔗" }
|
||||
select(bind:value=assembly_name) { /* DEBUG */
|
||||
option(value="general") { "General" }
|
||||
option(value="low-curv") { "Low-curvature" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue