refactor(imex): Mirror reflects about zone-boundary plane, not primary origin

Replace imex_head_transform's fifth argument (Vec3d primary_origin) with a
Vec2d primary_zone_center and rewrite the Mirror branch as a true reflection
about the plane x = primary_zone_center.x + gantry_offset.x/2. Previous math
flipped about the primary's current origin, which:
  * let the ghost drift out of the target zone as the primary moved, and
  * made mirrored drag motion track 1:1 with the primary instead of reflecting.

The new transform places the ghost at the mirrored position within the target
zone (matching where the mirror tool actually prints) and reflects drag so
primary +X → ghost -X while Y tracks 1:1 — i.e. the ghost stays a true
mirror while the user drags. Off-row Mirror targets (e.g. T3 on a 2x2) still
reflect across the same X-plane as on-row peers.

PartPlate::calc_imex_ghosts and update_imex_ghost_transforms now feed primary_off
(the primary head's zone center) instead of an instance-space Vec3d.

Mirror tests rewritten against the new geometric contract: ghost origin at the
reflected position, primary drag deltas reflected across the zone-boundary plane.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Clifford Garwood
2026-04-21 22:51:56 -04:00
co-authored by Claude Opus 4.7
parent 6a3de6a28f
commit 9a87b96ded
4 changed files with 66 additions and 67 deletions
+8 -7
View File
@@ -1092,10 +1092,11 @@ void PartPlate::calc_imex_ghosts()
if (phys >= IMEX_GHOST_MAX_HEADS) continue;
const Vec2d gantry = center_for(phys) - primary_off;
// Mirror needs the primary instance's origin so the geometric flip happens
// about that point instead of the old gantry midplane; Copy ignores it.
// Mirror reflects about the zone-boundary plane through the primary zone
// center, so the ghost lands at the mirrored position within the target
// zone and drag motion inverts X while Y tracks 1:1. Copy ignores it.
const Transform3d head_xf = imex_head_transform(
primary_phys, phys, role, gantry, inst_world.translation());
primary_phys, phys, role, gantry, primary_off);
ColorRGBA color = get_imex_head_filament_color(phys);
color.a(GHOST_ALPHA);
@@ -1171,11 +1172,11 @@ void PartPlate::update_imex_ghost_transforms(
}
const Vec2d gantry = center_for(head) - primary_off;
// Mirror uses primary_xf.translation() as the flip plane anchor so the ghost's
// geometry reflects about the primary's current position rather than a fixed
// midplane; Copy ignores this argument.
// Mirror reflects about the zone-boundary plane through the primary zone
// center, so the ghost lands at the mirrored position within the target
// zone and drag motion inverts X while Y tracks 1:1. Copy ignores it.
const Transform3d head_xf = imex_head_transform(
primary_phys, head, role_for(head), gantry, primary_xf.translation());
primary_phys, head, role_for(head), gantry, primary_off);
ghost->set_instance_transformation(head_xf * primary_xf);
}
}