Add Optimized Gyroid infill (auto-tuned wavelength + amplitude) (#13379)
* 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>
This commit is contained in:
@@ -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<SurfaceFill> 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.
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "../ClipperUtils.hpp"
|
||||
#include "../MarchingSquares.hpp"
|
||||
#include "../ShortestPath.hpp"
|
||||
#include "../Surface.hpp"
|
||||
#include <cmath>
|
||||
@@ -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<GyroidField>
|
||||
{
|
||||
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<Ring> 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<Vec2d> 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);
|
||||
|
||||
@@ -1008,6 +1008,7 @@ static std::vector<std::string> 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",
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -1133,6 +1133,7 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||
// Orca:
|
||||
((ConfigOptionFloatOrPercent, infill_combination_max_layer_height))
|
||||
((ConfigOptionInt, fill_multiline))
|
||||
((ConfigOptionBool, gyroid_optimized))
|
||||
// Ironing options
|
||||
((ConfigOptionEnum<IroningType>, ironing_type))
|
||||
((ConfigOptionEnum<InfillPattern>, ironing_pattern))
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user