Commit Graph
807 Commits
Author SHA1 Message Date
Clifford GarwoodandClaude Opus 5.5 2ede6d1631 Arrange every IDEX/IQEX plate inside its own primary zone
Arrange read the zones of the selected plate only and applied them to
every bed it packed. Arranging all plates with a plate in Primary
selected spread a parallel plate's parts across its whole bed, and with
a parallel plate selected, a Primary plate's parts were squeezed into
the zone. Arranging a single plate other than the first also ignored its
collision strips: they were tagged with the plate's index, while the
plate packs into the arranger's bed 0.

The IDEX/IQEX constraints now live in ImexArranger (IMEXArrange), and
ArrangeJob only snapshots each plate's zones on the main thread and
calls it:
- When every bed, plates the arrange may add included, has the same
  primary zone, the bed shape is that zone, so parts stay centered in it.
- Otherwise each plate in a parallel mode fences off the rest of its bed
  with fixed items on its own bed, and its parts are then arranged again
  inside the zone, so they sit centered rather than piled against the
  zone edge nearest the bed's center. Plates in Primary keep the whole
  bed, and plates the arrange adds take the process preset's mode.
- Zone edges inside the bed get the bed's own edge margin, and strips
  also keep room for the brim.
- A part too big for its zone, which libnest2d's first-fit retry places
  across the fixed items, is left unarranged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 01:44:42 -04:00
Clifford GarwoodandClaude Opus 5.5 8b5280098f Merge upstream main: center of mass markers, adaptive TPMS, texture bake color mixing, post-processing preview fix, GLEW/OpenCSG removal
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 01:44:42 -04:00
SoftFever e4142db820 Let texture bakes create a chosen number of mixed colours (#16320)
# Description

Follow-up to #16242, which turned texture colour mixes into mixed
filament slots but created a slot for every possible mix, even when only
previewing. A new Mixed colors setting (default 8) caps how many mixed
filaments a bake adds. They are picked from the texture's own colours,
and only the ones the bake actually paints with are created. Previews no
longer touch the project's filaments, both previews show a mix in the
colour its slot will have, and the bake paints each mix with the slot it
got, which went wrong whenever the project already held mixed slots.

It also improves the colour preview: the green paint highlight no longer
covers the colours, and the colours a bake writes stay visible in the
gizmo.

Only texture displacement changes. Models without a colour layer behave
as before, and there is no change to project or profile formats.

# Screenshots/Recordings/Graphs

**Before**



https://github.com/user-attachments/assets/554a0d0d-cd9f-4095-840e-ca764dde6d52

**After**



https://github.com/user-attachments/assets/7fe10431-8c3f-4759-bd3f-78b4f7a12fc7



## 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)
2026-10-10 12:00:39 +08:00
Kris Austin 4a20168742 Fix loading a multi-toolhead 3MF that has no filament_self_index (#16331) 2026-10-09 22:07:33 -03:00
0f3e8fbf27 Add center of mass markers to Prepare and Preview (#16291)
Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>
Co-authored-by: Kris Austin <kris.austin@gmail.com>
2026-10-09 16:48:48 -03:00
SoftFever 901b14a723 Merge branch 'main' into feature/texture-color-number 2026-10-10 02:46:28 +08:00
Ian BassiandRodrigo Faselli b5f5b50157 Adaptive TPMS (#16005)
Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>
2026-10-09 12:36:09 -03:00
e0b35f9ec9 Fix garbled G-code preview when a post-processing script is used (#15005)
* 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>
2026-10-09 23:08:43 +08:00
SoftFever b8665b69b0 Merge branch 'main' into feature/texture-color-number 2026-10-09 22:58:10 +08:00
SoftFever 10787dd59d Show the model's painted colours in the texture displacement gizmo 2026-10-09 22:25:36 +08:00
SoftFever 1fb5da4148 Keep the paint highlight off the texture colour preview between strokes
The green highlight and tint no longer cover a colour preview, and return while a stroke is
painted. The Fast view also keeps the other parts of a multi-part object.
2026-10-09 22:24:40 +08:00
SoftFever 0473da4ef8 Let texture bakes create a chosen number of mixed colours
The new Mixed colors setting caps how many mixed filaments a bake adds. They are picked from the
texture's colours, and only the ones the bake paints with are created. Previewing no longer creates
filament slots, both previews show a mix in its slot's colour, and the bake paints each mix with the
slot it actually got.
2026-10-09 22:23:07 +08:00
Clifford GarwoodandClaude Opus 5.5 f970a607ae Merge upstream main: belt printing, texture displacement color mixing, 3MF component cycle checks, undo blocked during background jobs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 07:44:12 -04:00
ExPikaPaka d55e32fed4 Stop reading a missing AMF metadata type as a string (#16060)
A `<metadata>` element without a `type` attribute makes
`get_attribute()` return nullptr, which was then assigned to a
`std::string` and read as a C string.

Check it the way the sibling metadata handler already does, and stop the
parse.

Regression test in `tests/libslic3r/test_amf.cpp`, a new file: the suite
had no AMF test at all.
2026-10-09 19:25:53 +08:00
SoftFever a124b7d2df Reject cyclic 3MF components without running out of memory, however many there are 2026-10-09 19:15:24 +08:00
SoftFever 3d2b219d6a Merge branch 'main' into fix/3mf-component-cycle 2026-10-09 18:14:00 +08:00
SoftFever 489e337bad Merge Belt Printing Into Upstream (#14394)
# Belt printing for OrcaSlicer

This merges the `belt-printer` branch into `main`. It adds support for
conveyor-belt ("infinite Z") printers like the BabyBelt Pro, the
IdeaFormer IR3 V2 and the CR-30 family, along with the things that had
to grow around it: tilted-plane slicing, supports that terminate on the
belt, belt-aware brims, a purge tower that works without a flat bed,
multi-colour belt prints, a preview that shows the part the way it was
designed, and starter profiles.

It has been a long road (the first attempt was #12733 back in March, the
pipeline has been rebuilt twice since) and a lot of people have put work
into it. Credits are at the bottom; please tell me if I've missed
anyone.

Closes #2628, closes #11344, closes #6885, closes #9004, closes #14188.

---

## How belt printing works

Slicers assume the bed sits on the XY plane and layers stack along Z. A
belt printer breaks that in two ways at once: the belt is tilted
(usually 45°) and the axis that advances the belt is the printer's Z, so
the "bed" lives on the XZ plane and is, in principle, infinitely long.

<img width="6360" height="2702" alt="A flat bed vs a tilted belt"
src="https://github.com/user-attachments/assets/3f5542f2-6dab-42bf-9233-f96d863b40c8"
/>

Rather than teach every part of the slicer about tilted beds, the branch
leaves the slicing engine alone and transforms what goes in and what
comes out. The pipeline has five steps.

![printer
pipeline](https://github.com/user-attachments/assets/4d2f9965-f768-4b22-afbe-b3fda05354c4)

<details>
<summary><b>The five steps in detail</b></summary>

### 1. Pre-slice rotation
The mesh is rotated by the belt angle before slicing
(`BeltSliceStrategy`, `BeltTransform`), so that the ordinary horizontal
slicer produces layers that are actually tilted planes relative to the
part. Rotation is about X by default (belt along Y); Y rotation and a Z
lift are supported too. A "global" mode rotates every object about one
common origin, which is what keeps several parts on one belt consistent
with each other.

### 2. Slice
Nothing special. The mesh is rotated, the slicer does what it always
does. This is the reason most of Orca's features (walls, infill, seams,
ironing, painting, …) just work on a belt without belt-specific code.

### 3. Supports
Supports are generated after slicing against a virtual floor: the belt
surface, expressed in the rotated frame (`BeltFloorContext`). Normal,
tree and organic supports all terminate on that plane instead of on Z=0,
and nothing may be generated below it. Painted supports and seams are
transformed with the same `trafo_sliced()` as the layers.

![adding
supports](https://github.com/user-attachments/assets/39c1a858-23e2-48ee-8eb3-7b1abb9be172)

### 4. G-code back-transform
The G-code is rotated back into the model's Cartesian frame
(`BeltBackTransform`). A nice side effect: with step 5 switched off you
can slice at a non-standard angle and print the result on a normal
printer. The first belt-sliced Benchy was printed exactly that way, on a
Sovol SV08.

### 5. Machine frame
The printer doesn't know its bed is tilted. To make straight walls come
out straight, the axes are remapped (the default mapping is X → reversed
X, Y → Z, Z → Y) and the result is sheared and scaled:

```math
\begin{bmatrix} X \\ Y \\ Z \end{bmatrix}
\longrightarrow
\begin{bmatrix} X \\ \dfrac{Y}{\cos\alpha} \\ Z + Y\cdot\tan\alpha \end{bmatrix}
```

This lives in `GCodeWriter` behind a small `MachineKinematics` strategy
(`BeltKinematics` on belts, identity otherwise), so the writer itself
has one code path. The slicing angle and the machine angle can differ if
you want to, e.g. slice at 30° on a 45° machine — mind your nozzle
clearance if you do.

</details>

A short recording of the back-transform from the original PR:


https://github.com/user-attachments/assets/cdb9cc83-711d-48b7-9d86-a014a32c5e8e

---

## What had to change to make it work

Belt mode is gated on the `belt_printer` printer setting; with it off,
every code path below is the old one.

<details>
<summary><b>Slicing and geometry</b></summary>

- `PrintObjectSlice` / `PrintObject`: the rotation, Z lift and
per-object layer-grid shift, plus the invalidation that goes with them.
Modifiers and painted volumes are transformed with the same matrix as
the model.
- `FirstLayerPlane`: "the first layer" on a belt is a band along the
belt, not the first slicing layer. First-layer speed, line width and the
fan band are measured against it.
- `Print::validate`: clearance checks against the gantry instead of the
printable height; skirt, raft, draft shield, the classic prime tower,
arc fitting, spiral vase with brim, and scarf-joint seams are refused or
disabled on belts because each of them either doesn't exist on a belt or
moves the belt the wrong way (a scarf seam starts one layer low, which
on a belt is a 0.28 mm back-step into the previous layer at every seam).
- Z-hop defaults to 0 on belt profiles; a lift on a belt is a belt move.

</details>

<details>
<summary><b>Supports</b></summary>

- `SupportMaterial`, `TreeSupport`, `TreeSupport3D`, `TreeModelVolumes`:
a shared `BeltFloorContext` provides the belt plane; supports clip to
it, extension layers are numbered sequentially, and the first-layer
flange that used to be stamped under everything is gone.
- `build_plate_tilt_x/y` (from #12733) is now derived from the slicing
rotation in `Print::apply`, so GUI and CLI agree; it's capped below 90°.
- Organic supports that reach the belt no longer produce negative flow.

</details>

<details>
<summary><b>Brims (#15155)</b></summary>

A belt first layer is effectively a single line of contact, so a brim
matters more than usual. `BeltBrim` generates per-layer bands along the
belt plus an "apron" ahead of the part, in the object's brim filament.
Two belt-specific settings came with it: **Leading edge brim length**
(more lines on the side printed first) and **Extra brim width** (across
the belt), plus a **Leading edge only** brim type.

<img width="1849" height="1043" alt="belt brim"
src="https://github.com/user-attachments/assets/f963ed8e-53e7-48f8-a495-123cb9ae27f7"
/>

</details>

<details>
<summary><b>Multi-colour: the belt purge tower</b></summary>

The classic wipe tower can't exist on a belt (its G-code bypasses the
transform and it needs a flat bed to stand on). Instead the GUI
generates a long, thin "purge prism" beside the parts, flush with the
far edge of the belt, one per plate (`BeltPurgeTower.cpp`). It is a real
model object, so it is sliced like everything else, and
`Print::_plan_belt_purge` routes every filament change into it via
`flush_into_objects`. It's sized from the flush matrix, split into one
island per simultaneous tool change, snapped onto the parts' layer grid,
cut off after the last colour change and stripped of infill no change
claimed, so what prints is a good deal smaller than the model you see in
Prepare.

</details>

<details>
<summary><b>G-code generation and cooling</b></summary>

- `GCodeWriter` + `MachineKinematics`/`BeltKinematics`: the
back-transform, axis remap, shear and scale, lifts that are belt moves,
and the first-layer travel speed.
- `GCode.cpp` / `BeltGCode`: a belt header (slicing rotation, remaps,
machine tilt) that the preview reads back; it is written outside the
optional header block so printers with a BTT TFT thumbnail still get it.
Exclude-object outlines are emitted in the plate frame.
- `CoolingBuffer`: the "first layers" the fan stays off for are a band
above the belt, marked per extrusion segment by the generator
(`;_BELT_BAND_START/END`) and honoured on every layer.
- `GCodeProcessor`: belt header parsing, start-G-code Z handling, and
height checks that don't compare belt travel against the printable
height.
- `ToolOrdering` / `BeltPurge`: filament changes are detected by
scanning the ordering (an apron layer never carries the first-layer
flag).

</details>

<details>
<summary><b>GUI</b></summary>

- Printer settings tab: the belt group (slicing rotation, angle, global
mode, infinite Y, purge tower, floor settings). The axis remap and
pre-slice remap options are Develop-mode only.
- `ConfigManipulation`: everything that doesn't apply on a belt is
greyed out (skirt, raft, draft shield, the wipe tower group, scarf
seams, …).
- Preview: a "designed view" that back-transforms the toolpaths onto the
model so you see the part upright, with `B` toggling the raw
machine-frame G-code (`GCodeViewer`, `Shortcuts`). The tilt comes from
the belt header, so imported G-code behaves.
- Arrange: parts are packed from the end of the belt that prints first,
colours are grouped into runs so each filament change happens once, the
purge tower's strip and the brim width are reserved, and piles aimed at
an off-centre `best_object_pos` are clamped to the bed (`Arrange.cpp`,
`ArrangeJob.cpp`, one clamp in `libnest2d`).
- `PartPlate`: plate icons stay in the gap between plates on a long,
narrow bed; the plate is open along Y for containment tests on an
infinite-Y belt.
- Calibration: a belt temperature tower (overhang variant) that slices
correctly on a tilt.
- The old tilted-bed rendering in Prepare was dormant and has been
removed; the bed is shown as the slicing pipeline treats it.

</details>

<details>
<summary><b>Config options</b></summary>

Printer: `belt_printer`, `belt_printer_infinite_y`,
`belt_slice_rotation`, `belt_slice_rotation_angle`,
`belt_slice_rotation_global`, `belt_preslice_global`,
`belt_frame_tilt_decouple`, `belt_frame_tilt_angle`,
`belt_support_floor_mode`, `belt_support_floor_offset`,
`belt_support_z_offset_mode`, `enable_belt_purge_tower`,
`first_layer_plane`, `first_layer_plane_offset`,
`first_layer_plane_thickness`, `build_plate_tilt_x/y`,
`gcode_back_transform`, `gcode_remap_x/y/z`, `preslice_remap_x/y/z`,
`preslice_remap_global`.
Process: `belt_purge_tower_width`, `leading_brim_length`,
`extra_brim_width`, brim type `leading_edge_only`. Object:
`belt_purge_tower_object`.

All of them have defaults that leave non-belt printers untouched, and
old `belt_support_floor_mode` values map to `none`.

</details>

<details>
<summary><b>Tests</b></summary>

`tests/libslic3r/test_belt_brim.cpp` and `test_arrange.cpp`, and belt
cases in `fff_print` (`test_print.cpp`, `test_skirt_brim.cpp`,
`test_gcodewriter.cpp`, `test_gcode_processor.cpp`): scarf gate, fan
band, gantry clearance, organic supports on the belt, brim with and
without the purge tower, apron widths, machine mapping at non-45°
angles, first-travel lift, start-G-code Z, arrange clamp and colour
grouping. All three suites pass on Linux, and the tree-wide profile
check passes.

</details>

---

## Starter profiles

Three vendors ship belt profiles. Belt mode needs the printer settings
at **Advanced** or above to show its group.

<img alt="advanced mode"
src="https://github.com/user-attachments/assets/7a519ce5-b3b5-400c-a914-4f208bb577b0"
/>

| Printer | Vendor bundle | Nozzles | Processes | Filaments |
|---|---|---|---|---|
| **Generic Belt Printer** (`MyBeltPrinter`) | Custom | 0.2, 0.4, 0.6,
0.8 | 0.20mm Standard, 0.12mm Fine | library |
| **BabyBelt Pro** (Printcepts) | Printcepts | 0.4 | 0.20mm Standard |
Generic PLA, Generic PETG, eSUN PLA |
| **IdeaFormer IR3 V2** | IdeaFormer | 0.4 | 0.20mm Standard | Generic
PLA, Generic PETG, eSUN PLA |

To set up a printer that isn't listed: pick **Generic Belt Printer**,
set the belt width and length, save the profile, then copy in your
machine's start/end G-code and limits and tune from there.

<img alt="generic belt printer"
src="https://github.com/user-attachments/assets/90134d55-d6fe-4dba-8695-5ea44e78ec2b"
/>

<details>
<summary>BabyBelt Pro</summary>
<img width="2467" height="1392" alt="BabyBelt Pro"
src="https://github.com/user-attachments/assets/2b448cee-339e-43c9-964b-1ee9044044c7"
/>
</details>

---

## Contributions

### @HarrierPigeon
***Majority of design & implementation***

I did most of the work here by myself with AI tools (primarily Claude,
some Codex.)
PRs #12733, #12998, #14385, #15155, #15361, #15156, #15526, #16127

### The @Unlayered3D Team
***Rotation-Mode Pipeline***

The initial version of this sheared the model in the pre-slice pipeline.
Talking with them convinced me to switch to the current
rotate->slice->unrotate-> remap & shear method, which had significant
immediate improvements. Working with them has been a blast.


### @tommasobbianchi
***IdeaFormer IR3V2 Profile, eSUN PLA Tuning, G-Code Render / Preview***

TommyB came in at the perfect time to help keep me motivated and
contributed several things I hadn't had the werewithal to implemement
yet. Without their contributions and encouragement, we wouldn't be here
yet.


### The BabyBelt Community

**BabyBelt Pro** — @rexit1982 for the profile, and @RobMink of
Printcepts for the printer and a lot of patient testing.

**Field reports** — Many members of the BabyBelt community helped,
testing on their machines, providing G-Code and examples of issues, and
encouraging me to keep working on it. Among them:
- @RobMink - creator of the BabyBelt
- @rexit1982 - initial BabyBelt Pro profile, bug hunter
- @shubhracc - found a *lot* of technical bugs
- @NeoDLC - bug hunter
and BabyBelt Discord members who found bugs & gave feedback in no
particular order:
- @horatio42 - also provided a build machine while mine was down
- @HotCubCar - requested belt printer brim support
- Swap_File
- @Nyctelios
- Sup
- @matschi140
- @Rise-Run
- @shooby-dooby

### OrcaSlicer Maintainers
**Generic belt printer** — @SoftFever
**Keeping on top of upstream** @RF47 & @HanifKoh
**Review and fixes** — @HanifKoh (#15685 and the review on this PR).
Among them: plates after the first printed off the bed on belts; painted
supports and seams ignored the belt transform; support generation failed
at a 90° tilt; the object table crashed on the Support column on every
printer because tilt keys were in the per-object tables; apron brims
printed in the wrong filament; `build_plate_tilt` went stale outside the
GUI; the CLI reserved a wipe tower on belts; every G-code file was
treated as belt G-code because the config block carries the angle; tests
didn't compile on Clang/MSVC; plus a long list of smaller clean-ups and
the review questions that led to the clearance check, the header length
fix, the retired floor modes and the removal of the diagnostic logging.

### Additional Thanks

A special thanks to LDO Motors, who provided equipment for validating
multicolor, and my wife, who not only put up with with this obsession,
and the addition of three belt printers to our home, but has encouraged
me to keep going ever since I started this project six months ago.

---

## Known Issues

- The purge prism's first tool is chosen by the shared `ToolOrdering`
logic; on some layouts the print opens on the wrong filament and makes
one extra change at the thin tip of the prism (the "cannot absorb the
full purge volume" warning at a low height).
- Colour grouping in arrange is a soft cost: when the belt is too short
for clean runs, colours overlap rather than spill onto another plate.
- Three OrcaFilamentLibrary filaments still carry `filament_z_hop` 0.4;
belt profiles override it to 0.

Also: slicing at an angle other than the machine's (decoupled frame
tilt) is supported but not something the starter profiles exercise.
2026-10-09 15:24:47 +08:00
Ian Chua 86ff2a9de7 fix: avoid substring denies in audit path keywords (#16243)
## Summary

   Fixes #15944.

   The plugin audit deny-list matched `secret`, `cert`, and
 `conf` as substrings of every path component. This blocked
 valid imports during plugin capability execution, for example
 `numpy/__config__.py`, because `conf` appeared inside the
 module filename.

   This PR changes deny keyword matching to use whole path
 components instead of substring matches. It keeps the
 intended protections for sensitive locations and config
 files, while allowing dependency and stdlib modules whose
 names merely contain those strings.

   ## Changes

   - Match denied path keywords as whole components instead of
 substrings.
   - Keep denying sensitive directory names such as:
     - `secret`
     - `secrets`
     - `cert`
     - `certs`
     - `certificate`
     - `certificates`
     - `conf`
     - `config`
   - Keep denying config files by extension:
     - `.conf`
     - `.ini`
   - Allow legitimate Python module/package paths such as:
     - `numpy/__config__.py`
     - `numpy/_core/_ufunc_config.py`
     - `configparser.py`
     - `sysconfig.py`
     - `logging/config.py`
     - `certifi/cacert.pem`
   - Include the denied target and reason in `PermissionError`
 messages when the audit hook blocks an operation.
   - Remove an unused `<memory>` include from
 `PluginAuditManager.hpp`.

   ## Why

   The previous substring matching caused false positives for
 common dependency and standard-library paths. It also made
 failures hard to diagnose because the Python exception did
 not include the refused path.

   The new behavior is narrower: it blocks sensitive path
 components and config file extensions without treating
 unrelated names like `__config__.py`, `configparser.py`,
 `Conference`, or `Concert` as secrets.

   ## Testing

   - Added/updated unit coverage in
 `tests/slic3rutils/test_plugin_audit.cpp` for:
     - whole-component keyword matches
     - `.conf` / `.ini` blocking
     - case-insensitive matching
     - false-positive paths from #15944

Plugin used for testing:

[orca_audit_numpy_config_repro.py](https://github.com/user-attachments/files/33143848/orca_audit_numpy_config_repro.py)
2026-10-09 15:20:38 +08:00
ExPikaPaka b3f4ea62a8 Merge remote-tracking branch 'origin/main' into fix/3mf-component-cycle
# Conflicts:
#	tests/libslic3r/test_3mf.cpp
2026-10-09 08:57:16 +02:00
SoftFever a5d21b9922 Merge branch 'main' into belt-printer 2026-10-09 13:28:39 +08:00
ExPikaPakaandRodrigo Faselli 018c4f49ee Fix a crash on loading a 3MF with empty project settings (#16016)
* Fix a crash on loading a 3MF with empty project settings

opt_float() dereferences what option<>() returns without checking it, and
option<>() is called with create = false. Three CLI sites read printable_height
that way, so a 3mf whose Metadata/project_settings.config holds an empty object
takes the CLI down with a null dereference. Both models shipped in
resources/handy_models are such files, so `--info` on either of them segfaults.

Guard the three reads the way the neighbouring reads of
extruder_clearance_height_to_rod and friends already are. All three target
variables are initialised to 0 and the consumer tests for > 0, so an absent
setting already had a defined meaning and nothing changes for a project that
carries the setting.

* Add a CLI regression test for a project with empty settings

Runs --info over a copy of a shipped model whose Metadata/project_settings.config
has been rewritten to an empty object, so the test keeps covering the crash no
matter what settings the shipped models carry later.

Verified both ways: the test passes against this branch and fails with a
segmentation fault against a build without the guards.

---------

Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>
2026-10-09 12:07:03 +08:00
ExPikaPaka 4c74d84b94 Fail cleanly on a truncated or corrupt PNG (#16014)
libpng reports a bad file by longjmp()ing back to the buffer set with
setjmp(), and the frame it lands in must own nothing that needs
destroying: with exceptions enabled MSVC unwinds the stack as part of
longjmp, and returning from a frame unwound that way crashes. It did on
Windows while working everywhere else.

The read callback also returned quietly on a short read, leaving libpng
to decode whatever happened to be in the output buffer.

The calls that can fail now sit in two helpers that own nothing but
pointers, so every C++ object the decoders need stays in their own
frames, and a short read is reported through png_error().
2026-10-09 11:52:55 +08:00
HanifKoh 65978fc87a Cap Recursion Depth in the Plugin JSON Converters (#16255)
* Cap Recursion Depth in the Plugin JSON Converters

* Add Missing Includes to the Plugin JSON Depth Test
2026-10-09 11:39:46 +08:00
Clifford GarwoodandClaude Opus 5.5 d4edf59301 Merge upstream main: vase settings from plate settings, infill density with modifiers, STEP chamfers, plugin thread permission
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 23:31:15 -04:00
Ian Bassi 785a1946a6 Fix Adaptive and Support Cubic infill density with modifiers (#16295) 2026-10-08 18:28:56 -03:00
Joseph Robertson 64cff12b9d Merge branch 'main' into belt-printer 2026-10-08 16:15:51 -05:00
Kris Austin 8790b07773 fix: missing chamfers on STEP import since the OCCT 8.0.1 update (#16290) 2026-10-08 18:10:37 -03:00
Rodrigo Faselli ee2c40ea85 Fix Mesh Boolean negative (cut) text object (#16275)
* Fix Mesh Boolean negative (cut) text object

* Update test_meshboolean.cpp

* missing headers

* Update test_meshboolean.cpp

* Refactor mcut difference test for source splits

* Apply suggestion from @raistlin7447
2026-10-08 16:00:28 -03: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
Rodrigo Faselli d09850c528 Merge branch 'main' into main 2026-10-08 10:45:49 -03:00
Ian Bassi 59fc97fb28 Extend Separated Infills (#16274) 2026-10-08 09:43:46 -03: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
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 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
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 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 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
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 e39d6cc089 Merge branch 'main' into belt-printer 2026-10-07 14:14:20 -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
Clifford GarwoodandClaude Opus 5.5 dbaec929bc test: rely on upstream's tests for the variant truncation guard
Remove three update_non_diff_values_to_base_config scenarios that
tested the truncation guard from upstream #13316. IMEX does not change
that code, and upstream's own tests cover it: removing the guard fails
#13316's test, and loosening it to `>=` fails #16107's.

The equal-size scenario broke when #16107 changed how variants are
matched, and the scalar-key scenario could not fail at all.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 08:54:18 -04:00
SoftFever 7fdfea6efa Merge branch 'main' into main 2026-10-07 19:31:24 +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 cc3769453f Merge branch 'main' into pr/yw4z/16162 2026-10-07 17:25:29 +08:00
harrierpigeonandClaude Fable 5.1 f64b49ab52 Belt printer: no layer changes that print nothing, and a preview that survives them
Since the slicing frame of a belt object starts at the belt below its
leading end, 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: the
top slider layer held nearly the whole print, the slider jumped every
other layer through the single-colour stretch before a second part on
another filament, and with the belt purge tower the whole print greyed
out while dragging.

Drop the belt layers that print nothing (no object, support or brim
content) in GCode::collect_layers_to_print, and renumber the layers
consecutively over the moves that exist when converting a result for
libvgcode, so a file with empty layers from any source still previews
correctly.  The layer slider labels a 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
ended; the slider assumes that list increases and 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 elsewhere.  Regression test: two cubes 60 mm apart along the
belt produce no layer without an extrusion and the header's layer count
matches.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 03:50:51 -05:00