diff --git a/README.md b/README.md index cf3e589..ac2771b 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,11 @@ Note that currently this is just the barest beginnings of the project, more of a ### Implementation goals -* Comfortable, intuitive UI +* Provide a comfortable, intuitive UI -* Able to run in browser (so implemented in WASM-compatible language) +* Allow execution in browser (so implemented in WASM-compatible language) -* Produce scalable graphics of 3D diagrams, and maybe STL files (or other fabricatable file format) as well. +* Produce scalable graphics of 3D diagrams, and maybe STL files (or other fabricatable file format) as well ## Prototype @@ -24,38 +24,40 @@ The latest prototype is in the folder `app-proto`. It includes both a user inter ### Install the prerequisites -1. Install [`rustup`](https://rust-lang.github.io/rustup/): the officially recommended Rust toolchain manager - - It's available on Ubuntu as a [Snap](https://snapcraft.io/rustup) -2. Call `rustup default stable` to "download the latest stable release of Rust and set it as your default toolchain" - - If you forget, the `rustup` [help system](https://github.com/rust-lang/rustup/blob/d9b3601c3feb2e88cf3f8ca4f7ab4fdad71441fd/src/errors.rs#L109-L112) will remind you -3. Call `rustup target add wasm32-unknown-unknown` to add the [most generic 32-bit WebAssembly target](https://doc.rust-lang.org/nightly/rustc/platform-support/wasm32-unknown-unknown.html) -4. Call `cargo install wasm-pack` to install the [WebAssembly toolchain](https://rustwasm.github.io/docs/wasm-pack/) -5. Call `cargo install trunk` to install the [Trunk](https://trunkrs.dev/) web-build tool +1. Install [`rustup`](https://rust-lang.github.io/rustup/): the officially recommended Rust toolchain manager. + - It's available on Ubuntu as a [Snap](https://snapcraft.io/rustup). +2. Call `rustup default stable` to "download the latest stable release of Rust and set it as your default toolchain". + - If you forget, the `rustup` [help system](https://github.com/rust-lang/rustup/blob/d9b3601c3feb2e88cf3f8ca4f7ab4fdad71441fd/src/errors.rs#L109-L112) will remind you. +3. Call `rustup target add wasm32-unknown-unknown` to add the [most generic 32-bit WebAssembly target](https://doc.rust-lang.org/nightly/rustc/platform-support/wasm32-unknown-unknown.html). +4. Call `cargo install wasm-pack` to install the [WebAssembly toolchain](https://rustwasm.github.io/docs/wasm-pack/). +5. Call `cargo install trunk` to install the [Trunk](https://trunkrs.dev/) web-build tool. + - In the future, `trunk` can be updated with the same command. (You may need the `--locked` flag if your ambient version of `rustc` does not match that required by `trunk`.) 6. Add the `.cargo/bin` folder in your home directory to your executable search path - - This lets you call Trunk, and other tools installed by Cargo, without specifying their paths - - On POSIX systems, the search path is stored in the `PATH` environment variable + - This lets you call Trunk, and other tools installed by Cargo, without specifying their paths. + - On POSIX systems, the search path is stored in the `PATH` environment variable. + - Alternatively, if you don't want to adjust your `PATH`, you can install `trunk` in another directory `DIR` via `cargo install --root DIR trunk`. ### Play with the prototype -1. From the `app-proto` folder, call `trunk serve --release` to build and serve the prototype - - The crates the prototype depends on will be downloaded and served automatically - - For a faster build, at the expense of a much slower prototype, you can call `trunk serve` without the `--release` flag +1. From the `app-proto` folder, call `trunk serve --release` to build and serve the prototype. + - The crates the prototype depends on will be downloaded and served automatically. + - For a faster build, at the expense of a much slower prototype, you can call `trunk serve` without the `--release` flag. - If you want to stay in the top-level folder, you can call `trunk serve --config app-proto [--release]` from there instead. -3. In a web browser, visit one of the URLs listed under the message `INFO 📡 server listening at:` - - Touching any file in the `app-proto` folder will make Trunk rebuild and live-reload the prototype -4. Press *ctrl+C* in the shell where Trunk is running to stop serving the prototype +3. In a web browser, visit one of the URLs listed under the message `INFO 📡 server listening at:`. + - Touching any file in the `app-proto` folder will make Trunk rebuild and live-reload the prototype. +4. Press *ctrl+C* in the shell where Trunk is running to stop serving the prototype. ### Run the engine on some example problems -1. Use `sh` to run the script `tools/run-examples.sh` - - The script is location-independent, so you can do this from anywhere in the dyna3 repository +1. Use `sh` to run the script `tools/run-examples.sh`. + - The script is location-independent, so you can do this from anywhere in the dyna3 repository. - The call from the top level of the repository is: ```bash sh tools/run-examples.sh ``` - - For each example problem, the engine will print the value of the loss function at each optimization step - - The first example that prints is the same as the Irisawa hexlet example from the Julia version of the engine prototype. If you go into `engine-proto/gram-test`, launch Julia, and then + - For each example problem, the engine will print the value of the loss function at each optimization step. + - The first example that prints is the same as the Irisawa hexlet example from the Julia version of the engine prototype. If you go into `engine-proto/gram-test`, launch Julia, and then execute ```julia include("irisawa-hexlet.jl") @@ -64,24 +66,24 @@ The latest prototype is in the folder `app-proto`. It includes both a user inter end ``` - you should see that it prints basically the same loss history until the last few steps, when the lower default precision of the Rust engine really starts to show + you should see that it prints basically the same loss history until the last few steps, when the lower default precision of the Rust engine really starts to show. ### Run the automated tests -1. Go into the `app-proto` folder -2. Call `cargo test` +1. Go into the `app-proto` folder. +2. Call `cargo test`. ### Deploy the prototype -1. From the `app-proto` folder, call `trunk build --release` - - Building in [release mode](https://doc.rust-lang.org/cargo/reference/profiles.html#release) produces an executable which is smaller and often much faster, but harder to debug and more time-consuming to build - - If you want to stay in the top-level folder, you can call `trunk build --config app-proto --release` from there instead +1. From the `app-proto` folder, call `trunk build --release`. + - Building in [release mode](https://doc.rust-lang.org/cargo/reference/profiles.html#release) produces an executable which is smaller and often much faster, but harder to debug and more time-consuming to build. + - If you want to stay in the top-level folder, you can call `trunk build --config app-proto --release` from there instead. 2. Use `sh` to run the packaging script `tools/package-for-deployment.sh`. - - The script is location-independent, so you can do this from anywhere in the dyna3 repository + - The script is location-independent, so you can do this from anywhere in the dyna3 repository. - The call from the top level of the repository is: ```bash sh tools/package-for-deployment.sh ``` - - This will overwrite or replace the files in `deploy/dyna3` + - This will overwrite or replace the files in `deploy/dyna3`. 3. Put the contents of `deploy/dyna3` in the folder on your server that the prototype will be served from. - - To simplify uploading, you might want to combine these files into an archive called `deploy/dyna3.zip`. Git has been set to ignore this path \ No newline at end of file + - To simplify uploading, you might want to combine these files into an archive called `deploy/dyna3.zip`. Git has been set to ignore this path. diff --git a/app-proto/main.css b/app-proto/main.css index 0ec33e9..a00d309 100644 --- a/app-proto/main.css +++ b/app-proto/main.css @@ -227,10 +227,6 @@ details[open]:has(li) .element-switch::after { border-radius: 8px; } -#distortion-gauge { - margin-top: 8px; -} - /* display */ #display { diff --git a/app-proto/rust-toolchain.toml b/app-proto/rust-toolchain.toml deleted file mode 100644 index 5d56faf..0000000 --- a/app-proto/rust-toolchain.toml +++ /dev/null @@ -1,2 +0,0 @@ -[toolchain] -channel = "nightly" diff --git a/app-proto/src/assembly.rs b/app-proto/src/assembly.rs index 29f1982..0264b75 100644 --- a/app-proto/src/assembly.rs +++ b/app-proto/src/assembly.rs @@ -1,13 +1,11 @@ use enum_iterator::{all, Sequence}; use nalgebra::{DMatrix, DVector, DVectorView}; use std::{ - any::Any, cell::Cell, cmp::Ordering, collections::{BTreeMap, BTreeSet}, - f64::consts::SQRT_2, fmt, - fmt::{Debug, Formatter}, + fmt::{Debug, Display, Formatter}, hash::{Hash, Hasher}, rc::Rc, sync::{atomic, atomic::AtomicU64}, @@ -88,6 +86,14 @@ impl Ord for dyn Serial { } } +// Small helper function to generate consistent errors when there +// are indexing issues in a ProblemPoser +fn indexing_error(item: &str, name: &str, actor: &str) -> String { + format!( + "{item} \"{name}\" must be indexed before {actor} writes problem data" + ) +} + pub trait ProblemPoser { fn pose(&self, problem: &mut ConstraintProblem); } @@ -97,7 +103,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: &str, id_num: u64) -> Self where Self: Sized; + fn default(id: String, id_num: u64) -> Self where Self: Sized; // the default regulators that come with this element fn default_regulators(self: Rc) -> Vec> { @@ -126,16 +132,11 @@ pub trait Element: Serial + ProblemPoser + DisplayItem { // be used carefully to preserve invariant (1), described in the comment on // the `tangent` field of the `Assembly` structure fn set_column_index(&self, index: usize); - - /* KLUDGE */ - fn has_distortion(&self) -> bool { - false - } } impl Debug for dyn Element { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> { - self.id().fmt(f) + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Debug::fmt(&self.id(), f) } } @@ -180,14 +181,14 @@ impl Sphere { const CURVATURE_COMPONENT: usize = 3; pub fn new( - id: &str, - label: &str, + id: String, + label: String, color: ElementColor, representation: DVector, ) -> Self { Self { - id: id.to_string(), - label: label.to_string(), + id, + label, color, representation: create_signal(representation), ghost: create_signal(false), @@ -203,11 +204,11 @@ impl Element for Sphere { "sphere".to_string() } - fn default(id: &str, id_num: u64) -> Self { + fn default(id: String, id_num: u64) -> Self { Self::new( id, - &format!("Sphere {id_num}"), - [0.75, 0.75, 0.75], + format!("Sphere {id_num}"), + [0.75_f32, 0.75_f32, 0.75_f32], sphere(0.0, 0.0, 0.0, 1.0), ) } @@ -258,8 +259,7 @@ impl Serial for Sphere { impl ProblemPoser for Sphere { fn pose(&self, problem: &mut ConstraintProblem) { let index = self.column_index().expect( - format!("Sphere \"{}\" should be indexed before writing problem data", self.id).as_str() - ); + indexing_error("Sphere", &self.id, "it").as_str()); problem.gram.push_sym(index, index, 1.0); problem.guess.set_column(index, &self.representation.get_clone_untracked()); } @@ -281,14 +281,14 @@ impl Point { const NORM_COMPONENT: usize = 4; pub fn new( - id: &str, - label: &str, + id: String, + label: String, color: ElementColor, representation: DVector, ) -> Self { Self { - id: id.to_string(), - label: label.to_string(), + id, + label, color, representation: create_signal(representation), ghost: create_signal(false), @@ -304,10 +304,10 @@ impl Element for Point { "point".to_string() } - fn default(id: &str, id_num: u64) -> Self { + fn default(id: String, id_num: u64) -> Self { Self::new( id, - &format!("Point {id_num}"), + format!("Point {id_num}"), [0.75_f32, 0.75_f32, 0.75_f32], point(0.0, 0.0, 0.0), ) @@ -353,10 +353,6 @@ impl Element for Point { fn set_column_index(&self, index: usize) { self.column_index.set(Some(index)); } - - fn has_distortion(&self) -> bool { - true - } } impl Serial for Point { @@ -368,33 +364,17 @@ impl Serial for Point { impl ProblemPoser for Point { fn pose(&self, problem: &mut ConstraintProblem) { let index = self.column_index().expect( - format!("Point \"{}\" should be indexed before writing problem data", self.id).as_str() - ); + indexing_error("Point", &self.id, "it").as_str()); problem.gram.push_sym(index, index, 0.0); problem.frozen.push(Self::WEIGHT_COMPONENT, index, 0.5); problem.guess.set_column(index, &self.representation.get_clone_untracked()); } } -pub trait Regulator: Any + Serial + ProblemPoser + OutlineItem { +pub trait Regulator: Serial + ProblemPoser + OutlineItem { fn subjects(&self) -> Vec>; fn measurement(&self) -> ReadSignal; fn set_point(&self) -> Signal; - fn distortion(&self) -> Option> { /* KLUDGE */ - None - } - 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 { @@ -427,7 +407,6 @@ pub struct InversiveDistanceRegulator { pub subjects: [Rc; 2], pub measurement: ReadSignal, pub set_point: Signal, - distortion: Option>, /* KLUDGE */ serial: u64, } @@ -443,23 +422,9 @@ impl InversiveDistanceRegulator { }); let set_point = create_signal(SpecifiedValue::from_empty_spec()); - let distortion = if subjects.iter().all(|subj| subj.has_distortion()) { - Some(create_memo(move || { - let set_point_opt = set_point.with(|set_pt| set_pt.value); - let measurement_val = measurement.get(); - match set_point_opt { - None => 0.0, - Some(set_point_val) => SQRT_2 * ( - (-set_point_val).sqrt() - (-measurement_val).sqrt() - ).abs(), - } - })) - } else { - None - }; let serial = Self::next_serial(); - Self { subjects, measurement, set_point, distortion, serial } + Self { subjects, measurement, set_point, serial } } } @@ -475,12 +440,6 @@ impl Regulator for InversiveDistanceRegulator { fn set_point(&self) -> Signal { self.set_point } - - fn distortion(&self) -> Option> { - self.distortion - } - - fn as_any(&self) -> &dyn Any {self} } impl Serial for InversiveDistanceRegulator { @@ -495,8 +454,8 @@ impl ProblemPoser for InversiveDistanceRegulator { if let Some(val) = set_pt.value { let [row, col] = self.subjects.each_ref().map( |subj| subj.column_index().expect( - "Subjects should be indexed before inversive distance regulator writes problem data" - ) + indexing_error("Subject", subj.id(), + "inversive distance regulator").as_str()) ); problem.gram.push_sym(row, col, val); } @@ -536,8 +495,6 @@ impl Regulator for HalfCurvatureRegulator { fn set_point(&self) -> Signal { self.set_point } - - fn as_any(&self) -> &dyn Any {self} } impl Serial for HalfCurvatureRegulator { @@ -551,8 +508,8 @@ impl ProblemPoser for HalfCurvatureRegulator { self.set_point.with_untracked(|set_pt| { if let Some(val) = set_pt.value { let col = self.subject.column_index().expect( - "Subject should be indexed before half-curvature regulator writes problem data" - ); + indexing_error("Subject", &self.subject.id, + "half-curvature regulator").as_str()); problem.frozen.push(Sphere::CURVATURE_COMPONENT, col, val); } }); @@ -560,11 +517,18 @@ impl ProblemPoser for HalfCurvatureRegulator { } #[derive(Clone, Copy, Sequence)] -pub enum Axis {X = 0, Y = 1, Z = 2} +pub enum Axis { X = 0, Y = 1, Z = 2 } impl Axis { - pub const N_AXIS: usize = (Axis::Z as usize) + 1; - pub const NAME: [&str; Axis::N_AXIS] = ["X", "Y", "Z"]; + fn name(&self) -> &'static str { + match self { Axis::X => "X", Axis::Y => "Y", Axis::Z => "Z" } + } +} + +impl Display for Axis { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.name()) + } } pub struct PointCoordinateRegulator { @@ -593,7 +557,6 @@ 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 { @@ -601,19 +564,20 @@ impl ProblemPoser for PointCoordinateRegulator { self.set_point.with_untracked(|set_pt| { if let Some(val) = set_pt.value { let col = self.subject.column_index().expect( - "Subject must be indexed before point-coordinate regulator poses."); + indexing_error("Subject", &self.subject.id, + "point-coordinate regulator").as_str()); problem.frozen.push(self.axis as usize, col, val); - // Check if all three coordinates have been frozen, and if so, - // freeze the coradius as well - let mut coords = [0.0; Axis::N_AXIS]; + // If all three of the subject's spatial coordinates have been + // frozen, then freeze its norm component: + let mut coords = [0.0; Axis::CARDINALITY]; let mut nset: usize = 0; for &MatrixEntry {index, value} in &(problem.frozen) { - if index.1 == col && index.0 < Axis::N_AXIS { + if index.1 == col && index.0 < Axis::CARDINALITY { nset += 1; coords[index.0] = value } } - if nset == Axis::N_AXIS { + if nset == Axis::CARDINALITY { let [x, y, z] = coords; problem.frozen.push( Point::NORM_COMPONENT, col, point(x,y,z)[Point::NORM_COMPONENT]); @@ -746,12 +710,9 @@ 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( @@ -788,11 +749,6 @@ 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 --- @@ -831,6 +787,7 @@ impl Assembly { /* DEBUG */ // log the Gram matrix console_log!("Gram matrix:\n{}", problem.gram); + console_log!("Frozen entries:\n{}", problem.frozen); /* DEBUG */ // log the initial configuration matrix @@ -990,7 +947,8 @@ mod tests { use crate::engine; #[test] - #[should_panic(expected = "Sphere \"sphere\" should be indexed before writing problem data")] + #[should_panic(expected = + "Sphere \"sphere\" must be indexed before it writes problem data")] fn unindexed_element_test() { let _ = create_root(|| { let elt = Sphere::default("sphere".to_string(), 0); @@ -999,7 +957,8 @@ mod tests { } #[test] - #[should_panic(expected = "Subjects should be indexed before inversive distance regulator writes problem data")] + #[should_panic(expected = "Subject \"sphere1\" must be indexed before \ + inversive distance regulator writes problem data")] fn unindexed_subject_test_inversive_distance() { let _ = create_root(|| { let subjects = [0, 1].map( @@ -1060,4 +1019,4 @@ mod tests { assert!((final_half_curv / INITIAL_HALF_CURV - 1.0).abs() < DRIFT_TOL); }); } -} \ No newline at end of file +} diff --git a/app-proto/src/components/diagnostics.rs b/app-proto/src/components/diagnostics.rs index ce4a0b4..51d58f1 100644 --- a/app-proto/src/components/diagnostics.rs +++ b/app-proto/src/components/diagnostics.rs @@ -111,28 +111,6 @@ fn StepInput() -> View { } } -#[component] -fn DistortionGauge() -> View { - let state = use_context::(); - let total_distortion = create_memo(move || { - state.assembly.regulators.with(|regs| { - let mut total = 0.0; - for reg in regs { - if let Some(distortion) = reg.distortion() { - total += distortion.get(); - } - } - total - }) - }); - - view! { - div(id = "distortion-gauge") { - "Distortion: " (total_distortion.with(|distort| distort.to_string())) - } - } -} - fn into_log10_time_point((step, value): (usize, f64)) -> Vec> { vec![ Some(step as f64), @@ -337,7 +315,6 @@ pub fn Diagnostics() -> View { } DiagnosticsPanel(name = "loss") { LossHistory {} } DiagnosticsPanel(name = "spectrum") { SpectrumHistory {} } - DistortionGauge {} } } } \ No newline at end of file diff --git a/app-proto/src/components/outline.rs b/app-proto/src/components/outline.rs index ed6c921..547b73b 100644 --- a/app-proto/src/components/outline.rs +++ b/app-proto/src/components/outline.rs @@ -1,12 +1,11 @@ use itertools::Itertools; use std::rc::Rc; use sycamore::prelude::*; -use web_sys::{KeyboardEvent, MouseEvent, wasm_bindgen::{JsCast,}}; +use web_sys::{KeyboardEvent, MouseEvent, wasm_bindgen::JsCast}; use crate::{ AppState, assembly::{ - Axis, Element, HalfCurvatureRegulator, InversiveDistanceRegulator, @@ -123,10 +122,11 @@ impl OutlineItem for HalfCurvatureRegulator { impl OutlineItem for PointCoordinateRegulator { fn outline_item(self: Rc, _element: &Rc) -> View { + let name = format!("{} coordinate", self.axis); view! { li(class = "regulator") { - div(class = "regulator-label") { (Axis::NAME[self.axis as usize]) } - div(class = "regulator-type") { "Coordinate" } + div(class = "regulator-label") // for spacing + div(class = "regulator-type") { (name) } RegulatorInput(regulator = self) div(class = "status") } @@ -261,31 +261,6 @@ pub fn Outline() -> View { on:click = { let state = use_context::(); move |_| state.selection.update(|sel| sel.clear()) - }, - on:keydown = { - let rep_list = state.assembly.elements.map( - |elts| elts - .clone() - .into_iter() - .map(|elt| format!("{}: {}", elt.id(), elt.representation())) - .collect::>() - ); - - move |event: KeyboardEvent| { - match event.key().as_str() { - "c" => { - console_log!("Dumping all coordinates"); - rep_list.map( - |reps| { - for item in reps { - console_log!("{}", item); - } - } - ); - }, - _ => {}, - } - } } ) { Keyed( diff --git a/app-proto/src/components/test_assembly_chooser.rs b/app-proto/src/components/test_assembly_chooser.rs index 97dabd4..0d387d3 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, SQRT_2}, rc::Rc}; +use std::{f64::consts::{FRAC_1_SQRT_2, PI}, rc::Rc}; use nalgebra::Vector3; use sycamore::prelude::*; use web_sys::{console, wasm_bindgen::JsValue}; @@ -12,80 +12,13 @@ use crate::{ ElementColor, InversiveDistanceRegulator, Point, - PointCoordinateRegulator, - Regulator, Sphere, }, engine, - engine::{DescentHistory, point}, + engine::DescentHistory, specified::SpecifiedValue, }; -// Convenience: macro to allow elision of const array lengths -// adapted from https://stackoverflow.com/a/59905715 -macro_rules! const_array { - ($name: ident: $ty: ty = $value: expr) => { - const $name: [$ty; $value.len()] = $value; - } -} - -// Convenience: use sqrt() as a function to get the square root of -// anything that can be losslessly converted to f64, since we happen -// to always want our sqrts to be f64. -// RUST KVETCHES: (I) Why is this so convoluted? -// In particular, what would be so bad about allowing -// const fn sqrt>(x: T) -> f64 { (x as f64).sqrt() } -// ??? -// (II) Oh dear, sqrt is not computable in a const context, so we have to -// roll our own. I hope I get it right! I definitely don't know how to ensure -// that the final double is correctly rounded :-( - -const SIXTH: f64 = 1./6.; -const FOURTH: f64 = 1./4.; -const fn invsqrt(xin: f64) -> f64 { - if !xin.is_finite() { return f64::NAN; } - let mut log4 = 0; - let mut x = xin; - while x < 1. { x *= 4.; log4 -= 1; } - while x > 4. { x *= FOURTH; log4 += 1; } - let mut next = 1.1 - SIXTH * x; - let mut diff = 1.; - while diff > 4. * f64::EPSILON { // termination condition?? - let last = next; - next = last * (1.5 - 0.5 * x * last * last); - diff = next - last; - if diff < 0. { diff *= -1.; } - } - while log4 > 0 { next *= 0.5; log4 -= 1; } - while log4 < 0 { next *= 2.; log4 += 1; } - return next; -} - -#[const_trait] -trait ConstSqrt {fn sqr(self) -> f64;} -impl const ConstSqrt for f64 {fn sqr(self) -> f64 {self * invsqrt(self)}} -impl const ConstSqrt for i32 {fn sqr(self) -> f64 {(self as f64).sqr()}} -const fn sqrt(x: T) -> f64 {x.sqr()} - -// RUST KVETCHES: (I) It is annoying that we must redundantly specify -// the type of the well-typed RHS to assign it to a const. -// See https://github.com/rust-lang/rfcs/pull/3546 -// Can we fix this in husht? Seems like we will need to be able to do full -// rust type inference in the transpiler; how will we accomplish that? -// (2) It is very annoying that there doesn't seem to be any way to specify -// that we want an expression like `5.0 / 2` to be evaluated by converting -// the 2 to a float, because of the "orphan rule". Can we fix this in husht? -// Again, it seems we would need full rust type inference. - -// 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 */ @@ -96,37 +29,49 @@ const BLUE: ElementColor = [0., 0.25, 1.]; fn load_general(assembly: &Assembly) { let _ = assembly.try_insert_element( Sphere::new( - "gemini_a", "Castor", [1.00, 0.25, 0.00], + 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( Sphere::new( - "gemini_b", "Pollux", BLUE, + 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( Sphere::new( - "ursa_major", "Ursa major", [0.25, 0.00, 1.00], + 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( Sphere::new( - "ursa_minor", "Ursa minor", GREEN, + 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( Sphere::new( - "moon_deimos", "Deimos", [0.75, 0.75, 0.00], + 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( Sphere::new( - "moon_phobos", "Phobos", [0.00, 0.75, 0.50], + 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), ) ); @@ -134,66 +79,88 @@ fn load_general(assembly: &Assembly) { fn load_low_curvature(assembly: &Assembly) { // create the spheres - const A: f64 = sqrt(0.75); + let a = 0.75_f64.sqrt(); let _ = assembly.try_insert_element( Sphere::new( - "central", "Central", GRAY, + "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( Sphere::new( - "assemb_plane", "Assembly plane", GRAY, + "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( Sphere::new( - "side1", "Side 1", RED, + "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( Sphere::new( - "side2", "Side 2", GREEN, - engine::sphere_with_offset(-0.5, A, 0.0, 1.0, 0.0), + "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( Sphere::new( - "side3", "Side 3", BLUE, - engine::sphere_with_offset(-0.5, -A, 0.0, 1.0, 0.0), + "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( Sphere::new( - "corner1", "Corner 1", GRAY, + "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( Sphere::new( - "corner2", "Corner 2", GRAY, - engine::sphere(2.0/3.0, -4.0/3.0 * A, 0.0, 1.0/3.0), + "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( Sphere::new( - "corner3", "Corner 3", GRAY, - engine::sphere(2.0/3.0, 4.0/3.0 * A, 0.0, 1.0/3.0), + 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), ) ); // impose the desired tangencies and make the sides planar let index_range = 1..=3; let [central, assemb_plane] = ["central", "assemb_plane"].map( - |id| assembly.find_element(id) + |id| assembly.elements_by_id.with_untracked( + |elts_by_id| elts_by_id[id].clone() + ) ); let sides = index_range.clone().map( - |k| assembly.find_element(&format!("side{k}")) + |k| assembly.elements_by_id.with_untracked( + |elts_by_id| elts_by_id[&format!("side{k}")].clone() + ) ); let corners = index_range.map( - |k| assembly.find_element(&format!("corner{k}")) + |k| assembly.elements_by_id.with_untracked( + |elts_by_id| elts_by_id[&format!("corner{k}")].clone() + ) ); for plane in [assemb_plane.clone()].into_iter().chain(sides.clone()) { // fix the curvature of each plane @@ -232,16 +199,16 @@ fn load_low_curvature(assembly: &Assembly) { fn load_pointed(assembly: &Assembly) { let _ = assembly.try_insert_element( Point::new( - "point_front", - "Front point", + format!("point_front"), + format!("Front point"), [0.75_f32, 0.75_f32, 0.75_f32], engine::point(0.0, 0.0, FRAC_1_SQRT_2), ) ); let _ = assembly.try_insert_element( Point::new( - "point_back", - "Back point", + format!("point_back"), + format!("Back point"), [0.75_f32, 0.75_f32, 0.75_f32], engine::point(0.0, 0.0, -FRAC_1_SQRT_2), ) @@ -253,8 +220,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), ) @@ -262,8 +229,8 @@ fn load_pointed(assembly: &Assembly) { let _ = assembly.try_insert_element( Point::new( - &format!("point{index_x}{index_y}"), - &format!("Point {index_x}{index_y}"), + format!("point{index_x}{index_y}"), + format!("Point {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::point(x, y, 0.0), ) @@ -281,42 +248,91 @@ fn load_pointed(assembly: &Assembly) { // A-C -0.25 * φ^2 = -0.6545084971874737 fn load_tridiminished_icosahedron(assembly: &Assembly) { // create the vertices - const COLOR_A: ElementColor = [1.00, 0.25, 0.25]; - const COLOR_B: ElementColor = [0.75, 0.75, 0.75]; - const COLOR_C: ElementColor = [0.25, 0.50, 1.00]; + const COLOR_A: ElementColor = [1.00_f32, 0.25_f32, 0.25_f32]; + const COLOR_B: ElementColor = [0.75_f32, 0.75_f32, 0.75_f32]; + const COLOR_C: ElementColor = [0.25_f32, 0.50_f32, 1.00_f32]; let vertices = [ - Point::new("a1", "A₁", COLOR_A, point( 0.25, 0.75, 0.75)), - Point::new("a2", "A₂", COLOR_A, point( 0.75, 0.25, 0.75)), - Point::new("a3", "A₃", COLOR_A, point( 0.75, 0.75, 0.25)), - Point::new("b1", "B₁", COLOR_B, point( 0.75, -0.25, -0.25)), - Point::new("b2", "B₂", COLOR_B, point(-0.25, 0.75, -0.25)), - Point::new("b3", "B₃", COLOR_B, point(-0.25, -0.25, 0.75)), - Point::new("c1", "C₁", COLOR_C, point( 0.0, -1.0, -1.0)), - Point::new("c2", "C₂", COLOR_C, point(-1.0, 0.0, -1.0)), - Point::new("c3", "C₃", COLOR_C, point(-1.0, -1.0, 0.0)), + Point::new( + "a1".to_string(), + "A₁".to_string(), + COLOR_A, + engine::point(0.25, 0.75, 0.75), + ), + Point::new( + "a2".to_string(), + "A₂".to_string(), + COLOR_A, + engine::point(0.75, 0.25, 0.75), + ), + Point::new( + "a3".to_string(), + "A₃".to_string(), + COLOR_A, + engine::point(0.75, 0.75, 0.25), + ), + Point::new( + "b1".to_string(), + "B₁".to_string(), + COLOR_B, + engine::point(0.75, -0.25, -0.25), + ), + Point::new( + "b2".to_string(), + "B₂".to_string(), + COLOR_B, + engine::point(-0.25, 0.75, -0.25), + ), + Point::new( + "b3".to_string(), + "B₃".to_string(), + COLOR_B, + engine::point(-0.25, -0.25, 0.75), + ), + Point::new( + "c1".to_string(), + "C₁".to_string(), + COLOR_C, + engine::point(0.0, -1.0, -1.0), + ), + Point::new( + "c2".to_string(), + "C₂".to_string(), + COLOR_C, + engine::point(-1.0, 0.0, -1.0), + ), + Point::new( + "c3".to_string(), + "C₃".to_string(), + COLOR_C, + engine::point(-1.0, -1.0, 0.0), + ), ]; for vertex in vertices { let _ = assembly.try_insert_element(vertex); } // create the faces - const SQRT_1_6: f64 = invsqrt(6.); - const SQRT_2_3: f64 = 2. * SQRT_1_6; + const COLOR_FACE: ElementColor = [0.75_f32, 0.75_f32, 0.75_f32]; + let frac_1_sqrt_6 = 1.0 / 6.0_f64.sqrt(); + let frac_2_sqrt_6 = 2.0 * frac_1_sqrt_6; let faces = [ Sphere::new( - "face1", "Face 1", GRAY, - engine::sphere_with_offset( - SQRT_2_3, -SQRT_1_6, -SQRT_1_6, -SQRT_1_6, 0.0), + "face1".to_string(), + "Face 1".to_string(), + COLOR_FACE, + engine::sphere_with_offset(frac_2_sqrt_6, -frac_1_sqrt_6, -frac_1_sqrt_6, -frac_1_sqrt_6, 0.0), ), Sphere::new( - "face2", "Face 2", GRAY, - engine::sphere_with_offset( - -SQRT_1_6, SQRT_2_3, -SQRT_1_6, -SQRT_1_6, 0.0), + "face2".to_string(), + "Face 2".to_string(), + COLOR_FACE, + engine::sphere_with_offset(-frac_1_sqrt_6, frac_2_sqrt_6, -frac_1_sqrt_6, -frac_1_sqrt_6, 0.0), ), Sphere::new( - "face3", "Face 3", GRAY, - engine::sphere_with_offset( - -SQRT_1_6, -SQRT_1_6, SQRT_2_3, -SQRT_1_6, 0.0), + "face3".to_string(), + "Face 3".to_string(), + COLOR_FACE, + engine::sphere_with_offset(-frac_1_sqrt_6, -frac_1_sqrt_6, frac_2_sqrt_6, -frac_1_sqrt_6, 0.0), ), ]; for face in faces { @@ -397,7 +413,9 @@ fn load_dodecahedral_packing(assembly: &Assembly) { // add the substrate let _ = assembly.try_insert_element( Sphere::new( - "substrate", "Substrate", GRAY, + "substrate".to_string(), + "Substrate".to_string(), + [0.75_f32, 0.75_f32, 0.75_f32], engine::sphere(0.0, 0.0, 0.0, 1.0), ) ); @@ -416,16 +434,17 @@ fn load_dodecahedral_packing(assembly: &Assembly) { const COLOR_A: ElementColor = [1.00_f32, 0.25_f32, 0.00_f32]; const COLOR_B: ElementColor = [1.00_f32, 0.00_f32, 0.25_f32]; const COLOR_C: ElementColor = [0.25_f32, 0.00_f32, 1.00_f32]; - const PHI_INV: f64 = 1.0 / PHI; - const COORD_SCALE: f64 = sqrt(PHI + 2.0); - const_array!(FACE_SCALES: f64 = [PHI_INV, (13.0 / 12.0) / COORD_SCALE]); - const_array!(FACE_RADII: f64 = [PHI_INV, 5.0 / 12.0]); + let phi = 0.5 + 1.25_f64.sqrt(); /* TO DO */ // replace with std::f64::consts::PHI when that gets stabilized + let phi_inv = 1.0 / phi; + let coord_scale = (phi + 2.0).sqrt(); + let face_scales = [phi_inv, (13.0 / 12.0) / coord_scale]; + let face_radii = [phi_inv, 5.0 / 12.0]; let mut faces = Vec::>::new(); let subscripts = ["₀", "₁"]; for j in 0..2 { for k in 0..2 { - let small_coord = FACE_SCALES[k] * if j > 0 {1.} else {-1.}; - let big_coord = FACE_SCALES[k] * PHI * if k > 0 {1.} else {-1.}; + let small_coord = face_scales[k] * (2.0*(j as f64) - 1.0); + let big_coord = face_scales[k] * (2.0*(k as f64) - 1.0) * phi; let id_num = format!("{j}{k}"); let label_sub = format!("{}{}", subscripts[j], subscripts[k]); @@ -434,10 +453,10 @@ fn load_dodecahedral_packing(assembly: &Assembly) { let id_a = format!("a{id_num}"); let _ = assembly.try_insert_element( Sphere::new( - &id_a, - &format!("A{label_sub}"), + id_a.clone(), + format!("A{label_sub}"), COLOR_A, - engine::sphere(0.0, small_coord, big_coord, FACE_RADII[k]), + engine::sphere(0.0, small_coord, big_coord, face_radii[k]), ) ); faces.push( @@ -450,10 +469,10 @@ fn load_dodecahedral_packing(assembly: &Assembly) { let id_b = format!("b{id_num}"); let _ = assembly.try_insert_element( Sphere::new( - &id_b, - &format!("B{label_sub}"), + id_b.clone(), + format!("B{label_sub}"), COLOR_B, - engine::sphere(small_coord, big_coord, 0.0, FACE_RADII[k]), + engine::sphere(small_coord, big_coord, 0.0, face_radii[k]), ) ); faces.push( @@ -466,10 +485,10 @@ fn load_dodecahedral_packing(assembly: &Assembly) { let id_c = format!("c{id_num}"); let _ = assembly.try_insert_element( Sphere::new( - &id_c, - &format!("C{label_sub}"), + id_c.clone(), + format!("C{label_sub}"), COLOR_C, - engine::sphere(big_coord, 0.0, small_coord, FACE_RADII[k]), + engine::sphere(big_coord, 0.0, small_coord, face_radii[k]), ) ); faces.push( @@ -537,9 +556,23 @@ fn load_balanced(assembly: &Assembly) { const R_INNER: f64 = 4.0; let spheres = [ Sphere::new( - "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)), + "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), + ), ]; for sphere in spheres { let _ = assembly.try_insert_element(sphere); @@ -547,7 +580,9 @@ fn load_balanced(assembly: &Assembly) { // get references to the spheres let [outer, a, b] = ["outer", "a", "b"].map( - |id| assembly.find_element(id) + |id| assembly.elements_by_id.with_untracked( + |elts_by_id| elts_by_id[id].clone() + ) ); // fix the diameters of the outer, sun, and moon spheres @@ -579,22 +614,32 @@ 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", GRAY, point(1e-9, 0.0, 0.0)), + Point::new( + "point".to_string(), + "Point".to_string(), + [0.75_f32, 0.75_f32, 0.75_f32], + engine::point(1e-9, 0.0, 0.0), + ), ); let _ = assembly.try_insert_element( Sphere::new( - "sphere", "Sphere", GRAY, engine::sphere(0.0, 0.0, 0.0, 1.0)), + "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), + ), ); - // get references to the elements let point_and_sphere = ["point", "sphere"].map( - |id| assembly.find_element(id) + |id| assembly.elements_by_id.with_untracked( + |elts_by_id| elts_by_id[id].clone() + ) ); // put the point on the sphere let incidence = InversiveDistanceRegulator::new(point_and_sphere); - incidence.set_to(0.); + incidence.set_point.set(SpecifiedValue::try_from("0".to_string()).unwrap()); assembly.insert_regulator(Rc::new(incidence)); } @@ -607,13 +652,18 @@ fn load_radius_ratio(assembly: &Assembly) { let index_range = 1..=4; // create the spheres + const GRAY: ElementColor = [0.75_f32, 0.75_f32, 0.75_f32]; let spheres = [ Sphere::new( - "sphere_faces", "Insphere", GRAY, + "sphere_faces".to_string(), + "Insphere".to_string(), + GRAY, engine::sphere(0.0, 0.0, 0.0, 0.5), ), Sphere::new( - "sphere_vertices", "Circumsphere", GRAY, + "sphere_vertices".to_string(), + "Circumsphere".to_string(), + GRAY, engine::sphere(0.0, 0.0, 0.0, 0.25), ), ]; @@ -639,8 +689,8 @@ fn load_radius_ratio(assembly: &Assembly) { ).map( |(k, color, representation)| { Point::new( - &format!("v{k}"), - &format!("Vertex {k}"), + format!("v{k}"), + format!("Vertex {k}"), color, representation, ) @@ -670,8 +720,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, ) @@ -684,18 +734,27 @@ 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.find_element(&id)); - + 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() + ) + ); // make the faces planar let curvature_regulator = face_j.regulators().with_untracked( |regs| regs.first().unwrap().clone() ); - curvature_regulator.set_to(0.); + curvature_regulator.set_point().set( + SpecifiedValue::try_from("0".to_string()).unwrap() + ); for k in index_range.clone().filter(|&index| index != j) { - let vertex_k = assembly.find_element(&format!("v{k}")); + let vertex_k = assembly.elements_by_id.with_untracked( + |elts_by_id| elts_by_id[&format!("v{k}")].clone() + ); // fix the distances between the vertices if j < k { @@ -707,7 +766,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_to(0.); + incidence_regulator.set_point.set(SpecifiedValue::try_from("0".to_string()).unwrap()); assembly.insert_regulator(Rc::new(incidence_regulator)); } } @@ -733,26 +792,32 @@ fn load_radius_ratio(assembly: &Assembly) { fn load_irisawa_hexlet(assembly: &Assembly) { let index_range = 1..=6; let colors = [ - [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], + [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], ].into_iter(); // create the spheres let spheres = [ Sphere::new( - "outer", "Outer", gray(0.5), + "outer".to_string(), + "Outer".to_string(), + [0.5_f32, 0.5_f32, 0.5_f32], engine::sphere(0.0, 0.0, 0.0, 1.5), ), Sphere::new( - "sun", "Sun", GRAY, + "sun".to_string(), + "Sun".to_string(), + [0.75_f32, 0.75_f32, 0.75_f32], engine::sphere(0.0, -0.75, 0.0, 0.75), ), Sphere::new( - "moon", "Moon", gray(0.25), + "moon".to_string(), + "Moon".to_string(), + [0.25_f32, 0.25_f32, 0.25_f32], engine::sphere(0.0, 0.75, 0.0, 0.75), ), ].into_iter().chain( @@ -760,8 +825,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), ) @@ -773,7 +838,9 @@ fn load_irisawa_hexlet(assembly: &Assembly) { } // put the outer sphere in ghost mode and fix its curvature - let outer = assembly.find_element("outer"); + let outer = assembly.elements_by_id.with_untracked( + |elts_by_id| elts_by_id["outer"].clone() + ); outer.ghost().set(true); let outer_curvature_regulator = outer.regulators().with_untracked( |regs| regs.first().unwrap().clone() @@ -783,9 +850,15 @@ fn load_irisawa_hexlet(assembly: &Assembly) { ); // impose the desired tangencies - let [sun, moon] = ["sun", "moon"].map(|id| assembly.find_element(id)); + let [outer, sun, moon] = ["outer", "sun", "moon"].map( + |id| assembly.elements_by_id.with_untracked( + |elts_by_id| elts_by_id[id].clone() + ) + ); let chain = index_range.map( - |k| assembly.find_element(&format!("chain{k}")) + |k| assembly.elements_by_id.with_untracked( + |elts_by_id| elts_by_id[&format!("chain{k}")].clone() + ) ); for (chain_sphere, chain_sphere_next) in chain.clone().zip(chain.cycle().skip(1)) { for (other_sphere, inversive_distance) in [ @@ -809,192 +882,6 @@ fn load_irisawa_hexlet(assembly: &Assembly) { assembly.insert_regulator(Rc::new(outer_moon_tangency)); } -const HPHI: f64 = PHI / 2.; // "half phi" -const RTHPHI: f64 = sqrt(HPHI); // "root half phi" -const RTPHIPH: f64 = sqrt(PHI + 0.5); // "root phi plus (half)" -const P: bool = true; // Pinned -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; 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.822], F, 1, "A_NE,A_SE"), - ("Z_S", [ 0.002, -0.229, 0.822], 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.897], F, 2, "A_SE,Z_E,Z_S"), - ("Y_NE", [ 0.11, 0.104, 1.019], F, 3, "B_NE"), - ("Y_NW", [-0.104, 0.104, 1.019], F, 3, "B_NW"), - ("Y_SE", [ 0.11, -0.11, 1.018], F, 3, "B_SE"), - ("Y_SW", [-0.104, -0.11, 1.019], F, 3, "B_SW"), - ("C_N", [ 0., 1., RTPHIPH], P, 4, "B_NE,B_NW,Y_NE,Y_NW"), - ("C_W", [-1., 0., RTPHIPH], P, 4, "B_NW,B_SW,Y_NW,Y_SW"), - ("C_E", [ 1.003, -0.003, 1.454], F, 4, "Z_E,B_NE,B_SE,Y_NE,Y_SE"), - ("C_S", [ 0.003, -1.003, 1.454], F, 4, "Z_S,B_SE,B_SW,Y_SE,Y_SW"), - ("D_NE", [ 0.195, 0.186, 2.012], F, 5, "Y_NE,C_N,C_E"), - ("D_NW", [-0.186, 0.186, 2.012], F, 5, "Y_NW,C_N,C_W"), - ("D_SE", [ 0.195, -0.195, 2.011], F, 5, "Y_SE,C_E,C_S"), - ("D_SW", [-0.186, -0.195, 2.012], F, 5, "Y_SW,C_W,C_S"), - ("E_N", [ 0.005, 1.062, 2.455], F, 6, "C_N,D_NE,D_NW"), - ("E_W", [-1.063, -0.005, 2.455], F, 6, "C_W,D_NW,D_SW"), - ("E_E", [ 1.072, -0.005, 2.452], F, 6, "C_E,D_NE,D_SE"), - ("E_S", [ 0.005, -1.072, 2.452], F, 6, "C_S,D_SE,D_SW"), - ("F_NE", [ 0.286, 0.275, 3.003], F, 7, "D_NE,E_N,E_E"), - ("F_NW", [-0.275, 0.275, 3.004], F, 7, "D_NW,E_N,E_W"), - ("F_SE", [ 0.286, -0.286, 3.003], F, 7, "D_SE,E_E,E_S"), - ("F_SW", [-0.275, -0.286, 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.506, 1.201, 3.309], F, 8, "E_N,F_NE"), - ("G_2", [ 1.213, 0.494, 3.307], F, 8, "E_E,F_NE"), - ("G_4", [ 1.213, -0.506, 3.306], F, 8, "E_E,F_SE"), - ("G_5", [ 0.506, -1.213, 3.306], F, 8, "E_S,F_SE"), - ("G_7", [-0.494, -1.213, 3.307], F, 8, "E_S,F_SW"), - ("G_8", [-1.201, -0.506, 3.309], F, 8, "E_W,F_SW"), - ("G_10", [-1.201, 0.494, 3.311], F, 8, "E_W,F_NW"), - ("G_11", [-0.494, 1.201, 3.311], F, 8, "E_N,F_NW"), -]); - -const_array!(LEVEL_COLORS: ElementColor = [ - [0.75, 0., 0.75], - [1., 0.4, 0.6], - [1., 0., 0.25], - [1., 0.75, 0.25], - [0.75, 0.5, 0.], - [0.9, 0.9, 0.], - [0.25, 0.75, 0.], - [0., 0.5, 0.75], - [0.25, 0., 1.], - [0.6, 0.15, 0.6], - [0.9, 0.5, 0.6], - [0.85, 0.15, 0.35] -]); - -fn load_554aug2(assembly: &Assembly) { - // 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); - // 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? Or could/should try_insert_element return - // the Rc ? - let pt_rc = assembly.find_element(id); - - if pinned { // regulate each coordinate to its given value - let mut freeze = Vec::>::new(); - // 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 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()]); - if offset == 1 { 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()]); - if offset == 1 { dist.set_to(OCT_DIST[offset]); } - assembly.insert_regulator(Rc::new(dist)); - } - } - } - // Finally, add any specified neighbors - for id in neighbors.split(",") { - if id.len() == 0 { continue; } - let strut = InversiveDistanceRegulator::new( - [assembly.find_element(id), pt_rc.clone()]); - strut.set_to(-0.5); - assembly.insert_regulator(Rc::new(strut)); - } - } -} - -const_array!(ACRON554_DOME: (&str, [f64; 3], bool, usize, &str) = [ - // id, coordinates, Pin/Free, level, earlier neighbor IDs. - ("H_E", [ 0.359, -0.006, 3.161], F, 9, "G_2,G_4"), - ("H_N", [ 0.005, 0.348, 3.158], F, 9, "G_1,G_11"), - ("H_S", [ 0.006, 0.359, 3.159], F, 9, "G_5,G_7"), - ("H_W", [-0.347, -0.005, 3.163], F, 9, "G_8,G_10"), - ("I_NE", [ 0.507, 0.493, 4.015], F, 10, "G_1,G_2,H_E,H_N"), - ("I_NW", [-0.493, 0.493, 4.013], F, 10, "G_10,G_11,H_N,H_W"), - ("I_SE", [ 0.507, -0.507, 4.012], F, 10, "G_4,G_5,H_E,H_S"), - ("I_SW", [-0.493, -0.507, 4.015], F, 10, "G_7,G_8,H_S,H_W"), - ("J", [ 0.004, -0.010, 3.303], F, 11, "I_NE,I_NW,I_SE,I_SW"), -]); - -fn load_554domed(assembly: &Assembly) { - load_554aug2(assembly); - // Now process the additional data - for (id, v, _pinned, l, neighbors) in ACRON554_DOME { - let pt = Point::new(id, id, LEVEL_COLORS[l], point(v[0], v[1], v[2])); - assembly.try_insert_element(pt); - let pt_rc = assembly.find_element(id); - // Add any specified neighbors - for id in neighbors.split(",") { - if id.len() == 0 { continue; } - let strut = InversiveDistanceRegulator::new( - [assembly.find_element(id), pt_rc.clone()]); - strut.set_to(-0.5); - assembly.insert_regulator(Rc::new(strut)); - } - } -} - // --- chooser --- /* DEBUG */ @@ -1031,15 +918,11 @@ pub fn TestAssemblyChooser() -> View { "off-center" => load_off_center(assembly), "radius-ratio" => load_radius_ratio(assembly), "irisawa-hexlet" => load_irisawa_hexlet(assembly), - "aug554" => load_554aug2(assembly), - "domed554" => load_554domed(assembly), _ => (), }; }); }); - - // FIXME: Non-DRY -- should not need to reiterate thie list of assembly - // labels + // build the chooser view! { select(bind:value = assembly_name) { @@ -1052,8 +935,6 @@ pub fn TestAssemblyChooser() -> View { option(value = "off-center") { "Off-center" } option(value = "radius-ratio") { "Radius ratio" } option(value = "irisawa-hexlet") { "Irisawa hexlet" } - option(value = "aug554") { "McNeill acron 554" } - option(value = "domed554") { "Domed acron 554" } option(value = "empty") { "Empty" } } } diff --git a/app-proto/src/engine.rs b/app-proto/src/engine.rs index feb23cf..0f26f02 100644 --- a/app-proto/src/engine.rs +++ b/app-proto/src/engine.rs @@ -46,7 +46,7 @@ pub fn project_sphere_to_normalized(rep: &mut DVector) { // normalize a point's representation vector by scaling pub fn project_point_to_normalized(rep: &mut DVector) { - rep.scale_mut(0.5 / rep[3]); //FIXME: This 3 should be Point::WEIGHT_COMPONENT + rep.scale_mut(0.5 / rep[3]); } // --- partial matrices --- diff --git a/app-proto/src/lib.rs b/app-proto/src/lib.rs index f37e0d6..0d9bc4a 100644 --- a/app-proto/src/lib.rs +++ b/app-proto/src/lib.rs @@ -1,3 +1 @@ -#![feature(const_trait_impl)] - pub mod engine; \ No newline at end of file diff --git a/app-proto/src/main.rs b/app-proto/src/main.rs index cb51571..a03b026 100644 --- a/app-proto/src/main.rs +++ b/app-proto/src/main.rs @@ -1,5 +1,3 @@ -#![feature(const_trait_impl)] - mod assembly; mod components; mod engine; diff --git a/data554/pinnedAug2.txt b/data554/pinnedAug2.txt deleted file mode 100644 index d0e051e..0000000 --- a/data554/pinnedAug2.txt +++ /dev/null @@ -1,378 +0,0 @@ -A_NE: - ┌ ┐ - │ 0.5 │ - │ 0.5 │ - │ 0 │ - │ 0.5 │ - │ 0.25 │ - └ ┘ - - -A_NW: - ┌ ┐ - │ -0.5 │ - │ 0.5 │ - │ 0 │ - │ 0.5 │ - │ 0.25 │ - └ ┘ - - -A_SE: - ┌ ┐ - │ 0.5 │ - │ -0.5 │ - │ 0 │ - │ 0.5 │ - │ 0.25 │ - └ ┘ - - -A_SW: - ┌ ┐ - │ -0.5 │ - │ -0.5 │ - │ 0 │ - │ 0.5 │ - │ 0.25 │ - └ ┘ - - -Z_E: - ┌ ┐ - │ 0.22634143549538555 │ - │ 0.000032427771744506665 │ - │ 0.8216513780396574 │ - │ 0.5 │ - │ 0.363170717377161 │ - └ ┘ - - -Z_S: - ┌ ┐ - │ -0.000032427771744220924 │ - │ -0.22634143549538618 │ - │ 0.8216513780396576 │ - │ 0.5 │ - │ 0.36317071737716133 │ - └ ┘ - - -B_NE: - ┌ ┐ - │ 0.8090169943749475 │ - │ 0.8090169943749475 │ - │ 0.8994537199739336 │ - │ 0.5 │ - │ 1.0590169943749475 │ - └ ┘ - - -B_NW: - ┌ ┐ - │ -0.8090169943749475 │ - │ 0.8090169943749475 │ - │ 0.8994537199739336 │ - │ 0.5 │ - │ 1.0590169943749475 │ - └ ┘ - - -B_SW: - ┌ ┐ - │ -0.8090169943749475 │ - │ -0.8090169943749475 │ - │ 0.8994537199739336 │ - │ 0.5 │ - │ 1.0590169943749475 │ - └ ┘ - - -B_SE: - ┌ ┐ - │ 0.8089673881587364 │ - │ -0.8089673881587335 │ - │ 0.8995105586041169 │ - │ 0.5 │ - │ 1.0589799582637938 │ - └ ┘ - - -Y_NE: - ┌ ┐ - │ 0.10684030416478518 │ - │ 0.1069861535711018 │ - │ 1.0181778574241942 │ - │ 0.5 │ - │ 0.5297735192825956 │ - └ ┘ - - -Y_NW: - ┌ ┐ - │ -0.10693925692260356 │ - │ 0.10693925692260356 │ - │ 1.0182278452645257 │ - │ 0.5 │ - │ 0.5298299819167654 │ - └ ┘ - - -Y_SE: - ┌ ┐ - │ 0.10684605297358556 │ - │ -0.10684605297358302 │ - │ 1.0181767492960683 │ - │ 0.5 │ - │ 0.5297580227088338 │ - └ ┘ - - -Y_SW: - ┌ ┐ - │ -0.10698615357110258 │ - │ -0.10684030416478382 │ - │ 1.0181778574241929 │ - │ 0.5 │ - │ 0.5297735192825943 │ - └ ┘ - - -C_N: - ┌ ┐ - │ 0 │ - │ 1 │ - │ 1.4553466902253547 │ - │ 0.5 │ - │ 1.5590169943749472 │ - └ ┘ - - -C_W: - ┌ ┐ - │ -1 │ - │ 0 │ - │ 1.4553466902253547 │ - │ 0.5 │ - │ 1.5590169943749472 │ - └ ┘ - - -C_E: - ┌ ┐ - │ 0.9997685166344451 │ - │ 0.000045591796741388215 │ - │ 1.4555126531079483 │ - │ 0.5 │ - │ 1.5590202705588938 │ - └ ┘ - - -C_S: - ┌ ┐ - │ -0.00004559179673933571 │ - │ -0.9997685166344433 │ - │ 1.4555126531079468 │ - │ 0.5 │ - │ 1.5590202705588896 │ - └ ┘ - - -D_NE: - ┌ ┐ - │ 0.19050130249898212 │ - │ 0.19080920821293734 │ - │ 2.0111349254444733 │ - │ 0.5 │ - │ 2.0586841044725492 │ - └ ┘ - - -D_NW: - ┌ ┐ - │ -0.19087531658436754 │ - │ 0.1908753165843677 │ - │ 2.0111018697108243 │ - │ 0.5 │ - │ 2.058720870516732 │ - └ ┘ - - -D_SE: - ┌ ┐ - │ 0.1904710244638656 │ - │ -0.1904710244638643 │ - │ 2.011170408319603 │ - │ 0.5 │ - │ 2.0586783801164676 │ - └ ┘ - - -D_SW: - ┌ ┐ - │ -0.19080920821293662 │ - │ -0.19050130249898098 │ - │ 2.011134925444472 │ - │ 0.5 │ - │ 2.0586841044725475 │ - └ ┘ - - -E_N: - ┌ ┐ - │ -0.0001774225161991373 │ - │ 1.0673561656973407 │ - │ 2.453087108367921 │ - │ 0.5 │ - │ 3.5784389787247153 │ - └ ┘ - - -E_W: - ┌ ┐ - │ -1.0673561656973403 │ - │ 0.00017742251619961636 │ - │ 2.4530871083679195 │ - │ 0.5 │ - │ 3.578438978724712 │ - └ ┘ - - -E_E: - ┌ ┐ - │ 1.0669548967200053 │ - │ 0.0001843766584768728 │ - │ 2.4532662028373866 │ - │ 0.5 │ - │ 3.5784510553790545 │ - └ ┘ - - -E_S: - ┌ ┐ - │ -0.00018437665847651806 │ - │ -1.0669548967200044 │ - │ 2.453266202837385 │ - │ 0.5 │ - │ 3.57845105537905 │ - └ ┘ - - -F_NE: - ┌ ┐ - │ 0.28011657185554717 │ - │ 0.280597474289424 │ - │ 3.003049209443169 │ - │ 0.5 │ - │ 4.587753011062896 │ - └ ┘ - - -F_NW: - ┌ ┐ - │ -0.280598407806719 │ - │ 0.28059840780671874 │ - │ 3.002988046197754 │ - │ 0.5 │ - │ 4.587705454166589 │ - └ ┘ - - -F_SE: - ┌ ┐ - │ 0.28011643423019444 │ - │ -0.2801164342301949 │ - │ 3.0031051243209257 │ - │ 0.5 │ - │ 4.587785491049536 │ - └ ┘ - - -F_SW: - ┌ ┐ - │ -0.2805974742894247 │ - │ -0.28011657185554784 │ - │ 3.003049209443168 │ - │ 0.5 │ - │ 4.587753011062893 │ - └ ┘ - - -G_1: - ┌ ┐ - │ 0.4997377212516245 │ - │ 1.2073683664308739 │ - │ 3.3077679987306667 │ - │ 0.5 │ - │ 6.324404048677748 │ - └ ┘ - - -G_2: - ┌ ┐ - │ 1.2068449832232118 │ - │ 0.5002622274345682 │ - │ 3.307880423181695 │ - │ 0.5 │ - │ 6.3244041808325075 │ - └ ┘ - - -G_4: - ┌ ┐ - │ 1.2068444751045393 │ - │ -0.4997377595067899 │ - │ 3.307966697528916 │ - │ 0.5 │ - │ 6.324427820224868 │ - └ ┘ - - -G_5: - ┌ ┐ - │ 0.4997377595067881 │ - │ -1.2068444751045408 │ - │ 3.307966697528914 │ - │ 0.5 │ - │ 6.324427820224864 │ - └ ┘ - - -G_7: - ┌ ┐ - │ -0.5002622274345697 │ - │ -1.2068449832232129 │ - │ 3.307880423181691 │ - │ 0.5 │ - │ 6.324404180832497 │ - └ ┘ - - -G_8: - ┌ ┐ - │ -1.2073683664308756 │ - │ -0.4997377212516256 │ - │ 3.307767998730663 │ - │ 0.5 │ - │ 6.3244040486777395 │ - └ ┘ - - -G_10: - ┌ ┐ - │ -1.2073693671510268 │ - │ 0.50026206687508 │ - │ 3.307678829535478 │ - │ 0.5 │ - │ 6.3243704479462215 │ - └ ┘ - - -G_11: - ┌ ┐ - │ -0.5002620668750811 │ - │ 1.2073693671510257 │ - │ 3.30767882953548 │ - │ 0.5 │ - │ 6.324370447946225 │ - └ ┘ diff --git a/data554/pinnedDomed1.txt b/data554/pinnedDomed1.txt deleted file mode 100644 index cd0fbd1..0000000 --- a/data554/pinnedDomed1.txt +++ /dev/null @@ -1,422 +0,0 @@ -A_NE: - ┌ ┐ - │ 0.5 │ - │ 0.5 │ - │ 0 │ - │ 0.5 │ - │ 0.25 │ - └ ┘ - -A_NW: - ┌ ┐ - │ -0.5 │ - │ 0.5 │ - │ 0 │ - │ 0.5 │ - │ 0.25 │ - └ ┘ - -A_SE: - ┌ ┐ - │ 0.5 │ - │ -0.5 │ - │ 0 │ - │ 0.5 │ - │ 0.25 │ - └ ┘ - -A_SW: - ┌ ┐ - │ -0.5 │ - │ -0.5 │ - │ 0 │ - │ 0.5 │ - │ 0.25 │ - └ ┘ - -Z_E: - ┌ ┐ - │ 0.226403187618189 │ - │ -0.0000011852849153538265 │ - │ 0.8216719444221399 │ - │ 0.5 │ - │ 0.36320159380866957 │ - └ ┘ - -Z_S: - ┌ ┐ - │ 0.0000012064271737704876 │ - │ -0.22640322646306607 │ - │ 0.8216719573565728 │ - │ 0.5 │ - │ 0.36320161323110667 │ - └ ┘ - -B_NE: - ┌ ┐ - │ 0.8090169943749475 │ - │ 0.8090169943749475 │ - │ 0.8994537199739336 │ - │ 0.5 │ - │ 1.0590169943749475 │ - └ ┘ - -B_NW: - ┌ ┐ - │ -0.8090169943749475 │ - │ 0.8090169943749475 │ - │ 0.8994537199739336 │ - │ 0.5 │ - │ 1.0590169943749475 │ - └ ┘ - -B_SW: - ┌ ┐ - │ -0.8090169943749475 │ - │ -0.8090169943749475 │ - │ 0.8994537199739336 │ - │ 0.5 │ - │ 1.0590169943749475 │ - └ ┘ - -B_SE: - ┌ ┐ - │ 0.8090190229759617 │ - │ -0.8090188141637347 │ - │ 0.899451950040933 │ - │ 0.5 │ - │ 1.059018649731349 │ - └ ┘ - -Y_NE: - ┌ ┐ - │ 0.10639264310226318 │ - │ 0.10730337799321536 │ - │ 1.0174285282252145 │ - │ 0.5 │ - │ 0.5289971090900759 │ - └ ┘ - -Y_NW: - ┌ ┐ - │ -0.10692454007698927 │ - │ 0.10692454007699025 │ - │ 1.0183290894713781 │ - │ 0.5 │ - │ 0.5299299245035725 │ - └ ┘ - -Y_SE: - ┌ ┐ - │ 0.10619251333984216 │ - │ -0.10758965782463996 │ - │ 1.0179033510994517 │ - │ 0.5 │ - │ 0.5294898085465076 │ - └ ┘ - -Y_SW: - ┌ ┐ - │ -0.1067218861162948 │ - │ -0.10720833408227096 │ - │ 1.018815416393646 │ - │ 0.5 │ - │ 0.5304340206102979 │ - └ ┘ - -C_N: - ┌ ┐ - │ 0 │ - │ 1 │ - │ 1.4553466902253547 │ - │ 0.5 │ - │ 1.5590169943749472 │ - └ ┘ - -C_W: - ┌ ┐ - │ -1 │ - │ 0 │ - │ 1.4553466902253547 │ - │ 0.5 │ - │ 1.5590169943749472 │ - └ ┘ - -C_E: - ┌ ┐ - │ 0.9987752175493758 │ - │ -0.0000014991453936079486 │ - │ 1.4557639853989686 │ - │ 0.5 │ - │ 1.558400358790791 │ - └ ┘ - -C_S: - ┌ ┐ - │ 0.0000016241779451142522 │ - │ -1.0006558417024733 │ - │ 1.4551187604443314 │ - │ 0.5 │ - │ 1.5593413623171548 │ - └ ┘ - -D_NE: - ┌ ┐ - │ 0.18880014858596228 │ - │ 0.1900242678455326 │ - │ 2.0105891402812603 │ - │ 0.5 │ - │ 2.057111349663646 │ - └ ┘ - -D_NW: - ┌ ┐ - │ -0.19098138154171115 │ - │ 0.19098137963576622 │ - │ 2.0112375319589524 │ - │ 0.5 │ - │ 2.0590124438119553 │ - └ ┘ - -D_SE: - ┌ ┐ - │ 0.18930742120763205 │ - │ -0.19118865645940125 │ - │ 2.0109297224500113 │ - │ 0.5 │ - │ 2.0581147310902232 │ - └ ┘ - -D_SW: - ┌ ┐ - │ -0.19150073518747784 │ - │ -0.19215789298794494 │ - │ 2.011588230853374 │ - │ 0.5 │ - │ 2.060041842611764 │ - └ ┘ - -E_N: - ┌ ┐ - │ 0.0018705386847266854 │ - │ 1.067093230632768 │ - │ 2.4530916457713374 │ - │ 0.5 │ - │ 3.5781750425903667 │ - └ ┘ - -E_W: - ┌ ┐ - │ -1.0677431983248686 │ - │ 0.0010069929693730891 │ - │ 2.453048970298719 │ - │ 0.5 │ - │ 3.578762902144111 │ - └ ┘ - -E_E: - ┌ ┐ - │ 1.0651802756853244 │ - │ 0.0009763264191362732 │ - │ 2.4535562533844497 │ - │ 0.5 │ - │ 3.5772741307914204 │ - └ ┘ - -E_S: - ┌ ┐ - │ 0.0019014550057512374 │ - │ -1.0684657533845878 │ - │ 2.4528152065600635 │ - │ 0.5 │ - │ 3.5789625604223154 │ - └ ┘ - -F_NE: - ┌ ┐ - │ 0.2768627273275836 │ - │ 0.27828736361573514 │ - │ 3.0027865275597208 │ - │ 0.5 │ - │ 4.58541185017254 │ - └ ┘ - -F_NW: - ┌ ┐ - │ -0.28103002630311136 │ - │ 0.2812882756471644 │ - │ 3.0030716277259866 │ - │ 0.5 │ - │ 4.588270112066947 │ - └ ┘ - -F_SE: - ┌ ┐ - │ 0.2784445942560668 │ - │ -0.28049951604978735 │ - │ 3.002936318943545 │ - │ 0.5 │ - │ 4.586918980412344 │ - └ ┘ - -F_SW: - ┌ ┐ - │ -0.28267553068657514 │ - │ -0.2835640963165625 │ - │ 3.0032197706602255 │ - │ 0.5 │ - │ 4.58982149472019 │ - └ ┘ - -G_1: - ┌ ┐ - │ 0.49499953176717715 │ - │ 1.2038466206487632 │ - │ 3.3122320493386623 │ - │ 0.5 │ - │ 6.332576199448855 │ - └ ┘ - -G_2: - ┌ ┐ - │ 1.202713808441931 │ - │ 0.49734958577973293 │ - │ 3.3107015388161924 │ - │ 0.5 │ - │ 6.327310911161432 │ - └ ┘ - -G_4: - ┌ ┐ - │ 1.205139169495155 │ - │ -0.5026367636047644 │ - │ 3.3060733731956917 │ - │ 0.5 │ - │ 6.3175626265818385 │ - └ ┘ - -G_5: - ┌ ┐ - │ 0.49496884524644963 │ - │ -1.2066437505221832 │ - │ 3.3117630879125723 │ - │ 0.5 │ - │ 6.334379009718901 │ - └ ┘ - -G_7: - ┌ ┐ - │ -0.5049809193563459 │ - │ -1.2113397181531034 │ - │ 3.3029076805907547 │ - │ 0.5 │ - │ 6.315774407531318 │ - └ ┘ - -G_8: - ┌ ┐ - │ -1.2105141090163352 │ - │ -0.502666189603216 │ - │ 3.305064063797819 │ - │ 0.5 │ - │ 6.320733099502539 │ - └ ┘ - -G_10: - ┌ ┐ - │ -1.2079897553472638 │ - │ 0.49731945797605365 │ - │ 3.309789835947903 │ - │ 0.5 │ - │ 6.330637311024589 │ - └ ┘ - -G_11: - ┌ ┐ - │ -0.5049515565196006 │ - │ 1.2084435744379876 │ - │ 3.303474805253526 │ - │ 0.5 │ - │ 6.314128853476387 │ - └ ┘ - -H_E: - ┌ ┐ - │ 0.3493418610082748 │ - │ -0.004066882149056481 │ - │ 3.1680910206723154 │ - │ 0.5 │ - │ 5.079428493907433 │ - └ ┘ - -H_N: - ┌ ┐ - │ -0.007700036653444471 │ - │ 0.35115095882911657 │ - │ 3.1700941994675693 │ - │ 0.5 │ - │ 5.086431758305634 │ - └ ┘ - -H_S: - ┌ ┐ - │ -0.007865804611166411 │ - │ -0.3529429622292672 │ - │ 3.176292181037656 │ - │ 0.5 │ - │ 5.10673131179707 │ - └ ┘ - -H_W: - ┌ ┐ - │ -0.35269124233601623 │ - │ -0.004232365263278458 │ - │ 3.179750192542026 │ - │ 0.5 │ - │ 5.117610155394313 │ - └ ┘ - -I_NE: - ┌ ┐ - │ 0.49805064236295854 │ - │ 0.4976522130513484 │ - │ 4.020243412022774 │ - │ 0.5 │ - │ 8.329034633323353 │ - └ ┘ - -I_NW: - ┌ ┐ - │ -0.5060555022841527 │ - │ 0.5128022974270082 │ - │ 4.021863319771454 │ - │ 0.5 │ - │ 8.34722145884986 │ - └ ┘ - -I_SE: - ┌ ┐ - │ 0.5060495556329386 │ - │ -0.5018683273402639 │ - │ 4.021107068324604 │ - │ 0.5 │ - │ 8.338630006433696 │ - └ ┘ - -I_SW: - ┌ ┐ - │ -0.5143110146278468 │ - │ -0.5172754412791255 │ - │ 4.0227602162137135 │ - │ 0.5 │ - │ 8.357344731885544 │ - └ ┘ - -J: - ┌ ┐ - │ -0.012852519748535315 │ - │ -0.006830373978588703 │ - │ 3.3242009136904245 │ - │ 0.5 │ - │ 5.525261774194571 │ - └ ┘ diff --git a/data554/processData.py b/data554/processData.py deleted file mode 100644 index 342b54c..0000000 --- a/data554/processData.py +++ /dev/null @@ -1,85 +0,0 @@ -from math import fabs, nan, sqrt -import sys -vertices = {} -current_id = "" -for line in sys.stdin: - text = line.strip() - if text.endswith(":"): - new_id = text.strip(":") - vertices[new_id] = [] - if current_id: print(current_id, vertices[current_id]) - current_id = new_id - continue - remainder = text.strip("┌ ┐└┘│") - if len(remainder): vertices[current_id].append(float(remainder)) -print(len(vertices), "vertices found") - -P = True -F = False -HPHI = nan -RTHPHI = nan -RTPHIPH = nan -# Taken verbatim from test_assembly_chooser.rs -acron_data = [ - ("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, "A_SE,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, "B_NE,B_SE,Y_NE,Y_SE"), - ("C_S", [ 0.006, -1.006, 1.45], F, 4, "B_SE,B_SW,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"), -] - -E = 0.0 -n_struts = 11 # for the pinned vertices, which all have length exactly 1 -for vi in range(0, len(acron_data)): - start_id = acron_data[vi][0] - start = vertices[start_id] - ends = acron_data[vi][4].split(",") - if acron_data[vi][3] == 8: - if start_id != "G_1": - ends.append(acron_data[vi-1][0]) - if vi+1 == len(acron_data): - ends.append("G_1") - for end_id in ends: - if not(end_id): continue - end = vertices[end_id] - dist = sqrt( - (end[0]-start[0])**2 + (end[1]-start[1])**2 + (end[2]-start[2])**2) - print(f"{start_id}-{end_id}: {dist} {dist-1}") - E += fabs(dist-1) - n_struts += 1 -print(n_struts, "unit edges") -print(f"----> Total distortion E={E}") diff --git a/data554/processDomed.py b/data554/processDomed.py deleted file mode 100644 index b2fe7b8..0000000 --- a/data554/processDomed.py +++ /dev/null @@ -1,95 +0,0 @@ -from math import fabs, nan, sqrt -import sys -vertices = {} -current_id = "" -for line in sys.stdin: - text = line.strip() - if text.endswith(":"): - new_id = text.strip(":") - vertices[new_id] = [] - if current_id: print(current_id, vertices[current_id]) - current_id = new_id - continue - remainder = text.strip("┌ ┐└┘│") - if len(remainder): vertices[current_id].append(float(remainder)) -print(len(vertices), "vertices found") - -P = True -F = False -HPHI = nan -RTHPHI = nan -RTPHIPH = nan -# Taken verbatim from test_assembly_chooser.rs -acron_data = [ - ("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, "A_SE,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, "B_NE,B_SE,Y_NE,Y_SE"), - ("C_S", [ 0.006, -1.006, 1.45], F, 4, "B_SE,B_SW,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"), - # Additional data - ("H_E", [ 0.359, -0.006, 3.161], F, 9, "G_2,G_4"), - ("H_N", [ 0.005, 0.348, 3.158], F, 9, "G_1,G_11"), - ("H_S", [ 0.006, 0.359, 3.159], F, 9, "G_5,G_7"), - ("H_W", [-0.347, -0.005, 3.163], F, 9, "G_8,G_10"), - ("I_NE", [ 0.507, 0.493, 4.015], F, 10, "G_1,G_2,H_E,H_N"), - ("I_NW", [-0.493, 0.493, 4.013], F, 10, "G_10,G_11,H_N,H_W"), - ("I_SE", [ 0.507, -0.507, 4.012], F, 10, "G_4,G_5,H_E,H_S"), - ("I_SW", [-0.493, -0.507, 4.015], F, 10, "G_7,G_8,H_S,H_W"), - ("J", [ 0.004, -0.010, 3.303], F, 11, "I_NE,I_NW,I_SE,I_SW"), -] - -E = 0.0 -n_struts = 11 # for the pinned vertices, which all have length exactly 1 -for vi in range(0, len(acron_data)): - start_id = acron_data[vi][0] - start = vertices[start_id] - ends = acron_data[vi][4].split(",") - if acron_data[vi][3] == 8: - if start_id != "G_1": - ends.append(acron_data[vi-1][0]) - if vi+1 == len(acron_data) or not(acron_data[vi+1][0].startswith("G")): - ends.append("G_1") - for end_id in ends: - if not(end_id): continue - end = vertices[end_id] - dist = sqrt( - (end[0]-start[0])**2 + (end[1]-start[1])**2 + (end[2]-start[2])**2) - print(f"{start_id}-{end_id}: {dist} {dist-1}") - E += fabs(dist-1) - n_struts += 1 -print(n_struts, "unit edges") -print(f"----> Total distortion E={E}")