Commit Graph
31915 Commits
Author SHA1 Message Date
harrierpigeonandClaude Opus 5.5 679638fca3 Belt G-code: correct the first-layer point test comment
The comment said the lambda takes off "the instance part" of m_origin.
On a belt m_origin has been rotated by on_set_origin() by then, so
m_origin minus the plate offset is not the instance shift.  Say what the
code does: undo what point_to_gcode() added and what the writer took
off.  Comment only.

Reported by raistlin7447 in the review of #14394.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 13:40:52 -05:00
harrierpigeonandClaude Opus 5.5 d29e3be0a0 Belt G-code: drop the empty layers in one place
The by-layer collect_layers_to_print() dropped every merged layer group
in which nothing prints, and the per-object overload drops every belt
entry that prints nothing.  The merged groups are built only from the
per-object entries, so after the second drop every group holds at least
one entry that prints and the first never removed anything.  Remove it
and keep its explanation at the drop that does the work.  No output
changes.

Reported by raistlin7447 in the review of #14394.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 13:40:52 -05:00
harrierpigeonandClaude Opus 5.5 c59eb1bcf9 Belt brim: cut the leading-edge brim at the first layer on the belt
The leading-edge-only brim is the outer brim cut down to the part's first
contact with the belt.  The cut was taken at the first layer with
geometry, but with an overhang on the leading side that layer is the
overhang's tip, which is sliced before the part reaches the belt and
does not touch it.  The cut then lay ahead of the part: a 30 mm fin
left a sliver of brim well ahead of a 20 mm cube, and a 40 mm fin, or a
leading brim length of 0, left none at all.

The footprint loop already finds the layers that touch the belt (their
contact band is not empty); record the first of them and cut there.

The new test slices a cube with and without a 30 or 40 mm fin over its
leading end and checks that the leading-edge brim is the same.  It fails
without the fix.

Reported by raistlin7447 in the review of #14394.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 13:40:52 -05:00
SoftFever 6edc858f8b Merge branch 'main' into belt-printer 2026-10-09 00:55:12 +08:00
Ian Chua 67a16dabca fix: prompt for permission when plugin tries to create a thread (#16248)
* fix: prompt for permission when plugin tries to create a thread

* fix: request permission on main thread
2026-10-08 23:49:33 +08:00
SoftFever 5072f6b614 Merge branch 'main' into belt-printer 2026-10-08 23:03:56 +08:00
Ian Bassi 59fc97fb28 Extend Separated Infills (#16274) 2026-10-08 09:43:46 -03:00
LixNix 7d44b60ae4 H2D X2D Multi Nozzle Size Printing Support (#14125) 2026-10-08 20:28:32 +08:00
ExPikaPakaandExPikaPaka 776ca6a3e4 build_linux.sh: add -J to build several dependencies at once (#16282)
* build_linux.sh: add -J to build several dependencies at once

The top-level deps build is fixed at -j1, so one dependency compiles at a
time while the small ones leave most cores idle. -J N raises that level.

-j still applies in full to each dependency, so the worst case is -J times
-j compile jobs: ninja has no job server to share a pool across the nested
builds. Without -J nothing changes.

* Quote the job count for shellcheck (SC2086)

---------

Co-authored-by: ExPikaPaka <mrfsfyt@gmail.com>
2026-10-08 18:56:02 +08:00
SoftFeverandxxxsam ee26e94170 Fix H2D prints rejected for a missing Filament Track Switch
Fixes #15927

Co-authored-by: xxxsam <31843242+xxxsam92123@users.noreply.github.com>
2026-10-08 17:49:04 +08:00
Ian Chua d401d4f837 revert: profile changes made for OTA testing (#16280) 2026-10-08 16:13:12 +08:00
HanifKoh 18b70844d1 Defer Plugin Dock Panes Until the Plater Is Shown (#16257)
A plugin enabled at startup loads before the main frame exists, so a
dock panel it opens from on_load was dropped by the one-shot CallAfter
that found no plater. Opened a moment later, before the frame was laid
out, the pane was sized against the unsized frame and track_docked_size
kept that width. Poll until the plater is shown on screen, then build
the pane; release the reserved id instead when the app is closing.
2026-10-08 14:18:51 +08:00
HanifKoh c8f2498681 Keep GLCanvas3D Building With SLIC3R_CAD Off (#16256)
The bed-axes toggle added for the Design tab's reference planes reads
m_design_sketch_tool, which only exists under SLIC3R_CAD. Compute the
flag once and read the sketch tool inside the same guard as its other
uses.
2026-10-08 14:02:34 +08:00
HanifKoh 30902561c0 Stop Exporting Names Through Usings in the Remaining Headers (#16250)
The last headers with a using or namespace alias at namespace scope:

- TCPConsole.hpp imported boost::asio::ip::tcp into Slic3r::Utils for
  two member declarations. The alias is now a private member of the
  class.
- WebSocketClient.hpp declared four namespace aliases and a tcp alias
  at global scope, each used only by the header. The names are spelled
  out.
- Repair.hpp aliased CGAL::Polygon_mesh_processing as PMP in
  Slic3r::tex2color. The three functions that use it declare the alias
  themselves.
- PreciseSeam.hpp, Thumbnails.hpp and MarchingSquares.hpp used a
  using-declaration or directive for one or two spots each; those spots
  are qualified. Thumbnails.hpp's "PNG"sv default argument becomes
  "PNG", which converts to the std::string_view parameter the same way.
- tests/sla_print/sla_test_utils.hpp had "using namespace Slic3r;" and
  tests/filament_group/fg_test_serialization.hpp "using json =
  nlohmann::json;" at global scope. The headers qualify their own names;
  the two SLA test sources get the directive themselves.

Also removed: twelve type aliases in headers that nothing references
(ConflictObjName, CircleSqf, CircleSqd, TRawBuffer, DistanceFunction,
SamePair, ExtruderNozzleInfos, Vec2dEvent, Vec2dsEvent, Vec3dEvent,
t_option, t_optgroups, Plater::fs_path) and a duplicate
fn_ft_job_msg_destroy alias in FileTransferUtils.hpp.
2026-10-08 13:59:12 +08:00
HanifKoh 3fc515f48d Prompt for Permission When a Plugin Calls os.exec (#16254)
* Prompt for Permission When a Plugin Calls os.exec

* Add a ProcessReplace Audit Category for os.exec
2026-10-08 13:52:09 +08:00
HanifKoh 6cd5feed79 Remove Duplicate Includes and the Dead GCodeSender Sources (#16249)
46 files include the same header twice at file scope, outside any #if,
66 times in all:
Model.cpp included Model.hpp twice, Utils.hpp <algorithm> and
<string_view> twice, seven GUI headers <wx/dataview.h> and
<wx/artprov.h> twice. The second include of each is removed.

GCodeSender.cpp and GCodeSender.hpp have been commented out of
libslic3r/CMakeLists.txt since 2022 and their only two includes are
commented out as well. Both files go, with the commented lines, and
the CMake entry for SLA/SupportTreeIGL.cpp, a file that no longer
exists.
2026-10-08 13:51:50 +08:00
HanifKoh 09530ef7c4 Size a Project's Mixed-Colour Metadata to the Filaments in the CLI (#16247)
The mixed-colour metadata options are parallel per-slot arrays in the project
config. A project saved before they were sized per slot stores a single value
for the gradient ones, and one saved before they existed stores none. The GUI
sizes all seven to the filament count when it opens a project; the CLI kept
the stored arrays and exported one-element defaults for absent ones, so a
project it exported carried one-element arrays where the GUI writes one entry
per filament. Slicing is unaffected, every reader treats a missing entry as
not mixed / no gradient, but the GUI-vs-CLI comparison reported the four
gradient keys on every mixed-filament project.

The resize helper moves from PresetBundle.cpp, where it was file-local, to
PrintConfig.cpp next to set_filament_dev_options(). It creates an option the
config lacks before sizing it, a no-op for the bundle's project config where
all seven always exist. The CLI calls it with its filament count once the
project and loaded filaments are merged, after the check that every mixed
slot has a filament of its own.
2026-10-08 13:40:36 +08:00
Joseph Robertson ed1537cdeb Belt printer: address the 2026-10-07 review of #14394 (#16277)
## Description

Addresses every item of @raistlin7447's review of 2026-10-07 on #14394
(https://github.com/OrcaSlicer/OrcaSlicer/pull/14394#pullrequestreview-5447529307),
one commit per item, plus a follow-up commit from a second adversarial
pass over the result.

**Organic supports (the one non-belt difference raistlin's export
fixtures found).** The debug-strip commit dda58b07cd had deleted the
loop in `organic_draw_branches()` that trims every branch slice against
the collision volume, the bed and the belt plane. It is restored exactly
as on `main` (plus the belt-floor clip). New test: a cube carrying a 60
mm plate, organic supports, flat-bed printer; on every support layer no
support extrusion may come within 0.2 mm of the part's slice. To be
clear about what it proves: it guards that invariant, but on this
fixture the loop's own effect is a sub-millimetre reshaping of one
branch (checked by running the test with the loop compiled out), so the
test does not by itself fail without the loop. The loop's effect is
shown separately by slicing six organic fixtures with the stripped and
the restored binary (CLI): on a plate-over-cube fixture the stripped
build brings a branch to 0.02 mm from the part's slice at the cube's
corner where the restored build keeps 0.39 mm; the Bulbasaur project
differs in ~2000 support lines; a fixture with no wall near the branches
is byte-identical.

**G-code (belt only).**
- First-layer speed test: the writer passes points with the plate origin
already removed, so only the instance part of `m_origin` is subtracted
now.
- The mixed-filament sub-layer pass calls `on_set_origin()` like the
main instance loop.
- `m_belt_in_band` is reset per object in by-object printing, with the
cooling buffer.
- `m_layer_count` counts only the layers that are written, through the
same predicate `collect_layers_to_print()` uses
(`belt_object_layer_prints_something()`); the by-object overload drops
the empty belt layers as well, so both print sequences write the same
layer changes. The empty-layers test now runs for both sequences and
checks `; total layers count` too. Side effect worth knowing: with the
empty entries dropped per object, a multi-filament belt layer no longer
selects a filament it then prints nothing with. On belt_project.3mf (two
filaments, belt purge tower) the T commands go from 472 to 106 with the
extruded length per filament unchanged; every removed tool change was
followed by no extrusion.

**Invalidation / ordering.**
- `posSlice` now also invalidates `posDetectOverhangsForLift` (not
belt-gated: a re-slice starts the layers over with empty overhang
regions while the step stayed done; this makes an incremental re-slice
match a fresh slice).
- `btLeadingEdgeOnly` takes part in the layer-0 outer-wall-first rule
and the matching `brim_type` → `posPerimeters` rule (not belt-gated:
`Print.cpp` already prints it as an outer brim on a flat bed).
- Adding or removing an object invalidates the support step of the other
belt-brim owners, so their brims are clipped against what is on the
plate now.

**Belt brim (found during the GUI pass, pre-existing since #16236).**
"Leading edge only" produced no brim at all: the cut that narrows the
outer brim to the first contact was taken at `layers().front()`, which
since the lead-in change is an empty layer whose contact lies ahead of
the part, so the whole region was clipped away. The cut is now taken at
the first layer with geometry; `leading_edge_only` joins the
all-brim-types test and a new test checks the brim starts no later than
the part and covers fewer layers than the outer brim.

**UI.** Build plate tilt X/Y are read-only on a belt printer (they are
derived from the belt tilt). The belt temperature tower refuses a range
without an embossed model, before the project is replaced, instead of
falling back to the 230–190 model.

**Strings, dead code, comments.** Tooltip and comment say cot and
1/|sin| (what `MachineFrameTransform.cpp` does); `gcode_remap_*` labels
and tooltips are `L("literal")` so they are extracted; removed
`belt_remapped_bbox()`, `belt_min_z()`, `m_belt_global_xy_correction`,
`LayerTools::has_belt_brim`, the `belt_surface_z` constant, and (second
pass) the unused kinematics inverse (`to_logical`,
`apply_axis_remap_inverse`, `to_build_volume` and their state), the
`world_coordinates()`, `is_active()` and `belt_brim_areas_by_layer()`
accessors and two unused overloads; rewrote the comments that still
described removed code (BeltBrim.cpp SEQUENCING, GCodeWriter.hpp,
calib.cpp/hpp, GCode.hpp, BeltSliceStrategy, PrintObjectSlice.cpp,
PrintApply.cpp).

Not changed, noted for a follow-up: the outer-wall-first rule keys on
numeric layer 0, which on a belt is usually an empty lead-in layer, so
the part's first contact layer does not get the rule; and a
leading-length-only brim (zero base width) is excluded by the
`brim_width > 0` test. Both need a geometry-based rule rather than a
one-line change.

## Screenshots/Recordings/Graphs

Build plate tilt fields greyed out on a belt printer, the temperature
tower error dialog, and the brim before/after deleting a neighbouring
object are attached below (from the Xvfb GUI pass).

## Tests

- `fff_print_tests`: all cases pass (includes the new organic test and
the extended empty-layers test in both print sequences);
`libslic3r_tests` pass.
- Organic test run with the loop compiled out (temporary local switch):
passes either way on this fixture, see above; the CLI comparison on six
fixtures is where the loop's effect is visible.
- `OrcaSlicer_profile_validator -s` on the belt vendors and Prusa as
control; `scripts/orca_profile_tool.py check`; profile tool unit tests
(281).
- `scripts/clang_tidy_diff.py` against `belt-printer`: clean.
- GUI pass on Xvfb (Linux): tilt fields greyed/editable with belt
on/off; temperature tower error for 250–200 leaves the project
untouched, 230–190 loads the tower; multi-colour demo by layer 595
slider layers = 595 layer changes with matching labels and no greying
while dragging; two cubes by object 314 = 314; outer brim complete after
deleting the neighbouring cube; organic supports clear of the part on
the belt preset and on a flat-bed variant; raw G-code toggle via menu
and `B` keeps the slider index; no crash or assert in the logs. The
leading-edge brim finding from this pass is fixed above.

OS: Linux (Ubuntu), GCC, local build. Written with AI assistance (Claude
Code), every change reviewed and tested locally as listed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-10-07 21:45:56 -05:00
harrierpigeonandClaude Fable 5.1 ed8c1f92d7 Belt brim: cut the leading-edge brim at the first contact layer
The leading-edge-only brim is the outer brim cut down to the part's
first contact with the belt, and the cut was taken at layers().front().
Since the slicing frame starts at the belt below the footprint (#16236)
that is an empty lead-in layer whose contact lies ahead of the part, so
the cut removed the whole region and the brim type produced no brim at
all.  Take the cut at the first layer with geometry.

The all-brim-types test now includes leading_edge_only, and a new test
checks that the brim starts no later than the part and covers fewer
layers than the outer brim.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 19:08:59 -05:00
harrierpigeonandClaude Fable 5.1 cfad587c2d Belt: follow-ups from a second review pass
Guard the layer count and the per-object layer collection against an
object that is left without a layer to print on a belt (the counting
loop stepped before begin() and front() was taken of an empty vector).
Check the belt temperature tower's embossed model before the current
project is replaced, not after.  Only invalidate the support step of
objects that own a belt brim when an object is added or removed.  The
empty-layers test now counts an extrusion only where material is laid
down along a move.  The BeltBrim.cpp SEQUENCING note says exactly which
layers are read, and the machine-frame scale is 1/|sin|.

Remove more code that nothing calls: the kinematics inverse
(to_logical, apply_axis_remap_inverse, to_build_volume and the state
kept for them), the world_coordinates(), is_active() and
belt_brim_areas_by_layer() accessors, the PrintConfig overload of
physical_tilt() and the DynamicPrintConfig overload of
compute_belt_height_and_floor().  Comments in GCode.hpp,
BeltSliceStrategy.hpp/.cpp and PrintObjectSlice.cpp that described the
retired pre-slice remap and plane-evaluator still did; the purge-tower
width tooltip named the wrong switch.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 19:08:59 -05:00
harrierpigeonandClaude Fable 5.1 a564ec23fe Belt: refresh comments that described earlier code
BeltBrim.cpp still described the brim as running inside the parallel
support step; it runs sequentially after it (generate_belt_brim).  The
GCodeWriter, calib.cpp and calib.hpp comments referred to an inheritance
layout and a dynamic_cast that no longer exist.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 19:08:59 -05:00
harrierpigeonandClaude Fable 5.1 441113cf3b Belt: remove dead code
belt_remapped_bbox() had no callers; belt_min_z() and
m_belt_global_xy_correction were written but never read;
LayerTools::has_belt_brim was set but never read; belt_surface_z was a
named zero.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 19:08:58 -05:00
harrierpigeonandClaude Fable 5.1 1fb585dc5c Belt config: fix the tilt tooltip math and extract the remap strings
The machine-frame transform is a shear of cot(tilt) and a scale of
1/sin(tilt), not tan and 1/cos; fix the tooltip and the matching comment
in BeltGCode.cpp.  The gcode_remap_* labels and tooltips were passed
through L() as variables inside a lambda, which the string extraction
does not see; pass L("literal") at the call sites.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 19:08:58 -05:00
harrierpigeonandClaude Fable 5.1 e78f437ce4 Belt temperature tower: refuse a range without a model
The calibration fell back to the 230-190 tower when no embossed model
existed for the requested range, so the printed numbers did not match
the temperatures.  Show an error naming the range and stop instead.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 19:08:58 -05:00
harrierpigeonandClaude Fable 5.1 798ca8272e Printer settings: build plate tilt is read-only on a belt printer
update_fff() derives build_plate_tilt_x/y from the belt tilt on a belt
printer, so a value typed into those fields was silently overwritten.
Disable the two fields while belt_printer is on.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 19:08:58 -05:00
harrierpigeonandClaude Fable 5.1 d5cfaae5dd Belt brim: adding or removing an object rebuilds the other objects' brims
A belt brim is clipped against the other objects on the plate and is
built with its object's support step.  When an object was added or
deleted only the print-level skirt/brim and export steps were
invalidated, so the remaining objects kept brims clipped against objects
that were no longer there, or overlapping ones that had arrived.
Invalidate posSupportMaterial on every object in that case on a belt
printer.  Also reword the comments that still described the global Z
offset as a minimum across all objects.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 19:08:58 -05:00
harrierpigeonandClaude Fable 5.1 9289fc4dd3 Leading-edge brim takes part in the outer-wall-first rule
The first-layer rule that prints the outer wall first when a brim is
attached to it, and the brim_type change rule that regenerates the
perimeters for it, only knew btOuterOnly.  btLeadingEdgeOnly, the belt
brim at the part's first contact, is an outer brim too.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 19:08:58 -05:00
harrierpigeonandClaude Fable 5.1 b2fb552e32 PrintObject: a re-slice invalidates posDetectOverhangsForLift
posSlice's invalidation list did not include posDetectOverhangsForLift.
A re-slice starts the layers over with empty overhang regions while the
step stayed done, so GCode::needs_retraction() had no overhangs to test
against until something else invalidated it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 19:08:58 -05:00
harrierpigeonandClaude Fable 5.1 febd82f6df Belt G-code: count only the layers that are written
collect_layers_to_print() drops the belt layers that print nothing (an
object's empty lead-in), but m_layer_count still counted every object
and support layer, so "total layers count", the total_layer_count
placeholder and the M73 progress disagreed with the layer changes in the
file.  Count with the same predicate, shared through
belt_object_layer_prints_something().  The by-object overload of
collect_layers_to_print() now drops those layers as well, so both print
sequences write the same layer changes.

Dropping the empty entries per object has one more effect on multi-
filament belt prints: a layer no longer selects a filament that it then
prints nothing with.  On belt_project.3mf (two filaments, belt purge
tower) the T commands go from 472 to 106 while the extruded length per
filament is unchanged; each of the removed tool changes was followed by
no extrusion.

The empty-layers test now runs for both print sequences and also checks
"total layers count" against the layer changes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 19:08:58 -05:00
harrierpigeonandClaude Fable 5.1 fba8b8b029 Belt G-code: reset the first-layer band state per object
In by-object printing the cooling buffer is reset for every object, but
m_belt_in_band, which tracks whether the extrusion is inside the band
along the belt where the part fan stays off, kept the previous object's
value.  If the previous object ended inside the band the next one never
emitted its band start marker.  Reset it with the cooling buffer.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 18:24:27 -05:00
harrierpigeonandClaude Fable 5.1 05e37d838c Belt G-code: the mixed-filament sub-layer pass rotates its origin too
process_layer()'s sub-layer pass (several filaments in one layer without
a purge tower) calls set_origin() per instance like the main instance
loop, but not on_set_origin(), which on a belt printer runs the origin
through the belt transform.  Add the call so both passes place the
instance the same way.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 18:24:27 -05:00
harrierpigeonandClaude Fable 5.1 4eaaf9a992 Belt G-code: first-layer speed test subtracts the instance offset only
The writer hands set_first_layer_point_test() a point with the plate
origin (its own XY offset) already removed, but the test subtracted the
whole of m_origin, which carries the plate origin as well as the
instance shift.  On a plate other than the first the point was moved by
the plate origin a second time and the band test looked at the wrong
spot.  Subtract only the part of m_origin that is not the writer's
offset.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 18:24:27 -05:00
harrierpigeonandClaude Fable 5.1 54e079ae25 Organic supports: restore the per-slice collision, bed and belt trim
dda58b07cd stripped debug instrumentation from TreeSupport3D.cpp with a
script, and that script also deleted the loop in organic_draw_branches()
that trims every branch slice against the collision volume, the bed and,
on a belt, the belt plane.  This is the generator every printer uses, not
a belt code path, and it is the one place where raistlin7447's export
fixtures differed from main with belt printing off.  Restore the loop as
it was on main, with the belt-floor clip.

The new test prints a cube carrying a 60 mm plate with organic supports
on a flat-bed printer and checks on every support layer that no support
extrusion comes within 0.2 mm of the part's slice.  It guards that
invariant; on this fixture the loop's own effect is a sub-millimetre
reshaping of one branch (verified by slicing the fixture with and
without the loop), below the asserted gap, so the test does not by
itself fail without the loop.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 18:24:27 -05:00
e729dbf142 Upgrade CGAL from 5.6.3 to 6.2.1 (#16258)
Co-authored-by: Andrei <1331777+andreili@users.noreply.github.com>
Co-authored-by: Amelia <26681721+elihwyma@users.noreply.github.com>
Co-authored-by: Kris Austin <kris.austin@gmail.com>
2026-10-07 20:24:22 -03:00
yw4z 33f886406e Profile folder optimizations (#16259)
* anycubic kobra 3 v2

* bbl

* rh3d

* melting point

* Pragostroj

* prusa

* ultimaker

* creality

* kingroon

* m3d

* wondermaker

* bbl fix plate origins

* update some of creality plates

* Update Creality.json
2026-10-08 01:24:57 +03:00
Kris AustinandRodrigo Faselli c33515914d fix: Create Printer finds no system vendors in release builds (#16175)
Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>
2026-10-07 17:30:36 -03:00
Joseph Robertson d0c2ada32a Belt printer: classic tree branches land on the belt instead of sliding down it (#16263)
Classic tree supports (tree hybrid / slim / strong) on a belt slid down
the belt plane ahead of the part instead of landing on it.
`TreeSupportData` added the belt surface to every layer's outlines, so
the belt fed the collision and avoidance maps, and a node that descends
onto an obstacle is pushed out of it; on a tilted surface that walks the
branch down the belt. This takes the belt out of the outlines. The belt
is where a branch ends, and that is already handled: `drop_nodes()`
stops a node once its whole circle is in the belt
(`belt_node_landed()`), and `draw_circles()` clips every layer's circles
to the belt plane, so the branch tapers to a tip on it. Organic got the
same treatment in #16236 (the belt is no longer a support blocker
there).

One file, +7/−12. Non-belt printers are untouched: the removed block
only ran when the belt floor context was active.

## Before / after

Cube with a fin whose underside is parallel to the layers, 20 mm ahead
of the cube, tree hybrid, Left view:

| | support footprint along the belt | filament for support |
|---|---|---|
| before | belt Z 43–139 (sweeps 72 mm ahead of the part) | 2403 mm |
| after | belt Z 60–139, columns parallel to the up direction | 1606 mm
|

Organic on the same model: belt Z 74–139 (unchanged). Before/after
screenshots follow in a comment.

## Tests

- *Belt supports reach the belt under a leading overhang* passes for
normal, organic and tree_hybrid; all `[belt]` tests pass;
`fff_print_tests` 355 and `libslic3r_tests` 1116 pass on the branch.
- `scripts/clang_tidy_diff.py --base upstream/belt-printer`: no
findings.
- Fork CI (Build all) on this change: unit tests green on Linux x86_64,
Linux aarch64 and macOS arm64
(https://github.com/HarrierPigeon/OrcaSlicer/actions/runs/37601644023;
its Windows and slice-check failures are the ones #16262 fixes).
- Scripted GUI pass on belt-printer + this change: tree hybrid, organic
and normal supports at Y≈120 all reach the belt (lowest 0.17–0.19 mm);
with the part within its height of Y = 0 all three generators now behave
the same (support before the belt start, plate-boundary error shown),
where tree hybrid used to be the odd one out (clipped, hanging 9.5 mm
above the belt).
- Written with Claude Code; reviewed and run by me.
2026-10-07 14:21:34 -05:00
harrierpigeonandClaude Fable 5.1 d527db6bdf Belt printer: classic tree branches land on the belt instead of sliding down it
TreeSupportData added the belt surface to every layer's outlines, so the
belt fed the classic tree's collision and avoidance maps.  A node that
descends onto an obstacle is pushed out of it, and on a belt that walked
the branch down the tilted surface, ahead of the part, before it could
end: tree hybrid/slim/strong supports swept far along the belt where
organic supports dropped straight down.  Take the belt out of the
outlines.  The belt is where a branch ends, and that is already handled:
drop_nodes() stops a node once its whole circle is in the belt
(belt_node_landed()) and draw_circles() clips every layer's circles to
the belt plane, so the branch tapers to a tip on it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 14:15:14 -05:00
Joseph Robertson e39d6cc089 Merge branch 'main' into belt-printer 2026-10-07 14:14:20 -05:00
Joseph Robertson 827efc3bc2 Belt printer: get the branch CI green (Windows Polyline clash, validator belt slice) (#16262)
Two one-file fixes that get `belt-printer`'s CI green again after
#16236; both failures are mine.

## Changes

1. **Tests: qualify `Polyline` in the belt overhang test for Windows.**
Both Windows builds fail at `tests/fff_print/test_print.cpp:1398`
("reference to 'Polyline' is ambiguous"): the GDI function of the same
name, like the `Polygon` fix in #16196. `Slic3r::Polyline`.
2. **Profile validator: slice belt printers with two cubes along the
belt.** The slice check (`-s`) prints one cube per printer with a height
range 4–10 on filament 2 and, on belt printers, expects a plain `T1`.
Since #16236 a belt object's slicing Z starts at the belt below its
leading end, well below the part's first printed layer, so that range
falls into the empty lead-in and filament 2 is never used; all six belt
printers reported "the filament change never fired". Belt printers are
now sliced with two cubes one behind the other along the belt, the
second on filament 2. Other printers are unchanged.

## Tests

- Root cause for both confirmed in the upstream logs (run 37583336264
and the push run on 0b11311d40) and reproduced locally with the rebuilt
validator.
- `OrcaSlicer_profile_validator -s -l 2`: Printcepts 8/8, IdeaFormer
8/8, Custom 20/20 (the four MyBeltPrinter nozzles included), Prusa 95/95
as a non-belt control.
- `fff_print_tests` and `libslic3r_tests` pass;
`scripts/clang_tidy_diff.py --base upstream/belt-printer`: no findings.
- A fork run of Build all with these two commits on top of belt-printer
(plus a pending belt change) was green on every job: Windows x64 and
arm64 builds, Slice check, unit tests on Linux x86_64, Linux aarch64,
macOS arm64, Windows x64, Windows arm64 and both Flatpaks:
https://github.com/HarrierPigeon/OrcaSlicer/actions/runs/37607869527
- Written with Claude Code; reviewed and run by me.
2026-10-07 14:14:06 -05:00
harrierpigeonandClaude Fable 5.1 006a9377c3 Profile validator: slice belt printers with two cubes along the belt
The slice check (-s) prints one 10 mm cube per printer with a height
range on filament 2 and expects the filament change to fire.  Since
#16236 a belt object's slicing Z starts at the belt below its leading
end, well below the part's first printed layer, so the range 4-10 falls
into the empty lead-in and filament 2 is never used: every belt printer
reported "the filament change never fired" and the Slice check job on
belt-printer went red.  A height range in slicing Z does not map onto a
part on a belt in any case.  Slice belt printers with two cubes one
behind the other along the belt, the second on filament 2, which gives
the one plain T1 the check looks for.  Other printers are unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 14:11:15 -05:00
harrierpigeonandClaude Fable 5.1 ef6d4a71de Tests: qualify Polyline in the belt overhang test for Windows
Windows headers declare a global Polyline, so the unqualified name in
test_print.cpp is ambiguous there (both Windows builds of belt-printer
fail at tests/fff_print/test_print.cpp:1336), as Polygon was in #16196.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 14:11:15 -05:00
Joseph Robertson 0b11311d40 Belt printer: no layer changes that print nothing, and a preview that survives them (#16245)
Fixes the preview layer bar on belt prints with several parts along the
belt (reported with a cube on filament 1 and a 3DBenchy on filament 2,
no purge tower): the top slider layer held nearly the whole print, the
slider jumped every other layer through the single-colour stretch before
the second part, and with the belt purge tower the whole print greyed
out while dragging.

## Cause

Since #16236 the slicing frame of a belt object starts at the belt below
its leading end, so its first layers are empty. On a single part they
carry the brim bands. With several parts along the belt the later parts'
empty layers fall between the earlier parts' printing layers and were
written to the G-code as layer changes with no moves at all. The preview
numbers its layers (`libvgcode::Layers`) from the vertices it is given
and expects consecutive ids, so at the first such gap it stopped
creating layers and folded everything after it into the last one.

## Fix

- `GCode::collect_layers_to_print` drops the belt layers that print
nothing (no object, support or brim content): no layer change without
moves in the file.
- `libvgcode::convert` renumbers the layers consecutively over the moves
that exist, so a file with empty layers from any source still previews
correctly.
- The layer slider labels each belt layer with its print Z (the slicer's
layer Z, which increases along the belt) instead of libvgcode's toolpath
height, which on a tilted layer is wherever its last extrusion happened
to end; the slider assumes the list increases, so the labels showed "0 /
max" on alternate layers. The processor reads that print Z from the
`;Z:` tag non-BBL printers write (it only knew `; Z_HEIGHT:`), on belt
printers only, so nothing changes for other printers.

## Verification

- New regression test *Belt G-code has no layer that prints nothing*
(two cubes 60 mm apart along the belt): fails on the previous code with
one empty layer, passes now.
- `fff_print_tests` 356 passed, `libslic3r_tests` 1116 passed;
`scripts/clang_tidy_diff.py --base upstream/belt-printer`: no findings.
- The reported project sliced through the CLI: 595 layers, none without
an extrusion, Z strictly increasing.
- Scripted GUI pass on the reported project with and without the purge
tower: the slider has one entry per G-code layer, each step shows a thin
tilted strip advancing along the belt, the top layer alone is a thin
strip, nothing greys out while dragging, the slider opens at the top
after slicing, and every label reads the layer number and the print Z
matching the G-code's `;Z:` (checked at the top, mid-print and through
the two-part stretch); raw-view toggle and slider retention unchanged.

Left as is: the lower handle at the bottom still reads `1 / 0.00` rather
than the first layer's Z (index correct); pre-existing.
2026-10-07 12:01:20 -05:00
SoftFever e027f8b225 Remove the CAD Primitive and Sketch gizmos from Prepare 2026-10-07 21:20:05 +08:00
SoftFever 6d02a945e0 Speed up the Linux incremental rebuild (optimizes packaging step) (#16244)
## Speeds up OrcaSlicer incremental rebuild on Linux

Profiled `build_linux_image.sh`: 96 s, of which 51 s in the dependency
audit.

**`appimage_is_elf_file()`** ran `file` and `grep` per candidate. An
AppDir holds ~9.6k of them, 4.8k being the bundled Python runtime and
none of them ELF: ~19k processes, 14 s. Reads the four-byte magic
instead. Checked against the old result on 4000 files, no disagreement.

**The dependency walk** popped its queue with `"${queue[@]:1}"`, which
rebuilds the whole array each time. At ~4.8k entries that was 22 s of
copying an array around. Uses a read index.

Audit still passes. `shellcheck` v0.11.0, the version CI uses, is clean.

## Notes
The 96 s -> 12.7 s. Measured on a 32-core / 48 GB machine, but the audit
is a serial bash loop, so cores and RAM is not the bottleneck. On slower
hardware the saving should be larger

## Images
<img width="1987" height="782" alt="Screenshot_20261007_092516"
src="https://github.com/user-attachments/assets/96fcb917-38e5-49e7-8cbe-b37be1a2f23a"
/>
<img width="1807" height="742" alt="Screenshot_20261007_092621"
src="https://github.com/user-attachments/assets/4a65ffae-4d59-41f0-a1c7-ee5b49f3c4be"
/>
2026-10-07 19:07:22 +08:00
SoftFever 01afd3b5b9 Use multiswitch for extruders instead new tabs on printer settings & publish dialog (#16162)
# CHANGES / TESTS
• Uses "Extruders" as tab name if it has multiple or it uses "Extruder" for single ones
• Keeps selected extruder while switching between "Extruders" and "Motion ability" tab
• Revert functions are working
• New extruders generated with values so they will shown in "Unchanged values" dialog if you try to change preset while its edited. revert functions not works properly without this
• BBL printers visible as Left / Right while normal printers visible as T1 / T2. i think there should be a separate option for how many toolheads and how many extruders it has. we might see 4 nozzles on same toolhead if one brand is brave enough :)
• Sidebar and other sections updates itself properly


<img width="751" height="173" alt="Screenshot-20261005173918" src="https://github.com/user-attachments/assets/3be0a6bd-84bd-4d15-822c-ed34acd98a9f" />
<img width="768" height="184" alt="Screenshot-20261005173905" src="https://github.com/user-attachments/assets/46164926-e385-4482-9fd1-41325eb9f61d" />
<img width="755" height="289" alt="Screenshot-20261005175318" src="https://github.com/user-attachments/assets/4550fa51-4c71-4a0a-b15e-9ca82dd0f1ad" />

# FIXES
• Extruders count on parameters section not updated when extruder count changed on printer settings. fixed on this PR
<img width="800" height="478" alt="Screenshot-20261005174702" src="https://github.com/user-attachments/assets/734e53df-f23f-4f83-8f87-2ecfeb6c162c" />

• New extruders gets randomly modifed parameters. fixed on this PR
<img width="871" height="87" alt="Screenshot-20261005174840" src="https://github.com/user-attachments/assets/254dae2a-fcfa-44ed-b3b0-038faf019abb" />

• Changed parameters not triggers revert / modified on extruder tabs. fixed on this PR

• Multi switch on motion ability tab not updated on extruder count change. fixed on this PR
<img width="813" height="184" alt="Screenshot-20261005174929" src="https://github.com/user-attachments/assets/f4f33f8f-b1bd-4a30-b91b-6ff632d08c2a" />
2026-10-07 19:05:37 +08:00
SoftFever b805f2ffd6 Fill a new extruder's machine limits the same way as its other settings 2026-10-07 18:42:09 +08:00
SoftFever 6b2b200f50 Merge branch 'main' into pr/yw4z/16162 2026-10-07 18:40:37 +08:00
yw4z a38e6c61f2 Show dummy image for printers without cover on printer selectiondialog (#16235)
init
2026-10-07 12:57:28 +03:00
SoftFever cc3769453f Merge branch 'main' into pr/yw4z/16162 2026-10-07 17:25:29 +08:00