forked from StudioInfinity/dyna3
refactor: Code formatting (#108)
Primarily, switch to using trailing commas. Also uniformizes commas with respect to switch branches, makes function call layout more consistent, line breaking more consistent, alphabetizes imports, uses the field init shorthand when possible, etc. Resolves #99. Co-authored-by: Aaron Fenyes <aaron.fenyes@fareycircles.ooo> Reviewed-on: StudioInfinity/dyna3#108 Co-authored-by: Vectornaut <vectornaut@nobody@nowhere.net> Co-committed-by: Vectornaut <vectornaut@nobody@nowhere.net>
This commit is contained in:
parent
2eba80fb69
commit
ef1a579ac0
12 changed files with 310 additions and 297 deletions
|
@ -23,7 +23,7 @@ fn main() {
|
||||||
let twist_motion: DMatrix<_> = (0..N_POINTS).step_by(4).flat_map(
|
let twist_motion: DMatrix<_> = (0..N_POINTS).step_by(4).flat_map(
|
||||||
|n| [
|
|n| [
|
||||||
tangent.proj(&up.as_view(), n),
|
tangent.proj(&up.as_view(), n),
|
||||||
tangent.proj(&down.as_view(), n+1)
|
tangent.proj(&down.as_view(), n+1),
|
||||||
]
|
]
|
||||||
).sum();
|
).sum();
|
||||||
let normalization = 5.0 / twist_motion[(2, 0)];
|
let normalization = 5.0 / twist_motion[(2, 0)];
|
||||||
|
|
|
@ -6,7 +6,7 @@ use dyna3::engine::{
|
||||||
realize_gram,
|
realize_gram,
|
||||||
sphere,
|
sphere,
|
||||||
ConfigNeighborhood,
|
ConfigNeighborhood,
|
||||||
ConstraintProblem
|
ConstraintProblem,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -25,7 +25,7 @@ fn main() {
|
||||||
);
|
);
|
||||||
print::title("Point on a sphere");
|
print::title("Point on a sphere");
|
||||||
print::realization_diagnostics(&realization);
|
print::realization_diagnostics(&realization);
|
||||||
if let Ok(ConfigNeighborhood{ config, .. }) = realization.result {
|
if let Ok(ConfigNeighborhood { config, .. }) = realization.result {
|
||||||
print::gram_matrix(&config);
|
print::gram_matrix(&config);
|
||||||
print::config(&config);
|
print::config(&config);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use dyna3::engine::{
|
||||||
realize_gram,
|
realize_gram,
|
||||||
sphere,
|
sphere,
|
||||||
ConfigNeighborhood,
|
ConfigNeighborhood,
|
||||||
ConstraintProblem
|
ConstraintProblem,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -14,7 +14,7 @@ fn main() {
|
||||||
&[
|
&[
|
||||||
sphere(1.0, 0.0, 0.0, 1.0),
|
sphere(1.0, 0.0, 0.0, 1.0),
|
||||||
sphere(-0.5, a, 0.0, 1.0),
|
sphere(-0.5, a, 0.0, 1.0),
|
||||||
sphere(-0.5, -a, 0.0, 1.0)
|
sphere(-0.5, -a, 0.0, 1.0),
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
for j in 0..3 {
|
for j in 0..3 {
|
||||||
|
@ -27,7 +27,7 @@ fn main() {
|
||||||
);
|
);
|
||||||
print::title("Three spheres");
|
print::title("Three spheres");
|
||||||
print::realization_diagnostics(&realization);
|
print::realization_diagnostics(&realization);
|
||||||
if let Ok(ConfigNeighborhood{ config, .. }) = realization.result {
|
if let Ok(ConfigNeighborhood { config, .. }) = realization.result {
|
||||||
print::gram_matrix(&config);
|
print::gram_matrix(&config);
|
||||||
}
|
}
|
||||||
print::loss_history(&realization.history);
|
print::loss_history(&realization.history);
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
use nalgebra::{DMatrix, DVector, DVectorView};
|
use nalgebra::{DMatrix, DVector, DVectorView};
|
||||||
use std::{
|
use std::{
|
||||||
cell::Cell,
|
cell::Cell,
|
||||||
collections::{BTreeMap, BTreeSet},
|
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
|
collections::{BTreeMap, BTreeSet},
|
||||||
fmt,
|
fmt,
|
||||||
fmt::{Debug, Formatter},
|
fmt::{Debug, Formatter},
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
sync::{atomic, atomic::AtomicU64}
|
sync::{atomic, atomic::AtomicU64},
|
||||||
};
|
};
|
||||||
use sycamore::prelude::*;
|
use sycamore::prelude::*;
|
||||||
use web_sys::{console, wasm_bindgen::JsValue}; /* DEBUG */
|
use web_sys::{console, wasm_bindgen::JsValue}; /* DEBUG */
|
||||||
|
@ -26,9 +26,9 @@ use crate::{
|
||||||
ConfigSubspace,
|
ConfigSubspace,
|
||||||
ConstraintProblem,
|
ConstraintProblem,
|
||||||
DescentHistory,
|
DescentHistory,
|
||||||
Realization
|
Realization,
|
||||||
},
|
},
|
||||||
specified::SpecifiedValue
|
specified::SpecifiedValue,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub type ElementColor = [f32; 3];
|
pub type ElementColor = [f32; 3];
|
||||||
|
@ -164,7 +164,7 @@ pub struct Sphere {
|
||||||
pub ghost: Signal<bool>,
|
pub ghost: Signal<bool>,
|
||||||
pub regulators: Signal<BTreeSet<Rc<dyn Regulator>>>,
|
pub regulators: Signal<BTreeSet<Rc<dyn Regulator>>>,
|
||||||
serial: u64,
|
serial: u64,
|
||||||
column_index: Cell<Option<usize>>
|
column_index: Cell<Option<usize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sphere {
|
impl Sphere {
|
||||||
|
@ -174,17 +174,17 @@ impl Sphere {
|
||||||
id: String,
|
id: String,
|
||||||
label: String,
|
label: String,
|
||||||
color: ElementColor,
|
color: ElementColor,
|
||||||
representation: DVector<f64>
|
representation: DVector<f64>,
|
||||||
) -> Sphere {
|
) -> Sphere {
|
||||||
Sphere {
|
Sphere {
|
||||||
id: id,
|
id,
|
||||||
label: label,
|
label,
|
||||||
color: color,
|
color,
|
||||||
representation: create_signal(representation),
|
representation: create_signal(representation),
|
||||||
ghost: create_signal(false),
|
ghost: create_signal(false),
|
||||||
regulators: create_signal(BTreeSet::new()),
|
regulators: create_signal(BTreeSet::new()),
|
||||||
serial: Self::next_serial(),
|
serial: Self::next_serial(),
|
||||||
column_index: None.into()
|
column_index: None.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -199,7 +199,7 @@ impl Element for Sphere {
|
||||||
id,
|
id,
|
||||||
format!("Sphere {id_num}"),
|
format!("Sphere {id_num}"),
|
||||||
[0.75_f32, 0.75_f32, 0.75_f32],
|
[0.75_f32, 0.75_f32, 0.75_f32],
|
||||||
sphere(0.0, 0.0, 0.0, 1.0)
|
sphere(0.0, 0.0, 0.0, 1.0),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,7 +264,7 @@ pub struct Point {
|
||||||
pub ghost: Signal<bool>,
|
pub ghost: Signal<bool>,
|
||||||
pub regulators: Signal<BTreeSet<Rc<dyn Regulator>>>,
|
pub regulators: Signal<BTreeSet<Rc<dyn Regulator>>>,
|
||||||
serial: u64,
|
serial: u64,
|
||||||
column_index: Cell<Option<usize>>
|
column_index: Cell<Option<usize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Point {
|
impl Point {
|
||||||
|
@ -274,7 +274,7 @@ impl Point {
|
||||||
id: String,
|
id: String,
|
||||||
label: String,
|
label: String,
|
||||||
color: ElementColor,
|
color: ElementColor,
|
||||||
representation: DVector<f64>
|
representation: DVector<f64>,
|
||||||
) -> Point {
|
) -> Point {
|
||||||
Point {
|
Point {
|
||||||
id,
|
id,
|
||||||
|
@ -284,7 +284,7 @@ impl Point {
|
||||||
ghost: create_signal(false),
|
ghost: create_signal(false),
|
||||||
regulators: create_signal(BTreeSet::new()),
|
regulators: create_signal(BTreeSet::new()),
|
||||||
serial: Self::next_serial(),
|
serial: Self::next_serial(),
|
||||||
column_index: None.into()
|
column_index: None.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -299,7 +299,7 @@ impl Element for Point {
|
||||||
id,
|
id,
|
||||||
format!("Point {id_num}"),
|
format!("Point {id_num}"),
|
||||||
[0.75_f32, 0.75_f32, 0.75_f32],
|
[0.75_f32, 0.75_f32, 0.75_f32],
|
||||||
point(0.0, 0.0, 0.0)
|
point(0.0, 0.0, 0.0),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -389,7 +389,7 @@ pub struct InversiveDistanceRegulator {
|
||||||
pub subjects: [Rc<dyn Element>; 2],
|
pub subjects: [Rc<dyn Element>; 2],
|
||||||
pub measurement: ReadSignal<f64>,
|
pub measurement: ReadSignal<f64>,
|
||||||
pub set_point: Signal<SpecifiedValue>,
|
pub set_point: Signal<SpecifiedValue>,
|
||||||
serial: u64
|
serial: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InversiveDistanceRegulator {
|
impl InversiveDistanceRegulator {
|
||||||
|
@ -449,7 +449,7 @@ pub struct HalfCurvatureRegulator {
|
||||||
pub subject: Rc<dyn Element>,
|
pub subject: Rc<dyn Element>,
|
||||||
pub measurement: ReadSignal<f64>,
|
pub measurement: ReadSignal<f64>,
|
||||||
pub set_point: Signal<SpecifiedValue>,
|
pub set_point: Signal<SpecifiedValue>,
|
||||||
serial: u64
|
serial: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HalfCurvatureRegulator {
|
impl HalfCurvatureRegulator {
|
||||||
|
@ -501,7 +501,7 @@ impl ProblemPoser for HalfCurvatureRegulator {
|
||||||
// the velocity is expressed in uniform coordinates
|
// the velocity is expressed in uniform coordinates
|
||||||
pub struct ElementMotion<'a> {
|
pub struct ElementMotion<'a> {
|
||||||
pub element: Rc<dyn Element>,
|
pub element: Rc<dyn Element>,
|
||||||
pub velocity: DVectorView<'a, f64>
|
pub velocity: DVectorView<'a, f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
type AssemblyMotion<'a> = Vec<ElementMotion<'a>>;
|
type AssemblyMotion<'a> = Vec<ElementMotion<'a>>;
|
||||||
|
@ -533,7 +533,7 @@ pub struct Assembly {
|
||||||
|
|
||||||
// realization diagnostics
|
// realization diagnostics
|
||||||
pub realization_status: Signal<Result<(), String>>,
|
pub realization_status: Signal<Result<(), String>>,
|
||||||
pub descent_history: Signal<DescentHistory>
|
pub descent_history: Signal<DescentHistory>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Assembly {
|
impl Assembly {
|
||||||
|
@ -546,7 +546,7 @@ impl Assembly {
|
||||||
elements_by_id: create_signal(BTreeMap::default()),
|
elements_by_id: create_signal(BTreeMap::default()),
|
||||||
realization_trigger: create_signal(()),
|
realization_trigger: create_signal(()),
|
||||||
realization_status: create_signal(Ok(())),
|
realization_status: create_signal(Ok(())),
|
||||||
descent_history: create_signal(DescentHistory::new())
|
descent_history: create_signal(DescentHistory::new()),
|
||||||
};
|
};
|
||||||
|
|
||||||
// realize the assembly whenever the element list, the regulator list,
|
// realize the assembly whenever the element list, the regulator list,
|
||||||
|
@ -724,7 +724,7 @@ impl Assembly {
|
||||||
// `Err(message)` we received from the match: we're changing the
|
// `Err(message)` we received from the match: we're changing the
|
||||||
// `Ok` type from `Realization` to `()`
|
// `Ok` type from `Realization` to `()`
|
||||||
self.realization_status.set(Err(message))
|
self.realization_status.set(Err(message))
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -807,7 +807,7 @@ impl Assembly {
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
console_log!("No velocity to unpack for fresh element \"{}\"", elt.id())
|
console_log!("No velocity to unpack for fresh element \"{}\"", elt.id())
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -867,7 +867,7 @@ mod tests {
|
||||||
String::from(sphere_id),
|
String::from(sphere_id),
|
||||||
String::from("Sphere 0"),
|
String::from("Sphere 0"),
|
||||||
[0.75_f32, 0.75_f32, 0.75_f32],
|
[0.75_f32, 0.75_f32, 0.75_f32],
|
||||||
engine::sphere(0.0, 0.0, 0.0, INITIAL_RADIUS)
|
engine::sphere(0.0, 0.0, 0.0, INITIAL_RADIUS),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -881,7 +881,7 @@ mod tests {
|
||||||
vec![
|
vec![
|
||||||
ElementMotion {
|
ElementMotion {
|
||||||
element: sphere.clone(),
|
element: sphere.clone(),
|
||||||
velocity: velocity.as_view()
|
velocity: velocity.as_view(),
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,15 +4,15 @@ use sycamore::prelude::*;
|
||||||
use super::test_assembly_chooser::TestAssemblyChooser;
|
use super::test_assembly_chooser::TestAssemblyChooser;
|
||||||
use crate::{
|
use crate::{
|
||||||
AppState,
|
AppState,
|
||||||
assembly::{InversiveDistanceRegulator, Point, Sphere}
|
assembly::{InversiveDistanceRegulator, Point, Sphere},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn AddRemove() -> View {
|
pub fn AddRemove() -> View {
|
||||||
view! {
|
view! {
|
||||||
div(id="add-remove") {
|
div(id = "add-remove") {
|
||||||
button(
|
button(
|
||||||
on:click=|_| {
|
on:click = |_| {
|
||||||
let state = use_context::<AppState>();
|
let state = use_context::<AppState>();
|
||||||
batch(|| {
|
batch(|| {
|
||||||
// this call is batched to avoid redundant realizations.
|
// this call is batched to avoid redundant realizations.
|
||||||
|
@ -33,18 +33,18 @@ pub fn AddRemove() -> View {
|
||||||
}
|
}
|
||||||
) { "Add sphere" }
|
) { "Add sphere" }
|
||||||
button(
|
button(
|
||||||
on:click=|_| {
|
on:click = |_| {
|
||||||
let state = use_context::<AppState>();
|
let state = use_context::<AppState>();
|
||||||
state.assembly.insert_element_default::<Point>();
|
state.assembly.insert_element_default::<Point>();
|
||||||
}
|
}
|
||||||
) { "Add point" }
|
) { "Add point" }
|
||||||
button(
|
button(
|
||||||
class="emoji", /* KLUDGE */ // for convenience, we're using an emoji as a temporary icon for this button
|
class = "emoji", /* KLUDGE */ // for convenience, we're using an emoji as a temporary icon for this button
|
||||||
disabled={
|
disabled = {
|
||||||
let state = use_context::<AppState>();
|
let state = use_context::<AppState>();
|
||||||
state.selection.with(|sel| sel.len() != 2)
|
state.selection.with(|sel| sel.len() != 2)
|
||||||
},
|
},
|
||||||
on:click=|_| {
|
on:click = |_| {
|
||||||
let state = use_context::<AppState>();
|
let state = use_context::<AppState>();
|
||||||
let subjects: [_; 2] = state.selection.with(
|
let subjects: [_; 2] = state.selection.with(
|
||||||
// the button is only enabled when two elements are
|
// the button is only enabled when two elements are
|
||||||
|
|
|
@ -11,14 +11,12 @@ use crate::AppState;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct DiagnosticsState {
|
struct DiagnosticsState {
|
||||||
active_tab: Signal<String>
|
active_tab: Signal<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DiagnosticsState {
|
impl DiagnosticsState {
|
||||||
fn new(initial_tab: String) -> DiagnosticsState {
|
fn new(initial_tab: String) -> DiagnosticsState {
|
||||||
DiagnosticsState {
|
DiagnosticsState { active_tab: create_signal(initial_tab) }
|
||||||
active_tab: create_signal(initial_tab)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,20 +27,20 @@ fn RealizationStatus() -> View {
|
||||||
let realization_status = state.assembly.realization_status;
|
let realization_status = state.assembly.realization_status;
|
||||||
view! {
|
view! {
|
||||||
div(
|
div(
|
||||||
id="realization-status",
|
id = "realization-status",
|
||||||
class=realization_status.with(
|
class = realization_status.with(
|
||||||
|status| match status {
|
|status| match status {
|
||||||
Ok(_) => "",
|
Ok(_) => "",
|
||||||
Err(_) => "invalid"
|
Err(_) => "invalid",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
div(class="status")
|
div(class = "status")
|
||||||
div {
|
div {
|
||||||
(realization_status.with(
|
(realization_status.with(
|
||||||
|status| match status {
|
|status| match status {
|
||||||
Ok(_) => "Target accuracy achieved".to_string(),
|
Ok(_) => "Target accuracy achieved".to_string(),
|
||||||
Err(message) => message.clone()
|
Err(message) => message.clone(),
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -53,7 +51,7 @@ fn RealizationStatus() -> View {
|
||||||
fn into_log10_time_point((step, value): (usize, f64)) -> Vec<Option<f64>> {
|
fn into_log10_time_point((step, value): (usize, f64)) -> Vec<Option<f64>> {
|
||||||
vec![
|
vec![
|
||||||
Some(step as f64),
|
Some(step as f64),
|
||||||
if value == 0.0 { None } else { Some(value.abs().log10()) }
|
if value == 0.0 { None } else { Some(value.abs().log10()) },
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,7 +103,7 @@ fn LossHistory() -> View {
|
||||||
});
|
});
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
div(id=CONTAINER_ID, class="diagnostics-chart")
|
div(id = CONTAINER_ID, class = "diagnostics-chart")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +120,7 @@ fn SpectrumHistory() -> View {
|
||||||
// positive, negative, and strictly-zero parts
|
// positive, negative, and strictly-zero parts
|
||||||
let (
|
let (
|
||||||
hess_eigvals_zero,
|
hess_eigvals_zero,
|
||||||
hess_eigvals_nonzero
|
hess_eigvals_nonzero,
|
||||||
): (Vec<_>, Vec<_>) = state.assembly.descent_history.with(
|
): (Vec<_>, Vec<_>) = state.assembly.descent_history.with(
|
||||||
|history| history.hess_eigvals
|
|history| history.hess_eigvals
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -143,7 +141,7 @@ fn SpectrumHistory() -> View {
|
||||||
.unwrap_or(1.0);
|
.unwrap_or(1.0);
|
||||||
let (
|
let (
|
||||||
hess_eigvals_pos,
|
hess_eigvals_pos,
|
||||||
hess_eigvals_neg
|
hess_eigvals_neg,
|
||||||
): (Vec<_>, Vec<_>) = hess_eigvals_nonzero
|
): (Vec<_>, Vec<_>) = hess_eigvals_nonzero
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.partition(|&(_, val)| val > 0.0);
|
.partition(|&(_, val)| val > 0.0);
|
||||||
|
@ -211,7 +209,7 @@ fn SpectrumHistory() -> View {
|
||||||
});
|
});
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
div(id=CONTAINER_ID, class="diagnostics-chart")
|
div(id = CONTAINER_ID, class = "diagnostics-chart")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,8 +218,8 @@ fn DiagnosticsPanel(name: &'static str, children: Children) -> View {
|
||||||
let diagnostics_state = use_context::<DiagnosticsState>();
|
let diagnostics_state = use_context::<DiagnosticsState>();
|
||||||
view! {
|
view! {
|
||||||
div(
|
div(
|
||||||
class="diagnostics-panel",
|
class = "diagnostics-panel",
|
||||||
"hidden"=diagnostics_state.active_tab.with(
|
"hidden" = diagnostics_state.active_tab.with(
|
||||||
|active_tab| {
|
|active_tab| {
|
||||||
if active_tab == name {
|
if active_tab == name {
|
||||||
None
|
None
|
||||||
|
@ -243,16 +241,16 @@ pub fn Diagnostics() -> View {
|
||||||
provide_context(diagnostics_state);
|
provide_context(diagnostics_state);
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
div(id="diagnostics") {
|
div(id = "diagnostics") {
|
||||||
div(id="diagnostics-bar") {
|
div(id = "diagnostics-bar") {
|
||||||
RealizationStatus {}
|
RealizationStatus {}
|
||||||
select(bind:value=active_tab) {
|
select(bind:value = active_tab) {
|
||||||
option(value="loss") { "Loss" }
|
option(value = "loss") { "Loss" }
|
||||||
option(value="spectrum") { "Spectrum" }
|
option(value = "spectrum") { "Spectrum" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DiagnosticsPanel(name="loss") { LossHistory {} }
|
DiagnosticsPanel(name = "loss") { LossHistory {} }
|
||||||
DiagnosticsPanel(name="spectrum") { SpectrumHistory {} }
|
DiagnosticsPanel(name = "spectrum") { SpectrumHistory {} }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -12,12 +12,12 @@ use web_sys::{
|
||||||
WebGlProgram,
|
WebGlProgram,
|
||||||
WebGlShader,
|
WebGlShader,
|
||||||
WebGlUniformLocation,
|
WebGlUniformLocation,
|
||||||
wasm_bindgen::{JsCast, JsValue}
|
wasm_bindgen::{JsCast, JsValue},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AppState,
|
AppState,
|
||||||
assembly::{Element, ElementColor, ElementMotion, Point, Sphere}
|
assembly::{Element, ElementColor, ElementMotion, Point, Sphere},
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- color ---
|
// --- color ---
|
||||||
|
@ -37,15 +37,15 @@ fn combine_channels(color: ElementColor, opacity: f32) -> ColorWithOpacity {
|
||||||
struct SceneSpheres {
|
struct SceneSpheres {
|
||||||
representations: Vec<DVector<f64>>,
|
representations: Vec<DVector<f64>>,
|
||||||
colors_with_opacity: Vec<ColorWithOpacity>,
|
colors_with_opacity: Vec<ColorWithOpacity>,
|
||||||
highlights: Vec<f32>
|
highlights: Vec<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SceneSpheres {
|
impl SceneSpheres {
|
||||||
fn new() -> SceneSpheres{
|
fn new() -> SceneSpheres {
|
||||||
SceneSpheres {
|
SceneSpheres {
|
||||||
representations: Vec::new(),
|
representations: Vec::new(),
|
||||||
colors_with_opacity: Vec::new(),
|
colors_with_opacity: Vec::new(),
|
||||||
highlights: Vec::new()
|
highlights: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +53,10 @@ impl SceneSpheres {
|
||||||
self.representations.len().try_into().expect("Number of spheres must fit in a 32-bit integer")
|
self.representations.len().try_into().expect("Number of spheres must fit in a 32-bit integer")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push(&mut self, representation: DVector<f64>, color: ElementColor, opacity: f32, highlight: f32) {
|
fn push(
|
||||||
|
&mut self, representation: DVector<f64>,
|
||||||
|
color: ElementColor, opacity: f32, highlight: f32,
|
||||||
|
) {
|
||||||
self.representations.push(representation);
|
self.representations.push(representation);
|
||||||
self.colors_with_opacity.push(combine_channels(color, opacity));
|
self.colors_with_opacity.push(combine_channels(color, opacity));
|
||||||
self.highlights.push(highlight);
|
self.highlights.push(highlight);
|
||||||
|
@ -64,7 +67,7 @@ struct ScenePoints {
|
||||||
representations: Vec<DVector<f64>>,
|
representations: Vec<DVector<f64>>,
|
||||||
colors_with_opacity: Vec<ColorWithOpacity>,
|
colors_with_opacity: Vec<ColorWithOpacity>,
|
||||||
highlights: Vec<f32>,
|
highlights: Vec<f32>,
|
||||||
selections: Vec<f32>
|
selections: Vec<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScenePoints {
|
impl ScenePoints {
|
||||||
|
@ -73,11 +76,14 @@ impl ScenePoints {
|
||||||
representations: Vec::new(),
|
representations: Vec::new(),
|
||||||
colors_with_opacity: Vec::new(),
|
colors_with_opacity: Vec::new(),
|
||||||
highlights: Vec::new(),
|
highlights: Vec::new(),
|
||||||
selections: Vec::new()
|
selections: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push(&mut self, representation: DVector<f64>, color: ElementColor, opacity: f32, highlight: f32, selected: bool) {
|
fn push(
|
||||||
|
&mut self, representation: DVector<f64>,
|
||||||
|
color: ElementColor, opacity: f32, highlight: f32, selected: bool,
|
||||||
|
) {
|
||||||
self.representations.push(representation);
|
self.representations.push(representation);
|
||||||
self.colors_with_opacity.push(combine_channels(color, opacity));
|
self.colors_with_opacity.push(combine_channels(color, opacity));
|
||||||
self.highlights.push(highlight);
|
self.highlights.push(highlight);
|
||||||
|
@ -87,14 +93,14 @@ impl ScenePoints {
|
||||||
|
|
||||||
pub struct Scene {
|
pub struct Scene {
|
||||||
spheres: SceneSpheres,
|
spheres: SceneSpheres,
|
||||||
points: ScenePoints
|
points: ScenePoints,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scene {
|
impl Scene {
|
||||||
fn new() -> Scene {
|
fn new() -> Scene {
|
||||||
Scene {
|
Scene {
|
||||||
spheres: SceneSpheres::new(),
|
spheres: SceneSpheres::new(),
|
||||||
points: ScenePoints::new()
|
points: ScenePoints::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,7 +111,12 @@ pub trait DisplayItem {
|
||||||
// the smallest positive depth, represented as a multiple of `dir`, where
|
// the smallest positive depth, represented as a multiple of `dir`, where
|
||||||
// the line generated by `dir` hits the element. returns `None` if the line
|
// the line generated by `dir` hits the element. returns `None` if the line
|
||||||
// misses the element
|
// misses the element
|
||||||
fn cast(&self, dir: Vector3<f64>, assembly_to_world: &DMatrix<f64>, pixel_size: f64) -> Option<f64>;
|
fn cast(
|
||||||
|
&self,
|
||||||
|
dir: Vector3<f64>,
|
||||||
|
assembly_to_world: &DMatrix<f64>,
|
||||||
|
pixel_size: f64,
|
||||||
|
) -> Option<f64>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DisplayItem for Sphere {
|
impl DisplayItem for Sphere {
|
||||||
|
@ -124,7 +135,12 @@ impl DisplayItem for Sphere {
|
||||||
|
|
||||||
// this method should be kept synchronized with `sphere_cast` in
|
// this method should be kept synchronized with `sphere_cast` in
|
||||||
// `spheres.frag`, which does essentially the same thing on the GPU side
|
// `spheres.frag`, which does essentially the same thing on the GPU side
|
||||||
fn cast(&self, dir: Vector3<f64>, assembly_to_world: &DMatrix<f64>, _pixel_size: f64) -> Option<f64> {
|
fn cast(
|
||||||
|
&self,
|
||||||
|
dir: Vector3<f64>,
|
||||||
|
assembly_to_world: &DMatrix<f64>,
|
||||||
|
_pixel_size: f64,
|
||||||
|
) -> Option<f64> {
|
||||||
// if `a/b` is less than this threshold, we approximate
|
// if `a/b` is less than this threshold, we approximate
|
||||||
// `a*u^2 + b*u + c` by the linear function `b*u + c`
|
// `a*u^2 + b*u + c` by the linear function `b*u + c`
|
||||||
const DEG_THRESHOLD: f64 = 1e-9;
|
const DEG_THRESHOLD: f64 = 1e-9;
|
||||||
|
@ -177,7 +193,12 @@ impl DisplayItem for Point {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SCAFFOLDING */
|
/* SCAFFOLDING */
|
||||||
fn cast(&self, dir: Vector3<f64>, assembly_to_world: &DMatrix<f64>, pixel_size: f64) -> Option<f64> {
|
fn cast(
|
||||||
|
&self,
|
||||||
|
dir: Vector3<f64>,
|
||||||
|
assembly_to_world: &DMatrix<f64>,
|
||||||
|
pixel_size: f64,
|
||||||
|
) -> Option<f64> {
|
||||||
let rep = self.representation.with_untracked(|rep| assembly_to_world * rep);
|
let rep = self.representation.with_untracked(|rep| assembly_to_world * rep);
|
||||||
if rep[2] < 0.0 {
|
if rep[2] < 0.0 {
|
||||||
// this constant should be kept synchronized with `point.frag`
|
// this constant should be kept synchronized with `point.frag`
|
||||||
|
@ -220,7 +241,7 @@ fn compile_shader(
|
||||||
fn set_up_program(
|
fn set_up_program(
|
||||||
context: &WebGl2RenderingContext,
|
context: &WebGl2RenderingContext,
|
||||||
vertex_shader_source: &str,
|
vertex_shader_source: &str,
|
||||||
fragment_shader_source: &str
|
fragment_shader_source: &str,
|
||||||
) -> WebGlProgram {
|
) -> WebGlProgram {
|
||||||
// compile the shaders
|
// compile the shaders
|
||||||
let vertex_shader = compile_shader(
|
let vertex_shader = compile_shader(
|
||||||
|
@ -260,12 +281,12 @@ fn get_uniform_array_locations<const N: usize>(
|
||||||
context: &WebGl2RenderingContext,
|
context: &WebGl2RenderingContext,
|
||||||
program: &WebGlProgram,
|
program: &WebGlProgram,
|
||||||
var_name: &str,
|
var_name: &str,
|
||||||
member_name_opt: Option<&str>
|
member_name_opt: Option<&str>,
|
||||||
) -> [Option<WebGlUniformLocation>; N] {
|
) -> [Option<WebGlUniformLocation>; N] {
|
||||||
array::from_fn(|n| {
|
array::from_fn(|n| {
|
||||||
let name = match member_name_opt {
|
let name = match member_name_opt {
|
||||||
Some(member_name) => format!("{var_name}[{n}].{member_name}"),
|
Some(member_name) => format!("{var_name}[{n}].{member_name}"),
|
||||||
None => format!("{var_name}[{n}]")
|
None => format!("{var_name}[{n}]"),
|
||||||
};
|
};
|
||||||
context.get_uniform_location(&program, name.as_str())
|
context.get_uniform_location(&program, name.as_str())
|
||||||
})
|
})
|
||||||
|
@ -276,7 +297,7 @@ fn bind_to_attribute(
|
||||||
context: &WebGl2RenderingContext,
|
context: &WebGl2RenderingContext,
|
||||||
attr_index: u32,
|
attr_index: u32,
|
||||||
attr_size: i32,
|
attr_size: i32,
|
||||||
buffer: &Option<WebGlBuffer>
|
buffer: &Option<WebGlBuffer>,
|
||||||
) {
|
) {
|
||||||
context.bind_buffer(WebGl2RenderingContext::ARRAY_BUFFER, buffer.as_ref());
|
context.bind_buffer(WebGl2RenderingContext::ARRAY_BUFFER, buffer.as_ref());
|
||||||
context.vertex_attrib_pointer_with_i32(
|
context.vertex_attrib_pointer_with_i32(
|
||||||
|
@ -292,7 +313,7 @@ fn bind_to_attribute(
|
||||||
// load the given data into a new vertex buffer object
|
// load the given data into a new vertex buffer object
|
||||||
fn load_new_buffer(
|
fn load_new_buffer(
|
||||||
context: &WebGl2RenderingContext,
|
context: &WebGl2RenderingContext,
|
||||||
data: &[f32]
|
data: &[f32],
|
||||||
) -> Option<WebGlBuffer> {
|
) -> Option<WebGlBuffer> {
|
||||||
// create a buffer and bind it to ARRAY_BUFFER
|
// create a buffer and bind it to ARRAY_BUFFER
|
||||||
let buffer = context.create_buffer();
|
let buffer = context.create_buffer();
|
||||||
|
@ -319,7 +340,7 @@ fn bind_new_buffer_to_attribute(
|
||||||
context: &WebGl2RenderingContext,
|
context: &WebGl2RenderingContext,
|
||||||
attr_index: u32,
|
attr_index: u32,
|
||||||
attr_size: i32,
|
attr_size: i32,
|
||||||
data: &[f32]
|
data: &[f32],
|
||||||
) {
|
) {
|
||||||
let buffer = load_new_buffer(context, data);
|
let buffer = load_new_buffer(context, data);
|
||||||
bind_to_attribute(context, attr_index, attr_size, &buffer);
|
bind_to_attribute(context, attr_index, attr_size, &buffer);
|
||||||
|
@ -341,9 +362,9 @@ fn event_dir(event: &MouseEvent) -> (Vector3<f64>, f64) {
|
||||||
Vector3::new(
|
Vector3::new(
|
||||||
FOCAL_SLOPE * (2.0*(f64::from(event.client_x()) - rect.left()) - width) / shortdim,
|
FOCAL_SLOPE * (2.0*(f64::from(event.client_x()) - rect.left()) - width) / shortdim,
|
||||||
FOCAL_SLOPE * (2.0*(rect.bottom() - f64::from(event.client_y())) - height) / shortdim,
|
FOCAL_SLOPE * (2.0*(rect.bottom() - f64::from(event.client_y())) - height) / shortdim,
|
||||||
-1.0
|
-1.0,
|
||||||
),
|
),
|
||||||
FOCAL_SLOPE * 2.0 / shortdim
|
FOCAL_SLOPE * 2.0 / shortdim,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -443,14 +464,14 @@ pub fn Display() -> View {
|
||||||
let sphere_program = set_up_program(
|
let sphere_program = set_up_program(
|
||||||
&ctx,
|
&ctx,
|
||||||
include_str!("identity.vert"),
|
include_str!("identity.vert"),
|
||||||
include_str!("spheres.frag")
|
include_str!("spheres.frag"),
|
||||||
);
|
);
|
||||||
|
|
||||||
// set up the point rendering program
|
// set up the point rendering program
|
||||||
let point_program = set_up_program(
|
let point_program = set_up_program(
|
||||||
&ctx,
|
&ctx,
|
||||||
include_str!("point.vert"),
|
include_str!("point.vert"),
|
||||||
include_str!("point.frag")
|
include_str!("point.frag"),
|
||||||
);
|
);
|
||||||
|
|
||||||
/* DEBUG */
|
/* DEBUG */
|
||||||
|
@ -467,7 +488,7 @@ pub fn Display() -> View {
|
||||||
// capped at 1024 elements
|
// capped at 1024 elements
|
||||||
console::log_2(
|
console::log_2(
|
||||||
&ctx.get_parameter(WebGl2RenderingContext::MAX_FRAGMENT_UNIFORM_VECTORS).unwrap(),
|
&ctx.get_parameter(WebGl2RenderingContext::MAX_FRAGMENT_UNIFORM_VECTORS).unwrap(),
|
||||||
&JsValue::from("uniform vectors available")
|
&JsValue::from("uniform vectors available"),
|
||||||
);
|
);
|
||||||
|
|
||||||
// find the sphere program's vertex attribute
|
// find the sphere program's vertex attribute
|
||||||
|
@ -503,7 +524,7 @@ pub fn Display() -> View {
|
||||||
// southeast triangle
|
// southeast triangle
|
||||||
-1.0, -1.0, 0.0,
|
-1.0, -1.0, 0.0,
|
||||||
1.0, 1.0, 0.0,
|
1.0, 1.0, 0.0,
|
||||||
1.0, -1.0, 0.0
|
1.0, -1.0, 0.0,
|
||||||
];
|
];
|
||||||
let viewport_position_buffer = load_new_buffer(&ctx, &viewport_positions);
|
let viewport_position_buffer = load_new_buffer(&ctx, &viewport_positions);
|
||||||
|
|
||||||
|
@ -596,7 +617,7 @@ pub fn Display() -> View {
|
||||||
vec![
|
vec![
|
||||||
ElementMotion {
|
ElementMotion {
|
||||||
element: sel,
|
element: sel,
|
||||||
velocity: elt_motion.as_view()
|
velocity: elt_motion.as_view(),
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
@ -629,7 +650,7 @@ pub fn Display() -> View {
|
||||||
0.0, 1.0, 0.0, 0.0, 0.0,
|
0.0, 1.0, 0.0, 0.0, 0.0,
|
||||||
0.0, 0.0, 1.0, 0.0, u,
|
0.0, 0.0, 1.0, 0.0, u,
|
||||||
0.0, 0.0, 2.0*u, 1.0, u*u,
|
0.0, 0.0, 2.0*u, 1.0, u*u,
|
||||||
0.0, 0.0, 0.0, 0.0, 1.0
|
0.0, 0.0, 0.0, 0.0, 1.0,
|
||||||
])
|
])
|
||||||
};
|
};
|
||||||
let asm_to_world = &location * &orientation;
|
let asm_to_world = &location * &orientation;
|
||||||
|
@ -668,19 +689,19 @@ pub fn Display() -> View {
|
||||||
let v = &sphere_reps_world[n];
|
let v = &sphere_reps_world[n];
|
||||||
ctx.uniform3fv_with_f32_array(
|
ctx.uniform3fv_with_f32_array(
|
||||||
sphere_sp_locs[n].as_ref(),
|
sphere_sp_locs[n].as_ref(),
|
||||||
v.rows(0, 3).as_slice()
|
v.rows(0, 3).as_slice(),
|
||||||
);
|
);
|
||||||
ctx.uniform2fv_with_f32_array(
|
ctx.uniform2fv_with_f32_array(
|
||||||
sphere_lt_locs[n].as_ref(),
|
sphere_lt_locs[n].as_ref(),
|
||||||
v.rows(3, 2).as_slice()
|
v.rows(3, 2).as_slice(),
|
||||||
);
|
);
|
||||||
ctx.uniform4fv_with_f32_array(
|
ctx.uniform4fv_with_f32_array(
|
||||||
sphere_color_locs[n].as_ref(),
|
sphere_color_locs[n].as_ref(),
|
||||||
&scene.spheres.colors_with_opacity[n]
|
&scene.spheres.colors_with_opacity[n],
|
||||||
);
|
);
|
||||||
ctx.uniform1f(
|
ctx.uniform1f(
|
||||||
sphere_highlight_locs[n].as_ref(),
|
sphere_highlight_locs[n].as_ref(),
|
||||||
scene.spheres.highlights[n]
|
scene.spheres.highlights[n],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -773,7 +794,7 @@ pub fn Display() -> View {
|
||||||
"ArrowLeft" if shift => roll_ccw.set(value),
|
"ArrowLeft" if shift => roll_ccw.set(value),
|
||||||
"ArrowRight" => yaw_right.set(value),
|
"ArrowRight" => yaw_right.set(value),
|
||||||
"ArrowLeft" => yaw_left.set(value),
|
"ArrowLeft" => yaw_left.set(value),
|
||||||
_ => navigating = false
|
_ => navigating = false,
|
||||||
};
|
};
|
||||||
if navigating {
|
if navigating {
|
||||||
scene_changed.set(true);
|
scene_changed.set(true);
|
||||||
|
@ -793,7 +814,7 @@ pub fn Display() -> View {
|
||||||
"s" | "S" => translate_neg_y.set(value),
|
"s" | "S" => translate_neg_y.set(value),
|
||||||
"]" | "}" => shrink_neg.set(value),
|
"]" | "}" => shrink_neg.set(value),
|
||||||
"[" | "{" => shrink_pos.set(value),
|
"[" | "{" => shrink_pos.set(value),
|
||||||
_ => manipulating = false
|
_ => manipulating = false,
|
||||||
};
|
};
|
||||||
if manipulating {
|
if manipulating {
|
||||||
event.prevent_default();
|
event.prevent_default();
|
||||||
|
@ -805,12 +826,12 @@ pub fn Display() -> View {
|
||||||
// switch back to integer-valued parameters when that becomes possible
|
// switch back to integer-valued parameters when that becomes possible
|
||||||
// again
|
// again
|
||||||
canvas(
|
canvas(
|
||||||
ref=display,
|
ref = display,
|
||||||
id="display",
|
id = "display",
|
||||||
width="600",
|
width = "600",
|
||||||
height="600",
|
height = "600",
|
||||||
tabindex="0",
|
tabindex = "0",
|
||||||
on:keydown=move |event: KeyboardEvent| {
|
on:keydown = move |event: KeyboardEvent| {
|
||||||
if event.key() == "Shift" {
|
if event.key() == "Shift" {
|
||||||
// swap navigation inputs
|
// swap navigation inputs
|
||||||
roll_cw.set(yaw_right.get());
|
roll_cw.set(yaw_right.get());
|
||||||
|
@ -836,7 +857,7 @@ pub fn Display() -> View {
|
||||||
set_manip_signal(&event, 1.0);
|
set_manip_signal(&event, 1.0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
on:keyup=move |event: KeyboardEvent| {
|
on:keyup = move |event: KeyboardEvent| {
|
||||||
if event.key() == "Shift" {
|
if event.key() == "Shift" {
|
||||||
// swap navigation inputs
|
// swap navigation inputs
|
||||||
yaw_right.set(roll_cw.get());
|
yaw_right.set(roll_cw.get());
|
||||||
|
@ -858,7 +879,7 @@ pub fn Display() -> View {
|
||||||
set_manip_signal(&event, 0.0);
|
set_manip_signal(&event, 0.0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
on:blur=move |_| {
|
on:blur = move |_| {
|
||||||
pitch_up.set(0.0);
|
pitch_up.set(0.0);
|
||||||
pitch_down.set(0.0);
|
pitch_down.set(0.0);
|
||||||
yaw_right.set(0.0);
|
yaw_right.set(0.0);
|
||||||
|
@ -866,7 +887,7 @@ pub fn Display() -> View {
|
||||||
roll_ccw.set(0.0);
|
roll_ccw.set(0.0);
|
||||||
roll_cw.set(0.0);
|
roll_cw.set(0.0);
|
||||||
},
|
},
|
||||||
on:click=move |event: MouseEvent| {
|
on:click = move |event: MouseEvent| {
|
||||||
// find the nearest element along the pointer direction
|
// find the nearest element along the pointer direction
|
||||||
let (dir, pixel_size) = event_dir(&event);
|
let (dir, pixel_size) = event_dir(&event);
|
||||||
console::log_1(&JsValue::from(dir.to_string()));
|
console::log_1(&JsValue::from(dir.to_string()));
|
||||||
|
@ -883,18 +904,18 @@ pub fn Display() -> View {
|
||||||
clicked = Some((elt, depth))
|
clicked = Some((elt, depth))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => clicked = Some((elt, depth))
|
None => clicked = Some((elt, depth)),
|
||||||
}
|
},
|
||||||
None => ()
|
None => (),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we clicked something, select it
|
// if we clicked something, select it
|
||||||
match clicked {
|
match clicked {
|
||||||
Some((elt, _)) => state.select(&elt, event.shift_key()),
|
Some((elt, _)) => state.select(&elt, event.shift_key()),
|
||||||
None => state.selection.update(|sel| sel.clear())
|
None => state.selection.update(|sel| sel.clear()),
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,11 +1,7 @@
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use sycamore::prelude::*;
|
use sycamore::prelude::*;
|
||||||
use web_sys::{
|
use web_sys::{KeyboardEvent, MouseEvent, wasm_bindgen::JsCast};
|
||||||
KeyboardEvent,
|
|
||||||
MouseEvent,
|
|
||||||
wasm_bindgen::JsCast
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AppState,
|
AppState,
|
||||||
|
@ -13,7 +9,7 @@ use crate::{
|
||||||
Element,
|
Element,
|
||||||
HalfCurvatureRegulator,
|
HalfCurvatureRegulator,
|
||||||
InversiveDistanceRegulator,
|
InversiveDistanceRegulator,
|
||||||
Regulator
|
Regulator,
|
||||||
},
|
},
|
||||||
specified::SpecifiedValue
|
specified::SpecifiedValue
|
||||||
};
|
};
|
||||||
|
@ -49,8 +45,8 @@ fn RegulatorInput(regulator: Rc<dyn Regulator>) -> View {
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
input(
|
input(
|
||||||
r#type="text",
|
r#type = "text",
|
||||||
class=move || {
|
class = move || {
|
||||||
if valid.get() {
|
if valid.get() {
|
||||||
set_point.with(|set_pt| {
|
set_point.with(|set_pt| {
|
||||||
if set_pt.is_present() {
|
if set_pt.is_present() {
|
||||||
|
@ -63,27 +59,27 @@ fn RegulatorInput(regulator: Rc<dyn Regulator>) -> View {
|
||||||
"regulator-input invalid"
|
"regulator-input invalid"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
placeholder=measurement.with(|result| result.to_string()),
|
placeholder = measurement.with(|result| result.to_string()),
|
||||||
bind:value=value,
|
bind:value = value,
|
||||||
on:change=move |_| {
|
on:change = move |_| {
|
||||||
valid.set(
|
valid.set(
|
||||||
match SpecifiedValue::try_from(value.get_clone_untracked()) {
|
match SpecifiedValue::try_from(value.get_clone_untracked()) {
|
||||||
Ok(set_pt) => {
|
Ok(set_pt) => {
|
||||||
set_point.set(set_pt);
|
set_point.set(set_pt);
|
||||||
true
|
true
|
||||||
}
|
},
|
||||||
Err(_) => false
|
Err(_) => false,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
on:keydown={
|
on:keydown = {
|
||||||
move |event: KeyboardEvent| {
|
move |event: KeyboardEvent| {
|
||||||
match event.key().as_str() {
|
match event.key().as_str() {
|
||||||
"Escape" => reset_value(),
|
"Escape" => reset_value(),
|
||||||
_ => ()
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,11 +96,11 @@ impl OutlineItem for InversiveDistanceRegulator {
|
||||||
self.subjects[0].label()
|
self.subjects[0].label()
|
||||||
}.clone();
|
}.clone();
|
||||||
view! {
|
view! {
|
||||||
li(class="regulator") {
|
li(class = "regulator") {
|
||||||
div(class="regulator-label") { (other_subject_label) }
|
div(class = "regulator-label") { (other_subject_label) }
|
||||||
div(class="regulator-type") { "Inversive distance" }
|
div(class = "regulator-type") { "Inversive distance" }
|
||||||
RegulatorInput(regulator=self)
|
RegulatorInput(regulator = self)
|
||||||
div(class="status")
|
div(class = "status")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,11 +109,11 @@ impl OutlineItem for InversiveDistanceRegulator {
|
||||||
impl OutlineItem for HalfCurvatureRegulator {
|
impl OutlineItem for HalfCurvatureRegulator {
|
||||||
fn outline_item(self: Rc<Self>, _element: &Rc<dyn Element>) -> View {
|
fn outline_item(self: Rc<Self>, _element: &Rc<dyn Element>) -> View {
|
||||||
view! {
|
view! {
|
||||||
li(class="regulator") {
|
li(class = "regulator") {
|
||||||
div(class="regulator-label") // for spacing
|
div(class = "regulator-label") // for spacing
|
||||||
div(class="regulator-type") { "Half-curvature" }
|
div(class = "regulator-type") { "Half-curvature" }
|
||||||
RegulatorInput(regulator=self)
|
RegulatorInput(regulator = self)
|
||||||
div(class="status")
|
div(class = "status")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -156,10 +152,10 @@ fn ElementOutlineItem(element: Rc<dyn Element>) -> View {
|
||||||
let details_node = create_node_ref();
|
let details_node = create_node_ref();
|
||||||
view! {
|
view! {
|
||||||
li {
|
li {
|
||||||
details(ref=details_node) {
|
details(ref = details_node) {
|
||||||
summary(
|
summary(
|
||||||
class=class.get(),
|
class = class.get(),
|
||||||
on:keydown={
|
on:keydown = {
|
||||||
let element_for_handler = element.clone();
|
let element_for_handler = element.clone();
|
||||||
move |event: KeyboardEvent| {
|
move |event: KeyboardEvent| {
|
||||||
match event.key().as_str() {
|
match event.key().as_str() {
|
||||||
|
@ -179,18 +175,18 @@ fn ElementOutlineItem(element: Rc<dyn Element>) -> View {
|
||||||
.unchecked_into::<web_sys::Element>()
|
.unchecked_into::<web_sys::Element>()
|
||||||
.remove_attribute("open");
|
.remove_attribute("open");
|
||||||
},
|
},
|
||||||
_ => ()
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
div(
|
div(
|
||||||
class="element-switch",
|
class = "element-switch",
|
||||||
on:click=|event: MouseEvent| event.stop_propagation()
|
on:click = |event: MouseEvent| event.stop_propagation()
|
||||||
)
|
)
|
||||||
div(
|
div(
|
||||||
class="element",
|
class = "element",
|
||||||
on:click={
|
on:click = {
|
||||||
let state_for_handler = state.clone();
|
let state_for_handler = state.clone();
|
||||||
let element_for_handler = element.clone();
|
let element_for_handler = element.clone();
|
||||||
move |event: MouseEvent| {
|
move |event: MouseEvent| {
|
||||||
|
@ -200,20 +196,20 @@ fn ElementOutlineItem(element: Rc<dyn Element>) -> View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
div(class="element-label") { (label) }
|
div(class = "element-label") { (label) }
|
||||||
div(class="element-representation") { (rep_components) }
|
div(class = "element-representation") { (rep_components) }
|
||||||
input(
|
input(
|
||||||
r#type="checkbox",
|
r#type = "checkbox",
|
||||||
bind:checked=element.ghost(),
|
bind:checked = element.ghost(),
|
||||||
on:click=|event: MouseEvent| event.stop_propagation()
|
on:click = |event: MouseEvent| event.stop_propagation()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ul(class="regulators") {
|
ul(class = "regulators") {
|
||||||
Keyed(
|
Keyed(
|
||||||
list=regulator_list,
|
list = regulator_list,
|
||||||
view=move |reg| reg.outline_item(&element),
|
view = move |reg| reg.outline_item(&element),
|
||||||
key=|reg| reg.serial()
|
key = |reg| reg.serial()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -246,18 +242,18 @@ pub fn Outline() -> View {
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
ul(
|
ul(
|
||||||
id="outline",
|
id = "outline",
|
||||||
on:click={
|
on:click = {
|
||||||
let state = use_context::<AppState>();
|
let state = use_context::<AppState>();
|
||||||
move |_| state.selection.update(|sel| sel.clear())
|
move |_| state.selection.update(|sel| sel.clear())
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
Keyed(
|
Keyed(
|
||||||
list=element_list,
|
list = element_list,
|
||||||
view=|elt| view! {
|
view = |elt| view! {
|
||||||
ElementOutlineItem(element=elt)
|
ElementOutlineItem(element = elt)
|
||||||
},
|
},
|
||||||
key=|elt| elt.serial()
|
key = |elt| elt.serial()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,17 +6,17 @@ use web_sys::{console, wasm_bindgen::JsValue};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AppState,
|
AppState,
|
||||||
engine,
|
|
||||||
engine::DescentHistory,
|
|
||||||
assembly::{
|
assembly::{
|
||||||
Assembly,
|
Assembly,
|
||||||
Element,
|
Element,
|
||||||
ElementColor,
|
ElementColor,
|
||||||
InversiveDistanceRegulator,
|
InversiveDistanceRegulator,
|
||||||
Point,
|
Point,
|
||||||
Sphere
|
Sphere,
|
||||||
},
|
},
|
||||||
specified::SpecifiedValue
|
engine,
|
||||||
|
engine::DescentHistory,
|
||||||
|
specified::SpecifiedValue,
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- loaders ---
|
// --- loaders ---
|
||||||
|
@ -32,7 +32,7 @@ fn load_gen_assemb(assembly: &Assembly) {
|
||||||
String::from("gemini_a"),
|
String::from("gemini_a"),
|
||||||
String::from("Castor"),
|
String::from("Castor"),
|
||||||
[1.00_f32, 0.25_f32, 0.00_f32],
|
[1.00_f32, 0.25_f32, 0.00_f32],
|
||||||
engine::sphere(0.5, 0.5, 0.0, 1.0)
|
engine::sphere(0.5, 0.5, 0.0, 1.0),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
let _ = assembly.try_insert_element(
|
let _ = assembly.try_insert_element(
|
||||||
|
@ -40,7 +40,7 @@ fn load_gen_assemb(assembly: &Assembly) {
|
||||||
String::from("gemini_b"),
|
String::from("gemini_b"),
|
||||||
String::from("Pollux"),
|
String::from("Pollux"),
|
||||||
[0.00_f32, 0.25_f32, 1.00_f32],
|
[0.00_f32, 0.25_f32, 1.00_f32],
|
||||||
engine::sphere(-0.5, -0.5, 0.0, 1.0)
|
engine::sphere(-0.5, -0.5, 0.0, 1.0),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
let _ = assembly.try_insert_element(
|
let _ = assembly.try_insert_element(
|
||||||
|
@ -48,7 +48,7 @@ fn load_gen_assemb(assembly: &Assembly) {
|
||||||
String::from("ursa_major"),
|
String::from("ursa_major"),
|
||||||
String::from("Ursa major"),
|
String::from("Ursa major"),
|
||||||
[0.25_f32, 0.00_f32, 1.00_f32],
|
[0.25_f32, 0.00_f32, 1.00_f32],
|
||||||
engine::sphere(-0.5, 0.5, 0.0, 0.75)
|
engine::sphere(-0.5, 0.5, 0.0, 0.75),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
let _ = assembly.try_insert_element(
|
let _ = assembly.try_insert_element(
|
||||||
|
@ -56,7 +56,7 @@ fn load_gen_assemb(assembly: &Assembly) {
|
||||||
String::from("ursa_minor"),
|
String::from("ursa_minor"),
|
||||||
String::from("Ursa minor"),
|
String::from("Ursa minor"),
|
||||||
[0.25_f32, 1.00_f32, 0.00_f32],
|
[0.25_f32, 1.00_f32, 0.00_f32],
|
||||||
engine::sphere(0.5, -0.5, 0.0, 0.5)
|
engine::sphere(0.5, -0.5, 0.0, 0.5),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
let _ = assembly.try_insert_element(
|
let _ = assembly.try_insert_element(
|
||||||
|
@ -64,7 +64,7 @@ fn load_gen_assemb(assembly: &Assembly) {
|
||||||
String::from("moon_deimos"),
|
String::from("moon_deimos"),
|
||||||
String::from("Deimos"),
|
String::from("Deimos"),
|
||||||
[0.75_f32, 0.75_f32, 0.00_f32],
|
[0.75_f32, 0.75_f32, 0.00_f32],
|
||||||
engine::sphere(0.0, 0.15, 1.0, 0.25)
|
engine::sphere(0.0, 0.15, 1.0, 0.25),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
let _ = assembly.try_insert_element(
|
let _ = assembly.try_insert_element(
|
||||||
|
@ -72,7 +72,7 @@ fn load_gen_assemb(assembly: &Assembly) {
|
||||||
String::from("moon_phobos"),
|
String::from("moon_phobos"),
|
||||||
String::from("Phobos"),
|
String::from("Phobos"),
|
||||||
[0.00_f32, 0.75_f32, 0.50_f32],
|
[0.00_f32, 0.75_f32, 0.50_f32],
|
||||||
engine::sphere(0.0, -0.15, -1.0, 0.25)
|
engine::sphere(0.0, -0.15, -1.0, 0.25),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
|
||||||
"central".to_string(),
|
"central".to_string(),
|
||||||
"Central".to_string(),
|
"Central".to_string(),
|
||||||
[0.75_f32, 0.75_f32, 0.75_f32],
|
[0.75_f32, 0.75_f32, 0.75_f32],
|
||||||
engine::sphere(0.0, 0.0, 0.0, 1.0)
|
engine::sphere(0.0, 0.0, 0.0, 1.0),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
let _ = assembly.try_insert_element(
|
let _ = assembly.try_insert_element(
|
||||||
|
@ -93,7 +93,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
|
||||||
"assemb_plane".to_string(),
|
"assemb_plane".to_string(),
|
||||||
"Assembly plane".to_string(),
|
"Assembly plane".to_string(),
|
||||||
[0.75_f32, 0.75_f32, 0.75_f32],
|
[0.75_f32, 0.75_f32, 0.75_f32],
|
||||||
engine::sphere_with_offset(0.0, 0.0, 1.0, 0.0, 0.0)
|
engine::sphere_with_offset(0.0, 0.0, 1.0, 0.0, 0.0),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
let _ = assembly.try_insert_element(
|
let _ = assembly.try_insert_element(
|
||||||
|
@ -101,7 +101,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
|
||||||
"side1".to_string(),
|
"side1".to_string(),
|
||||||
"Side 1".to_string(),
|
"Side 1".to_string(),
|
||||||
[1.00_f32, 0.00_f32, 0.25_f32],
|
[1.00_f32, 0.00_f32, 0.25_f32],
|
||||||
engine::sphere_with_offset(1.0, 0.0, 0.0, 1.0, 0.0)
|
engine::sphere_with_offset(1.0, 0.0, 0.0, 1.0, 0.0),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
let _ = assembly.try_insert_element(
|
let _ = assembly.try_insert_element(
|
||||||
|
@ -109,7 +109,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
|
||||||
"side2".to_string(),
|
"side2".to_string(),
|
||||||
"Side 2".to_string(),
|
"Side 2".to_string(),
|
||||||
[0.25_f32, 1.00_f32, 0.00_f32],
|
[0.25_f32, 1.00_f32, 0.00_f32],
|
||||||
engine::sphere_with_offset(-0.5, a, 0.0, 1.0, 0.0)
|
engine::sphere_with_offset(-0.5, a, 0.0, 1.0, 0.0),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
let _ = assembly.try_insert_element(
|
let _ = assembly.try_insert_element(
|
||||||
|
@ -117,7 +117,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
|
||||||
"side3".to_string(),
|
"side3".to_string(),
|
||||||
"Side 3".to_string(),
|
"Side 3".to_string(),
|
||||||
[0.00_f32, 0.25_f32, 1.00_f32],
|
[0.00_f32, 0.25_f32, 1.00_f32],
|
||||||
engine::sphere_with_offset(-0.5, -a, 0.0, 1.0, 0.0)
|
engine::sphere_with_offset(-0.5, -a, 0.0, 1.0, 0.0),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
let _ = assembly.try_insert_element(
|
let _ = assembly.try_insert_element(
|
||||||
|
@ -125,7 +125,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
|
||||||
"corner1".to_string(),
|
"corner1".to_string(),
|
||||||
"Corner 1".to_string(),
|
"Corner 1".to_string(),
|
||||||
[0.75_f32, 0.75_f32, 0.75_f32],
|
[0.75_f32, 0.75_f32, 0.75_f32],
|
||||||
engine::sphere(-4.0/3.0, 0.0, 0.0, 1.0/3.0)
|
engine::sphere(-4.0/3.0, 0.0, 0.0, 1.0/3.0),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
let _ = assembly.try_insert_element(
|
let _ = assembly.try_insert_element(
|
||||||
|
@ -133,7 +133,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
|
||||||
"corner2".to_string(),
|
"corner2".to_string(),
|
||||||
"Corner 2".to_string(),
|
"Corner 2".to_string(),
|
||||||
[0.75_f32, 0.75_f32, 0.75_f32],
|
[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)
|
engine::sphere(2.0/3.0, -4.0/3.0 * a, 0.0, 1.0/3.0),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
let _ = assembly.try_insert_element(
|
let _ = assembly.try_insert_element(
|
||||||
|
@ -141,7 +141,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
|
||||||
String::from("corner3"),
|
String::from("corner3"),
|
||||||
String::from("Corner 3"),
|
String::from("Corner 3"),
|
||||||
[0.75_f32, 0.75_f32, 0.75_f32],
|
[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)
|
engine::sphere(2.0/3.0, 4.0/3.0 * a, 0.0, 1.0/3.0),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -202,7 +202,7 @@ fn load_pointed_assemb(assembly: &Assembly) {
|
||||||
format!("point_front"),
|
format!("point_front"),
|
||||||
format!("Front point"),
|
format!("Front point"),
|
||||||
[0.75_f32, 0.75_f32, 0.75_f32],
|
[0.75_f32, 0.75_f32, 0.75_f32],
|
||||||
engine::point(0.0, 0.0, FRAC_1_SQRT_2)
|
engine::point(0.0, 0.0, FRAC_1_SQRT_2),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
let _ = assembly.try_insert_element(
|
let _ = assembly.try_insert_element(
|
||||||
|
@ -210,7 +210,7 @@ fn load_pointed_assemb(assembly: &Assembly) {
|
||||||
format!("point_back"),
|
format!("point_back"),
|
||||||
format!("Back point"),
|
format!("Back point"),
|
||||||
[0.75_f32, 0.75_f32, 0.75_f32],
|
[0.75_f32, 0.75_f32, 0.75_f32],
|
||||||
engine::point(0.0, 0.0, -FRAC_1_SQRT_2)
|
engine::point(0.0, 0.0, -FRAC_1_SQRT_2),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
for index_x in 0..=1 {
|
for index_x in 0..=1 {
|
||||||
|
@ -223,7 +223,7 @@ fn load_pointed_assemb(assembly: &Assembly) {
|
||||||
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],
|
[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)
|
engine::sphere(x, y, 0.0, 1.0),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -232,7 +232,7 @@ fn load_pointed_assemb(assembly: &Assembly) {
|
||||||
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],
|
[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)
|
engine::point(x, y, 0.0),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -256,56 +256,56 @@ fn load_tridim_icosahedron_assemb(assembly: &Assembly) {
|
||||||
"a1".to_string(),
|
"a1".to_string(),
|
||||||
"A₁".to_string(),
|
"A₁".to_string(),
|
||||||
COLOR_A,
|
COLOR_A,
|
||||||
engine::point(0.25, 0.75, 0.75)
|
engine::point(0.25, 0.75, 0.75),
|
||||||
),
|
),
|
||||||
Point::new(
|
Point::new(
|
||||||
"a2".to_string(),
|
"a2".to_string(),
|
||||||
"A₂".to_string(),
|
"A₂".to_string(),
|
||||||
COLOR_A,
|
COLOR_A,
|
||||||
engine::point(0.75, 0.25, 0.75)
|
engine::point(0.75, 0.25, 0.75),
|
||||||
),
|
),
|
||||||
Point::new(
|
Point::new(
|
||||||
"a3".to_string(),
|
"a3".to_string(),
|
||||||
"A₃".to_string(),
|
"A₃".to_string(),
|
||||||
COLOR_A,
|
COLOR_A,
|
||||||
engine::point(0.75, 0.75, 0.25)
|
engine::point(0.75, 0.75, 0.25),
|
||||||
),
|
),
|
||||||
Point::new(
|
Point::new(
|
||||||
"b1".to_string(),
|
"b1".to_string(),
|
||||||
"B₁".to_string(),
|
"B₁".to_string(),
|
||||||
COLOR_B,
|
COLOR_B,
|
||||||
engine::point(0.75, -0.25, -0.25)
|
engine::point(0.75, -0.25, -0.25),
|
||||||
),
|
),
|
||||||
Point::new(
|
Point::new(
|
||||||
"b2".to_string(),
|
"b2".to_string(),
|
||||||
"B₂".to_string(),
|
"B₂".to_string(),
|
||||||
COLOR_B,
|
COLOR_B,
|
||||||
engine::point(-0.25, 0.75, -0.25)
|
engine::point(-0.25, 0.75, -0.25),
|
||||||
),
|
),
|
||||||
Point::new(
|
Point::new(
|
||||||
"b3".to_string(),
|
"b3".to_string(),
|
||||||
"B₃".to_string(),
|
"B₃".to_string(),
|
||||||
COLOR_B,
|
COLOR_B,
|
||||||
engine::point(-0.25, -0.25, 0.75)
|
engine::point(-0.25, -0.25, 0.75),
|
||||||
),
|
),
|
||||||
Point::new(
|
Point::new(
|
||||||
"c1".to_string(),
|
"c1".to_string(),
|
||||||
"C₁".to_string(),
|
"C₁".to_string(),
|
||||||
COLOR_C,
|
COLOR_C,
|
||||||
engine::point(0.0, -1.0, -1.0)
|
engine::point(0.0, -1.0, -1.0),
|
||||||
),
|
),
|
||||||
Point::new(
|
Point::new(
|
||||||
"c2".to_string(),
|
"c2".to_string(),
|
||||||
"C₂".to_string(),
|
"C₂".to_string(),
|
||||||
COLOR_C,
|
COLOR_C,
|
||||||
engine::point(-1.0, 0.0, -1.0)
|
engine::point(-1.0, 0.0, -1.0),
|
||||||
),
|
),
|
||||||
Point::new(
|
Point::new(
|
||||||
"c3".to_string(),
|
"c3".to_string(),
|
||||||
"C₃".to_string(),
|
"C₃".to_string(),
|
||||||
COLOR_C,
|
COLOR_C,
|
||||||
engine::point(-1.0, -1.0, 0.0)
|
engine::point(-1.0, -1.0, 0.0),
|
||||||
)
|
),
|
||||||
];
|
];
|
||||||
for vertex in vertices {
|
for vertex in vertices {
|
||||||
let _ = assembly.try_insert_element(vertex);
|
let _ = assembly.try_insert_element(vertex);
|
||||||
|
@ -320,20 +320,20 @@ fn load_tridim_icosahedron_assemb(assembly: &Assembly) {
|
||||||
"face1".to_string(),
|
"face1".to_string(),
|
||||||
"Face 1".to_string(),
|
"Face 1".to_string(),
|
||||||
COLOR_FACE,
|
COLOR_FACE,
|
||||||
engine::sphere_with_offset(frac_2_sqrt_6, -frac_1_sqrt_6, -frac_1_sqrt_6, -frac_1_sqrt_6, 0.0)
|
engine::sphere_with_offset(frac_2_sqrt_6, -frac_1_sqrt_6, -frac_1_sqrt_6, -frac_1_sqrt_6, 0.0),
|
||||||
),
|
),
|
||||||
Sphere::new(
|
Sphere::new(
|
||||||
"face2".to_string(),
|
"face2".to_string(),
|
||||||
"Face 2".to_string(),
|
"Face 2".to_string(),
|
||||||
COLOR_FACE,
|
COLOR_FACE,
|
||||||
engine::sphere_with_offset(-frac_1_sqrt_6, frac_2_sqrt_6, -frac_1_sqrt_6, -frac_1_sqrt_6, 0.0)
|
engine::sphere_with_offset(-frac_1_sqrt_6, frac_2_sqrt_6, -frac_1_sqrt_6, -frac_1_sqrt_6, 0.0),
|
||||||
),
|
),
|
||||||
Sphere::new(
|
Sphere::new(
|
||||||
"face3".to_string(),
|
"face3".to_string(),
|
||||||
"Face 3".to_string(),
|
"Face 3".to_string(),
|
||||||
COLOR_FACE,
|
COLOR_FACE,
|
||||||
engine::sphere_with_offset(-frac_1_sqrt_6, -frac_1_sqrt_6, frac_2_sqrt_6, -frac_1_sqrt_6, 0.0)
|
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 {
|
for face in faces {
|
||||||
face.ghost().set(true);
|
face.ghost().set(true);
|
||||||
|
@ -416,7 +416,7 @@ fn load_dodeca_packing_assemb(assembly: &Assembly) {
|
||||||
"substrate".to_string(),
|
"substrate".to_string(),
|
||||||
"Substrate".to_string(),
|
"Substrate".to_string(),
|
||||||
[0.75_f32, 0.75_f32, 0.75_f32],
|
[0.75_f32, 0.75_f32, 0.75_f32],
|
||||||
engine::sphere(0.0, 0.0, 0.0, 1.0)
|
engine::sphere(0.0, 0.0, 0.0, 1.0),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
let substrate = assembly.elements_by_id.with_untracked(
|
let substrate = assembly.elements_by_id.with_untracked(
|
||||||
|
@ -456,7 +456,7 @@ fn load_dodeca_packing_assemb(assembly: &Assembly) {
|
||||||
id_a.clone(),
|
id_a.clone(),
|
||||||
format!("A{label_sub}"),
|
format!("A{label_sub}"),
|
||||||
COLOR_A,
|
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(
|
faces.push(
|
||||||
|
@ -472,7 +472,7 @@ fn load_dodeca_packing_assemb(assembly: &Assembly) {
|
||||||
id_b.clone(),
|
id_b.clone(),
|
||||||
format!("B{label_sub}"),
|
format!("B{label_sub}"),
|
||||||
COLOR_B,
|
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(
|
faces.push(
|
||||||
|
@ -488,7 +488,7 @@ fn load_dodeca_packing_assemb(assembly: &Assembly) {
|
||||||
id_c.clone(),
|
id_c.clone(),
|
||||||
format!("C{label_sub}"),
|
format!("C{label_sub}"),
|
||||||
COLOR_C,
|
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(
|
faces.push(
|
||||||
|
@ -559,19 +559,19 @@ fn load_balanced_assemb(assembly: &Assembly) {
|
||||||
"outer".to_string(),
|
"outer".to_string(),
|
||||||
"Outer".to_string(),
|
"Outer".to_string(),
|
||||||
[0.75_f32, 0.75_f32, 0.75_f32],
|
[0.75_f32, 0.75_f32, 0.75_f32],
|
||||||
engine::sphere(0.0, 0.0, 0.0, R_OUTER)
|
engine::sphere(0.0, 0.0, 0.0, R_OUTER),
|
||||||
),
|
),
|
||||||
Sphere::new(
|
Sphere::new(
|
||||||
"a".to_string(),
|
"a".to_string(),
|
||||||
"A".to_string(),
|
"A".to_string(),
|
||||||
[1.00_f32, 0.00_f32, 0.25_f32],
|
[1.00_f32, 0.00_f32, 0.25_f32],
|
||||||
engine::sphere(0.0, 4.0, 0.0, R_INNER)
|
engine::sphere(0.0, 4.0, 0.0, R_INNER),
|
||||||
),
|
),
|
||||||
Sphere::new(
|
Sphere::new(
|
||||||
"b".to_string(),
|
"b".to_string(),
|
||||||
"B".to_string(),
|
"B".to_string(),
|
||||||
[0.00_f32, 0.25_f32, 1.00_f32],
|
[0.00_f32, 0.25_f32, 1.00_f32],
|
||||||
engine::sphere(0.0, -4.0, 0.0, R_INNER)
|
engine::sphere(0.0, -4.0, 0.0, R_INNER),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
for sphere in spheres {
|
for sphere in spheres {
|
||||||
|
@ -589,7 +589,7 @@ fn load_balanced_assemb(assembly: &Assembly) {
|
||||||
for (sphere, radius) in [
|
for (sphere, radius) in [
|
||||||
(outer.clone(), R_OUTER),
|
(outer.clone(), R_OUTER),
|
||||||
(a.clone(), R_INNER),
|
(a.clone(), R_INNER),
|
||||||
(b.clone(), R_INNER)
|
(b.clone(), R_INNER),
|
||||||
] {
|
] {
|
||||||
let curvature_regulator = sphere.regulators().with_untracked(
|
let curvature_regulator = sphere.regulators().with_untracked(
|
||||||
|regs| regs.first().unwrap().clone()
|
|regs| regs.first().unwrap().clone()
|
||||||
|
@ -618,7 +618,7 @@ fn load_off_center_assemb(assembly: &Assembly) {
|
||||||
"point".to_string(),
|
"point".to_string(),
|
||||||
"Point".to_string(),
|
"Point".to_string(),
|
||||||
[0.75_f32, 0.75_f32, 0.75_f32],
|
[0.75_f32, 0.75_f32, 0.75_f32],
|
||||||
engine::point(1e-9, 0.0, 0.0)
|
engine::point(1e-9, 0.0, 0.0),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
let _ = assembly.try_insert_element(
|
let _ = assembly.try_insert_element(
|
||||||
|
@ -626,7 +626,7 @@ fn load_off_center_assemb(assembly: &Assembly) {
|
||||||
"sphere".to_string(),
|
"sphere".to_string(),
|
||||||
"Sphere".to_string(),
|
"Sphere".to_string(),
|
||||||
[0.75_f32, 0.75_f32, 0.75_f32],
|
[0.75_f32, 0.75_f32, 0.75_f32],
|
||||||
engine::sphere(0.0, 0.0, 0.0, 1.0)
|
engine::sphere(0.0, 0.0, 0.0, 1.0),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -658,14 +658,14 @@ fn load_radius_ratio_assemb(assembly: &Assembly) {
|
||||||
"sphere_faces".to_string(),
|
"sphere_faces".to_string(),
|
||||||
"Insphere".to_string(),
|
"Insphere".to_string(),
|
||||||
GRAY,
|
GRAY,
|
||||||
engine::sphere(0.0, 0.0, 0.0, 0.5)
|
engine::sphere(0.0, 0.0, 0.0, 0.5),
|
||||||
),
|
),
|
||||||
Sphere::new(
|
Sphere::new(
|
||||||
"sphere_vertices".to_string(),
|
"sphere_vertices".to_string(),
|
||||||
"Circumsphere".to_string(),
|
"Circumsphere".to_string(),
|
||||||
GRAY,
|
GRAY,
|
||||||
engine::sphere(0.0, 0.0, 0.0, 0.25)
|
engine::sphere(0.0, 0.0, 0.0, 0.25),
|
||||||
)
|
),
|
||||||
];
|
];
|
||||||
for sphere in spheres {
|
for sphere in spheres {
|
||||||
let _ = assembly.try_insert_element(sphere);
|
let _ = assembly.try_insert_element(sphere);
|
||||||
|
@ -678,13 +678,13 @@ fn load_radius_ratio_assemb(assembly: &Assembly) {
|
||||||
[1.00_f32, 0.50_f32, 0.75_f32],
|
[1.00_f32, 0.50_f32, 0.75_f32],
|
||||||
[1.00_f32, 0.75_f32, 0.50_f32],
|
[1.00_f32, 0.75_f32, 0.50_f32],
|
||||||
[1.00_f32, 1.00_f32, 0.50_f32],
|
[1.00_f32, 1.00_f32, 0.50_f32],
|
||||||
[0.75_f32, 0.50_f32, 1.00_f32]
|
[0.75_f32, 0.50_f32, 1.00_f32],
|
||||||
].into_iter(),
|
].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),
|
||||||
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()
|
].into_iter()
|
||||||
).map(
|
).map(
|
||||||
|(k, color, representation)| {
|
|(k, color, representation)| {
|
||||||
|
@ -692,7 +692,7 @@ fn load_radius_ratio_assemb(assembly: &Assembly) {
|
||||||
format!("v{k}"),
|
format!("v{k}"),
|
||||||
format!("Vertex {k}"),
|
format!("Vertex {k}"),
|
||||||
color,
|
color,
|
||||||
representation
|
representation,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -709,13 +709,13 @@ fn load_radius_ratio_assemb(assembly: &Assembly) {
|
||||||
[1.00_f32, 0.00_f32, 0.25_f32],
|
[1.00_f32, 0.00_f32, 0.25_f32],
|
||||||
[1.00_f32, 0.25_f32, 0.00_f32],
|
[1.00_f32, 0.25_f32, 0.00_f32],
|
||||||
[0.75_f32, 0.75_f32, 0.00_f32],
|
[0.75_f32, 0.75_f32, 0.00_f32],
|
||||||
[0.25_f32, 0.00_f32, 1.00_f32]
|
[0.25_f32, 0.00_f32, 1.00_f32],
|
||||||
].into_iter(),
|
].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),
|
||||||
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()
|
].into_iter()
|
||||||
).map(
|
).map(
|
||||||
|(k, color, representation)| {
|
|(k, color, representation)| {
|
||||||
|
@ -723,7 +723,7 @@ fn load_radius_ratio_assemb(assembly: &Assembly) {
|
||||||
format!("f{k}"),
|
format!("f{k}"),
|
||||||
format!("Face {k}"),
|
format!("Face {k}"),
|
||||||
color,
|
color,
|
||||||
representation
|
representation,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -736,7 +736,7 @@ fn load_radius_ratio_assemb(assembly: &Assembly) {
|
||||||
for j in index_range.clone() {
|
for j in index_range.clone() {
|
||||||
let [face_j, vertex_j] = [
|
let [face_j, vertex_j] = [
|
||||||
format!("f{j}"),
|
format!("f{j}"),
|
||||||
format!("v{j}")
|
format!("v{j}"),
|
||||||
].map(
|
].map(
|
||||||
|id| assembly.elements_by_id.with_untracked(
|
|id| assembly.elements_by_id.with_untracked(
|
||||||
|elts_by_id| elts_by_id[&id].clone()
|
|elts_by_id| elts_by_id[&id].clone()
|
||||||
|
@ -797,7 +797,7 @@ fn load_irisawa_hexlet_assemb(assembly: &Assembly) {
|
||||||
[0.75_f32, 0.75_f32, 0.00_f32],
|
[0.75_f32, 0.75_f32, 0.00_f32],
|
||||||
[0.25_f32, 1.00_f32, 0.00_f32],
|
[0.25_f32, 1.00_f32, 0.00_f32],
|
||||||
[0.00_f32, 0.25_f32, 1.00_f32],
|
[0.00_f32, 0.25_f32, 1.00_f32],
|
||||||
[0.25_f32, 0.00_f32, 1.00_f32]
|
[0.25_f32, 0.00_f32, 1.00_f32],
|
||||||
].into_iter();
|
].into_iter();
|
||||||
|
|
||||||
// create the spheres
|
// create the spheres
|
||||||
|
@ -806,19 +806,19 @@ fn load_irisawa_hexlet_assemb(assembly: &Assembly) {
|
||||||
"outer".to_string(),
|
"outer".to_string(),
|
||||||
"Outer".to_string(),
|
"Outer".to_string(),
|
||||||
[0.5_f32, 0.5_f32, 0.5_f32],
|
[0.5_f32, 0.5_f32, 0.5_f32],
|
||||||
engine::sphere(0.0, 0.0, 0.0, 1.5)
|
engine::sphere(0.0, 0.0, 0.0, 1.5),
|
||||||
),
|
),
|
||||||
Sphere::new(
|
Sphere::new(
|
||||||
"sun".to_string(),
|
"sun".to_string(),
|
||||||
"Sun".to_string(),
|
"Sun".to_string(),
|
||||||
[0.75_f32, 0.75_f32, 0.75_f32],
|
[0.75_f32, 0.75_f32, 0.75_f32],
|
||||||
engine::sphere(0.0, -0.75, 0.0, 0.75)
|
engine::sphere(0.0, -0.75, 0.0, 0.75),
|
||||||
),
|
),
|
||||||
Sphere::new(
|
Sphere::new(
|
||||||
"moon".to_string(),
|
"moon".to_string(),
|
||||||
"Moon".to_string(),
|
"Moon".to_string(),
|
||||||
[0.25_f32, 0.25_f32, 0.25_f32],
|
[0.25_f32, 0.25_f32, 0.25_f32],
|
||||||
engine::sphere(0.0, 0.75, 0.0, 0.75)
|
engine::sphere(0.0, 0.75, 0.0, 0.75),
|
||||||
),
|
),
|
||||||
].into_iter().chain(
|
].into_iter().chain(
|
||||||
index_range.clone().zip(colors).map(
|
index_range.clone().zip(colors).map(
|
||||||
|
@ -828,7 +828,7 @@ fn load_irisawa_hexlet_assemb(assembly: &Assembly) {
|
||||||
format!("chain{k}"),
|
format!("chain{k}"),
|
||||||
format!("Chain {k}"),
|
format!("Chain {k}"),
|
||||||
color,
|
color,
|
||||||
engine::sphere(1.0 * ang.sin(), 0.0, 1.0 * ang.cos(), 0.5)
|
engine::sphere(1.0 * ang.sin(), 0.0, 1.0 * ang.cos(), 0.5),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -865,7 +865,7 @@ fn load_irisawa_hexlet_assemb(assembly: &Assembly) {
|
||||||
(outer.clone(), "1"),
|
(outer.clone(), "1"),
|
||||||
(sun.clone(), "-1"),
|
(sun.clone(), "-1"),
|
||||||
(moon.clone(), "-1"),
|
(moon.clone(), "-1"),
|
||||||
(chain_sphere_next.clone(), "-1")
|
(chain_sphere_next.clone(), "-1"),
|
||||||
] {
|
] {
|
||||||
let tangency = InversiveDistanceRegulator::new([chain_sphere.clone(), other_sphere]);
|
let tangency = InversiveDistanceRegulator::new([chain_sphere.clone(), other_sphere]);
|
||||||
tangency.set_point.set(SpecifiedValue::try_from(inversive_distance.to_string()).unwrap());
|
tangency.set_point.set(SpecifiedValue::try_from(inversive_distance.to_string()).unwrap());
|
||||||
|
@ -918,24 +918,24 @@ pub fn TestAssemblyChooser() -> View {
|
||||||
"off-center" => load_off_center_assemb(assembly),
|
"off-center" => load_off_center_assemb(assembly),
|
||||||
"radius-ratio" => load_radius_ratio_assemb(assembly),
|
"radius-ratio" => load_radius_ratio_assemb(assembly),
|
||||||
"irisawa-hexlet" => load_irisawa_hexlet_assemb(assembly),
|
"irisawa-hexlet" => load_irisawa_hexlet_assemb(assembly),
|
||||||
_ => ()
|
_ => (),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// build the chooser
|
// build the chooser
|
||||||
view! {
|
view! {
|
||||||
select(bind:value=assembly_name) {
|
select(bind:value = assembly_name) {
|
||||||
option(value="general") { "General" }
|
option(value = "general") { "General" }
|
||||||
option(value="low-curv") { "Low-curvature" }
|
option(value = "low-curv") { "Low-curvature" }
|
||||||
option(value="pointed") { "Pointed" }
|
option(value = "pointed") { "Pointed" }
|
||||||
option(value="tridim-icosahedron") { "Tridiminished icosahedron" }
|
option(value = "tridim-icosahedron") { "Tridiminished icosahedron" }
|
||||||
option(value="dodeca-packing") { "Dodecahedral packing" }
|
option(value = "dodeca-packing") { "Dodecahedral packing" }
|
||||||
option(value="balanced") { "Balanced" }
|
option(value = "balanced") { "Balanced" }
|
||||||
option(value="off-center") { "Off-center" }
|
option(value = "off-center") { "Off-center" }
|
||||||
option(value="radius-ratio") { "Radius ratio" }
|
option(value = "radius-ratio") { "Radius ratio" }
|
||||||
option(value="irisawa-hexlet") { "Irisawa hexlet" }
|
option(value = "irisawa-hexlet") { "Irisawa hexlet" }
|
||||||
option(value="empty") { "Empty" }
|
option(value = "empty") { "Empty" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -16,7 +16,7 @@ pub fn sphere(center_x: f64, center_y: f64, center_z: f64, radius: f64) -> DVect
|
||||||
center_y / radius,
|
center_y / radius,
|
||||||
center_z / radius,
|
center_z / radius,
|
||||||
0.5 / radius,
|
0.5 / radius,
|
||||||
0.5 * (center_norm_sq / radius - radius)
|
0.5 * (center_norm_sq / radius - radius),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ pub fn sphere_with_offset(dir_x: f64, dir_y: f64, dir_z: f64, off: f64, curv: f6
|
||||||
norm_sp * dir_y,
|
norm_sp * dir_y,
|
||||||
norm_sp * dir_z,
|
norm_sp * dir_z,
|
||||||
0.5 * curv,
|
0.5 * curv,
|
||||||
off * (1.0 + 0.5 * off * curv)
|
off * (1.0 + 0.5 * off * curv),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ pub fn project_point_to_normalized(rep: &mut DVector<f64>) {
|
||||||
|
|
||||||
pub struct MatrixEntry {
|
pub struct MatrixEntry {
|
||||||
index: (usize, usize),
|
index: (usize, usize),
|
||||||
value: f64
|
value: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PartialMatrix(Vec<MatrixEntry>);
|
pub struct PartialMatrix(Vec<MatrixEntry>);
|
||||||
|
@ -65,7 +65,7 @@ impl PartialMatrix {
|
||||||
|
|
||||||
pub fn push(&mut self, row: usize, col: usize, value: f64) {
|
pub fn push(&mut self, row: usize, col: usize, value: f64) {
|
||||||
let PartialMatrix(entries) = self;
|
let PartialMatrix(entries) = self;
|
||||||
entries.push(MatrixEntry { index: (row, col), value: value });
|
entries.push(MatrixEntry { index: (row, col), value });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_sym(&mut self, row: usize, col: usize, value: f64) {
|
pub fn push_sym(&mut self, row: usize, col: usize, value: f64) {
|
||||||
|
@ -135,22 +135,26 @@ impl<'a> IntoIterator for &'a PartialMatrix {
|
||||||
pub struct ConfigSubspace {
|
pub struct ConfigSubspace {
|
||||||
assembly_dim: usize,
|
assembly_dim: usize,
|
||||||
basis_std: Vec<DMatrix<f64>>,
|
basis_std: Vec<DMatrix<f64>>,
|
||||||
basis_proj: Vec<DMatrix<f64>>
|
basis_proj: Vec<DMatrix<f64>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConfigSubspace {
|
impl ConfigSubspace {
|
||||||
pub fn zero(assembly_dim: usize) -> ConfigSubspace {
|
pub fn zero(assembly_dim: usize) -> ConfigSubspace {
|
||||||
ConfigSubspace {
|
ConfigSubspace {
|
||||||
assembly_dim: assembly_dim,
|
assembly_dim,
|
||||||
basis_proj: Vec::new(),
|
basis_proj: Vec::new(),
|
||||||
basis_std: Vec::new()
|
basis_std: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// approximate the kernel of a symmetric endomorphism of the configuration
|
// approximate the kernel of a symmetric endomorphism of the configuration
|
||||||
// space for `assembly_dim` elements. we consider an eigenvector to be part
|
// space for `assembly_dim` elements. we consider an eigenvector to be part
|
||||||
// of the kernel if its eigenvalue is smaller than the constant `THRESHOLD`
|
// of the kernel if its eigenvalue is smaller than the constant `THRESHOLD`
|
||||||
fn symmetric_kernel(a: DMatrix<f64>, proj_to_std: DMatrix<f64>, assembly_dim: usize) -> ConfigSubspace {
|
fn symmetric_kernel(
|
||||||
|
a: DMatrix<f64>,
|
||||||
|
proj_to_std: DMatrix<f64>,
|
||||||
|
assembly_dim: usize,
|
||||||
|
) -> ConfigSubspace {
|
||||||
// find a basis for the kernel. the basis is expressed in the projection
|
// find a basis for the kernel. the basis is expressed in the projection
|
||||||
// coordinates, and it's orthonormal with respect to the projection
|
// coordinates, and it's orthonormal with respect to the projection
|
||||||
// inner product
|
// inner product
|
||||||
|
@ -170,7 +174,7 @@ impl ConfigSubspace {
|
||||||
const ELEMENT_DIM: usize = 5;
|
const ELEMENT_DIM: usize = 5;
|
||||||
const UNIFORM_DIM: usize = 4;
|
const UNIFORM_DIM: usize = 4;
|
||||||
ConfigSubspace {
|
ConfigSubspace {
|
||||||
assembly_dim: assembly_dim,
|
assembly_dim,
|
||||||
basis_std: basis_std.column_iter().map(
|
basis_std: basis_std.column_iter().map(
|
||||||
|v| Into::<DMatrix<f64>>::into(
|
|v| Into::<DMatrix<f64>>::into(
|
||||||
v.reshape_generic(Dyn(ELEMENT_DIM), Dyn(assembly_dim))
|
v.reshape_generic(Dyn(ELEMENT_DIM), Dyn(assembly_dim))
|
||||||
|
@ -180,7 +184,7 @@ impl ConfigSubspace {
|
||||||
|v| Into::<DMatrix<f64>>::into(
|
|v| Into::<DMatrix<f64>>::into(
|
||||||
v.reshape_generic(Dyn(UNIFORM_DIM), Dyn(assembly_dim))
|
v.reshape_generic(Dyn(UNIFORM_DIM), Dyn(assembly_dim))
|
||||||
)
|
)
|
||||||
).collect()
|
).collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,9 +218,9 @@ pub struct DescentHistory {
|
||||||
pub config: Vec<DMatrix<f64>>,
|
pub config: Vec<DMatrix<f64>>,
|
||||||
pub scaled_loss: Vec<f64>,
|
pub scaled_loss: Vec<f64>,
|
||||||
pub neg_grad: Vec<DMatrix<f64>>,
|
pub neg_grad: Vec<DMatrix<f64>>,
|
||||||
pub hess_eigvals: Vec::<DVector<f64>>,
|
pub hess_eigvals: Vec<DVector<f64>>,
|
||||||
pub base_step: Vec<DMatrix<f64>>,
|
pub base_step: Vec<DMatrix<f64>>,
|
||||||
pub backoff_steps: Vec<i32>
|
pub backoff_steps: Vec<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DescentHistory {
|
impl DescentHistory {
|
||||||
|
@ -246,7 +250,7 @@ impl ConstraintProblem {
|
||||||
ConstraintProblem {
|
ConstraintProblem {
|
||||||
gram: PartialMatrix::new(),
|
gram: PartialMatrix::new(),
|
||||||
frozen: PartialMatrix::new(),
|
frozen: PartialMatrix::new(),
|
||||||
guess: DMatrix::<f64>::zeros(ELEMENT_DIM, element_count)
|
guess: DMatrix::<f64>::zeros(ELEMENT_DIM, element_count),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,7 +259,7 @@ impl ConstraintProblem {
|
||||||
ConstraintProblem {
|
ConstraintProblem {
|
||||||
gram: PartialMatrix::new(),
|
gram: PartialMatrix::new(),
|
||||||
frozen: PartialMatrix::new(),
|
frozen: PartialMatrix::new(),
|
||||||
guess: DMatrix::from_columns(guess_columns)
|
guess: DMatrix::from_columns(guess_columns),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -269,25 +273,21 @@ lazy_static! {
|
||||||
0.0, 1.0, 0.0, 0.0, 0.0,
|
0.0, 1.0, 0.0, 0.0, 0.0,
|
||||||
0.0, 0.0, 1.0, 0.0, 0.0,
|
0.0, 0.0, 1.0, 0.0, 0.0,
|
||||||
0.0, 0.0, 0.0, 0.0, -2.0,
|
0.0, 0.0, 0.0, 0.0, -2.0,
|
||||||
0.0, 0.0, 0.0, -2.0, 0.0
|
0.0, 0.0, 0.0, -2.0, 0.0,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SearchState {
|
struct SearchState {
|
||||||
config: DMatrix<f64>,
|
config: DMatrix<f64>,
|
||||||
err_proj: DMatrix<f64>,
|
err_proj: DMatrix<f64>,
|
||||||
loss: f64
|
loss: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SearchState {
|
impl SearchState {
|
||||||
fn from_config(gram: &PartialMatrix, config: DMatrix<f64>) -> SearchState {
|
fn from_config(gram: &PartialMatrix, config: DMatrix<f64>) -> SearchState {
|
||||||
let err_proj = gram.sub_proj(&(config.tr_mul(&*Q) * &config));
|
let err_proj = gram.sub_proj(&(config.tr_mul(&*Q) * &config));
|
||||||
let loss = err_proj.norm_squared();
|
let loss = err_proj.norm_squared();
|
||||||
SearchState {
|
SearchState { config, err_proj, loss }
|
||||||
config: config,
|
|
||||||
err_proj: err_proj,
|
|
||||||
loss: loss
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,7 +314,7 @@ pub fn local_unif_to_std(v: DVectorView<f64>) -> DMatrix<f64> {
|
||||||
curv, 0.0, 0.0, 0.0, v[0],
|
curv, 0.0, 0.0, 0.0, v[0],
|
||||||
0.0, curv, 0.0, 0.0, v[1],
|
0.0, curv, 0.0, 0.0, v[1],
|
||||||
0.0, 0.0, curv, 0.0, v[2],
|
0.0, 0.0, curv, 0.0, v[2],
|
||||||
0.0, 0.0, 0.0, 0.0, 1.0
|
0.0, 0.0, 0.0, 0.0, 1.0,
|
||||||
])
|
])
|
||||||
} else {
|
} else {
|
||||||
// `v` represents a sphere. the normalization condition says that the
|
// `v` represents a sphere. the normalization condition says that the
|
||||||
|
@ -323,7 +323,7 @@ pub fn local_unif_to_std(v: DVectorView<f64>) -> DMatrix<f64> {
|
||||||
curv, 0.0, 0.0, 0.0, v[0],
|
curv, 0.0, 0.0, 0.0, v[0],
|
||||||
0.0, curv, 0.0, 0.0, v[1],
|
0.0, curv, 0.0, 0.0, v[1],
|
||||||
0.0, 0.0, curv, 0.0, v[2],
|
0.0, 0.0, curv, 0.0, v[2],
|
||||||
curv*v[0], curv*v[1], curv*v[2], curv*v[3], curv*v[4] + 1.0
|
curv*v[0], curv*v[1], curv*v[2], curv*v[3], curv*v[4] + 1.0,
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -336,7 +336,7 @@ fn seek_better_config(
|
||||||
base_target_improvement: f64,
|
base_target_improvement: f64,
|
||||||
min_efficiency: f64,
|
min_efficiency: f64,
|
||||||
backoff: f64,
|
backoff: f64,
|
||||||
max_backoff_steps: i32
|
max_backoff_steps: i32,
|
||||||
) -> Option<(SearchState, i32)> {
|
) -> Option<(SearchState, i32)> {
|
||||||
let mut rate = 1.0;
|
let mut rate = 1.0;
|
||||||
for backoff_steps in 0..max_backoff_steps {
|
for backoff_steps in 0..max_backoff_steps {
|
||||||
|
@ -354,12 +354,12 @@ fn seek_better_config(
|
||||||
// a first-order neighborhood of a configuration
|
// a first-order neighborhood of a configuration
|
||||||
pub struct ConfigNeighborhood {
|
pub struct ConfigNeighborhood {
|
||||||
pub config: DMatrix<f64>,
|
pub config: DMatrix<f64>,
|
||||||
pub nbhd: ConfigSubspace
|
pub nbhd: ConfigSubspace,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Realization {
|
pub struct Realization {
|
||||||
pub result: Result<ConfigNeighborhood, String>,
|
pub result: Result<ConfigNeighborhood, String>,
|
||||||
pub history: DescentHistory
|
pub history: DescentHistory,
|
||||||
}
|
}
|
||||||
|
|
||||||
// seek a matrix `config` that matches the partial matrix `problem.frozen` and
|
// seek a matrix `config` that matches the partial matrix `problem.frozen` and
|
||||||
|
@ -373,12 +373,10 @@ pub fn realize_gram(
|
||||||
backoff: f64,
|
backoff: f64,
|
||||||
reg_scale: f64,
|
reg_scale: f64,
|
||||||
max_descent_steps: i32,
|
max_descent_steps: i32,
|
||||||
max_backoff_steps: i32
|
max_backoff_steps: i32,
|
||||||
) -> Realization {
|
) -> Realization {
|
||||||
// destructure the problem data
|
// destructure the problem data
|
||||||
let ConstraintProblem {
|
let ConstraintProblem { gram, guess, frozen } = problem;
|
||||||
gram, guess, frozen
|
|
||||||
} = problem;
|
|
||||||
|
|
||||||
// start the descent history
|
// start the descent history
|
||||||
let mut history = DescentHistory::new();
|
let mut history = DescentHistory::new();
|
||||||
|
@ -391,10 +389,10 @@ pub fn realize_gram(
|
||||||
let result = Ok(
|
let result = Ok(
|
||||||
ConfigNeighborhood {
|
ConfigNeighborhood {
|
||||||
config: guess.clone(),
|
config: guess.clone(),
|
||||||
nbhd: ConfigSubspace::zero(0)
|
nbhd: ConfigSubspace::zero(0),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return Realization { result, history }
|
return Realization { result, history };
|
||||||
}
|
}
|
||||||
|
|
||||||
// find the dimension of the search space
|
// find the dimension of the search space
|
||||||
|
@ -475,8 +473,8 @@ pub fn realize_gram(
|
||||||
Some(cholesky) => cholesky,
|
Some(cholesky) => cholesky,
|
||||||
None => return Realization {
|
None => return Realization {
|
||||||
result: Err("Cholesky decomposition failed".to_string()),
|
result: Err("Cholesky decomposition failed".to_string()),
|
||||||
history
|
history,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
let base_step_stacked = hess_cholesky.solve(&neg_grad_stacked);
|
let base_step_stacked = hess_cholesky.solve(&neg_grad_stacked);
|
||||||
let base_step = base_step_stacked.reshape_generic(Dyn(element_dim), Dyn(assembly_dim));
|
let base_step = base_step_stacked.reshape_generic(Dyn(element_dim), Dyn(assembly_dim));
|
||||||
|
@ -485,16 +483,16 @@ pub fn realize_gram(
|
||||||
// use backtracking line search to find a better configuration
|
// use backtracking line search to find a better configuration
|
||||||
if let Some((better_state, backoff_steps)) = seek_better_config(
|
if let Some((better_state, backoff_steps)) = seek_better_config(
|
||||||
gram, &state, &base_step, neg_grad.dot(&base_step),
|
gram, &state, &base_step, neg_grad.dot(&base_step),
|
||||||
min_efficiency, backoff, max_backoff_steps
|
min_efficiency, backoff, max_backoff_steps,
|
||||||
) {
|
) {
|
||||||
state = better_state;
|
state = better_state;
|
||||||
history.backoff_steps.push(backoff_steps);
|
history.backoff_steps.push(backoff_steps);
|
||||||
} else {
|
} else {
|
||||||
return Realization {
|
return Realization {
|
||||||
result: Err("Line search failed".to_string()),
|
result: Err("Line search failed".to_string()),
|
||||||
history
|
history,
|
||||||
}
|
};
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
let result = if state.loss < tol {
|
let result = if state.loss < tol {
|
||||||
// express the uniform basis in the standard basis
|
// express the uniform basis in the standard basis
|
||||||
|
@ -539,7 +537,7 @@ pub mod examples {
|
||||||
[
|
[
|
||||||
sphere(0.0, 0.0, 0.0, 15.0),
|
sphere(0.0, 0.0, 0.0, 15.0),
|
||||||
sphere(0.0, 0.0, -9.0, 5.0),
|
sphere(0.0, 0.0, -9.0, 5.0),
|
||||||
sphere(0.0, 0.0, 11.0, 3.0)
|
sphere(0.0, 0.0, 11.0, 3.0),
|
||||||
].into_iter().chain(
|
].into_iter().chain(
|
||||||
(1..=6).map(
|
(1..=6).map(
|
||||||
|k| {
|
|k| {
|
||||||
|
@ -598,7 +596,7 @@ pub mod examples {
|
||||||
point(0.0, 0.0, 0.0),
|
point(0.0, 0.0, 0.0),
|
||||||
point(ang_hor.cos(), ang_hor.sin(), 0.0),
|
point(ang_hor.cos(), ang_hor.sin(), 0.0),
|
||||||
point(x_vert, y_vert, -0.5),
|
point(x_vert, y_vert, -0.5),
|
||||||
point(x_vert, y_vert, 0.5)
|
point(x_vert, y_vert, 0.5),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
).collect::<Vec<_>>().as_slice()
|
).collect::<Vec<_>>().as_slice()
|
||||||
|
@ -641,15 +639,15 @@ mod tests {
|
||||||
MatrixEntry { index: (0, 0), value: 14.0 },
|
MatrixEntry { index: (0, 0), value: 14.0 },
|
||||||
MatrixEntry { index: (0, 2), value: 28.0 },
|
MatrixEntry { index: (0, 2), value: 28.0 },
|
||||||
MatrixEntry { index: (1, 1), value: 42.0 },
|
MatrixEntry { index: (1, 1), value: 42.0 },
|
||||||
MatrixEntry { index: (1, 2), value: 49.0 }
|
MatrixEntry { index: (1, 2), value: 49.0 },
|
||||||
]);
|
]);
|
||||||
let config = DMatrix::<f64>::from_row_slice(2, 3, &[
|
let config = DMatrix::<f64>::from_row_slice(2, 3, &[
|
||||||
1.0, 2.0, 3.0,
|
1.0, 2.0, 3.0,
|
||||||
4.0, 5.0, 6.0
|
4.0, 5.0, 6.0,
|
||||||
]);
|
]);
|
||||||
let expected_result = DMatrix::<f64>::from_row_slice(2, 3, &[
|
let expected_result = DMatrix::<f64>::from_row_slice(2, 3, &[
|
||||||
14.0, 2.0, 28.0,
|
14.0, 2.0, 28.0,
|
||||||
4.0, 42.0, 49.0
|
4.0, 42.0, 49.0,
|
||||||
]);
|
]);
|
||||||
assert_eq!(frozen.freeze(&config), expected_result);
|
assert_eq!(frozen.freeze(&config), expected_result);
|
||||||
}
|
}
|
||||||
|
@ -660,15 +658,15 @@ mod tests {
|
||||||
MatrixEntry { index: (0, 0), value: 19.0 },
|
MatrixEntry { index: (0, 0), value: 19.0 },
|
||||||
MatrixEntry { index: (0, 2), value: 39.0 },
|
MatrixEntry { index: (0, 2), value: 39.0 },
|
||||||
MatrixEntry { index: (1, 1), value: 59.0 },
|
MatrixEntry { index: (1, 1), value: 59.0 },
|
||||||
MatrixEntry { index: (1, 2), value: 69.0 }
|
MatrixEntry { index: (1, 2), value: 69.0 },
|
||||||
]);
|
]);
|
||||||
let attempt = DMatrix::<f64>::from_row_slice(2, 3, &[
|
let attempt = DMatrix::<f64>::from_row_slice(2, 3, &[
|
||||||
1.0, 2.0, 3.0,
|
1.0, 2.0, 3.0,
|
||||||
4.0, 5.0, 6.0
|
4.0, 5.0, 6.0,
|
||||||
]);
|
]);
|
||||||
let expected_result = DMatrix::<f64>::from_row_slice(2, 3, &[
|
let expected_result = DMatrix::<f64>::from_row_slice(2, 3, &[
|
||||||
18.0, 0.0, 36.0,
|
18.0, 0.0, 36.0,
|
||||||
0.0, 54.0, 63.0
|
0.0, 54.0, 63.0,
|
||||||
]);
|
]);
|
||||||
assert_eq!(target.sub_proj(&attempt), expected_result);
|
assert_eq!(target.sub_proj(&attempt), expected_result);
|
||||||
}
|
}
|
||||||
|
@ -686,7 +684,7 @@ mod tests {
|
||||||
DMatrix::from_columns(&[
|
DMatrix::from_columns(&[
|
||||||
sphere(1.0, 0.0, 0.0, a),
|
sphere(1.0, 0.0, 0.0, a),
|
||||||
sphere(-0.5, a, 0.0, a),
|
sphere(-0.5, a, 0.0, a),
|
||||||
sphere(-0.5, -a, 0.0, a)
|
sphere(-0.5, -a, 0.0, a),
|
||||||
])
|
])
|
||||||
};
|
};
|
||||||
let state = SearchState::from_config(&gram, config);
|
let state = SearchState::from_config(&gram, config);
|
||||||
|
@ -700,7 +698,7 @@ mod tests {
|
||||||
fn frozen_entry_test() {
|
fn frozen_entry_test() {
|
||||||
let mut problem = ConstraintProblem::from_guess(&[
|
let mut problem = ConstraintProblem::from_guess(&[
|
||||||
point(0.0, 0.0, 2.0),
|
point(0.0, 0.0, 2.0),
|
||||||
sphere(0.0, 0.0, 0.0, 0.95)
|
sphere(0.0, 0.0, 0.0, 0.95),
|
||||||
]);
|
]);
|
||||||
for j in 0..2 {
|
for j in 0..2 {
|
||||||
for k in j..2 {
|
for k in j..2 {
|
||||||
|
@ -744,7 +742,7 @@ mod tests {
|
||||||
let mut problem = ConstraintProblem::from_guess(&[
|
let mut problem = ConstraintProblem::from_guess(&[
|
||||||
sphere(0.0, 0.0, 0.0, -2.0),
|
sphere(0.0, 0.0, 0.0, -2.0),
|
||||||
sphere(0.0, 0.0, 1.0, 1.0),
|
sphere(0.0, 0.0, 1.0, 1.0),
|
||||||
sphere(0.0, 0.0, -1.0, 1.0)
|
sphere(0.0, 0.0, -1.0, 1.0),
|
||||||
]);
|
]);
|
||||||
for j in 0..3 {
|
for j in 0..3 {
|
||||||
for k in j..3 {
|
for k in j..3 {
|
||||||
|
@ -774,8 +772,8 @@ mod tests {
|
||||||
DMatrix::<f64>::from_column_slice(UNIFORM_DIM, assembly_dim, &[
|
DMatrix::<f64>::from_column_slice(UNIFORM_DIM, assembly_dim, &[
|
||||||
0.0, 0.0, 0.0, 0.0,
|
0.0, 0.0, 0.0, 0.0,
|
||||||
0.0, 0.0, -0.5, -0.5,
|
0.0, 0.0, -0.5, -0.5,
|
||||||
0.0, 0.0, -0.5, 0.5
|
0.0, 0.0, -0.5, 0.5,
|
||||||
])
|
]),
|
||||||
];
|
];
|
||||||
let tangent_motions_std = vec![
|
let tangent_motions_std = vec![
|
||||||
basis_matrix((0, 1), element_dim, assembly_dim),
|
basis_matrix((0, 1), element_dim, assembly_dim),
|
||||||
|
@ -785,8 +783,8 @@ mod tests {
|
||||||
DMatrix::<f64>::from_column_slice(element_dim, assembly_dim, &[
|
DMatrix::<f64>::from_column_slice(element_dim, assembly_dim, &[
|
||||||
0.0, 0.0, 0.0, 0.00, 0.0,
|
0.0, 0.0, 0.0, 0.00, 0.0,
|
||||||
0.0, 0.0, -1.0, -0.25, -1.0,
|
0.0, 0.0, -1.0, -0.25, -1.0,
|
||||||
0.0, 0.0, -1.0, 0.25, 1.0
|
0.0, 0.0, -1.0, 0.25, 1.0,
|
||||||
])
|
]),
|
||||||
];
|
];
|
||||||
|
|
||||||
// confirm that the dimension of the tangent space is no greater than
|
// confirm that the dimension of the tangent space is no greater than
|
||||||
|
@ -862,10 +860,10 @@ mod tests {
|
||||||
DVector::from_column_slice(&[0.0, 0.0, 5.0, 0.0]),
|
DVector::from_column_slice(&[0.0, 0.0, 5.0, 0.0]),
|
||||||
DVector::from_column_slice(&[0.0, 0.0, 1.0, 0.0]),
|
DVector::from_column_slice(&[0.0, 0.0, 1.0, 0.0]),
|
||||||
DVector::from_column_slice(&[-vel_vert_x, -vel_vert_y, -3.0, 0.0]),
|
DVector::from_column_slice(&[-vel_vert_x, -vel_vert_y, -3.0, 0.0]),
|
||||||
DVector::from_column_slice(&[vel_vert_x, vel_vert_y, -3.0, 0.0])
|
DVector::from_column_slice(&[vel_vert_x, vel_vert_y, -3.0, 0.0]),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
).collect::<Vec<_>>()
|
).collect::<Vec<_>>(),
|
||||||
];
|
];
|
||||||
let tangent_motions_std = tangent_motions_unif.iter().map(
|
let tangent_motions_std = tangent_motions_unif.iter().map(
|
||||||
|motion| DMatrix::from_columns(
|
|motion| DMatrix::from_columns(
|
||||||
|
@ -898,7 +896,7 @@ mod tests {
|
||||||
0.0, 1.0, 0.0, 0.0, dis[1],
|
0.0, 1.0, 0.0, 0.0, dis[1],
|
||||||
0.0, 0.0, 1.0, 0.0, dis[2],
|
0.0, 0.0, 1.0, 0.0, dis[2],
|
||||||
2.0*dis[0], 2.0*dis[1], 2.0*dis[2], 1.0, dis.norm_squared(),
|
2.0*dis[0], 2.0*dis[1], 2.0*dis[2], 1.0, dis.norm_squared(),
|
||||||
0.0, 0.0, 0.0, 0.0, 1.0
|
0.0, 0.0, 0.0, 0.0, 1.0,
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -910,7 +908,7 @@ mod tests {
|
||||||
const SCALED_TOL: f64 = 1.0e-12;
|
const SCALED_TOL: f64 = 1.0e-12;
|
||||||
let mut problem_orig = ConstraintProblem::from_guess(&[
|
let mut problem_orig = ConstraintProblem::from_guess(&[
|
||||||
sphere(0.0, 0.0, 0.5, 1.0),
|
sphere(0.0, 0.0, 0.5, 1.0),
|
||||||
sphere(0.0, 0.0, -0.5, 1.0)
|
sphere(0.0, 0.0, -0.5, 1.0),
|
||||||
]);
|
]);
|
||||||
problem_orig.gram.push_sym(0, 0, 1.0);
|
problem_orig.gram.push_sym(0, 0, 1.0);
|
||||||
problem_orig.gram.push_sym(1, 1, 1.0);
|
problem_orig.gram.push_sym(1, 1, 1.0);
|
||||||
|
@ -928,13 +926,13 @@ mod tests {
|
||||||
let a = 0.5 * FRAC_1_SQRT_2;
|
let a = 0.5 * FRAC_1_SQRT_2;
|
||||||
DMatrix::from_columns(&[
|
DMatrix::from_columns(&[
|
||||||
sphere(a, 0.0, 7.0 + a, 1.0),
|
sphere(a, 0.0, 7.0 + a, 1.0),
|
||||||
sphere(-a, 0.0, 7.0 - a, 1.0)
|
sphere(-a, 0.0, 7.0 - a, 1.0),
|
||||||
])
|
])
|
||||||
};
|
};
|
||||||
let problem_tfm = ConstraintProblem {
|
let problem_tfm = ConstraintProblem {
|
||||||
gram: problem_orig.gram,
|
gram: problem_orig.gram,
|
||||||
|
frozen: problem_orig.frozen,
|
||||||
guess: guess_tfm,
|
guess: guess_tfm,
|
||||||
frozen: problem_orig.frozen
|
|
||||||
};
|
};
|
||||||
let Realization { result: result_tfm, history: history_tfm } = realize_gram(
|
let Realization { result: result_tfm, history: history_tfm } = realize_gram(
|
||||||
&problem_tfm, SCALED_TOL, 0.5, 0.9, 1.1, 200, 110
|
&problem_tfm, SCALED_TOL, 0.5, 0.9, 1.1, 200, 110
|
||||||
|
@ -962,7 +960,7 @@ mod tests {
|
||||||
0.0, 1.0, 0.0, 0.0, 0.0,
|
0.0, 1.0, 0.0, 0.0, 0.0,
|
||||||
FRAC_1_SQRT_2, 0.0, FRAC_1_SQRT_2, 0.0, 0.0,
|
FRAC_1_SQRT_2, 0.0, FRAC_1_SQRT_2, 0.0, 0.0,
|
||||||
0.0, 0.0, 0.0, 1.0, 0.0,
|
0.0, 0.0, 0.0, 1.0, 0.0,
|
||||||
0.0, 0.0, 0.0, 0.0, 1.0
|
0.0, 0.0, 0.0, 0.0, 1.0,
|
||||||
]);
|
]);
|
||||||
let transl = translation(Vector3::new(0.0, 0.0, 7.0));
|
let transl = translation(Vector3::new(0.0, 0.0, 7.0));
|
||||||
let motion_proj_tfm = transl * rot * motion_orig_proj;
|
let motion_proj_tfm = transl * rot * motion_orig_proj;
|
||||||
|
|
|
@ -14,20 +14,20 @@ use components::{
|
||||||
add_remove::AddRemove,
|
add_remove::AddRemove,
|
||||||
diagnostics::Diagnostics,
|
diagnostics::Diagnostics,
|
||||||
display::Display,
|
display::Display,
|
||||||
outline::Outline
|
outline::Outline,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct AppState {
|
struct AppState {
|
||||||
assembly: Assembly,
|
assembly: Assembly,
|
||||||
selection: Signal<BTreeSet<Rc<dyn Element>>>
|
selection: Signal<BTreeSet<Rc<dyn Element>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppState {
|
impl AppState {
|
||||||
fn new() -> AppState {
|
fn new() -> AppState {
|
||||||
AppState {
|
AppState {
|
||||||
assembly: Assembly::new(),
|
assembly: Assembly::new(),
|
||||||
selection: create_signal(BTreeSet::default())
|
selection: create_signal(BTreeSet::default()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ fn main() {
|
||||||
provide_context(AppState::new());
|
provide_context(AppState::new());
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
div(id="sidebar") {
|
div(id = "sidebar") {
|
||||||
AddRemove {}
|
AddRemove {}
|
||||||
Outline {}
|
Outline {}
|
||||||
Diagnostics {}
|
Diagnostics {}
|
||||||
|
|
|
@ -13,7 +13,7 @@ use std::num::ParseFloatError;
|
||||||
#[readonly::make]
|
#[readonly::make]
|
||||||
pub struct SpecifiedValue {
|
pub struct SpecifiedValue {
|
||||||
pub spec: String,
|
pub spec: String,
|
||||||
pub value: Option<f64>
|
pub value: Option<f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SpecifiedValue {
|
impl SpecifiedValue {
|
||||||
|
@ -37,7 +37,7 @@ impl TryFrom<String> for SpecifiedValue {
|
||||||
Ok(SpecifiedValue::from_empty_spec())
|
Ok(SpecifiedValue::from_empty_spec())
|
||||||
} else {
|
} else {
|
||||||
spec.parse::<f64>().map(
|
spec.parse::<f64>().map(
|
||||||
|value| SpecifiedValue { spec: spec, value: Some(value) }
|
|value| SpecifiedValue { spec, value: Some(value) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue