Compare commits

...
Sign in to create a new pull request.

10 commits

Author SHA1 Message Date
0b03ea2a0d fix: The last six elusive edges 2025-09-22 16:34:53 -07:00
a1b7c1fcb0 feat: add domed configuration for acron 554 2025-09-22 11:31:21 -07:00
0949dc5e8a refactor: leave octagon constraints unset so they can be filled in manually 2025-09-22 09:31:30 -07:00
3afdd3a36b fix: Add three missing edges 2025-09-22 08:38:29 -07:00
02cf7580bc chore: record 554aug2 data in git 2025-09-22 07:47:48 -07:00
d572231a71 feat: add final struts and dump the coordinates 2025-09-22 07:44:14 -07:00
c3c3e14a43 feat: planar octagon with correct dimensions for 554aug2 2025-09-22 04:20:49 -07:00
aeace1a562 refactor: macro to infer const array length 2025-09-21 22:30:38 -07:00
9d9e0da2c3 feat[WIP]: begin a test assembly for the doubly augmented 554 acron 2025-09-21 21:47:54 -07:00
ecbbe2068c feat: Point coordinate regulators
Implements regulators for the Euclidean coordinates of Point entities,
  automatically creating all three of them for each added point entity. When
  such a regulator is set, it freezes the corresponding representation
  coordinate to the set point. In addition, if all three coordinates of a
  given Point are set, the coradius coordinate (which holds the norm of the
  point) is frozen as well.

  Note that a PointCoordinateRegulator must be created with a Point as the
  subject. This commit modifies HalfCurvatureRegulator analogously, so that
  it can only be created with a Sphere.

  A couple of prospective issues that should be filed in association with
  this commit:
  * The new coordinate regulators create redundant display information with
    the raw representation coordinates of a point that are already shown in
    the outline view.
  * The optimization status of these regulators together with HalfCurvature
    regulators (i.e., the ones implemented by freezing coordinates) is different
    from InversiveDistance regulators when an Assembly is unrealizable: the
    frozen-coordinate constraints will be "hard" in that they will be forced
    to precisely equal their set point, whereas the distance regulators are
    "soft" in that they can be relaxed from their set points in an effort to
    minimize the loss function of the configuration as compared to the values
    of the constraints. Perhaps at some point we should/will have a mechanism
    to specify the softness/hardness of constraints, but in the meantime,
    there should not be two different categories of constraints. Suppose we
    decide that by default that all constraints are soft. Then the optimizer
    should be able to search changing, for example, the radius of a
    curvature-constrained sphere, so as to minimize the loss function (for a
    loss that would therefore presumably have a term akin to the square of the
    difference between the specified and actual half-curvature of the sphere).
    For example, suppose you specify that the half-curvature of a sphere is 1
    (so it has radius 1/2) but that its distance to a point is -1. These
    constraints cannot be satisfied, so the optimization fails, presumably
    with the point at the sphere center, and the sphere with radius 1/2.
    So all of the loss is concentrated in the difference between the actual
    point-sphere distance being -1/2, not -1. It would be more appropriate
    (in the all-soft constraint regime) to end up at something like a sphere of
    half-curvature 1/√2 with the point at the center, so that the loss is split
    between both the half-curvature and the distance to the sphere being off by
    1 - 1/√2. (At a guess, that would minimize the sum of the squares of the
    two differences.)
2025-09-20 00:51:26 -07:00
13 changed files with 1551 additions and 270 deletions

21
app-proto/Cargo.lock generated
View file

@ -255,6 +255,7 @@ dependencies = [
"charming",
"console_error_panic_hook",
"dyna3",
"enum-iterator",
"itertools",
"js-sys",
"lazy_static",
@ -271,6 +272,26 @@ version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "enum-iterator"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4549325971814bda7a44061bf3fe7e487d447cba01e4220a4b454d630d7a016"
dependencies = [
"enum-iterator-derive",
]
[[package]]
name = "enum-iterator-derive"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "685adfa4d6f3d765a26bc5dbc936577de9abf756c1feeb3089b01dd395034842"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "equivalent"
version = "1.0.1"

View file

@ -10,6 +10,7 @@ default = ["console_error_panic_hook"]
dev = []
[dependencies]
enum-iterator = "2.3.0"
itertools = "0.13.0"
js-sys = "0.3.70"
lazy_static = "1.5.0"

View file

@ -0,0 +1,2 @@
[toolchain]
channel = "nightly"

View file

@ -1,5 +1,7 @@
use enum_iterator::{all, Sequence};
use nalgebra::{DMatrix, DVector, DVectorView};
use std::{
any::Any,
cell::Cell,
cmp::Ordering,
collections::{BTreeMap, BTreeSet},
@ -26,6 +28,7 @@ use crate::{
ConfigSubspace,
ConstraintProblem,
DescentHistory,
MatrixEntry,
Realization,
},
specified::SpecifiedValue,
@ -93,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<Self>) -> Vec<Rc<dyn Regulator>> {
@ -171,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<f64>,
) -> Self {
Self {
id,
label,
id: id.to_string(),
label: label.to_string(),
color,
representation: create_signal(representation),
ghost: create_signal(false),
@ -194,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),
)
}
@ -269,16 +272,17 @@ pub struct Point {
impl Point {
const WEIGHT_COMPONENT: usize = 3;
const NORM_COMPONENT: usize = 4;
pub fn new(
id: String,
label: String,
id: &str,
label: &str,
color: ElementColor,
representation: DVector<f64>,
) -> Self {
Self {
id,
label,
id: id.to_string(),
label: label.to_string(),
color,
representation: create_signal(representation),
ghost: create_signal(false),
@ -294,15 +298,24 @@ 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,
format!("Point {id_num}"),
&format!("Point {id_num}"),
[0.75_f32, 0.75_f32, 0.75_f32],
point(0.0, 0.0, 0.0),
)
}
fn default_regulators(self: Rc<Self>) -> Vec<Rc<dyn Regulator>> {
all::<Axis>()
.map(|axis| {
Rc::new(PointCoordinateRegulator::new(self.clone(), axis))
as Rc::<dyn Regulator>
})
.collect()
}
fn id(&self) -> &String {
&self.id
}
@ -353,10 +366,22 @@ impl ProblemPoser for Point {
}
}
pub trait Regulator: Serial + ProblemPoser + OutlineItem {
pub trait Regulator: Any + Serial + ProblemPoser + OutlineItem {
fn subjects(&self) -> Vec<Rc<dyn Element>>;
fn measurement(&self) -> ReadSignal<f64>;
fn set_point(&self) -> Signal<SpecifiedValue>;
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 {
@ -422,6 +447,8 @@ impl Regulator for InversiveDistanceRegulator {
fn set_point(&self) -> Signal<SpecifiedValue> {
self.set_point
}
fn as_any(&self) -> &dyn Any {self}
}
impl Serial for InversiveDistanceRegulator {
@ -446,14 +473,14 @@ impl ProblemPoser for InversiveDistanceRegulator {
}
pub struct HalfCurvatureRegulator {
pub subject: Rc<dyn Element>,
pub subject: Rc<Sphere>,
pub measurement: ReadSignal<f64>,
pub set_point: Signal<SpecifiedValue>,
serial: u64,
}
impl HalfCurvatureRegulator {
pub fn new(subject: Rc<dyn Element>) -> Self {
pub fn new(subject: Rc<Sphere>) -> Self {
let measurement = subject.representation().map(
|rep| rep[Sphere::CURVATURE_COMPONENT]
);
@ -477,6 +504,8 @@ impl Regulator for HalfCurvatureRegulator {
fn set_point(&self) -> Signal<SpecifiedValue> {
self.set_point
}
fn as_any(&self) -> &dyn Any {self}
}
impl Serial for HalfCurvatureRegulator {
@ -498,6 +527,70 @@ impl ProblemPoser for HalfCurvatureRegulator {
}
}
#[derive(Clone, Copy, Sequence)]
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"];
}
pub struct PointCoordinateRegulator {
pub subject: Rc<Point>,
pub axis: Axis,
pub measurement: ReadSignal<f64>,
pub set_point: Signal<SpecifiedValue>,
serial: u64
}
impl PointCoordinateRegulator {
pub fn new(subject: Rc<Point>, axis: Axis) -> Self {
let measurement = subject.representation().map(
move |rep| rep[axis as usize]
);
let set_point = create_signal(SpecifiedValue::from_empty_spec());
Self { subject, axis, measurement, set_point, serial: Self::next_serial() }
}
}
impl Serial for PointCoordinateRegulator {
fn serial(&self) -> u64 { self.serial }
}
impl Regulator for PointCoordinateRegulator {
fn subjects(&self) -> Vec<Rc<dyn Element>> { vec![self.subject.clone()] }
fn measurement(&self) -> ReadSignal<f64> { self.measurement }
fn set_point(&self) -> Signal<SpecifiedValue> { self.set_point }
fn as_any(&self) -> &dyn Any {self}
}
impl ProblemPoser for PointCoordinateRegulator {
fn pose(&self, problem: &mut ConstraintProblem) {
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.");
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];
let mut nset: usize = 0;
for &MatrixEntry {index, value} in &(problem.frozen) {
if index.1 == col && index.0 < Axis::N_AXIS {
nset += 1;
coords[index.0] = value
}
}
if nset == Axis::N_AXIS {
let [x, y, z] = coords;
problem.frozen.push(
Point::NORM_COMPONENT, col, point(x,y,z)[Point::NORM_COMPONENT]);
}
}
});
}
}
// the velocity is expressed in uniform coordinates
pub struct ElementMotion<'a> {
pub element: Rc<dyn Element>,
@ -621,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<dyn Regulator>) {
// add the regulator to the assembly's regulator list
self.regulators.update(
@ -661,6 +757,11 @@ impl Assembly {
});
}
// --- finding entities ---
pub fn find_element(&self, id: &str) -> Rc<dyn Element> {
self.elements_by_id.with_untracked( |elts| elts[id].clone() )
}
// --- updating the configuration ---
pub fn load_config(&self, config: &DMatrix<f64>) {

View file

@ -1,14 +1,16 @@
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,
PointCoordinateRegulator,
Regulator,
},
specified::SpecifiedValue
@ -119,6 +121,19 @@ impl OutlineItem for HalfCurvatureRegulator {
}
}
impl OutlineItem for PointCoordinateRegulator {
fn outline_item(self: Rc<Self>, _element: &Rc<dyn Element>) -> View {
view! {
li(class = "regulator") {
div(class = "regulator-label") { (Axis::NAME[self.axis as usize]) }
div(class = "regulator-type") { "Coordinate" }
RegulatorInput(regulator = self)
div(class = "status")
}
}
}
}
// a list item that shows an element in an outline view of an assembly
#[component(inline_props)]
fn ElementOutlineItem(element: Rc<dyn Element>) -> View {
@ -246,6 +261,31 @@ pub fn Outline() -> View {
on:click = {
let state = use_context::<AppState>();
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::<Vec<_>>()
);
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(

View file

@ -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,13 +12,80 @@ use crate::{
ElementColor,
InversiveDistanceRegulator,
Point,
PointCoordinateRegulator,
Regulator,
Sphere,
},
engine,
engine::DescentHistory,
engine::{DescentHistory, point},
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<T: Into<f64>>(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<T: const ConstSqrt>(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 */
@ -29,49 +96,37 @@ use crate::{
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),
)
);
@ -79,88 +134,66 @@ fn load_general(assembly: &Assembly) {
fn load_low_curvature(assembly: &Assembly) {
// create the spheres
let a = 0.75_f64.sqrt();
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],
engine::sphere_with_offset(-0.5, a, 0.0, 1.0, 0.0),
"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],
engine::sphere_with_offset(-0.5, -a, 0.0, 1.0, 0.0),
"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],
engine::sphere(2.0/3.0, -4.0/3.0 * a, 0.0, 1.0/3.0),
"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],
engine::sphere(2.0/3.0, 4.0/3.0 * a, 0.0, 1.0/3.0),
"corner3", "Corner 3", GRAY,
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.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
@ -199,16 +232,16 @@ fn load_low_curvature(assembly: &Assembly) {
fn load_pointed(assembly: &Assembly) {
let _ = assembly.try_insert_element(
Point::new(
format!("point_front"),
format!("Front point"),
"point_front",
"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(
format!("point_back"),
format!("Back point"),
"point_back",
"Back point",
[0.75_f32, 0.75_f32, 0.75_f32],
engine::point(0.0, 0.0, -FRAC_1_SQRT_2),
)
@ -220,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),
)
@ -229,8 +262,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),
)
@ -248,91 +281,42 @@ 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_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];
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];
let vertices = [
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),
),
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)),
];
for vertex in vertices {
let _ = assembly.try_insert_element(vertex);
}
// create the faces
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;
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(frac_2_sqrt_6, -frac_1_sqrt_6, -frac_1_sqrt_6, -frac_1_sqrt_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(-frac_1_sqrt_6, frac_2_sqrt_6, -frac_1_sqrt_6, -frac_1_sqrt_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(-frac_1_sqrt_6, -frac_1_sqrt_6, frac_2_sqrt_6, -frac_1_sqrt_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 {
@ -413,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),
)
);
@ -434,17 +416,16 @@ 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];
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];
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 mut faces = Vec::<Rc<dyn Element>>::new();
let subscripts = ["", ""];
for j in 0..2 {
for k in 0..2 {
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 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 id_num = format!("{j}{k}");
let label_sub = format!("{}{}", subscripts[j], subscripts[k]);
@ -453,10 +434,10 @@ 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]),
engine::sphere(0.0, small_coord, big_coord, FACE_RADII[k]),
)
);
faces.push(
@ -469,10 +450,10 @@ 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]),
engine::sphere(small_coord, big_coord, 0.0, FACE_RADII[k]),
)
);
faces.push(
@ -485,10 +466,10 @@ 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]),
engine::sphere(big_coord, 0.0, small_coord, FACE_RADII[k]),
)
);
faces.push(
@ -556,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);
@ -580,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
@ -614,32 +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".to_string(),
"Point".to_string(),
[0.75_f32, 0.75_f32, 0.75_f32],
engine::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));
}
@ -652,18 +607,13 @@ 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".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),
),
];
@ -689,8 +639,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,
)
@ -720,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,
)
@ -734,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 {
@ -766,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));
}
}
@ -792,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(
@ -825,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),
)
@ -838,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()
@ -850,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 [
@ -882,6 +809,205 @@ 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, "Y_NE,Y_NW"),
("C_W", [-1., 0., RTPHIPH], P, 4, "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::<Rc<dyn Element>>::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<dyn Element> 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<dyn Element> ?
let pt_rc = assembly.find_element(id);
if pinned { // regulate each coordinate to its given value
let mut freeze = Vec::<Rc<dyn Regulator>>::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::<PointCoordinateRegulator>() {
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_INDOME: (&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_NE"),
("I_SE", [ 0.507, -0.507, 4.012], F, 10, "G_4,G_5,H_E,H_S,I_NE"),
("I_SW", [-0.493, -0.507, 4.015], F, 10, "G_7,G_8,H_S,H_W,I_NW,I_SE"),
("J", [ 0.004, -0.010, 3.303], F, 11, "I_NE,I_NW,I_SE,I_SW"),
]);
const_array!(ACRON554_OUTDOME: (&str, [f64; 3], bool, usize, &str) = [
// id, coordinates, Pin/Free, level, earlier neighbor IDs.
("H_E", [ 1.361, -0.007, 4.16], F, 9, "G_2,G_4"),
("H_N", [ 0.007, 1.346, 4.164], F, 9, "G_1,G_11"),
("H_S", [ 0.007, -1.361, 4.16], F, 9, "G_5,G_7"),
("H_W", [-1.346, -0.007, 4.164], 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_NE"),
("I_SE", [ 0.507, -0.507, 4.012], F, 10, "G_4,G_5,H_E,H_S,I_NE"),
("I_SW", [-0.493, -0.507, 4.015], F, 10, "G_7,G_8,H_S,H_W,I_NW,I_SE"),
("J", [ 0.008, -0.008, 4.722], 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_INDOME {
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 */
@ -918,11 +1044,15 @@ 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) {
@ -935,6 +1065,8 @@ 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" }
}
}

View file

@ -46,14 +46,14 @@ pub fn project_sphere_to_normalized(rep: &mut DVector<f64>) {
// normalize a point's representation vector by scaling
pub fn project_point_to_normalized(rep: &mut DVector<f64>) {
rep.scale_mut(0.5 / rep[3]);
rep.scale_mut(0.5 / rep[3]); //FIXME: This 3 should be Point::WEIGHT_COMPONENT
}
// --- partial matrices ---
pub struct MatrixEntry {
index: (usize, usize),
value: f64,
pub index: (usize, usize),
pub value: f64,
}
pub struct PartialMatrix(Vec<MatrixEntry>);

View file

@ -1 +1,3 @@
#![feature(const_trait_impl)]
pub mod engine;

View file

@ -1,3 +1,5 @@
#![feature(const_trait_impl)]
mod assembly;
mod components;
mod engine;

378
data554/pinnedAug2.txt Normal file
View file

@ -0,0 +1,378 @@
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 │
└ ┘

422
data554/pinnedDomed1.txt Normal file
View file

@ -0,0 +1,422 @@
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 │
└ ┘

85
data554/processData.py Normal file
View file

@ -0,0 +1,85 @@
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}")

95
data554/processDomed.py Normal file
View file

@ -0,0 +1,95 @@
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}")