From c80f1ab312285d7884a021abd9815d4bf230ccde Mon Sep 17 00:00:00 2001 From: harrierpigeon Date: Sat, 13 Jun 2026 09:51:48 -0500 Subject: [PATCH] cancel top of purge tower early if no extra parts to print --- src/libslic3r/Print.cpp | 21 +++++++++++++++++++++ src/libslic3r/Print.hpp | 3 +++ src/libslic3r/PrintObjectSlice.cpp | 25 +++++++++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index b5d3701e41..5a0a6f8d8b 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -4345,6 +4345,27 @@ void Print::_plan_belt_purge() const bool use_flush_matrix = m_config.purge_in_prime_tower && m_config.single_extruder_multi_material; const float flush_multiplier = (float) m_config.flush_multiplier.get_at(0); + // Cancel the purge prism early: pre-scan the tool ordering for the highest + // print_z that actually has a toolchange, then drop the prism's layers above + // it so the tower stops at the last color swap (saves filament/time). This + // MUST happen before the marking loop below: ensure_perimeters_infills_order + // force-overrides the prism's extrusions on every layer (it is a dedicated + // flush object), so truncating afterwards would leave dangling overrides + // pointing into deleted layers. + { + double last_tc_z = -1.; + unsigned int cur_ext = m_wipe_tower_data.tool_ordering.first_extruder(); + for (const auto < : m_wipe_tower_data.tool_ordering.layer_tools()) + for (const unsigned int e : lt.extruders) + if (e != cur_ext) { last_tc_z = lt.print_z; cur_ext = e; } + if (last_tc_z >= 0.) + for (PrintObject *po : m_objects) + if (po->config().belt_purge_tower_object.value) { + po->belt_truncate_layers_above(last_tc_z); + break; + } + } + // Diagnostic: the prism only absorbs purge at toolchange layers whose // print_z coincides with one of its own layers. Compare the prism's layer // print_z range to the toolchange print_z range and count how many diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index fc78c5efef..2591f6cbd1 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -562,6 +562,9 @@ private: // clipping shift) by delta, used by Print::_align_belt_purge_layers() to // snap the purge prism's layers onto the printed objects' layer grid. void belt_shift_layer_grid(double delta); + // Belt mode: remove layers above z (cancel the purge prism past the last + // toolchange). Returns how many layers were dropped. + size_t belt_truncate_layers_above(coordf_t z); //BBS ExPolygons _shrink_contour_holes(double contour_delta, double hole_delta, const ExPolygons& polys) const; // BBS diff --git a/src/libslic3r/PrintObjectSlice.cpp b/src/libslic3r/PrintObjectSlice.cpp index b95bc4903f..f13b208a3a 100644 --- a/src/libslic3r/PrintObjectSlice.cpp +++ b/src/libslic3r/PrintObjectSlice.cpp @@ -1413,6 +1413,31 @@ void PrintObject::belt_shift_layer_grid(double delta) << " first_layer.print_z=" << (m_layers.empty() ? 0. : m_layers.front()->print_z); } +// Belt mode: drop layers strictly above z (used to cancel the purge prism early +// once there are no more toolchanges above z, so the tower stops at the last +// color swap instead of wasting filament up the rest of the belt). Each layer's +// cross-section is already sliced, so removing upper layers does not affect the +// last toolchange's coverage. Deletes the Layer objects and clears the new top +// layer's upper-layer link. Returns the number of layers removed. +size_t PrintObject::belt_truncate_layers_above(coordf_t z) +{ + size_t keep = m_layers.size(); + while (keep > 0 && m_layers[keep - 1]->print_z > z + EPSILON) + --keep; + if (keep >= m_layers.size()) + return 0; + const size_t removed = m_layers.size() - keep; + for (size_t i = keep; i < m_layers.size(); ++i) + delete m_layers[i]; + m_layers.resize(keep); + if (!m_layers.empty()) + m_layers.back()->upper_layer = nullptr; + BOOST_LOG_TRIVIAL(debug) << "[BELT-DEBUG] truncate purge prism above print_z=" << z + << " kept=" << keep << " removed=" << removed + << " new_top=" << (m_layers.empty() ? 0. : m_layers.back()->print_z); + return removed; +} + // 1) Decides Z positions of the layers, // 2) Initializes layers and their regions // 3) Slices the object meshes