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>
Code review items (raistlin7447):
1. PrintObject::slice() zeroes m_belt_min_z, m_belt_global_z_offset and
m_belt_global_xy_correction before slicing. They were only written in belt
mode, so a project switched to a normal printer, or whose tilt axis was set
to None, kept the old offsets and shifted the adaptive infill octree and the
organic support layers by them.
2. TreeModelVolumes shifts the support blockers into the raft-offset index
space; a test now pins the index the blocker lands on.
3. The final-alignment clamp in libnest2d is opt-in (NfpPConfig::clamp_to_bin)
and arrange sets it for belt printers only. Printers with an off-centre
best_object_pos keep their alignment; a flat-bed test pins that.
4. The preview's belt view follows the loaded G-code, not the selected printer:
GCodeProcessor carries the file's belt keys (and, for a belt file, its bed)
into export_config_for_render(), and GCodeViewer enables the belt view from
the header tilt.
5. belt_shift_layer_grid() also shifts the cached belt floor and the global Z
offset, so a support-only or brim-only change after the purge-prism snap
matches a fresh slice.
6. update_print_fff_config() resets raft_layers and draft_shield on a belt
printer instead of only greying out the fields Print::validate() rejects.
7. GCodeWriter takes a first-layer point test instead of the FirstLayerPlane;
GCode installs one that measures from the belt surface, like its
extrusions, so the first-layer travel speed and the second-layer
temperature change no longer depend on the gcode_remap_* convention.
8. belt_brim_clip_leading_edge() is exported and called by both the generator
and the test.
9. Both phong.vs shaders use slope.up_direction for the overhang highlight.
The pre-slice and G-code axis remaps are gated on belt_printer through
BeltTransformPipeline::axis_remap_enabled(), so belt keys left in a profile
cannot change a non-belt print.
Tests requested in the review: belt-only keys at non-default values leave
non-belt G-code unchanged; switching a sliced project from belt to non-belt
(and tilt axis None) matches a fresh slice; a support-only change on a belt
purge print matches a fresh slice; non-belt start G-code moves keep the
first-layer Z in the processor; the belt brim's segment count catches a band
emitted twice.
The belt-to-non-belt test exposed an unrelated gap: invalidate_step(posSlice)
re-invalidated posSupportMaterial but not posSimplifySupportPath, so after
any re-slice the regenerated support paths were exported unsimplified.
posSimplifySupportPath is now in that list.
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
* initial commit
* fix upper bounds for assemblies
* significantly less Z shift issues, still not quite tamped down yet though
* add instrumentation to logs
* finally found the issue
* update printer defaults
* minor logic swap
* first attempt, has a race condition
* fixed the offset issue
* found a solution, I think things work now (at least once I quash this race condition)
* still chasing down race conditions
* add manual shear / scale order strategy swap
* tweak manual shear, fix ui uninitialization crash
* fix z height / g-code desync issue
* fix shear then scale cutoff planes
* getting closer
* fix support termination planes
* fix incorrect offsets in shear-then-scale mode
* test - fix overextrusion due to model/layer scale