mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-11 09:51:06 +00:00
f0778ef5fa5a770a9887df12cffd9ff842befb1b
8
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
f0778ef5fa |
fix(imex): shorten the off-primary message and block blended filaments
The routing error ran to roughly 450 characters and explained the mechanism before it got to the remedy. It also offered to "edit the mode in Printer Settings so its Primary tool is one of %3%", which on a plate whose filaments resolve to no head at all rendered as "one of no configured extruder". Cut it to the mode, the tool it prints with, where the plate's filaments actually are, and the two things the user can do about it. The second msgid that named candidate modes went with it. It could only suggest a mode whose primary is among the routed heads, and every mode on the printers this fires for declares 0:P, so it had nothing to offer. Blended filaments now return before that check rather than falling through it. A blend is mixed at the nozzle by its component toolheads, and a parallel mode is already using those toolheads to print copies or mirrors, so the two cannot run at once regardless of where the components route -- including when a component sits on the declared primary. Reaching the routing rule would also have described them wrongly: mixed slots sit past the end of physical_extruder_map, so they resolve to no head and read as merely unrouted. Keeps the empty-list guard the shortening first dropped. validate() reads the raw physical_extruder_map, whose registered default is a single entry, so a profile that declares IMEX modes without authoring a map leaves every slot past the first outside it -- and the sentence ended in a dangling "on .". Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
baef398ee3 |
fix(imex): refuse a plate whose filament cannot reach the mode's primary tool
The IMEX primary tool prints the sliced paths directly, so it can only load a filament that physical_extruder_map routes to it. The ghost filament picker enforces that for the secondary tools -- it offers only lanes whose pem entry equals that head -- but the primary's filament comes from the ordinary object filament selector, which has no IMEX awareness. Nothing detected the mismatch: collect_imex_warnings() computes the same condition and discards it into a display fallback, and the multi-color rule never examines it. Block it in Print::validate() via the existing imex_primary_tool_for_mode and imex_primary_logical_from_objects helpers. The message names the declared primary, the heads the plate's filaments actually live on, and any configured modes whose primary would work, and carries the object so the notification can offer a jump to it. Blocks rather than warns, matching the multi-color rule: the plate is not printable as configured, and where the routed head is also absent from the mode's active tools the 1st->2nd layer temperature branch skips it too, leaving that head at its initial-layer temperature for the whole job. The multi-color check now runs first. Its constraints -- an MMU manifold sharing one head, a single-gantry mode -- cannot be fixed by switching mode, so the more specific error should win rather than be masked by routing advice that leads straight back to it. The extruders().size() > 1 gate moved onto that call, since the routing check must also see single-filament plates, which is its common case. The copy-mode guard-rail test printed on a filament routed off the primary, so it asserted a plate this rule now refuses; retargeted to a well-formed plate. Its replacement pins the object's own extruder, because ModelVolume reports its extruder_id and would otherwise put a primary-routed slot on the plate. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
ef8d80980d |
fix(imex): enumerate no secondary carriages in single-tool primary mode
get_imex_active_tools returned every physical head named by the active mode's tool string, including the one carrying the Primary role. The pressure-advance and nozzle-temperature sites are already gated on the mode not being primary, so only the is_extruder_used supplement was exposed. In primary mode that supplement treated the mode's single declared tool as a secondary carriage and marked its filament slot used, so machine_start_gcode emitted a heat command for an extruder that never prints. The phantom slot appears when the mode's declared tool differs from the head the initial tool routes to through physical_extruder_map -- on an AFC/MMU layout, printing with a filament that lives on any head other than the declared one. Return an empty roster for primary mode, where there are no parallel carriages by definition. This lives in the enumerator rather than at the call site because the mode is already resolved and normalized there, and the two guarded callers cannot reach it in that mode, so their behaviour is unchanged. Scope: this closes the primary-mode instance. The same phantom slot still occurs in a parallel mode when the initial tool's head is not the mode's declared Primary, which turns on which of the two notions of "primary" the three emission sites should skip. That question is unresolved and deliberately left alone here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
c94e8324d0 |
fix(imex): give the printing head its second-layer temperature in parallel modes
The IMEX branch of the 1st->2nd layer temperature transition is mutually exclusive with the standard per-extruder path in its `else`, but it skipped the head carrying the print's own toolpaths on the premise that "the standard per-extruder temp path already addresses it". That path is the `else` branch and never runs for a parallel mode, so the printing head received no transition at all and held nozzle_temperature_initial_layer for the entire job. Emit for every carriage the mode drives, the printing one included. The printing head takes this layer's own filament; the parallel carriages, which carry no toolpaths of their own, keep resolving through the per-plate head map with pem inversion as the fallback. The lookup now goes through get_filament_config_index() like the standard path, since a variant-expanded printer gives a filament its own column and a raw index would read the wrong one. Reproduced on a 4-carriage IQEX in copy mode: the only temperature command in the whole file set the idle secondary carriage to the value it already had, while the head doing the printing never left its first-layer temperature. The defect is invisible whenever initial and regular temperatures match, which is why earlier per-tool validation passed. Tests cover both gantry counts, since the active set comes from the mode's tool roster: an IDEX copy mode drives two carriages, an IQEX mode drives four, and the IQEX case asserts a first-layer filament and a second-layer transition for each of the four. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
8e243faa3a |
Fix Linux unit test failure in the wipe tower temperature trace comparison (#15161)
## Problem `Toolchange temperature commands are unchanged when the wipe tower wait is off` (added in #15144) fails on both Linux runners and passes on Windows and macOS. It is the only failing test in the suite, and it has been failing on main since that PR merged. | Job | Result | | --- | --- | | Windows x64 / Unit Tests | pass | | Windows arm64 / Unit Tests | pass | | macOS arm64 / Unit Tests | pass | | Linux x86_64 / Unit Tests | **fail** | | Linux aarch64 / Unit Tests | **fail** | From the merge commit ([Linux x86_64](https://github.com/OrcaSlicer/OrcaSlicer/actions/runs/31072382258/job/92531704095), [Linux aarch64](https://github.com/OrcaSlicer/OrcaSlicer/actions/runs/31072382258/job/92531704075)), still reproducing on current main: ``` first difference at trace entry 29 main: M104 S240 T0 ; preheat T0 time: 31s lead 30.9s branch: M104 S240 T0 ; preheat T0 time: 30s lead 30.3s ``` ## Cause Each preheat entry records the same quantity twice: `lead` at one decimal, and `time:` inside the command text as that value rounded to a whole second. `split_lead` already compares `lead` with a 0.5s tolerance and explains why the estimate moves. `time:` sits in the exactly-compared command text, so it never got that tolerance — and being rounded, it flips on a drift far below 0.5s (30.4 and 30.6 render as `30s` and `31s`). Entry 29 is the only entry in the 163-entry golden whose lead rounds up; every other preheat sits at 30.0–30.4 and rounds down, which is why it is the only one that fails. The variation is per-toolchain, not run to run. Both Linux arches produce exactly `lead 30.3s`; Windows x64/arm64 and macOS arm64 all produce exactly `30.9s`. Repeated local runs are byte-identical. macOS arm64 passing while Linux aarch64 fails rules out the ISA — it is floating-point accumulation over a few thousand move durations under GCC vs Clang vs MSVC. The mechanism makes it discrete rather than gradual: the backtrace parks the preheat at the first exported line at least `preheat_time` before the tool change, so `lead` is `preheat_time` plus the leftover of whichever move that landed on. A sub-tenth difference selects the neighbouring move and `lead` steps by that move's whole duration. Entries 1–28 match exactly, including five earlier preheats whose leads fall inside the existing tolerance, so the toolpaths themselves are identical. I also reverted the two prime-tower commits that landed between the golden's capture point and now, rebuilt, and got a byte-identical trace — this is not behavioural drift. That also rules out regenerating the golden: no single capture satisfies all three toolchains, and recapturing on Linux would turn the three currently-green runners red. ## Fix Test-only. - `lead` keeps a tolerance, widened to 1.5s (measured drift 0.6s; a preheat actually leaving its backtrace position would move by tens of seconds). - `time:` is **not** compared across runs at all. Being a rounding of `lead`, it carries nothing the tolerance does not already cover, and comparing it across runs can only reproduce the flake. It is instead checked against its own entry's `lead` — a correct rounding keeps `|time - lead| <= 0.5`. That second point matters: simply tolerating `time:` numerically would have made the test blind to a real change, because drift and a wrong rounding both move it by 1. The self-consistency check keeps that coverage. I verified it by changing `(int) std::round(time_diffs[0])` to `(int) time_diffs[0]` in `GCodeProcessor::export_lines` — the test fails with `"time:" is not its entry's "lead" rounded to a whole second`, where a plain tolerance would have passed silently. Everything else is still compared exactly: all M104/M109 values, tool ids, block markers, ordering, entry count, and the annotation text including its trailing `s`. The other 138 entries remain byte-exact. No production code, no golden regeneration. The golden file and these helpers are used by this one test and nothing else, and the tolerance only widens, so Windows and macOS keep passing unchanged. A note is added to the golden's header so the next mismatch in those fields is not "fixed" by recapturing. ## How to verify Before, on Linux: ```bash git checkout main && ./build_linux.sh -t ctest --test-dir build/tests -R "Toolchange temperature commands are unchanged" --output-on-failure # fails at trace entry 29 ``` After: ```bash cmake --build build --config Release --target fff_print_tests ctest --test-dir build/tests --output-on-failure # 463/463 ``` |
||
|
|
408db4b3b0 |
Wait for the toolchange temperature on the wipe tower
Adds a printer option that picks up the new tool without a blocking temperature wait, travels to the wipe tower, and waits there right before purging, parked beside the tower so the ooze from the heat-up lands next to it rather than on the model. The incoming filament's target is raised ahead of the tool change, so the heat-up overlaps both the change itself and the travel to the tower. Off by default, and only offered for multi-extruder printers using a Type 2 wipe tower; the generic toolchanger profile enables it. |
||
|
|
6fda82476d |
fix: out-of-bounds read computing tool-ordering max layer height (#14665)
* fix: out-of-bounds read computing tool-ordering max layer height calc_max_layer_height() loops over the extruder count (nozzle_diameter) but indexes max_layer_height with the same counter, reading past the end when that array is shorter. Silent on release builds, aborts under a bounds-checked STL (_GLIBCXX_ASSERTIONS). Read via get_at(), which falls back to the first entry when the index is out of range, as Slicing.cpp already does for this option. Add a fff_print regression test slicing a two-extruder printer with a single-entry max_layer_height. * docs: clarify how max_layer_height ends up short in the regression test Normalization sizes it to the filament count under single_extruder_multi_material, not "a mismatch a profile can ship" as the earlier comment guessed. |
||
|
|
29f31b9b38 |
fff_print: a maintainable testing framework (proposal + coverage) (#14426)
* fix: initialize Print::m_isBBLPrinter
Built outside the GUI/CLI (headless tests, embedded use) the member was read
uninitialized: is_BBL_printer()/wipe_tower_type() feed it into ToolOrdering,
which then non-deterministically dropped per-feature filament assignments.
Default it to false, the value the GUI and CLI already assign for non-Bambu
printers.
* docs(test): add the fff_print testing contract
tests/fff_print/README.md codifies how the suite is organized: one file per
subsystem (each owning both in-memory and emitted-G-code assertions), flat
behavioral test names with a single [Subsystem] tag, a robust-tests guide,
the shared helpers, and an add-a-test checklist. Linked from tests/CLAUDE.md.
* test(fff_print): reorganize the suite to the contract and add coverage
Bring every subsystem into one file per the README: rename the test_data
harness to test_helpers; consolidate skirt/brim; split multi-filament and
cooling into their own files; disperse the test_printgcode grab-bag and the
end-to-end smoke scenario into focused tests; fold test_gcode into
test_gcodewriter. Standardize names and tags, align cube tests on the cube()
helper, and de-qualify the flagship files.
New coverage: multi-filament per-feature and per-object routing; a skirt/brim
behavior matrix (the #14333 rework, including brim ears, with regression
coverage for #14319 and #14366); resolved extrusion-width and config
comments; custom-G-code placeholders; fan control and speed-marker
consumption.
Re-enable three slice tests previously tagged [NotWorking]: the clipper
"Coordinate outside allowed range" error that disabled them was specific to a
past CI runner environment and no longer reproduces.
* test(fff_print): tag arm64-flaky skirt/brim tests NotWorking
Four skirt/brim slice tests intermittently throw ClipperLib's "Coordinate
outside allowed range" on the macOS and Windows arm64 CI toolchains (an FP
divergence, not a slicing bug; see PR #14207). Linux x86_64 and aarch64 are
unaffected. Tag them [NotWorking] so ctest -LE NotWorking skips them.
* test(fff_print): re-enable the arm64 skirt/brim tests
These were tagged [NotWorking] as a stopgap when myfork's daily-driver build
combined them with the cross-platform CI on a base that predated upstream's
m_origin fix (
|