Large STEP imports: no more multi-minute hang, shared STEP text, cancel and progress (#925)
This commit is contained in:
1 parent
dfbf7dd6a8
commit
2f91338d3d
18 files changed
+525
-45
No files matched your search
+63
-1
@@ -4407,9 +4407,12 @@ fn eval_feature(doc: &Document, vals: &BTreeMap<String, Value>, f: &Feature, st:
|
||||
FeatureKind::Import { step, .. } => {
|
||||
let imp = kernel::step_import_shared(step)?;
|
||||
let digest = crate::config::payload_digest(step);
|
||||
// Files from board and assembly tools give thousands of bodies the same name: name
|
||||
// them from a set, not by searching the bodies for every candidate (cubic).
|
||||
let mut names = BodyNames::new(st);
|
||||
for (k, b) in imp.bodies.iter().enumerate() {
|
||||
let base = f.body_names.get(k).filter(|n| !n.trim().is_empty()).unwrap_or(&b.name);
|
||||
let name = unique_body_name(st, base);
|
||||
let name = names.unique(base);
|
||||
let b = crate::lineage::numbered_tool(b.body.clone().with_import_certificate(&digest, f.id)?);
|
||||
st.bodies.push(ModelBody::traced_new(name, b, f.id));
|
||||
}
|
||||
@@ -4442,6 +4445,35 @@ fn mesh_bodies(meshes: &[crate::MeshData]) -> Result<Vec<(String, Body)>> {
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
/// [`unique_body_name`] for many bodies in a row: the same names, in time linear in the bodies.
|
||||
struct BodyNames {
|
||||
taken: std::collections::HashSet<String>,
|
||||
/// The next suffix worth trying for each base (smaller ones are all taken).
|
||||
next: std::collections::HashMap<String, usize>,
|
||||
}
|
||||
|
||||
impl BodyNames {
|
||||
fn new(st: &ModelState) -> Self {
|
||||
BodyNames { taken: st.bodies.iter().map(|b| b.name.clone()).collect(), next: std::collections::HashMap::new() }
|
||||
}
|
||||
fn unique(&mut self, base: &str) -> String {
|
||||
let base = if base.trim().is_empty() { "Body" } else { base.trim() };
|
||||
if self.taken.insert(base.to_string()) {
|
||||
return base.to_string();
|
||||
}
|
||||
let mut i = self.next.get(base).copied().unwrap_or(2);
|
||||
let name = loop {
|
||||
let candidate = format!("{base} ({i})");
|
||||
i += 1;
|
||||
if self.taken.insert(candidate.clone()) {
|
||||
break candidate;
|
||||
}
|
||||
};
|
||||
self.next.insert(base.to_string(), i);
|
||||
name
|
||||
}
|
||||
}
|
||||
|
||||
/// `base`, or `base (2)`, `base (3)`… if a body already has that name.
|
||||
fn unique_body_name(st: &ModelState, base: &str) -> String {
|
||||
let base = if base.trim().is_empty() { "Body" } else { base.trim() };
|
||||
@@ -4780,3 +4812,33 @@ mod chain_tests {
|
||||
assert_eq!(faces.len(), 3, "{faces:?}");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod body_name_tests {
|
||||
use super::*;
|
||||
|
||||
/// Imported bodies get the names one-at-a-time naming gives them, in time linear in the
|
||||
/// bodies: a board file with thousands of same-named parts once took minutes (#883).
|
||||
#[test]
|
||||
fn many_same_named_bodies_are_named_in_linear_time() {
|
||||
let mut st = ModelState::default();
|
||||
let body = kernel::box_solid(Vec3::ZERO, Vec3::new(1.0, 1.0, 1.0)).unwrap();
|
||||
for name in ["R", "R (3)", "C"] {
|
||||
st.bodies.push(ModelBody::new(name.into(), body.clone(), 1));
|
||||
}
|
||||
// The same names as asking the bodies one at a time.
|
||||
let mut names = BodyNames::new(&st);
|
||||
let mut slow = st.clone();
|
||||
for base in ["R", "R", "C", " ", "Body", "R", "R (2)", "X"] {
|
||||
let expected = unique_body_name(&slow, base);
|
||||
assert_eq!(names.unique(base), expected);
|
||||
slow.bodies.push(ModelBody::new(expected, body.clone(), 2));
|
||||
}
|
||||
// 50,000 parts named alike: milliseconds (one-at-a-time naming would take hours).
|
||||
let began = std::time::Instant::now();
|
||||
let mut names = BodyNames::new(&ModelState::default());
|
||||
let last = (0..50_000).map(|_| names.unique("R_0603")).last().unwrap();
|
||||
assert_eq!(last, "R_0603 (50000)");
|
||||
assert!(began.elapsed() < std::time::Duration::from_secs(5), "{:?}", began.elapsed());
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user