From ddf9b8516909b63a7930920bdb93987233be23fa Mon Sep 17 00:00:00 2001 From: HanifKoh <76276251+HanifKoh@users.noreply.github.com> Date: Fri, 25 Sep 2026 08:39:52 +0800 Subject: [PATCH] Reserve the Prime Tower When the CLI Arranges a Project (#15837) The global arrange branch, taken by --arrange with all plates selected, only reserved the prime tower when filament ids had been given on the command line for STL input. A project carries its filament use per plate and its own tower positions, but that set was empty for it, so the tower was never an obstacle: the arranged pile was centred over it and the slice then failed on a G-code path conflict. When no filament ids were given, count the filaments each plate uses and reserve a tower on every plate that needs one, keeping the project's tower position instead of resetting it to the default. Only a tower the slicer will print is reserved: the prime tower must be enabled, and a by-object print gets none unless a smooth timelapse needs it, as the per-plate arrange decides. Overflow beds are sized for the busiest plate. The STL route is unchanged. --- src/OrcaSlicer.cpp | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/OrcaSlicer.cpp b/src/OrcaSlicer.cpp index 507c65f7bb..e7facbdbd8 100644 --- a/src/OrcaSlicer.cpp +++ b/src/OrcaSlicer.cpp @@ -5527,12 +5527,28 @@ int CLI::run(int argc, char **argv) //add the virtual object into unselect list if has partplate_list.preprocess_exclude_areas(unselected, enable_wrapping_detect); - if (used_filament_set.size() > 0) + // Filament ids given on the command line size the tower for STL input. A project + // records its filament use per plate, so count there and keep its tower positions. + const int plate_count = partplate_list.get_plate_count(); + const bool from_project = used_filament_set.empty(); + std::vector plate_filament_counts(plate_count, static_cast(used_filament_set.size())); + if (from_project) + for (int plate_index = 0; plate_index < plate_count; ++plate_index) + plate_filament_counts[plate_index] = static_cast(partplate_list.get_plate(plate_index)->get_extruders_under_cli(true, m_print_config).size()); + // A project only gets a tower the slicer will print: the prime tower enabled, and not + // a by-object print unless a smooth timelapse needs it, as the per-plate arrange decides. + const bool project_tower_allowed = m_print_config.option("enable_prime_tower", true)->value && + (is_smooth_timelapse || !arrange_cfg.is_seq_print); + const auto plate_needs_wipe_tower = [from_project, project_tower_allowed, is_smooth_timelapse](int filament_count) { + if (!from_project) + return filament_count > 0; + return project_tower_allowed && (filament_count > 1 || (filament_count > 0 && is_smooth_timelapse)); + }; + const int max_filament_count = plate_count > 0 ? *std::max_element(plate_filament_counts.begin(), plate_filament_counts.end()) : 0; + + if (plate_needs_wipe_tower(max_filament_count)) { //prepare the wipe tower - int plate_count = partplate_list.get_plate_count(); - int extruder_size = used_filament_set.size(); - auto printer_structure_opt = m_print_config.option>("printer_structure"); // This margin only pre-adjusts the default away from the near edges; // estimate_wipe_tower_polygon below computes the real clamped position. @@ -5568,7 +5584,11 @@ int CLI::run(int argc, char **argv) for (int bedid = 0; bedid < MAX_PLATE_COUNT; bedid++) { int plate_index_valid = std::min(bedid, plate_count - 1); - if (bedid < plate_count) { + // Overflow beds may receive objects from any plate, so size them for the busiest one. + const int extruder_size = bedid < plate_count ? plate_filament_counts[bedid] : max_filament_count; + if (!plate_needs_wipe_tower(extruder_size)) + continue; + if (bedid < plate_count && !from_project) { wipe_x_option->set_at(&wt_x_opt, plate_index_valid, 0); wipe_y_option->set_at(&wt_y_opt, plate_index_valid, 0); }