From 8bedb0baf752a26ce636e0248434b78e42cb5024 Mon Sep 17 00:00:00 2001 From: Aaron Fenyes Date: Sat, 23 Aug 2025 12:40:11 -0400 Subject: [PATCH] Sketch a 5-5-4 near miss test assembly --- .../src/components/test_assembly_chooser.rs | 434 +++++++++++++++++- 1 file changed, 433 insertions(+), 1 deletion(-) diff --git a/app-proto/src/components/test_assembly_chooser.rs b/app-proto/src/components/test_assembly_chooser.rs index 0d387d3..f659215 100644 --- a/app-proto/src/components/test_assembly_chooser.rs +++ b/app-proto/src/components/test_assembly_chooser.rs @@ -1,5 +1,5 @@ use itertools::izip; -use std::{f64::consts::{FRAC_1_SQRT_2, PI}, rc::Rc}; +use std::{f64::consts::{FRAC_1_SQRT_2, PI, SQRT_2}, rc::Rc}; use nalgebra::Vector3; use sycamore::prelude::*; use web_sys::{console, wasm_bindgen::JsValue}; @@ -882,6 +882,436 @@ fn load_irisawa_hexlet(assembly: &Assembly) { assembly.insert_regulator(Rc::new(outer_moon_tangency)); } +fn load_554a(assembly: &Assembly) { + // create the vertices + const COLOR_A: ElementColor = [0.75_f32, 0.00_f32, 0.75_f32]; + const COLOR_B: ElementColor = [1.00_f32, 0.00_f32, 0.25_f32]; + const COLOR_C: ElementColor = [0.75_f32, 0.50_f32, 0.00_f32]; + const COLOR_D: ElementColor = [0.90_f32, 0.90_f32, 0.00_f32]; + const COLOR_E: ElementColor = [0.25_f32, 0.75_f32, 0.00_f32]; + const COLOR_F: ElementColor = [0.00_f32, 0.50_f32, 0.75_f32]; + const COLOR_G: ElementColor = [0.25_f32, 0.00_f32, 1.00_f32]; + let vertices = [ + Point::new( + "a_NE".to_string(), + "A-NE".to_string(), + COLOR_A, + engine::point(0.5, 0.5, 0.0), + ), + Point::new( + "a_NW".to_string(), + "A-NW".to_string(), + COLOR_A, + engine::point(-0.5, 0.5, 0.0), + ), + Point::new( + "a_SW".to_string(), + "A-SW".to_string(), + COLOR_A, + engine::point(-0.5, -0.5, 0.0), + ), + Point::new( + "a_SE".to_string(), + "A-SE".to_string(), + COLOR_A, + engine::point(0.5, -0.5, 0.0), + ), + Point::new( + "b_NE".to_string(), + "B-NE".to_string(), + COLOR_B, + engine::point(0.7, 0.7, 0.9), + ), + Point::new( + "b_NW".to_string(), + "B-NW".to_string(), + COLOR_B, + engine::point(-0.7, 0.7, 0.9), + ), + Point::new( + "b_SW".to_string(), + "B-SW".to_string(), + COLOR_B, + engine::point(-0.7, -0.7, 0.9), + ), + Point::new( + "b_SE".to_string(), + "B-SE".to_string(), + COLOR_B, + engine::point(0.7, -0.7, 0.9), + ), + Point::new( + "c_N".to_string(), + "C-N".to_string(), + COLOR_C, + engine::point(0.0, 0.8, 1.4), + ), + Point::new( + "c_W".to_string(), + "C-W".to_string(), + COLOR_C, + engine::point(-0.8, 0.0, 1.4), + ), + Point::new( + "c_S".to_string(), + "C-S".to_string(), + COLOR_C, + engine::point(0.0, -0.8, 1.4), + ), + Point::new( + "c_E".to_string(), + "C-E".to_string(), + COLOR_C, + engine::point(0.8, 0.0, 1.4), + ), + Point::new( + "d_NE".to_string(), + "D-NE".to_string(), + COLOR_D, + engine::point(0.1, 0.1, 1.8), + ), + Point::new( + "d_NW".to_string(), + "D-NW".to_string(), + COLOR_D, + engine::point(-0.1, 0.1, 1.8), + ), + Point::new( + "d_SW".to_string(), + "D-SW".to_string(), + COLOR_D, + engine::point(-0.1, -0.1, 1.8), + ), + Point::new( + "d_SE".to_string(), + "D-SE".to_string(), + COLOR_D, + engine::point(0.1, -0.1, 1.8), + ), + Point::new( + "e_N".to_string(), + "E-N".to_string(), + COLOR_E, + engine::point(0.0, 0.7, 2.3), + ), + Point::new( + "e_W".to_string(), + "E-W".to_string(), + COLOR_E, + engine::point(-0.7, 0.0, 2.3), + ), + Point::new( + "e_S".to_string(), + "E-S".to_string(), + COLOR_E, + engine::point(0.0, -0.7, 2.3), + ), + Point::new( + "e_E".to_string(), + "E-E".to_string(), + COLOR_E, + engine::point(0.7, 0.0, 2.3), + ), + Point::new( + "f_NE".to_string(), + "F-NE".to_string(), + COLOR_F, + engine::point(0.2, 0.2, 2.7), + ), + Point::new( + "f_NW".to_string(), + "F-NW".to_string(), + COLOR_F, + engine::point(-0.2, 0.2, 2.7), + ), + Point::new( + "f_SW".to_string(), + "F-SW".to_string(), + COLOR_F, + engine::point(-0.2, -0.2, 2.7), + ), + Point::new( + "f_SE".to_string(), + "F-SE".to_string(), + COLOR_F, + engine::point(0.2, -0.2, 2.7), + ), + Point::new( + "g_NNE".to_string(), + "G-NNE".to_string(), + COLOR_G, + engine::point(0.5, 1.2, 3.0), + ), + Point::new( + "g_NNW".to_string(), + "G-NNW".to_string(), + COLOR_G, + engine::point(-0.5, 1.2, 3.0), + ), + Point::new( + "g_WNW".to_string(), + "G-WNW".to_string(), + COLOR_G, + engine::point(-1.2, 0.5, 3.0), + ), + Point::new( + "g_WSW".to_string(), + "G-WSW".to_string(), + COLOR_G, + engine::point(-1.2, -0.5, 3.0), + ), + Point::new( + "g_SSW".to_string(), + "G-SSW".to_string(), + COLOR_G, + engine::point(-0.5, -1.2, 3.0), + ), + Point::new( + "g_SSE".to_string(), + "G-SSE".to_string(), + COLOR_G, + engine::point(0.5, -1.2, 3.0), + ), + Point::new( + "g_ESE".to_string(), + "G-ESE".to_string(), + COLOR_G, + engine::point(1.2, -0.5, 3.0), + ), + Point::new( + "g_ENE".to_string(), + "G-ENE".to_string(), + COLOR_G, + engine::point(1.2, 0.5, 3.0), + ), + ]; + for vertex in vertices { + let _ = assembly.try_insert_element(vertex); + } + + // fix the distances between adjacent vertices + let square_in_octagon = (2.0 + SQRT_2).sqrt(); + let struts = [ + (1.0, vec![ + ["a_NE", "a_NW"], + ["a_NW", "a_SW"], + ["a_SW", "a_SE"], + ["a_SE", "a_NE"], + ["a_NE", "b_NE"], + ["a_NW", "b_NW"], + ["a_SW", "b_SW"], + ["a_SE", "b_SE"], + ["b_NE", "c_N"], + ["b_NW", "c_N"], + ["b_NW", "c_W"], + ["b_SW", "c_W"], + ["b_SW", "c_S"], + ["b_SE", "c_S"], + ["b_SE", "c_E"], + ["b_NE", "c_E"], + ["c_N", "d_NE"], + ["c_N", "d_NW"], + ["c_W", "d_NW"], + ["c_W", "d_SW"], + ["c_S", "d_SW"], + ["c_S", "d_SE"], + ["c_E", "d_SE"], + ["c_E", "d_NE"], + ["d_NE", "e_N"], + ["d_NW", "e_N"], + ["d_NW", "e_W"], + ["d_SW", "e_W"], + ["d_SW", "e_S"], + ["d_SE", "e_S"], + ["d_SE", "e_E"], + ["d_NE", "e_E"], + ["c_N", "e_N"], + ["c_W", "e_W"], + ["c_S", "e_S"], + ["c_E", "e_E"], + ["e_N", "f_NE"], + ["e_N", "f_NW"], + ["e_W", "f_NW"], + ["e_W", "f_SW"], + ["e_S", "f_SW"], + ["e_S", "f_SE"], + ["e_E", "f_SE"], + ["e_E", "f_NE"], + ["d_NE", "f_NE"], + ["d_NW", "f_NW"], + ["d_SW", "f_SW"], + ["d_SE", "f_SE"], + ["f_NE", "g_ENE"], + ["f_NE", "g_NNE"], + ["f_NW", "g_NNW"], + ["f_NW", "g_WNW"], + ["f_SW", "g_WSW"], + ["f_SW", "g_SSW"], + ["f_SE", "g_SSE"], + ["f_SE", "g_ESE"], + ["e_N", "g_NNE"], + ["e_N", "g_NNW"], + ["e_W", "g_WNW"], + ["e_W", "g_WSW"], + ["e_S", "g_SSW"], + ["e_S", "g_SSE"], + ["e_E", "g_ESE"], + ["e_E", "g_ENE"], + ["g_NNE", "g_NNW"], + ["g_NNW", "g_WNW"], + ["g_WNW", "g_WSW"], + ["g_WSW", "g_SSW"], + ["g_SSW", "g_SSE"], + ["g_SSE", "g_ESE"], + ["g_ESE", "g_ENE"], + ["g_ENE", "g_NNE"], + ]), + (SQRT_2, vec![ + ["a_NE", "a_SW"], + ["a_NW", "a_SE"], + ["b_NE", "d_NE"], + ["b_NW", "d_NW"], + ["b_SW", "d_SW"], + ["b_SE", "d_SE"], + ]), + (0.5*(1.0 + 5.0_f64.sqrt()), vec![ + ["a_NE", "c_N"], + ["a_NW", "c_N"], + ["a_NW", "c_W"], + ["a_SW", "c_W"], + ["a_SW", "c_S"], + ["a_SE", "c_S"], + ["a_SE", "c_E"], + ["a_NE", "c_E"], + ]), + (square_in_octagon, vec![ + ["g_NNE", "g_WNW"], + ["g_WNW", "g_SSW"], + ["g_SSW", "g_ESE"], + ["g_ESE", "g_NNE"], + ]), + (SQRT_2 * square_in_octagon, vec![ + ["g_NNE", "g_SSW"], + ]), + ]; + for (length, vertex_pairs) in struts { + let inv_dist = Some(-0.5 * length * length); + for pair in vertex_pairs { + let adjacent_vertices = pair.map( + |id| assembly.elements_by_id.with_untracked( + |elts_by_id| elts_by_id[id].clone() + ) + ); + let distance = InversiveDistanceRegulator::new(adjacent_vertices); + distance.set_point.set(SpecifiedValue::from(inv_dist)); + assembly.insert_regulator(Rc::new(distance)); + } + } + + // create the faces + const COLOR_FACE: ElementColor = [0.75_f32, 0.75_f32, 0.75_f32]; + let faces = [ + Sphere::new( + "f_a".to_string(), + "Face A".to_string(), + COLOR_FACE, + engine::sphere_with_offset(0.0, 0.0, -1.0, 0.0, 0.0), + ), + Sphere::new( + "f_abc_N".to_string(), + "Face ABC-N".to_string(), + COLOR_FACE, + engine::sphere_with_offset(0.0, 1.0, 0.0, 0.5, 0.0), + ), + Sphere::new( + "f_abc_W".to_string(), + "Face ABC-W".to_string(), + COLOR_FACE, + engine::sphere_with_offset(-1.0, 0.0, 0.0, 0.5, 0.0), + ), + Sphere::new( + "f_abc_S".to_string(), + "Face ABC-S".to_string(), + COLOR_FACE, + engine::sphere_with_offset(0.0, -1.0, 0.0, 0.5, 0.0), + ), + Sphere::new( + "f_abc_E".to_string(), + "Face ABC-E".to_string(), + COLOR_FACE, + engine::sphere_with_offset(1.0, 0.0, 0.0, 0.5, 0.0), + ), + Sphere::new( + "f_bcd_NE".to_string(), + "Face BCD-NE".to_string(), + COLOR_FACE, + engine::sphere_with_offset(FRAC_1_SQRT_2, FRAC_1_SQRT_2, 0.0, FRAC_1_SQRT_2, 0.0), + ), + Sphere::new( + "f_bcd_NW".to_string(), + "Face BCD-NW".to_string(), + COLOR_FACE, + engine::sphere_with_offset(-FRAC_1_SQRT_2, FRAC_1_SQRT_2, 0.0, FRAC_1_SQRT_2, 0.0), + ), + Sphere::new( + "f_bcd_SW".to_string(), + "Face BCD-SW".to_string(), + COLOR_FACE, + engine::sphere_with_offset(-FRAC_1_SQRT_2, -FRAC_1_SQRT_2, 0.0, FRAC_1_SQRT_2, 0.0), + ), + Sphere::new( + "f_bcd_SE".to_string(), + "Face BCD-SE".to_string(), + COLOR_FACE, + engine::sphere_with_offset(FRAC_1_SQRT_2, -FRAC_1_SQRT_2, 0.0, FRAC_1_SQRT_2, 0.0), + ), + Sphere::new( + "f_g".to_string(), + "Face G".to_string(), + COLOR_FACE, + engine::sphere_with_offset(0.0, 0.0, 1.0, 3.0, 0.0), + ), + ]; + for face in faces { + face.ghost().set(true); + let _ = assembly.try_insert_element(face); + } + + // make the faces planar and make them pass through their vertices + let face_incidences = [ + ("f_a", vec!["a_NE", "a_NW", "a_SW", "a_SE"]), + ("f_abc_N", vec!["a_NE", "a_NW", "b_NE", "b_NW", "c_N"]), + ("f_abc_W", vec!["a_NW", "a_SW", "b_NW", "b_SW", "c_W"]), + ("f_abc_S", vec!["a_SW", "a_SE", "b_SW", "b_SE", "c_S"]), + ("f_abc_E", vec!["a_SE", "a_NE", "b_SE", "b_NE", "c_E"]), + ("f_bcd_NE", vec!["b_NE", "c_N", "c_E", "d_NE"]), + ("f_bcd_NW", vec!["b_NW", "c_N", "c_W", "d_NW"]), + ("f_bcd_SW", vec!["b_SW", "c_S", "c_W", "d_SW"]), + ("f_bcd_SE", vec!["b_SE", "c_S", "c_E", "d_SE"]), + ("f_g", vec!["g_NNE", "g_NNW", "g_WNW", "g_WSW", "g_SSW", "g_SSE", "g_ESE", "g_ENE"]), + ]; + for (face_id, vertex_ids) in face_incidences { + // make the face planar + let face = assembly.elements_by_id.with_untracked( + |elts_by_id| elts_by_id[face_id].clone() + ); + let curvature_regulator = face.regulators().with_untracked( + |regs| regs.first().unwrap().clone() + ); + curvature_regulator.set_point().set(SpecifiedValue::from(Some(0.0))); + + // make the face pass through its vertices + for v_id in vertex_ids { + let vertex = assembly.elements_by_id.with_untracked( + |elts_by_id| elts_by_id[v_id].clone() + ); + let incidence = InversiveDistanceRegulator::new([face.clone(), vertex]); + incidence.set_point.set(SpecifiedValue::from(Some(0.0))); + assembly.insert_regulator(Rc::new(incidence)); + } + } +} + // --- chooser --- /* DEBUG */ @@ -918,6 +1348,7 @@ pub fn TestAssemblyChooser() -> View { "off-center" => load_off_center(assembly), "radius-ratio" => load_radius_ratio(assembly), "irisawa-hexlet" => load_irisawa_hexlet(assembly), + "554a" => load_554a(assembly), _ => (), }; }); @@ -935,6 +1366,7 @@ pub fn TestAssemblyChooser() -> View { option(value = "off-center") { "Off-center" } option(value = "radius-ratio") { "Radius ratio" } option(value = "irisawa-hexlet") { "Irisawa hexlet" } + option(value = "554a") { "5-5-4 near miss A" } option(value = "empty") { "Empty" } } }