fix(imex): make the plate badge count filaments the way validate does

The badge is meant to predict whether slicing will be refused, and it delegates
to the same helper for that reason. It was feeding that helper a different
filament list. get_extruders(true) resolves a mixed slot into its physical
components -- right for AMS mapping, which has to know what is actually loaded
-- while Print::validate counts the slot itself.

So a plate holding one two-component blend reads as two filaments to the badge
and one to validate. The badge sees two, decides the plate is fine, and stays
silent; the slice is then refused. It also runs the other way: a plate the user
sees as a single colour draws a multi-material warning, because the expansion
made it look like two.

Give get_extruders an expand_mixed flag, defaulted so every existing caller
keeps the resolved list, and have the badge ask for the authored one.

The badge was also only mirroring validate's multi-color rule, not its first
one -- a mixed filament is unsupported in a parallel mode outright. Without it
the badge stays quiet on exactly the plate validate refuses first.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Clifford Garwood
2026-08-27 10:36:15 -04:00
co-authored by Claude Opus 5
parent 2473ca7496
commit 1aa9bb8d93
2 changed files with 23 additions and 4 deletions
+19 -3
View File
@@ -1549,11 +1549,27 @@ bool PartPlate::has_imex_multimaterial_conflict() const
}
// Convert PartPlate's 1-based extruder list to the 0-based form the helper expects.
const std::vector<int> used_1b = get_extruders(true);
//
// get_extruders(true) expands a mixed slot into its physical components, which is right for
// AMS mapping but wrong here: Print::validate counts the slot itself, so an expanded list
// makes the badge disagree with the thing it is previewing. A plate holding one 2-component
// blend reads as 2 filaments to the badge and 1 to validate -- the badge stays silent and
// the slice is then refused, or it warns about "multi-material objects" on a plate the user
// sees as single-colour. Undo the expansion so both sides count the same way.
const std::vector<int> used_1b = get_extruders(true, /*expand_mixed=*/false);
std::vector<int> used_0b;
used_0b.reserve(used_1b.size());
for (int e : used_1b) if (e > 0) used_0b.push_back(e - 1);
// validate()'s first rule: a mixed filament is unsupported in a parallel mode outright,
// ahead of any multi-color reasoning. The badge has to agree or it under-reports.
if (auto* is_mixed_opt = wxGetApp().preset_bundle->project_config.option<ConfigOptionBools>("filament_is_mixed")) {
const auto& is_mixed = is_mixed_opt->values;
if (std::any_of(used_0b.begin(), used_0b.end(),
[&](int slot) { return slot >= 0 && slot < (int) is_mixed.size() && is_mixed[slot]; }))
return true;
}
return !imex_multicolor_block_reason(mode, active_tools_str, tpg_opt->value, used_0b, *pem_opt).empty();
}
@@ -2761,7 +2777,7 @@ int PartPlate::picking_id_component(int idx) const
return this->m_plate_index * GRABBER_COUNT + idx;
}
std::vector<int> PartPlate::get_extruders(bool conside_custom_gcode) const
std::vector<int> PartPlate::get_extruders(bool conside_custom_gcode, bool expand_mixed) const
{
std::vector<int> plate_extruders;
if (check_objects_empty_and_gcode3mf(plate_extruders)) {
@@ -2920,7 +2936,7 @@ std::vector<int> PartPlate::get_extruders(bool conside_custom_gcode) const
auto& project_config = wxGetApp().preset_bundle->project_config;
auto* is_mixed_opt = project_config.option<ConfigOptionBools>("filament_is_mixed");
auto* comp_strs_opt = project_config.option<ConfigOptionStrings>("filament_mixed_components");
if (is_mixed_opt && comp_strs_opt && has_any_mixed_filament(is_mixed_opt->values)) {
if (expand_mixed && is_mixed_opt && comp_strs_opt && has_any_mixed_filament(is_mixed_opt->values)) {
std::vector<unsigned int> ext_0based;
for (int e : plate_extruders)
if (e >= 1) ext_0based.push_back((unsigned int)(e - 1));
+4 -1
View File
@@ -433,7 +433,10 @@ public:
arrangement::ArrangePolygon estimate_wipe_tower_polygon(const DynamicPrintConfig & config, int plate_index, Vec3d& wt_pos, Vec3d& wt_size, int extruder_count = 1, int plate_extruder_size = 0, bool use_global_objects = false) const;
bool check_objects_empty_and_gcode3mf(std::vector<int> &result) const;
// get used filaments from config, 1 based idx
std::vector<int> get_extruders(bool conside_custom_gcode = false) const;
// expand_mixed=false returns the plate's filament slots as authored, without resolving a
// mixed slot into its components. Callers that mirror Print::validate need that form --
// validate counts the mixed slot itself, so an expanded list makes the two disagree.
std::vector<int> get_extruders(bool conside_custom_gcode = false, bool expand_mixed = true) const;
std::vector<int> get_extruders_under_cli(bool conside_custom_gcode, DynamicPrintConfig& full_config) const;
std::vector<int> get_extruders_without_support(bool conside_custom_gcode = false) const;
// get used filaments from gcode result, 1 based idx