The 2026-06-21 assessment was written before the persistence work landed and
got two load-bearing facts wrong. Both are corrected here against the branch
itself rather than from recollection:
1. It called OCCT "a dependency mainline OrcaSlicer has never carried" and
built its whole conclusion on that. False: deps/OCCT/ exists at the
merge-base, and upstream already links it from Format/STEP.cpp,
Format/svg.cpp and Shape/TextShape.cpp. The real dependency diff is one
line -- BUILD_MODULE_ModelingAlgorithms OFF -> ON -- costing a measured
3.77 MiB of Windows DLLs (TKFillet + TKOffset; TKBool already arrives
transitively via DataExchange).
2. It described the vendored SolveSpace solver as LGPL. False:
src/libslic3r/slvs/LICENSE is GPL-3.0. Harmless for us, but a licence
must not be misstated in a document aimed at upstream.
It also claimed no changes to Model, which stopped being true when 3MF
recipe persistence added a std::string there.
The rewrite replaces prose estimates with counted figures: 138 new files,
23 modified upstream files at +457/-75, nothing deleted, 99.3 % of the diff
in new files. That reframes the ask from "adopt a CAD kernel" to "widen a
build flag you already carry", which is the argument that actually has a
chance upstream.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BVzKmX6Y1aEteit1HTXG4Q
Selection failures on a real desktop kept looking identical from the UI
whether the ray missed the solid, the click was rejected as a drag, or the
press never reached the tool at all. The status line added in edb1adbfa3
reports WHICH body/face was picked, so it distinguishes "picked" from
"silence" and nothing finer -- not enough to tell those three apart.
This narrates the whole press -> release -> ray path on stderr, one distinct
line per failure mode:
down x= y= the press reached the tool
up with no pending press the press was eaten upstream
up ... drift=N / rejected the click-vs-drag threshold decided
ray tris=N -> body= face= t= the ray reached the solid (or missed)
no solid data (bodies= mesh=) the pick pointers were never wired
Gated on getenv("SNAPORCA_PICK_TRACE"), cached in a function-local static,
so a normal build pays one load and prints nothing. It ships enabled-on-
demand because the failing environment is a real X session with a real
mouse, which the headless rig cannot reproduce.
First use retired a wrong theory of my own: the trace showed drift=0 on
three consecutive picks, so the widened threshold in edb1adbfa3 was not
what fixed anything. The reported symptom is best explained by a stale
pre-orcawidgets binary left running alongside the current one.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BVzKmX6Y1aEteit1HTXG4Q
## Problem
On H2C (carousel) printers, the wipe tower purge volume calculation in
`_make_wipe_tower()` tracks filament state **per-extruder** (2 slots).
Since H2C has up to 7 carousel nozzle slots on a single extruder, all
filaments sharing that extruder are collapsed into one tracking slot.
This causes:
Test:
[5cubes.3mf.zip](https://github.com/user-attachments/files/30092551/5cubes.3mf.zip)
- **Massive redundant AMS flushing** every filament change on the
carousel triggers a full purge against the "previous" filament, even
when the target nozzle slot already has the correct filament loaded
- **60.9g total weight** instead of ~17g (**3.5× material waste**)
- **3h09m print time** instead of ~1h57m (**60% longer**)
## Root Cause
The code uses `nozzle_cur_filament_ids[extruder_id]` (a 2-element array)
to track which filament was last used for each extruder. BambuStudio
uses `NozzleStatusRecorder`, which tracks per `group_id` (physical
carousel slot 0..6).
## Changes
| File | Change |
|---|---|
| `Print.cpp` | Replace `nozzle_cur_filament_ids` with
`NozzleStatusRecorder`. Use `get_nozzle_for_filament()` to resolve the
physical carousel slot per layer. Select `filament_prime_volume_nc` for
nozzle changes, `filament_prime_volume` for filament changes. |
| `PrintConfig.hpp` | Add `ConfigOptionFloats filament_prime_volume`
(per-filament EC prime volume, missing from upstream but present in BBS
and H2C profiles) |
| `PrintConfig.cpp` | Register `filament_prime_volume` with default
45mm³ (matching BBS) |
| `Preset.cpp` | Add `filament_prime_volume` to preset keys |
Also includes `tests/compare_analyzer/` - two standalone Python tools
for G-code slice comparison and temperature timeline analysis (stdlib
only, no dependencies).
## Test Results (5-color H2C Hybrid print, same 3mf project)
| Metric | Upstream (broken) | **Fixed** | BBS (reference) |
|---|---|---|---|
| **Total weight** | 60.90g | **16.20g** ✅ | 17.47g |
| **Print time** | 3h09m | **1h57m** ✅ | 1h51m |
| **Filament changes** | 105 | 105 | 140 |
| **Tool changes** | 35 | 35 | 35 |
| **Critical discrepancies vs BBS** | ⚠️ YES | ✅ None | — |
## Analysis Tools (`tests/compare_analyzer/`)
Two standalone Python tools (stdlib only, no dependencies) for deep
G-code comparison:
- **`compare_slices.py`** - comprehensive .3mf slice comparison:
filament usage, nozzle mapping, tool change sequences, prime tower
analysis, temperature timeline, retract parameters, and automatic
critical discrepancy detection (weight/time anomalies)
- **`show_temp_plot.py`** - interactive HTML temperature timeline
plotter for visualising heater profiles during multi-nozzle prints
(supports single-file and side-by-side comparison)
Usage:
```bash
python3 tests/compare_analyzer/compare_slices.py file1.3mf file2.3mf --labels "Upstream" "Fixed"
python3 tests/compare_analyzer/show_temp_plot.py file1.3mf file2.3mf
```
## Screenshots
### OrcaSlicer Upstream (unfixed) - 60.90g, 3h09m
<img width="1512" height="982" alt="Screenshot 2026-07-16 at 15 22 58"
src="https://github.com/user-attachments/assets/3efb2bff-ff1e-43db-9669-feafa5921b51"
/>
### OrcaSlicer Fixed - 16.20g, 1h57m
<img width="1512" height="982" alt="Screenshot 2026-07-16 at 15 23 08"
src="https://github.com/user-attachments/assets/c1d36dc5-9b01-4691-80ef-7364540e1f4e"
/>
### BambuStudio Reference - 17.47g, 1h51m
<img width="1512" height="982" alt="Screenshot 2026-07-16 at 15 24 52"
src="https://github.com/user-attachments/assets/5c0b11e2-64f4-40e9-8c7c-3f42519786c3"
/>
### Temperature Timeline: Upstream vs Fixed
<img width="1511" height="829" alt="Screenshot 2026-07-16 at 15 23 35"
src="https://github.com/user-attachments/assets/926c2cb5-dfd4-4ce0-bb40-82e6165eb134"
/>
### Temperature Timeline: Fixed vs BBS
<img width="1512" height="825" alt="Screenshot 2026-07-16 at 15 23 51"
src="https://github.com/user-attachments/assets/85c72dda-e779-4aa6-8118-fb17e5f8482d"
/>
## Compatibility
Safe for non-carousel printers: when each extruder has a single nozzle,
`group_id == extruder_id`, so `NozzleStatusRecorder` behaves identically
to the original per-extruder tracking. The `filament_prime_volume`
default (45mm³) matches the existing global `prime_volume` default.
## Reference
BambuStudio `Print.cpp` `_make_wipe_tower()` L3341-3392 -
`NozzleStatusRecorder` pattern.
* Ensure spiral lift positive quadrant
* check for printable area
* clamp area
* simpler version
* Adjust printable area bounds with safety safety margin
Added safety margin to printable area bounds calculations.
* increase safety margin
* Refactor safety margin calculations in GCodeWriter
* New Logic
Co-Authored-By: Ian Bassi <12130714+ianalexis@users.noreply.github.com>
---------
Co-authored-by: Ian Bassi <12130714+ianalexis@users.noreply.github.com>
# Description
Typo introduced a regression failure. Fixes failing 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)
Adopt BambuStudio's load_last_machine (cloud machines only, remembered
machine preferred) and port record_user_last_machine /
get_user_last_machine. Orca's version auto-connected an arbitrary LAN
printer, starting an unrequested connection that the user's first
printer switch tore down mid-flight, which the 02.08 plugin's connect
worker does not survive. This also caused the 100% crash-on-relaunch
loop: the crashed-on printer was auto-connected at startup, so
re-selecting it always hit the same-machine disconnect+reconnect path.
* fix: constrain PA_Line calibration bounding box to model geometry
- PA_Line bounding box now uses actual model convex hull for X constraint instead of full printable area
- Skip EXCLUDE_OBJECT_DEFINE for PA_Line mode (single object, no exclusion needed)
- Add tool config files to .gitignore
* modified: .gitignore
* fix: add gcode type annotations and fix box height in PA line calibration
- Label calibration segments with appropriate TYPE comments (Outer wall, Bottom surface, Top surface, Custom) for proper gcode processing
- Fix bounding box height calculation to account for z_offset
- Add LAYER_CHANGE and HEIGHT comments for multi-layer numbering display
* fix: lock PA_Line bounding box X to bed centre instead of model hull
* Added extra TYPE to ensure text/numbers/glyphs are labelled correctly
` gcode << ";TYPE:Outer wall\n"; `
* Remove hardcoded Perl path in OpenSSL.cmake
Remove hardcoded Perl path for Windows configuration.
* Add cross compilation support for Windows in OpenSSL.cmake
* Remove unnecessary blank line in OpenSSL.cmake
* Set perl config command back to variable
Accidentally uploaded version with hardcoded path for my local environment
* whitespace adjustment in previous
* removed personal .gitignore config
Remove specific files and directories from .gitignore.
* Fix box height parameter in DrawBoxOptArgs
Update DrawBoxOptArgs to use `m_height_layer` instead of `m_height_layer*2+z_offset`. This isn't a Z coordinate, it's a layer height
* Replace hardcoded extrusion type with call to `GCodeProcessor::reserved_tag` Etags
* Get pa_line bounding box from actual calibration variables
Updated calibration line bounding box calculation to use actual geometry for X bounds, using a fake call to generate the calibration pattern.
This will accurately get the size of the calibration pattern, massively reducing wasted time from bed mesh probing.
* Implement print_extents method in CalibPressureAdvanceLine
Add print_extents method to calculate bounding box extents based on bed dimensions.
* Declare print_extents method in CalibPressureAdvanceLine
Added print_extents method to return X-bounds of the pattern.
* Fixed whitespace issues
* Adjust print_extents to account for delta printers
Check if the printer is delta layout and adjust bed dimensions if so.
Used code from `CalibPressureAdvanceLine::generate_test`
* Added semicolons to reserved tags
Didn't realise etags wouldn't add semicolon - added these
* only include number list in bounding box if number list is used
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* avoid bounding box overflowing bed
* Tabs to spaces
---------
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Ian Bassi <ian.bassi@outlook.com>
Ports snaporca-cad f5c7e74e9b.
The LeftUp pick discarded anything moving more than 4 px total since the
press. A hand-held mouse drifts that much during an ordinary click, so
real clicks were thrown away as drags and it read as "selection does not
work". Use 8 px per axis, GTK's own drag threshold.
Also report the pick on the status line (body / face / edge). A solid
pick previously set no text at all, so its only feedback was the viewport
highlight, and a pick that registers but draws faintly looked identical
to one that never fired.
DesignSketchTool.cpp copied verbatim (identical between the forks apart
from this change). DesignPanel.cpp took the status hunk only, since this
fork keeps mainline's Item-based DropDown in feat_dropdown/ToolFlyout.
Not confirmed on hardware yet, on either fork; this fork remains
uncompiled (needs Eigen 5.0.1).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BVzKmX6Y1aEteit1HTXG4Q
- WipeTower: use filament_ramming_volumetric_speed(_nc) for ramming, falling back to
max_vol_speed only when nil; gate precool temps on enable_pre_heating
- ToolOrderUtils: disable the inter-layer forecast in the per-nozzle base reorder so
H2D/H2C ordering is unchanged
- PrintConfig: stop stripping filament_prime_volume in handle_legacy; document that
prime_volume drives the Type2 wipe tower and filament_prime_volume the Type1 one
- GCodeProcessor: exclude post-print end-gcode M400 dwells from the M73 estimate and
drop the dead air-filtration state
- Trim verbose BambuStudio source-location comments across the port
Ports snaporca-cad c741fb9677.
SketchInlineEditor::open() clamped its position with
wxGetClientDisplayRect(), which describes only the PRIMARY monitor. On a
multi-head desktop (the reporting machine runs 5760x1080 across screens
at +0, +1920 and +3840) a field anchored on the left or right screen was
clamped onto the middle one and left invisible, while m_awaiting_length
made the sketch tool consume every mouse event until it was answered:
orbit and pan died after any sketch, with Enter the only way out. Clamp
to the display the anchor is actually on instead.
Also let drags and the wheel through that freeze, so a field that lands
somewhere unexpected degrades to odd placement rather than a dead
viewport.
Both files were byte-identical between the forks apart from this change,
so they are copied verbatim. Verified on the snaporca side by the user;
this fork is still uncompiled (needs Eigen 5.0.1, which the available
deps image does not provide).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BVzKmX6Y1aEteit1HTXG4Q
# Description
<!--
> 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.
-->
load_local_machines_from_config() iterated a reference to the live
m_local_machines map while erase_local_machine() erased from it for
printers without access rights, invalidating the range-for iterator
(use-after-free on ++it). Iterate a copy instead, as the code did
before commit 5028a5000e.