* Rebuild the G-code line offsets after post-processing scripts run in place
* Clamp the G-code window reads to the mapped file size
* Add tests for rebuilding the G-code line offsets
* Include <mutex>, <ios> and boost/filesystem/operations.hpp where they are used
* Keep the preview's G-code lines and highlight in step with post-processing scripts
---------
Co-authored-by: SoftFever <103989404+SoftFever@users.noreply.github.com>
Co-authored-by: SoftFever <softfeverever@gmail.com>
The slicing frame of a belt object started at its lowest vertex, but the
belt under the leading end of an overhang lies below that, by the
overhang's length times the tilt's shear. Every support generator works
in layers at z >= 0, so none of them could reach it: normal supports
stopped at the object's own lowest layer, and the two tree generators
each carried a stack of hacks to extend themselves below it (a post-hoc
copy of the lowest base area in TreeSupport, "virtual belt raft layers"
in TreeSupport3D/TreeModelVolumes), sized from the pre-rotation bbox
and capped at global z = 0, which is only right for the trailing half
of the belt.
Start the frame at the lowest belt-floor point under the footprint
instead, less a 10 mm margin along the belt for the base of a support
column (BeltSliceStrategy::apply_preslice_transforms and
BeltTransformPipeline::compute_belt_height_and_floor agree on it). The
layers between it and the first vertex come out empty, which belt
slicing already tolerates, and the generators need no extension at all:
- normal supports: the generator anchors its layer grid at the frame
origin, so run it in the object frame and shift the global belt Z
offset onto the result afterwards, as organic supports already did.
With the offset on the object layers a top contact at negative z
turned the intermediate-layer count negative and the generator
allocated layers until the kernel killed it (any overhang in the
leading half of the belt). Drop the first-layer flange expansion on a
belt: the first support layer is the leading tip of the support, not
a flange, and inflating it put lines in the air ahead of the belt.
- classic tree: a node now keeps dropping until its whole circle is in
the belt, so the branch tapers to a tip on the belt instead of
stopping, a radius above it, when its centre crosses.
- organic: the belt is no longer a support blocker. A blocker is a
collision, and a branch descending onto one slides off it, down the
tilted belt and ahead of the part; the belt is where branches end,
which the per-layer m_belt_floor clipping already does.
The belt brim is generated after the parallel support step instead of
inside it: belt_brim_obstacles() reads every object's layers and support
layers, which another object's support step rebuilds (and, now, shifts)
at the same time. This is the race behind the Windows arm64 segfault
in "Belt brim of each object precedes its perimeters on its own
filament".
Also: the belt tilt axis moves to Developer mode as its own row (a
shared line is shown by its first option's mode), first_layer_plane
band thickness, belt_support_floor_mode, belt_preslice_global and
gcode_back_transform are retired and presumed on, the gravity arrow is
a plain line along the up direction, and the "Show raw G-code (belt
only)" preview toggle is gone.
Regression test: "Belt supports reach the belt under a leading
overhang" slices a cube with a fin whose underside is parallel to the
layers, 20 mm ahead of the cube and up to 41 mm of slicing Z above the
belt, for normal, organic and classic tree supports, and checks that
the lowest support layer sits on the belt beneath its own lines.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Removed, with the keys added to handle_legacy()'s ignore list so saved
profiles and 3MFs keep loading:
- belt_slice_rotation_global and preslice_remap_global. Both were only
consulted when belt_preslice_global ("Global mesh transforms") was off,
which no profile does; belt_preslice_global is now the single global
mode and is presumed on everywhere the old flags were ORed in
(PrintObjectSlice, BeltBackTransform, BeltGCode, Print::process,
PrintApply). The Belt tilt row is axis + angle only.
- preslice_remap_x/y/z. No profile used the pre-slice axis remap; the belt
tilt axis plus the G-code axis remap cover the machines that exist, and
its implementation only agreed with itself for a plain swap (matrix
columns vs remap_bbox rows). BeltTransformPipeline::build_preslice_remap,
remap_bbox and has_preslice_remap are gone, the forward transform is the
rotation, and the G-code header no longer carries the remap.
- belt_support_z_offset_mode. Saved and invalidated steps, but no support
generator read it.
- first_layer_plane and first_layer_plane_offset, with FirstLayerPlane.cpp.
On every shipped configuration the band is measured from the belt
surface (GCode::belt_height_above_floor) and the evaluator was only
reached for an explicit XY/YZ/XZ choice or a non-zero offset, which
nobody set. first_layer_plane_thickness stays as the band unit,
relabelled "First layer band thickness".
UI: the Machine frame transforms group is five single-option rows (G-code
remap X / Y / Z, Decouple machine-frame tilt, Machine-frame tilt angle;
the angle row is shown only when decoupled) instead of two multi-column
lines, and the remap fields carry full labels.
Also carries the phong.fs struct fix from #16226 so the worktree build
links its shaders.
libslic3r_tests and fff_print_tests pass; clang-tidy diff check clean;
orca_profile_tool.py check clean.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The clang-tidy job on #14394 fails on 129 misc-include-cleaner findings:
the belt sources and tests use std::, Eigen, Point/PrintConfig and
BeltBrim symbols without including the header that provides them, which
only compiled because the precompiled header supplied it. Every include
the job names is added, in each file's existing include style ("../" in
the GCode/ and Support/ subdirectories, quoted libslic3r/ paths in the
GUI and tests). No code changes.
Verified with scripts/clang_tidy_diff.py -p build-tidy --base eb5b9a77b9
(SLIC3R_PCH=OFF compile database, clang-tidy 22.1.8): no findings left.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L6Kg5igmmMU2YLoK6HrsWV
* Remove Unused Project Includes and Forward-Declare Where a Type Is Only Referenced
Generated with include-what-you-use and applied conservatively. Only OrcaSlicer's own headers, the ones under src/ and tests/, are removed or forward-declared; standard-library and third-party includes are left alone. An include is removed only when both the Release and the Debug configuration leave it unused, never from inside a conditional block, and never from a file with platform-specific blocks, which only gain includes. Files whose only use of a header sits behind a feature or debug macro (libvgcode's OpenGL ES and marker code, the ARACHNE/TESTS_EXPORT_SVGS debug output) keep their includes.
clonable_ptr.hpp gains #pragma once; it had no include guard and was only safe while Config.hpp was its sole includer.
* Remove Unused Project Includes From Files With Platform-Specific Code
A Linux include-what-you-use run cannot see the code inside _WIN32, __APPLE__ or __linux__ blocks, so its verdict is only taken where nothing the removed header declares, directly or through what it includes, is named inside those blocks. Removals also have to hold in both the Release and Debug configuration and never touch a line inside a conditional block.
* Restore the libslic3r Precompiled Header and Direct Includes Lost in the Platform Pass
The platform-file pass treated pchheader.hpp as an ordinary header and
emptied it, and left GUI_Preview.hpp and 14 other files relying on
headers they no longer reached directly.
* Restore MainFrame.hpp in ParamsDialog.cpp for the Windows-Only Reparent Call
* Include Headers That Files Reached Through Ones the Cleanup Removed
* Drop Includes Duplicated by the Cleanup or by Main's Own Additions
* Leave PreciseSeam.cpp as Main Has It After the Precise Seam Rework
Brings belt-printer up to main 4b4a261787. Resolutions:
- G-code header (#15897, #15915): main moved the header, config and
thumbnail block later in _do_export; write_belt_header() moves with it,
still after the thumbnails and outside the BTT_TFT gate.
- _extrude: first-layer acceleration keeps the per-path first-layer plane
test with main's cached nozzle index (#16028); main's set_speed out-param
form (#16108) everywhere else.
- GCodeWriter (#16108): the arc-to-polyline fallback for machine mappings
that cannot express G2/G3 now runs in the out-param extrude_arc_to_xy,
which is the overload GCode calls, and appends to the caller's string.
- GCodeProcessorResult: the belt fields join main's forwarding assign.
- Clipper2 (#15969): belt arrange helpers take Slic3r::Point; the tree
support join types lose their ClipperLib qualifier.
- CLI arrange (#15837): belt printers still reserve no wipe tower.
- Wipe tower options (#15841): the two new sparse-layer toggles are hidden
for belt printers like the rest of the tower options.
- Keyboard shortcuts (#15706): main's registry replaces the old key switch;
the belt view toggle is re-registered in the next commit.
- Print::process: the belt purge-plan undo runs before main's SliceStarted
event.
- scripts/filament_id_snapshot.json: deleted on main (a77209af8f).
- Includes and appended tests: union of both sides.
Every file that included STEP.hpp, directly or not, got namespace fs = boost::filesystem at global scope, and 29 sources and three headers relied on it without saying so. Headers now spell out boost::filesystem, and each source that uses fs declares the alias itself.
The purge plan snaps every object onto one layer grid after the brim is built;
the per-layer brim bands follow their layers but the apron bands below the
first layer carry their own print_z and were left behind, which is why a brim
was refused next to a purge tower object. The shift now moves them too and the
combination is accepted again.
* Add Missing Includes Across src/libslic3r
Every libslic3r source and header now directly includes the headers declaring what it uses, rather than relying on the precompiled header or transitive includes. Generated with clang-tidy misc-include-cleaner, with libslic3r headers spelled libslic3r/... so they resolve outside the library's private include paths. MultiMaterialSegmentation.hpp, Support/SupportParameters.hpp and Format/STEP.hpp are made self-contained by hand.
* Make the libslic3r Headers Compile on Their Own
Each now includes, or forward-declares, what it uses instead of relying on what its includers happened to include first. Left out: I18N.hpp, which errors on purpose when included from GUI code, and VoxelizeCSGMesh.hpp and SLA/bicubic.h, which nothing includes and which no longer compile at all.
* Add the Includes Missing From the Hand-Fixed libslic3r Headers
clang-tidy would not edit these headers while they failed to compile on their own, so the first pass skipped them. With the headers now self-contained, a second pass adds the rest.
* Keep Windows Setup Ahead of the Added libslic3r Includes
Print.cpp and Thread.cpp open with a _WIN32 block that has to come first; without the precompiled header, Print.cpp otherwise reaches windows.h through OCCT with NONLS defined and boost/regex fails. OpenVDBUtils.cpp and SLA/SupportTreeBuilder.cpp had includes inside #ifndef NOMINMAX, which libslic3r defines on Windows, so those were skipped there. .clang-tidy also ignores the MSVC STL and UCRT internals, Boost.Multiprecision's fwd.hpp and CPython's Windows include directory.
* Re-Add libslic3r Includes After the Clipper2 2.0.1 Migration
Rebasing onto main took main's version of the files the Clipper2 migration rewrote, so their added includes are restored here, along with includes for main's new code. Clipper2's individual headers are now ignored by clang-tidy: they only build the Z variant through clipper2_z.hpp, which defines USINGZ first, so including clipper.core.h and the like directly broke ClipperZUtils.cpp.
A tool change added from the layer slider switches heads mid-print like a
painted color, but the parallel-mode checks only looked at the filaments of the
plate's objects, support and prime tower. A one-filament plate with a slider
change to a copying head's filament passed them. They now include those tool
changes, as the plate's warning badge already did.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Three commits: G-code export caches its filament config slot and repeated
option lookups, per-plate bed type overrides follow the printer's multi-bed
support, and the gizmo checkboxes and texture displacement panel get styling
and refresh fixes. No conflicts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The purge plan moves objects onto a common layer grid after the brim bands are
built, so the two cannot share a print. The prime tower setting alone still does
not block a brim. The missing-prism warning now counts the filaments the objects
use, as the GUI does.
The purge tower is a model object the GUI creates and sizes, and libslic3r
only purges into one that exists. A multi-filament belt project sliced from
the CLI without it changed filament with nowhere to purge, silently.
Raised in Hanif Koh's review of #14394.
enable_prime_tower stays on for any multi-filament project, but a belt
printer never prints the classic tower and the belt purge prism is an
ordinary object that never takes a brim, so every brim on a multi-filament
belt print was refused for nothing.
Raised in Hanif Koh's review of #14394.
validate() skipped the build-volume height check whenever the machine-frame
transform was active, which is every shipped belt profile, so a 400 mm
object passed on a 300 mm printable_height. The transform only changes how
the height is written to G-code; the clearance check from f682ab5cd3
applies regardless.
Raised in Hanif Koh's review of #14394.
138 commits. The count is large because texture displacement merged with its
whole branch history behind it, going back to July, alongside config and preset
file locking across instances, a foundation for configurable printer agent
connections, and a day of smaller fixes and CI work.
Two conflicts, both the same shape: each side had appended to a sorted list and
git could not choose an order. libslic3r's CMakeLists gained InstanceLock
alongside our IMEXHelpers and IMEXZones, and the preset bundle loading test
gained an include for ParallelResolve alongside ours for IMEXHelpers. Both sides
kept, alphabetical. No logic conflicted.
Verified: 740 targets build clean under -Werror, and the Release suite passes
1740 of 1740, up from 1665 -- the 75 new cases arrived with the merge and all
pass. That mattered more than usual here, since preset loading and config
locking are both areas the IMEX preset code touches.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Brings in upstream/belt-printer (the Sept 14 main merge) plus Hanif Koh's
21 review-fix commits from PR #15685, on top of the MachineKinematics
refactor and the purge-prism / tree-support / first-layer-speed fixes.
Conflict resolution:
- BeltGCodeWriter is gone (kinematics refactor), so Hanif's plate-offset
fix for it is ported into GCodeWriter: the first-layer-plane checks in
travel_to_xy / travel_to_xyz / _travel_to_z now evaluate the plate-local
point, and BeltGCode::init_belt_writer hands the stored plate origin to
the writer it installs.
- init_belt_writer(Print&) takes Hanif's signature; the BBL flag is set on
the surviving writer by GCode::_do_export.
- The shared emit_belt_brim_bands() loop keeps the BeltFloorObjectGuard the
local branch added, so apron bands classify first-layer height against
their own object.
- eager_lift keeps effective_type: it now carries set_force_normal_lift().
- GCodeWriter's initializer list follows Hanif's member order with
m_kinematics in its declared position.
- TreeSupport::detect_overhangs uses Hanif's clamped build_plate_tilt_slope()
for the non-belt path and the belt shear for the belt path.
Fan speeds, multi-tool ramming, the tower interface and flush temperature
fallbacks and the custom G-code placeholders now use the extruder variant a
filament prints with on each layer, instead of reading by filament id.
Upstream moved pressure advance onto the extruder variant: enable_pressure_advance,
pressure_advance and the four adaptive keys joined filament_options_with_variant,
the repeated inline blocks in set_extruder() became a helper, and the lookups
moved from the filament id to get_filament_config_index().
All three conflicts were the same collision, because this branch had modified two
of those same inline blocks to pass a tool qualifier so each carriage is addressed
explicitly in parallel modes. Taking either side whole would have lost something:
upstream's drops the qualifier and leaves parallel carriages with no pressure
advance, ours drops the per-variant indexing and reads the wrong column on a
multi-variant printer. The helper now takes an optional tool, defaulting to -1,
which omits the qualifier. imex_pem_tool_for() already returns -1 off IMEX and in
primary mode, so non-IMEX output is unchanged, and the three call sites that never
passed a tool keep upstream's behavior exactly.
The third conflict was two test cases appended at the same place. Both are kept.
Separately, one defect that merged cleanly and so was not flagged: the loop that
emits pressure advance for secondary carriages at the start of a print still
bounded and indexed those vectors with a raw filament id. They are variant
expanded now, so their length is columns rather than filament slots -- the value
read was the wrong column, and the bound no longer sat in slot space, letting an
out-of-slot filament through. It now bounds on filament_diameter and translates
with get_filament_config_index(), which is what the sibling second-layer
temperature loop already does.
Verified: both changed translation units compile clean under -Werror. The merge
was resolved independently twice and the two resolutions agree on every line of
code. Not yet run: the Release test suite and a parallel-mode slice sweep.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Pressure advance, adaptive pressure advance and its model can now take a
different value for each extruder variant of a filament, such as Standard and
High Flow nozzles, like the other per-variant filament settings. Projects
saved with one value per filament apply it to every variant of that filament,
and the addnorth BBL filaments in the Orca Filament Library are updated to the
per-variant layout.
The two conflicts are both places where upstream landed on top of IDEX/IQEX
code. In GCode.cpp the relocated file header block meets the IMEX placeholder
block, and the placeholders are set first: file_start_gcode is processed through
the placeholder parser now, which throws on a name it does not know, so a script
naming {imex_mode} would abort the export if the header ran first. In
test_multifilament.cpp both sides appended a case at the end of the file.
# Description
Extruder variants (Standard, High Flow, extra high flow) now work on any
printer. Any vendor profile can declare them, and a multi-variant
filament picks up the right variant on every printer. In the sidebar,
users can switch the printer variant and set the nozzle volume type of
each extruder on multi-extruder printers. This also fixes a later
filament printing at the first filament's temperature on a P1S or X1C
with a High Flow nozzle. The profile checks now reject variant arrays of
the wrong size and outdated variant strings. Every shipped vendor
profile passes them, and the orca-profiles skill documents the rules.
Slicing output changes only where the wrong variant was used before.
# Screenshots/Recordings/Graphs
<img width="393" height="218" alt="Screenshot 2026-09-28 at 11 28 07 PM"
src="https://github.com/user-attachments/assets/8bee4b0e-c38c-4039-8c11-096ace6fbad0"
/>
<img width="448" height="267" alt="Screenshot 2026-09-28 at 11 28 37 PM"
src="https://github.com/user-attachments/assets/e767cd97-a5d0-4728-b010-c8ea2bc94ca7"
/>
<img width="746" height="603" alt="Screenshot 2026-09-28 at 11 28 54 PM"
src="https://github.com/user-attachments/assets/23c8af3b-c679-46e5-9fd0-2e43df0449b3"
/>
https://github.com/user-attachments/assets/10d75d72-86a3-42e8-8a95-b1627bd58e91
## Tests
<!--
> Please describe the tests that you have conducted to verify the
changes made in this PR.
-->
<!--
> 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)
G-code generation collects errors raised per object, such as an empty
first layer, into one SlicingErrors exception whose own message is just
"Errors". The CLI's generic handler printed that word and recorded the
generic slicing error text, so a headless caller had nothing to act on.
Let Print render the per-object messages with each object's name, and have
the CLI catch SlicingErrors ahead of the generic handler, print that text
and record it as the result's error string. The exit code is unchanged. A
unit test lifts a cube off the bed and checks the message names the object.
A coEnum config value has two representations: the typed ConfigOptionEnum<T> a
config cloned from the static classes carries, and the ConfigOptionEnumGeneric
that a config assembled from the option definitions creates - which is what a
preset, a project's own settings and the CLI all hold. imex_cfg_enum() accepted
only the first, so every IDEX/IQEX reader took the option default instead: a
printer saved as rear-left came back front-left in the settings, the bed zones
and the carriage markers, while the preset on disk still held rear-left.
Read the generic form too, keyed on the value map it carries, since only T's own
map yields a T. The last reader that matched on the coEnum tag alone and cast
across the two hierarchies now goes through the helper with everything else.
Declaring the three keys the static classes were missing is what lets a change
to imex_tool_layout invalidate the slice it moves, which it never did before.
The two that are only ever drawn stay out of that: a colour scheme and the
advisory margin bands do not reach a slice, so changing one must not discard it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Four files overlapped, and each resolution favours upstream where the two sides
had done the same work:
WipeTower's M104/M109 tool qualifier. Both sides bounds-checked the physical
extruder map lookup; upstream omits the T qualifier when the map cannot answer,
where this branch fell back to the logical index and so named a carriage that may
not be the one printing. Upstream's behaviour is what this branch documents
elsewhere, so its version is taken and the local helper is dropped.
get_extruders' mixed-slot switch. Upstream added the same concept to the CLI
overload as expand_mixed_slots, so the GUI overloads' parameter is renamed to
match rather than carrying two names for one idea.
GLCanvas3D's sequential-clearance branch gains upstream's
update_compacted_wipe_tower_clearance for the by-layer case.
The printer_agent re-sync in TabPrinter::reload_config was upstream's and their
preset-undo fix removed it, so it goes; the IMEX modes grid re-sync beside it
stays, since it spans three options and is not a Field.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Toolchange Cyclic Order
* Apply cyclic order to first layer
* Unit test
* Copilot fixes
---------
Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>
gcode_back_transform, first_layer_plane* and belt_printer_infinite_y fell through to invalidate_all_steps(), which re-ran tool ordering, skirt/brim and G-code export on toggles that only affect G-code export.
Merge origin/main (00429da739) into belt-printer.
Conflicts resolved:
- src/CMakeLists.txt: keep both wxInspector workarounds.
- GCodeProcessor.cpp: keep the belt compare_pos / z_for_height lines.
- PrintObjectSlice.cpp: the belt bbox-Z guard also covers main's
printable_region_ids bookkeeping.
- TreeSupport.cpp: the belt-floor check runs before main's PendingNode
queueing.
- Tab.hpp: keep the belt fields, drop the removed upload description
fields.
- tests/libslic3r/CMakeLists.txt: keep both test files.
Also included:
- eSUN PLA belt presets declare their own filament_id (OFkrxQC4) and
scripts/filament_id_snapshot.json is regenerated, as main's filament_id
check requires.
- Custom.json version bumped to 02.04.00.05 so the belt entries reach
existing installs.
- Fix the ambiguous WithinRel call in the belt apron width test, which
otherwise breaks the fff_print build.