Motion analysis review round 2: a number names a study by id first, the dialog analyses the study it made on the scratch copy, duration 0.001 s or more, volumes by the innermost member
This commit is contained in:
1 parent
b25e9c75aa
commit
3128762014
5 files changed
+49
-23
No files matched your search
@@ -476,12 +476,15 @@ fn check(s: &mut Session, _p: &Value) -> Result<Value> {
|
||||
// ---- Motion studies ----
|
||||
|
||||
fn study_index(s: &Session, p: &Value, cmd: &str) -> Result<usize> {
|
||||
let key = match p.get("study") {
|
||||
Some(Value::Number(n)) => n.to_string(),
|
||||
Some(Value::String(x)) => x.clone(),
|
||||
// A number is an id first, text a name first: a study may be named like another's id.
|
||||
let (key, id_first) = match p.get("study") {
|
||||
Some(Value::Number(n)) => (n.to_string(), true),
|
||||
Some(Value::String(x)) => (x.clone(), false),
|
||||
_ => return Err(bad(cmd, "`study` must be an id or a name")),
|
||||
};
|
||||
s.doc.assembly.studies.iter().position(|m| m.id.to_string() == key || m.name == key).ok_or_else(|| bad(cmd, format!("no motion study `{key}`")))
|
||||
let studies = &s.doc.assembly.studies;
|
||||
let (by_id, by_name) = (studies.iter().position(|m| m.id.to_string() == key), studies.iter().position(|m| m.name == key));
|
||||
if id_first { by_id.or(by_name) } else { by_name.or(by_id) }.ok_or_else(|| bad(cmd, format!("no motion study `{key}`")))
|
||||
}
|
||||
|
||||
fn study(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
|
||||
@@ -19,7 +19,7 @@ use crate::{EngineError, Result, Session};
|
||||
|
||||
pub const PLOT_DOC: &str = "study: id|name; joints?: [id|name] (default: every joint that moves); occurrence? and point? (a point \
|
||||
of a part to follow, as motion.trace takes them); samples? (3…1000, default the study's steps + 1); duration?: seconds the \
|
||||
whole study takes (velocities and accelerations then per second, else per step) → step: [the study step of each sample], \
|
||||
whole study takes, 0.001 or more (velocities and accelerations then per second, else per step) → step: [the study step of each sample], \
|
||||
time?: [s], joints: [{joint, name, index, dof, unit, value, velocity, acceleration, velocity_unit, acceleration_unit}] \
|
||||
(degrees for angles, mm for distances; angles unwrapped), point?: {occurrence, position: [[x,y,z]…], velocity, \
|
||||
acceleration (vectors), speed, acceleration_norm, unit, velocity_unit, acceleration_unit}, samples (taken), stopped_at, \
|
||||
@@ -173,7 +173,8 @@ pub(super) fn plot(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let duration = match p.get("duration") {
|
||||
None | Some(Value::Null) => None,
|
||||
Some(v) => {
|
||||
Some(v.as_f64().filter(|d| d.is_finite() && *d > 0.0 && *d <= 1e9).ok_or_else(|| bad(cmd, "`duration` must be seconds, more than 0"))?)
|
||||
// At least a millisecond: shorter sample spacings square to nothing.
|
||||
Some(v.as_f64().filter(|d| (1e-3..=1e9).contains(d)).ok_or_else(|| bad(cmd, "`duration` must be seconds, 0.001 or more"))?)
|
||||
}
|
||||
};
|
||||
let series = plotted(s, p, cmd)?;
|
||||
@@ -261,10 +262,11 @@ fn shared_volume(s: &Session, doc: &Document, a: u64, b: u64, booleans: &mut usi
|
||||
// The bodies under each (and not under the other), with their world frames and boxes.
|
||||
let mut sides: [Vec<(Mat, Aabb3, &solidcraft_doc::ModelBody)>; 2] = Default::default();
|
||||
for (comp, path, m) in doc.placements() {
|
||||
let side = match (path.contains(&a), path.contains(&b)) {
|
||||
(true, false) => 0,
|
||||
(false, true) => 1,
|
||||
_ => continue,
|
||||
// A body belongs to the innermost of the two on its path, as contact sets pair them.
|
||||
let side = match path.iter().rev().find(|o| **o == a || **o == b) {
|
||||
Some(o) if *o == a => 0,
|
||||
Some(_) => 1,
|
||||
None => continue,
|
||||
};
|
||||
for body in st.bodies.iter().filter(|x| doc.model_body_component(x) == comp && !x.body.is_mesh()) {
|
||||
let frame = doc.model_body_offset(body).map(|o| mat_mul(&m, o)).unwrap_or(m);
|
||||
|
||||
@@ -153,6 +153,18 @@ fn interference_names_the_step_two_parts_start_to_collide() {
|
||||
assert!(r["clear"] == true && r["collisions"] == json!([]), "{r}");
|
||||
}
|
||||
|
||||
/// A number names a study by its id first, text by its name first: a study may be named like
|
||||
/// another's id.
|
||||
#[test]
|
||||
fn studies_by_id_or_name() {
|
||||
let mut s = rail();
|
||||
let keys = json!([{"joint": "Rail", "points": [[0, 10], [15, -5]]}]);
|
||||
let first = run(&mut s, "motion.study", json!({"name": "Late", "steps": 15, "keys": keys}))["study"].as_u64().unwrap_or(0);
|
||||
run(&mut s, "motion.study", json!({"name": first.to_string(), "steps": 15, "keys": keys}));
|
||||
assert_eq!(run(&mut s, "motion.plot", json!({"study": first, "samples": 3}))["study"], "Late");
|
||||
assert_eq!(run(&mut s, "motion.plot", json!({"study": first.to_string(), "samples": 3}))["study"], first.to_string());
|
||||
}
|
||||
|
||||
/// Hostile parameters are refused, never a panic.
|
||||
#[test]
|
||||
fn motion_analysis_refuses_what_it_cannot_do() {
|
||||
@@ -165,6 +177,7 @@ fn motion_analysis_refuses_what_it_cannot_do() {
|
||||
("motion.plot", json!({"study": "Push", "samples": "many"})),
|
||||
("motion.plot", json!({"study": "Push", "duration": 0})),
|
||||
("motion.plot", json!({"study": "Push", "duration": -3})),
|
||||
("motion.plot", json!({"study": "Push", "duration": 1e-200})),
|
||||
("motion.plot", json!({"study": "Push", "joints": ["Nope"]})),
|
||||
("motion.plot", json!({"study": "Push", "joints": vec![json!("Rail"); 300]})),
|
||||
("motion.plot", json!({"study": "Push", "point": [1, 2]})),
|
||||
|
||||
Reference in new issue
Block a user