diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index a59e5aa46b..a9f56a805f 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -1066,8 +1066,8 @@ void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_ // The `print_z < object_bottom_z` clause reads "below the object" as "raft // gap". On a belt printer that is wrong: the brim apron legitimately prints // below the object's first layer, and treating those layers as raft would put a - // wipe tower at negative Z. Belt brim and the prime tower are mutually - // exclusive (rejected in Print::validate()), so simply drop the clause there. + // wipe tower at negative Z. A belt printer never prints the classic + // prime tower (Print::has_wipe_tower()), so simply drop the clause there. // // Gate on config.belt_printer, NOT on has_belt_brim: every layer below the // object bottom on a belt printer is legitimately a sub-object stream - brim diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 444bf7cde6..66de6d88ee 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1420,10 +1420,14 @@ StringObjectException Print::validate(std::vector *warnin return { L("Draft shield is not compatible with belt printer mode.") }; // Belt brim spans many layers and owns the layers below the object, which - // spiral vase cannot share. The prime tower setting is no obstacle: belt - // printers never print the classic tower, and the belt purge prism is an - // ordinary object that never takes a brim. + // neither the belt purge tower nor spiral vase can share (the purge plan moves + // objects onto a common layer grid after the brim bands are built). The prime + // tower setting alone is no obstacle: it stays on for any multi-filament + // project, and belt printers never print the classic tower. if (this->has_belt_brim()) { + if (this->has_belt_purge_tower()) + return { L("Brim is not compatible with the belt purge tower. " + "Disable one of them.") }; if (m_config.spiral_mode.value) return { L("Brim is not compatible with spiral vase mode on a belt printer. " "Disable one of them.") }; @@ -1558,7 +1562,7 @@ StringObjectException Print::validate(std::vector *warnin // the tower was generated) changes filament with nowhere to purge. if (m_config.belt_printer.value && m_config.enable_belt_purge_tower.value && m_config.print_sequence != PrintSequence::ByObject - && ! m_config.spiral_mode.value && extruders.size() > 1 && ! this->has_belt_purge_tower()) { + && ! m_config.spiral_mode.value && this->object_extruders().size() > 1 && ! this->has_belt_purge_tower()) { StringObjectException warningtemp; warningtemp.string = L("The belt purge tower is enabled but the project has no purge tower object; " "filament changes will not be purged. Open the project in the application " diff --git a/tests/fff_print/test_skirt_brim.cpp b/tests/fff_print/test_skirt_brim.cpp index edd2f0a56a..d762c49421 100644 --- a/tests/fff_print/test_skirt_brim.cpp +++ b/tests/fff_print/test_skirt_brim.cpp @@ -930,6 +930,28 @@ TEST_CASE("Belt inner-only leading brim does not reject the prime tower or spira CHECK(print.validate().string.empty()); CHECK_FALSE(gcode(print).empty()); } + // An actual purge tower object is different: the purge plan moves objects onto a common + // layer grid after the brim bands are built, so the two are still refused together. + SECTION("a brim is refused next to a belt purge tower object") { + DynamicPrintConfig config = belt_brim_multifilament_config(2, { + { "brim_type", "outer_only" }, + { "brim_width", 4 }, + { "brim_object_gap", 0 }, + { "enable_belt_purge_tower", 1 }, + }); + const std::vector> overrides { + { { "extruder", 1 } }, { { "extruder", 2 } }, + }; + Print print; + Model model; + init_print({ cube(20), cube(20) }, print, model, config, &overrides); + CHECK(print.validate().string.empty()); + + model.objects.back()->config.set_key_value("belt_purge_tower_object", new ConfigOptionBool(true)); + print.apply(model, config); + REQUIRE(print.has_belt_purge_tower()); + CHECK_FALSE(print.validate().string.empty()); + } } TEST_CASE("Belt brim spans many layers instead of one", "[SkirtBrim][belt]")