mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-19 15:03:05 +00:00
Stop estimating a prime tower for a single used filament (#15760)
# Description A plate using one filament no longer reserves or draws a prime tower in the plater just because multiple filament slots are configured. The shared footprint estimate gated "no tower" on the purge volume being zero, but on non-Bambu printers with the shipped defaults that volume comes from the SEMM flush matrix, which reads every configured slot and stays nonzero even when only one filament is used — so the preview showed a tower the print could never contain. The estimate now decides from the filament count alone, with wrapping detection and smooth timelapse staying the only reasons a single-filament plate keeps a tower, matching `Print::has_wipe_tower()`. The gate also moved above the flush-volume scan so the lone-filament path no longer pays for it. No change to slicing output — toolpath generation already omitted the tower for a single used filament; this removes the phantom preview, placement reservation, and validation footprint. # Screenshots/Recordings/Graphs Before the fix: https://github.com/user-attachments/assets/c5b0ea61-127d-408e-bafe-f1f76c58b996 After the fix: https://github.com/user-attachments/assets/ac6632b3-5d44-4013-aca3-73f6cfd1139c ## Tests <!-- > Please describe the tests that you have conducted to verify the changes made in this PR. --> Added a shipped-defaults single-filament case to `tests/libslic3r/test_wipe_tower_estimate.cpp`: it estimates a 5.04 mm-deep tower before the fix and zero depth after. `[WipeTowerEstimate]` and the fff_print `[WipeTower]` suites pass. <!-- > A guide for users on how to download the artifacts from this PR. --> [How to Download Pull Requests Artifacts for Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts)
This commit is contained in:
@@ -107,6 +107,12 @@ WipeTowerFootprint estimate_wipe_tower_footprint(const ConfigBase &config, WipeT
|
||||
// normalize_fdm_2 clearing enable_prime_tower. Its mixed-filament case is not modelled.
|
||||
const bool need_wipe_tower = smooth_timelapse || wrapping;
|
||||
|
||||
// Fewer than two filaments cannot make a tool change, so only wrapping detection or smooth
|
||||
// timelapse print a tower then. The flush volume is no proof of one: it is read from the
|
||||
// matrix of every configured slot, nonzero even when a single one of them is used.
|
||||
if (filaments_cnt < 2 && !need_wipe_tower)
|
||||
return footprint;
|
||||
|
||||
// A tower printed for one of the reasons above has no tool change to purge for; both
|
||||
// planners give it the idle depth below and nothing more.
|
||||
const size_t purge_count = filaments_cnt > 1 ? (dual_nozzle ? filaments_cnt : filaments_cnt - 1) : 0;
|
||||
@@ -151,14 +157,6 @@ WipeTowerFootprint estimate_wipe_tower_footprint(const ConfigBase &config, WipeT
|
||||
purges[longest_ramming].filament_change_length = float(float_at("filament_change_length", filament_ids[longest_ramming], 0.) * double(nozzles.size() - 1));
|
||||
}
|
||||
|
||||
// Both wall types decide this together: over-reserving only wastes bed area, but reporting
|
||||
// no tower for one that is built collapses the validation hull to a point.
|
||||
// A tool change is a reason on its own (see the base commit); Type1 already reserves
|
||||
// per filament, Type2 has only the volume, which can resolve to zero.
|
||||
const bool has_purge = type1 ? !purges.empty() : volume > EPSILON;
|
||||
if (!has_purge && filaments_cnt < 2 && !need_wipe_tower)
|
||||
return footprint;
|
||||
|
||||
const double min_depth = WipeTower::get_limit_depth_by_height(float(max_object_height));
|
||||
const float perimeter_width = float(nozzle_diameter) * 1.25f; // Width_To_Nozzle_Ratio
|
||||
// With nothing to purge, plan_tower_new sizes the tower for wrapping detection or the
|
||||
@@ -171,7 +169,10 @@ WipeTowerFootprint estimate_wipe_tower_footprint(const ConfigBase &config, WipeT
|
||||
if (!purges.empty())
|
||||
side = WipeTower::estimate_rib_tower_bbox_side(purges, float(width), float(layer_height), float(nozzle_diameter), float(extra_spacing), float(rib_width), float(extra_rib_length), float(max_object_height));
|
||||
else {
|
||||
const double square = has_purge ? std::sqrt(volume / layer_height * extra_spacing) : idle_depth;
|
||||
// Type2 squares the tower from its purge volume; Type1 with no purge list (a lone
|
||||
// filament kept for timelapse or wrapping) sizes for the idle depth.
|
||||
const bool has_purge = !type1 && volume > EPSILON;
|
||||
const double square = has_purge ? std::sqrt(volume / layer_height * extra_spacing) : idle_depth;
|
||||
side = WipeTower::rib_footprint_side(float(square), float(square), float(rib_width), float(extra_rib_length), float(max_object_height));
|
||||
}
|
||||
footprint.width = footprint.depth = side;
|
||||
|
||||
@@ -335,6 +335,10 @@ TEST_CASE("The shipped defaults size the tower from the flush matrix", "[WipeTow
|
||||
const double flush_volume = WipeTower2::estimate_semm_flush_volume(config, 2);
|
||||
const double expected = std::max(double(WipeTower::get_limit_depth_by_height(5.f)), flush_volume / (0.2 * 50.));
|
||||
CHECK_THAT(estimate(config, 2, 0.2, 5.).depth, WithinAbs(expected, 1e-6));
|
||||
|
||||
// The flush volume is nonzero for one slot, but a lone filament makes no tool change.
|
||||
REQUIRE(WipeTower2::estimate_semm_flush_volume(config, 1) > 0.);
|
||||
CHECK_THAT(estimate(config, 1, 0.2, 5.).depth, WithinAbs(0., 1e-9));
|
||||
}
|
||||
|
||||
TEST_CASE("A config missing a tower key falls back to that key's default", "[WipeTowerEstimate]") {
|
||||
|
||||
Reference in New Issue
Block a user