forked from StudioInfinity/dyna3
Add the test assemblies for the demo
These are partial setups of the tetrahedron radius ratio problem and the Irisawa hexlet problem.
This commit is contained in:
parent
eba15a6e83
commit
6928ac8765
2 changed files with 272 additions and 6 deletions
|
@ -1,11 +1,20 @@
|
|||
use std::{f64::consts::FRAC_1_SQRT_2, rc::Rc};
|
||||
use itertools::izip;
|
||||
use nalgebra::Vector3;
|
||||
use std::{f64::consts::{FRAC_1_SQRT_2, PI}, rc::Rc};
|
||||
use sycamore::prelude::*;
|
||||
use web_sys::{console, wasm_bindgen::JsValue};
|
||||
|
||||
use crate::{
|
||||
engine,
|
||||
AppState,
|
||||
assembly::{Assembly, InversiveDistanceRegulator, Point, Sphere}
|
||||
assembly::{
|
||||
Assembly,
|
||||
ElementColor,
|
||||
InversiveDistanceRegulator,
|
||||
Point,
|
||||
Sphere
|
||||
},
|
||||
specified::SpecifiedValue
|
||||
};
|
||||
|
||||
/* DEBUG */
|
||||
|
@ -179,6 +188,241 @@ fn load_pointed_assemb(assembly: &Assembly) {
|
|||
}
|
||||
}
|
||||
|
||||
// to finish setting up the problem, fix the following curvatures:
|
||||
// sun 1
|
||||
// moon 5/3 = 1.666666666666666...
|
||||
// chain1 2
|
||||
// a tiny `x` or `z` nudge of the outer sphere reliably prevents realization
|
||||
// failures before they happen, or resolves them after they happen. the result
|
||||
// depends sensitively on the translation direction, suggesting that realization
|
||||
// is failing because the engine is having trouble breaking a symmetry
|
||||
// /* TO DO */
|
||||
// the engine's performance on this problem is scale-dependent! with the current
|
||||
// initial conditions, realization fails for any order of imposing the remaining
|
||||
// curvature constraints. scaling everything up by a factor of ten, as done in
|
||||
// the original problem, makes realization succeed reliably. one potentially
|
||||
// relevant difference is that a lot of the numbers in the current initial
|
||||
// conditions are exactly representable as floats, unlike the analogous numbers
|
||||
// in the scaled-up problem. the inexact representations might break the
|
||||
// symmetry that's getting the engine stuck
|
||||
fn load_irisawa_hexlet_assemb(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]
|
||||
].into_iter();
|
||||
|
||||
// create the spheres
|
||||
let spheres = [
|
||||
Sphere::new(
|
||||
"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".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".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(
|
||||
index_range.clone().zip(colors).map(
|
||||
|(k, color)| {
|
||||
let ang = (k as f64) * PI/3.0;
|
||||
Sphere::new(
|
||||
format!("chain{k}"),
|
||||
format!("Chain {k}"),
|
||||
color,
|
||||
engine::sphere(1.0 * ang.sin(), 0.0, 1.0 * ang.cos(), 0.5)
|
||||
)
|
||||
}
|
||||
)
|
||||
);
|
||||
for sphere in spheres {
|
||||
let _ = assembly.try_insert_element(sphere);
|
||||
}
|
||||
|
||||
// fix the curvature of the outer sphere
|
||||
let outer = assembly.elements_by_id.with_untracked(
|
||||
|elts_by_id| elts_by_id["outer"].clone()
|
||||
);
|
||||
let outer_curvature_regulator = outer.regulators().with_untracked(
|
||||
|regs| regs.first().unwrap().clone()
|
||||
);
|
||||
outer_curvature_regulator.set_point().set(
|
||||
SpecifiedValue::try_from((1.0 / 3.0/*30.0*/).to_string()).unwrap()
|
||||
);
|
||||
|
||||
// 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 chain = index_range.map(
|
||||
|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 [
|
||||
(outer.clone(), "1"),
|
||||
(sun.clone(), "-1"),
|
||||
(moon.clone(), "-1"),
|
||||
(chain_sphere_next.clone(), "-1")
|
||||
] {
|
||||
let tangency = InversiveDistanceRegulator::new([chain_sphere.clone(), other_sphere]);
|
||||
tangency.set_point.set(SpecifiedValue::try_from(inversive_distance.to_string()).unwrap());
|
||||
assembly.insert_regulator(Rc::new(tangency));
|
||||
}
|
||||
}
|
||||
|
||||
let outer_sun_tangency = InversiveDistanceRegulator::new([outer.clone(), sun]);
|
||||
outer_sun_tangency.set_point.set(SpecifiedValue::try_from("1".to_string()).unwrap());
|
||||
assembly.insert_regulator(Rc::new(outer_sun_tangency));
|
||||
|
||||
let outer_moon_tangency = InversiveDistanceRegulator::new([outer.clone(), moon]);
|
||||
outer_moon_tangency.set_point.set(SpecifiedValue::try_from("1".to_string()).unwrap());
|
||||
assembly.insert_regulator(Rc::new(outer_moon_tangency));
|
||||
}
|
||||
|
||||
// setting the inversive distances between the vertices to -2 gives a
|
||||
// regular tetrahedron with side length 1, whose insphere and circumsphere have
|
||||
// radii sqrt(1/6) and sqrt(3/2), respectively
|
||||
fn load_radius_ratio_assemb(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,
|
||||
engine::sphere(0.0, 0.0, 0.0, 0.5)
|
||||
),
|
||||
Sphere::new(
|
||||
"sphere_vertices".to_string(),
|
||||
"Circumsphere".to_string(),
|
||||
GRAY,
|
||||
engine::sphere(0.0, 0.0, 0.0, 0.25)
|
||||
)
|
||||
];
|
||||
for sphere in spheres {
|
||||
let _ = assembly.try_insert_element(sphere);
|
||||
}
|
||||
|
||||
// create the vertices
|
||||
let vertices = izip!(
|
||||
index_range.clone(),
|
||||
[
|
||||
[1.00_f32, 0.50_f32, 0.75_f32],
|
||||
[1.00_f32, 0.75_f32, 0.50_f32],
|
||||
[1.00_f32, 1.00_f32, 0.50_f32],
|
||||
[0.75_f32, 0.50_f32, 1.00_f32]
|
||||
].into_iter(),
|
||||
[
|
||||
engine::point(-0.6, -0.8, -0.6),
|
||||
engine::point(-0.6, 0.8, 0.6),
|
||||
engine::point(0.6, -0.8, 0.6),
|
||||
engine::point(0.6, 0.8, -0.6)
|
||||
].into_iter()
|
||||
).map(
|
||||
|(k, color, representation)| {
|
||||
Point::new(
|
||||
format!("v{k}"),
|
||||
format!("Vertex {k}"),
|
||||
color,
|
||||
representation
|
||||
)
|
||||
}
|
||||
);
|
||||
for vertex in vertices {
|
||||
let _ = assembly.try_insert_element(vertex);
|
||||
}
|
||||
|
||||
// create the faces
|
||||
let base_dir = Vector3::new(1.0, 0.75, 1.0).normalize();
|
||||
let offset = base_dir.dot(&Vector3::new(-0.6, 0.8, 0.6));
|
||||
let faces =izip!(
|
||||
index_range.clone(),
|
||||
[
|
||||
[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, 0.00_f32, 1.00_f32]
|
||||
].into_iter(),
|
||||
[
|
||||
engine::sphere_with_offset(base_dir[0], base_dir[1], base_dir[2], offset, 0.0),
|
||||
engine::sphere_with_offset(base_dir[0], -base_dir[1], -base_dir[2], offset, 0.0),
|
||||
engine::sphere_with_offset(-base_dir[0], base_dir[1], -base_dir[2], offset, 0.0),
|
||||
engine::sphere_with_offset(-base_dir[0], -base_dir[1], base_dir[2], offset, 0.0)
|
||||
].into_iter()
|
||||
).map(
|
||||
|(k, color, representation)| {
|
||||
Sphere::new(
|
||||
format!("f{k}"),
|
||||
format!("Face {k}"),
|
||||
color,
|
||||
representation
|
||||
)
|
||||
}
|
||||
);
|
||||
for face in faces {
|
||||
let _ = assembly.try_insert_element(face);
|
||||
}
|
||||
|
||||
// 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()
|
||||
)
|
||||
);
|
||||
|
||||
// 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()
|
||||
);
|
||||
|
||||
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()
|
||||
);
|
||||
|
||||
// fix the distances between the vertices
|
||||
if j < k {
|
||||
let distance_regulator = InversiveDistanceRegulator::new(
|
||||
[vertex_j.clone(), vertex_k.clone()]
|
||||
);
|
||||
assembly.insert_regulator(Rc::new(distance_regulator));
|
||||
}
|
||||
|
||||
// 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());
|
||||
assembly.insert_regulator(Rc::new(incidence_regulator));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn AddRemove() -> View {
|
||||
/* DEBUG */
|
||||
|
@ -205,6 +449,8 @@ pub fn AddRemove() -> View {
|
|||
"general" => load_gen_assemb(assembly),
|
||||
"low-curv" => load_low_curv_assemb(assembly),
|
||||
"pointed" => load_pointed_assemb(assembly),
|
||||
"irisawa-hexlet" => load_irisawa_hexlet_assemb(assembly),
|
||||
"radius-ratio" => load_radius_ratio_assemb(assembly),
|
||||
_ => ()
|
||||
};
|
||||
});
|
||||
|
@ -253,6 +499,8 @@ pub fn AddRemove() -> View {
|
|||
option(value="general") { "General" }
|
||||
option(value="low-curv") { "Low-curvature" }
|
||||
option(value="pointed") { "Pointed" }
|
||||
option(value="irisawa-hexlet") { "Irisawa hexlet" }
|
||||
option(value="radius-ratio") { "Radius ratio" }
|
||||
option(value="empty") { "Empty" }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -534,6 +534,9 @@ pub struct Assembly {
|
|||
pub elements: Signal<BTreeSet<Rc<dyn Element>>>,
|
||||
pub regulators: Signal<BTreeSet<Rc<dyn Regulator>>>,
|
||||
|
||||
// a flag that tells us whether the assembly is realized
|
||||
pub realized: Signal<bool>,
|
||||
|
||||
// solution variety tangent space. the basis vectors are stored in
|
||||
// configuration matrix format, ordered according to the elements' column
|
||||
// indices. when you realize the assembly, every element that's present
|
||||
|
@ -552,12 +555,24 @@ pub struct Assembly {
|
|||
|
||||
impl Assembly {
|
||||
pub fn new() -> Assembly {
|
||||
Assembly {
|
||||
// create an assembly
|
||||
let assembly = Assembly {
|
||||
elements: create_signal(BTreeSet::new()),
|
||||
regulators: create_signal(BTreeSet::new()),
|
||||
realized: create_signal(true),
|
||||
tangent: create_signal(ConfigSubspace::zero(0)),
|
||||
elements_by_id: create_signal(BTreeMap::default())
|
||||
}
|
||||
};
|
||||
|
||||
// realize the assembly whenever the `realized` flag is set to `false`
|
||||
let assembly_for_effect = assembly.clone();
|
||||
create_memo(move || {
|
||||
if !assembly_for_effect.realized.get() {
|
||||
assembly_for_effect.realize();
|
||||
}
|
||||
});
|
||||
|
||||
assembly
|
||||
}
|
||||
|
||||
// --- inserting elements and regulators ---
|
||||
|
@ -627,7 +642,7 @@ impl Assembly {
|
|||
console_log!("Updated regulator with subjects {:?}", regulator.subjects());
|
||||
|
||||
if regulator.try_activate() {
|
||||
self_for_effect.realize();
|
||||
self_for_effect.realized.set(false);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -710,6 +725,9 @@ impl Assembly {
|
|||
);
|
||||
}
|
||||
|
||||
// update the realization flag
|
||||
self.realized.set(true);
|
||||
|
||||
// save the tangent space
|
||||
self.tangent.set_silent(tangent);
|
||||
}
|
||||
|
@ -802,7 +820,7 @@ impl Assembly {
|
|||
// bring the configuration back onto the solution variety. this also
|
||||
// gets the elements' column indices and the saved tangent space back in
|
||||
// sync
|
||||
self.realize();
|
||||
self.realized.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue