diff --git a/app-proto/src/assembly.rs b/app-proto/src/assembly.rs index acef6c8..233ef66 100644 --- a/app-proto/src/assembly.rs +++ b/app-proto/src/assembly.rs @@ -1,6 +1,7 @@ use enum_iterator::{all, Sequence}; use nalgebra::{DMatrix, DVector, DVectorView}; use std::{ + any::Any, cell::Cell, cmp::Ordering, collections::{BTreeMap, BTreeSet}, @@ -95,7 +96,7 @@ pub trait Element: Serial + ProblemPoser + DisplayItem { fn default_id() -> String where Self: Sized; // the default example of an element of this type - fn default(id: String, id_num: u64) -> Self where Self: Sized; + fn default(id: &str, id_num: u64) -> Self where Self: Sized; // the default regulators that come with this element fn default_regulators(self: Rc) -> Vec> { @@ -173,14 +174,14 @@ impl Sphere { const CURVATURE_COMPONENT: usize = 3; pub fn new( - id: String, - label: String, + id: &str, + label: &str, color: ElementColor, representation: DVector, ) -> Self { Self { - id, - label, + id: id.to_string(), + label: label.to_string(), color, representation: create_signal(representation), ghost: create_signal(false), @@ -196,11 +197,11 @@ impl Element for Sphere { "sphere".to_string() } - fn default(id: String, id_num: u64) -> Self { + fn default(id: &str, id_num: u64) -> Self { Self::new( id, - format!("Sphere {id_num}"), - [0.75_f32, 0.75_f32, 0.75_f32], + &format!("Sphere {id_num}"), + [0.75, 0.75, 0.75], sphere(0.0, 0.0, 0.0, 1.0), ) } @@ -297,9 +298,9 @@ impl Element for Point { "point".to_string() } - fn default(id: String, id_num: u64) -> Self { + fn default(id: &str, id_num: u64) -> Self { Self::new( - &id, + id, &format!("Point {id_num}"), [0.75_f32, 0.75_f32, 0.75_f32], point(0.0, 0.0, 0.0), @@ -365,10 +366,22 @@ impl ProblemPoser for Point { } } -pub trait Regulator: Serial + ProblemPoser + OutlineItem { +pub trait Regulator: Any + Serial + ProblemPoser + OutlineItem { fn subjects(&self) -> Vec>; fn measurement(&self) -> ReadSignal; fn set_point(&self) -> Signal; + fn set_to(&self, val: f64) { + self.set_point().set(SpecifiedValue::from(Some(val))) + } + // QUESTION: Why doesn't the following work? When I used it to + // set the coordinate regulators on pinned points, dyna3 would panic + // when trying to nudge unpinned points :-( + // fn set_to_current(&self) { + // self.set_point().set( + // SpecifiedValue::from(Some(self.measurement().get())), + // ) + // } + fn as_any(&self) -> &dyn Any; } impl Hash for dyn Regulator { @@ -434,6 +447,8 @@ impl Regulator for InversiveDistanceRegulator { fn set_point(&self) -> Signal { self.set_point } + + fn as_any(&self) -> &dyn Any {self} } impl Serial for InversiveDistanceRegulator { @@ -489,6 +504,8 @@ impl Regulator for HalfCurvatureRegulator { fn set_point(&self) -> Signal { self.set_point } + + fn as_any(&self) -> &dyn Any {self} } impl Serial for HalfCurvatureRegulator { @@ -544,6 +561,7 @@ impl Regulator for PointCoordinateRegulator { fn subjects(&self) -> Vec> { vec![self.subject.clone()] } fn measurement(&self) -> ReadSignal { self.measurement } fn set_point(&self) -> Signal { self.set_point } + fn as_any(&self) -> &dyn Any {self} } impl ProblemPoser for PointCoordinateRegulator { @@ -696,9 +714,12 @@ impl Assembly { } // create and insert the default example of `T` - let _ = self.insert_element_unchecked(T::default(id, id_num)); + let _ = self.insert_element_unchecked(T::default(&id, id_num)); } - + + // FIXME: insert_element and insert_regulator are not parallel; + // the former takes an element and calls Rc::new, inserting clones of + // the result, whereas the latter takes an Rc and inserts clones of that pub fn insert_regulator(&self, regulator: Rc) { // add the regulator to the assembly's regulator list self.regulators.update( @@ -735,6 +756,11 @@ impl Assembly { } }); } + + // --- finding entities --- + pub fn find_element(&self, id: &str) -> Rc { + self.elements_by_id.with_untracked( |elts| elts[id].clone() ) + } // --- updating the configuration --- diff --git a/app-proto/src/components/test_assembly_chooser.rs b/app-proto/src/components/test_assembly_chooser.rs index 1444325..f6e1f84 100644 --- a/app-proto/src/components/test_assembly_chooser.rs +++ b/app-proto/src/components/test_assembly_chooser.rs @@ -1,5 +1,5 @@ use itertools::izip; -use std::{f64::consts::{FRAC_1_SQRT_2, PI}, rc::Rc}; +use std::{f64::consts::{FRAC_1_SQRT_2, PI, SQRT_2}, rc::Rc}; use nalgebra::Vector3; use sycamore::prelude::*; use web_sys::{console, wasm_bindgen::JsValue}; @@ -12,6 +12,8 @@ use crate::{ ElementColor, InversiveDistanceRegulator, Point, + PointCoordinateRegulator, + Regulator, Sphere, }, engine, @@ -78,6 +80,12 @@ const fn sqrt(x: T) -> f64 {x.sqr()} // FIXME: replace with std::f64::consts::PHI when that gets stabilized const PHI: f64 = (1. + sqrt(5)) / 2.; +const fn gray(level: f32) -> ElementColor { [level, level, level] } +const GRAY: ElementColor = gray(0.75); +const RED: ElementColor = [1., 0., 0.25]; +const GREEN: ElementColor = [0.25, 1., 0.]; +const BLUE: ElementColor = [0., 0.25, 1.]; + // --- loaders --- /* DEBUG */ @@ -88,49 +96,37 @@ const PHI: f64 = (1. + sqrt(5)) / 2.; fn load_general(assembly: &Assembly) { let _ = assembly.try_insert_element( Sphere::new( - String::from("gemini_a"), - String::from("Castor"), - [1.00_f32, 0.25_f32, 0.00_f32], + "gemini_a", "Castor", [1.00, 0.25, 0.00], engine::sphere(0.5, 0.5, 0.0, 1.0), ) ); let _ = assembly.try_insert_element( Sphere::new( - String::from("gemini_b"), - String::from("Pollux"), - [0.00_f32, 0.25_f32, 1.00_f32], + "gemini_b", "Pollux", BLUE, engine::sphere(-0.5, -0.5, 0.0, 1.0), ) ); let _ = assembly.try_insert_element( Sphere::new( - String::from("ursa_major"), - String::from("Ursa major"), - [0.25_f32, 0.00_f32, 1.00_f32], + "ursa_major", "Ursa major", [0.25, 0.00, 1.00], engine::sphere(-0.5, 0.5, 0.0, 0.75), ) ); let _ = assembly.try_insert_element( Sphere::new( - String::from("ursa_minor"), - String::from("Ursa minor"), - [0.25_f32, 1.00_f32, 0.00_f32], + "ursa_minor", "Ursa minor", GREEN, engine::sphere(0.5, -0.5, 0.0, 0.5), ) ); let _ = assembly.try_insert_element( Sphere::new( - String::from("moon_deimos"), - String::from("Deimos"), - [0.75_f32, 0.75_f32, 0.00_f32], + "moon_deimos", "Deimos", [0.75, 0.75, 0.00], engine::sphere(0.0, 0.15, 1.0, 0.25), ) ); let _ = assembly.try_insert_element( Sphere::new( - String::from("moon_phobos"), - String::from("Phobos"), - [0.00_f32, 0.75_f32, 0.50_f32], + "moon_phobos", "Phobos", [0.00, 0.75, 0.50], engine::sphere(0.0, -0.15, -1.0, 0.25), ) ); @@ -141,65 +137,49 @@ fn load_low_curvature(assembly: &Assembly) { const A: f64 = sqrt(0.75); let _ = assembly.try_insert_element( Sphere::new( - "central".to_string(), - "Central".to_string(), - [0.75_f32, 0.75_f32, 0.75_f32], + "central", "Central", GRAY, engine::sphere(0.0, 0.0, 0.0, 1.0), ) ); let _ = assembly.try_insert_element( Sphere::new( - "assemb_plane".to_string(), - "Assembly plane".to_string(), - [0.75_f32, 0.75_f32, 0.75_f32], + "assemb_plane", "Assembly plane", GRAY, engine::sphere_with_offset(0.0, 0.0, 1.0, 0.0, 0.0), ) ); let _ = assembly.try_insert_element( Sphere::new( - "side1".to_string(), - "Side 1".to_string(), - [1.00_f32, 0.00_f32, 0.25_f32], + "side1", "Side 1", RED, engine::sphere_with_offset(1.0, 0.0, 0.0, 1.0, 0.0), ) ); let _ = assembly.try_insert_element( Sphere::new( - "side2".to_string(), - "Side 2".to_string(), - [0.25_f32, 1.00_f32, 0.00_f32], + "side2", "Side 2", GREEN, engine::sphere_with_offset(-0.5, A, 0.0, 1.0, 0.0), ) ); let _ = assembly.try_insert_element( Sphere::new( - "side3".to_string(), - "Side 3".to_string(), - [0.00_f32, 0.25_f32, 1.00_f32], + "side3", "Side 3", BLUE, engine::sphere_with_offset(-0.5, -A, 0.0, 1.0, 0.0), ) ); let _ = assembly.try_insert_element( Sphere::new( - "corner1".to_string(), - "Corner 1".to_string(), - [0.75_f32, 0.75_f32, 0.75_f32], + "corner1", "Corner 1", GRAY, engine::sphere(-4.0/3.0, 0.0, 0.0, 1.0/3.0), ) ); let _ = assembly.try_insert_element( Sphere::new( - "corner2".to_string(), - "Corner 2".to_string(), - [0.75_f32, 0.75_f32, 0.75_f32], + "corner2", "Corner 2", GRAY, engine::sphere(2.0/3.0, -4.0/3.0 * A, 0.0, 1.0/3.0), ) ); let _ = assembly.try_insert_element( Sphere::new( - String::from("corner3"), - String::from("Corner 3"), - [0.75_f32, 0.75_f32, 0.75_f32], + "corner3", "Corner 3", GRAY, engine::sphere(2.0/3.0, 4.0/3.0 * A, 0.0, 1.0/3.0), ) ); @@ -207,19 +187,13 @@ fn load_low_curvature(assembly: &Assembly) { // impose the desired tangencies and make the sides planar let index_range = 1..=3; let [central, assemb_plane] = ["central", "assemb_plane"].map( - |id| assembly.elements_by_id.with_untracked( - |elts_by_id| elts_by_id[id].clone() - ) + |id| assembly.find_element(id) ); let sides = index_range.clone().map( - |k| assembly.elements_by_id.with_untracked( - |elts_by_id| elts_by_id[&format!("side{k}")].clone() - ) + |k| assembly.find_element(&format!("side{k}")) ); let corners = index_range.map( - |k| assembly.elements_by_id.with_untracked( - |elts_by_id| elts_by_id[&format!("corner{k}")].clone() - ) + |k| assembly.find_element(&format!("corner{k}")) ); for plane in [assemb_plane.clone()].into_iter().chain(sides.clone()) { // fix the curvature of each plane @@ -279,8 +253,8 @@ fn load_pointed(assembly: &Assembly) { let _ = assembly.try_insert_element( Sphere::new( - format!("sphere{index_x}{index_y}"), - format!("Sphere {index_x}{index_y}"), + &format!("sphere{index_x}{index_y}"), + &format!("Sphere {index_x}{index_y}"), [0.5*(1.0 + x) as f32, 0.5*(1.0 + y) as f32, 0.5*(1.0 - x*y) as f32], engine::sphere(x, y, 0.0, 1.0), ) @@ -326,27 +300,23 @@ fn load_tridiminished_icosahedron(assembly: &Assembly) { } // create the faces - const COLOR_FACE: ElementColor = [0.75, 0.75, 0.75]; const SQRT_1_6: f64 = invsqrt(6.); const SQRT_2_3: f64 = 2. * SQRT_1_6; let faces = [ Sphere::new( - "face1".to_string(), - "Face 1".to_string(), - COLOR_FACE, - engine::sphere_with_offset(SQRT_2_3, -SQRT_1_6, -SQRT_1_6, -SQRT_1_6, 0.0), + "face1", "Face 1", GRAY, + engine::sphere_with_offset( + SQRT_2_3, -SQRT_1_6, -SQRT_1_6, -SQRT_1_6, 0.0), ), Sphere::new( - "face2".to_string(), - "Face 2".to_string(), - COLOR_FACE, - engine::sphere_with_offset(-SQRT_1_6, SQRT_2_3, -SQRT_1_6, -SQRT_1_6, 0.0), + "face2", "Face 2", GRAY, + engine::sphere_with_offset( + -SQRT_1_6, SQRT_2_3, -SQRT_1_6, -SQRT_1_6, 0.0), ), Sphere::new( - "face3".to_string(), - "Face 3".to_string(), - COLOR_FACE, - engine::sphere_with_offset(-SQRT_1_6, -SQRT_1_6, SQRT_2_3, -SQRT_1_6, 0.0), + "face3", "Face 3", GRAY, + engine::sphere_with_offset( + -SQRT_1_6, -SQRT_1_6, SQRT_2_3, -SQRT_1_6, 0.0), ), ]; for face in faces { @@ -427,9 +397,7 @@ fn load_dodecahedral_packing(assembly: &Assembly) { // add the substrate let _ = assembly.try_insert_element( Sphere::new( - "substrate".to_string(), - "Substrate".to_string(), - [0.75_f32, 0.75_f32, 0.75_f32], + "substrate", "Substrate", GRAY, engine::sphere(0.0, 0.0, 0.0, 1.0), ) ); @@ -466,8 +434,8 @@ fn load_dodecahedral_packing(assembly: &Assembly) { let id_a = format!("a{id_num}"); let _ = assembly.try_insert_element( Sphere::new( - id_a.clone(), - format!("A{label_sub}"), + &id_a, + &format!("A{label_sub}"), COLOR_A, engine::sphere(0.0, small_coord, big_coord, FACE_RADII[k]), ) @@ -482,8 +450,8 @@ fn load_dodecahedral_packing(assembly: &Assembly) { let id_b = format!("b{id_num}"); let _ = assembly.try_insert_element( Sphere::new( - id_b.clone(), - format!("B{label_sub}"), + &id_b, + &format!("B{label_sub}"), COLOR_B, engine::sphere(small_coord, big_coord, 0.0, FACE_RADII[k]), ) @@ -498,8 +466,8 @@ fn load_dodecahedral_packing(assembly: &Assembly) { let id_c = format!("c{id_num}"); let _ = assembly.try_insert_element( Sphere::new( - id_c.clone(), - format!("C{label_sub}"), + &id_c, + &format!("C{label_sub}"), COLOR_C, engine::sphere(big_coord, 0.0, small_coord, FACE_RADII[k]), ) @@ -569,23 +537,9 @@ fn load_balanced(assembly: &Assembly) { const R_INNER: f64 = 4.0; let spheres = [ Sphere::new( - "outer".to_string(), - "Outer".to_string(), - [0.75_f32, 0.75_f32, 0.75_f32], - engine::sphere(0.0, 0.0, 0.0, R_OUTER), - ), - Sphere::new( - "a".to_string(), - "A".to_string(), - [1.00_f32, 0.00_f32, 0.25_f32], - engine::sphere(0.0, 4.0, 0.0, R_INNER), - ), - Sphere::new( - "b".to_string(), - "B".to_string(), - [0.00_f32, 0.25_f32, 1.00_f32], - engine::sphere(0.0, -4.0, 0.0, R_INNER), - ), + "outer","Outer", GRAY, engine::sphere(0.0, 0.0, 0.0, R_OUTER)), + Sphere::new("a", "A", RED, engine::sphere(0.0, 4.0, 0.0, R_INNER)), + Sphere::new("b", "B", BLUE, engine::sphere(0.0, -4.0, 0.0, R_INNER)), ]; for sphere in spheres { let _ = assembly.try_insert_element(sphere); @@ -593,9 +547,7 @@ fn load_balanced(assembly: &Assembly) { // get references to the spheres let [outer, a, b] = ["outer", "a", "b"].map( - |id| assembly.elements_by_id.with_untracked( - |elts_by_id| elts_by_id[id].clone() - ) + |id| assembly.find_element(id) ); // fix the diameters of the outer, sun, and moon spheres @@ -627,27 +579,22 @@ fn load_balanced(assembly: &Assembly) { fn load_off_center(assembly: &Assembly) { // create a point almost at the origin and a sphere centered on the origin let _ = assembly.try_insert_element( - Point::new("point", "Point", [0.75, 0.75, 0.75], point(1e-9, 0.0, 0.0)), + Point::new("point", "Point", GRAY, point(1e-9, 0.0, 0.0)), ); let _ = assembly.try_insert_element( Sphere::new( - "sphere".to_string(), - "Sphere".to_string(), - [0.75_f32, 0.75_f32, 0.75_f32], - engine::sphere(0.0, 0.0, 0.0, 1.0), - ), + "sphere", "Sphere", GRAY, engine::sphere(0.0, 0.0, 0.0, 1.0)), ); + // get references to the elements let point_and_sphere = ["point", "sphere"].map( - |id| assembly.elements_by_id.with_untracked( - |elts_by_id| elts_by_id[id].clone() - ) + |id| assembly.find_element(id) ); // put the point on the sphere let incidence = InversiveDistanceRegulator::new(point_and_sphere); - incidence.set_point.set(SpecifiedValue::try_from("0".to_string()).unwrap()); + incidence.set_to(0.); assembly.insert_regulator(Rc::new(incidence)); } @@ -660,18 +607,13 @@ fn load_radius_ratio(assembly: &Assembly) { let index_range = 1..=4; // create the spheres - const GRAY: ElementColor = [0.75, 0.75, 0.75]; let spheres = [ Sphere::new( - "sphere_faces".to_string(), - "Insphere".to_string(), - GRAY, + "sphere_faces", "Insphere", GRAY, engine::sphere(0.0, 0.0, 0.0, 0.5), ), Sphere::new( - "sphere_vertices".to_string(), - "Circumsphere".to_string(), - GRAY, + "sphere_vertices", "Circumsphere", GRAY, engine::sphere(0.0, 0.0, 0.0, 0.25), ), ]; @@ -728,8 +670,8 @@ fn load_radius_ratio(assembly: &Assembly) { ).map( |(k, color, representation)| { Sphere::new( - format!("f{k}"), - format!("Face {k}"), + &format!("f{k}"), + &format!("Face {k}"), color, representation, ) @@ -742,27 +684,18 @@ fn load_radius_ratio(assembly: &Assembly) { // impose the constraints for j in index_range.clone() { - let [face_j, vertex_j] = [ - format!("f{j}"), - format!("v{j}"), - ].map( - |id| assembly.elements_by_id.with_untracked( - |elts_by_id| elts_by_id[&id].clone() - ) - ); + let [face_j, vertex_j] = [format!("f{j}"),format!("v{j}")] + .map(|id| assembly.find_element(&id)); + // make the faces planar let curvature_regulator = face_j.regulators().with_untracked( |regs| regs.first().unwrap().clone() ); - curvature_regulator.set_point().set( - SpecifiedValue::try_from("0".to_string()).unwrap() - ); + curvature_regulator.set_to(0.); for k in index_range.clone().filter(|&index| index != j) { - let vertex_k = assembly.elements_by_id.with_untracked( - |elts_by_id| elts_by_id[&format!("v{k}")].clone() - ); + let vertex_k = assembly.find_element(&format!("v{k}")); // fix the distances between the vertices if j < k { @@ -774,7 +707,7 @@ fn load_radius_ratio(assembly: &Assembly) { // put the vertices on the faces let incidence_regulator = InversiveDistanceRegulator::new([face_j.clone(), vertex_k.clone()]); - incidence_regulator.set_point.set(SpecifiedValue::try_from("0".to_string()).unwrap()); + incidence_regulator.set_to(0.); assembly.insert_regulator(Rc::new(incidence_regulator)); } } @@ -800,32 +733,26 @@ fn load_radius_ratio(assembly: &Assembly) { fn load_irisawa_hexlet(assembly: &Assembly) { let index_range = 1..=6; let colors = [ - [1.00_f32, 0.00_f32, 0.25_f32], - [1.00_f32, 0.25_f32, 0.00_f32], - [0.75_f32, 0.75_f32, 0.00_f32], - [0.25_f32, 1.00_f32, 0.00_f32], - [0.00_f32, 0.25_f32, 1.00_f32], - [0.25_f32, 0.00_f32, 1.00_f32], + [1.00, 0.00, 0.25], + [1.00, 0.25, 0.00], + [0.75, 0.75, 0.00], + [0.25, 1.00, 0.00], + [0.00, 0.25, 1.00], + [0.25, 0.00, 1.00], ].into_iter(); // create the spheres let spheres = [ Sphere::new( - "outer".to_string(), - "Outer".to_string(), - [0.5_f32, 0.5_f32, 0.5_f32], + "outer", "Outer", gray(0.5), engine::sphere(0.0, 0.0, 0.0, 1.5), ), Sphere::new( - "sun".to_string(), - "Sun".to_string(), - [0.75_f32, 0.75_f32, 0.75_f32], + "sun", "Sun", GRAY, engine::sphere(0.0, -0.75, 0.0, 0.75), ), Sphere::new( - "moon".to_string(), - "Moon".to_string(), - [0.25_f32, 0.25_f32, 0.25_f32], + "moon", "Moon", gray(0.25), engine::sphere(0.0, 0.75, 0.0, 0.75), ), ].into_iter().chain( @@ -833,8 +760,8 @@ fn load_irisawa_hexlet(assembly: &Assembly) { |(k, color)| { let ang = (k as f64) * PI/3.0; Sphere::new( - format!("chain{k}"), - format!("Chain {k}"), + &format!("chain{k}"), + &format!("Chain {k}"), color, engine::sphere(1.0 * ang.sin(), 0.0, 1.0 * ang.cos(), 0.5), ) @@ -846,9 +773,7 @@ fn load_irisawa_hexlet(assembly: &Assembly) { } // put the outer sphere in ghost mode and fix its curvature - let outer = assembly.elements_by_id.with_untracked( - |elts_by_id| elts_by_id["outer"].clone() - ); + let outer = assembly.find_element("outer"); outer.ghost().set(true); let outer_curvature_regulator = outer.regulators().with_untracked( |regs| regs.first().unwrap().clone() @@ -858,15 +783,9 @@ fn load_irisawa_hexlet(assembly: &Assembly) { ); // impose the desired tangencies - let [outer, sun, moon] = ["outer", "sun", "moon"].map( - |id| assembly.elements_by_id.with_untracked( - |elts_by_id| elts_by_id[id].clone() - ) - ); + let [sun, moon] = ["sun", "moon"].map(|id| assembly.find_element(id)); let chain = index_range.map( - |k| assembly.elements_by_id.with_untracked( - |elts_by_id| elts_by_id[&format!("chain{k}")].clone() - ) + |k| assembly.find_element(&format!("chain{k}")) ); for (chain_sphere, chain_sphere_next) in chain.clone().zip(chain.cycle().skip(1)) { for (other_sphere, inversive_distance) in [ @@ -899,46 +818,47 @@ const F: bool = false; // Free // Initial data for the vertices commmon to 554aug2 and 554domed. // Used the Vectornaut near_miss branch final positions for 554aug2, // to the 3 decimal places currently shown. -const_array!(ACRON554_COMMON: (&str, (f64, f64, f64), bool, usize, &str) = [ +const_array!(ACRON554_COMMON: (&str, [f64; 3], bool, usize, &str) = [ // id, coordinates, Pin/Free, level, earlier neighbor IDs. - ("A_NE", ( 0.5, 0.5, 0.), P, 0, ""), - ("A_NW", (-0.5, 0.5, 0.), P, 0, ""), - ("A_SE", ( 0.5, -0.5, 0.), P, 0, ""), - ("A_SW", (-0.5, -0.5, 0.), P, 0, ""), - ("Z_E", ( 0.229, -0.002, 0.821), F, 1, "A_NE,A_SE"), - ("Z_S", ( 0.002, -0.229, 0.821), F, 1, "A_SE,A_SW"), - ("B_NE", ( HPHI, HPHI, RTHPHI), P, 2, "Z_E"), - ("B_NW", (-HPHI, HPHI, RTHPHI), P, 2, ""), - ("B_SW", (-HPHI, -HPHI, RTHPHI), P, 2, "Z_S"), - ("B_SE", ( 0.812, -0.812, 0.89), F, 2, "Z_E,Z_S"), - ("Y_NE", ( 0.11, 0.103, 1.019), F, 3, "B_NE"), - ("Y_NW", (-0.103, 0.103, 1.02), F, 3, "B_NW"), - ("Y_SE", ( 0.11, -0.11, 1.017), F, 3, "B_SE"), - ("Y_SW", (-0.103, -0.11, 1.019), F, 3, "B_SW"), - ("C_N", ( 0., 1., RTPHIPH), P, 4, "Y_NE,Y_NW"), - ("C_W", (-1., 0., RTPHIPH), P, 4, "Y_NW,Y_SW"), - ("C_E", ( 1.006, -0.006, 1.45), F, 4, "Y_NE,Y_SE"), - ("C_S", ( 0.006, -1.006, 1.45), F, 4, "Y_SE,Y_SW"), - ("D_NE", ( 0.2, 0.181, 2.011), F, 5, "Y_NE,C_N,C_E"), - ("D_NW", (-0.181, 0.181, 2.014), F, 5, "Y_NW,C_N,C_W"), - ("D_SE", ( 0.2, -0.2, 2.009), F, 5, "Y_SE,C_E,C_S"), - ("D_SW", (-0.181, -0.2, 2.011), F, 5, "Y_SW,C_W,C_S"), - ("E_N", ( 0.012, 1.055, 2.46), F, 6, "C_N,D_NE,D_NW"), - ("E_W", (-1.055, -0.012, 2.46), F, 6, "C_W,D_NW,D_SW"), - ("E_E", ( 1.079, -0.012, 2.447), F, 6, "C_E,D_NE,D_SE"), - ("E_S", ( 0.012, -1.079, 2.447), F, 6, "C_S,D_SE,D_SW"), - ("F_NE", ( 0.296, 0.265, 3.003), F, 7, "D_NE,E_N,E_E"), - ("F_NW", (-0.265, 0.265, 3.007), F, 7, "D_NW,E_N,E_W"), - ("F_SE", ( 0.296, -0.296, 3.0), F, 7, "D_SE,E_E,E_S"), - ("F_SW", (-0.265, -0.296, 3.003), F, 7, "D_SW,E_W,E_S"), - ("G_1", ( 0.517, 1.19, 3.312), F, 8, "E_N,F_NE"), - ("G_2", ( 1.224, 0.483, 3.304), F, 8, "E_E,F_NE,G_1"), - ("G_4", ( 1.224, -0.517, 3.298), F, 8, "E_E,F_SE,G_2"), - ("G_5", ( 0.517, -1.224, 3.298), F, 8, "E_S,F_SE,G_4"), - ("G_7", (-0.483, -1.224, 3.304), F, 8, "E_S,F_SW,G_5"), - ("G_8", (-1.19, -0.517, 3.312), F, 8, "E_W,F_SW,G_7"), - ("G_10", (-1.19, 0.483, 3.318), F, 8, "E_W,F_NW,G_8"), - ("G_11", (-0.483, 1.19, 3.318), F, 8, "E_N,F_NW,G_1,G_10"), + ("A_NE", [ 0.5, 0.5, 0.], P, 0, ""), + ("A_NW", [-0.5, 0.5, 0.], P, 0, ""), + ("A_SE", [ 0.5, -0.5, 0.], P, 0, ""), + ("A_SW", [-0.5, -0.5, 0.], P, 0, ""), + ("Z_E", [ 0.229, -0.002, 0.821], F, 1, "A_NE,A_SE"), + ("Z_S", [ 0.002, -0.229, 0.821], F, 1, "A_SE,A_SW"), + ("B_NE", [ HPHI, HPHI, RTHPHI], P, 2, "Z_E"), + ("B_NW", [-HPHI, HPHI, RTHPHI], P, 2, ""), + ("B_SW", [-HPHI, -HPHI, RTHPHI], P, 2, "Z_S"), + ("B_SE", [ 0.812, -0.812, 0.89], F, 2, "Z_E,Z_S"), + ("Y_NE", [ 0.11, 0.103, 1.019], F, 3, "B_NE"), + ("Y_NW", [-0.103, 0.103, 1.02], F, 3, "B_NW"), + ("Y_SE", [ 0.11, -0.11, 1.017], F, 3, "B_SE"), + ("Y_SW", [-0.103, -0.11, 1.019], F, 3, "B_SW"), + ("C_N", [ 0., 1., RTPHIPH], P, 4, "Y_NE,Y_NW"), + ("C_W", [-1., 0., RTPHIPH], P, 4, "Y_NW,Y_SW"), + ("C_E", [ 1.006, -0.006, 1.45], F, 4, "Y_NE,Y_SE"), + ("C_S", [ 0.006, -1.006, 1.45], F, 4, "Y_SE,Y_SW"), + ("D_NE", [ 0.2, 0.181, 2.011], F, 5, "Y_NE,C_N,C_E"), + ("D_NW", [-0.181, 0.181, 2.014], F, 5, "Y_NW,C_N,C_W"), + ("D_SE", [ 0.2, -0.2, 2.009], F, 5, "Y_SE,C_E,C_S"), + ("D_SW", [-0.181, -0.2, 2.011], F, 5, "Y_SW,C_W,C_S"), + ("E_N", [ 0.012, 1.055, 2.46], F, 6, "C_N,D_NE,D_NW"), + ("E_W", [-1.055, -0.012, 2.46], F, 6, "C_W,D_NW,D_SW"), + ("E_E", [ 1.079, -0.012, 2.447], F, 6, "C_E,D_NE,D_SE"), + ("E_S", [ 0.012, -1.079, 2.447], F, 6, "C_S,D_SE,D_SW"), + ("F_NE", [ 0.296, 0.265, 3.003], F, 7, "D_NE,E_N,E_E"), + ("F_NW", [-0.265, 0.265, 3.007], F, 7, "D_NW,E_N,E_W"), + ("F_SE", [ 0.296, -0.296, 3.0], F, 7, "D_SE,E_E,E_S"), + ("F_SW", [-0.265, -0.296, 3.003], F, 7, "D_SW,E_W,E_S"), + // The following must be in order around the octagon (in some orientation) + ("G_1", [ 0.517, 1.19, 3.312], F, 8, "E_N,F_NE"), + ("G_2", [ 1.224, 0.483, 3.304], F, 8, "E_E,F_NE"), + ("G_4", [ 1.224, -0.517, 3.298], F, 8, "E_E,F_SE"), + ("G_5", [ 0.517, -1.224, 3.298], F, 8, "E_S,F_SE"), + ("G_7", [-0.483, -1.224, 3.304], F, 8, "E_S,F_SW"), + ("G_8", [-1.19, -0.517, 3.312], F, 8, "E_W,F_SW"), + ("G_10", [-1.19, 0.483, 3.318], F, 8, "E_W,F_NW"), + ("G_11", [-0.483, 1.19, 3.318], F, 8, "E_N,F_NW"), ]); const_array!(LEVEL_COLORS: ElementColor = [ @@ -954,9 +874,83 @@ const_array!(LEVEL_COLORS: ElementColor = [ ]); fn load_554aug2(assembly: &Assembly) { - for (id, v, _pinned, level, _neighbors) in ACRON554_COMMON { - let pt = Point::new(id, id, LEVEL_COLORS[level], point(v.0, v.1, v.2)); + // first a plane for the octagon + let oct_id = "f_g"; + let engsph = engine::sphere_with_offset( + 0., 0., 1., ACRON554_COMMON[37].1[2], 0.); + let octaface = Sphere::new(oct_id, "Octagon", [0.7, 0.7, 0.7], engsph); + octaface.ghost().set(true); + assembly.try_insert_element(octaface); + let face_rc = assembly.find_element(oct_id); + let face_curvature = face_rc.regulators().with_untracked( + |regs| regs.first().unwrap().clone() + ); + face_curvature.set_to(0.); + // Octagon vertices and side/diagonal lengths + let mut oct_verts = Vec::>::new(); + const OCT_LONG: usize = 4; + const OCT_N_DIAG: usize = 5; + const OCT_N: usize = 8; + const OCT_DIST: [f64; OCT_N_DIAG] = [0., // dummy at start + -0.5, + -0.5*(2. + SQRT_2), + -0.5*(3. + 2.*SQRT_2), + -0.5*(4. + 2.*SQRT_2) + ]; + // Now process the acron data + for (id, v, pinned, l, _neighbors) in ACRON554_COMMON { + let pt = Point::new(id, id, LEVEL_COLORS[l], point(v[0], v[1], v[2])); assembly.try_insert_element(pt); + if pinned { // regulate each coordinate to its given value + let mut freeze = Vec::>::new(); + // QUESTION: Would there be a way to insert an Rc into + // an assembly to avoid the need to re-lookup pt in the assembly + // after just inserting it? + let pt_rc = assembly.elements_by_id.with_untracked( + |elts| elts[id].clone() + ); + // filter the three coordinate regulators into freeze + pt_rc.regulators().with_untracked( |regs| { + for reg in regs { + if let Some(_pcr) = reg + .as_any().downcast_ref::() { + freeze.push(reg.clone()) + } + } + }); + // now set them to their originally specified values. + let mut coord: usize = 0; + for reg in freeze { + reg.set_to(v[coord]); + coord += 1; + } + } + // If part of the octagon, make incident to the plane: + if l == 8 { + let pt_rc = assembly.find_element(id); + let oct_index = oct_verts.len(); + oct_verts.push(pt_rc.clone()); + let incidence = InversiveDistanceRegulator::new( + [face_rc.clone(), pt_rc.clone()]); + incidence.set_to(0.0); + assembly.insert_regulator(Rc::new(incidence)); + // And regulate the length to the other vertices of the octagon + for offset in 1..OCT_N_DIAG { + if offset <= oct_index { + let dist = InversiveDistanceRegulator::new( + [oct_verts[oct_index - offset].clone(), pt_rc.clone()]); + dist.set_to(OCT_DIST[offset]); + assembly.insert_regulator(Rc::new(dist)); + } + if offset < OCT_LONG && oct_index + offset >= OCT_N { + let forward = oct_index + offset - OCT_N; + let dist = InversiveDistanceRegulator::new( + [oct_verts[forward].clone(), pt_rc.clone()]); + dist.set_to(OCT_DIST[offset]); + assembly.insert_regulator(Rc::new(dist)); + } + } + } } }