diff options
author | supermerill <merill@free.fr> | 2022-07-22 02:24:40 +0300 |
---|---|---|
committer | supermerill <merill@free.fr> | 2022-07-24 02:45:21 +0300 |
commit | d16b7d155b8d76db73c1b1e912d91d53f4241fb9 (patch) | |
tree | 04db985c9525d03047accecd9cb943dec8088f23 | |
parent | 3ce5d1a4e1ea3fce0a8f869cad581370a49e7dcd (diff) |
gapfill min_width and max_width
-rw-r--r-- | resources/ui_layout/default/print.ui | 6 | ||||
-rw-r--r-- | src/libslic3r/Geometry/MedialAxis.cpp | 124 | ||||
-rw-r--r-- | src/libslic3r/Geometry/MedialAxis.hpp | 8 | ||||
-rw-r--r-- | src/libslic3r/Layer.cpp | 2 | ||||
-rw-r--r-- | src/libslic3r/PerimeterGenerator.cpp | 19 | ||||
-rw-r--r-- | src/libslic3r/Preset.cpp | 2 | ||||
-rw-r--r-- | src/libslic3r/PrintConfig.cpp | 31 | ||||
-rw-r--r-- | src/libslic3r/PrintConfig.hpp | 2 | ||||
-rw-r--r-- | src/libslic3r/PrintObject.cpp | 2 | ||||
-rw-r--r-- | src/slic3r/GUI/ConfigManipulation.cpp | 2 |
10 files changed, 186 insertions, 12 deletions
diff --git a/resources/ui_layout/default/print.ui b/resources/ui_layout/default/print.ui index b61c33748..52668964d 100644 --- a/resources/ui_layout/default/print.ui +++ b/resources/ui_layout/default/print.ui @@ -66,9 +66,13 @@ group:Advanced setting:width$25:no_perimeter_unsupported_algo line:Gap Fill setting:label$_:gap_fill_enabled - setting:width$5:gap_fill_min_area setting:width$5:gap_fill_last end_line + line:Gap Fill threshold + setting:width$5:gap_fill_min_width + setting:width$5:gap_fill_max_width + setting:width$5:gap_fill_min_area + end_line line:Seam setting:tags$Simple$Advanced$Expert$Prusa$SuSi:script:enum$corners$Corners$nearest$Nearest$random$Random$aligned$Aligned$rear$Rear$custom$Custom:depends$seam_position$seam_angle_cost$seam_travel_cost:label$Seam position:label_width$12:sidetext_width$0:tooltip$Position of perimeters' starting points.\nCustom can be defined in Advanced or Expert mode. Cost-based settings let you choose the angle and travel cost. A high angle cost will place the seam where it can be hidden by a corner, the travel cost place the seam near the last position (often at the end of the previous infill).:s_seam_position # setting:tags$Expert:label_width$12:sidetext_width$0:seam_position diff --git a/src/libslic3r/Geometry/MedialAxis.cpp b/src/libslic3r/Geometry/MedialAxis.cpp index 670c8fb45..e5cc5d6dd 100644 --- a/src/libslic3r/Geometry/MedialAxis.cpp +++ b/src/libslic3r/Geometry/MedialAxis.cpp @@ -1979,7 +1979,72 @@ MedialAxis::remove_too_thin_extrusion(ThickPolylines& pp) changes = true; } //remove points and bits that comes from a "main line" - if (polyline.points.size() < 2 || (polyline_changes && polyline.points.size() == 2 && polyline.length() < std::max(this->min_length, std::max(polyline.width.front(), polyline.width.back()))) ) { + if (polyline.points.size() < 2 || (polyline_changes && polyline.points.size() == 2 && polyline.length() < std::max(this->min_length, std::max(polyline.width.front(), polyline.width.back())))) { + //remove self if too small + pp.erase(pp.begin() + i); + --i; + } + } + if (changes) concatThickPolylines(pp); +} + +void +MedialAxis::remove_too_thick_extrusion(ThickPolylines& pp) +{ + // remove too thin extrusion at start & end of polylines + bool changes = false; + for (size_t i = 0; i < pp.size(); ++i) { + ThickPolyline& polyline = pp[i]; + bool polyline_changes = false; + // remove bits with too small extrusion + while (polyline.points.size() > 1 && polyline.width.front() > this->biggest_width && polyline.endpoints.first) { + //try to split if possible + if (polyline.width[1] < this->biggest_width) { + double percent_can_keep = (this->biggest_width - polyline.width[0]) / (polyline.width[1] - polyline.width[0]); + if (polyline.points.front().distance_to(polyline.points[1]) * (1 - percent_can_keep) > coordf_t(this->resolution)) { + //Can split => move the first point and assign a new weight. + //the update of endpoints wil be performed in concatThickPolylines + polyline.points.front() = polyline.points.front().interpolate(percent_can_keep, polyline.points[1]); + polyline.width.front() = this->biggest_width; + } else { + /// almost 0-length, Remove + polyline.points.erase(polyline.points.begin()); + polyline.width.erase(polyline.width.begin()); + } + changes = true; + polyline_changes = true; + break; + } + polyline.points.erase(polyline.points.begin()); + polyline.width.erase(polyline.width.begin()); + changes = true; + polyline_changes = true; + } + while (polyline.points.size() > 1 && polyline.width.back() > this->biggest_width && polyline.endpoints.second) { + //try to split if possible + if (polyline.width[polyline.points.size() - 2] < this->biggest_width) { + double percent_can_keep = (this->biggest_width - polyline.width.back()) / (polyline.width[polyline.points.size() - 2] - polyline.width.back()); + if (polyline.points.back().distance_to(polyline.points[polyline.points.size() - 2]) * (1 - percent_can_keep) > coordf_t(this->resolution)) { + //Can split => move the first point and assign a new weight. + //the update of endpoints wil be performed in concatThickPolylines + polyline.points.back() = polyline.points.back().interpolate(percent_can_keep, polyline.points[polyline.points.size() - 2]); + polyline.width.back() = this->biggest_width; + } else { + /// almost 0-length, Remove + polyline.points.erase(polyline.points.end() - 1); + polyline.width.erase(polyline.width.end() - 1); + } + polyline_changes = true; + changes = true; + break; + } + polyline.points.erase(polyline.points.end() - 1); + polyline.width.erase(polyline.width.end() - 1); + polyline_changes = true; + changes = true; + } + //remove points and bits that comes from a "main line" + if (polyline.points.size() < 2 || (polyline_changes && polyline.points.size() == 2 && polyline.length() < std::max(this->min_length, std::max(polyline.width.front(), polyline.width.back())))) { //remove self if too small pp.erase(pp.begin() + i); --i; @@ -2229,6 +2294,62 @@ MedialAxis::remove_too_thin_points(ThickPolylines& pp) } void +MedialAxis::remove_too_thick_points(ThickPolylines& pp) +{ + if (biggest_width <= 0) return; + //remove too thin polylines points (inside a polyline : split it) + for (size_t i = 0; i < pp.size(); ++i) { + ThickPolyline* polyline = &pp[i]; + + // remove bits with too small extrusion + size_t idx_point = 0; + while (idx_point < polyline->points.size()) { + if (polyline->width[idx_point] > biggest_width) { + if (idx_point == 0) { + //too thin at start + polyline->points.erase(polyline->points.begin()); + polyline->width.erase(polyline->width.begin()); + idx_point = 0; + } else if (idx_point == 1) { + //too thin at start + polyline->points.erase(polyline->points.begin()); + polyline->width.erase(polyline->width.begin()); + polyline->points.erase(polyline->points.begin()); + polyline->width.erase(polyline->width.begin()); + idx_point = 0; + } else if (idx_point == polyline->points.size() - 2) { + //too thin at (near) end + polyline->points.erase(polyline->points.end() - 1); + polyline->width.erase(polyline->width.end() - 1); + polyline->points.erase(polyline->points.end() - 1); + polyline->width.erase(polyline->width.end() - 1); + } else if (idx_point == polyline->points.size() - 1) { + //too thin at end + polyline->points.erase(polyline->points.end() - 1); + polyline->width.erase(polyline->width.end() - 1); + } else { + //too thin in middle : split + pp.emplace_back(); + polyline = &pp[i]; // have to refresh the pointer, as the emplace_back() may have moved the array + ThickPolyline& newone = pp.back(); + newone.points.insert(newone.points.begin(), polyline->points.begin() + idx_point + 1, polyline->points.end()); + newone.width.insert(newone.width.begin(), polyline->width.begin() + idx_point + 1, polyline->width.end()); + polyline->points.erase(polyline->points.begin() + idx_point, polyline->points.end()); + polyline->width.erase(polyline->width.begin() + idx_point, polyline->width.end()); + } + } else idx_point++; + + if (polyline->points.size() < 2) { + //remove self if too small + pp.erase(pp.begin() + i); + --i; + break; + } + } + } +} + +void MedialAxis::remove_too_short_polylines(ThickPolylines& pp) { // reduce the flow at the intersection ( + ) points @@ -2800,6 +2921,7 @@ MedialAxis::build(ThickPolylines& polylines_out) //} remove_too_thin_points(pp); + remove_too_thick_extrusion(pp); //{ // std::stringstream stri; // stri << "medial_axis_5.0_thuinner_" << id << ".svg"; diff --git a/src/libslic3r/Geometry/MedialAxis.hpp b/src/libslic3r/Geometry/MedialAxis.hpp index e9a0f5737..21e2ddad8 100644 --- a/src/libslic3r/Geometry/MedialAxis.hpp +++ b/src/libslic3r/Geometry/MedialAxis.hpp @@ -72,6 +72,7 @@ public: /// optional parameter: if true, the extension inside the bounds can be cut if the width is too small. Default : true MedialAxis& set_stop_at_min_width(const bool stop_at_min_width) { this->stop_at_min_width = stop_at_min_width; return *this; } MedialAxis& set_min_length(const coord_t min_length) { this->min_length = min_length; return *this; } + MedialAxis& set_biggest_width(const coord_t biggest_width) { this->biggest_width = biggest_width; return *this; } private: @@ -80,10 +81,12 @@ private: /// the copied expolygon from surface, it's modified in build() to simplify it. It's then used to create the voronoi diagram. ExPolygon expolygon; const ExPolygon* bounds; - /// maximum width of the extrusion. _expolygon shouldn't have a spot where a circle diameter is higher than that (or almost). + /// maximum width for the algorithm. _expolygon shouldn't have a spot where a circle diameter is higher than that (or almost). const coord_t max_width; /// minimum width of the extrusion, every spot where a circle diameter is lower than that will be ignored (unless it's the tip of the extrusion) const coord_t min_width; + /// maximum width of the extrusion. if a point has a width higher than that, it will be removed + coord_t biggest_width = 0; /// minimum length of continuous segments (may cross a crossing) coord_t min_length; /// resolution for simplifuing and stuff like that @@ -123,16 +126,19 @@ private: void fusion_corners(ThickPolylines& pp); /// extends the polylines inside bounds, use extends_line on both end void extends_line_both_side(ThickPolylines& pp); + void extends_line_extra(ThickPolylines& pp); /// extends the polylines inside bounds (anchors) void extends_line(ThickPolyline& polyline, const ExPolygons& anchors, const coord_t join_width); /// remove too thin bits at start & end of polylines void remove_too_thin_extrusion(ThickPolylines& pp); + void remove_too_thick_extrusion(ThickPolylines& pp); /// when we have a too small polyline, try to see if we can't concatenate it at a crossing to keep it. void concatenate_small_polylines(ThickPolylines& pp); /// instead of keeping polyline split at each corssing, we try to create long strait polylines that can cross each other. void concatenate_polylines_with_crossing(ThickPolylines& pp); /// remove bits around points that are too thin (can be inside the polyline) void remove_too_thin_points(ThickPolylines& pp); + void remove_too_thick_points(ThickPolylines& pp); /// delete polylines that are too short (below the this->min_length) void remove_too_short_polylines(ThickPolylines& pp); /// be sure we didn't try to push more plastic than the volume defined by surface * height can receive. If overextruded, reduce all widths by the correct %. diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index 5046bd285..5c1966560 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -183,7 +183,9 @@ void Layer::make_perimeters() && ((config.gap_fill_speed == other_config.gap_fill_speed) || !config.gap_fill_enabled) && config.gap_fill_last == other_config.gap_fill_last && config.gap_fill_flow_match_perimeter == other_config.gap_fill_flow_match_perimeter + && config.gap_fill_max_width == other_config.gap_fill_max_width && config.gap_fill_min_area == other_config.gap_fill_min_area + && config.gap_fill_min_width == other_config.gap_fill_min_width && config.gap_fill_overlap == other_config.gap_fill_overlap && config.infill_dense == other_config.infill_dense && config.infill_dense_algo == other_config.infill_dense_algo diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index 9e23d3847..83cd8da6f 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -1127,14 +1127,23 @@ void PerimeterGenerator::process() ExPolygons gap_srf; if (!gaps.empty()) { // collapse - double min = 0.2 * perimeter_width * (1 - INSET_OVERLAP_TOLERANCE); + coordf_t min = 0.2 * perimeter_width * (1 - INSET_OVERLAP_TOLERANCE); //be sure we don't gapfill where the perimeters are already touching each other (negative spacing). min = std::max(min, double(Flow::new_from_spacing((float)EPSILON, (float)this->perimeter_flow.nozzle_diameter(), (float)this->layer->height, (float)this->perimeter_flow.spacing_ratio(), false).scaled_width())); - double max = 2.2 * perimeter_spacing; + coordf_t real_max = 2.5 * perimeter_spacing; + const coordf_t minwidth = scale_d(this->config->gap_fill_min_width.get_abs_value(unscaled((double)perimeter_width))); + const coordf_t maxwidth = scale_d(this->config->gap_fill_max_width.get_abs_value(unscaled((double)perimeter_width))); + if (minwidth > 0) { + min = std::max(min, minwidth); + } + coordf_t max = real_max; + if (maxwidth > 0) { + max = std::min(max, maxwidth); + } //remove areas that are too big (shouldn't occur...) ExPolygons too_big = offset2_ex(gaps, double(-max / 2), double(+max / 2)); ExPolygons gaps_ex_to_test = too_big.empty() ? gaps : diff_ex(gaps, too_big, ApplySafetyOffset::Yes); - const double minarea = scale_(scale_(this->config->gap_fill_min_area.get_abs_value(unscaled((double)perimeter_width) * unscaled((double)perimeter_width)))); + const double minarea = scale_d(scale_d(this->config->gap_fill_min_area.get_abs_value(unscaled((double)perimeter_width) * unscaled((double)perimeter_width)))); // check each gapfill area to see if it's printable. for (const ExPolygon& expoly : gaps_ex_to_test) { //remove too small gaps that are too hard to fill. @@ -1189,7 +1198,9 @@ void PerimeterGenerator::process() // create lines from the area ThickPolylines polylines; for (const ExPolygon& ex : gaps_ex) { - Geometry::MedialAxis{ ex, coord_t(max * 1.1), coord_t(min), coord_t(this->layer->height) }.build(polylines); + Geometry::MedialAxis{ ex, coord_t(real_max), coord_t(min), coord_t(this->layer->height) } + .set_biggest_width(max) + .build(polylines); } // create extrusion from lines if (!polylines.empty()) { diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index aa33fb602..c0346f3f5 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -534,7 +534,9 @@ static std::vector<std::string> s_Preset_print_options { "gap_fill_enabled", "gap_fill_flow_match_perimeter", "gap_fill_last", + "gap_fill_max_width", "gap_fill_min_area", + "gap_fill_min_width", "gap_fill_overlap", "gap_fill_speed", // fuzzy diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index acf5c08de..77792980a 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2587,7 +2587,7 @@ void PrintConfigDef::init_fff_params() def = this->add("gap_fill_flow_match_perimeter", coPercent); def->label = L("Cap with perimeter flow"); - def->full_label = L("Cap gapfill speed with perimeter flow"); + def->full_label = L("Gapfill: cap speed with perimeter flow"); def->category = OptionCategory::output; def->tooltip = L("A percentage of the perimeter flow (mm3/s) is used as a limit for the gap fill flow, and so the gapfill may reduce its speed when the gap fill extrusions became too thick." " This allow you to use a high gapfill speed, to print the thin gapfill quickly and reduce the difference in flow rate for the gapfill." @@ -2599,21 +2599,44 @@ void PrintConfigDef::init_fff_params() def = this->add("gap_fill_last", coBool); def->label = L("after last perimeter"); - def->full_label = L("Gapfill after last perimeter"); + def->full_label = L("Gapfill: after last perimeter"); def->category = OptionCategory::perimeter; def->tooltip = L("All gaps, between the last perimeter and the infill, which are thinner than a perimeter will be filled by gapfill."); def->mode = comExpert | comSuSi; def->set_default_value(new ConfigOptionBool(false)); + def = this->add("gap_fill_max_width", coFloatOrPercent); + def->label = L("Max width"); + def->full_label = L("Gapfill: Max width"); + def->category = OptionCategory::perimeter; + def->tooltip = L("This setting represents the maximum width of a gapfill. Points wider than this threshold won't be created.\nCan be a % of the perimeter width\n0 to auto"); + def->ratio_over = "perimeter_width"; + def->sidetext = L("mm or %"); + def->min = 0; + def->mode = comExpert | comSuSi; + def->set_default_value(new ConfigOptionFloatOrPercent{ 0, false }); + def = this->add("gap_fill_min_area", coFloatOrPercent); def->label = L("Min surface"); - def->full_label = L("Min surface for gap filling"); + def->full_label = L("Gapfill: Min surface"); def->category = OptionCategory::perimeter; def->tooltip = L("This setting represents the minimum mm² for a gapfill extrusion to be created.\nCan be a % of (perimeter width)²"); def->ratio_over = "perimeter_width_square"; + def->sidetext = L("mm² or %"); + def->min = 0; + def->mode = comExpert | comSuSi; + def->set_default_value(new ConfigOptionFloatOrPercent{ 100, true }); + + def = this->add("gap_fill_min_width", coFloatOrPercent); + def->label = L("Min width"); + def->full_label = L("Gapfill: Min width"); + def->category = OptionCategory::perimeter; + def->tooltip = L("This setting represents the minimum width of a gapfill. Points thinner than this threshold won't be created.\nCan be a % of the perimeter width\n0 to auto"); + def->ratio_over = "perimeter_width"; + def->sidetext = L("mm or %"); def->min = 0; def->mode = comExpert | comSuSi; - def->set_default_value(new ConfigOptionFloatOrPercent{100, true }); + def->set_default_value(new ConfigOptionFloatOrPercent{ 0, false }); def = this->add("gap_fill_overlap", coPercent); def->label = L("Gap fill overlap"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 568c00181..37402d12c 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -812,7 +812,9 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionBool, gap_fill_enabled)) ((ConfigOptionPercent, gap_fill_flow_match_perimeter)) ((ConfigOptionBool, gap_fill_last)) + ((ConfigOptionFloatOrPercent, gap_fill_max_width)) ((ConfigOptionFloatOrPercent, gap_fill_min_area)) + ((ConfigOptionFloatOrPercent, gap_fill_min_width)) ((ConfigOptionPercent, gap_fill_overlap)) ((ConfigOptionFloatOrPercent, gap_fill_speed)) ((ConfigOptionFloatOrPercent, infill_anchor)) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 82b5397ee..a6209ac69 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -714,7 +714,9 @@ bool PrintObject::invalidate_state_by_config_options( if ( opt_key == "gap_fill_enabled" || opt_key == "gap_fill_last" + || opt_key == "gap_fill_max_width" || opt_key == "gap_fill_min_area" + || opt_key == "gap_fill_min_width" || opt_key == "only_one_perimeter_first_layer" || opt_key == "only_one_perimeter_top" || opt_key == "only_one_perimeter_top_other_algo" diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index db0097f79..ab9ce37ce 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -345,7 +345,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) toggle_field("perimeter_loop_seam", config->opt_bool("perimeter_loop")); - for (auto el : { "gap_fill_last", "gap_fill_min_area" }) + for (auto el : { "gap_fill_last", "gap_fill_max_width", "gap_fill_min_area", "gap_fill_min_width" }) toggle_field(el, config->opt_bool("gap_fill_enabled")); for (auto el : { "fuzzy_skin_thickness", "fuzzy_skin_point_dist" }) |