Belt validation: refuse a brim next to a purge tower object

The purge plan moves objects onto a common layer grid after the brim bands are
built, so the two cannot share a print. The prime tower setting alone still does
not block a brim. The missing-prism warning now counts the filaments the objects
use, as the GUI does.
This commit is contained in:
harrierpigeon
2026-10-02 12:46:44 -05:00
parent 997fac8752
commit 550229b0fa
3 changed files with 32 additions and 6 deletions
+2 -2
View File
@@ -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
+8 -4
View File
@@ -1420,10 +1420,14 @@ StringObjectException Print::validate(std::vector<StringObjectException> *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<StringObjectException> *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 "
+22
View File
@@ -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<std::vector<Slic3r::ConfigBase::SetDeserializeItem>> 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]")