From 9f6a344162797d09da26f91110854648791202a9 Mon Sep 17 00:00:00 2001 From: Ian Bassi Date: Mon, 19 Oct 2026 12:05:55 -0300 Subject: [PATCH] Make the adaptive infill settings pattern-neutral (#16654) --- ...tive-tpms-infill.md => adaptive-infill.md} | 14 ++-- src/libslic3r/CMakeLists.txt | 4 +- ...msAdaptive.cpp => AdaptiveInfillField.cpp} | 74 ++++++++-------- ...msAdaptive.hpp => AdaptiveInfillField.hpp} | 24 +++--- src/libslic3r/Fill/Fill.cpp | 46 +++++----- src/libslic3r/Fill/FillBase.hpp | 10 +-- src/libslic3r/Fill/FillGyroid.cpp | 12 +-- src/libslic3r/Fill/FillTpmsD.cpp | 12 +-- src/libslic3r/Fill/FillTpmsFK.cpp | 14 ++-- src/libslic3r/Layer.cpp | 4 +- src/libslic3r/Preset.cpp | 6 +- src/libslic3r/Print.hpp | 8 +- src/libslic3r/PrintConfig.cpp | 50 ++++++----- src/libslic3r/PrintConfig.hpp | 22 ++--- src/libslic3r/PrintObject.cpp | 26 +++--- src/slic3r/GUI/ConfigManipulation.cpp | 16 ++-- src/slic3r/GUI/GUI_Factories.cpp | 6 +- src/slic3r/GUI/Tab.cpp | 6 +- tests/fff_print/test_fill.cpp | 62 +++++++------- tests/libslic3r/CMakeLists.txt | 2 +- ...ive.cpp => test_adaptive_infill_field.cpp} | 84 +++++++++---------- tests/libslic3r/test_config.cpp | 13 +++ 22 files changed, 267 insertions(+), 248 deletions(-) rename docs/HLSD/{adaptive-tpms-infill.md => adaptive-infill.md} (96%) rename src/libslic3r/Fill/{FillTpmsAdaptive.cpp => AdaptiveInfillField.cpp} (91%) rename src/libslic3r/Fill/{FillTpmsAdaptive.hpp => AdaptiveInfillField.hpp} (84%) rename tests/libslic3r/{test_fill_tpms_adaptive.cpp => test_adaptive_infill_field.cpp} (73%) diff --git a/docs/HLSD/adaptive-tpms-infill.md b/docs/HLSD/adaptive-infill.md similarity index 96% rename from docs/HLSD/adaptive-tpms-infill.md rename to docs/HLSD/adaptive-infill.md index 5fc578f7e2..30eb364753 100644 --- a/docs/HLSD/adaptive-tpms-infill.md +++ b/docs/HLSD/adaptive-infill.md @@ -1,8 +1,8 @@ -# Adaptive TPMS infill — High Level Design +# Adaptive infill — High Level Design ## Purpose and scope -`tpms_adaptive` grades the sparse infill of the Gyroid, TPMS-D and TPMS-FK +`adaptive_infill_mode` grades the sparse infill of the Gyroid, TPMS-D and TPMS-FK patterns inside the object: the cells grow continuously from the surface towards the center of the object. `distance_warp`, `smooth_blend` and `stepped_shells` follow the distance to the nearest surface, including the top @@ -10,8 +10,8 @@ and bottom, like concentric shells; `lobes` follows the whole 3D shape towards the center of each lobe of the object; `normal_z`, `normal_y` and `normal_x` follow each section of the object normal to that axis, so the grading does not change along the axis, as suits a profile extruded along it. -`sparse_infill_density` is the density at the surface, `tpms_interior_density` -the density at the center, and `tpms_adaptive_gradient` picks how the density +`sparse_infill_density` is the density at the surface, `adaptive_infill_interior_density` +the density at the center, and `adaptive_infill_gradient` picks how the density goes from one to the other. Only internal sparse infill is graded; the Gyroid Z-buckling optimization does not apply to it. @@ -22,9 +22,9 @@ split into shells or blended between densities. ## Radial field -`TpmsRadialField` gives every point of an object the center of its lobe and a +`AdaptiveInfillField` gives every point of an object the center of its lobe and a radial coordinate: 0 at the center, 1 at the surface along the ray from the -center. `PrintObject::prepare_tpms_radial_fields()` builds it in +center. `PrintObject::prepare_adaptive_infill_fields()` builds it in `bridge_over_infill()`, next to the adaptive cubic octree, because the anchoring infill generated there has to match the printed infill. A field is built for every mode a region uses, and is shared by the regions using that mode: the @@ -202,7 +202,7 @@ built for them. ## Constraints -- With `tpms_adaptive` disabled, or for other patterns, the fill parameters are reset +- With `adaptive_infill_mode` disabled, or for other patterns, the fill parameters are reset to their defaults, so they neither change the infill nor split fill batches. - `Layer::get_sparse_infill_max_void_area()` uses the sparser of the two densities, as the voids at the center are that large. diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index fa9aec8531..265efb2eea 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -182,8 +182,8 @@ set(lisbslic3r_sources Fill/FillPlanePath.hpp Fill/FillRectilinear.cpp Fill/FillRectilinear.hpp - Fill/FillTpmsAdaptive.cpp - Fill/FillTpmsAdaptive.hpp + Fill/AdaptiveInfillField.cpp + Fill/AdaptiveInfillField.hpp Fill/FillTpmsD.cpp Fill/FillTpmsD.hpp Fill/FillTpmsFK.cpp diff --git a/src/libslic3r/Fill/FillTpmsAdaptive.cpp b/src/libslic3r/Fill/AdaptiveInfillField.cpp similarity index 91% rename from src/libslic3r/Fill/FillTpmsAdaptive.cpp rename to src/libslic3r/Fill/AdaptiveInfillField.cpp index 2dcd2930b9..1f5ea234d3 100644 --- a/src/libslic3r/Fill/FillTpmsAdaptive.cpp +++ b/src/libslic3r/Fill/AdaptiveInfillField.cpp @@ -1,4 +1,4 @@ -#include "FillTpmsAdaptive.hpp" +#include "AdaptiveInfillField.hpp" #include #include @@ -146,11 +146,11 @@ void rasterize(const ExPolygons &expolygons, const Vec2d &origin, double cell, i } // Scale of the pattern relative to the surface at a depth from 0 at the surface to 1 at the deepest point. -double target_scale(double ratio, TpmsAdaptiveGradient gradient, double depth) +double target_scale(double ratio, AdaptiveInfillGradient gradient, double depth) { switch (gradient) { - case TpmsAdaptiveGradient::Quadratic: return 1. + (ratio - 1.) * depth * depth; - case TpmsAdaptiveGradient::Exponential: return std::pow(ratio, depth); + case AdaptiveInfillGradient::Quadratic: return 1. + (ratio - 1.) * depth * depth; + case AdaptiveInfillGradient::Exponential: return std::pow(ratio, depth); default: return 1. + (ratio - 1.) * depth; } } @@ -159,7 +159,7 @@ double target_scale(double ratio, TpmsAdaptiveGradient gradient, double depth) // continuous level of the target of a depth. struct DensityLevels { - DensityLevels(double ratio, double step, TpmsAdaptiveGradient gradient) + DensityLevels(double ratio, double step, AdaptiveInfillGradient gradient) : ratio(ratio), gradient(gradient), count(int(std::ceil(std::abs(std::log(ratio)) / std::log(step) - EPSILON))) {} @@ -170,7 +170,7 @@ struct DensityLevels } double ratio; - TpmsAdaptiveGradient gradient; + AdaptiveInfillGradient gradient; int count; }; @@ -212,12 +212,12 @@ private: } // namespace -TpmsRadialField::TpmsRadialField(const std::vector &slices, const BoundingBox &bbox, TpmsAdaptiveMode mode, +AdaptiveInfillField::AdaptiveInfillField(const std::vector &slices, const BoundingBox &bbox, AdaptiveInfillMode mode, const std::function &throw_if_canceled) : m_mode(mode) - , m_axis(mode == TpmsAdaptiveMode::NormalX ? 0 : mode == TpmsAdaptiveMode::NormalY ? 1 : mode == TpmsAdaptiveMode::NormalZ ? 2 : -1) + , m_axis(mode == AdaptiveInfillMode::NormalX ? 0 : mode == AdaptiveInfillMode::NormalY ? 1 : mode == AdaptiveInfillMode::NormalZ ? 2 : -1) { - assert(!slices.empty() && mode != TpmsAdaptiveMode::Disabled); + assert(!slices.empty() && mode != AdaptiveInfillMode::Disabled); const Vec3d min(unscaled(bbox.min.x()), unscaled(bbox.min.y()), slices.front().bottom_z); const Vec3d extent = Vec3d(unscaled(bbox.max.x()), unscaled(bbox.max.y()), slices.back().top_z) - min; @@ -269,7 +269,7 @@ TpmsRadialField::TpmsRadialField(const std::vector &slices, const Boundin // Bodies are the connected inside nodes, none of which is on the border. The deepest nodes of a body are the // centers of its lobes, unless the depth between them stays above NeckRatio; where the depth ties, the center // is the node nearest to the middle of the tied nodes. - const bool lobes = m_mode != TpmsAdaptiveMode::SteppedShells && m_mode != TpmsAdaptiveMode::SmoothBlend; + const bool lobes = m_mode != AdaptiveInfillMode::SteppedShells && m_mode != AdaptiveInfillMode::SmoothBlend; m_body.assign(depth.size(), -1); std::vector body_nodes; for (size_t seed = 0; seed < depth.size(); ++seed) { @@ -341,7 +341,7 @@ TpmsRadialField::TpmsRadialField(const std::vector &slices, const Boundin } throw_if_canceled(); - if (m_mode == TpmsAdaptiveMode::SteppedShells || m_mode == TpmsAdaptiveMode::SmoothBlend || m_mode == TpmsAdaptiveMode::DistanceWarp) { + if (m_mode == AdaptiveInfillMode::SteppedShells || m_mode == AdaptiveInfillMode::SmoothBlend || m_mode == AdaptiveInfillMode::DistanceWarp) { m_depth.assign(depth.size(), 0.f); for (size_t i = 0; i < depth.size(); ++i) if (m_body[i] >= 0) @@ -421,7 +421,7 @@ TpmsRadialField::TpmsRadialField(const std::vector &slices, const Boundin lobe.reach.resize(log_reach.size()); std::transform(log_reach.begin(), log_reach.end(), lobe.reach.begin(), [](double v) { return float(std::exp(v)); }); - if (m_mode == TpmsAdaptiveMode::DistanceWarp) { + if (m_mode == AdaptiveInfillMode::DistanceWarp) { std::vector mean(log_reach.size() * (Samples + 1)); for (size_t d = 0; d < log_reach.size(); ++d) { const Vec3d dir = direction(int(d) / Azimuth, int(d) % Azimuth); @@ -488,7 +488,7 @@ TpmsRadialField::TpmsRadialField(const std::vector &slices, const Boundin } } -double TpmsRadialField::depth(const Vec3d &pt) const +double AdaptiveInfillField::depth(const Vec3d &pt) const { assert(!m_depth.empty()); const Vec3d f = (pt - m_origin) / m_cell; @@ -508,7 +508,7 @@ double TpmsRadialField::depth(const Vec3d &pt) const return value; } -Vec3d TpmsRadialField::offset(const Vec3d &pt, const Vec3d ¢er) const +Vec3d AdaptiveInfillField::offset(const Vec3d &pt, const Vec3d ¢er) const { Vec3d d = pt - center; if (m_axis >= 0) @@ -516,7 +516,7 @@ Vec3d TpmsRadialField::offset(const Vec3d &pt, const Vec3d ¢er) const return d; } -double TpmsRadialField::radial(const Lobe &lobe, const Vec3d &pt) const +double AdaptiveInfillField::radial(const Lobe &lobe, const Vec3d &pt) const { const Vec3d d = this->offset(pt, lobe.center); const double r = d.norm(); @@ -562,7 +562,7 @@ double TpmsRadialField::radial(const Lobe &lobe, const Vec3d &pt) const return warp(mean); } -size_t TpmsRadialField::radial(const Vec3d &pt, Radials &out) const +size_t AdaptiveInfillField::radial(const Vec3d &pt, Radials &out) const { assert(!this->empty()); Vec3i32 idx; @@ -588,7 +588,7 @@ size_t TpmsRadialField::radial(const Vec3d &pt, Radials &out) const return count; } -size_t TpmsRadialField::body_radial(size_t node, const Vec3d &pt, float weight, Radial *out) const +size_t AdaptiveInfillField::body_radial(size_t node, const Vec3d &pt, float weight, Radial *out) const { const Body &body = m_bodies[m_body[node]]; if (body.lobes == 1) { @@ -641,7 +641,7 @@ struct AdaptiveTpmsField const long gsize = std::lround(gsizef / rsizef); const AdaptiveTpms &tpms; - const TpmsRadialField &radial_field; + const AdaptiveInfillField &radial_field; RadialScale scale; DensityLevels levels; Point size; @@ -650,7 +650,7 @@ struct AdaptiveTpmsField double cos_angle; double sin_angle; - AdaptiveTpmsField(const AdaptiveTpms &tpms, const TpmsRadialField &radial_field, const BoundingBox &bbox, coordf_t z, float angle) + AdaptiveTpmsField(const AdaptiveTpms &tpms, const AdaptiveInfillField &radial_field, const BoundingBox &bbox, coordf_t z, float angle) : tpms(tpms), radial_field(radial_field), scale(tpms, radial_field.axis() < 0 ? 3 : 2) , levels(std::max(tpms.interior_frequency / tpms.surface_frequency, 1e-3), BlendRatio, tpms.gradient) , size(bbox.size()), offs(bbox.min), z(z) @@ -666,7 +666,7 @@ struct AdaptiveTpmsField const double x = unscaled(pt.x()); const double y = unscaled(pt.y()); const Vec3d obj(cos_angle * x - sin_angle * y, sin_angle * x + cos_angle * y, z); - if (radial_field.mode() == TpmsAdaptiveMode::SmoothBlend) { + if (radial_field.mode() == AdaptiveInfillMode::SmoothBlend) { // The regular patterns of the two levels around the target of the depth, blended by a smoothstep. auto lattice = [this, x, y](int level) { const double frequency = tpms.surface_frequency * levels.scale(level); @@ -681,7 +681,7 @@ struct AdaptiveTpmsField return float((w < 1. ? (1. - w) * lattice(k) : 0.) + (w > 0. ? w * lattice(k + 1) : 0.)); } const int axis = radial_field.axis(); - TpmsRadialField::Radials radials; + AdaptiveInfillField::Radials radials; const size_t count = radial_field.radial(obj, radials); float value = 0.f; for (size_t i = 0; i < count; ++i) { @@ -708,20 +708,20 @@ template<> struct _RasterTraits }; // Continuous density level of the depth over a layer, in the object frame. -struct TpmsLevelField +struct AdaptiveLevelField { static constexpr float gsizef = 0.5f; static constexpr float rsizef = 0.05f; const coord_t rsize = scaled(rsizef); const long gsize = std::lround(gsizef / rsizef); - const TpmsRadialField &field; + const AdaptiveInfillField &field; const DensityLevels &levels; Point size; Point offs; double z; - TpmsLevelField(const TpmsRadialField &field, const DensityLevels &levels, const BoundingBox &bbox, coordf_t z) + AdaptiveLevelField(const AdaptiveInfillField &field, const DensityLevels &levels, const BoundingBox &bbox, coordf_t z) : field(field), levels(levels), size(bbox.size()), offs(bbox.min), z(z) {} @@ -736,19 +736,19 @@ struct TpmsLevelField inline Point to_Point(const Coord &p) const { return Point(to_coord(p.c) + offs.x(), to_coord(p.r) + offs.y()); } }; -template<> struct _RasterTraits +template<> struct _RasterTraits { using ValueType = float; - static float get(const TpmsLevelField &sf, size_t row, size_t col) { return sf.get_scalar(Coord(long(row), long(col))); } - static size_t rows(const TpmsLevelField &sf) { return sf.to_coordr(sf.size.y()); } - static size_t cols(const TpmsLevelField &sf) { return sf.to_coordr(sf.size.x()); } + static float get(const AdaptiveLevelField &sf, size_t row, size_t col) { return sf.get_scalar(Coord(long(row), long(col))); } + static size_t rows(const AdaptiveLevelField &sf) { return sf.to_coordr(sf.size.y()); } + static size_t cols(const AdaptiveLevelField &sf) { return sf.to_coordr(sf.size.x()); } }; } // namespace marchsq namespace Slic3r { -Polylines make_adaptive_tpms(const AdaptiveTpms &tpms, const TpmsRadialField &field, BoundingBox bbox, +Polylines make_adaptive_tpms(const AdaptiveTpms &tpms, const AdaptiveInfillField &field, BoundingBox bbox, coordf_t z, coordf_t layer_height, coordf_t spacing, float angle) { // A cell of margin for the rings closed along the raster border, and a fixed sampling grid for every region. @@ -775,21 +775,21 @@ Polylines make_adaptive_tpms(const AdaptiveTpms &tpms, const TpmsRadialField &fi return polylines; } -std::vector make_tpms_shells(const TpmsRadialField &field, const ExPolygon &expolygon, coordf_t z, - float surface_density, float interior_density, TpmsAdaptiveGradient gradient) +std::vector make_adaptive_infill_shells(const AdaptiveInfillField &field, const ExPolygon &expolygon, coordf_t z, + float surface_density, float interior_density, AdaptiveInfillGradient gradient) { const DensityLevels levels(interior_density / surface_density, ShellRatio, gradient); if (levels.count == 0) return {{surface_density, {expolygon}}}; // A fixed sampling grid, so that every region of a layer gets the same shells. - const coord_t cell = scaled(marchsq::TpmsLevelField::gsizef); + const coord_t cell = scaled(marchsq::AdaptiveLevelField::gsizef); BoundingBox bbox = get_extents(expolygon); bbox.offset(cell); bbox.merge(align_to_grid(bbox.min, Point(cell, cell))); - const marchsq::TpmsLevelField raster(field, levels, bbox, z); + const marchsq::AdaptiveLevelField raster(field, levels, bbox, z); // Each level takes the part deeper than the middle between it and the previous one. - std::vector shells; + std::vector shells; ExPolygons remaining{expolygon}; for (int level = 0; level < levels.count && !remaining.empty(); ++level) { Polygons deeper; @@ -808,12 +808,12 @@ std::vector make_tpms_shells(const TpmsRadialField &field, const ExPo return shells; } -void fill_tpms_shells(const TpmsRadialField &field, const ExPolygon &expolygon, coordf_t z, const FillParams ¶ms, coordf_t spacing, +void fill_adaptive_infill_shells(const AdaptiveInfillField &field, const ExPolygon &expolygon, coordf_t z, const FillParams ¶ms, coordf_t spacing, const std::function &fill_shell) { FillParams shell_params = params; - shell_params.tpms_adaptive = TpmsAdaptiveMode::Disabled; - for (const TpmsShell &shell : make_tpms_shells(field, expolygon, z, params.density, params.tpms_interior_density, params.tpms_adaptive_gradient)) { + shell_params.adaptive_infill_mode = AdaptiveInfillMode::Disabled; + for (const AdaptiveInfillShell &shell : make_adaptive_infill_shells(field, expolygon, z, params.density, params.adaptive_infill_interior_density, params.adaptive_infill_gradient)) { shell_params.density = shell.density; for (const ExPolygon &part : offset_ex(shell.expolygons, -float(scale_(0.5 * spacing)))) fill_shell(shell_params, part); diff --git a/src/libslic3r/Fill/FillTpmsAdaptive.hpp b/src/libslic3r/Fill/AdaptiveInfillField.hpp similarity index 84% rename from src/libslic3r/Fill/FillTpmsAdaptive.hpp rename to src/libslic3r/Fill/AdaptiveInfillField.hpp index 8e7b9db6cd..bfeaf07692 100644 --- a/src/libslic3r/Fill/FillTpmsAdaptive.hpp +++ b/src/libslic3r/Fill/AdaptiveInfillField.hpp @@ -21,7 +21,7 @@ namespace Slic3r { // lobe, 1 at its surface. Lobes are parts of a body separated by a neck, like two spheres united. In the 2D modes, // every section normal to the axis has its own bodies and lobes, and distances are measured within the section. The // modes following the distance to the surface use the depth of every point instead; Distance warp also the lobes. -class TpmsRadialField +class AdaptiveInfillField { public: struct Slice @@ -39,7 +39,7 @@ public: }; // Slices sorted by z, in the XY coordinates of the fill and the print Z. - TpmsRadialField(const std::vector &slices, const BoundingBox &bbox, TpmsAdaptiveMode mode, + AdaptiveInfillField(const std::vector &slices, const BoundingBox &bbox, AdaptiveInfillMode mode, const std::function &throw_if_canceled); // Lobes blended near the sides between them, from a body or from each of the two sections around a point. @@ -56,7 +56,7 @@ public: // Axis normal to the sections in the 2D modes, -1 in the modes graded in 3D. int axis() const { return m_axis; } - TpmsAdaptiveMode mode() const { return m_mode; } + AdaptiveInfillMode mode() const { return m_mode; } // In the modes following the distance to the surface: depth relative to the deepest point of the body, from 0 at // the surface to 1. @@ -91,7 +91,7 @@ private: static constexpr int Polar = 24; static constexpr int Azimuth = 48; - TpmsAdaptiveMode m_mode; + AdaptiveInfillMode m_mode; int m_axis; Vec3d m_origin; double m_cell; @@ -106,9 +106,9 @@ private: std::vector m_depth; }; -using TpmsRadialFieldPtr = std::unique_ptr; +using AdaptiveInfillFieldPtr = std::unique_ptr; // A field for every adaptive mode in use, indexed by the mode. -using TpmsRadialFields = std::array; +using AdaptiveInfillFields = std::array; struct AdaptiveTpms { @@ -117,14 +117,14 @@ struct AdaptiveTpms // Pattern frequencies at the surface and at the center, in radians per mm. double surface_frequency; double interior_frequency; - TpmsAdaptiveGradient gradient; + AdaptiveInfillGradient gradient; }; // Infill lines in the fill frame, the object frame rotated by -angle; z is the print_z of the layer. -Polylines make_adaptive_tpms(const AdaptiveTpms &tpms, const TpmsRadialField &field, BoundingBox bbox, +Polylines make_adaptive_tpms(const AdaptiveTpms &tpms, const AdaptiveInfillField &field, BoundingBox bbox, coordf_t z, coordf_t layer_height, coordf_t spacing, float angle); -struct TpmsShell +struct AdaptiveInfillShell { float density; ExPolygons expolygons; @@ -132,12 +132,12 @@ struct TpmsShell // Stepped shells: the parts of an expolygon in the object frame at each density, from the surface inwards; z is the // middle of the layer. -std::vector make_tpms_shells(const TpmsRadialField &field, const ExPolygon &expolygon, coordf_t z, - float surface_density, float interior_density, TpmsAdaptiveGradient gradient); +std::vector make_adaptive_infill_shells(const AdaptiveInfillField &field, const ExPolygon &expolygon, coordf_t z, + float surface_density, float interior_density, AdaptiveInfillGradient gradient); // Stepped shells: fills every shell with fill_shell at its density, each shrunk by half a line like a filled region, // so the lines connected along the boundaries of two shells don't overlap. -void fill_tpms_shells(const TpmsRadialField &field, const ExPolygon &expolygon, coordf_t z, const FillParams ¶ms, coordf_t spacing, +void fill_adaptive_infill_shells(const AdaptiveInfillField &field, const ExPolygon &expolygon, coordf_t z, const FillParams ¶ms, coordf_t spacing, const std::function &fill_shell); } // namespace Slic3r diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index 146d3ee7b4..1e6eade821 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -312,9 +312,9 @@ struct SurfaceFillParams bool gyroid_optimized = false; // For TPMS: grade the density from the surface to the interior of the object. - TpmsAdaptiveMode tpms_adaptive = TpmsAdaptiveMode::Disabled; - float tpms_interior_density = 0.f; - TpmsAdaptiveGradient tpms_adaptive_gradient = TpmsAdaptiveGradient::Linear; + AdaptiveInfillMode adaptive_infill_mode = AdaptiveInfillMode::Disabled; + float adaptive_infill_interior_density = 0.f; + AdaptiveInfillGradient adaptive_infill_gradient = AdaptiveInfillGradient::Linear; // Orca: corner smoothing factor in the range [0, 1]. double smooth_factor { 0. }; @@ -358,9 +358,9 @@ struct SurfaceFillParams RETURN_COMPARE_NON_EQUAL(skin_infill_depth); RETURN_COMPARE_NON_EQUAL(infill_overhang_angle); RETURN_COMPARE_NON_EQUAL(gyroid_optimized); - RETURN_COMPARE_NON_EQUAL(tpms_adaptive); - RETURN_COMPARE_NON_EQUAL(tpms_interior_density); - RETURN_COMPARE_NON_EQUAL(tpms_adaptive_gradient); + RETURN_COMPARE_NON_EQUAL(adaptive_infill_mode); + RETURN_COMPARE_NON_EQUAL(adaptive_infill_interior_density); + RETURN_COMPARE_NON_EQUAL(adaptive_infill_gradient); RETURN_COMPARE_NON_EQUAL(smooth_factor); RETURN_COMPARE_NON_EQUAL(center_of_surface_pattern); RETURN_COMPARE_NON_EQUAL(separated_infills); @@ -394,9 +394,9 @@ struct SurfaceFillParams this->center_of_surface_pattern == rhs.center_of_surface_pattern && this->separated_infills == rhs.separated_infills && this->gyroid_optimized == rhs.gyroid_optimized && - this->tpms_adaptive == rhs.tpms_adaptive && - this->tpms_interior_density == rhs.tpms_interior_density && - this->tpms_adaptive_gradient == rhs.tpms_adaptive_gradient && + this->adaptive_infill_mode == rhs.adaptive_infill_mode && + this->adaptive_infill_interior_density == rhs.adaptive_infill_interior_density && + this->adaptive_infill_gradient == rhs.adaptive_infill_gradient && this->smooth_factor == rhs.smooth_factor && this->fill_order == rhs.fill_order; } @@ -1010,17 +1010,17 @@ std::vector group_fills(const Layer &layer, LockRegionParam &lock_p params.extrusion_role != erTopSolidInfill && params.extrusion_role != erBottomSurface; // Orca: only the TPMS sparse infill is graded; reset otherwise, as params is reused. - params.tpms_adaptive = is_tpms_adaptive_pattern(params.pattern) && params.extrusion_role == erInternalInfill ? - region_config.tpms_adaptive.value : TpmsAdaptiveMode::Disabled; - const bool tpms_adaptive = params.tpms_adaptive != TpmsAdaptiveMode::Disabled; - params.tpms_interior_density = tpms_adaptive ? std::max(1.f, float(region_config.tpms_interior_density)) : 0.f; - params.tpms_adaptive_gradient = tpms_adaptive ? region_config.tpms_adaptive_gradient.value : TpmsAdaptiveGradient::Linear; + params.adaptive_infill_mode = is_adaptive_infill_pattern(params.pattern) && params.extrusion_role == erInternalInfill ? + region_config.adaptive_infill_mode.value : AdaptiveInfillMode::Disabled; + const bool adaptive_infill_mode = params.adaptive_infill_mode != AdaptiveInfillMode::Disabled; + params.adaptive_infill_interior_density = adaptive_infill_mode ? std::max(1.f, float(region_config.adaptive_infill_interior_density)) : 0.f; + params.adaptive_infill_gradient = adaptive_infill_mode ? region_config.adaptive_infill_gradient.value : AdaptiveInfillGradient::Linear; // 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). Adaptive density replaces it. // Stored on SurfaceFillParams; copied to FillParams during conversion. - params.gyroid_optimized = (params.pattern == ipGyroid) && region_config.gyroid_optimized && !tpms_adaptive; + params.gyroid_optimized = (params.pattern == ipGyroid) && region_config.gyroid_optimized && !adaptive_infill_mode; if (params.extrusion_role == erInternalInfill) { params.angle = calculate_infill_rotation_angle(layer.object(), layer.id(), region_config.infill_direction.value, @@ -1373,7 +1373,7 @@ void Layer::make_fills(const FillAdaptive::RegionOctrees* fill_octrees, FillLigh f->angle = surface_fill.params.angle; f->fixed_angle = surface_fill.params.fixed_angle; const FillAdaptive::Octrees *octrees = fill_octrees ? fill_octrees->region(surface_fill.region_id) : nullptr; - f->tpms_radial_field = this->object()->tpms_radial_field(surface_fill.params.tpms_adaptive); + f->adaptive_infill_field = this->object()->adaptive_infill_field(surface_fill.params.adaptive_infill_mode); f->print_config = &this->object()->print()->config(); f->print_object_config = &this->object()->config(); if (surface_fill.params.pattern == ipConcentricInternal) { @@ -1423,9 +1423,9 @@ void Layer::make_fills(const FillAdaptive::RegionOctrees* fill_octrees, FillLigh 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; - params.tpms_adaptive = surface_fill.params.tpms_adaptive; - params.tpms_interior_density = float(0.01 * surface_fill.params.tpms_interior_density); - params.tpms_adaptive_gradient = surface_fill.params.tpms_adaptive_gradient; + params.adaptive_infill_mode = surface_fill.params.adaptive_infill_mode; + params.adaptive_infill_interior_density = float(0.01 * surface_fill.params.adaptive_infill_interior_density); + params.adaptive_infill_gradient = surface_fill.params.adaptive_infill_gradient; params.smooth_factor = surface_fill.params.smooth_factor; // BBS @@ -1598,7 +1598,7 @@ Polylines Layer::generate_sparse_infill_polylines_for_anchoring(const FillAdapti f->angle = surface_fill.params.angle; f->fixed_angle = surface_fill.params.fixed_angle; const FillAdaptive::Octrees *octrees = fill_octrees ? fill_octrees->region(surface_fill.region_id) : nullptr; - f->tpms_radial_field = this->object()->tpms_radial_field(surface_fill.params.tpms_adaptive); + f->adaptive_infill_field = this->object()->adaptive_infill_field(surface_fill.params.adaptive_infill_mode); f->print_config = &this->object()->print()->config(); f->print_object_config = &this->object()->config(); @@ -1638,9 +1638,9 @@ Polylines Layer::generate_sparse_infill_polylines_for_anchoring(const FillAdapti params.infill_overhang_angle = surface_fill.params.infill_overhang_angle; params.multiline = surface_fill.params.multiline; params.gyroid_optimized = surface_fill.params.gyroid_optimized; - params.tpms_adaptive = surface_fill.params.tpms_adaptive; - params.tpms_interior_density = float(0.01 * surface_fill.params.tpms_interior_density); - params.tpms_adaptive_gradient = surface_fill.params.tpms_adaptive_gradient; + params.adaptive_infill_mode = surface_fill.params.adaptive_infill_mode; + params.adaptive_infill_interior_density = float(0.01 * surface_fill.params.adaptive_infill_interior_density); + params.adaptive_infill_gradient = surface_fill.params.adaptive_infill_gradient; params.smooth_factor = surface_fill.params.smooth_factor; // Orca: Match make_fills() when choosing the origin of plane-path patterns. // Without the sparse extrusion role, the filler uses each surface's bounds diff --git a/src/libslic3r/Fill/FillBase.hpp b/src/libslic3r/Fill/FillBase.hpp index e0308c9450..d1f07af77c 100644 --- a/src/libslic3r/Fill/FillBase.hpp +++ b/src/libslic3r/Fill/FillBase.hpp @@ -33,7 +33,7 @@ namespace Slic3r { class ExtrusionEntityCollection; } namespace Slic3r { class Surface; -class TpmsRadialField; +class AdaptiveInfillField; enum InfillPattern : int; namespace FillAdaptive { @@ -93,9 +93,9 @@ struct FillParams bool gyroid_optimized { false }; // For TPMS: grade the density from the surface to the interior of the object. Density fraction. - TpmsAdaptiveMode tpms_adaptive { TpmsAdaptiveMode::Disabled }; - float tpms_interior_density { 0.f }; - TpmsAdaptiveGradient tpms_adaptive_gradient { TpmsAdaptiveGradient::Linear }; + AdaptiveInfillMode adaptive_infill_mode { AdaptiveInfillMode::Disabled }; + float adaptive_infill_interior_density { 0.f }; + AdaptiveInfillGradient adaptive_infill_gradient { AdaptiveInfillGradient::Linear }; // Orca: corner smoothing factor in the range [0, 1]. double smooth_factor { 0. }; @@ -162,7 +162,7 @@ public: FillAdaptive::Octree* adapt_fill_octree = nullptr; // Radial coordinate inside the object for the adaptive TPMS infill - const TpmsRadialField* tpms_radial_field = nullptr; + const AdaptiveInfillField* adaptive_infill_field = nullptr; // PrintConfig and PrintObjectConfig are used by infills that use Arachne (Concentric and FillEnsuring). // Orca: also used by gap fill function. diff --git a/src/libslic3r/Fill/FillGyroid.cpp b/src/libslic3r/Fill/FillGyroid.cpp index 06cb55f70e..3ebb2f9633 100644 --- a/src/libslic3r/Fill/FillGyroid.cpp +++ b/src/libslic3r/Fill/FillGyroid.cpp @@ -18,7 +18,7 @@ #include "FillGyroid.hpp" #include "libslic3r/Polygon.hpp" #include "libslic3r/PrintConfig.hpp" -#include "FillTpmsAdaptive.hpp" +#include "AdaptiveInfillField.hpp" namespace Slic3r { @@ -315,8 +315,8 @@ void FillGyroid::_fill_surface_single( ExPolygon expolygon, Polylines &polylines_out) { - if (params.tpms_adaptive == TpmsAdaptiveMode::SteppedShells && this->tpms_radial_field != nullptr) { - fill_tpms_shells(*this->tpms_radial_field, expolygon, this->z - 0.5 * params.layer_height, params, this->spacing, + if (params.adaptive_infill_mode == AdaptiveInfillMode::SteppedShells && this->adaptive_infill_field != nullptr) { + fill_adaptive_infill_shells(*this->adaptive_infill_field, expolygon, this->z - 0.5 * params.layer_height, params, this->spacing, [&](const FillParams &shell_params, const ExPolygon &shell) { this->_fill_surface_single(shell_params, thickness_layers, direction, shell, polylines_out); }); @@ -342,11 +342,11 @@ void FillGyroid::_fill_surface_single( // generate pattern Polylines polylines; - if (params.tpms_adaptive != TpmsAdaptiveMode::Disabled && this->tpms_radial_field != nullptr) { + if (params.adaptive_infill_mode != AdaptiveInfillMode::Disabled && this->adaptive_infill_field != nullptr) { // Radians per mm of the regular pattern at a density. auto frequency = [¶ms, this](double density) { return density * DensityAdjust / (params.multiline * this->spacing); }; - polylines = make_adaptive_tpms({gyroid, frequency(params.density), frequency(params.tpms_interior_density), params.tpms_adaptive_gradient}, - *this->tpms_radial_field, bb, this->z, params.layer_height, this->spacing, infill_angle); + polylines = make_adaptive_tpms({gyroid, frequency(params.density), frequency(params.adaptive_infill_interior_density), params.adaptive_infill_gradient}, + *this->adaptive_infill_field, bb, this->z, params.layer_height, this->spacing, infill_angle); } else 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. diff --git a/src/libslic3r/Fill/FillTpmsD.cpp b/src/libslic3r/Fill/FillTpmsD.cpp index 04f8222ca5..d1a9fae8fd 100644 --- a/src/libslic3r/Fill/FillTpmsD.cpp +++ b/src/libslic3r/Fill/FillTpmsD.cpp @@ -17,7 +17,7 @@ #include "libslic3r/PrintConfig.hpp" #include "libslic3r/libslic3r.h" #include "FillTpmsD.hpp" -#include "FillTpmsAdaptive.hpp" +#include "AdaptiveInfillField.hpp" namespace Slic3r { @@ -117,8 +117,8 @@ void FillTpmsD::_fill_surface_single( ExPolygon expolygon, Polylines &polylines_out) { - if (params.tpms_adaptive == TpmsAdaptiveMode::SteppedShells && this->tpms_radial_field != nullptr) { - fill_tpms_shells(*this->tpms_radial_field, expolygon, this->z - 0.5 * params.layer_height, params, this->spacing, + if (params.adaptive_infill_mode == AdaptiveInfillMode::SteppedShells && this->adaptive_infill_field != nullptr) { + fill_adaptive_infill_shells(*this->adaptive_infill_field, expolygon, this->z - 0.5 * params.layer_height, params, this->spacing, [&](const FillParams &shell_params, const ExPolygon &shell) { this->_fill_surface_single(shell_params, thickness_layers, direction, shell, polylines_out); }); @@ -130,13 +130,13 @@ void FillTpmsD::_fill_surface_single( expolygon.rotate(-infill_angle); Polylines polylines; - if (params.tpms_adaptive != TpmsAdaptiveMode::Disabled && this->tpms_radial_field != nullptr) { + if (params.adaptive_infill_mode != AdaptiveInfillMode::Disabled && this->adaptive_infill_field != nullptr) { // Radians per mm of the regular pattern at a density. auto frequency = [¶ms, this](double density) { return density * DensityAdjust / (params.multiline * this->spacing); }; BoundingBox bbox = expolygon.contour.bounding_box(); bbox.offset(scale_((params.multiline + 1) * this->spacing)); - polylines = make_adaptive_tpms({schwarz_d, frequency(params.density), frequency(params.tpms_interior_density), params.tpms_adaptive_gradient}, - *this->tpms_radial_field, bbox, this->z, params.layer_height, this->spacing, infill_angle); + polylines = make_adaptive_tpms({schwarz_d, frequency(params.density), frequency(params.adaptive_infill_interior_density), params.adaptive_infill_gradient}, + *this->adaptive_infill_field, bbox, this->z, params.layer_height, this->spacing, infill_angle); } else { BoundingBox bb = expolygon.contour.bounding_box(); // Density adjusted to have a good %of weight. diff --git a/src/libslic3r/Fill/FillTpmsFK.cpp b/src/libslic3r/Fill/FillTpmsFK.cpp index 819ef2998e..6ebc495dd6 100644 --- a/src/libslic3r/Fill/FillTpmsFK.cpp +++ b/src/libslic3r/Fill/FillTpmsFK.cpp @@ -8,7 +8,7 @@ #include "libslic3r/Fill/FillBase.hpp" #include "libslic3r/ExPolygon.hpp" #include "FillTpmsFK.hpp" -#include "FillTpmsAdaptive.hpp" +#include "AdaptiveInfillField.hpp" #include #include #include @@ -132,8 +132,8 @@ void FillTpmsFK::_fill_surface_single(const FillParams& params, ExPolygon expolygon, Polylines& polylines_out) { - if (params.tpms_adaptive == TpmsAdaptiveMode::SteppedShells && this->tpms_radial_field != nullptr) { - fill_tpms_shells(*this->tpms_radial_field, expolygon, this->z - 0.5 * params.layer_height, params, this->spacing, + if (params.adaptive_infill_mode == AdaptiveInfillMode::SteppedShells && this->adaptive_infill_field != nullptr) { + fill_adaptive_infill_shells(*this->adaptive_infill_field, expolygon, this->z - 0.5 * params.layer_height, params, this->spacing, [&](const FillParams &shell_params, const ExPolygon &shell) { this->_fill_surface_single(shell_params, thickness_layers, direction, shell, polylines_out); }); @@ -151,10 +151,10 @@ void FillTpmsFK::_fill_surface_single(const FillParams& params, // Enlarge the bounding box by the multi-line width to avoid artifacts at the edges. bbox.offset(scale_((params.multiline + 1) * spacing)); Polylines polylines; - if (params.tpms_adaptive != TpmsAdaptiveMode::Disabled && this->tpms_radial_field != nullptr) { - polylines = make_adaptive_tpms({fischer_koch, 2. * PI / period(params.density), 2. * PI / period(params.tpms_interior_density), - params.tpms_adaptive_gradient}, - *this->tpms_radial_field, bbox, this->z, params.layer_height, spacing, infill_angle); + if (params.adaptive_infill_mode != AdaptiveInfillMode::Disabled && this->adaptive_infill_field != nullptr) { + polylines = make_adaptive_tpms({fischer_koch, 2. * PI / period(params.density), 2. * PI / period(params.adaptive_infill_interior_density), + params.adaptive_infill_gradient}, + *this->adaptive_infill_field, bbox, this->z, params.layer_height, spacing, infill_angle); } else { marchsq::ScalarField sf = marchsq::ScalarField(bbox, this->z, period(params.density)); // Get simplified lines using coarse tolerance of 0.1mm (this is infill). diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index 20eff0446f..8e58a5e671 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -443,8 +443,8 @@ coordf_t Layer::get_sparse_infill_max_void_area() if (density == 0.) return -1; // Orca: the adaptive TPMS infill is as sparse as its interior density. - if (density < 100.f && config.tpms_adaptive != TpmsAdaptiveMode::Disabled && is_tpms_adaptive_pattern(pattern)) - density = std::min(density, std::max(1.f, float(config.tpms_interior_density))); + if (density < 100.f && config.adaptive_infill_mode != AdaptiveInfillMode::Disabled && is_adaptive_infill_pattern(pattern)) + density = std::min(density, std::max(1.f, float(config.adaptive_infill_interior_density))); //BBS: rough estimation and need to be optimized double spacing = flow.scaled_spacing() * (100 - density) / density; diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 9135f8fd2e..edd93390b4 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -1183,9 +1183,9 @@ static std::vector s_Preset_print_options{ "is_infill_first", "sparse_infill_density", "fill_multiline", - "tpms_adaptive", - "tpms_interior_density", - "tpms_adaptive_gradient", + "adaptive_infill_mode", + "adaptive_infill_interior_density", + "adaptive_infill_gradient", "gyroid_optimized", "sparse_infill_pattern", "sparse_infill_smooth_factor", diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 11de1d80e4..b36349c587 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -12,7 +12,7 @@ #include "PrintBase.hpp" #include "Fill/FillAdaptive.hpp" #include "Fill/FillLightning.hpp" -#include "Fill/FillTpmsAdaptive.hpp" +#include "Fill/AdaptiveInfillField.hpp" #include "BoundingBox.hpp" #include "ExtrusionEntityCollection.hpp" @@ -407,7 +407,7 @@ public: double max_z() const { return m_max_z; } // Centering offset of the sliced mesh from the scaled and rotated mesh of the model. const Point& center_offset() const { return m_center_offset; } - const TpmsRadialField* tpms_radial_field(TpmsAdaptiveMode mode) const { return m_tpms_radial_fields[size_t(mode)].get(); } + const AdaptiveInfillField* adaptive_infill_field(AdaptiveInfillMode mode) const { return m_adaptive_infill_fields[size_t(mode)].get(); } // BBS void generate_support_preview(); @@ -655,7 +655,7 @@ private: FillAdaptive::RegionOctrees prepare_adaptive_infill_data( const std::vector>& surfaces_w_layer) const; FillLightning::GeneratorPtr prepare_lightning_infill_data(); - TpmsRadialFields prepare_tpms_radial_fields() const; + AdaptiveInfillFields prepare_adaptive_infill_fields() const; // BBS SupportNecessaryType is_support_necessary(); @@ -706,7 +706,7 @@ private: FillAdaptive::RegionOctrees m_adaptive_fill_octrees; std::vector m_separated_body_bboxes; FillLightning::GeneratorPtr m_lightning_generator; - TpmsRadialFields m_tpms_radial_fields; + AdaptiveInfillFields m_adaptive_infill_fields; std::vector < VolumeSlices > firstLayerObjSliceByVolume; std::vector firstLayerObjSliceByGroups; diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 1d9316e8df..48d92da201 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -366,24 +366,24 @@ static t_config_enum_values s_keys_map_SurfaceFillOrder{ CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(SurfaceFillOrder) //Orca -static t_config_enum_values s_keys_map_TpmsAdaptiveMode{ - { "disabled", int(TpmsAdaptiveMode::Disabled) }, - { "distance_warp", int(TpmsAdaptiveMode::DistanceWarp) }, - { "smooth_blend", int(TpmsAdaptiveMode::SmoothBlend) }, - { "stepped_shells", int(TpmsAdaptiveMode::SteppedShells) }, - { "lobes", int(TpmsAdaptiveMode::Lobes) }, - { "normal_z", int(TpmsAdaptiveMode::NormalZ) }, - { "normal_y", int(TpmsAdaptiveMode::NormalY) }, - { "normal_x", int(TpmsAdaptiveMode::NormalX) }, +static t_config_enum_values s_keys_map_AdaptiveInfillMode{ + { "disabled", int(AdaptiveInfillMode::Disabled) }, + { "distance_warp", int(AdaptiveInfillMode::DistanceWarp) }, + { "smooth_blend", int(AdaptiveInfillMode::SmoothBlend) }, + { "stepped_shells", int(AdaptiveInfillMode::SteppedShells) }, + { "lobes", int(AdaptiveInfillMode::Lobes) }, + { "normal_z", int(AdaptiveInfillMode::NormalZ) }, + { "normal_y", int(AdaptiveInfillMode::NormalY) }, + { "normal_x", int(AdaptiveInfillMode::NormalX) }, }; -CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(TpmsAdaptiveMode) +CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(AdaptiveInfillMode) -static t_config_enum_values s_keys_map_TpmsAdaptiveGradient{ - { "linear", int(TpmsAdaptiveGradient::Linear) }, - { "quadratic", int(TpmsAdaptiveGradient::Quadratic) }, - { "exponential", int(TpmsAdaptiveGradient::Exponential) }, +static t_config_enum_values s_keys_map_AdaptiveInfillGradient{ + { "linear", int(AdaptiveInfillGradient::Linear) }, + { "quadratic", int(AdaptiveInfillGradient::Quadratic) }, + { "exponential", int(AdaptiveInfillGradient::Exponential) }, }; -CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(TpmsAdaptiveGradient) +CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(AdaptiveInfillGradient) //BBS static t_config_enum_values s_keys_map_PrintSequence { @@ -3660,7 +3660,7 @@ void PrintConfigDef::init_fff_params() def->max = 10; // Maximum number of lines for infill pattern def->set_default_value(new ConfigOptionInt(1)); - def = this->add("tpms_adaptive", coEnum); + def = this->add("adaptive_infill_mode", coEnum); def->label = L("Adaptive density (experimental)"); def->category = L("Strength"); def->tooltip = L("Grades the Gyroid and TPMS infill inside the object: its cells grow from the surface of the " @@ -3678,7 +3678,7 @@ void PrintConfigDef::init_fff_params() "joined to the rest by a narrower neck, is graded towards its own center.\n" " - Normal Z, Y or X: follows the sections of the object normal to that axis, so the density " "does not change along it."); - def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); + def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); def->enum_values.push_back("disabled"); def->enum_values.push_back("distance_warp"); def->enum_values.push_back("smooth_blend"); @@ -3696,9 +3696,9 @@ void PrintConfigDef::init_fff_params() def->enum_labels.push_back(L("Normal Y")); def->enum_labels.push_back(L("Normal X")); def->mode = comAdvanced; - def->set_default_value(new ConfigOptionEnum(TpmsAdaptiveMode::Disabled)); + def->set_default_value(new ConfigOptionEnum(AdaptiveInfillMode::Disabled)); - def = this->add("tpms_interior_density", coPercent); + def = this->add("adaptive_infill_interior_density", coPercent); def->label = L("Interior density"); def->category = L("Strength"); def->tooltip = L("Density of the adaptive infill at the center of the object."); @@ -3708,7 +3708,7 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionPercent(5)); - def = this->add("tpms_adaptive_gradient", coEnum); + def = this->add("adaptive_infill_gradient", coEnum); def->label = L("Adaptive gradient"); def->category = L("Strength"); def->tooltip = L("How the density changes from the surface to the center of the object.\n" @@ -3717,7 +3717,7 @@ void PrintConfigDef::init_fff_params() "changes faster towards the center.\n" "Exponential: the density changes quickly just below the surface and levels off towards " "the center."); - def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); + def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); def->enum_values.push_back("linear"); def->enum_values.push_back("quadratic"); def->enum_values.push_back("exponential"); @@ -3725,7 +3725,7 @@ void PrintConfigDef::init_fff_params() def->enum_labels.push_back(L("Quadratic")); def->enum_labels.push_back(L("Exponential")); def->mode = comAdvanced; - def->set_default_value(new ConfigOptionEnum(TpmsAdaptiveGradient::Linear)); + def->set_default_value(new ConfigOptionEnum(AdaptiveInfillGradient::Linear)); // 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 @@ -9665,6 +9665,12 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va opt_key = "change_filament_gcode"; } else if (opt_key == "bridge_fan_speed") { opt_key = "overhang_fan_speed"; + } else if (opt_key == "tpms_adaptive") { + opt_key = "adaptive_infill_mode"; + } else if (opt_key == "tpms_interior_density") { + opt_key = "adaptive_infill_interior_density"; + } else if (opt_key == "tpms_adaptive_gradient") { + opt_key = "adaptive_infill_gradient"; } else if (opt_key == "infill_extruder" || opt_key == "sparse_infill_filament") { // ORCA: legacy feature-filament selector. Pre-2.4.0-dev these keys were 1-based and the // default value "1" meant "the first/active filament". The current scheme uses a dedicated diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index ed793ec3cc..55e82656f0 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -172,8 +172,8 @@ inline bool is_separable_infill_pattern(InfillPattern pattern) // Orca: Infill patterns laid out by an octree, which each connected body always gets of its own. inline bool is_octree_infill_pattern(InfillPattern pattern) { return pattern == ipAdaptiveCubic || pattern == ipSupportCubic; } -// Orca: Infill patterns graded by the "tpms_adaptive" option. -inline bool is_tpms_adaptive_pattern(InfillPattern pattern) { return pattern == ipGyroid || pattern == ipTpmsD || pattern == ipTpmsFK; } +// Orca: Infill patterns graded by the "adaptive_infill_mode" option. +inline bool is_adaptive_infill_pattern(InfillPattern pattern) { return pattern == ipGyroid || pattern == ipTpmsD || pattern == ipTpmsFK; } // Orca: Infill patterns that round their corners by the "sparse_infill_smooth_factor" option. // Grid, Triangles and Tri-hexagon only do so in their trapezoidal form, which is generated with more @@ -279,8 +279,8 @@ enum class SurfaceFillOrder { Count, }; -// Orca: what the adaptive TPMS density follows: the 3D shape of the object, or its 2D sections normal to an axis. -enum class TpmsAdaptiveMode { +// Orca: what the adaptive infill density follows: the 3D shape of the object, or its 2D sections normal to an axis. +enum class AdaptiveInfillMode { Disabled, DistanceWarp, SmoothBlend, @@ -292,8 +292,8 @@ enum class TpmsAdaptiveMode { Count, }; -// Orca: how the adaptive TPMS density changes from the object surface to its deepest point. -enum class TpmsAdaptiveGradient { +// Orca: how the adaptive infill density changes from the object surface to its deepest point. +enum class AdaptiveInfillGradient { Linear, Quadratic, Exponential, @@ -816,8 +816,8 @@ CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(PerimeterGeneratorType) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(ToolChangeOrderingType) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(PowerLossRecoveryMode) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SurfaceFillOrder) -CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(TpmsAdaptiveMode) -CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(TpmsAdaptiveGradient) +CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(AdaptiveInfillMode) +CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(AdaptiveInfillGradient) #undef CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS @@ -1501,9 +1501,9 @@ PRINT_CONFIG_CLASS_DEFINE( // Orca: ((ConfigOptionFloatOrPercent, infill_combination_max_layer_height)) ((ConfigOptionInt, fill_multiline)) - ((ConfigOptionEnum, tpms_adaptive)) - ((ConfigOptionPercent, tpms_interior_density)) - ((ConfigOptionEnum, tpms_adaptive_gradient)) + ((ConfigOptionEnum, adaptive_infill_mode)) + ((ConfigOptionPercent, adaptive_infill_interior_density)) + ((ConfigOptionEnum, adaptive_infill_gradient)) ((ConfigOptionBool, gyroid_optimized)) // Ironing options ((ConfigOptionEnum, ironing_type)) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 7e9b21ccdf..150e987bcb 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -33,7 +33,7 @@ #include "Fill/FillAdaptive.hpp" #include "Fill/Fill.hpp" #include "Fill/FillLightning.hpp" -#include "Fill/FillTpmsAdaptive.hpp" +#include "Fill/AdaptiveInfillField.hpp" #include "format.hpp" #include "AABBTreeIndirect.hpp" #include "AABBTreeLines.hpp" @@ -1252,19 +1252,19 @@ FillLightning::GeneratorPtr PrintObject::prepare_lightning_infill_data() return has_lightning_infill ? FillLightning::build_generator(std::as_const(*this), [this]() -> void { this->throw_if_canceled(); }) : FillLightning::GeneratorPtr(); } -TpmsRadialFields PrintObject::prepare_tpms_radial_fields() const +AdaptiveInfillFields PrintObject::prepare_adaptive_infill_fields() const { - TpmsRadialFields fields; - std::array modes{}; + AdaptiveInfillFields fields; + std::array modes{}; for (size_t region_id = 0; region_id < this->num_printing_regions(); ++region_id) if (const PrintRegionConfig &config = this->printing_region(region_id).config(); - config.sparse_infill_density > 0 && config.sparse_infill_density < 100 && is_tpms_adaptive_pattern(config.sparse_infill_pattern)) - modes[size_t(config.tpms_adaptive.value)] = true; - modes[size_t(TpmsAdaptiveMode::Disabled)] = false; + config.sparse_infill_density > 0 && config.sparse_infill_density < 100 && is_adaptive_infill_pattern(config.sparse_infill_pattern)) + modes[size_t(config.adaptive_infill_mode.value)] = true; + modes[size_t(AdaptiveInfillMode::Disabled)] = false; if (std::find(modes.begin(), modes.end(), true) == modes.end() || m_layers.empty()) return fields; - std::vector slices; + std::vector slices; slices.reserve(m_layers.size()); BoundingBox bbox; for (const Layer *layer : m_layers) { @@ -1277,7 +1277,7 @@ TpmsRadialFields PrintObject::prepare_tpms_radial_fields() const if (!modes[mode]) continue; // Without a field, the infill falls back to the regular pattern. - auto field = std::make_unique(slices, bbox, TpmsAdaptiveMode(mode), [this]() { m_print->throw_if_canceled(); }); + auto field = std::make_unique(slices, bbox, AdaptiveInfillMode(mode), [this]() { m_print->throw_if_canceled(); }); if (!field->empty()) fields[mode] = std::move(field); } @@ -1685,9 +1685,9 @@ bool PrintObject::invalidate_state_by_config_options( || opt_key == "infill_overhang_angle") { steps.emplace_back(posInfill); } else if (opt_key == "sparse_infill_pattern" - || opt_key == "tpms_adaptive" - || opt_key == "tpms_interior_density" - || opt_key == "tpms_adaptive_gradient" + || opt_key == "adaptive_infill_mode" + || opt_key == "adaptive_infill_interior_density" + || opt_key == "adaptive_infill_gradient" // Orca: Body centering now also determines bridge anchors during preparation. // Invalidating preparation also invalidates infill, including top/bottom surfaces. || opt_key == "center_of_surface_pattern" @@ -3195,7 +3195,7 @@ void PrintObject::bridge_over_infill() } this->m_adaptive_fill_octrees = this->prepare_adaptive_infill_data(surfaces_w_layer); - this->m_tpms_radial_fields = this->prepare_tpms_radial_fields(); + this->m_adaptive_infill_fields = this->prepare_adaptive_infill_fields(); std::vector layers_to_generate_infill; for (const auto &pair : surfaces_by_layer) { diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 8bf5b843cc..a03f63c737 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -843,17 +843,17 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, in 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; - // The sparse infill density is the surface density of the adaptive TPMS infill; at 100% the infill is solid. - bool have_tpms_infill = have_infill && config->option("sparse_infill_density")->value < 100 && - is_tpms_adaptive_pattern(pattern); - toggle_line("tpms_adaptive", have_tpms_infill); - bool have_tpms_adaptive = have_tpms_infill && config->opt_enum("tpms_adaptive") != TpmsAdaptiveMode::Disabled; - toggle_line("tpms_interior_density", have_tpms_adaptive); - toggle_line("tpms_adaptive_gradient", have_tpms_adaptive); + // The sparse infill density is the surface density of the adaptive infill; at 100% the infill is solid. + bool have_adaptive_infill_pattern = have_infill && config->option("sparse_infill_density")->value < 100 && + is_adaptive_infill_pattern(pattern); + toggle_line("adaptive_infill_mode", have_adaptive_infill_pattern); + bool have_adaptive_infill = have_adaptive_infill_pattern && config->opt_enum("adaptive_infill_mode") != AdaptiveInfillMode::Disabled; + toggle_line("adaptive_infill_interior_density", have_adaptive_infill); + toggle_line("adaptive_infill_gradient", have_adaptive_infill); // gyroid_optimized only applies when the sparse infill pattern is gyroid without adaptive density; // hide the whole line otherwise. - toggle_line("gyroid_optimized", have_infill && pattern == ipGyroid && !have_tpms_adaptive); + toggle_line("gyroid_optimized", have_infill && pattern == ipGyroid && !have_adaptive_infill); // If there is infill, enable/disable fill_multiline according to whether the pattern supports multiline infill. if (have_infill) { diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index c838b898f6..f6adfc0c38 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -149,9 +149,9 @@ std::map> SettingsFactory::PART_CATE {"sparse_infill_density", "", 1}, {"fill_multiline", "", 1}, {"sparse_infill_pattern", "", 1}, - {"tpms_adaptive", "", 1}, - {"tpms_interior_density", "", 1}, - {"tpms_adaptive_gradient", "", 1}, + {"adaptive_infill_mode", "", 1}, + {"adaptive_infill_interior_density", "", 1}, + {"adaptive_infill_gradient", "", 1}, {"sparse_infill_smooth_factor", "", 1}, {"lateral_lattice_angle_1", "", 1}, {"lateral_lattice_angle_2", "", 1}, diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 0b96ceed78..00fd72e57f 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2968,9 +2968,9 @@ 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("tpms_adaptive", "strength_settings_patterns#adaptive-density"); - optgroup->append_single_option_line("tpms_interior_density", "strength_settings_patterns#interior-density"); - optgroup->append_single_option_line("tpms_adaptive_gradient", "strength_settings_patterns#adaptive-gradient"); + optgroup->append_single_option_line("adaptive_infill_mode", "strength_settings_patterns#adaptive-density"); + optgroup->append_single_option_line("adaptive_infill_interior_density", "strength_settings_patterns#interior-density"); + optgroup->append_single_option_line("adaptive_infill_gradient", "strength_settings_patterns#adaptive-gradient"); optgroup->append_single_option_line("gyroid_optimized", "strength_settings_patterns#gyroid-optimized"); optgroup->append_single_option_line("sparse_infill_smooth_factor", "strength_settings_infill#sparse-infill-smooth-factor"); optgroup->append_single_option_line("infill_direction", "strength_settings_infill#direction"); diff --git a/tests/fff_print/test_fill.cpp b/tests/fff_print/test_fill.cpp index 1fbedcda8f..7ca8487965 100644 --- a/tests/fff_print/test_fill.cpp +++ b/tests/fff_print/test_fill.cpp @@ -37,7 +37,7 @@ #include "libslic3r/Fill/Fill.hpp" #include "libslic3r/Fill/FillAdaptive.hpp" #include "libslic3r/Fill/FillGyroid.hpp" -#include "libslic3r/Fill/FillTpmsAdaptive.hpp" +#include "libslic3r/Fill/AdaptiveInfillField.hpp" #include "libslic3r/Flow.hpp" #include "libslic3r/Geometry.hpp" #include "libslic3r/IntersectionPoints.hpp" @@ -2060,9 +2060,9 @@ TEST_CASE("Adaptive TPMS infill thins out from the surface to the interior densi Slic3r::Test::init_and_process_print({Slic3r::Test::cube(60)}, print, {{"sparse_infill_pattern", pattern}, {"sparse_infill_density", "25%"}, - {"tpms_adaptive", adaptive}, - {"tpms_interior_density", "5%"}, - {"tpms_adaptive_gradient", "linear"}, + {"adaptive_infill_mode", adaptive}, + {"adaptive_infill_interior_density", "5%"}, + {"adaptive_infill_gradient", "linear"}, {"layer_height", 0.4}, {"initial_layer_print_height", 0.4}}); }; @@ -2089,9 +2089,9 @@ TEST_CASE("Adaptive TPMS infill of a tall object is sparsest at its middle heigh Slic3r::Test::init_and_process_print({make_cube(30., 30., 90.)}, print, {{"sparse_infill_pattern", "tpmsd"}, {"sparse_infill_density", "25%"}, - {"tpms_adaptive", "lobes"}, - {"tpms_interior_density", "5%"}, - {"tpms_adaptive_gradient", "linear"}, + {"adaptive_infill_mode", "lobes"}, + {"adaptive_infill_interior_density", "5%"}, + {"adaptive_infill_gradient", "linear"}, {"layer_height", 0.4}, {"initial_layer_print_height", 0.4}}); const Polygons core = centered_square(5.); @@ -2111,9 +2111,9 @@ TEST_CASE("2D adaptive TPMS infill does not change along its axis", "[Fill]") Slic3r::Test::init_and_process_print({along_x ? make_cube(90., 30., 30.) : make_cube(30., 30., 90.)}, print, {{"sparse_infill_pattern", "gyroid"}, {"sparse_infill_density", "25%"}, - {"tpms_adaptive", adaptive}, - {"tpms_interior_density", "5%"}, - {"tpms_adaptive_gradient", "linear"}, + {"adaptive_infill_mode", adaptive}, + {"adaptive_infill_interior_density", "5%"}, + {"adaptive_infill_gradient", "linear"}, {"layer_height", 0.4}, {"initial_layer_print_height", 0.4}}); }; @@ -2147,9 +2147,9 @@ TEST_CASE("Adaptive TPMS shells and blend keep the whole deep core of a tall obj Slic3r::Test::init_and_process_print({make_cube(30., 30., 90.)}, print, {{"sparse_infill_pattern", "tpmsd"}, {"sparse_infill_density", "25%"}, - {"tpms_adaptive", adaptive}, - {"tpms_interior_density", "5%"}, - {"tpms_adaptive_gradient", "linear"}, + {"adaptive_infill_mode", adaptive}, + {"adaptive_infill_interior_density", "5%"}, + {"adaptive_infill_gradient", "linear"}, {"layer_height", 0.4}, {"initial_layer_print_height", 0.4}}); }; @@ -2179,9 +2179,9 @@ TEST_CASE("Adaptive TPMS infill is sparse at the center of both of two united sp Slic3r::Test::init_and_process_print({TriangleMesh(spheres)}, print, {{"sparse_infill_pattern", "gyroid"}, {"sparse_infill_density", "25%"}, - {"tpms_adaptive", adaptive}, - {"tpms_interior_density", "5%"}, - {"tpms_adaptive_gradient", "linear"}, + {"adaptive_infill_mode", adaptive}, + {"adaptive_infill_interior_density", "5%"}, + {"adaptive_infill_gradient", "linear"}, {"layer_height", 0.4}, {"initial_layer_print_height", 0.4}}); }; @@ -2209,9 +2209,9 @@ TEST_CASE("Adaptive TPMS gradients keep the surface density deeper in the order Slic3r::Test::init_and_process_print({Slic3r::Test::cube(40)}, print, {{"sparse_infill_pattern", "tpmsd"}, {"sparse_infill_density", "25%"}, - {"tpms_adaptive", "lobes"}, - {"tpms_interior_density", "5%"}, - {"tpms_adaptive_gradient", gradient}, + {"adaptive_infill_mode", "lobes"}, + {"adaptive_infill_interior_density", "5%"}, + {"adaptive_infill_gradient", gradient}, {"layer_height", 0.4}, {"initial_layer_print_height", 0.4}}); return sparse_infill_length(print, 0., 40., centered_square(20.)); @@ -2236,9 +2236,9 @@ TEST_CASE("Adaptive TPMS settings leave the infill unchanged when they do not ap {{"sparse_infill_pattern", pattern}, {"sparse_infill_density", "20%"}, {"layer_height", 0.2}, - {"tpms_adaptive", adaptive}, - {"tpms_interior_density", "40%"}, - {"tpms_adaptive_gradient", "exponential"}}); + {"adaptive_infill_mode", adaptive}, + {"adaptive_infill_interior_density", "40%"}, + {"adaptive_infill_gradient", "exponential"}}); const SparseInfillShape expected = sparse_infill_shape(reference); REQUIRE(expected.path_count > 0); CHECK(sparse_infill_shape(tuned).sequence == expected.sequence); @@ -2252,7 +2252,7 @@ TEST_CASE("Adaptive gyroid infill ignores the Z-buckling optimization", "[Fill]" {{"sparse_infill_pattern", "gyroid"}, {"sparse_infill_density", "10%"}, {"gyroid_optimized", gyroid_optimized}, - {"tpms_adaptive", "lobes"}, + {"adaptive_infill_mode", "lobes"}, {"layer_height", 0.2}}); return sparse_infill_shape(print); }; @@ -2268,10 +2268,10 @@ TEST_CASE("Adaptive TPMS infill of a region matches the infill of a larger regio // An 80 x 80 x 40 mm box around both regions, which share its radial field. const ExPolygons box{ExPolygon(Points{Point::new_scale(60., 20.), Point::new_scale(140., 20.), Point::new_scale(140., 100.), Point::new_scale(60., 100.)})}; - std::vector slices; + std::vector slices; for (int i = 0; i < 200; ++i) slices.push_back({0.2 * i, 0.2 * (i + 1), &box}); - const TpmsRadialField field(slices, get_extents(box), TpmsAdaptiveMode::Lobes, [] {}); + const AdaptiveInfillField field(slices, get_extents(box), AdaptiveInfillMode::Lobes, [] {}); auto circle = [](double radius) { Polygon contour = make_circle_num_segments(scale_(radius), 120); @@ -2285,13 +2285,13 @@ TEST_CASE("Adaptive TPMS infill of a region matches the infill of a larger regio filler->spacing = 0.45; filler->angle = float(M_PI / 7.); filler->z = z; - filler->tpms_radial_field = &field; + filler->adaptive_infill_field = &field; FillParams params; params.density = 0.2f; - params.tpms_adaptive = TpmsAdaptiveMode::Lobes; - params.tpms_interior_density = 0.05f; - params.tpms_adaptive_gradient = TpmsAdaptiveGradient::Linear; + params.adaptive_infill_mode = AdaptiveInfillMode::Lobes; + params.adaptive_infill_interior_density = 0.05f; + params.adaptive_infill_gradient = AdaptiveInfillGradient::Linear; params.layer_height = 0.2; params.dont_adjust = true; Surface surface(stInternal, expolygon); @@ -2328,8 +2328,8 @@ TEST_CASE("Adaptive TPMS anchors match the printed infill", "[Fill][InternalBrid Slic3r::Test::init_and_process_print({Slic3r::Test::cube(30)}, print, {{"sparse_infill_pattern", pattern}, {"sparse_infill_density", "25%"}, - {"tpms_adaptive", "lobes"}, - {"tpms_interior_density", "5%"}, + {"adaptive_infill_mode", "lobes"}, + {"adaptive_infill_interior_density", "5%"}, {"layer_height", 0.2}, {"initial_layer_print_height", 0.2}, {"resolution", 0.012}}); diff --git a/tests/libslic3r/CMakeLists.txt b/tests/libslic3r/CMakeLists.txt index 1f72f83478..5c34b151b2 100644 --- a/tests/libslic3r/CMakeLists.txt +++ b/tests/libslic3r/CMakeLists.txt @@ -35,7 +35,7 @@ add_executable(${_TEST_NAME}_tests test_fill_corner_smoothing.cpp test_filament_mixer.cpp test_fill_plane_path.cpp - test_fill_tpms_adaptive.cpp + test_adaptive_infill_field.cpp test_geometry.cpp test_imex_arrange.cpp test_imex_helpers.cpp diff --git a/tests/libslic3r/test_fill_tpms_adaptive.cpp b/tests/libslic3r/test_adaptive_infill_field.cpp similarity index 73% rename from tests/libslic3r/test_fill_tpms_adaptive.cpp rename to tests/libslic3r/test_adaptive_infill_field.cpp index d150ae8d7b..ab422bb95d 100644 --- a/tests/libslic3r/test_fill_tpms_adaptive.cpp +++ b/tests/libslic3r/test_adaptive_infill_field.cpp @@ -13,7 +13,7 @@ #include "libslic3r/BoundingBox.hpp" #include "libslic3r/ClipperUtils.hpp" #include "libslic3r/ExPolygon.hpp" -#include "libslic3r/Fill/FillTpmsAdaptive.hpp" +#include "libslic3r/Fill/AdaptiveInfillField.hpp" #include "libslic3r/Point.hpp" #include "libslic3r/Polygon.hpp" #include "libslic3r/PrintConfig.hpp" @@ -30,24 +30,24 @@ ExPolygon rectangle(double x0, double y0, double x1, double y1) } // The expolygons stacked in 0.2 mm layers from z = 0 to height. -TpmsRadialField radial_field(const ExPolygons &expolygons, double height, TpmsAdaptiveMode mode = TpmsAdaptiveMode::Lobes) +AdaptiveInfillField radial_field(const ExPolygons &expolygons, double height, AdaptiveInfillMode mode = AdaptiveInfillMode::Lobes) { - std::vector slices; + std::vector slices; for (int i = 0; 0.2 * (i + 1) < height + EPSILON; ++i) slices.push_back({0.2 * i, 0.2 * (i + 1), &expolygons}); - return TpmsRadialField(slices, get_extents(expolygons), mode, [] {}); + return AdaptiveInfillField(slices, get_extents(expolygons), mode, [] {}); } -double radial(const TpmsRadialField &field, const Vec3d &pt) +double radial(const AdaptiveInfillField &field, const Vec3d &pt) { - TpmsRadialField::Radials radials; + AdaptiveInfillField::Radials radials; field.radial(pt, radials); return radials[0].t; } -Vec3d center(const TpmsRadialField &field, const Vec3d &pt) +Vec3d center(const AdaptiveInfillField &field, const Vec3d &pt) { - TpmsRadialField::Radials radials; + AdaptiveInfillField::Radials radials; field.radial(pt, radials); return radials[0].center; } @@ -57,11 +57,11 @@ constexpr double Tolerance = 0.075; } // namespace -TEST_CASE("TPMS radial field is zero at the center of a cube and one at its faces", "[FillTpmsAdaptive]") +TEST_CASE("Adaptive infill field is zero at the center of a cube and one at its faces", "[AdaptiveInfillField]") { // A 20 mm cube, 10 mm from its center to every face. const ExPolygons square{rectangle(0., 0., 20., 20.)}; - const TpmsRadialField field = radial_field(square, 20.); + const AdaptiveInfillField field = radial_field(square, 20.); const Vec3d c = center(field, {10., 10., 10.}); CHECK_THAT(c.x(), WithinAbs(10., 0.5)); @@ -74,10 +74,10 @@ TEST_CASE("TPMS radial field is zero at the center of a cube and one at its face } } -TEST_CASE("TPMS radial field grows linearly from the center of a cube to its faces", "[FillTpmsAdaptive]") +TEST_CASE("Adaptive infill field grows linearly from the center of a cube to its faces", "[AdaptiveInfillField]") { const ExPolygons square{rectangle(0., 0., 20., 20.)}; - const TpmsRadialField field = radial_field(square, 20.); + const AdaptiveInfillField field = radial_field(square, 20.); for (double d = 1.; d < 10.; d += 1.) { CAPTURE(d); CHECK_THAT(radial(field, {10. - d, 10., 10.}), WithinAbs(d / 10., Tolerance)); @@ -85,11 +85,11 @@ TEST_CASE("TPMS radial field grows linearly from the center of a cube to its fac } } -TEST_CASE("TPMS radial field of a tall box is centered at its middle height", "[FillTpmsAdaptive]") +TEST_CASE("Adaptive infill field of a tall box is centered at its middle height", "[AdaptiveInfillField]") { // 20 x 20 x 60 mm: 10 mm from the center to the sides, 30 mm to the top and the bottom. const ExPolygons square{rectangle(0., 0., 20., 20.)}; - const TpmsRadialField field = radial_field(square, 60.); + const AdaptiveInfillField field = radial_field(square, 60.); CHECK_THAT(center(field, {10., 10., 45.}).z(), WithinAbs(30., 0.5)); CHECK_THAT(radial(field, {10., 10., 15.}), WithinAbs(0.5, Tolerance)); @@ -97,10 +97,10 @@ TEST_CASE("TPMS radial field of a tall box is centered at its middle height", "[ CHECK_THAT(radial(field, {15., 10., 30.}), WithinAbs(0.5, Tolerance)); } -TEST_CASE("TPMS radial field grades every body towards its own center", "[FillTpmsAdaptive]") +TEST_CASE("Adaptive infill field grades every body towards its own center", "[AdaptiveInfillField]") { const ExPolygons squares{rectangle(0., 0., 20., 20.), rectangle(30., 0., 50., 20.)}; - const TpmsRadialField field = radial_field(squares, 20.); + const AdaptiveInfillField field = radial_field(squares, 20.); CHECK_THAT(center(field, {5., 10., 10.}).x(), WithinAbs(10., 0.5)); CHECK_THAT(center(field, {45., 10., 10.}).x(), WithinAbs(40., 0.5)); @@ -108,20 +108,20 @@ TEST_CASE("TPMS radial field grades every body towards its own center", "[FillTp CHECK_THAT(radial(field, {30., 10., 10.}), WithinAbs(1., Tolerance)); } -TEST_CASE("TPMS radial field is beyond one outside of the object", "[FillTpmsAdaptive]") +TEST_CASE("Adaptive infill field is beyond one outside of the object", "[AdaptiveInfillField]") { const ExPolygons square{rectangle(0., 0., 20., 20.)}; - const TpmsRadialField field = radial_field(square, 20.); + const AdaptiveInfillField field = radial_field(square, 20.); CHECK(radial(field, {-5., 10., 10.}) > 1.); CHECK(radial(field, {10., 10., 30.}) > 1.); } -TEST_CASE("TPMS radial field grades every lobe of a body towards its own center", "[FillTpmsAdaptive]") +TEST_CASE("Adaptive infill field grades every lobe of a body towards its own center", "[AdaptiveInfillField]") { // Two spheres of 10 mm united, their centers 16 mm apart: the neck between them is 6 mm deep. const Vec3d c1(10., 10., 10.), c2(26., 10., 10.); std::vector layers; - std::vector slices; + std::vector slices; for (int i = 0; i < 100; ++i) { const double z = 0.2 * i + 0.1, r = std::sqrt(std::max(0., 100. - sqr(z - 10.))); Polygons circles; @@ -134,7 +134,7 @@ TEST_CASE("TPMS radial field grades every lobe of a body towards its own center" } for (int i = 0; i < 100; ++i) slices.push_back({0.2 * i, 0.2 * (i + 1), &layers[i]}); - const TpmsRadialField field(slices, get_extents(layers[50]), TpmsAdaptiveMode::Lobes, [] {}); + const AdaptiveInfillField field(slices, get_extents(layers[50]), AdaptiveInfillMode::Lobes, [] {}); for (const Vec3d &c : {c1, c2}) { CAPTURE(c.x()); @@ -143,7 +143,7 @@ TEST_CASE("TPMS radial field grades every lobe of a body towards its own center" CHECK_THAT(radial(field, c + Vec3d(0., 0., 9.5)), WithinAbs(1., 2. * Tolerance)); } // The side between the lobes is half way to the surface, where both patterns morph into each other. - TpmsRadialField::Radials radials; + AdaptiveInfillField::Radials radials; REQUIRE(field.radial(0.5 * (c1 + c2), radials) == 2); for (size_t i = 0; i < 2; ++i) { CHECK_THAT(radials[i].t, WithinAbs(0.5, 2. * Tolerance)); @@ -151,12 +151,12 @@ TEST_CASE("TPMS radial field grades every lobe of a body towards its own center" } } -TEST_CASE("TPMS radial field blends the lobes meeting at a junction continuously", "[FillTpmsAdaptive]") +TEST_CASE("Adaptive infill field blends the lobes meeting at a junction continuously", "[AdaptiveInfillField]") { // Three spheres of 10 mm united, their centers on a triangle of 16 mm sides: the necks meet at its middle. const std::array centers{Vec3d(10., 10., 10.), Vec3d(26., 10., 10.), Vec3d(18., 10. + 8. * std::sqrt(3.), 10.)}; std::vector layers; - std::vector slices; + std::vector slices; for (int i = 0; i < 100; ++i) { const double z = 0.2 * i + 0.1, r = std::sqrt(std::max(0., 100. - sqr(z - 10.))); Polygons circles; @@ -169,7 +169,7 @@ TEST_CASE("TPMS radial field blends the lobes meeting at a junction continuously } for (int i = 0; i < 100; ++i) slices.push_back({0.2 * i, 0.2 * (i + 1), &layers[i]}); - const TpmsRadialField field(slices, get_extents(layers[50]), TpmsAdaptiveMode::Lobes, [] {}); + const AdaptiveInfillField field(slices, get_extents(layers[50]), AdaptiveInfillMode::Lobes, [] {}); // Around the junction the nearest lobes swap, but the weight of every lobe changes smoothly. const Vec3d junction = (centers[0] + centers[1] + centers[2]) / 3.; @@ -179,7 +179,7 @@ TEST_CASE("TPMS radial field blends the lobes meeting at a junction continuously for (int row = 0; row <= 100; ++row) { std::array previous{}; for (int step = 0; step <= 200; ++step) { - TpmsRadialField::Radials radials; + AdaptiveInfillField::Radials radials; const size_t count = field.radial(junction + Vec3d(0.01 * step - 1., 0.02 * row - 1., 0.), radials); max_count = std::max(max_count, count); std::array weights{}; @@ -201,23 +201,23 @@ TEST_CASE("TPMS radial field blends the lobes meeting at a junction continuously CHECK(max_jump < 0.05); } -TEST_CASE("TPMS radial field is empty when the object is thinner than the grid cells", "[FillTpmsAdaptive]") +TEST_CASE("Adaptive infill field is empty when the object is thinner than the grid cells", "[AdaptiveInfillField]") { // A 0.3 mm square bar between the nodes of a grid sized by a 200 mm bounding box, with cells of 0.5 mm or more. const ExPolygons bar{rectangle(0.1, 0.1, 0.4, 0.4)}; - std::vector slices; + std::vector slices; for (int i = 0; i < 1000; ++i) slices.push_back({0.2 * i, 0.2 * (i + 1), &bar}); - const TpmsRadialField field(slices, BoundingBox(Point::new_scale(0., 0.), Point::new_scale(200., 200.)), - TpmsAdaptiveMode::Lobes, [] {}); + const AdaptiveInfillField field(slices, BoundingBox(Point::new_scale(0., 0.), Point::new_scale(200., 200.)), + AdaptiveInfillMode::Lobes, [] {}); CHECK(field.empty()); } -TEST_CASE("TPMS depth follows the distance to the surface relative to the deepest point", "[FillTpmsAdaptive]") +TEST_CASE("Adaptive infill depth follows the distance to the surface relative to the deepest point", "[AdaptiveInfillField]") { // 20 x 20 x 60 mm: from 10 to 50 mm high the axis is 10 mm deep, as deep as the center. const ExPolygons square{rectangle(0., 0., 20., 20.)}; - const TpmsRadialField field = radial_field(square, 60., TpmsAdaptiveMode::SmoothBlend); + const AdaptiveInfillField field = radial_field(square, 60., AdaptiveInfillMode::SmoothBlend); for (double z : {15., 30., 45.}) { CAPTURE(z); CHECK_THAT(field.depth({10., 10., z}), WithinAbs(1., Tolerance)); @@ -227,18 +227,18 @@ TEST_CASE("TPMS depth follows the distance to the surface relative to the deepes CHECK_THAT(field.depth({0., 10., 30.}), WithinAbs(0., Tolerance)); } -TEST_CASE("TPMS radial field in Distance warp mode follows the distance to the surface", "[FillTpmsAdaptive]") +TEST_CASE("Adaptive infill field in Distance warp mode follows the distance to the surface", "[AdaptiveInfillField]") { // In a cube the depth falls linearly along every ray from the center, so Distance warp matches Lobes. const ExPolygons square{rectangle(0., 0., 20., 20.)}; - const TpmsRadialField cube = radial_field(square, 20., TpmsAdaptiveMode::DistanceWarp); + const AdaptiveInfillField cube = radial_field(square, 20., AdaptiveInfillMode::DistanceWarp); CHECK_THAT(radial(cube, {10., 10., 10.}), WithinAbs(0., Tolerance)); CHECK_THAT(radial(cube, {15., 10., 10.}), WithinAbs(0.5, Tolerance)); CHECK_THAT(radial(cube, {10., 10., 20.}), WithinAbs(1., Tolerance)); // 20 x 20 x 60 mm: Lobes grades the axis towards the top and the bottom, Distance warp keeps it deep. - const TpmsRadialField lobes = radial_field(square, 60.); - const TpmsRadialField warp = radial_field(square, 60., TpmsAdaptiveMode::DistanceWarp); + const AdaptiveInfillField lobes = radial_field(square, 60.); + const AdaptiveInfillField warp = radial_field(square, 60., AdaptiveInfillMode::DistanceWarp); for (double z : {15., 45.}) { CAPTURE(z); CHECK_THAT(radial(lobes, {10., 10., z}), WithinAbs(0.5, Tolerance)); @@ -247,12 +247,12 @@ TEST_CASE("TPMS radial field in Distance warp mode follows the distance to the s CHECK_THAT(radial(warp, {0., 10., 30.}), WithinAbs(1., Tolerance)); } -TEST_CASE("TPMS stepped shells split a layer by depth from the surface inwards", "[FillTpmsAdaptive]") +TEST_CASE("Adaptive infill stepped shells split a layer by depth from the surface inwards", "[AdaptiveInfillField]") { // The middle layer of a 40 mm cube, 20 mm from its center to every face, 20% at the surface to 5% inside. const ExPolygons square{rectangle(0., 0., 40., 40.)}; - const TpmsRadialField field = radial_field(square, 40., TpmsAdaptiveMode::SteppedShells); - const std::vector shells = make_tpms_shells(field, square.front(), 20., 0.2f, 0.05f, TpmsAdaptiveGradient::Linear); + const AdaptiveInfillField field = radial_field(square, 40., AdaptiveInfillMode::SteppedShells); + const std::vector shells = make_adaptive_infill_shells(field, square.front(), 20., 0.2f, 0.05f, AdaptiveInfillGradient::Linear); REQUIRE(shells.size() == 5); CHECK_THAT(shells.front().density, WithinAbs(0.2, 1e-6)); CHECK_THAT(shells.back().density, WithinAbs(0.05, 1e-6)); @@ -270,11 +270,11 @@ TEST_CASE("TPMS stepped shells split a layer by depth from the surface inwards", [¢er](const ExPolygon &expolygon) { return expolygon.contains(center); })); } -TEST_CASE("TPMS radial field in 2D grades every section normal to the axis on its own", "[FillTpmsAdaptive]") +TEST_CASE("Adaptive infill field in 2D grades every section normal to the axis on its own", "[AdaptiveInfillField]") { // 20 x 20 x 60 mm: every section normal to Z is 10 mm from its center to the sides, whatever its height. const ExPolygons square{rectangle(0., 0., 20., 20.)}; - const TpmsRadialField normal_z = radial_field(square, 60., TpmsAdaptiveMode::NormalZ); + const AdaptiveInfillField normal_z = radial_field(square, 60., AdaptiveInfillMode::NormalZ); for (double z : {5., 30., 55.}) { CAPTURE(z); CHECK_THAT(radial(normal_z, {10., 10., z}), WithinAbs(0., Tolerance)); @@ -283,7 +283,7 @@ TEST_CASE("TPMS radial field in 2D grades every section normal to the axis on it } // Normal to X, the sections are 20 x 60 mm: 10 mm from the center to the sides, 30 mm to the top and the bottom. - const TpmsRadialField normal_x = radial_field(square, 60., TpmsAdaptiveMode::NormalX); + const AdaptiveInfillField normal_x = radial_field(square, 60., AdaptiveInfillMode::NormalX); for (double x : {3., 10., 17.}) { CAPTURE(x); CHECK_THAT(radial(normal_x, {x, 15., 30.}), WithinAbs(0.5, Tolerance)); diff --git a/tests/libslic3r/test_config.cpp b/tests/libslic3r/test_config.cpp index 20177bcc07..8017c60dcf 100644 --- a/tests/libslic3r/test_config.cpp +++ b/tests/libslic3r/test_config.cpp @@ -1457,6 +1457,19 @@ TEST_CASE("min_object_distance yields no floor when an FFF config lacks the opti } } +TEST_CASE("handle_legacy migrates the adaptive TPMS keys", "[Config]") { + ConfigSubstitutionContext ctxt(ForwardCompatibilitySubstitutionRule::Enable); + DynamicPrintConfig config; + config.set_deserialize("tpms_adaptive", "stepped_shells", ctxt); + config.set_deserialize("tpms_interior_density", "12%", ctxt); + config.set_deserialize("tpms_adaptive_gradient", "quadratic", ctxt); + + CHECK(config.opt_enum("adaptive_infill_mode") == AdaptiveInfillMode::SteppedShells); + CHECK(config.option("adaptive_infill_interior_density")->value == Catch::Approx(12.)); + CHECK(config.opt_enum("adaptive_infill_gradient") == AdaptiveInfillGradient::Quadratic); + CHECK(ctxt.substitutions.empty()); +} + TEST_CASE("handle_legacy migrates every IDEX/IQEX key testers already have", "[Config]") { // Three eras of saved profiles: the feature shipped as iXex (is_ixex + ixex_*), the clearance // pair was renamed to say what it measures, then the whole prefix became imex_. Driven from the