* fix: prevent out-of-bounds crash in Arachne beading interpolation
SkeletalTrapezoidation::interpolate() derives an inset index from `left` but
uses it to index the merged beading, which follows the thicker of left/right.
When the thicker side has fewer insets, the index runs past the end and the
slicer crashes during "Generating walls".
Skip the adjustment when the index is out of range, as the adjacent guards
already do. interpolate() uses no instance state, so make it static and add a
regression test that exercises it directly.
Fixes#14584
* Add test for Arachne duplicate wall segment detection
Add test cases that reproduce an issue where Arachne generates
duplicate/coinciding extrusion segments at certain min_bead_width settings.
Test configuration:
- Profile: 0.28mm Extra Draft @BBL X1C (0.4mm nozzle, 0.28mm layer)
- outer_wall_line_width: 0.42mm, inner_wall_line_width: 0.45mm
- wall_loops: 2, precise_outer_wall: enabled
- Test polygon: outer rectangle (0,0)-(20,20) with inner cutout (0.5,0.5)-(19.5,19.5)
This creates a 0.5mm wide frame around the perimeter.
Results:
- 50% min_bead_width (0.20mm): FAILS - detects 4 duplicate segments (all 4 sides)
- 60% min_bead_width (0.24mm): PASSES - no duplicates
At 50%, Arachne generates two separate closed loops that share all 4 edges
of the inner square. At 60%, Arachne generates a single closed loop.
SVG output is exported to /tmp/opencode/ for visual debugging.
* Fix Arachne duplicate extrusion caused by bead count mismatch
WideningBeadingStrategy::compute() used optimal_width (inner wall width)
to determine if a thin wall should produce a single bead. However,
getOptimalBeadCount() uses optimal_width_outer (outer wall width) via
RedistributeBeadingStrategy to decide the bead count.
This inconsistency caused situations where getOptimalBeadCount() returned
2 beads, but compute() produced only 1 bead at full thickness. The single
bead was then generated for both inner and outer contours, resulting in
duplicate extrusion paths.
Fix: Use getTransitionThickness(1) instead of optimal_width. This method
returns the exact threshold for the 1-to-2 bead transition, ensuring
consistency between bead count calculation and bead generation.
Reproduces with: 50% min_bead_width, 0.42mm outer wall, 0.45mm inner wall,
0.5mm polygon inset creating ~0.38mm wall thickness.
Fixes#13917
---------
Co-authored-by: SoftFever <softfeverever@gmail.com>