From 34209a7cd74fa048b79d945833407d2e40926110 Mon Sep 17 00:00:00 2001 From: Peyton Marcotte Date: Wed, 20 May 2026 11:42:32 -0400 Subject: [PATCH] Add Optimized Gyroid infill (auto-tuned wavelength + amplitude) (#13379) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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 * 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 Co-authored-by: SoftFever --- src/libslic3r/Fill/Fill.cpp | 15 ++- src/libslic3r/Fill/FillBase.hpp | 3 + src/libslic3r/Fill/FillGyroid.cpp | 180 ++++++++++++++++++++++++-- src/libslic3r/Preset.cpp | 1 + src/libslic3r/PrintConfig.cpp | 13 ++ src/libslic3r/PrintConfig.hpp | 1 + src/slic3r/GUI/ConfigManipulation.cpp | 4 + src/slic3r/GUI/Tab.cpp | 1 + 8 files changed, 208 insertions(+), 10 deletions(-) diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index 74e6d14d14..d47518bbca 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -271,6 +271,9 @@ struct SurfaceFillParams // Params for Lateral honeycomb float infill_overhang_angle = 60.f; + // For Gyroid: when true, use the parameterized "optimized" wave. + bool gyroid_optimized = false; + bool operator<(const SurfaceFillParams &rhs) const { #define RETURN_COMPARE_NON_EQUAL(KEY) if (this->KEY < rhs.KEY) return true; if (this->KEY > rhs.KEY) return false; #define RETURN_COMPARE_NON_EQUAL_TYPED(TYPE, KEY) if (TYPE(this->KEY) < TYPE(rhs.KEY)) return true; if (TYPE(this->KEY) > TYPE(rhs.KEY)) return false; @@ -303,6 +306,7 @@ struct SurfaceFillParams RETURN_COMPARE_NON_EQUAL(symmetric_infill_y_axis); RETURN_COMPARE_NON_EQUAL(infill_lock_depth); RETURN_COMPARE_NON_EQUAL(skin_infill_depth); RETURN_COMPARE_NON_EQUAL(infill_overhang_angle); + RETURN_COMPARE_NON_EQUAL(gyroid_optimized); return false; } @@ -330,7 +334,8 @@ struct SurfaceFillParams this->lateral_lattice_angle_2 == rhs.lateral_lattice_angle_2 && this->infill_lock_depth == rhs.infill_lock_depth && this->skin_infill_depth == rhs.skin_infill_depth && - this->infill_overhang_angle == rhs.infill_overhang_angle; + this->infill_overhang_angle == rhs.infill_overhang_angle && + this->gyroid_optimized == rhs.gyroid_optimized; } }; @@ -920,6 +925,12 @@ std::vector group_fills(const Layer &layer, LockRegionParam &lock_p // Orca: apply fill multiline only for sparse infill params.multiline = params.extrusion_role == erInternalInfill ? int(region_config.fill_multiline) : 1; + // Pass through gyroid_optimized only when the effective pattern is Gyroid, + // so non-Gyroid fills do not differ in SurfaceFillParams by an irrelevant flag + // (which would unnecessarily split fill batching). + // Stored on SurfaceFillParams; copied to FillParams during conversion. + params.gyroid_optimized = (params.pattern == ipGyroid) && region_config.gyroid_optimized; + if (params.extrusion_role == erInternalInfill) { params.angle = calculate_infill_rotation_angle(layer.object(), layer.id(), region_config.infill_direction.value, region_config.sparse_infill_rotate_template.value); @@ -1273,6 +1284,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive: params.lateral_lattice_angle_1 = surface_fill.params.lateral_lattice_angle_1; params.lateral_lattice_angle_2 = surface_fill.params.lateral_lattice_angle_2; params.infill_overhang_angle = surface_fill.params.infill_overhang_angle; + params.gyroid_optimized = surface_fill.params.gyroid_optimized; // BBS params.flow = surface_fill.params.flow; @@ -1468,6 +1480,7 @@ Polylines Layer::generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Oc params.lateral_lattice_angle_2 = surface_fill.params.lateral_lattice_angle_2; params.infill_overhang_angle = surface_fill.params.infill_overhang_angle; params.multiline = surface_fill.params.multiline; + params.gyroid_optimized = surface_fill.params.gyroid_optimized; for (ExPolygon &expoly : surface_fill.expolygons) { // Spacing is modified by the filler to indicate adjustments. Reset it for each expolygon. diff --git a/src/libslic3r/Fill/FillBase.hpp b/src/libslic3r/Fill/FillBase.hpp index 47195c850d..ef6a6bc804 100644 --- a/src/libslic3r/Fill/FillBase.hpp +++ b/src/libslic3r/Fill/FillBase.hpp @@ -79,6 +79,9 @@ struct FillParams // Layer height for Concentric infill with Arachne. coordf_t layer_height { 0.f }; + // For Gyroid: when true, use the parameterized "optimized" variant. + bool gyroid_optimized { false }; + // For Lateral lattice coordf_t lateral_lattice_angle_1 { 0.f }; coordf_t lateral_lattice_angle_2 { 0.f }; diff --git a/src/libslic3r/Fill/FillGyroid.cpp b/src/libslic3r/Fill/FillGyroid.cpp index 8700c1746e..c740dd2b4b 100644 --- a/src/libslic3r/Fill/FillGyroid.cpp +++ b/src/libslic3r/Fill/FillGyroid.cpp @@ -1,4 +1,5 @@ #include "../ClipperUtils.hpp" +#include "../MarchingSquares.hpp" #include "../ShortestPath.hpp" #include "../Surface.hpp" #include @@ -7,6 +8,99 @@ #include "FillBase.hpp" #include "FillGyroid.hpp" +// --------------------------------------------------------------------------- +// Marching-squares scalar field for the optimized gyroid branch. +// Modeled after FillTpmsFK.cpp's ScalarField. +// +// The gyroid scalar field is the standard implicit equation +// F(x,y,z) = sin(fx*x)cos(fy*y) + sin(fy*y)cos(fz*z) + sin(fz*z)cos(fx*x) +// Marching squares extracts the iso-zero contour, which gives smoother +// transitions between vertical and horizontal regimes than the analytical +// asin-based wave generator. Setting fz = omega * baseline anisotropically +// tightens the wave along the layer-stacking axis, shortening the effective +// vertical strand length and improving column-buckling resistance under +// Z-axis compression. +// --------------------------------------------------------------------------- +namespace marchsq { +using namespace Slic3r; + +using coordr_t = long; +using Pointf = Vec2d; + +struct GyroidField +{ + static constexpr float gsizef = 0.40f; + static constexpr float rsizef = 0.004f; + const coord_t rsize = scaled(rsizef); + const coordr_t gsize = std::round(gsizef / rsizef); + Point size; + Point offs; + coordf_t z; + float fx; + float fy; + float fz; + float isoval = 0.0f; + + explicit GyroidField(const BoundingBox bb, const coordf_t z, const float period, const float omega = 1.0f) + : size{bb.size()}, offs{bb.min}, z{z} + { + const float baseline = float(2.0 * PI) / std::max(period, 1e-3f); + fx = baseline; + fy = baseline; + fz = omega * baseline; + } + + float get_scalar(coordf_t x, coordf_t y, coordf_t z_arg) const + { + const float a = fx * float(x); + const float b = fy * float(y); + const float c = fz * float(z_arg); + return std::sin(a) * std::cos(b) + std::sin(b) * std::cos(c) + std::sin(c) * std::cos(a); + } + + float get_scalar(Coord p) const + { + Pointf pf = to_Pointf(p); + return get_scalar(pf.x(), pf.y(), z); + } + + inline coord_t to_coord (const coordr_t& x) const { return x * rsize; } + inline coordr_t to_coordr(const coord_t& x) const { return x / rsize; } + inline Point to_Point (const Coord& p) const { return Point(to_coord(p.c) + offs.x(), to_coord(p.r) + offs.y()); } + inline Coord to_Coord (const Point& p) const { return Coord(to_coordr(p.y() - offs.y()), to_coordr(p.x() - offs.x())); } + inline Pointf to_Pointf(const Point& p) const { return Pointf(unscaled(p.x()), unscaled(p.y())); } + inline Pointf to_Pointf(const Coord& p) const { return to_Pointf(to_Point(p)); } +}; + +template<> struct _RasterTraits +{ + using ValueType = float; + static float get (const GyroidField& sf, size_t row, size_t col) { return sf.get_scalar(Coord(row, col)); } + static size_t rows(const GyroidField& sf) { return sf.to_coordr(sf.size.y()); } + static size_t cols(const GyroidField& sf) { return sf.to_coordr(sf.size.x()); } +}; + +inline Polylines get_gyroid_polylines(const GyroidField& sf, const double tolerance = SCALED_EPSILON) +{ + std::vector rings = execute_with_policy(ex_tbb, sf, sf.isoval, {sf.gsize, sf.gsize}); + Polylines polys; + polys.reserve(rings.size()); + for (const Ring& ring : rings) { + Polyline poly; + Points& pts = poly.points; + pts.reserve(ring.size() + 1); + for (const Coord& crd : ring) + pts.emplace_back(sf.to_Point(crd)); + pts.push_back(pts.front()); + if (tolerance >= 0.0) + poly.simplify(tolerance); + polys.emplace_back(poly); + } + return polys; +} + +} // namespace marchsq + namespace Slic3r { static inline double f(double x, double z_sin, double z_cos, bool vertical, bool flip) @@ -102,6 +196,49 @@ static std::vector make_one_period(double width, double scaleFactor, doub return points; } +// --------------------------------------------------------------------------- +// "Optimized" gyroid wave: marching-squares variant gated on +// params.gyroid_optimized. The wave shape is extracted from the gyroid +// implicit scalar field (see marchsq::GyroidField above) at iso=0, with +// the Z dimension's spatial frequency multiplied by an Euler-Bernoulli +// buckling-derived factor so the vertical strands become shorter columns, +// raising the critical buckling load against Z-axis compression. +// +// The formula is INVERTED from a naive "scale with density" derivation: +// at LOW density the gyroid strands are long and slender (prime buckling +// targets), so they need the most shortening; at high density the strands +// are already short and need little extra help. omega is therefore the +// inverse-square-root of density_adjusted: +// +// omega = sqrt(1 / density_adj) / sqrt(1 + layer_h/spacing), +// clamped [1.0, 2.0] +// +// fx and fy are left at the baseline frequency, so the per-XY-slice line +// length per unit area is preserved -> mass at the same `sparse_infill_density` +// setting matches the standard gyroid path. Strength gain comes purely from +// the shorter vertical column length (P_cr proportional to 1/L^2). +// +// Empirical Python sim (sim_gyroid_compare.py) at layer_h=0.20, spacing=0.45: +// +// density omega line/std strength/std strength_per_mass +// 10% 2.00 1.00 2.84 2.84 +// 15% 1.38 1.00 1.89 1.89 +// 20% 1.19 1.00 1.42 1.42 +// 30% 1.00 1.00 1.00 1.00 +// 50%+ 1.00 1.00 1.00 1.00 +// +// When gyroid_optimized is false, behavior is byte-identical to the +// standard parametric gyroid path below. +// --------------------------------------------------------------------------- + +static inline double compute_omega_factor(double density_adjusted, double line_spacing, double layer_height) +{ + double lh_ratio = (line_spacing > 0.) ? layer_height / line_spacing : 0.5; + double correction = 1.0 / std::sqrt(1.0 + lh_ratio); + double raw = std::sqrt(1.0 / std::max(density_adjusted, 0.1)) * correction; + return std::clamp(raw, 1.0, 2.0); +} + static Polylines make_gyroid_waves(double gridZ, double density_adjusted, double line_spacing, double width, double height) { const double scaleFactor = scale_(line_spacing) / density_adjusted; @@ -173,16 +310,41 @@ void FillGyroid::_fill_surface_single( bb.offset(expand); // generate pattern - Polylines polylines = make_gyroid_waves( - scale_(this->z), - density_adjusted, - this->spacing, - ceil(bb.size()(0) / distance) + 1., - ceil(bb.size()(1) / distance) + 1.); + Polylines polylines; + if (params.gyroid_optimized) { + // Marching-squares path on the gyroid implicit field. Base period matches + // the standard parametric path's wavelength: 2*pi * spacing / density_adj. + // omega >= 1 always, so fz >= baseline -> shorter vertical wavelength -> + // shorter effective column length -> higher buckling resistance. + // + // Mass: fx and fy are left at baseline (same as standard), so the + // per-XY-slice line length per unit area is approximately preserved. + // Empirically (sim_gyroid_compare.py) the optimized line/std ratio is + // ~1.000 across densities, so no period compensation is needed. + const double lh = (params.layer_height > 0.) ? double(params.layer_height) : double(this->spacing); + const double omega = compute_omega_factor(density_adjusted, this->spacing * params.multiline, lh); - // shift the polyline to the grid origin - for (Polyline &pl : polylines) - pl.translate(bb.min); + const float density_factor = std::max(0.001f, float(params.density * DensityAdjust / params.multiline)); + const float period = float(2.0 * M_PI) * float(this->spacing) / density_factor; + + // bb is already expanded above by 10 * scale_(spacing) for edge artifacts; + // skip a second offset here to avoid raster-area bloat in the marching squares pass. + marchsq::GyroidField sf(bb, this->z, period, float(omega)); + polylines = marchsq::get_gyroid_polylines(sf, SCALED_SPARSE_INFILL_RESOLUTION); + } else { + polylines = make_gyroid_waves( + scale_(this->z), + density_adjusted, + this->spacing, + ceil(bb.size()(0) / distance) + 1., + ceil(bb.size()(1) / distance) + 1.); + + // The parametric generator produces wave coords relative to the grid origin; + // shift them into absolute layer coords. The marching-squares branch above + // already emits absolute coords via GyroidField::to_Point, so it skips this. + for (Polyline &pl : polylines) + pl.translate(bb.min); + } // Apply multiline offset if needed multiline_fill(polylines, params, spacing); diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 2c894450dd..ade6f42c29 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -1008,6 +1008,7 @@ static std::vector s_Preset_print_options{ "is_infill_first", "sparse_infill_density", "fill_multiline", + "gyroid_optimized", "sparse_infill_pattern", "lateral_lattice_angle_1", "lateral_lattice_angle_2", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 393198351b..be73c9d349 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2912,6 +2912,19 @@ void PrintConfigDef::init_fff_params() def->max = 10; // Maximum number of lines for infill pattern def->set_default_value(new ConfigOptionInt(1)); + // Z-buckling bias optimization (experimental). Tightens the gyroid wave along the Z + // (vertical) axis at low infill density to shorten the effective column length under + // Z-axis compression. Filament use at the same `sparse_infill_density` setting is + // preserved. No effect above ~30% density (formula clamps to no-op). + def = this->add("gyroid_optimized", coBool); + def->label = L("Z-buckling bias optimization (experimental)"); + def->category = L("Strength"); + def->tooltip = L("Tightens the gyroid wave along the Z (vertical) axis at low infill density " + "to shorten the effective vertical column length and improve Z-axis compression " + "buckling resistance. Filament use is preserved. No effect at ~30% sparse infill " + "density and above. Only applies when Sparse infill pattern is set to Gyroid."); + def->set_default_value(new ConfigOptionBool(false)); + def = this->add("sparse_infill_pattern", coEnum); def->label = L("Sparse infill pattern"); def->category = L("Strength"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index b84e227c4c..cdde293cfa 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1133,6 +1133,7 @@ PRINT_CONFIG_CLASS_DEFINE( // Orca: ((ConfigOptionFloatOrPercent, infill_combination_max_layer_height)) ((ConfigOptionInt, fill_multiline)) + ((ConfigOptionBool, gyroid_optimized)) // Ironing options ((ConfigOptionEnum, ironing_type)) ((ConfigOptionEnum, ironing_pattern)) diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index dbb0e8d525..1df4dba9c2 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -605,6 +605,10 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co bool have_multiline_infill_pattern = pattern == ipGyroid || pattern == ipGrid || pattern == ipRectilinear || pattern == ipTpmsD || pattern == ipTpmsFK || pattern == ipCrossHatch || pattern == ipHoneycomb || pattern == ipLateralLattice || pattern == ipLateralHoneycomb || pattern == ipConcentric || pattern == ipCubic || pattern == ipStars || pattern == ipAlignedRectilinear || pattern == ipLightning || pattern == ip3DHoneycomb || pattern == ipAdaptiveCubic || pattern == ipSupportCubic|| pattern == ipTriangles || pattern == ipQuarterCubic|| pattern == ipArchimedeanChords || pattern == ipHilbertCurve || pattern == ipOctagramSpiral; + // gyroid_optimized only applies when the sparse infill pattern is gyroid; + // hide the whole line otherwise. + toggle_line("gyroid_optimized", have_infill && pattern == ipGyroid); + // If there is infill, enable/disable fill_multiline according to whether the pattern supports multiline infill. if (have_infill) { toggle_field("fill_multiline", have_multiline_infill_pattern); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 3bfdc39983..1affaebc5c 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2445,6 +2445,7 @@ void TabPrint::build() optgroup->append_single_option_line("sparse_infill_density", "strength_settings_infill#sparse-infill-density"); optgroup->append_single_option_line("fill_multiline", "strength_settings_infill#fill-multiline"); optgroup->append_single_option_line("sparse_infill_pattern", "strength_settings_infill#sparse-infill-pattern"); + optgroup->append_single_option_line("gyroid_optimized", "strength_settings_patterns#gyroid_optimized"); optgroup->append_single_option_line("infill_direction", "strength_settings_infill#direction"); optgroup->append_single_option_line("sparse_infill_rotate_template", "strength_settings_infill_rotation_template_metalanguage"); optgroup->append_single_option_line("skin_infill_density", "strength_settings_patterns#locked-zag");