feat: Curvature regulators (#80)
All checks were successful
/ test (push) Successful in 2m21s

Prior to this commit, there's only one kind of regulator: the one that regulates the inversive distance between two spheres (or, more generally, the Lorentz product between two element representation vectors). Adds a new kind of regulator, which regulates the curvature of a sphere (issue #55). In the process, introduces a general framework based on new traits for organizing and sharing code between different kinds of regulators.

Co-authored-by: Aaron Fenyes <aaron.fenyes@fareycircles.ooo>
Reviewed-on: #80
Co-authored-by: Vectornaut <vectornaut@nobody@nowhere.net>
Co-committed-by: Vectornaut <vectornaut@nobody@nowhere.net>
This commit is contained in:
Vectornaut 2025-04-21 23:40:42 +00:00 committed by Glen Whitney
parent 23ba5acad7
commit 360ce12d8b
6 changed files with 640 additions and 331 deletions

View file

@ -4,14 +4,14 @@ use web_sys::{console, wasm_bindgen::JsValue};
use crate::{
engine,
AppState,
assembly::{Assembly, Element}
assembly::{Assembly, Element, InversiveDistanceRegulator}
};
/* 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(
let _ = assembly.try_insert_sphere(
Element::new(
String::from("gemini_a"),
String::from("Castor"),
@ -19,7 +19,7 @@ fn load_gen_assemb(assembly: &Assembly) {
engine::sphere(0.5, 0.5, 0.0, 1.0)
)
);
let _ = assembly.try_insert_element(
let _ = assembly.try_insert_sphere(
Element::new(
String::from("gemini_b"),
String::from("Pollux"),
@ -27,7 +27,7 @@ fn load_gen_assemb(assembly: &Assembly) {
engine::sphere(-0.5, -0.5, 0.0, 1.0)
)
);
let _ = assembly.try_insert_element(
let _ = assembly.try_insert_sphere(
Element::new(
String::from("ursa_major"),
String::from("Ursa major"),
@ -35,7 +35,7 @@ fn load_gen_assemb(assembly: &Assembly) {
engine::sphere(-0.5, 0.5, 0.0, 0.75)
)
);
let _ = assembly.try_insert_element(
let _ = assembly.try_insert_sphere(
Element::new(
String::from("ursa_minor"),
String::from("Ursa minor"),
@ -43,7 +43,7 @@ fn load_gen_assemb(assembly: &Assembly) {
engine::sphere(0.5, -0.5, 0.0, 0.5)
)
);
let _ = assembly.try_insert_element(
let _ = assembly.try_insert_sphere(
Element::new(
String::from("moon_deimos"),
String::from("Deimos"),
@ -51,7 +51,7 @@ fn load_gen_assemb(assembly: &Assembly) {
engine::sphere(0.0, 0.15, 1.0, 0.25)
)
);
let _ = assembly.try_insert_element(
let _ = assembly.try_insert_sphere(
Element::new(
String::from("moon_phobos"),
String::from("Phobos"),
@ -66,7 +66,7 @@ fn load_gen_assemb(assembly: &Assembly) {
// 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(
let _ = assembly.try_insert_sphere(
Element::new(
"central".to_string(),
"Central".to_string(),
@ -74,7 +74,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
engine::sphere(0.0, 0.0, 0.0, 1.0)
)
);
let _ = assembly.try_insert_element(
let _ = assembly.try_insert_sphere(
Element::new(
"assemb_plane".to_string(),
"Assembly plane".to_string(),
@ -82,7 +82,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
engine::sphere_with_offset(0.0, 0.0, 1.0, 0.0, 0.0)
)
);
let _ = assembly.try_insert_element(
let _ = assembly.try_insert_sphere(
Element::new(
"side1".to_string(),
"Side 1".to_string(),
@ -90,7 +90,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
engine::sphere_with_offset(1.0, 0.0, 0.0, 1.0, 0.0)
)
);
let _ = assembly.try_insert_element(
let _ = assembly.try_insert_sphere(
Element::new(
"side2".to_string(),
"Side 2".to_string(),
@ -98,7 +98,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
engine::sphere_with_offset(-0.5, a, 0.0, 1.0, 0.0)
)
);
let _ = assembly.try_insert_element(
let _ = assembly.try_insert_sphere(
Element::new(
"side3".to_string(),
"Side 3".to_string(),
@ -106,7 +106,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
engine::sphere_with_offset(-0.5, -a, 0.0, 1.0, 0.0)
)
);
let _ = assembly.try_insert_element(
let _ = assembly.try_insert_sphere(
Element::new(
"corner1".to_string(),
"Corner 1".to_string(),
@ -114,7 +114,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
engine::sphere(-4.0/3.0, 0.0, 0.0, 1.0/3.0)
)
);
let _ = assembly.try_insert_element(
let _ = assembly.try_insert_sphere(
Element::new(
"corner2".to_string(),
"Corner 2".to_string(),
@ -122,7 +122,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
engine::sphere(2.0/3.0, -4.0/3.0 * a, 0.0, 1.0/3.0)
)
);
let _ = assembly.try_insert_element(
let _ = assembly.try_insert_sphere(
Element::new(
String::from("corner3"),
String::from("Corner 3"),
@ -148,6 +148,7 @@ pub fn AddRemove() -> View {
let assembly = &state.assembly;
// clear state
assembly.regulators.update(|regs| regs.clear());
assembly.elements.update(|elts| elts.clear());
assembly.elements_by_id.update(|elts_by_id| elts_by_id.clear());
state.selection.update(|sel| sel.clear());
@ -166,18 +167,7 @@ pub fn AddRemove() -> View {
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)
);
}
state.assembly.insert_new_sphere();
}
) { "+" }
button(
@ -188,13 +178,20 @@ pub fn AddRemove() -> View {
},
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 subjects: [_; 2] = state.selection.with(
// the button is only enabled when two elements are
// selected, so we know the cast to a two-element array
// will succeed
|sel| sel
.clone()
.into_iter()
.collect::<Vec<_>>()
.try_into()
.unwrap()
);
state.assembly.insert_regulator(
InversiveDistanceRegulator::new(subjects, &state.assembly)
);
state.assembly.insert_new_regulator(subjects);
state.selection.update(|sel| sel.clear());
}
) { "🔗" }