diff --git a/app-proto/src/assembly.rs b/app-proto/src/assembly.rs index ec480ac..fa0a48c 100644 --- a/app-proto/src/assembly.rs +++ b/app-proto/src/assembly.rs @@ -33,8 +33,8 @@ pub struct Element { pub serial: u64, // the configuration matrix column index that was assigned to this element - // last time the assembly was realized, or `None` if the assembly has never - // been realized with this element in it + // last time the assembly was realized, or `None` if the element has never + // been through a realization column_index: Option } @@ -160,13 +160,6 @@ impl Assembly { let id = elt.id.clone(); let key = self.elements.update(|elts| elts.insert(elt)); self.elements_by_id.update(|elts_by_id| elts_by_id.insert(id, key)); - - // realize to update the tangent space - /* KLUDGE */ - // since the newly inserted element is unconstrained, we should be able - // to update the tangent space without recomputing the Hessian and its - // eigendecomposition - self.realize(); } pub fn try_insert_element(&self, elt: Element) -> bool { @@ -300,35 +293,43 @@ impl Assembly { pub fn deform(&self, motion: AssemblyMotion) { /* KLUDGE */ - // when the tangent space is zero, we currently need to avoid calling - // its `proj` method, because it will panic rather than returning zero. - // in the future, we'll want a more intentionally designed system for - // handling this case - if self.tangent.with(|tan| tan.dim() <= 0) { + // when the tangent space is zero, deformation won't do anything, but + // the attempt to deform should be registered in the UI. this console + // message will do for now + if self.tangent.with(|tan| tan.dim() <= 0 && tan.assembly_dim() > 0) { console::log_1(&JsValue::from("The assembly is rigid")); - return; } const ELEMENT_DIM: usize = 5; - let assembly_dim = self.tangent.with(|tan| tan.assembly_dim()); + let assembly_dim = self.elements.with(|elts| elts.len()); let mut motion_proj = DMatrix::zeros(ELEMENT_DIM, assembly_dim); + let tan_assembly_dim = self.tangent.with(|tan| tan.assembly_dim()); // project the element motions onto the tangent space of the solution // variety, and sum them to get a deformation of the whole assembly + let mut next_column_index = tan_assembly_dim; for elt_motion in motion { match self.elements.with_untracked(|elts| elts[elt_motion.key].column_index) { Some(column_index) => { - motion_proj += self.tangent.with( + let mut target_columns = motion_proj.columns_mut(0, tan_assembly_dim); + target_columns += self.tangent.with( |tan| tan.proj(&elt_motion.velocity, column_index) ) }, None => { - console::log_1(&JsValue::from( - format!( - "Ignoring motion of fresh element \"{}\"", - self.elements.with_untracked(|elts| elts[elt_motion.key].id.clone()) - ) - )) + // give the element a column index, even though it's never + // been through a realization, and add its motion to that + // column of the projected motion. this puts the element + // column indices out of sync with the saved tangent space, + // but that's okay: the realization we do to get back onto + // the solution variety will re-index the elements and + // recompute the tangent space + let mut target_column = motion_proj.column_mut(next_column_index); + target_column += elt_motion.velocity; + self.elements.update_silent( + |elts| elts[elt_motion.key].column_index = Some(next_column_index) + ); + next_column_index += 1; } } } @@ -355,7 +356,9 @@ impl Assembly { }); } - // bring the configuration back onto the solution variety + // bring the configuration back onto the solution variety. this also + // gets the elements' column indices and the saved tangent space back in + // sync self.realize(); } } \ No newline at end of file