From 2b7f43888771c18f1c2dfcb5a8b45f57b6043a62 Mon Sep 17 00:00:00 2001 From: Clifford Garwood Date: Sat, 25 Apr 2026 03:42:23 -0400 Subject: [PATCH] =?UTF-8?q?fix(imex):=20translate=20physical=E2=86=92logic?= =?UTF-8?q?al=20when=20marking=20is=5Fextruder=5Fused=20for=20IMEX=20activ?= =?UTF-8?q?e=20tools?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit is_extruder_used is a logical-filament-slot indexed bool array — start-gcode templates use it as `is_extruder_used[N]` where N is a logical filament slot (matches how the rest of the codebase consumes per-filament arrays like filament_settings_id, nozzle_temperature_initial_layer, etc.). `tool_ordering.all_extruders()` returns LOGICAL slots and was correctly marking those. But the IMEX-secondary marking added in 5aa624b025 was writing PHYSICAL extruder indices straight into the logical array, mixing index spaces. On any printer with physical_extruder_map size > 1 (MMU/AFC), this marks the wrong slots and misses the right ones. Symptom on the user's Neo XP 0.6 (pem [0,0,0,0,1,2,3,3]) in copy mode [0:P,1:C] with object on slot 2 (PLA): - tool_ordering marks slot 2 (correct: object's filament). - IMEX active = [0, 1] (physical T0, T1) → mistakenly marks logical slots 0 (ABS) and 1 (ASA), neither of which is used. - Slot 4 (PLA on physical T1, the actual filament that loads on the secondary in copy mode) is NOT marked. - Start-gcode template emits EXTRUDER=ABS_temp EXTRUDER1=ASA_temp EXTRUDER2=PLA_temp; no EXTRUDER4. - PRINT_START macro reads t4=0, skips heating extruder1 — T1 stays cold during the print. Translate physical → logical via resolve_filament_for_head before marking (per-plate imex_head_filament_map override consulted, with first-routed fallback when no override is set). This matches what the firmware actually loads on each carriage during the parallel-mode print, and what the rest of the IMEX hot path (PA emission, layer-change temperature) already does. Result on the user's setup post-fix: - is_extruder_used[2]=true (object), is_extruder_used[4]=true (T1 in copy). - Start-gcode emits 2 temps for the actually-used filaments. - extruder1 heats correctly to slot 4's temp before the print begins. Co-Authored-By: Claude Opus 4.7 --- src/libslic3r/GCode.cpp | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 73b4d90946..61b8640d62 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2869,13 +2869,27 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato for (unsigned int extruder : tool_ordering.all_extruders()) is_extruder_used[extruder] = true; - // Orca IMEX: Also mark secondary carriages as used in parallel modes - // so is_extruder_used[N] is true for all physical tools in the active mode. - // Secondary carriages never appear in tool_ordering.all_extruders() because - // the firmware duplicates the primary's moves — no tool-change commands are emitted. - for (int tool_idx : get_imex_active_tools(print)) - if (tool_idx < (int)is_extruder_used.size()) - is_extruder_used[tool_idx] = true; + // Orca IMEX: also mark the LOGICAL filament slot that each active secondary + // carriage will load during the print. is_extruder_used is logical-slot indexed + // (consumed as `is_extruder_used[N]` in machine_start_gcode templates), but + // get_imex_active_tools returns PHYSICAL extruder indices. On any printer with + // physical_extruder_map size > 1 (MMU/AFC), writing the physical index into a + // logical-indexed array marks the wrong slot — start-gcode templates would emit + // the wrong filament's temp / not emit the correct one. + // + // Translate physical -> logical via the per-plate imex_head_filament_map (set by + // the IMEX ghost picker), with first_filament_for_physical_head as the fallback + // when no override is set. + if (print.config().is_imex.value && !print.objects().empty()) { + const auto plate_head_map = parse_imex_head_filament_map( + print.objects().front()->config().imex_head_filament_map.value); + const ConfigOptionInts& pem = print.config().physical_extruder_map; + for (int phys_tool : get_imex_active_tools(print)) { + const int logical = resolve_filament_for_head(plate_head_map, pem, phys_tool); + if (logical >= 0 && logical < (int)is_extruder_used.size()) + is_extruder_used[logical] = true; + } + } this->placeholder_parser().set("is_extruder_used", new ConfigOptionBools(is_extruder_used));