solid.mirror: mirror bodies of placed components where they are shown (#1896)

Thanks @NOWN-DEV.
This commit is contained in:
NOWN-DEV authored and GitHub committed 2026-10-17 04:08:22 -04:00
1 parent 9ce940b0b1
commit 2831426c51
9 files changed
+198 -8

No files matched your search

+22
View File
@@ -1358,6 +1358,7 @@ fn mirror(s: &mut Session, p: &Value) -> Result<Value> {
let features = if bodies.is_empty() { source_features(s, p, cmd)? } else { Vec::new() };
let plane = plane_param(s, p.get("plane"), cmd)?;
let combine = bool_(p, "combine").unwrap_or(false);
let (bodies, placements) = placed_bodies(s, bodies, cmd)?;
add_feature(
s,
p,
@@ -1366,10 +1367,31 @@ fn mirror(s: &mut Session, p: &Value) -> Result<Value> {
plane,
bodies: bodies.into_iter().map(BodyName).collect(),
combine,
placements,
},
)
}
/// Bodies picked where the viewport shows them: each world name ("Body1", or "Body1 (Occ:2)"
/// for a further instance) becomes its component's body name, with the occurrence path of the
/// placement it was picked at. Names stay as they are (and no placement is kept) while every
/// component is in place, or when one of them is not a body.
fn placed_bodies(s: &Session, names: Vec<String>, cmd: &str) -> Result<(Vec<String>, Vec<Vec<u64>>)> {
if names.is_empty() || !crate::frames::placed(s) {
return Ok((names, Vec::new()));
}
let frames = s.doc.body_frames_with_source(&s.model.state());
let mut picked = Vec::with_capacity(names.len());
for name in &names {
let Some((_, own, _, path, _)) = frames.iter().find(|(world, ..)| world == name) else { return Ok((names, Vec::new())) };
if path.iter().any(|id| s.pending_moves.contains_key(id)) {
return Err(bad(cmd, format!("`{name}` has a position that is not captured yet: Capture Position (component.capture_position) first")));
}
picked.push((own.clone(), path.clone()));
}
Ok(picked.into_iter().unzip())
}
/// The other name of an origin plane (`Top` for `XY`, `XY` for `Top`...), if `name` is one.
pub(super) fn origin_plane_alias(name: &str) -> Option<&'static str> {
match name.trim().to_ascii_uppercase().as_str() {