Paste New copies an import's bodies under the names its features use when the names are numbered (#1117)
Where an Import's stored labels pair one for one with its numbered built bodies (X, X (2), X (3)), component.paste_new stores the copy under the bodies' names, so the copied features after it find their bodies. No format change.
This commit is contained in:
1 parent
6ebfcd16b6
commit
f79dfe41b6
2 files changed
+201
-4
No files matched your search
@@ -94,6 +94,24 @@ fn unique(base: &str, used: &mut BTreeSet<String>) -> String {
|
||||
name
|
||||
}
|
||||
|
||||
/// Whether `built`, the bodies a feature made, are the ones its `stored` names give, one for one. A
|
||||
/// name is built as stored, or as `stored (n)` when a body of that name exists already: the solids
|
||||
/// of a STEP file that share a label are stored as `X`, `X`, `X` and built as `X`, `X (2)`, `X (3)`,
|
||||
/// and a second import of a file builds `Aa (2)` for the stored `Aa`.
|
||||
fn named_by(stored: &[String], built: &[String]) -> bool {
|
||||
!stored.is_empty()
|
||||
&& stored.len() == built.len()
|
||||
&& stored.iter().zip(built).all(|(stored, built)| {
|
||||
let base = stored.trim();
|
||||
!base.is_empty()
|
||||
&& (built == base
|
||||
|| built
|
||||
.strip_prefix(base)
|
||||
.and_then(|rest| rest.strip_prefix(" (")?.strip_suffix(')'))
|
||||
.is_some_and(|n| !n.is_empty() && n.bytes().all(|b| b.is_ascii_digit())))
|
||||
})
|
||||
}
|
||||
|
||||
fn graph(doc: &Document, root: u64) -> Result<Vec<u64>> {
|
||||
let definitions: BTreeSet<_> = doc.components.iter().map(|c| c.id).collect();
|
||||
let mut children: BTreeMap<u64, Vec<u64>> = BTreeMap::new();
|
||||
@@ -271,17 +289,26 @@ pub(super) fn paste(
|
||||
}
|
||||
// Collect historical outputs too: a later Combine may have consumed a named tool body.
|
||||
let mut outputs: BTreeMap<u64, Vec<String>> = BTreeMap::new();
|
||||
// The names the bodies of a feature have in the model, where they are its stored names, numbered.
|
||||
let mut shown: BTreeMap<u64, Vec<String>> = BTreeMap::new();
|
||||
for f in &feats {
|
||||
if let Some(result) = s.model.result(f.id) {
|
||||
let created: Vec<_> = result.state.bodies.iter().filter(|b| b.feature == f.id).map(|b| b.name.clone()).collect();
|
||||
for name in &created {
|
||||
bodies.entry(name.clone()).or_insert_with(|| unique(name, &mut used));
|
||||
}
|
||||
if named_by(&f.body_names, &created) {
|
||||
shown.insert(f.id, created.clone());
|
||||
}
|
||||
outputs.insert(f.id, created);
|
||||
}
|
||||
for name in &f.body_names {
|
||||
if !name.is_empty() {
|
||||
bodies.entry(name.clone()).or_insert_with(|| unique(name, &mut used));
|
||||
// Later features name a body as the model shows it. Where that differs from the stored name,
|
||||
// the stored name is only a label (the first body of another import may be called so).
|
||||
if !shown.contains_key(&f.id) {
|
||||
for name in &f.body_names {
|
||||
if !name.is_empty() {
|
||||
bodies.entry(name.clone()).or_insert_with(|| unique(name, &mut used));
|
||||
}
|
||||
}
|
||||
}
|
||||
if bodies.len() > MAX_WORK {
|
||||
@@ -379,7 +406,11 @@ pub(super) fn paste(
|
||||
f.id = *features.get(&old.id).ok_or_else(|| bad(CMD, "missing feature mapping"))?;
|
||||
f.name = names.get(&old.name).cloned().ok_or_else(|| bad(CMD, "missing feature name"))?;
|
||||
f.component = *components.get(&old.component).ok_or_else(|| bad(CMD, "missing component mapping"))?;
|
||||
if f.body_names.is_empty() {
|
||||
if let Some(names) = shown.get(&old.id) {
|
||||
// Stored as `X`, `X`, `X` and built as `X`, `X (2)`, `X (3)`: the copy is stored under the
|
||||
// names of the bodies, so that it builds the names the copied features after it use.
|
||||
f.body_names = names.clone();
|
||||
} else if f.body_names.is_empty() {
|
||||
f.body_names = outputs.get(&old.id).cloned().unwrap_or_default();
|
||||
}
|
||||
f.remap_clone(&features, &names, &bodies, ¶meters)?;
|
||||
|
||||
Reference in new issue
Block a user