Catches the iXex/IDEX branch up to upstream main (44 commits). One
content conflict resolved:
- src/libslic3r/Print.hpp: kept upstream's default-initialized
m_origin {0,0,0} alongside our m_imex_slice_offset member.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Catches the iXex/IDEX parallel-printing branch up to upstream main
(102 commits). Two content conflicts resolved:
- src/libslic3r/Preset.cpp: s_Preset_printer_options — kept upstream's
new "use_3mf" key and our iMEX printer-capability/mode keys.
- tests/fff_print/test_gcodewriter.cpp: upstream revived the disabled
suite (#14196), dropping the obsolete [.]-tagged lift() test and its
config_lift_unlift.ini; kept their set_speed + z_hop tests and appended
our 10 per-firmware set_pressure_advance/set_temperature scenarios.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat: add support for 3MF file format in printer configurations and export options
* fix file extension
* enable 3mf for X Max 4
* disable use_3mf for X Plus 4
* Fixed an issue where `label_object_enabled` was not properly propagated to 3mf
* enable exclude object for Max 4
* remove hardcoded use 3mf for flashforge, move them to the new printer profiles config
* Fix junction deviation and jerk settings behavior
Process settings now follow the selected printer's junction deviation
configuration. When machine_max_junction_deviation is enabled,
default_junction_deviation is shown and jerk settings are hidden. When
junction deviation is disabled, jerk settings are restored and
default_junction_deviation is hidden.
Fix a validation issue where junction deviation mismatch warnings could
be reported even when machine_max_junction_deviation was set to 0.
Warnings now apply only when junction deviation is active and point
directly to default_junction_deviation.
Also simplify Motion ability page visibility checks by reusing local
firmware-flavor booleans.
* GUI tweak
- separate Junction Deviation segment
- JD and Jerk stay visible
124 upstream commits including CrealityPrint integration (added include
in Plater.cpp alongside the existing IMEXHelpers include), profile fixes
and version bumps (#14084, #14085, Polymaker), CI artifact publishing,
test refactors (arachne walls test added; test_3mf/test_config/
test_gcodewriter content moved/removed upstream — IMEX test file
preserved as it is feedback-only), translations.
Includes nozzle-diameter guards for printers without nozzle info (#13255,
now landed upstream) and manual-calibration nozzle mismatch fix (#13882).
# Conflicts:
# src/slic3r/GUI/GCodeViewer.cpp
# src/slic3r/GUI/GLCanvas3D.hpp
# src/slic3r/GUI/Tab.cpp
* Add Optimized Gyroid infill (auto-tuned wavelength + amplitude)
New infill geometry derived from FillGyroid. Two parameters are
auto-computed per-region from density, line spacing, and layer height
(no user inputs):
omega = sqrt(density_adj) / sqrt(1 + layer_height/spacing)
clamped to [0.5, 2.0]
-- Euler-Bernoulli buckling: critical load ~ 1/L^2,
so shorter wavelength under higher load (denser infill)
raises buckling resistance.
amplitude = 0.55 / omega^2, clamped to [0.20, 0.65]
-- Curved-beam bending stress: peak stress ~ A * omega^2,
so amplitude is reduced as omega rises to keep peak
fiber stress bounded while preserving stiffness.
Files:
- src/libslic3r/Fill/FillOptimizedGyroid.{hpp,cpp} (new)
- src/libslic3r/Fill/FillBase.cpp (factory case)
- src/libslic3r/Fill/Fill.cpp (switch case)
- src/libslic3r/Layer.cpp (switch case)
- src/libslic3r/PrintConfig.{hpp,cpp} (enum + label)
- src/libslic3r/CMakeLists.txt (build sources)
User-facing: appears as "Optimized Gyroid" in the Fill Pattern dropdown.
Density still chosen by user; omega/amplitude are internal.
* Fix build: layer_height is in FillParams, not Fill base
* Add ipOptimizedGyroid to multiline infill list in ConfigManipulation
* Refactor: replace ipOptimizedGyroid enum with gyroid_optimized boolean
Per @RF47's review feedback, fold the optimized wave math into FillGyroid
itself behind a per-region boolean instead of a separate infill enum.
What changes:
- New ConfigOptionBool "gyroid_optimized" on PrintRegionConfig (default
false). When unchecked, gyroid behavior is byte-identical to before.
- Optimized wave math (compute_omega_factor, compute_amplitude_factor,
f_opt, make_*_opt, make_optimized_gyroid_waves) lives inside
FillGyroid.cpp. _fill_surface_single branches on params.gyroid_optimized.
- FillParams gains a bool gyroid_optimized field, populated in Fill.cpp
from region_config alongside fill_multiline.
- UI checkbox added under Strength > Infill in Tab.cpp, label
"Optimize gyroid wave (experimental)". Toggle is hidden by
ConfigManipulation when sparse_infill_pattern != ipGyroid.
- "gyroid_optimized" added to s_Preset_print_options for preset I/O.
What goes away:
- ipOptimizedGyroid enum value, factory case, switch cases, dropdown
label, string key.
- FillOptimizedGyroid.cpp / FillOptimizedGyroid.hpp (math moved into
FillGyroid.cpp).
- Net diff drops by ~250 lines.
Existing profiles using gyroid are unaffected.
* Wire gyroid_optimized through SurfaceFillParams to FillParams
Linux build failed because line 921 in Fill.cpp populates a
SurfaceFillParams (the dedup struct), not FillParams directly.
Add the field there, in operator< / operator==, and copy it to
FillParams at both conversion sites.
* Use toggle_line for gyroid_optimized: hide row when pattern != gyroid
* Account for multiline wall thickness in omega correction (per @RF47)
When fill_multiline = N, each gyroid wall is N lines thick, so the
geometric scale fed into the buckling correction term should be
spacing * N rather than spacing. Increases omega (tighter wavelength)
when multiline is enabled, consistent with the thicker wall being
more buckling-resistant.
* Optimized gyroid via marching squares on the implicit scalar field
Per @RF47 review: replace the analytical f_opt / make_one_period_opt
wave generator (which had visible kinks at vertical-horizontal
transitions) with a marching-squares iso-extraction on the gyroid
scalar field, modeled on FillTpmsFK.cpp.
- New marchsq::GyroidField in FillGyroid.cpp evaluates
F(x,y,z) = sin(fx*x)cos(fy*y) + sin(fy*y)cos(fz*z) + sin(fz*z)cos(fx*x)
where fx = omega * baseline (anisotropic in x), fy = fz = baseline.
- get_gyroid_polylines() runs marching squares at iso=0 and converts
rings to polylines.
- _fill_surface_single() optimized branch now builds GyroidField,
runs marching squares, and skips the bb.min translate (field
output is already in absolute coords).
- Dropped: f_opt, make_one_period_opt, make_wave_opt,
make_optimized_gyroid_waves, compute_amplitude_factor. Amplitude
has no clean analog in iso-zero extraction.
- Standard (non-optimized) gyroid path unchanged.
* Mass calibration: compensate period by cbrt(omega) for x-anisotropic field
Per @RF47: optimized vs standard gyroid had different masses at the
same sparse_infill_density setting. Cause: scaling fx by omega while
leaving fy=fz at the baseline raised the surface-area-to-volume ratio
by approximately omega^(1/3) (the geometric mean of the three
frequencies).
Fix: multiply the base period by cbrt(omega) so the geometric mean of
(fx, fy, fz) returns to the standard baseline. Net effect:
fx = omega^(2/3) * baseline_orig
fy = fz = omega^(-1/3) * baseline_orig
which preserves total mass at the same density setting while
preserving the load-direction anisotropy this PR introduces.
* Switch optimized gyroid anisotropy from X to Z (per @RF47)
Z is the typical compression-load axis for FFF parts and is not at
delamination risk under compression — so the dominant failure mode
is column buckling of the vertical strands themselves. Tightening
fz directly shortens the effective vertical strand length, which
improves Z-axis buckling resistance.
Mass calibration via cbrt(omega) period compensation still applies
(scaling exactly one of three frequencies by omega; the geometric-
mean preservation argument is symmetric across axes).
* Update src/slic3r/GUI/Tab.cpp
Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>
* Address review feedback (Copilot + @RF47)
- Fill.cpp: gate params.gyroid_optimized on (params.pattern == ipGyroid)
so non-gyroid surfaces don't differ in SurfaceFillParams by an
irrelevant flag (would unnecessarily split fill batching).
[Copilot suggestion, RF47 confirmed correct]
- PrintConfig.cpp: drop "amplitude" from the tooltip; only wavelength
is parameterized (the marching-squares iso=0 extraction is invariant
to a uniform field scale, so amplitude has no effect).
- FillBase.hpp: shorten gyroid_optimized comment to match the actual
carried state (no amplitude term).
- FillGyroid.cpp: shorten the marchsq namespace comment block; the
ODR concern was overstated (FillTpmsFK uses the same pattern fine).
* Drop redundant marchsq bb expansion (Copilot)
bb is already offset by 10 * scale_(spacing) above for edge-artifact
margin; the second offset on bb_field doubled the raster area for no
geometric benefit and hurt CPU time on large parts.
* Update src/slic3r/GUI/Tab.cpp
Co-authored-by: Ian Bassi <ian.bassi@outlook.com>
* Fix density mismatch + rename to Z-buckling bias optimization
Issue (per @ianalexis): at the same sparse_infill_density setting,
the optimized branch produced denser fill than standard. Verified via
Python sim (sim_gyroid_compare.py) using marching squares on the
implicit field across multiple z slices.
Root cause: the omega formula was inverted from the buckling-physics
intent. The naive sqrt(density_adj) factor produced omega < 1 at
typical print densities (10-30%), which LENGTHENED the Z wavelength
instead of shortening it -- net loss in both mass and strength.
Fix:
- compute_omega_factor: invert to sqrt(1 / density_adj), clamp to
[1.0, 2.0]. Now omega = 2.0 at low density (long strands need
most help) and clamps to 1.0 above ~30% density (no-op, since
standard gyroid is already short enough).
- Remove the cbrt(omega) period compensation. Empirically (sim
table embedded in FillGyroid.cpp comment) the inverted formula
keeps line length per area at ~1.000 of standard across all
densities with no period scaling needed.
Predicted gains (sim, Z-axis Euler buckling proxy):
density line/std strength/std
10% 1.000 2.84x
15% 1.000 1.89x
20% 1.000 1.42x
30%+ 1.000 1.00x (no-op)
Rename per @ianalexis: "Optimize gyroid wave" oversells (now no-op
above 30% density and Z-only). Renamed user-facing label to
"Z-buckling bias optimization (experimental)" with updated tooltip
that scopes to vertical compression and discloses the density cutoff.
Internal config key (gyroid_optimized) unchanged for diff size.
Real-world Instron compression tests at Brown's Prince Lab to follow.
---------
Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>
Co-authored-by: Ian Bassi <ian.bassi@outlook.com>
Co-authored-by: SoftFever <softfeverever@gmail.com>
For single-gantry IMEX setups, front/rear is meaningless — only left/right
matters. Collapse the imex_tool_layout dropdown to two items ("Left" / "Right",
mapped to front-left/front-right internally) when imex_gantry_count == 1, and
show all four corner items otherwise. Normalize stored rear-* selections to
their front-* equivalents on the transition so the displayed selection always
matches the persisted value.
Also rename the field label "Tool 0 Corner" → "Tool 0 Position" so it reads
correctly in both single- and dual-gantry contexts, with a tooltip that
explains the IDEX/IQEX distinction.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Fix a regression that second extruder settings not properly handled for H2D/X2D (OrcaSlicer/OrcaSlicer#13559)
The problem here is how it deals with comparasion between signed & unsigned unmbers. It will convert both into unsigned then do the comparasion,
which means when `extruder_id` is `-1` (which is a valid value, means all extruders), it will be treated as `0xFFFFFFFF` which is obviously greater than `nozzle_volumes->size()`
then be reset to `0`. So when the parameter dialog is built (which will call this function with `extruder_id=-1`), only the first extruder will be set to the correct variant index.
Adds the `imex_firmware_managed_zones` printer-config key (default off) for
IDEX/IQEX printers whose firmware applies its own copy/mirror offsets in
non-primary modes (e.g. RepRapFirmware IDEX duplication mode, Flashforge
Creator Pro 2/3 Pro). For these printers the slicer needs to emit a single
centered slice at bed origin and let the firmware fan toolheads out from there;
the previous slicer-managed iMEX rendering would draw a print at the primary
zone's world position (off-bed for the firmware-fan-out paradigm).
When the flag is on and the active mode is non-primary, the slicer subtracts
the primary zone's plate-local center from the gcode emission frame. The
writer offset is augmented but the gcode-processor offset stays at plate_origin
so the gcode-preview visualizer renders the centered slice at the bed center
rather than at the prepare-view zone placement. translate_to_print_space is
augmented too so first_layer_print_min/max placeholders (consumed by user
start_gcode like Felix's M118 header) reflect the centered frame.
Slice handoff lives in PartPlate::refresh_imex_slice_offset, called from both
update_slice_context (plate switch) and Plater::priv::update_background_process
(every-slice path — reslice() goes through here with switch_print=false so the
plate-switch hook alone wouldn't fire on mode toggle).
calc_imex_ghosts early-returns in firmware-managed mode: the existing
imex_head_transform math places ghosts at primary_zone_center + gantry_offset
(slicer-managed semantics), which renders off-bed when the toolpath is being
emitted in a centered frame. Proper firmware-managed ghost rendering (showing
where copies/mirrors will actually print after firmware fan-out) is deferred.
When the flag is off, all the new code paths reduce to no-ops byte-identical to
prior behavior. Layer 1 unit tests in test_imex_helpers cover every gating path
of compute_imex_slice_offset; full ctest suite passes (247/247).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>