From 3ae74ff9525d8cdf7a75e96d902f0c119a02b154 Mon Sep 17 00:00:00 2001 From: Clifford Garwood Date: Sat, 3 Oct 2026 00:16:05 -0400 Subject: [PATCH] Count layer slider tool changes in the parallel-mode checks A tool change added from the layer slider switches heads mid-print like a painted color, but the parallel-mode checks only looked at the filaments of the plate's objects, support and prime tower. A one-filament plate with a slider change to a copying head's filament passed them. They now include those tool changes, as the plate's warning badge already did. Co-Authored-By: Claude Opus 5.5 --- src/libslic3r/Print.cpp | 9 ++++++--- tests/fff_print/test_multifilament.cpp | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index ea95e4fbbc..ce141c95a4 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1768,11 +1768,14 @@ StringObjectException Print::validate(std::vector *warnin if (m_config.is_imex.value && !m_objects.empty()) { const std::string& parallel_mode = m_objects.front()->config().imex_parallel_mode.value; if (!parallel_mode.empty() && parallel_mode != kImexPrimaryMode) { + // Tool changes added from the layer slider switch heads mid-print as a painted color + // does, so they count here, as the plate's warning badge counts them. + const std::vector imex_extruders = this->extruders(/*conside_custom_gcode=*/true); std::vector used_filaments_0b; std::vector used_slots_1b; - used_filaments_0b.reserve(extruders.size()); - used_slots_1b.reserve(extruders.size()); - for (unsigned int e : extruders) { + used_filaments_0b.reserve(imex_extruders.size()); + used_slots_1b.reserve(imex_extruders.size()); + for (unsigned int e : imex_extruders) { used_filaments_0b.push_back((int)e); used_slots_1b.push_back((int)e + 1); } diff --git a/tests/fff_print/test_multifilament.cpp b/tests/fff_print/test_multifilament.cpp index fc24268b0a..7837f26cc8 100644 --- a/tests/fff_print/test_multifilament.cpp +++ b/tests/fff_print/test_multifilament.cpp @@ -1256,6 +1256,29 @@ TEST_CASE("A mixed filament outranks the multi-color rule on the same plate", } } +// A tool change added from the layer slider switches heads mid-print just as a painted color +// does, so a parallel mode has to judge it with the plate's other filaments. Before it counted, +// a one-filament plate with a slider change to a copying head's filament passed validate(). +TEST_CASE("A layer slider tool change counts as a color in a parallel mode", "[MultiFilament][IMEX]") +{ + DynamicPrintConfig config = multifilament_config(7); + imex_7x4_printer(config); + all_regions_on_filament(config, 1); // filament 1 => logical slot 0 => physical head 0 + config.set_deserialize_strict({ { "imex_parallel_mode", "copy" } }); + + Slic3r::Model model; + Slic3r::Print print; + init_print({ cube(20) }, print, model, config); + std::vector warnings; + REQUIRE(print.validate(&warnings).string.empty()); + + // Filament 5 routes to head 1, which copies the primary in this mode. + model.plates_custom_gcodes[model.curr_plate_index].gcodes.push_back( + { 5.0, CustomGCode::Type::ToolChange, 5, "", "" }); + print.apply(model, print.full_print_config()); + REQUIRE_FALSE(print.validate(&warnings).string.empty()); +} + // Guard rail: the block must not fire on a well-formed plate. Filament 1 (slot 0) routes to // head 0, which `copy` declares Primary, so the Primary tool has something to print with. TEST_CASE("An IMEX plate whose filament routes to the Primary tool validates",