feat: Point coordinate regulators #118
|
@ -31,14 +31,11 @@ The latest prototype is in the folder `app-proto`. It includes both a user inter
|
||||||
3. Call `rustup target add wasm32-unknown-unknown` to add the [most generic 32-bit WebAssembly target](https://doc.rust-lang.org/nightly/rustc/platform-support/wasm32-unknown-unknown.html)
|
3. Call `rustup target add wasm32-unknown-unknown` to add the [most generic 32-bit WebAssembly target](https://doc.rust-lang.org/nightly/rustc/platform-support/wasm32-unknown-unknown.html)
|
||||||
4. Call `cargo install wasm-pack` to install the [WebAssembly toolchain](https://rustwasm.github.io/docs/wasm-pack/)
|
4. Call `cargo install wasm-pack` to install the [WebAssembly toolchain](https://rustwasm.github.io/docs/wasm-pack/)
|
||||||
5. Call `cargo install trunk` to install the [Trunk](https://trunkrs.dev/) web-build tool
|
5. Call `cargo install trunk` to install the [Trunk](https://trunkrs.dev/) web-build tool
|
||||||
- In the future, `trunk` can be updated with the same command. You may
|
- In the future, `trunk` can be updated with the same command. You may need the `--locked` flag if your ambient version of `rustc` does not match that required by `trunk`.
|
||||||
|
|||||||
need the `--locked` flag if your ambient version of `rustc` does not
|
|
||||||
match that required by `trunk`.
|
|
||||||
6. Add the `.cargo/bin` folder in your home directory to your executable search path
|
6. Add the `.cargo/bin` folder in your home directory to your executable search path
|
||||||
- This lets you call Trunk, and other tools installed by Cargo, without specifying their paths
|
- This lets you call Trunk, and other tools installed by Cargo, without specifying their paths
|
||||||
Vectornaut marked this conversation as resolved
Outdated
Vectornaut
commented
The information here looks accurate to me, although I've never installed a global tool with the The existing style for this file does not use manual line-wrapping. I'd prefer to keep the new text consistent with that style by putting it all on one line. The information here looks accurate to me, although I've never installed a global tool with the `--locked` flag, and I don't know whether it's recommended.
The existing style for this file does not use manual line-wrapping. I'd prefer to keep the new text consistent with that style by putting it all on one line.
glen
commented
Ok, I will go ahead and remove the newlines in the additions to this file, but i will say that trying to impose formatting rules like this on markdown files feels rather contradictory to the spirit/genesis of markdown: it's an explicit reaction to various markup languages to be more free-form and lightweight. Ok, I will go ahead and remove the newlines in the additions to this file, but i will say that trying to impose formatting rules like this on markdown files feels rather contradictory to the spirit/genesis of markdown: it's an explicit reaction to various markup languages to be more free-form and lightweight.
glen
commented
`--locked` is in fact now part of the installation command that trunk itself recommends, so i feel pretty safe recommending it here.
|
|||||||
- On POSIX systems, the search path is stored in the `PATH` environment variable
|
- On POSIX systems, the search path is stored in the `PATH` environment variable
|
||||||
- Alternatively, if you don't want to adjust your `PATH`, you can install
|
- Alternatively, if you don't want to adjust your `PATH`, you can install `trunk` in another directory `DIR` via `cargo install --root DIR trunk`
|
||||||
`trunk` in another directory `DIR` via `cargo install --root DIR trunk`
|
|
||||||
|
|
||||||
### Play with the prototype
|
### Play with the prototype
|
||||||
|
|
||||||
Vectornaut
commented
I'll trust your experience with installing Cargo tools at custom locations, since I've never tried it! The request above about manual line-wrapping also applies here. I'll trust your experience with installing Cargo tools at custom locations, since I've never tried it!
The [request](https://code.studioinfinity.org/StudioInfinity/dyna3/pulls/118#issuecomment-3346) above about manual line-wrapping also applies here.
|
|||||||
|
|
|
@ -86,6 +86,14 @@ impl Ord for dyn Serial {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Small helper function to generate consistent errors when there
|
||||||
|
// are indexing issues in a ProblemPoser
|
||||||
|
fn indexing_error(item: &str, name: &str, actor: &str) -> String {
|
||||||
|
format!(
|
||||||
|
"{item} \"{name}\" must be indexed before {actor} writes problem data"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub trait ProblemPoser {
|
pub trait ProblemPoser {
|
||||||
fn pose(&self, problem: &mut ConstraintProblem);
|
fn pose(&self, problem: &mut ConstraintProblem);
|
||||||
}
|
}
|
||||||
|
@ -248,19 +256,12 @@ impl Serial for Sphere {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn index_message(thing: &str, name: &str, actor: &str) -> String {
|
|
||||||
format!(
|
|
||||||
"{thing} \"{name}\" must be indexed before {actor} writes problem data"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ProblemPoser for Sphere {
|
impl ProblemPoser for Sphere {
|
||||||
fn pose(&self, problem: &mut ConstraintProblem) {
|
fn pose(&self, problem: &mut ConstraintProblem) {
|
||||||
let index = self.column_index().expect(
|
let index = self.column_index().expect(
|
||||||
index_message("Sphere", &self.id, "it").as_str());
|
indexing_error("Sphere", &self.id, "it").as_str());
|
||||||
problem.gram.push_sym(index, index, 1.0);
|
problem.gram.push_sym(index, index, 1.0);
|
||||||
problem.guess.set_column(
|
problem.guess.set_column(index, &self.representation.get_clone_untracked());
|
||||||
index, &self.representation.get_clone_untracked());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,11 +364,10 @@ impl Serial for Point {
|
||||||
impl ProblemPoser for Point {
|
impl ProblemPoser for Point {
|
||||||
fn pose(&self, problem: &mut ConstraintProblem) {
|
fn pose(&self, problem: &mut ConstraintProblem) {
|
||||||
let index = self.column_index().expect(
|
let index = self.column_index().expect(
|
||||||
index_message("Point", &self.id, "it").as_str());
|
indexing_error("Point", &self.id, "it").as_str());
|
||||||
problem.gram.push_sym(index, index, 0.0);
|
problem.gram.push_sym(index, index, 0.0);
|
||||||
problem.frozen.push(Self::WEIGHT_COMPONENT, index, 0.5);
|
problem.frozen.push(Self::WEIGHT_COMPONENT, index, 0.5);
|
||||||
problem.guess.set_column(
|
problem.guess.set_column(index, &self.representation.get_clone_untracked());
|
||||||
index, &self.representation.get_clone_untracked());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -412,8 +412,7 @@ pub struct InversiveDistanceRegulator {
|
||||||
|
|
||||||
impl InversiveDistanceRegulator {
|
impl InversiveDistanceRegulator {
|
||||||
pub fn new(subjects: [Rc<dyn Element>; 2]) -> Self {
|
pub fn new(subjects: [Rc<dyn Element>; 2]) -> Self {
|
||||||
let representations = subjects.each_ref().map(
|
let representations = subjects.each_ref().map(|subj| subj.representation());
|
||||||
|subj| subj.representation());
|
|
||||||
let measurement = create_memo(move || {
|
let measurement = create_memo(move || {
|
||||||
representations[0].with(|rep_0|
|
representations[0].with(|rep_0|
|
||||||
representations[1].with(|rep_1|
|
representations[1].with(|rep_1|
|
||||||
|
@ -455,7 +454,7 @@ impl ProblemPoser for InversiveDistanceRegulator {
|
||||||
if let Some(val) = set_pt.value {
|
if let Some(val) = set_pt.value {
|
||||||
let [row, col] = self.subjects.each_ref().map(
|
let [row, col] = self.subjects.each_ref().map(
|
||||||
|subj| subj.column_index().expect(
|
|subj| subj.column_index().expect(
|
||||||
index_message("Subject", subj.id(),
|
indexing_error("Subject", subj.id(),
|
||||||
"inversive distance regulator").as_str())
|
"inversive distance regulator").as_str())
|
||||||
);
|
);
|
||||||
problem.gram.push_sym(row, col, val);
|
problem.gram.push_sym(row, col, val);
|
||||||
|
@ -509,7 +508,7 @@ impl ProblemPoser for HalfCurvatureRegulator {
|
||||||
self.set_point.with_untracked(|set_pt| {
|
self.set_point.with_untracked(|set_pt| {
|
||||||
if let Some(val) = set_pt.value {
|
if let Some(val) = set_pt.value {
|
||||||
let col = self.subject.column_index().expect(
|
let col = self.subject.column_index().expect(
|
||||||
index_message("Subject", &self.subject.id,
|
indexing_error("Subject", &self.subject.id,
|
||||||
"half-curvature regulator").as_str());
|
"half-curvature regulator").as_str());
|
||||||
problem.frozen.push(Sphere::CURVATURE_COMPONENT, col, val);
|
problem.frozen.push(Sphere::CURVATURE_COMPONENT, col, val);
|
||||||
}
|
}
|
||||||
|
@ -546,9 +545,7 @@ impl PointCoordinateRegulator {
|
||||||
move |rep| rep[axis as usize]
|
move |rep| rep[axis as usize]
|
||||||
);
|
);
|
||||||
let set_point = create_signal(SpecifiedValue::from_empty_spec());
|
let set_point = create_signal(SpecifiedValue::from_empty_spec());
|
||||||
Self {
|
Self { subject, axis, measurement, set_point, serial: Self::next_serial() }
|
||||||
subject, axis, measurement, set_point, serial: Self::next_serial()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -567,7 +564,7 @@ impl ProblemPoser for PointCoordinateRegulator {
|
||||||
self.set_point.with_untracked(|set_pt| {
|
self.set_point.with_untracked(|set_pt| {
|
||||||
Vectornaut marked this conversation as resolved
Outdated
Vectornaut
commented
I've been wrapping comments at 80 characters throughout the code. Under that convention, this comment would need to be reflowed. I prefer to use comments only at the beginnings of a code sections (which are separated by blank lines). To me, the stuff after this comment does feel like a distinct section, so I'd add a blank line before the comment. I think the comment could be made a little clearer and more terse, although I won't insist on it. Here's a wording I like.
(I've also been writing comments in lower case except for stuff like proper nouns and acronyms, but that seems more controversial, so I won't fuss about it in this pull request.) I've been wrapping comments at 80 characters throughout the code. Under that convention, this comment would need to be reflowed.
I prefer to use comments only at the beginnings of a code sections (which are separated by blank lines). To me, the stuff after this comment does feel like a distinct section, so I'd add a blank line before the comment.
I think the comment could be made a little clearer and more terse, although I won't insist on it. Here's a wording I like.
```
// if all three of the subject's spatial coordinates have been
// frozen, then freeze its norm component too
```
(I've also been writing comments in lower case except for stuff like proper nouns and acronyms, but that seems more controversial, so I won't fuss about it in this pull request.)
glen
commented
I will adhere to the 80-character line limit (which I am a strong supporter of), which I inadvertently violated. I will reword the comment as suggested. I feel the comment breaks up the code sufficiently, meaning no need for a blank line. I will adhere to the 80-character line limit (which I am a strong supporter of), which I inadvertently violated. I will reword the comment as suggested. I feel the comment breaks up the code sufficiently, meaning no need for a blank line.
glen
commented
Actually there are many 80-character line violations; again, I didn't realize. I will fix the ones in this source file, and we can fix other source files as we edit them, I guess, or do a PR for them. Actually there are many 80-character line violations; again, I didn't realize. I will fix the ones in this source file, and we can fix other source files as we edit them, I guess, or do a PR for them.
Vectornaut
commented
Thanks for reflowing and rewording the comment!
I'd rather do this in a separate pull request. Reflowing code that this pull request adds or rewrites is okay with me, but I have a slight preference for also keeping that code consistent with the existing style. The other reflows in commit Thanks for reflowing and rewording the comment!
> Actually there are many 80-character line violations; again, I didn't realize. I will fix the ones in this source file, and we can fix other source files as we edit them, I guess, or do a PR for them.
I'd rather do this in a separate pull request. Reflowing code that this pull request adds or rewrites is okay with me, but I have a slight preference for also keeping that code consistent with the existing style.
The other reflows in commit c0e6ebf affect code lines, rather than comment lines. I've been less strict about wrapping code to 80 characters, because sometimes I think the value of keeping a line together outweighs the cost of going slightly over 80 characters. I'd be fine with switching to a more consistent convention, like the [line width](https://doc.rust-lang.org/beta/style-guide/index.html#indentation-and-line-width) and [comment width](https://doc.rust-lang.org/beta/style-guide/index.html#comments) rules from the Rust style guide, but I think we should discuss what rule we want to adopt and then implement it in its own pull request.
glen
commented
I am super confused. I cannot understand a different line length limit for comments and code; comments are code. (The point of code is to communicate what a program does, bith to humans and compilers. Comments are an integral part of that.) Also the point of line length limits is to manage the horizontal width of the code display (so the reason I like 80 is that my display devices are all right around 160-170 characters wide at comfortable font sizes, and it is at times very useful to display two source files side by side). Again it doesn't make sense to have different limits for code and comments. I only messed with this because you pointed out a violation of our 80-character limit. So naturally when I saw there were many others, I fixed them. I can revert all these changes, and do a PR after the whitespace one fixing all the 80-character violations in the whole code base. Ok? I am super confused. I cannot understand a different line length limit for comments and code; comments are code. (The point of code is to communicate what a program does, bith to humans and compilers. Comments are an integral part of that.) Also the point of line length limits is to manage the horizontal width of the code display (so the reason I like 80 is that my display devices are all right around 160-170 characters wide at comfortable font sizes, and it is at times very useful to display two source files side by side). Again it doesn't make sense to have different limits for code and comments. I only messed with this because you pointed out a violation of our 80-character limit. So naturally when I saw there were many others, I fixed them. I can revert all these changes, and do a PR after the whitespace one fixing all the 80-character violations in the whole code base. Ok?
Vectornaut
commented
Making a later pull request to impose a consistent line width limit for both comments and code is okay with me. Maybe you can decide what limit you prefer while preparing that pull request? From my experience so far, I can see why the style guide authors chose 100 characters: wrapping strictly at 80 characters expands the code vertically quite a bit. > I can revert all these changes, and do a PR after the whitespace one fixing all the 80-character violations in the whole code base. Ok?
Making a later pull request to impose a consistent line width limit for both comments and code is okay with me. Maybe you can decide what limit you prefer while preparing that pull request? From my experience so far, I can see why the style guide authors chose 100 characters: wrapping strictly at 80 characters expands the code vertically quite a bit.
glen
commented
The point of line length convention is to keep the code fitting horizontally in some amount of space. For me the salient amount of space is "narrow enough to fit two full lines side-by-side" which happens to work out to the old-school-standard 80 characters, more or less by coincidence. So I'd like to just stick with 80, thanks. As for the resulting vertical expansion, well, right now we have a lot of line noise expanding things vertically. A very large fraction of our lines contain just 0-3 characters. I am looking forward to cleaning that up with Husht. I also find that if one is not too rigid about where one must or must not break lines, vertical expansion isn't too bad. In the meantime, I would be perfectly happy to do either or both of the following two things, but they might each be a bridge too far for you at the moment:
The point of line length convention is to keep the code fitting horizontally in some amount of space. For me the salient amount of space is "narrow enough to fit two full lines side-by-side" which happens to work out to the old-school-standard 80 characters, more or less by coincidence. So I'd like to just stick with 80, thanks.
As for the resulting vertical expansion, well, right now we have a lot of line noise expanding things vertically. A very large fraction of our lines contain just 0-3 characters. I am looking forward to cleaning that up with Husht. I also find that if one is not too rigid about where one must or must not break lines, vertical expansion isn't too bad. In the meantime, I would be perfectly happy to do either or both of the following two things, but they might each be a bridge too far for you at the moment:
* switch to a 3-character standard indent. I personally find this the best compromise between visual salience, and not forcing nested code too far to the right so that it needs to break a lot.
* switch to putting all closing punctuation at the end of the line that it closes, rather than skipping a line for it. After all (and this is one of the main motivations for Husht), all that closing punctuation is redundant with the indenting. E.g.
```
fn myfn(arg: Type) {
if condition {
take_action(arg, other, long,
arguments, in, list)}}
fn my otherfn() -> ReturnType {
...
```
Vectornaut
commented
Sounds good!
Each of those changes would bother me more than seeing more vertical expansion, so I'd rather hold off for now. > So I'd like to just stick with 80, thanks.
Sounds good!
> In the meantime, I would be perfectly happy to do either or both of the following two things, but they might each be a bridge too far for you at the moment
Each of those changes would bother me more than seeing more vertical expansion, so I'd rather hold off for now.
|
|||||||
if let Some(val) = set_pt.value {
|
if let Some(val) = set_pt.value {
|
||||||
let col = self.subject.column_index().expect(
|
let col = self.subject.column_index().expect(
|
||||||
index_message("Subject", &self.subject.id,
|
indexing_error("Subject", &self.subject.id,
|
||||||
"point-coordinate regulator").as_str());
|
"point-coordinate regulator").as_str());
|
||||||
problem.frozen.push(self.axis as usize, col, val);
|
problem.frozen.push(self.axis as usize, col, val);
|
||||||
// If all three of the subject's spatial coordinates have been
|
// If all three of the subject's spatial coordinates have been
|
||||||
|
@ -583,9 +580,7 @@ impl ProblemPoser for PointCoordinateRegulator {
|
||||||
if nset == Axis::CARDINALITY {
|
if nset == Axis::CARDINALITY {
|
||||||
let [x, y, z] = coords;
|
let [x, y, z] = coords;
|
||||||
problem.frozen.push(
|
problem.frozen.push(
|
||||||
Point::NORM_COMPONENT,
|
Point::NORM_COMPONENT, col, point(x,y,z)[Point::NORM_COMPONENT]);
|
||||||
col,
|
|
||||||
point(x,y,z)[Point::NORM_COMPONENT]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -684,8 +679,7 @@ impl Assembly {
|
||||||
let id = elt.id().clone();
|
let id = elt.id().clone();
|
||||||
let elt_rc = Rc::new(elt);
|
let elt_rc = Rc::new(elt);
|
||||||
self.elements.update(|elts| elts.insert(elt_rc.clone()));
|
self.elements.update(|elts| elts.insert(elt_rc.clone()));
|
||||||
self.elements_by_id.update(
|
self.elements_by_id.update(|elts_by_id| elts_by_id.insert(id, elt_rc.clone()));
|
||||||
|elts_by_id| elts_by_id.insert(id, elt_rc.clone()));
|
|
||||||
|
|
||||||
// create and insert the element's default regulators
|
// create and insert the element's default regulators
|
||||||
for reg in elt_rc.default_regulators() {
|
for reg in elt_rc.default_regulators() {
|
||||||
|
@ -694,9 +688,7 @@ impl Assembly {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_insert_element(&self, elt: impl Element + 'static) -> bool {
|
pub fn try_insert_element(&self, elt: impl Element + 'static) -> bool {
|
||||||
let can_insert = self.elements_by_id.with_untracked(
|
let can_insert = self.elements_by_id.with_untracked(|elts_by_id| !elts_by_id.contains_key(elt.id()));
|
||||||
Vectornaut
commented
Flagging this as a potential mistake because it adds a new change to the pull request, rather than reverting one of the changes in commit Flagging this as a potential mistake because it adds a new change to the pull request, rather than reverting one of the changes in commit c0e6ebf, and I don't see an obvious reason for this pull request to touch it. Could you confirm that this change was deliberate if it was, and revert it if it wasn't?
glen
commented
Oh, when I was undoing, there was some exactly analogous line that was the other way, so it was easy just to falsely revert this. I will fix the mistaken non-reversion. Oh, when I was undoing, there was some exactly analogous line that was the other way, so it was easy just to falsely revert this. I will fix the mistaken non-reversion.
|
|||||||
|elts_by_id| !elts_by_id.contains_key(elt.id())
|
|
||||||
);
|
|
||||||
if can_insert {
|
if can_insert {
|
||||||
self.insert_element_unchecked(elt);
|
self.insert_element_unchecked(elt);
|
||||||
}
|
}
|
||||||
|
@ -761,8 +753,7 @@ impl Assembly {
|
||||||
pub fn load_config(&self, config: &DMatrix<f64>) {
|
pub fn load_config(&self, config: &DMatrix<f64>) {
|
||||||
for elt in self.elements.get_clone_untracked() {
|
for elt in self.elements.get_clone_untracked() {
|
||||||
elt.representation().update(
|
elt.representation().update(
|
||||||
|rep| rep.set_column(
|
|rep| rep.set_column(0, &config.column(elt.column_index().unwrap()))
|
||||||
0, &config.column(elt.column_index().unwrap()))
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -907,8 +898,7 @@ impl Assembly {
|
||||||
if column_index < realized_dim {
|
if column_index < realized_dim {
|
||||||
// this element had a column index when we started, so by
|
// this element had a column index when we started, so by
|
||||||
// invariant (1), it's reflected in the tangent space
|
// invariant (1), it's reflected in the tangent space
|
||||||
let mut target_columns =
|
let mut target_columns = motion_proj.columns_mut(0, realized_dim);
|
||||||
motion_proj.columns_mut(0, realized_dim);
|
|
||||||
target_columns += self.tangent.with(
|
target_columns += self.tangent.with(
|
||||||
|tan| tan.proj(&elt_motion.velocity, column_index)
|
|tan| tan.proj(&elt_motion.velocity, column_index)
|
||||||
);
|
);
|
||||||
|
@ -916,10 +906,9 @@ impl Assembly {
|
||||||
// this element didn't have a column index when we started, so
|
// this element didn't have a column index when we started, so
|
||||||
// by invariant (2), it's unconstrained
|
// by invariant (2), it's unconstrained
|
||||||
let mut target_column = motion_proj.column_mut(column_index);
|
let mut target_column = motion_proj.column_mut(column_index);
|
||||||
let unif_to_std = elt_motion
|
let unif_to_std = elt_motion.element.representation().with_untracked(
|
||||||
.element.representation()
|
|rep| local_unif_to_std(rep.as_view())
|
||||||
.with_untracked(
|
);
|
||||||
|rep| local_unif_to_std(rep.as_view()));
|
|
||||||
target_column += unif_to_std * elt_motion.velocity;
|
target_column += unif_to_std * elt_motion.velocity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -936,9 +925,7 @@ impl Assembly {
|
||||||
elt.project_to_normalized(rep);
|
elt.project_to_normalized(rep);
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
console_log!(
|
console_log!("No velocity to unpack for fresh element \"{}\"", elt.id())
|
||||||
"No velocity to unpack for fresh element \"{}\"",
|
|
||||||
elt.id())
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -973,15 +960,13 @@ inversive distance regulator writes problem data")]
|
||||||
fn unindexed_subject_test_inversive_distance() {
|
fn unindexed_subject_test_inversive_distance() {
|
||||||
let _ = create_root(|| {
|
let _ = create_root(|| {
|
||||||
Vectornaut marked this conversation as resolved
Vectornaut
commented
When I originally wrote this test, it bothered me that the identifiers When I originally wrote this test, it bothered me that the identifiers `sphere0` and `sphere1` were assigned but never tested. The new, more informative indexing error message makes them part of the test, which is very satisfying.
|
|||||||
let subjects = [0, 1].map(
|
let subjects = [0, 1].map(
|
||||||
|k| Rc::new(Sphere::default(
|
|k| Rc::new(Sphere::default(format!("sphere{k}"), k)) as Rc<dyn Element>
|
||||||
format!("sphere{k}"), k)) as Rc<dyn Element>
|
|
||||||
);
|
);
|
||||||
subjects[0].set_column_index(0);
|
subjects[0].set_column_index(0);
|
||||||
InversiveDistanceRegulator {
|
InversiveDistanceRegulator {
|
||||||
subjects: subjects,
|
subjects: subjects,
|
||||||
measurement: create_memo(|| 0.0),
|
measurement: create_memo(|| 0.0),
|
||||||
set_point: create_signal(
|
set_point: create_signal(SpecifiedValue::try_from("0.0".to_string()).unwrap()),
|
||||||
SpecifiedValue::try_from("0.0".to_string()).unwrap()),
|
|
||||||
serial: InversiveDistanceRegulator::next_serial()
|
serial: InversiveDistanceRegulator::next_serial()
|
||||||
}.pose(&mut ConstraintProblem::new(2));
|
}.pose(&mut ConstraintProblem::new(2));
|
||||||
});
|
});
|
||||||
|
@ -1010,10 +995,8 @@ inversive distance regulator writes problem data")]
|
||||||
// nudge the sphere repeatedly along the `z` axis
|
// nudge the sphere repeatedly along the `z` axis
|
||||||
const STEP_SIZE: f64 = 0.0025;
|
const STEP_SIZE: f64 = 0.0025;
|
||||||
const STEP_CNT: usize = 400;
|
const STEP_CNT: usize = 400;
|
||||||
let sphere = assembly.elements_by_id.with(
|
let sphere = assembly.elements_by_id.with(|elts_by_id| elts_by_id[sphere_id].clone());
|
||||||
|elts_by_id| elts_by_id[sphere_id].clone());
|
let velocity = DVector::from_column_slice(&[0.0, 0.0, STEP_SIZE, 0.0]);
|
||||||
let velocity =
|
|
||||||
DVector::from_column_slice(&[0.0, 0.0, STEP_SIZE, 0.0]);
|
|
||||||
for _ in 0..STEP_CNT {
|
for _ in 0..STEP_CNT {
|
||||||
assembly.deform(
|
assembly.deform(
|
||||||
vec![
|
vec![
|
||||||
|
@ -1031,8 +1014,7 @@ inversive distance regulator writes problem data")]
|
||||||
let final_half_curv = sphere.representation().with_untracked(
|
let final_half_curv = sphere.representation().with_untracked(
|
||||||
|rep| rep[Sphere::CURVATURE_COMPONENT]
|
|rep| rep[Sphere::CURVATURE_COMPONENT]
|
||||||
);
|
);
|
||||||
assert!((final_half_curv / INITIAL_HALF_CURV - 1.0).abs()
|
assert!((final_half_curv / INITIAL_HALF_CURV - 1.0).abs() < DRIFT_TOL);
|
||||||
< DRIFT_TOL);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Very minor: the rest of the list is formatted as one sentence per list item, with no final period. It would be nice to keep that consistent.
OK, I have properly punctuated the whole file, so that complete sentences have periods, and fragments do not.