Rename the Element structure to Sphere

This makes way for an `Element` trait. Some `Sphere` variables, like the
arguments of the sphere insertion methods, have been renamed to show
that they refer specifically to spheres. Others, like the argument of
`ElementOutlineItem`, have kept their general names, because I expect
them to become `Element` trait objects.
This commit is contained in:
Aaron Fenyes 2025-04-23 01:01:59 -07:00
parent 68abc2ad44
commit a1e23543cb
4 changed files with 41 additions and 41 deletions

View file

@ -4,7 +4,7 @@ use web_sys::{console, wasm_bindgen::JsValue};
use crate::{ use crate::{
engine, engine,
AppState, AppState,
assembly::{Assembly, Element, InversiveDistanceRegulator} assembly::{Assembly, InversiveDistanceRegulator, Sphere}
}; };
/* DEBUG */ /* DEBUG */
@ -12,7 +12,7 @@ use crate::{
// built a more formal test assembly system // built a more formal test assembly system
fn load_gen_assemb(assembly: &Assembly) { fn load_gen_assemb(assembly: &Assembly) {
let _ = assembly.try_insert_sphere( let _ = assembly.try_insert_sphere(
Element::new( Sphere::new(
String::from("gemini_a"), String::from("gemini_a"),
String::from("Castor"), String::from("Castor"),
[1.00_f32, 0.25_f32, 0.00_f32], [1.00_f32, 0.25_f32, 0.00_f32],
@ -20,7 +20,7 @@ fn load_gen_assemb(assembly: &Assembly) {
) )
); );
let _ = assembly.try_insert_sphere( let _ = assembly.try_insert_sphere(
Element::new( Sphere::new(
String::from("gemini_b"), String::from("gemini_b"),
String::from("Pollux"), String::from("Pollux"),
[0.00_f32, 0.25_f32, 1.00_f32], [0.00_f32, 0.25_f32, 1.00_f32],
@ -28,7 +28,7 @@ fn load_gen_assemb(assembly: &Assembly) {
) )
); );
let _ = assembly.try_insert_sphere( let _ = assembly.try_insert_sphere(
Element::new( Sphere::new(
String::from("ursa_major"), String::from("ursa_major"),
String::from("Ursa major"), String::from("Ursa major"),
[0.25_f32, 0.00_f32, 1.00_f32], [0.25_f32, 0.00_f32, 1.00_f32],
@ -36,7 +36,7 @@ fn load_gen_assemb(assembly: &Assembly) {
) )
); );
let _ = assembly.try_insert_sphere( let _ = assembly.try_insert_sphere(
Element::new( Sphere::new(
String::from("ursa_minor"), String::from("ursa_minor"),
String::from("Ursa minor"), String::from("Ursa minor"),
[0.25_f32, 1.00_f32, 0.00_f32], [0.25_f32, 1.00_f32, 0.00_f32],
@ -44,7 +44,7 @@ fn load_gen_assemb(assembly: &Assembly) {
) )
); );
let _ = assembly.try_insert_sphere( let _ = assembly.try_insert_sphere(
Element::new( Sphere::new(
String::from("moon_deimos"), String::from("moon_deimos"),
String::from("Deimos"), String::from("Deimos"),
[0.75_f32, 0.75_f32, 0.00_f32], [0.75_f32, 0.75_f32, 0.00_f32],
@ -52,7 +52,7 @@ fn load_gen_assemb(assembly: &Assembly) {
) )
); );
let _ = assembly.try_insert_sphere( let _ = assembly.try_insert_sphere(
Element::new( Sphere::new(
String::from("moon_phobos"), String::from("moon_phobos"),
String::from("Phobos"), String::from("Phobos"),
[0.00_f32, 0.75_f32, 0.50_f32], [0.00_f32, 0.75_f32, 0.50_f32],
@ -67,7 +67,7 @@ fn load_gen_assemb(assembly: &Assembly) {
fn load_low_curv_assemb(assembly: &Assembly) { fn load_low_curv_assemb(assembly: &Assembly) {
let a = 0.75_f64.sqrt(); let a = 0.75_f64.sqrt();
let _ = assembly.try_insert_sphere( let _ = assembly.try_insert_sphere(
Element::new( Sphere::new(
"central".to_string(), "central".to_string(),
"Central".to_string(), "Central".to_string(),
[0.75_f32, 0.75_f32, 0.75_f32], [0.75_f32, 0.75_f32, 0.75_f32],
@ -75,7 +75,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
) )
); );
let _ = assembly.try_insert_sphere( let _ = assembly.try_insert_sphere(
Element::new( Sphere::new(
"assemb_plane".to_string(), "assemb_plane".to_string(),
"Assembly plane".to_string(), "Assembly plane".to_string(),
[0.75_f32, 0.75_f32, 0.75_f32], [0.75_f32, 0.75_f32, 0.75_f32],
@ -83,7 +83,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
) )
); );
let _ = assembly.try_insert_sphere( let _ = assembly.try_insert_sphere(
Element::new( Sphere::new(
"side1".to_string(), "side1".to_string(),
"Side 1".to_string(), "Side 1".to_string(),
[1.00_f32, 0.00_f32, 0.25_f32], [1.00_f32, 0.00_f32, 0.25_f32],
@ -91,7 +91,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
) )
); );
let _ = assembly.try_insert_sphere( let _ = assembly.try_insert_sphere(
Element::new( Sphere::new(
"side2".to_string(), "side2".to_string(),
"Side 2".to_string(), "Side 2".to_string(),
[0.25_f32, 1.00_f32, 0.00_f32], [0.25_f32, 1.00_f32, 0.00_f32],
@ -99,7 +99,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
) )
); );
let _ = assembly.try_insert_sphere( let _ = assembly.try_insert_sphere(
Element::new( Sphere::new(
"side3".to_string(), "side3".to_string(),
"Side 3".to_string(), "Side 3".to_string(),
[0.00_f32, 0.25_f32, 1.00_f32], [0.00_f32, 0.25_f32, 1.00_f32],
@ -107,7 +107,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
) )
); );
let _ = assembly.try_insert_sphere( let _ = assembly.try_insert_sphere(
Element::new( Sphere::new(
"corner1".to_string(), "corner1".to_string(),
"Corner 1".to_string(), "Corner 1".to_string(),
[0.75_f32, 0.75_f32, 0.75_f32], [0.75_f32, 0.75_f32, 0.75_f32],
@ -115,7 +115,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
) )
); );
let _ = assembly.try_insert_sphere( let _ = assembly.try_insert_sphere(
Element::new( Sphere::new(
"corner2".to_string(), "corner2".to_string(),
"Corner 2".to_string(), "Corner 2".to_string(),
[0.75_f32, 0.75_f32, 0.75_f32], [0.75_f32, 0.75_f32, 0.75_f32],
@ -123,7 +123,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
) )
); );
let _ = assembly.try_insert_sphere( let _ = assembly.try_insert_sphere(
Element::new( Sphere::new(
String::from("corner3"), String::from("corner3"),
String::from("Corner 3"), String::from("Corner 3"),
[0.75_f32, 0.75_f32, 0.75_f32], [0.75_f32, 0.75_f32, 0.75_f32],

View file

@ -33,11 +33,11 @@ pub type ElementColor = [f32; 3];
static NEXT_ELEMENT_SERIAL: AtomicU64 = AtomicU64::new(0); static NEXT_ELEMENT_SERIAL: AtomicU64 = AtomicU64::new(0);
pub trait ProblemPoser { pub trait ProblemPoser {
fn pose(&self, problem: &mut ConstraintProblem, elts: &Slab<Element>); fn pose(&self, problem: &mut ConstraintProblem, elts: &Slab<Sphere>);
} }
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
pub struct Element { pub struct Sphere {
pub id: String, pub id: String,
pub label: String, pub label: String,
pub color: ElementColor, pub color: ElementColor,
@ -57,7 +57,7 @@ pub struct Element {
column_index: Option<usize> column_index: Option<usize>
} }
impl Element { impl Sphere {
const CURVATURE_COMPONENT: usize = 3; const CURVATURE_COMPONENT: usize = 3;
pub fn new( pub fn new(
@ -65,7 +65,7 @@ impl Element {
label: String, label: String,
color: ElementColor, color: ElementColor,
representation: DVector<f64> representation: DVector<f64>
) -> Element { ) -> Sphere {
// take the next serial number, panicking if that was the last number we // take the next serial number, panicking if that was the last number we
// had left. the technique we use to panic on overflow is taken from // had left. the technique we use to panic on overflow is taken from
// _Rust Atomics and Locks_, by Mara Bos // _Rust Atomics and Locks_, by Mara Bos
@ -77,7 +77,7 @@ impl Element {
|serial| serial.checked_add(1) |serial| serial.checked_add(1)
).expect("Out of serial numbers for elements"); ).expect("Out of serial numbers for elements");
Element { Sphere {
id: id, id: id,
label: label, label: label,
color: color, color: color,
@ -132,10 +132,10 @@ impl Element {
} }
} }
impl ProblemPoser for Element { impl ProblemPoser for Sphere {
fn pose(&self, problem: &mut ConstraintProblem, _elts: &Slab<Element>) { fn pose(&self, problem: &mut ConstraintProblem, _elts: &Slab<Sphere>) {
let index = self.column_index.expect( let index = self.column_index.expect(
format!("Element \"{}\" should be indexed before writing problem data", self.id).as_str() format!("Sphere \"{}\" should be indexed before writing problem data", self.id).as_str()
); );
problem.gram.push_sym(index, index, 1.0); problem.gram.push_sym(index, index, 1.0);
problem.guess.set_column(index, &self.representation.get_clone_untracked()); problem.guess.set_column(index, &self.representation.get_clone_untracked());
@ -198,7 +198,7 @@ impl Regulator for InversiveDistanceRegulator {
} }
impl ProblemPoser for InversiveDistanceRegulator { impl ProblemPoser for InversiveDistanceRegulator {
fn pose(&self, problem: &mut ConstraintProblem, elts: &Slab<Element>) { fn pose(&self, problem: &mut ConstraintProblem, elts: &Slab<Sphere>) {
self.set_point.with_untracked(|set_pt| { self.set_point.with_untracked(|set_pt| {
if let Some(val) = set_pt.value { if let Some(val) = set_pt.value {
let [row, col] = self.subjects.map( let [row, col] = self.subjects.map(
@ -222,7 +222,7 @@ impl HalfCurvatureRegulator {
pub fn new(subject: ElementKey, assembly: &Assembly) -> HalfCurvatureRegulator { pub fn new(subject: ElementKey, assembly: &Assembly) -> HalfCurvatureRegulator {
let measurement = assembly.elements.map( let measurement = assembly.elements.map(
move |elts| elts[subject].representation.with( move |elts| elts[subject].representation.with(
|rep| rep[Element::CURVATURE_COMPONENT] |rep| rep[Sphere::CURVATURE_COMPONENT]
) )
); );
@ -262,13 +262,13 @@ impl Regulator for HalfCurvatureRegulator {
} }
impl ProblemPoser for HalfCurvatureRegulator { impl ProblemPoser for HalfCurvatureRegulator {
fn pose(&self, problem: &mut ConstraintProblem, elts: &Slab<Element>) { fn pose(&self, problem: &mut ConstraintProblem, elts: &Slab<Sphere>) {
self.set_point.with_untracked(|set_pt| { self.set_point.with_untracked(|set_pt| {
if let Some(val) = set_pt.value { if let Some(val) = set_pt.value {
let col = elts[self.subject].column_index.expect( let col = elts[self.subject].column_index.expect(
"Subject should be indexed before half-curvature regulator writes problem data" "Subject should be indexed before half-curvature regulator writes problem data"
); );
problem.frozen.push(Element::CURVATURE_COMPONENT, col, val); problem.frozen.push(Sphere::CURVATURE_COMPONENT, col, val);
} }
}); });
} }
@ -286,7 +286,7 @@ type AssemblyMotion<'a> = Vec<ElementMotion<'a>>;
#[derive(Clone)] #[derive(Clone)]
pub struct Assembly { pub struct Assembly {
// elements and regulators // elements and regulators
pub elements: Signal<Slab<Element>>, pub elements: Signal<Slab<Sphere>>,
pub regulators: Signal<Slab<Rc<dyn Regulator>>>, pub regulators: Signal<Slab<Rc<dyn Regulator>>>,
// solution variety tangent space. the basis vectors are stored in // solution variety tangent space. the basis vectors are stored in
@ -320,10 +320,10 @@ impl Assembly {
// insert a sphere into the assembly without checking whether we already // insert a sphere into the assembly without checking whether we already
// have an element with the same identifier. any element that does have the // 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 // same identifier will get kicked out of the `elements_by_id` index
fn insert_sphere_unchecked(&self, elt: Element) -> ElementKey { fn insert_sphere_unchecked(&self, sphere: Sphere) -> ElementKey {
// insert the sphere // insert the sphere
let id = elt.id.clone(); let id = sphere.id.clone();
let key = self.elements.update(|elts| elts.insert(elt)); let key = self.elements.update(|elts| elts.insert(sphere));
self.elements_by_id.update(|elts_by_id| elts_by_id.insert(id, key)); self.elements_by_id.update(|elts_by_id| elts_by_id.insert(id, key));
// regulate the sphere's curvature // regulate the sphere's curvature
@ -332,12 +332,12 @@ impl Assembly {
key key
} }
pub fn try_insert_sphere(&self, elt: Element) -> Option<ElementKey> { pub fn try_insert_sphere(&self, sphere: Sphere) -> Option<ElementKey> {
let can_insert = self.elements_by_id.with_untracked( let can_insert = self.elements_by_id.with_untracked(
|elts_by_id| !elts_by_id.contains_key(&elt.id) |elts_by_id| !elts_by_id.contains_key(&sphere.id)
); );
if can_insert { if can_insert {
Some(self.insert_sphere_unchecked(elt)) Some(self.insert_sphere_unchecked(sphere))
} else { } else {
None None
} }
@ -356,7 +356,7 @@ impl Assembly {
// create and insert a sphere // create and insert a sphere
let _ = self.insert_sphere_unchecked( let _ = self.insert_sphere_unchecked(
Element::new( Sphere::new(
id, id,
format!("Sphere {}", id_num), format!("Sphere {}", id_num),
[0.75_f32, 0.75_f32, 0.75_f32], [0.75_f32, 0.75_f32, 0.75_f32],
@ -607,10 +607,10 @@ mod tests {
use super::*; use super::*;
#[test] #[test]
#[should_panic(expected = "Element \"sphere\" should be indexed before writing problem data")] #[should_panic(expected = "Sphere \"sphere\" should be indexed before writing problem data")]
fn unindexed_element_test() { fn unindexed_element_test() {
let _ = create_root(|| { let _ = create_root(|| {
Element::new( Sphere::new(
"sphere".to_string(), "sphere".to_string(),
"Sphere".to_string(), "Sphere".to_string(),
[1.0_f32, 1.0_f32, 1.0_f32], [1.0_f32, 1.0_f32, 1.0_f32],
@ -626,7 +626,7 @@ mod tests {
let mut elts = Slab::new(); let mut elts = Slab::new();
let subjects = [0, 1].map(|k| { let subjects = [0, 1].map(|k| {
elts.insert( elts.insert(
Element::new( Sphere::new(
format!("sphere{k}"), format!("sphere{k}"),
format!("Sphere {k}"), format!("Sphere {k}"),
[1.0_f32, 1.0_f32, 1.0_f32], [1.0_f32, 1.0_f32, 1.0_f32],

View file

@ -14,7 +14,7 @@ use web_sys::{
wasm_bindgen::{JsCast, JsValue} wasm_bindgen::{JsCast, JsValue}
}; };
use crate::{AppState, assembly::{Element, ElementKey, ElementColor, ElementMotion}}; use crate::{AppState, assembly::{ElementKey, ElementColor, ElementMotion, Sphere}};
// --- scene data --- // --- scene data ---
@ -74,7 +74,7 @@ trait DisplayItem {
fn show(&self, scene: &mut Scene, selected: bool); fn show(&self, scene: &mut Scene, selected: bool);
} }
impl DisplayItem for Element { impl DisplayItem for Sphere {
fn show(&self, scene: &mut Scene, selected: bool) { fn show(&self, scene: &mut Scene, selected: bool) {
const HIGHLIGHT: f32 = 0.2; /* SCAFFOLDING */ const HIGHLIGHT: f32 = 0.2; /* SCAFFOLDING */
let representation = self.representation.get_clone_untracked(); let representation = self.representation.get_clone_untracked();

View file

@ -141,7 +141,7 @@ fn RegulatorOutlineItem(regulator_key: RegulatorKey, element_key: ElementKey) ->
// a list item that shows an element in an outline view of an assembly // a list item that shows an element in an outline view of an assembly
#[component(inline_props)] #[component(inline_props)]
fn ElementOutlineItem(key: ElementKey, element: assembly::Element) -> View { fn ElementOutlineItem(key: ElementKey, element: assembly::Sphere) -> View {
let state = use_context::<AppState>(); let state = use_context::<AppState>();
let class = state.selection.map( let class = state.selection.map(
move |sel| if sel.contains(&key) { "selected" } else { "" } move |sel| if sel.contains(&key) { "selected" } else { "" }