mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-10 17:21:10 +00:00
fix(imex): primary's filament lookup must come from object assignment, not pem default
The pre-slice warning's primary-tool filament lookup (added in
fbc58d2a1d) used resolve_filament_for_head, which returns the FIRST
slot routed to the primary's physical extruder via pem. That's the
right rule for *secondaries* (no object owns them in copy/mirror mode;
filament comes from the per-plate imex_head_filament_map override) but
wrong for the *primary*: the primary prints the actual objects on the
plate, and the slot it uses is whatever the user assigned to those
objects — not whatever happens to be at the head of the AFC manifold.
Symptom on the user's Neo XP 0.6:
- pem = [0,0,0,0,1,2,3,3] (slots 0-3 share AFC manifold on physical T0)
- filaments: slot 0 ABS, slot 2 PLA, slots 4-6 PLA, etc.
- object assigned to slot 2 (PLA), IMEX mode "copy" (T0 primary, T1 copy)
- User picks slot 5 PLA for T1 via the IMEX ghost picker (writes a
per-plate imex_head_filament_map).
- Warning reads slot 0 (ABS) for primary because that's
first_filament_for_physical_head(pem, 0). Fires "T0 ABS vs T1 PLA
type mismatch" even though the actual print uses slot 2 (PLA) for
the primary — slicer and warning disagree.
Split the lookup:
logical_for_primary(physical_idx)
Walks plate->get_extruders(true) (1-based slots used by objects on
this plate), returns the first slot whose pem entry maps to
physical_idx. Falls back to first_filament_for_physical_head if no
object on the plate routes to this physical extruder (defensive).
logical_for_secondary(physical_idx)
Unchanged behavior: per-plate imex_head_filament_map override with
first_filament_for_physical_head fallback.
The user-facing "T%d" labels still display the physical extruder index
(carriage identity); only the filament-info lookups change.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
0db99d21dd
commit
c8e7c5678b
@@ -10022,19 +10022,40 @@ static std::vector<wxString> collect_imex_warnings(PartPlate* plate)
|
||||
// imex_mode_active_tools). filament_presets and bed_temps are indexed by LOGICAL
|
||||
// filament slot. For MMU/AFC layouts where multiple logical slots feed one
|
||||
// physical extruder, looking up filament_presets[physical_idx] returns the wrong
|
||||
// filament. Translate physical -> logical via the effective pem (with per-plate
|
||||
// imex_head_filament_map override) before indexing.
|
||||
// filament. Translate physical -> logical before indexing.
|
||||
//
|
||||
// Primary vs secondary use DIFFERENT translation rules:
|
||||
// - Primary's filament: the slot the user assigned to the printing object(s).
|
||||
// Walk plate->get_extruders() and pick a slot whose pem entry maps to the
|
||||
// primary's physical index. If multiple slots qualify, the first match wins.
|
||||
// - Secondary's filament: per-plate imex_head_filament_map override (set via
|
||||
// the IMEX ghost picker). No object owns a secondary in copy/mirror mode —
|
||||
// the firmware duplicates the primary, so the override is the only source.
|
||||
// - Both fall back to first_filament_for_physical_head as a last resort so a
|
||||
// warning still has *some* filament to name.
|
||||
const ConfigOptionInts pem = effective_physical_extruder_map(*bundle);
|
||||
std::map<int, int> plate_head_map;
|
||||
if (auto* hfm = plate->config()->option<ConfigOptionString>("imex_head_filament_map"))
|
||||
plate_head_map = parse_imex_head_filament_map(hfm->value);
|
||||
auto logical_for = [&](int physical_idx) -> int {
|
||||
|
||||
auto logical_for_primary = [&](int physical_idx) -> int {
|
||||
// get_extruders() returns 1-based filament slots used by objects on this plate.
|
||||
const std::vector<int> used_slots_1b = plate->get_extruders(true);
|
||||
for (int slot_1b : used_slots_1b) {
|
||||
const int slot_0b = slot_1b - 1;
|
||||
if (slot_0b >= 0 && slot_0b < (int)pem.values.size()
|
||||
&& pem.values[slot_0b] == physical_idx)
|
||||
return slot_0b;
|
||||
}
|
||||
return first_filament_for_physical_head(pem, physical_idx);
|
||||
};
|
||||
auto logical_for_secondary = [&](int physical_idx) -> int {
|
||||
const int logical = resolve_filament_for_head(plate_head_map, pem, physical_idx);
|
||||
return logical >= 0 ? logical : physical_idx; // fallback: identity if no routing found
|
||||
return logical >= 0 ? logical : physical_idx;
|
||||
};
|
||||
|
||||
// Primary tool's bed temp and filament type (looked up by logical slot)
|
||||
const int primary_logical = logical_for(primary_tool);
|
||||
const int primary_logical = logical_for_primary(primary_tool);
|
||||
const int primary_bed_temp = (bed_temps && primary_logical < (int)bed_temps->values.size())
|
||||
? bed_temps->values[primary_logical] : 0;
|
||||
std::string primary_display_type;
|
||||
@@ -10048,7 +10069,7 @@ static std::vector<wxString> collect_imex_warnings(PartPlate* plate)
|
||||
const int tool_idx = active_tools[i];
|
||||
if (tool_idx == primary_tool) continue;
|
||||
|
||||
const int secondary_logical = logical_for(tool_idx);
|
||||
const int secondary_logical = logical_for_secondary(tool_idx);
|
||||
|
||||
std::string secondary_display_type;
|
||||
if (secondary_logical < (int)filament_presets.size()) {
|
||||
|
||||
Reference in New Issue
Block a user