Includes nozzle-diameter guards for printers without nozzle info (#13255,
now landed upstream) and manual-calibration nozzle mismatch fix (#13882).
# Conflicts:
# src/slic3r/GUI/GCodeViewer.cpp
# src/slic3r/GUI/GLCanvas3D.hpp
# src/slic3r/GUI/Tab.cpp
* fix: restore version placeholder in custom G-code
PlaceholderParser sets "version" in its constructor, but Print::apply() calls clear_config() which wipes it. Unlike timestamp/user (restored during G-code export), version was never restored, so [version]/{version} threw "Variable does not exist" in custom G-code while working in output filenames.
Re-set version after both clear_config() calls so it resolves everywhere.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: resolve timestamp and user placeholders in File header G-code
file_start_gcode is processed via print.placeholder_parser() directly, before the G-code parser integration copy that restores timestamp/user. As a result {timestamp}, {year}..{second} and {user} threw "Variable does not exist" in the File header G-code field while working in Machine start/end G-code.
Inject fresh timestamp and user into the file_start_gcode config so they resolve, matching the other custom G-code fields.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: expose initial_extruder and extruded_*_total placeholders in output filenames
PrintStatistics exposed initial_tool (not its documented alias initial_extruder) and total_weight/extruded_volume (not the documented extruded_weight_total/extruded_volume_total). Filename formats using the missing names failed with "not a variable name".
Add the missing aliases to PrintStatistics::config() and placeholders().
Fixes#12436Fixes#10708
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: populate total_toolchanges without a wipe tower
total_toolchanges is documented as available while change_filament_gcode (and the wipe-tower toolchange flow) is evaluated, but it was sourced only from WipeTowerData::number_of_toolchanges, which stays -1 (clamped to 0) when no wipe tower is generated. Manual filament swaps and toolchanger/IDEX setups without a wipe tower therefore always saw total_toolchanges = 0 in custom G-code and output filenames, despite real tool changes occurring -- breaking the placeholder's documented contract.
Add a tool-ordering fallback: when number_of_toolchanges < 0, count tool changes from the print's tool ordering (the transitions in the per-layer extruder sequence). Wipe-tower prints are untouched -- number_of_toolchanges >= 0 still wins -- so their reported count does not change.
Limitation: sequential (by-object) prints without a wipe tower leave Print::tool_ordering() empty, so total_toolchanges stays 0 there (unchanged from before).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(viewer): Display travel distance and move count in G-code summary
This commit introduces a new feature that enhances the G-code viewer by displaying the total travel distance and the total number of travel moves in the 'Line Type' summary.
This provides users with more detailed statistics about their prints, helping them to better understand the printer's behavior and identify opportunities to optimize travel moves for faster print times.
This commit also fixes a critical bug in the G-code processor where the travel distance was being calculated incorrectly. The distance variable was not being updated for non-extruding travel moves, leading to inaccurate statistics. The calculation has been corrected to ensure it is performed for all relevant move types, resulting in accurate travel distance reporting.
* Subfix segments
kilo mega giga tera peta exa
* Add missing values
* Grams to Kilos and tons
* add distance
* Fix tool view
* Record and display seam distances
Track seam-related distances in print statistics and show them in the GCode viewer. Added total_seam_gap_distance and total_seam_scarf_distance to PrintEstimatedStatistics (with initialization). In GCode::extrude_loop the code now computes seam gap and scarf distances and accumulates them for external perimeters. GCodeViewer uses the summed seam distance when the Seams option is selected in the legend.
* Fix travel / wipe distances
* Update GCode.cpp
* Filament changes estimated time
---------
Co-authored-by: Steve Scargall <37674041+sscargal@users.noreply.github.com>
* Base IS Machine
* Toggle line
* Rebase
* Intento 1
* Wiki IS
* Flavorized
* Tooltips
* Calibration using the same list
* max
* Reorder JD validation
* Refactor set input shaping
* Calibrations IS
* Default values
* Axis
* Orca comments
* Rename input_shaping_enable to input_shaping_emit
Refactor all references of the input shaping configuration option from 'input_shaping_enable' to 'input_shaping_emit' across the codebase. This improves clarity by better reflecting the option's purpose of controlling whether input shaping commands are emitted in the generated G-code.
Restore DONT EMIT FOR KLIPPER
* Refactor input shaping option toggling logic
Simplifies and consolidates the logic for toggling input shaping related options in TabPrinter::toggle_options(). Uses a loop to handle enabling/disabling lines based on GCode flavor compatibility, and refines the conditions for toggling individual options.
* Improve input shaping option toggling logic in TabPrinter
* GrayOut Emit to gcode limits for klipper
* Typo
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Typo
* Skip Y input-shaper when type is Disable
If marlin2 and disabled it will be already disabled at X.
* IS expert
Co-Authored-By: SoftFever <softfeverever@gmail.com>
---------
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: SoftFever <softfeverever@gmail.com>
Fix extrusion of some support layers at wrong Z height
Fixes the issue that PR #12736 (github.com/OrcaSlicer/OrcaSlicer/pull/12736) reverted the changes of PR #13327 (github.com/OrcaSlicer/OrcaSlicer/pull/13327)
This PR supersedes #12225, which originally proposed this feature but
appears inactive.
The feature originated from work I developed earlier in
[BambuStudio-ZAA](https://github.com/adob/BambuStudio-ZAA), a private
fork of Bambu Studio
Compared to #12225, I updated the implementation for current upstream
and fixed the following issues:
- fixed broken tests
- removed references to nonplanar directory
Reviewers may want to compare against #12225 for earlier
discussion/context.
## Summary
Port of **Z Anti-Aliasing (ZAA)** from
[BambuStudio-ZAA](https://github.com/adob/BambuStudio-ZAA) to
OrcaSlicer.
ZAA eliminates visible stair-stepping on curved and sloped top surfaces
by raycasting each extrusion point against the original 3D mesh and
micro-adjusting its Z height to follow the actual surface geometry. The
result is visibly smoother domes, chamfers, and shallow slopes — without
post-processing.
## How It Works
1. The slicer runs normally, then a **posContouring** step processes
each layer
2. `ContourZ.cpp` raycasts every extrusion point vertically against the
source mesh
3. Each point's Z is adjusted to the mesh intersection, converting flat
`Polyline` paths into `Polyline3` paths with per-point Z coordinates
4. The G-code writer emits the adjusted Z values, so the printer follows
the true surface
## Configuration
Five new settings under **Print Settings > Quality**:
| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `zaa_enabled` | bool | off | Master enable/disable switch |
| `zaa_min_z` | float | 0.06 mm | Minimum Z layer height; controls
slicing plane offset |
| `zaa_minimize_perimeter_height` | float | 35° | Reduce perimeter
heights on slopes below this angle (0 = disabled) |
| `zaa_dont_alternate_fill_direction` | bool | off | Keep fill direction
consistent instead of alternating |
| `zaa_region_disable` | bool | off | Disable ZAA for a specific print
region/material |
## Key Changes
- **Core algorithm**: New `src/libslic3r/ContourZ.cpp` (~330 lines) —
raycasting engine
- **3D geometry**: `Point3`, `Line3`, `Polyline3`, `MultiPoint3` extend
existing 2D types
- **Arc fitting**: Templated to work with both 2D and 3D geometry
- **Pipeline**: `ExtrusionPath::polyline` changed from `Polyline` to
`Polyline3`; new `posContouring` step in `PrintObject.cpp`
- **G-code**: `GCode.cpp` writes per-point Z when `path.z_contoured` is
set
- **UI**: ZAA settings exposed in Print Settings > Quality panel
- **Documentation**: `docs/ZAA.md` with usage and implementation details
57 files changed, ~1800 insertions, ~200 deletions.
## Test Plan
- [ ] Load a model with curved top surfaces (sphere, dome, chamfered
box)
- [ ] Enable **Z contouring** in Print Settings > Quality
- [ ] Slice and verify G-code has varying Z values within contoured
layers
- [ ] Build on macOS (verified), test on Linux and Windows
Felix14-v2 PR review feedback (https://github.com/OrcaSlicer/OrcaSlicer/pull/13086#issuecomment-4323696312)
plus the slice-time validation work that follows from his bug list.
UI polish:
- Capitalize "Primary" in display (right-click mode menu, plate tooltip).
Sentinel stays lowercase for wire compatibility.
- Pre-slice-warnings checkbox now uses Orca's ::CheckBox so it matches the
green toggle style of the rest of the IDEX/IQEX configuration page.
- DPI-scaled the IMEXModesCtrl (modes editor) sub-panels, button grid,
text wraps, gcode textarea, and the ghost-tooltip swatch (imgui.scaled).
Legend swatches sized to body-text height for visual balance.
- Primary mode tool buttons in the modes editor are now disabled (read-
only): cycling roles on the IMEX-off mode is a no-op and confusing.
- Modes editor sub-panels now explicitly inherit the app's window-default
dark colour so chromeless ScalableButtons don't render with a visible
light box around their icons on GTK dark themes.
- Per-mode-line reset arrows in the modes editor: each row gets a small
reset bitmap that snaps that row's name+tools+gcode triplet back to the
saved preset's value. matches_config() guard on the page-level reload
prevents the textbox-being-typed-into from being destroyed mid-keystroke.
- New View menu item "Show IDEX/IQEX Toolhead" — toggles the per-carriage
footprint boxes during G-code preview playback. Gated to Preview tab +
IMEX printer; backed by app_config so it persists.
Coordinated config migrations:
- imex_tool_layout and imex_viz_theme migrate from coString to coEnum
(ImexToolLayout / ImexVizTheme). Existing wire format preserved so
saved presets and 3MFs deserialize unchanged. Side-benefit: both now
pick up standard Field rendering and so finally show reset arrows.
Slice-time safeguards (the validation half):
- imex_suppresses_bare_toolchange(parallel_mode, count): suppresses the
slicer's bare T<n> at print-start in any IMEX parallel mode (the user's
imex_mode_gcode + machine_start_gcode owns tool activation there). Mid-
print T<n> emits normally — Print::validate blocks the configurations
where mid-print T<n> wouldn't make sense. Applied to both code paths
inside GCode::set_extruder (the long multi-extruder path AND the
single-extruder path that fires when multiple_extruders=false).
- imex_multicolor_block_reason(): hard-stop validator returning a user-
facing reason string when the active IMEX configuration can't physically
support multi-color. Catches IDEX (1 tool/gantry), 2-tool-active IQEX
(no within-gantry swap topology), and any MMU/AFC lane sharing among
used filaments. Wired into Print::validate as a slice blocker, and into
PartPlate::has_imex_multimaterial_conflict so the plater badge agrees
with the slice block (no more false positives where the badge warns but
the slice goes through).
- New imex_mode_types config option (parallel array to imex_mode_names)
and imex_mode_type_for() helper. Mode-type tag drives behaviour: zones,
ghosts, and validation interpret modes differently per type. Initial
types: "primary", "copy", "mirror", "split". Split modes are explicitly
designed for paired-gantry IQEX multi-color and bypass the gantry-pair
check in imex_multicolor_block_reason (MMU sharing still blocks them).
Test coverage:
- New unit tests cover imex_suppresses_bare_toolchange (4 cases),
imex_multicolor_block_reason (8 cases including IDEX, IQEX 2-/4-tool-
active, MMU sharing, missing primary, Split type), and imex_mode_type_for
(3 cases including legacy fallback). Total: 186 IMEX assertions across
71 test cases, all passing.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Three of the four IMEX physical-vs-logical fixes landed earlier on this
branch (fbc58d2a1d, fa048babeb, a38b95bf45, e11e7d46df) used inline
lambdas / direct loops to translate physical extruder indices to logical
filament slots. No test coverage existed for the specific composition,
even though the underlying primitives (resolve_filament_for_head,
first_filament_for_physical_head) were tested.
Pull two patterns out of Plater.cpp and GCode.cpp into IMEXHelpers as
named helpers, then unit-test them:
imex_primary_logical_from_objects(used_slots_1b, pem, primary_physical)
Walks the plate's used filament slots (1-based) and returns the
first one whose pem entry maps to the primary's physical extruder.
This is what the warning's `logical_for_primary` now delegates to —
moves the "look at object assignments, not pem first-routed default"
behavior introduced in fa048babeb out of the lambda and into a
separately-testable function.
imex_secondary_logical_slots(active_physicals, primary_physical,
plate_head_filament_map, pem)
Iterates IMEX active physicals, skips the one matching primary,
resolves each remainder via resolve_filament_for_head (per-plate
override + first-routed fallback), deduplicates, drops -1 entries.
Replaces the inline loop in GCode::_do_export's is_extruder_used
marking (a38b95bf45 + e11e7d46df).
10 new test cases in test_imex_helpers.cpp cover the cases that
correspond directly to bugs hit:
imex_primary_logical_from_objects:
- AFC primary picks the object's slot (the user's specific bug)
- Multi-color AFC primary returns first input-order match
- Direct extruder primary unambiguous (no MMU)
- No object routed to primary returns -1
- Empty inputs (no objects, empty pem)
imex_secondary_logical_slots:
- Copy mode skips primary, falls back to first-routed
- IQEX 4-mode enumerates all three secondaries
- Per-plate override wins over first-routed
- Drops unrouted physicals + deduplicates
- Only-primary-active returns empty
All [IMEX] + [Variant] + [3mf] regression: 166 assertions / 61 cases.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
a38b95bf45 translated physical -> logical for IMEX active tools but used
resolve_filament_for_head for *all* active tools including the primary.
For the primary, that falls back to first_filament_for_physical_head —
which returns the FIRST logical slot routed to the primary's physical
extruder, not the slot the user actually assigned to the printing object.
On the user's Neo XP 0.6 (pem [0,0,0,0,1,2,3,3]) printing in copy mode
with the object on slot 2 (PLA dark grey):
- tool_ordering correctly marks slot 2 (object's filament).
- The IMEX-marking loop then *also* marked slot 0 (ABS) as the primary's
"first-routed" slot — wrong: slot 0 isn't loaded, slot 2 is.
- Start-gcode template emitted EXTRUDER=260 EXTRUDER2=235 EXTRUDER4=235;
the ABS-temp emission for slot 0 was harmless noise in this macro
design but conceptually bogus.
The primary's filament is already correctly covered by
tool_ordering.all_extruders() — that lists the slots the objects on the
plate are assigned to. Skip the primary in the IMEX-marking loop using
the same pattern as the IMEX PA emission path at GCode.cpp:3265
(translate initial_extruder_id -> physical via pem, skip that physical).
Result on the user's setup post-fix:
- is_extruder_used: slot 2 (object), slot 4 (T1's filament in copy).
- Start-gcode emits EXTRUDER2=235 EXTRUDER4=235 — exactly two temps,
one per active heater, with no spurious ABS bookkeeping.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
is_extruder_used is a logical-filament-slot indexed bool array — start-gcode
templates use it as `is_extruder_used[N]` where N is a logical filament slot
(matches how the rest of the codebase consumes per-filament arrays like
filament_settings_id, nozzle_temperature_initial_layer, etc.).
`tool_ordering.all_extruders()` returns LOGICAL slots and was correctly
marking those. But the IMEX-secondary marking added in 5aa624b025 was
writing PHYSICAL extruder indices straight into the logical array, mixing
index spaces. On any printer with physical_extruder_map size > 1 (MMU/AFC),
this marks the wrong slots and misses the right ones.
Symptom on the user's Neo XP 0.6 (pem [0,0,0,0,1,2,3,3]) in copy mode
[0:P,1:C] with object on slot 2 (PLA):
- tool_ordering marks slot 2 (correct: object's filament).
- IMEX active = [0, 1] (physical T0, T1) → mistakenly marks logical
slots 0 (ABS) and 1 (ASA), neither of which is used.
- Slot 4 (PLA on physical T1, the actual filament that loads on the
secondary in copy mode) is NOT marked.
- Start-gcode template emits EXTRUDER=ABS_temp EXTRUDER1=ASA_temp
EXTRUDER2=PLA_temp; no EXTRUDER4.
- PRINT_START macro reads t4=0, skips heating extruder1 — T1 stays
cold during the print.
Translate physical → logical via resolve_filament_for_head before marking
(per-plate imex_head_filament_map override consulted, with first-routed
fallback when no override is set). This matches what the firmware actually
loads on each carriage during the parallel-mode print, and what the rest
of the IMEX hot path (PA emission, layer-change temperature) already does.
Result on the user's setup post-fix:
- is_extruder_used[2]=true (object), is_extruder_used[4]=true (T1 in copy).
- Start-gcode emits 2 temps for the actually-used filaments.
- extruder1 heats correctly to slot 4's temp before the print begins.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Brings in the IMEX test coverage (PA per-firmware, Temperature per-firmware,
[Variant] expansion, 3MF round-trip, imex_pem_tool_for helper + tests, and
the cherry-picked variant-truncation regression test).
Resolution notes:
- Two GCode.cpp call sites for set_pressure_advance had divergent edits:
* tests/imex-coverage rewrote them to use the new imex_pem_tool_for
helper (commit c2492ccc47), eliminating the inline parallel-mode
check entirely.
* feedback replaced the literal "primary" with kImexPrimaryMode in the
same lines (commit 085f5ccec8).
Resolution: keep the helper-call form. The kImex change is moot on lines
the helper replaces, and imex_pem_tool_for in IMEXHelpers.cpp is also
updated to use kImexPrimaryMode for consistency with the rest of the
codebase.
- Test test_3mf.cpp updated for upstream's load_bbs_3mf signature change
(PR adds is_orca_3mf out-parameter between is_bbl_3mf and file_version).
All three call sites in the new IMEX 3MF round-trip tests pass &is_orca
in addition to &is_bbl.
Full regression post-merge:
libslic3r: 143 cases / 48,553 assertions (+10 cases from new tests)
fff_print: 24 cases / 245 assertions (+10 cases from new tests)
sla_print: 21 cases / 14,100 assertions
libnest2d: 14 cases / 488 assertions
slic3rutils: 3 cases / 3 assertions
All tests pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
GCode.cpp's static get_imex_active_tools() inlined its own "phys[:role]"
tokenizer with subtly different semantics from IMEXHelpers'
parse_imex_active_tools — only the GCode version bounded against
MAXIMUM_EXTRUDER_NUMBER. Three other call sites (PartPlate zones,
GCodeViewer legend, Plater warnings) routed through parse_imex_active_tools
already.
Move the bounds check into parse_imex_active_tools so all consumers get
it consistently, then rewrite get_imex_active_tools to do only the
Print-extraction portion (active mode lookup, tools-string fetch) and
delegate token parsing to the helper. Keeps Print out of IMEXHelpers'
include set.
No behavior change for the non-pathological case (mode strings have always
parsed identically); for indices >= MAXIMUM_EXTRUDER_NUMBER (64) the three
older call sites silently filter them out now where previously they would
have accepted them — this matches what get_imex_active_tools already did.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Across 6 files the literal "primary" string was the sentinel for "no IMEX
parallel mode active" — used for short-circuiting in serialization, ghost
visualization, zone calc, popup-menu list construction, the IMEXModesCtrl
non-deletable first row, and several layer-of-export checks. A typo in
any one would silently bypass the guard.
Define kImexPrimaryMode in IMEXHelpers.hpp with a docstring describing
what equality with it means semantically, and route every call site
through it. No behavior change.
Touched: bbs_3mf.cpp, GCode.cpp, PartPlate.cpp, Plater.cpp, Tab.cpp.
The bbs_3mf and Tab files now include IMEXHelpers.hpp; the other three
already did.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
af59501f4a ("feat: firmware-agnostic per-tool PA emission for IMEX
parallel modes") inadvertently deleted the BBL-specific PA emission for
initial_non_support_extruder_id while adding IMEX per-tool PA support.
That deletion was scope creep into core BBL functionality and not part
of the IMEX feature.
Restore the original block verbatim. The new IMEX-parallel-modes PA
emission (per-secondary-tool, gated on m_imex_parallel_mode) is left
untouched — that's legitimately IMEX scope. BBL printers in non-IMEX
mode now get back the pre-PR initial-PA behavior.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The physical_extruder_map translation used by IMEX per-tool PA emission was
inlined identically at two sites in GCode.cpp (tool-change and second-layer
transition). Extract to IMEXHelpers so the routing rule ("parallel mode AND
populated pem → physical index, else -1") is testable in isolation and the
call sites read as intent rather than re-deriving the conditional.
Production change is behavior-preserving:
- Same predicate (`!mode.empty() && mode != "primary"`)
- Same empty-pem short-circuit returning -1
- Same get_at() dispatch on hit
- Both call sites replaced with a single call
Four unit tests in [IMEX] cover the routing matrix:
- non-IMEX ("") and primary mode short-circuit
- parallel mode + empty pem short-circuits (defense-in-depth; get_at would
throw on empty values otherwise)
- identity pem (non-MMU IDEX) routes filament to itself
- MMU collapse routes multiple logical slots to one physical (7-slot profile
with 4-lane MMU on physical 0 and direct drives on 1/2/3)
All IMEX + Variant regression suites pass post-refactor (133 assertions / 48
cases under libslic3r, 25 assertions / 6 cases under fff_print [PressureAdvance]).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Add extrusion role change G-code options
Introduces new G-code options for handling extrusion role changes at the process and filament levels. Updates configuration, GUI, and GCode logic to support 'process_change_extrusion_role_gcode' and 'filament_change_extrusion_role_gcode', allowing custom G-code insertion when the extrusion role changes.
Co-Authored-By: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>
* Optimize extrusion role-change gcode handling
Cache gcode template strings and current filament id, and guard creation of DynamicConfig/placeholder processing behind a check that at least one role-change gcode is non-empty. This avoids redundant config lookups and DynamicConfig/placeholder parsing when no custom role-change gcode is defined, improving clarity and performance without changing behavior.
---------
Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>
In some rare support edge cases, Orca could start extruding a new layer before moving to the correct Z height.
This happened when two support layers were generated back-to-back and the next layer started exactly where the previous one ended. In that situation, there was no movement that naturally updated the Z position first.
The code was clearing the “pending layer change” flag too early, so it lost track of the fact that a Z move was still required.
This change ensures that if a layer change is still pending, Orca will always move to the correct Z height before the first extrusion of that layer.
This guarantees that every layer starts at the correct height and fixes the missing / incorrect support layers seen in those edge cases.
Adjust initial- and slowdown-layer speed logic to correctly account for raft layers. Replace the previous layer checks with object_layer_over_raft(), simplify initial-layer speed selection, and split the slow_down_layers interpolation into separate branches for configurations with and without rafts so the lerp uses the correct layer offset. Also avoid applying overhang speed adjustments to object layers that are over rafts.
# Description
This commit adds the enhancement of https://github.com/OrcaSlicer/OrcaSlicer/issues/13116
- Adds checkboxes to enable or disable the fan speed override during print or after printing is completed. This allows users to, for example, only override the fan speed during printing whilst leaving the fan speed as is set in the machine gcode at the end.
- Two new flags are added for this: `activate_air_filtration_during_print[extruder]` and `activate_air_filtration_on_completion[extruder]`. These can be used to more finely control machine gcode
- Current filament settings remain as they are: `activate_air_filtration[extruder]` settings are unaffected and by default both new flags are set to true, ensuring the same set behavior as before.
# Screenshots/Recordings/Graphs
<img width="856" height="208" alt="Screenshot From 2026-04-09 18-57-14" src="https://github.com/user-attachments/assets/e71e7de3-2def-4046-b5dc-55bf3b516ce5" />
As you can see there are now checkboxes left of the fan speeds. They have their own tooltip too, which also helps identify the correct flags for users who want to adjust their machine gcode.
## Tests
I have thoroughly tested this on my own computer (CachyOS) and on my printer. I have also carefully checked the gcode in every possible state this is in and ensured that the unsaved changes dialog properly displays the labels for these settings. Flags are set properly, sliced files properly use the flags if you check for them in machine gcode and default behavior is unaffected for those who have already changed settings for air filtration. From what I can see, this does exactly what it should be doing without any issues.
* make initial layer travel move acceleration and jerk configurable
* Update spelling to match UI pattern
* Update min integer and re-order to match patterns
---------
Co-authored-by: Thomas Scheiblauer <tom@sharkbay.at>
Co-authored-by: Ioannis Giannakas <59056762+igiannakas@users.noreply.github.com>
Replaces the plater-icon popover with colored transparent ghost copies
of primary-head instances on the plate, one per secondary active head
under its Copy/Mirror role transform. Left-click on a ghost opens a
compact filament picker popover for the ghost's head (MMU lane override).
Ghosts track the primary through drag/rotate/scale/mirror and invalidate
on mode or pem changes.
Key pieces:
IMEXHelpers -- imex_head_transform (Primary/Copy/Mirror), shared role
parser, per-head filament resolution with X-axis Mirror anchor.
PartPlate -- ghost state, volume rebuild on mode/map/object mutation,
primary_origin plumbed for Mirror reflection across the primary-row
gantry plane.
GLCanvas3D -- ghost rendering with per-head filament color and
translucent blending; picking routed via volume composite id.
Plater -- ghost click + tooltip; plater icon left-click always cycles.
IMEXFilamentPickerPopover -- BitmapComboBox row for one secondary head,
writes imex_head_filament_map on selection.
bbs_3mf -- round-trip the per-plate imex_head_filament_map option.
PrintConfig -- add imex_head_filament_map as a plate option.
MMU/AFC routing for parallel modes relies on the printer profile's
physical_extruder_map (see prior commit for authoring format). Primary-
row heads and their per-plate filament overrides are resolved through
that map, so PA and temperature emission address the correct physical
extruder when multiple logical slots share one carriage.
Tests: IMEXHelpers coverage for Primary/Copy/Mirror transforms
including a 2x2 off-row regression guard for the X-axis reflection fix.
Auto-populate physical_extruder_map (0-indexed) from printer_extruder_id
(1-indexed) in Print::apply(). The guard only runs when the map is still
at default size (<= 1 element), so printer profiles that set it explicitly
are untouched.
All IMEX parallel-mode PA and temperature emission now routes tool slot
indices through physical_extruder_map before constructing firmware
extruder qualifiers (EXTRUDER=, M104 T, M572 D). This ensures AFC/MMU
setups where multiple slots share one physical extruder get the correct
qualifier -- e.g. T6 on physical extruder 3 emits EXTRUDER=extruder3
instead of EXTRUDER=extruder6.
Profile authoring for MMU/AFC printers:
Add physical_extruder_map to the printer profile JSON as a 0-indexed
string array, one entry per logical filament slot, whose value is the
physical extruder carrying that slot. The array size must be > 1 for
the explicit map to override the auto-derive. Example for a 7-slot
printer with a 4-lane MMU on extruder 0 and three independent direct
drives on extruders 1/2/3:
"physical_extruder_map": ["0","0","0","0","1","2","3"]
Non-MMU printers need no action -- printer_extruder_id already encodes
the 1:1 mapping and the auto-derive handles it.
Deeper integration (zone validation, collision detection, filament
assignment grouping, Moonraker agent auto-population) is deferred.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extends set_pressure_advance() with an optional tool index (default -1,
preserving existing behavior for all non-IMEX call sites). Per-firmware:
- Klipper: EXTRUDER=extruder[N] when tool >= 0, bare command otherwise
- RRF: M572 D<N> when tool >= 0, bare M572 otherwise (no D0 fallback)
- Marlin 2: M900 K<X> T<N> when tool >= 0, bare M900 otherwise
- Marlin Legacy / fallback: M900 K<X> always
Adds m_imex_parallel_mode to GCode, set once per export from the active
plate mode. PA and layer-transition temperature tool-qualification are
gated on this being a non-primary parallel mode — primary mode prints
use regular tool-change PA exactly like any non-IMEX printer. Secondary
active tools in parallel modes receive explicit per-tool PA at print
start since they never go through a tool-change sequence.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Temperature emission (GCode.cpp, PrintConfig.cpp, ConfigManipulation.cpp):
- Set temperatures for all active tools in layer_change_gcode for iMEX
parallel modes (primary + secondary carriages)
- Fix filament temperature commands so Layer 1 temperatures only emit on
the first layer; subsequent layers use normal layer-change temperatures
- Remove stray temperature commands that fired outside the intended context
- Consolidate iMEX temperature handling into the second-layer transition;
clean up emission logic and naming throughout
Pre-slice warning dialogs (PartPlate.cpp/hpp, Plater.cpp):
- Collect per-plate IMEX warnings before slicing: multi-material conflict,
bed temperature mismatch between carriages (>5 °C delta), and filament
type incompatibility
- Show a dismissible Yes/No dialog from both "Slice Plate" and "Slice All"
actions; No returns to 3D view, Yes proceeds to slice
- Refresh plate thumbnails after the panel switch so previously-generated
thumbnails are not left black
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
In iMEX (IDEX/IQEX) parallel printing modes (copy/mirror), only the
primary extruder generates toolpaths. The firmware duplicates the
primary's movements for secondary carriages, so they don't appear in
tool_ordering.all_extruders().
This caused is_extruder_used[N] to return false for secondary tools
even though they're physically active and moving.
The fix adds logic to parse the active mode's tool assignments from
imex_mode_active_tools config and marks all assigned tools as used.
Changes:
- Added null checks and bounds validation for config options
- Skip empty tool strings to avoid unnecessary parsing
- Reordered bounds checks for defensive programming
- Added clarifying comments for exception handling
This ensures is_extruder_used[N] is true for all tools in a parallel
mode, allowing printer profiles to correctly enable heaters and
emit cleanup G-code for all active carriages.
Fixes: is_extruder_used[1] returns false in copy/mirror modes (#13086)
Related: Comment [28]/[30], Comment [18] (is_extruder_used in G-code header)
Register imex_mode (string), imex_mode_index (int), and imex_mode_gcode
(string) in OtherSlicingStatesConfigDef so they appear in the placeholder
search UI under Slicing State.
Set all three via placeholder_parser().set() before any script processing
in _do_export(). Process imex_mode_gcode first so {global} declarations
defined there flow forward into machine_start_gcode.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
IMEXModesCtrl:
- Primary mode is now a non-deletable first row stored as sentinel
"primary" in imex_mode_names; older configs load cleanly
- New rows default T0 → Primary when no tool assignment is stored
- Filter "primary" from plater popup/cycle list to prevent double entry
- imex_tools_per_gantry cap raised 2 → 4
Zone sizing:
- Zone width/height now based on active tool count only; inactive tools
donate their bed share to active neighbors (fixes 4-tool layout)
- Active col/row maps (col_to_zone/row_to_zone) applied consistently
across zone fills, collision strips, and primary zone box
GCodeViewer animation:
- Mirror position formula fixed: left-of-copy reflects across copy
zone's left edge; right-of-copy reflects across right edge
(T3 was rendering on top of T1)
- strip_width/row_strip_height use active counts, matching PartPlate
Stability:
- Early return in calc_imex_zones() when tool_states is empty; prevents
OOB crash on new printer with stale process-preset mode name
- is_imex toggle in on_config_change calls refresh_imex_icons() so the
plate mode icon appears without requiring a new project
GCode:
- Remove "primary" guard so Primary mode gcode field is emitted at
start of print
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>