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:
SoftFever
2026-09-19 12:46:00 +08:00
committed by GitHub
2 changed files with 14 additions and 9 deletions
@@ -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]") {