feat(imex): firmware-managed zones — center slice + ghost suppression

Adds the `imex_firmware_managed_zones` printer-config key (default off) for
IDEX/IQEX printers whose firmware applies its own copy/mirror offsets in
non-primary modes (e.g. RepRapFirmware IDEX duplication mode, Flashforge
Creator Pro 2/3 Pro). For these printers the slicer needs to emit a single
centered slice at bed origin and let the firmware fan toolheads out from there;
the previous slicer-managed iMEX rendering would draw a print at the primary
zone's world position (off-bed for the firmware-fan-out paradigm).

When the flag is on and the active mode is non-primary, the slicer subtracts
the primary zone's plate-local center from the gcode emission frame. The
writer offset is augmented but the gcode-processor offset stays at plate_origin
so the gcode-preview visualizer renders the centered slice at the bed center
rather than at the prepare-view zone placement. translate_to_print_space is
augmented too so first_layer_print_min/max placeholders (consumed by user
start_gcode like Felix's M118 header) reflect the centered frame.

Slice handoff lives in PartPlate::refresh_imex_slice_offset, called from both
update_slice_context (plate switch) and Plater::priv::update_background_process
(every-slice path — reslice() goes through here with switch_print=false so the
plate-switch hook alone wouldn't fire on mode toggle).

calc_imex_ghosts early-returns in firmware-managed mode: the existing
imex_head_transform math places ghosts at primary_zone_center + gantry_offset
(slicer-managed semantics), which renders off-bed when the toolpath is being
emitted in a centered frame. Proper firmware-managed ghost rendering (showing
where copies/mirrors will actually print after firmware fan-out) is deferred.

When the flag is off, all the new code paths reduce to no-ops byte-identical to
prior behavior. Layer 1 unit tests in test_imex_helpers cover every gating path
of compute_imex_slice_offset; full ctest suite passes (247/247).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Clifford Garwood
2026-05-13 00:55:45 -04:00
co-authored by Claude Opus 4.7
parent 493a9e96d2
commit 48c603faa5
13 changed files with 199 additions and 4 deletions
+15
View File
@@ -5620,6 +5620,21 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false));
// Firmware-managed zones: slice the primary zone's contents at bed origin (0,0)
// so a center-origin printer firmware can apply its own copy/mirror offsets to
// each toolhead. The slicer's zone overlay, placement check, and mode signaling
// are unchanged; only the gcode emission frame shifts.
def = this->add("imex_firmware_managed_zones", coBool);
def->label = L("Firmware-managed zones (center-origin slice)");
def->tooltip = L("When enabled, the slicer emits g-code with the primary zone's "
"contents centered on bed origin (0,0). The printer firmware is "
"responsible for placing copies/mirrors at each physical zone "
"position. Enable only on printers whose firmware applies its own "
"zone offsets in copy/mirror mode (e.g. RepRapFirmware IDEX "
"duplication mode). Has no effect in Primary mode.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false));
def = this->add("imex_gantry_count", coInt);
def->label = L("Gantry Count");
def->tooltip = L("Number of independent Y-axis gantries. 1 for IDEX/single-rail IQEX. 2 for dual-gantry systems (divides bed into rows).");