From 1389862ad818c6a71dd97cbacb769282b053ec6b Mon Sep 17 00:00:00 2001 From: "jianjia.ma" Date: Wed, 3 Apr 2024 17:08:39 +0800 Subject: [PATCH] NEW: FlipLines infill jira:6701 New infill pattern that combine block lines infill and switching layers for smooth transition. Change-Id: I2608a2d39b14efcdfe9d39a9437280da350b94c0 (cherry picked from commit 8d0a09c8b763dfc924cbba9913c241e6afadbc7f) --- resources/images/param_flippingline.svg | 570 ++++++++++++++++++++++++ src/libslic3r/CMakeLists.txt | 2 + src/libslic3r/Fill/FillBase.cpp | 2 + src/libslic3r/Fill/FillFlippingLine.cpp | 235 ++++++++++ src/libslic3r/Fill/FillFlippingLine.hpp | 29 ++ src/libslic3r/PrintConfig.cpp | 5 +- src/libslic3r/PrintConfig.hpp | 2 +- 7 files changed, 843 insertions(+), 2 deletions(-) create mode 100644 resources/images/param_flippingline.svg create mode 100644 src/libslic3r/Fill/FillFlippingLine.cpp create mode 100644 src/libslic3r/Fill/FillFlippingLine.hpp diff --git a/resources/images/param_flippingline.svg b/resources/images/param_flippingline.svg new file mode 100644 index 000000000..03a1f04a7 --- /dev/null +++ b/resources/images/param_flippingline.svg @@ -0,0 +1,570 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index f93f233d2..b63f58ec0 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -84,6 +84,8 @@ set(lisbslic3r_sources Fill/FillConcentric.hpp Fill/FillConcentricInternal.cpp Fill/FillConcentricInternal.hpp + Fill/FillFlippingLine.cpp + Fill/FillFlippingLine.hpp Fill/FillHoneycomb.cpp Fill/FillHoneycomb.hpp Fill/FillGyroid.cpp diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index 49a715c43..19d535e1e 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -23,6 +23,7 @@ #include "FillLightning.hpp" // BBS: new infill pattern header #include "FillConcentricInternal.hpp" +#include "FillFlippingLine.hpp" // #define INFILL_DEBUG_OUTPUT @@ -37,6 +38,7 @@ Fill* Fill::new_from_type(const InfillPattern type) case ipGyroid: return new FillGyroid(); case ipRectilinear: return new FillRectilinear(); case ipAlignedRectilinear: return new FillAlignedRectilinear(); + case ipFlippingLine: return new FillFlippingLine(); case ipMonotonic: return new FillMonotonic(); case ipLine: return new FillLine(); case ipGrid: return new FillGrid(); diff --git a/src/libslic3r/Fill/FillFlippingLine.cpp b/src/libslic3r/Fill/FillFlippingLine.cpp new file mode 100644 index 000000000..fe6f56759 --- /dev/null +++ b/src/libslic3r/Fill/FillFlippingLine.cpp @@ -0,0 +1,235 @@ +#include "../ClipperUtils.hpp" +#include "../ShortestPath.hpp" +#include "../Surface.hpp" + +#include "FillFlippingLine.hpp" + +namespace Slic3r { + +// FlipLines Infill: Enhances 3D Printing Speed & Reduces Noise +// FlipLines, as its name hints, alternates line direction by 90 degrees every few layers to improve adhesion. +// It introduces transform layers between direction shifts for better line cohesion, which fixes the weakness of line infill. +// The transform technique is inspired by David Eccles, improved 3D honeycomb but also a more flexible implementation. +// This method notably increases printing speed, meeting the demands of modern high-speed 3D printers, and reduces noise for most layers. +// By Bambu Lab + +// graph credits: David Eccles (gringer). +// But we made a different definition for points. +/* o---o + * / \ + * / \ + * \ / + * \ / + * o---o + * p1 p2 p3 p4 + * + * // X1 = progress * (1/8) * period + * // X2 = ( (1/2 - progress) * (1/8) ) * period + * // X3 = X1 + (1/2) * period + * // X4 = ( (1 - progress) * (1/8) ) * period + * // Y1 = X1 + * // Y2 = X1 + * // Y3 = -X1 + * // Y4 = -X1 + */ + +static Pointfs generate_one_cycle(double progress, coordf_t period) +{ + Pointfs out; + double offset = progress * 1. / 8. * period; + out.reserve(4); + out.push_back(Vec2d(offset, offset)); + out.push_back(Vec2d(0.5 * period - offset, offset)); + out.push_back(Vec2d(0.5 * period + offset, -offset)); + out.push_back(Vec2d(1. * period - offset, -offset)); + return out; +} + +static Polylines generate_transform_pattern(double inprogress, int direction, coordf_t ingrid_size, coordf_t inwidth, coordf_t inheight) +{ + coordf_t width = inwidth; + coordf_t height = inheight; + coordf_t grid_size = ingrid_size * 2; // we due with odd and even saparately. + double progress = inprogress; + Polylines out_polylines; + + // generate template patterns; + Pointfs one_cycle_points = generate_one_cycle(progress, grid_size); + + Polyline one_cycle; + one_cycle.points.reserve(one_cycle_points.size()); + for (size_t i = 0; i < one_cycle_points.size(); i++) one_cycle.points.push_back(Point(one_cycle_points[i])); + + // swap if vertical + if (direction < 0) { + width = height; + height = inwidth; + } + + // replicate polylines; + Polylines odd_polylines; + Polyline odd_poly; + int num_of_cycle = width / grid_size + 2; + odd_poly.points.reserve(num_of_cycle * one_cycle.size()); + + // replicate to odd line + Point translate = Point(0, 0); + for (size_t i = 0; i < num_of_cycle; i++) { + Polyline odd_points; + odd_points = Polyline(one_cycle); + odd_points.translate(Point(i * grid_size, 0.0)); + odd_poly.points.insert(odd_poly.points.end(), odd_points.begin(), odd_points.end()); + } + + // fill the height + int num_of_lines = height / grid_size + 2; + odd_polylines.reserve(num_of_lines * odd_poly.size()); + for (size_t i = 0; i < num_of_lines; i++) { + Polyline poly = odd_poly; + poly.translate(Point(0.0, grid_size * i)); + odd_polylines.push_back(poly); + } + // save to output + out_polylines.insert(out_polylines.end(), odd_polylines.begin(), odd_polylines.end()); + + // replicate to even lines + Polylines even_polylines; + even_polylines.reserve(odd_polylines.size()); + for (size_t i = 0; i < odd_polylines.size(); i++) { + Polyline even = odd_poly; + even.translate(Point(-0.5 * grid_size, (i + 0.5) * grid_size)); + even_polylines.push_back(even); + } + + // save for output + out_polylines.insert(out_polylines.end(), even_polylines.begin(), even_polylines.end()); + + // change to vertical if need + if (direction < 0) { + // swap xy, see if we need better performance method + for (Polyline &poly : out_polylines) { + for (Point &p : poly) { std::swap(p.x(), p.y()); } + } + } + + return out_polylines; +} + +static Polylines generate_repeat_pattern(int direction, coordf_t grid_size, coordf_t inwidth, coordf_t inheight) +{ + coordf_t width = inwidth; + coordf_t height = inheight; + Polylines out_polylines; + + // swap if vertical + if (direction < 0) { + width = height; + height = inwidth; + } + + int num_of_lines = height / grid_size + 1; + out_polylines.reserve(num_of_lines); + + for (int i = 0; i < num_of_lines; i++) { + Polyline poly; + poly.points.reserve(2); + poly.append(Point(coordf_t(0), coordf_t(grid_size * i))); + poly.append(Point(width, coordf_t(grid_size * i))); + out_polylines.push_back(poly); + } + + // change to vertical if needed + if (direction < 0) { + // swap xy + for (Polyline &poly : out_polylines) { + for (Point &p : poly) { std::swap(p.x(), p.y()); } + } + } + + return out_polylines; +} + +// it makes the real patterns that overlap the bounding box +// repeat_ratio define the ratio between the height of repeat pattern and grid +static Polylines generate_infill_layers(coordf_t z_height, double repeat_ratio, coordf_t grid_size, coordf_t width, coordf_t height) +{ + Polylines result; + coordf_t trans_layer_size = grid_size * 0.3; // upper. + coordf_t repeat_layer_size = grid_size * repeat_ratio; // lower. + coordf_t period = trans_layer_size + repeat_layer_size; + coordf_t remains = z_height - std::floor(z_height / period) * period; + coordf_t trans_z = remains - repeat_layer_size; // put repeat layer first. + coordf_t repeat_z = remains; + + int phase = fmod(z_height, period * 2) - (period - 1); // add epsilon + int direction = phase <= 0 ? -1 : 1; + + // this is a repeat layer + if (trans_z < 0) { + result = generate_repeat_pattern(direction, grid_size, width, height); + } + // this is a transform layer + else { + double progress = fmod(trans_z, trans_layer_size) / trans_layer_size; + + // split the progress to forward and backward, with a opposite direction. + if (progress < 0.5) + result = generate_transform_pattern(progress * 2, direction, grid_size, width, height); + else + result = generate_transform_pattern((1 - progress) * 2, -1 * direction, grid_size, width, height); + } + + return result; +} + +void FillFlippingLine ::_fill_surface_single( + const FillParams ¶ms, unsigned int thickness_layers, const std::pair &direction, ExPolygon expolygon, Polylines &polylines_out) +{ + // rotate angle + auto infill_angle = float(this->angle); + if (std::abs(infill_angle) >= EPSILON) expolygon.rotate(-infill_angle); + + // get the rotated bounding box + BoundingBox bb = expolygon.contour.bounding_box(); + + // linespace modifier + coord_t line_spacing = coord_t(scale_(this->spacing) / params.density); + + // reduce density + if (params.density < 0.999) line_spacing *= 1.5; + + bb.merge(align_to_grid(bb.min, Point(line_spacing * 4, line_spacing * 4))); + + // generate pattern + Polylines polylines = generate_infill_layers(scale_(this->z), 1, line_spacing, bb.size()(0), bb.size()(1)); + + // shift the pattern to the actual space + for (Polyline &pl : polylines) { pl.translate(bb.min); } + + polylines = intersection_pl(polylines, to_polygons(expolygon)); + + // --- remove small remains from gyroid infill + if (!polylines.empty()) { + // Remove very small bits, but be careful to not remove infill lines connecting thin walls! + // The infill perimeter lines should be separated by around a single infill line width. + const double minlength = scale_(0.8 * this->spacing); + polylines.erase(std::remove_if(polylines.begin(), polylines.end(), [minlength](const Polyline &pl) + { return pl.length() < minlength; }), polylines.end()); + } + + if (!polylines.empty()) { + int infill_start_idx = polylines_out.size(); // only rotate what belongs to us. + // connect lines + if (params.dont_connect() || polylines.size() <= 1) + append(polylines_out, chain_polylines(std::move(polylines))); + else + this->connect_infill(std::move(polylines), expolygon, polylines_out, this->spacing, params); + + // rotate back + if (std::abs(infill_angle) >= EPSILON) { + for (auto it = polylines_out.begin() + infill_start_idx; it != polylines_out.end(); ++it) it->rotate(infill_angle); + } + } +} + +} // namespace Slic3r \ No newline at end of file diff --git a/src/libslic3r/Fill/FillFlippingLine.hpp b/src/libslic3r/Fill/FillFlippingLine.hpp new file mode 100644 index 000000000..3bf576c14 --- /dev/null +++ b/src/libslic3r/Fill/FillFlippingLine.hpp @@ -0,0 +1,29 @@ +#ifndef slic3r_FillFlippingLines_hpp_ +#define slic3r_FillFlippingLines_hpp_ + +#include + +#include "../libslic3r.h" + +#include "FillBase.hpp" + +namespace Slic3r { + +class FillFlippingLine : public Fill +{ +public: + Fill *clone() const override { return new FillFlippingLine(*this); }; + ~FillFlippingLine() override {} + +protected: + void _fill_surface_single( + const FillParams ¶ms, + unsigned int thickness_layers, + const std::pair &direction, + ExPolygon expolygon, + Polylines &polylines_out) override; +}; + +} // namespace Slic3r + +#endif // slic3r_FillFlippingLines_hpp_ diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 40f133e59..95e5753b2 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -134,7 +134,8 @@ static t_config_enum_values s_keys_map_InfillPattern { { "archimedeanchords", ipArchimedeanChords }, { "octagramspiral", ipOctagramSpiral }, { "supportcubic", ipSupportCubic }, - { "lightning", ipLightning } + { "lightning", ipLightning }, + { "flippingline", ipFlippingLine} }; CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(InfillPattern) @@ -1602,6 +1603,7 @@ void PrintConfigDef::init_fff_params() def->enum_values.push_back("octagramspiral"); def->enum_values.push_back("supportcubic"); def->enum_values.push_back("lightning"); + def->enum_values.push_back("flippingline"); def->enum_labels.push_back(L("Concentric")); def->enum_labels.push_back(L("Rectilinear")); def->enum_labels.push_back(L("Grid")); @@ -1619,6 +1621,7 @@ void PrintConfigDef::init_fff_params() def->enum_labels.push_back(L("Octagram Spiral")); def->enum_labels.push_back(L("Support Cubic")); def->enum_labels.push_back(L("Lightning")); + def->enum_labels.push_back(L("Flipping Line")); def->set_default_value(new ConfigOptionEnum(ipCubic)); def = this->add("top_surface_acceleration", coFloat); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index fcb637ea1..3010b2ff1 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -54,7 +54,7 @@ enum AuthorizationType { enum InfillPattern : int { ipConcentric, ipRectilinear, ipGrid, ipLine, ipCubic, ipTriangles, ipStars, ipGyroid, ipHoneycomb, ipAdaptiveCubic, ipMonotonic, ipMonotonicLine, ipAlignedRectilinear, ip3DHoneycomb, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipSupportCubic, ipSupportBase, ipConcentricInternal, - ipLightning, + ipLightning, ipFlippingLine, ipCount, };