Port wipe tower BBS improvements (#15485)

This commit is contained in:
Ian Bassi
2026-09-17 09:08:50 -03:00
committed by GitHub
parent ca668a3bc9
commit 82e91bd472
17 changed files with 945 additions and 43 deletions
+41 -18
View File
@@ -1028,11 +1028,21 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
double current_z = gcodegen.writer().get_position().z();
if (z == -1.) // in case no specific z was provided, print at current_z pos
z = current_z;
if (!is_approx(z, current_z)) {
// Orca: wipe_tower_no_sparse_layers crash guard. With sparse layers skipped the tower is
// compacted far below the object, so descending to it is only safe once the nozzle is parked
// over the tower - which is what the is_finish_first travel above does. Otherwise the nozzle
// is still over the model and this descent would drive it into the print, so defer it to the
// re-descents below, which run after the travel to the tower.
const bool defer_compacted_descend = m_sparse_layers_skipped
&& !tcr.priming && !tcr.is_finish_first && (current_z - z) > EPSILON;
if (!is_approx(z, current_z) && !defer_compacted_descend) {
gcode += gcodegen.writer().retract();
gcode += gcodegen.writer().travel_to_z(z, "Travel down to the last wipe tower layer.");
gcode += gcodegen.writer().unretract();
}
// Tower compacted below the object, so any extrusion emitted without an explicit z has to be
// pulled back down to it first.
const bool compacted_below_object = m_sparse_layers_skipped && z >= 0. && (tcr.print_z - z) > EPSILON;
// Process the end filament gcode.
bool add_change_filament_624 = false;
@@ -1085,11 +1095,23 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
std::string nozzle_change_gcode_trans;
if (is_nozzle_change) {
// move to start_pos before nozzle change
// Orca: travel_to() lifts to the object layer height to clear the print. That lift is
// needed when arriving from the model, but is a wasted full-height Z bounce when the
// nozzle already sits on the compacted tower, so travel at the compacted z instead.
const bool compact_intower_nc_travel = compacted_below_object
&& (tcr.print_z - gcodegen.writer().get_position().z()) > EPSILON;
std::string start_pos_str;
start_pos_str = gcodegen.travel_to(wipe_tower_point_to_object_point(gcodegen, transform_wt_pt(tcr.nozzle_change_result.start_pos) + plate_origin_2d), erMixed,
"Move to nozzle change start pos");
"Move to nozzle change start pos", compact_intower_nc_travel ? z : DBL_MAX);
check_add_eol(start_pos_str);
nozzle_change_gcode_trans += start_pos_str;
// The nozzle-change wipe below carries no explicit z, so it would extrude at the object
// layer height and float above the compacted tower. Descend unless the travel stayed down.
if (!compact_intower_nc_travel && compacted_below_object) {
std::string nc_z_descend = gcodegen.writer().travel_to_z(z, "Descend to compacted wipe tower z (no sparse layers)");
check_add_eol(nc_z_descend);
nozzle_change_gcode_trans += nc_z_descend;
}
nozzle_change_gcode_trans += gcodegen.unretract();
nozzle_change_gcode_trans += transform_gcode(tcr.nozzle_change_result.gcode, tcr.nozzle_change_result.start_pos, wipe_tower_offset, wipe_tower_rotation);
gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, transform_wt_pt(tcr.nozzle_change_result.end_pos) + plate_origin_2d));
@@ -1428,6 +1450,15 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
start_filament_gcode_str = start_filament_gcode_str + wipe_next_start_point_str + toolchange_unretract_str;
// Orca: the custom change_filament_gcode lifts to the object layer height and the unretract
// de-hops back to it, so every tower extrusion emitted after it (purge moves, and the wall
// when it prints after the toolchange) would float above the compacted tower. Descend first.
if (compacted_below_object) {
std::string z_descend = gcodegen.writer().travel_to_z(z, "Descend to compacted wipe tower z (no sparse layers)");
check_add_eol(z_descend);
start_filament_gcode_str += z_descend;
}
// Insert the end filament, toolchange, and start filament gcode into the generated gcode.
DynamicConfig config;
config.set_key_value("filament_end_gcode", new ConfigOptionString(end_filament_gcode_str));
@@ -1915,11 +1946,9 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
// resulting in a wipe tower with sparse layers.
double wipe_tower_z = -1;
bool ignore_sparse = false;
if (gcodegen.config().wipe_tower_no_sparse_layers.value) {
if (m_sparse_layers_skipped) {
wipe_tower_z = m_last_wipe_tower_print_z;
ignore_sparse = (m_tool_changes[m_layer_idx].size() == 1 &&
m_tool_changes[m_layer_idx].front().initial_tool == m_tool_changes[m_layer_idx].front().new_tool &&
m_layer_idx != 0);
ignore_sparse = wipe_tower_layer_is_sparse(m_tool_changes[m_layer_idx]) && m_layer_idx != 0;
if (m_tool_change_idx == 0 && !ignore_sparse)
wipe_tower_z = m_last_wipe_tower_print_z + m_tool_changes[m_layer_idx].front().layer_height;
}
@@ -1935,12 +1964,9 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
// resulting in a wipe tower with sparse layers.
double wipe_tower_z = -1;
bool ignore_sparse = false;
if (gcodegen.config().wipe_tower_no_sparse_layers.value) {
wipe_tower_z = m_last_wipe_tower_print_z;
ignore_sparse = (m_tool_changes[m_layer_idx].size() == 1 &&
m_tool_changes[m_layer_idx].front().initial_tool == m_tool_changes[m_layer_idx].front().new_tool);
if (m_tool_change_idx == 0 && !ignore_sparse)
wipe_tower_z = m_last_wipe_tower_print_z + m_tool_changes[m_layer_idx].front().layer_height;
if (m_sparse_layers_skipped) {
ignore_sparse = wipe_tower_layer_is_sparse(m_tool_changes[m_layer_idx]);
wipe_tower_z = m_compacted_tower_z[m_layer_idx];
}
if ((m_enable_timelapse_print || m_enable_wrapping_detection) && m_is_first_print) {
@@ -1953,10 +1979,8 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
if (!(size_t(m_tool_change_idx) < m_tool_changes[m_layer_idx].size()))
throw Slic3r::RuntimeError("Wipe tower generation failed, possibly due to empty first layer.");
if (!ignore_sparse) {
if (!ignore_sparse)
gcode += append_tcr(gcodegen, m_tool_changes[m_layer_idx][m_tool_change_idx++], extruder_id, wipe_tower_z);
m_last_wipe_tower_print_z = wipe_tower_z;
}
}
}
@@ -1970,9 +1994,8 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
return true;
bool ignore_sparse = false;
if (gcodegen.config().wipe_tower_no_sparse_layers.value) {
ignore_sparse = (m_tool_changes[m_layer_idx].size() == 1 && m_tool_changes[m_layer_idx].front().initial_tool == m_tool_changes[m_layer_idx].front().new_tool);
}
if (m_sparse_layers_skipped)
ignore_sparse = wipe_tower_layer_is_sparse(m_tool_changes[m_layer_idx]);
if ((m_enable_timelapse_print || m_enable_wrapping_detection) && m_is_first_print) {
return false;