mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-27 19:01:02 +00:00
b2bc4e358b3d04a29fd95b537a52a1f803f35cb4
12
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
f21f062ded |
Cache compiled objects between CI runs (#15611)
# Description <!-- > Please provide a summary of the changes made in this PR. Include details such as: > * What issue does this PR address or fix? > * What new features or enhancements does this PR introduce? > * Are there any breaking changes or dependencies that need to be considered? --> Every CI build leg compiles the whole tree from scratch: 42 to 57 minutes of each build job, on every push and every pull request, roughly 200 runs a week. This PR caches the compiled objects with ccache so that a run only compiles what changed since the last push to main. With a warm cache the compile steps take 1 to 4 minutes on all six legs and a pull-request run finishes in about 30 minutes instead of 75. Three prerequisites landed last week and made this measurable: #15537 took `GIT_COMMIT_HASH` off the compile line, #15552 made a build without the precompiled header work on Windows, and #15501 stopped the Flatpak job from rebuilding its dependencies. ## Changes ### Compiler cache in `build_orca.yml` Each build leg (Linux x86_64/aarch64, Windows x64/arm64, macOS arm64/x86_64) restores a cache entry keyed by that leg, compiles through `ccache` via `CMAKE_<LANG>_COMPILER_LAUNCHER`, and prints its hit statistics at the end of the job. The macOS universal combine does not compile and is left out. Who writes the cache is the important part. Cache entries are immutable and a restore always takes the newest matching one, so every save is a new entry that is never read again once a newer one exists. Therefore: - **Pushes save.** After a successful save, the older entries for the same leg on the same ref are deleted, so a branch holds exactly one entry per leg. The save comes first, so a failed save leaves the previous entry in place. - **Pull requests restore only.** They read main's entries (GitHub lets a PR read the base branch's caches) and keep nothing. Saving from PRs would add about 6 GB per run that no other run can read. The store is therefore a flat ~7 GB (one entry per leg: Linux ~1 GB, Windows ~2 GB, macOS ~0.6 GB), not a growing one. The `hendrikmuhs/ccache-action` only installs and configures ccache; restore and save go through `actions/cache` with one path string, because the cache service only matches entries saved under the identical path and the action spells it differently on Windows. A failed ccache install falls back to an uncached build rather than failing the job. ### Precompiled header off when the cache is on With `SLIC3R_PCH` left on, a warm cache hit only 19 % of compiles: Clang stamps the PCH with the build time, CMake does not pass `-fno-pch-timestamp`, and everything that includes the PCH (libslic3r and libslic3r_gui, ~750 files) missed every run. `build_linux.sh -p` exists for exactly this reason. The workflow now exports `ORCA_EXTRA_BUILD_ARGS=-DSLIC3R_PCH=OFF` whenever ccache is enabled, which brings the warm hit rate to 98.4–98.9 %. The cost is on cold compiles, which are 25–60 % slower than today's PCH build (ccache preprocesses every miss before compiling it, and the miss compiles without PCH). Main pays this once after an image update or a wide header change; PRs pay it only for the files their change invalidates. A change to a header included by half the tree (`PrintConfig.hpp`, `Preset.hpp`, `Model.hpp`) lands a run at 1.2–1.9× today's time. `ccache`'s depend mode would remove the preprocessor pass and is the natural follow-up. ### Includes the precompiled header was supplying on macOS A build without PCH had never been tried on macOS. Three files used what `pchheader.hpp` happened to include: `LocalesUtils.cpp` needs `<sstream>` and `<iomanip>`, and `AmsMappingPopup.cpp` / `PhysicalPrinterDialog.cpp` need `<wx/tooltip.h>`. libstdc++ and the GTK wx port pull these in transitively; libc++ and the Cocoa port do not. This is the macOS counterpart of #15552 and is worth merging on its own. ### `ORCA_EXTRA_BUILD_ARGS` pass-through `build_linux.sh` already forwarded this variable to the slicer configure. `build_release_macos.sh` now reads it into an array (shellcheck-clean), and `build_release_vs.bat` appends it on both configure lines, so CI can add a CMake option without editing three scripts. ## Behaviour reviewers should know about - **Main-only cache writes need `actions: write`** on the workflow token to delete the previous entry. The default token already has it (the nightly deploy steps write with it), so no `permissions:` block was added. A fork PR's read-only token never reaches the delete step. - **A runner image update cold-starts the cache** as configured, because ccache keys the compiler by its mtime and every image rebuild reinstalls it. Images updated 20260819 → 20260828 during this work, about every one to two weeks. Keying on the compiler version string (`compiler_check`) would avoid that; left as a follow-up since it changes every hash. - **What is now the critical path:** the two Flatpak jobs (46–66 min, untouched here), the orca-test-repo regression suite run inline in the Linux job (7 min), and NSIS/PDB/MSIX packaging on Windows (6 min). Those are the next wins. - **Open question:** CI still drives `build_release_vs.bat`. #15552 gave `build_win.bat` a `--cache ccache --no-pch` option; moving the Windows job onto it would replace the batch-file change here. # Screenshots/Recordings/Graphs <!-- > Please attach relevant screenshots to showcase the UI changes. > Please attach images that can help explain the changes. --> Compile step of each build leg, minutes. Main's numbers are from run 34324625046. | Leg | main | cold, PCH on | warm, PCH on | cold, PCH off | warm, PCH off | ~50 % of headers changed | 5 source files changed | |---|---|---|---|---|---|---|---| | Linux x86_64 | 48 | ~75 | (19 % hits) | ~110 | **2.6** | 91.3 (452/928 misses) | 3.4 | | Linux aarch64 | 41.7 | 53.4 | 52.2 (178/927 hits) | 58.8 | **2.5** | 55.8 (452/928) | 2.9 | | Windows x64 | 57 | 85.5 | — | ~105 | **2.4** | 76.8 (449/974) | 2.5 | | Windows arm64 | ~45 | 64.4 | — | ~78 | **4.3** | 59.6 (450/974) | 4.2 | | macOS arm64 | 51 | ~71 | — | — | **0.8** | 79.7 (453/947) | 0.9 | | macOS x86_64 | ~43 | 70.2 | — | — | **1.0** | 68.1 (411/742) | 1.0 | Warm hit rates: 98.4–98.9 % on every leg; the 11–14 misses are what any commit changes (version stamp and its includers). The "50 % of headers" column is a real event: #15251 and #15416 merged into main between two runs, changing 20 headers that reach 453 of 870 translation units. Whole run, before and after (a pull-request run; wall clock to the last non-Flatpak job): | Job | main (run 34324625046) | warm cache (run 34444305385) | what remains | |---|---|---|---| | Windows arm64 | 50.0 | 15.7 | compile 4.3, NSIS 3.5, cache save 1.6, deps restore 1.1, cache restore 1.0 | | Windows x64 | 67.4 | 13.2 | NSIS 3.2, PDB 2.6, compile 2.4, MSIX 0.5 | | Linux x86_64 | 57.5 | 12.6 | orca-test-repo regression 7.6, compile 2.6 | | macOS x86_64 | 46.9 | 6.1 | free disk space 2.3, compile 1.0 | | Linux aarch64 | 43.9 | 4.6 | compile 2.5, apt 0.9 | | macOS arm64 | 54.9 | 4.4 | free disk space 1.7, compile 0.8 | | macOS universal | 7.7 | 2.2 | signing and notarisation only on main | | Flatpak x86_64 / aarch64 | 66.6 / 46.5 | unchanged | full compile inside flatpak-builder | | **Wall clock** | **75 min** | **31 min** (Flatpak excluded; 66 with it) | macOS runner queueing now exceeds job time | Cache storage: one generation per leg is 400–680 MB compressed at PCH on, 0.6–2 GB at PCH off; six legs ≈ 7 GB. Without the delete step, 21 main pushes a week would hold ~80 GB of entries that are never read. ## Tests <!-- > Please describe the tests that you have conducted to verify the changes made in this PR. --> - Thirteen CI runs on this PR, one change per run, with the ccache statistics printed by every leg: cold (34336272234), warm with PCH (34346737197), cold and warm without PCH (34352209577, 34364791732), the macOS include fixes (34435044411, 34435968806 with `ninja -k 0` to list every remaining file, 34439532375), all legs warm (34444305385), the keep-only-newest cleanup (34450381312, then 34452640274 after the Windows CRLF fix), the half-tree invalidation (34452640274), the five-file change (34463517683, 34464720539), and this final shape (34466377763, restore-only). - Unit tests on all five platforms, the profile slice check, the Windows build-script suite, Shellcheck and the universal DMG build all pass on the cached binaries. - The cleanup was verified against the PR's own cache scope: 44 entries from the earlier runs reduced to exactly one per leg, on all three platforms, after fixing the CRLF that made `gh cache delete` fail on Windows. - A libc++ syntax-only pass over all 1986 C++ translation units on Linux found the `LocalesUtils.cpp` include; the two wx includes only surface in a real macOS build and were found with a keep-going build in one round. <!-- > 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) |
||
|
|
8d874cdc36 |
Register Instance Copies and Moves with Their Plate (#15613)
# Description Each plate keeps a registry of the instances it holds (`PartPlate::obj_to_instance_set`). The plate's filament list (`get_extruders`), its wipe tower preview and position clamp, the object list grouping and the saved project's per-plate instance list all read it. Two paths left it stale: * `Plater::increase_instances` (the `+` key / toolbar) adds the copy to the model but never registers it with any plate. * `GLCanvas3D::do_move` (drag release and arrow keys) ended with `notify_instance_update(-1, 0)`, so only instance 0 of each selected object was re-registered. Rotate, scale and mirror already notify every instance. So a copy created with `+` and dragged onto another plate stayed unknown to that plate: the project saved afterwards listed it on no plate, and a multi-filament copy moved onto a single-filament plate drew no wipe tower there and never got its tower position clamped. The Print side selects instances by geometry, so the plate still sliced, which is why this went unnoticed. This PR * registers new copies with their plate at creation; * has `do_move` notify exactly the instances it moved (every instance of the object when a part was moved in Volume mode), rather than instance 0 or all instances - notifying an instance that stayed put invalidates its plate's slice result, so `(-1, -1)` as used by rotate would have un-sliced every plate holding a sibling copy; * drops the registry entry again when `decrease_instances` removes a copy. A second commit finishes the switch #15532 started with `contain_any_instance_totally()`: `get_extruders_without_support()`, `check_single_extruder_mixed_filament_risk()` and `check_compatible_of_nozzle_and_filament()` still tested instance 0 only, so an object whose copy - not its original - sits on the plate was skipped by all three. No new options, no format change. The `is_new` flag is deliberately not passed for the copies: a copy landing on a spiral-vase plate gets the same "apply spiral mode settings?" prompt a dragged instance gets, instead of a silent rewrite of the object's settings. # Screenshots/Recordings/Graphs Before: <img width="1920" height="1080" alt="05-moved" src="https://github.com/user-attachments/assets/3cf9f5a9-1a4e-41e8-8c57-578f849d8c29" /> After: <img width="1920" height="1080" alt="05-moved" src="https://github.com/user-attachments/assets/1b801a7e-b7cd-4ffb-bd1d-b701f90dade6" /> ## Tests Re-run after the rebase, both binaries driven through the same headless harness (Xvfb 1920x1080, llvmpipe) on the same fixture: `cubeA` (filament 1) alone on plate 1, `cubeB` (a two-part object, filaments 2 and 1) alone on plate 2, so plate 1 shows no wipe tower at load. Select the plate-2 object, press `+`, walk the copy onto plate 1 with 36 x Left (10 mm per press, one `do_move` each), save, slice plate 1. Before is main `8af92214d0` - i.e. with #15532's `contain_any_instance_totally()` already in place, so the only difference is this PR. * **Before:** the saved `model_settings.config` lists plate 1 with `cubeA` only and plate 2 with `cubeB` instance 0. The copy (instance 1) is listed **on no plate at all**, and plate 1 draws no wipe tower even though a two-filament object is sitting on it. * **After:** plate 1 lists `cubeA` **and** `cubeB` instance 1; plate 2 still lists instance 0. The plate-1 tower preview appears, and slicing plate 1 succeeds with the tower actually generated - the filament panel reports 1.10 m / 0.48 m in its Tower column over 51 filament changes, and the G-code carries `EXCLUDE_OBJECT_END NAME=cubeB.stl_id_1_copy_0`. Same camera and fixture on both runs, so the screenshots above are directly comparable. |
||
|
|
8af92214d0 |
Extract and Unify Wipe Tower Estimation (#15532)
# Description
The pre-slice wipe tower size estimate existed twice:
`Print::wipe_tower_data()` (validation) and
`PartPlate::estimate_wipe_tower_size()` (GUI placement clamp, default
placement, preview, arrange, CLI placement) — with a third partial copy
in the CLI, which resolved the brim itself around the second. They were
hand-written twins reading their inputs from different places, so
validation could measure a tower with one number after the clamp had
placed it with another.
This PR extracts the estimate into one function,
`estimate_wipe_tower_footprint()` in
`src/libslic3r/GCode/WipeTowerEstimate.{hpp,cpp}`. It takes a
`ConfigBase&` (static `PrintConfig` and GUI/CLI `DynamicPrintConfig`
both work), the filament count, layer height and tallest object height,
and returns width, depth, height and the resolved brim width.
`Print::wipe_tower_data()` and a new
`PartPlate::estimate_wipe_tower_footprint()` become thin adapters around
it; `PartPlate::estimate_wipe_tower_size()` had no callers left and is
deleted.
**Inputs made to agree** — sharing the arithmetic is not enough when
each caller derives the inputs from its own view of the model:
* **Layer height** — thinnest layer among the objects on the plate,
resolved per object (Print used the first object's, PartPlate the
preset's).
* **Objects setting the height** — `PartPlate::get_extruders` counts an
object if *any* instance is on the plate, matching `PrintApply` (it only
looked at instance 0).
* **Height per object** — per on-plate instance, from the cached convex
hull (same z extent as the mesh). `PrintObject::size()` still measures
the model's first instance, so objects whose instances differ in scale
or x/y tilt can still disagree; that is inherent to the two data
sources.
* **Wipe tower filament** — counted for every caller, since
`Print::extruders()` adds it to the tool ordering even when unused.
* **Rib width cap** — kept for both (Print lacked it).
* **Config source** — everything read from the config passed in
(PartPlate read `m_print->config()`, stale on fresh plates and in the
CLI).
* **Dual-nozzle test** — `nozzle_diameter.size()` from the config for
both.
**One decision about whether a tower exists.** The rectangle branch
sized a tower the generator never builds while the rib branch reported
none for one it does; with rib as the shipped default, a single-filament
plate that still prints a tower (custom G-code tool changes) validated
against depth 0, collapsing the collision/exclusion hull to a point. The
purge volume is computed first, and an empty footprint is returned only
when nothing is purged, there is no tool change, and nothing else puts a
tower on the plate. The reason a single config cannot see arrives as a
resolved input: validation counts `Print::extruders(true)`.
A raft is deliberately **not** one of those reasons.
`DynamicPrintConfig::normalize_fdm_2` clears `enable_prime_tower` for a
plate that purges one filament unless smooth timelapse or wrapping
detection is on, and `Print::apply()` runs it, so a raft alone leaves no
tower to reserve for. (It also keeps the tower for a single *mixed*
filament, which this does not model — `Print::extruders(true)` does not
expand mixed filaments.)
**Two implementation notes:**
* Enums are read **by value**: a preset-built `DynamicPrintConfig` holds
`ConfigOptionEnumGeneric`, so a `dynamic_cast` to `ConfigOptionEnum<T>`
is null for exactly the config the GUI and CLI pass. The tests build
their configs the way `PresetBundle::full_config()` does, so that
storage is what gets tested.
* `PartPlate::estimate_wipe_tower_footprint()` is CLI-reachable, so
`get_extruders(bool)` gained a config-taking core with the identical
body; the GUI wrapper passes the app's presets, the adapter passes the
config it is given. `get_extruders_under_cli()` was not substituted: it
filters the plate's instances differently (skips unprintable ones, keeps
ones the plate flags as outside), so the GUI's filament set would have
changed in edge cases.
**Also fixed here:** `WipeTowerData` carries the effective width — set
by the estimate, and then by both planners at generation, so it never
disagrees with its neighbour `depth`; the preview and the containment
check take *whether there is a tower at all* from the footprint instead
of each re-deriving it; the config-taking `get_extruders` answers for an
object-less (`.gcode.3mf`) plate the way the wx overload does; the
preview takes body *and* brim from the plate's own footprint (an auto
brim drew every plate with the selected plate's brim);
`estimate_wipe_tower_polygon` builds its margin from the resolved brim
("Auto" gave a margin of 0) and no longer calls `std::clamp` with `hi <
lo`; the estimate falls back to declared defaults instead of hand-copied
constants. `estimate_wipe_tower_size()` /
`estimate_wipe_tower_polygon()` lose four parameters every caller took
from the same config.
## Behaviour changes reviewers should know about
G-code is never affected; no 3MF, profile or string changes. But this is
**not** a pure refactor:
1. **Validation now reserves what the placement clamp reserves**, which
is in places larger than before. A saved 3MF with a tower close to an
exclusion area or the rear edge can be rejected where it previously
sliced; dragging resolves it since the clamp agrees. Nothing re-clamps a
stored position on load (out of scope; the CLI side lands with #15518).
2. **`PartPlate::get_extruders` counts any-instance-on-plate**, which
reaches every caller of it, not only the estimate. It is `PrintApply`'s
rule and closes a GUI/CLI divergence.
3. **`estimate_wipe_tower_polygon`'s rear/right bound is looser by one
brim width** (it subtracted the brim twice).
4. **A single-filament plate with a rib wall no longer reserves a
phantom tower.**
5. **A single-filament plate whose tower comes from wrapping detection
is now validated against the bed.** Neither the old estimate (which read
only the wall type and smooth timelapse) nor the old containment gate
(the filament count or smooth timelapse) knew about that tower, so
between them it was never checked. It is printed, so it can be rejected
now.
Not addressed: the estimate still does not read `wipe_tower_type` or
per-filament `filament_prime_volume`, inherited unchanged from both
copies (the generated Type 1 tower is ~10 mm larger than the estimate on
Bambu profiles). #15516 mirrors the planners and folds into this
function on rebase.
## Verification
Before/after on the same fixtures with a main build and this branch, all
numbers read from the CLI (details, method and the real-tower and
arrange-clamp tables in the first comment):
| Fixture (divergence) | Side | Before (w × d, mm) | After (w × d, mm) |
|---|---|---|---|
| control | GUI/CLI · validation | 23.585 × 23.585 · 23.585 × 23.585 |
same |
| per-object layer 0.1 | GUI/CLI · validation | **23.585** · 31.637 |
**31.638** · 31.637 |
| unused `wipe_tower_filament` | GUI/CLI · validation depth | **39.332**
· 44.542 | **44.541** · 44.542 |
| tall object, instance 0 on another plate | GUI/CLI · validation |
**23.585** · 29.391 | **29.390** · 29.391 |
| rib cap binds | GUI/CLI · validation | 11.170 · **13.910** | 11.170 ·
**11.170** |
Before, the two estimates disagree on every divergence fixture; after,
they agree to the 0.001 mm bisection resolution, the control is
unchanged, and G-code is byte-identical. GUI screenshots of the preview
on both binaries are in the same comment.
The table was measured on the first commit; none of its fixtures uses a
raft or a zero purge volume, so the second commit does not move them.
G-code equivalence was re-checked on the final tip: `Cube.3mf` sliced by
a `main` build and by this branch is byte-identical.
# Screenshots/Recordings/Graphs
Before:
No Wipe Tower Preview:
<img width="2068" height="871" alt="image"
src="https://github.com/user-attachments/assets/7875a944-b8db-4bbc-b380-e8188a45caa7"
/>
After:
Has Wipe Tower Preview:
<img width="2551" height="882" alt="image"
src="https://github.com/user-attachments/assets/b4413695-4f24-4aa3-bae4-57304e8b7865"
/>
**Per-object layer height reaching the preview.** One object with a 0.1
mm override against a 0.2 mm preset. `main` sizes the previewed tower
from the preset, so it is smaller than the one validation reserves and
the one that prints; this PR sizes it from the object. Captured
headlessly on both builds from the same project, top view:
<img width="1408" height="596" alt="D_per_object_layer_height"
src="https://github.com/user-attachments/assets/989920fc-9f14-4658-8a3d-681c92a7f754"
/>
Measured over the four evidence fixtures on both builds, this is the
only one of the corrected inputs that changes what is drawn: the others
(an object contributing through a non-zero instance, an unused
`wipe_tower_filament`) change the estimate by amounts confirmed through
the CLI bisection above, but leave the rendered tower pixel-identical.
Arrange is unaffected either way — the tower enters the arranger as a
fixed obstacle (`m_unselected`), so it never moves.
## Tests
* `tests/libslic3r/test_wipe_tower_estimate.cpp` (10 cases / 104
assertions): rectangle and rib sizing, stability floor and auto brim,
single-filament cases (timelapse, wrapping, and a raft *not* reserving
one), a tool change reserving the floor when the purge volumes resolve
to zero, both wall types agreeing on tower existence, dual-nozzle
volume, the shipped flush-matrix path, default fallback for a missing
key, and a {rectangle, cone, rib} × {type1, type2} matrix asserting a
preset-shaped `DynamicPrintConfig` and a static `FullPrintConfig` give
the same footprint.
* `tests/fff_print/test_wipe_tower.cpp`: what `Print` feeds the
estimator — thinnest object layer height, effective width reaching
validation, the width staying current through generation, a
single-filament plate reserving a tower only when one is really printed
(raft no, smooth timelapse yes), and a wrapping-detection tower being
bed-validated. The last two fail on `main` and on the first commit of
this PR.
* Full suites green on this branch: `libslic3r_tests` 342 cases / 58325
assertions, `fff_print_tests` 174 cases / 3152 assertions. `--target
all` builds clean (including `OrcaSlicer_profile_validator`, which needs
`-DORCA_TOOLS=ON`). No new warnings.
* CLI evidence run above; its unused-`wipe_tower_filament` fixture is
also the regression check for the adapter under the CLI, which no unit
test can reach (`PartPlate` needs a GL context).
[How to Download Pull Requests Artifacts for
Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts)
|
||
|
|
8a291f9d56 |
Confine config import to the preset directory (#15608)
import_presets reduced each zip entry to a basename by stripping only '/', so on Windows an entry named with '\' separators kept its directory components and was extracted wherever they pointed. Strip both separators, and reject any entry whose name still escapes the extraction folder. The preset name from the JSON and the bundle id from bundle_structure.json were joined onto the preset directory unchecked as well, which let either of them write outside it on every platform. Both are now validated before anything is written. The check is the is_path_within_root helper the 3MF importer already had, moved to Utils so both importers share it. It treats '/' and '\' as separators on every platform, so a bundle that would escape on one OS is rejected on all of them. |
||
|
|
4deadc9dce |
Make Tree-Support Deterministic (#15565)
* Make tree support deterministic without giving up its parallelism * Break equal-distance ties in the tree support MST by coordinates * test: cover the determinism this PR fixes The MST unit tests here cover the tie-break, but the drop_nodes rework has no test. Adds two cases to the tree support suite. The thread-scheduling one slices five configs twice each and compares the support point sequence, which is what the node ordering moves. The MST tie one pins the branch diameter and line width that carry Prim's equal-distance ties into the toolpaths. slice_with_tree_support takes an optional config list so the second case can add the tree parameters it needs, and the double-slice comparison is shared rather than written twice. Both fail on main without this PR. The first passes from |
||
|
|
58bf267fdd |
Scale Min Junction Width to Prevent Fuzzy Skin From Failing Slice (#15566)
* Fix fuzzy skin failing the slice: the minimum junction width was unscaled * Unit Tests For Fuzzy Fix * Cover ridged multifractal noise in the fuzzy skin width floor test Its output is not bounded to [-1, 1], so it scales past the configured thickness and drives the junction width negative. The floor has to hold for any noise value, not just an in-range one. |
||
|
|
8e064659ad |
Fix Non-Deterministic Slicing - Order Per-Layer Intersection Lines Canonically (#15563)
Fix nondeterministic slicing: order per-layer intersection lines canonically Facet processing in slice_make_lines() is parallel, so the per-layer line order depended on thread scheduling. make_loops() consumes that order for island order and loop start vertices, so the same model could slice to different G-code run to run. Sort each layer's lines by a topology-based key. edge_type and flags are appended to the key purely to break ties: two lines can share every id and endpoint (a Horizontal facet can emit such a pair) and std::sort is not stable, so without them that pair's order would stay thread-dependent. |
||
|
|
c61d2fe5d1 |
Fix the Folgertech i3 0.6 nozzle printable area (#15577)
The bed was declared as 0x0, 20x0, 200x200, 0x200 - a triangle - where the 0.4 nozzle profile and the printer have the 200 x 200 square. Found by the profile validator once it placed the prime tower beside the test cube: no tower fits inside that outline. |
||
|
|
886d43d37a |
Fix Support Fill Cost Thresholds Being Frozen By The First Call (#15564)
Fix support fill cost thresholds being frozen by the first call |
||
|
|
1170b048e8 |
[CLI]: Fix Plate Config Reading and BuildVolume Height Checks (#15479)
* Fix incorrect early exit for CLI mode no-support preventing parameters from being read * Use PartPlate's m_height to allow CLI to perform proper BuildVolume check * Add safeguard against extruder_pintable_heights and extruder_areas vector size mismatch * Preserve printable_height precision in PartPlate/PartPlateList * Fixed multiple BuildVolume warning issue, and keep check_outside diff minimal |
||
|
|
df30e22427 |
[CLI]: CLI Crash Guards (#15477)
# Description <!-- > Please provide a summary of the changes made in this PR. Include details such as: > * What issue does this PR address or fix? > * What new features or enhancements does this PR introduce? > * Are there any breaking changes or dependencies that need to be considered? --> Part 1 of 3 of the CLI-mode bug sweep, split out of #15452 per review feedback there. This PR contains the crash fixes. ## Fixes - **`--outputdir`/`--datadir` with a missing parent directory aborted** via unguarded `create_directory`. Directories are now created recursively, with a graceful early exit and a specific error message if creation fails. - **`--slice` + `--export-3mf` segfaulted on a from-scratch slice**: `ConfigOptionVector::get_at()` on an empty vector is `.front()` of an empty vector (UB). Guards added for `filament_color`/`filament_id` at the CLI call site, and inside `DynamicPrintConfig::get_filament_type` for `filament_type`/`filament_is_support`/`filament_id`. Only *empty* vectors are treated as missing — the existing clamp-to-front behavior for merely out-of-range indices is preserved, so GUI callers are unaffected. - **OOB heap write from stale `filament_self_index` on `--load-filaments`** (fixes #14181): a 3MF carrying more `filament_self_index` entries than loaded filaments wrote past the end of `old_variant_counts`. The guard validates both bounds — entries `> filament_count` *and* non-positive entries (`< 1`), since a single `0` in an otherwise-valid array indexes `old_variant_counts[-1]`. - **Wrong printable-area check** for non-rectangular beds: use the printable area's bounding box instead of a naive vertex calculation (fixes #15363). - **`nozzle_height` and `align_center` were not read into the arrange config** in CLI mode. # Screenshots/Recordings/Graphs <!-- > Please attach relevant screenshots to showcase the UI changes. > Please attach images that can help explain the changes. --> ## Tests <!-- > Please describe the tests that you have conducted to verify the changes made in this PR. --> - Repro'd each crash on CLI before the fix; all resolved after. - `tests/libslic3r` suite passes; full binary builds clean on Linux. - Added `get_filament_type` unit tests <!-- > 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) |
||
|
|
57ce18d70d |
[CLI]: CLI Argument Parsing Fixes (#15478)
* Reject invalid CLI argument values instead of silently accepting them * Add read_cli accept/reject tests * Update Option Type for LogFile argument * Add read_cli vector option tests * Accept common bool spellings on the CLI, cover --logfile in tests * Add unit tests for truthy bool parsing |