Skip to content

Commit d16b7d1

Browse files
committed
gapfill min_width and max_width
1 parent 3ce5d1a commit d16b7d1

File tree

10 files changed

+186
-12
lines changed

10 files changed

+186
-12
lines changed

resources/ui_layout/default/print.ui

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,13 @@ group:Advanced
6666
setting:width$25:no_perimeter_unsupported_algo
6767
line:Gap Fill
6868
setting:label$_:gap_fill_enabled
69-
setting:width$5:gap_fill_min_area
7069
setting:width$5:gap_fill_last
7170
end_line
71+
line:Gap Fill threshold
72+
setting:width$5:gap_fill_min_width
73+
setting:width$5:gap_fill_max_width
74+
setting:width$5:gap_fill_min_area
75+
end_line
7276
line:Seam
7377
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
7478
# setting:tags$Expert:label_width$12:sidetext_width$0:seam_position

src/libslic3r/Geometry/MedialAxis.cpp

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1979,7 +1979,72 @@ MedialAxis::remove_too_thin_extrusion(ThickPolylines& pp)
19791979
changes = true;
19801980
}
19811981
//remove points and bits that comes from a "main line"
1982-
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()))) ) {
1982+
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())))) {
1983+
//remove self if too small
1984+
pp.erase(pp.begin() + i);
1985+
--i;
1986+
}
1987+
}
1988+
if (changes) concatThickPolylines(pp);
1989+
}
1990+
1991+
void
1992+
MedialAxis::remove_too_thick_extrusion(ThickPolylines& pp)
1993+
{
1994+
// remove too thin extrusion at start & end of polylines
1995+
bool changes = false;
1996+
for (size_t i = 0; i < pp.size(); ++i) {
1997+
ThickPolyline& polyline = pp[i];
1998+
bool polyline_changes = false;
1999+
// remove bits with too small extrusion
2000+
while (polyline.points.size() > 1 && polyline.width.front() > this->biggest_width && polyline.endpoints.first) {
2001+
//try to split if possible
2002+
if (polyline.width[1] < this->biggest_width) {
2003+
double percent_can_keep = (this->biggest_width - polyline.width[0]) / (polyline.width[1] - polyline.width[0]);
2004+
if (polyline.points.front().distance_to(polyline.points[1]) * (1 - percent_can_keep) > coordf_t(this->resolution)) {
2005+
//Can split => move the first point and assign a new weight.
2006+
//the update of endpoints wil be performed in concatThickPolylines
2007+
polyline.points.front() = polyline.points.front().interpolate(percent_can_keep, polyline.points[1]);
2008+
polyline.width.front() = this->biggest_width;
2009+
} else {
2010+
/// almost 0-length, Remove
2011+
polyline.points.erase(polyline.points.begin());
2012+
polyline.width.erase(polyline.width.begin());
2013+
}
2014+
changes = true;
2015+
polyline_changes = true;
2016+
break;
2017+
}
2018+
polyline.points.erase(polyline.points.begin());
2019+
polyline.width.erase(polyline.width.begin());
2020+
changes = true;
2021+
polyline_changes = true;
2022+
}
2023+
while (polyline.points.size() > 1 && polyline.width.back() > this->biggest_width && polyline.endpoints.second) {
2024+
//try to split if possible
2025+
if (polyline.width[polyline.points.size() - 2] < this->biggest_width) {
2026+
double percent_can_keep = (this->biggest_width - polyline.width.back()) / (polyline.width[polyline.points.size() - 2] - polyline.width.back());
2027+
if (polyline.points.back().distance_to(polyline.points[polyline.points.size() - 2]) * (1 - percent_can_keep) > coordf_t(this->resolution)) {
2028+
//Can split => move the first point and assign a new weight.
2029+
//the update of endpoints wil be performed in concatThickPolylines
2030+
polyline.points.back() = polyline.points.back().interpolate(percent_can_keep, polyline.points[polyline.points.size() - 2]);
2031+
polyline.width.back() = this->biggest_width;
2032+
} else {
2033+
/// almost 0-length, Remove
2034+
polyline.points.erase(polyline.points.end() - 1);
2035+
polyline.width.erase(polyline.width.end() - 1);
2036+
}
2037+
polyline_changes = true;
2038+
changes = true;
2039+
break;
2040+
}
2041+
polyline.points.erase(polyline.points.end() - 1);
2042+
polyline.width.erase(polyline.width.end() - 1);
2043+
polyline_changes = true;
2044+
changes = true;
2045+
}
2046+
//remove points and bits that comes from a "main line"
2047+
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())))) {
19832048
//remove self if too small
19842049
pp.erase(pp.begin() + i);
19852050
--i;
@@ -2228,6 +2293,62 @@ MedialAxis::remove_too_thin_points(ThickPolylines& pp)
22282293
}
22292294
}
22302295

2296+
void
2297+
MedialAxis::remove_too_thick_points(ThickPolylines& pp)
2298+
{
2299+
if (biggest_width <= 0) return;
2300+
//remove too thin polylines points (inside a polyline : split it)
2301+
for (size_t i = 0; i < pp.size(); ++i) {
2302+
ThickPolyline* polyline = &pp[i];
2303+
2304+
// remove bits with too small extrusion
2305+
size_t idx_point = 0;
2306+
while (idx_point < polyline->points.size()) {
2307+
if (polyline->width[idx_point] > biggest_width) {
2308+
if (idx_point == 0) {
2309+
//too thin at start
2310+
polyline->points.erase(polyline->points.begin());
2311+
polyline->width.erase(polyline->width.begin());
2312+
idx_point = 0;
2313+
} else if (idx_point == 1) {
2314+
//too thin at start
2315+
polyline->points.erase(polyline->points.begin());
2316+
polyline->width.erase(polyline->width.begin());
2317+
polyline->points.erase(polyline->points.begin());
2318+
polyline->width.erase(polyline->width.begin());
2319+
idx_point = 0;
2320+
} else if (idx_point == polyline->points.size() - 2) {
2321+
//too thin at (near) end
2322+
polyline->points.erase(polyline->points.end() - 1);
2323+
polyline->width.erase(polyline->width.end() - 1);
2324+
polyline->points.erase(polyline->points.end() - 1);
2325+
polyline->width.erase(polyline->width.end() - 1);
2326+
} else if (idx_point == polyline->points.size() - 1) {
2327+
//too thin at end
2328+
polyline->points.erase(polyline->points.end() - 1);
2329+
polyline->width.erase(polyline->width.end() - 1);
2330+
} else {
2331+
//too thin in middle : split
2332+
pp.emplace_back();
2333+
polyline = &pp[i]; // have to refresh the pointer, as the emplace_back() may have moved the array
2334+
ThickPolyline& newone = pp.back();
2335+
newone.points.insert(newone.points.begin(), polyline->points.begin() + idx_point + 1, polyline->points.end());
2336+
newone.width.insert(newone.width.begin(), polyline->width.begin() + idx_point + 1, polyline->width.end());
2337+
polyline->points.erase(polyline->points.begin() + idx_point, polyline->points.end());
2338+
polyline->width.erase(polyline->width.begin() + idx_point, polyline->width.end());
2339+
}
2340+
} else idx_point++;
2341+
2342+
if (polyline->points.size() < 2) {
2343+
//remove self if too small
2344+
pp.erase(pp.begin() + i);
2345+
--i;
2346+
break;
2347+
}
2348+
}
2349+
}
2350+
}
2351+
22312352
void
22322353
MedialAxis::remove_too_short_polylines(ThickPolylines& pp)
22332354
{
@@ -2800,6 +2921,7 @@ MedialAxis::build(ThickPolylines& polylines_out)
28002921
//}
28012922

28022923
remove_too_thin_points(pp);
2924+
remove_too_thick_extrusion(pp);
28032925
//{
28042926
// std::stringstream stri;
28052927
// stri << "medial_axis_5.0_thuinner_" << id << ".svg";

src/libslic3r/Geometry/MedialAxis.hpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ class MedialAxis {
7272
/// optional parameter: if true, the extension inside the bounds can be cut if the width is too small. Default : true
7373
MedialAxis& set_stop_at_min_width(const bool stop_at_min_width) { this->stop_at_min_width = stop_at_min_width; return *this; }
7474
MedialAxis& set_min_length(const coord_t min_length) { this->min_length = min_length; return *this; }
75+
MedialAxis& set_biggest_width(const coord_t biggest_width) { this->biggest_width = biggest_width; return *this; }
7576

7677
private:
7778

@@ -80,10 +81,12 @@ class MedialAxis {
8081
/// the copied expolygon from surface, it's modified in build() to simplify it. It's then used to create the voronoi diagram.
8182
ExPolygon expolygon;
8283
const ExPolygon* bounds;
83-
/// maximum width of the extrusion. _expolygon shouldn't have a spot where a circle diameter is higher than that (or almost).
84+
/// maximum width for the algorithm. _expolygon shouldn't have a spot where a circle diameter is higher than that (or almost).
8485
const coord_t max_width;
8586
/// 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)
8687
const coord_t min_width;
88+
/// maximum width of the extrusion. if a point has a width higher than that, it will be removed
89+
coord_t biggest_width = 0;
8790
/// minimum length of continuous segments (may cross a crossing)
8891
coord_t min_length;
8992
/// resolution for simplifuing and stuff like that
@@ -123,16 +126,19 @@ class MedialAxis {
123126
void fusion_corners(ThickPolylines& pp);
124127
/// extends the polylines inside bounds, use extends_line on both end
125128
void extends_line_both_side(ThickPolylines& pp);
129+
void extends_line_extra(ThickPolylines& pp);
126130
/// extends the polylines inside bounds (anchors)
127131
void extends_line(ThickPolyline& polyline, const ExPolygons& anchors, const coord_t join_width);
128132
/// remove too thin bits at start & end of polylines
129133
void remove_too_thin_extrusion(ThickPolylines& pp);
134+
void remove_too_thick_extrusion(ThickPolylines& pp);
130135
/// when we have a too small polyline, try to see if we can't concatenate it at a crossing to keep it.
131136
void concatenate_small_polylines(ThickPolylines& pp);
132137
/// instead of keeping polyline split at each corssing, we try to create long strait polylines that can cross each other.
133138
void concatenate_polylines_with_crossing(ThickPolylines& pp);
134139
/// remove bits around points that are too thin (can be inside the polyline)
135140
void remove_too_thin_points(ThickPolylines& pp);
141+
void remove_too_thick_points(ThickPolylines& pp);
136142
/// delete polylines that are too short (below the this->min_length)
137143
void remove_too_short_polylines(ThickPolylines& pp);
138144
/// 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 %.

src/libslic3r/Layer.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,9 @@ void Layer::make_perimeters()
183183
&& ((config.gap_fill_speed == other_config.gap_fill_speed) || !config.gap_fill_enabled)
184184
&& config.gap_fill_last == other_config.gap_fill_last
185185
&& config.gap_fill_flow_match_perimeter == other_config.gap_fill_flow_match_perimeter
186+
&& config.gap_fill_max_width == other_config.gap_fill_max_width
186187
&& config.gap_fill_min_area == other_config.gap_fill_min_area
188+
&& config.gap_fill_min_width == other_config.gap_fill_min_width
187189
&& config.gap_fill_overlap == other_config.gap_fill_overlap
188190
&& config.infill_dense == other_config.infill_dense
189191
&& config.infill_dense_algo == other_config.infill_dense_algo

src/libslic3r/PerimeterGenerator.cpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,14 +1127,23 @@ void PerimeterGenerator::process()
11271127
ExPolygons gap_srf;
11281128
if (!gaps.empty()) {
11291129
// collapse
1130-
double min = 0.2 * perimeter_width * (1 - INSET_OVERLAP_TOLERANCE);
1130+
coordf_t min = 0.2 * perimeter_width * (1 - INSET_OVERLAP_TOLERANCE);
11311131
//be sure we don't gapfill where the perimeters are already touching each other (negative spacing).
11321132
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()));
1133-
double max = 2.2 * perimeter_spacing;
1133+
coordf_t real_max = 2.5 * perimeter_spacing;
1134+
const coordf_t minwidth = scale_d(this->config->gap_fill_min_width.get_abs_value(unscaled((double)perimeter_width)));
1135+
const coordf_t maxwidth = scale_d(this->config->gap_fill_max_width.get_abs_value(unscaled((double)perimeter_width)));
1136+
if (minwidth > 0) {
1137+
min = std::max(min, minwidth);
1138+
}
1139+
coordf_t max = real_max;
1140+
if (maxwidth > 0) {
1141+
max = std::min(max, maxwidth);
1142+
}
11341143
//remove areas that are too big (shouldn't occur...)
11351144
ExPolygons too_big = offset2_ex(gaps, double(-max / 2), double(+max / 2));
11361145
ExPolygons gaps_ex_to_test = too_big.empty() ? gaps : diff_ex(gaps, too_big, ApplySafetyOffset::Yes);
1137-
const double minarea = scale_(scale_(this->config->gap_fill_min_area.get_abs_value(unscaled((double)perimeter_width) * unscaled((double)perimeter_width))));
1146+
const double minarea = scale_d(scale_d(this->config->gap_fill_min_area.get_abs_value(unscaled((double)perimeter_width) * unscaled((double)perimeter_width))));
11381147
// check each gapfill area to see if it's printable.
11391148
for (const ExPolygon& expoly : gaps_ex_to_test) {
11401149
//remove too small gaps that are too hard to fill.
@@ -1189,7 +1198,9 @@ void PerimeterGenerator::process()
11891198
// create lines from the area
11901199
ThickPolylines polylines;
11911200
for (const ExPolygon& ex : gaps_ex) {
1192-
Geometry::MedialAxis{ ex, coord_t(max * 1.1), coord_t(min), coord_t(this->layer->height) }.build(polylines);
1201+
Geometry::MedialAxis{ ex, coord_t(real_max), coord_t(min), coord_t(this->layer->height) }
1202+
.set_biggest_width(max)
1203+
.build(polylines);
11931204
}
11941205
// create extrusion from lines
11951206
if (!polylines.empty()) {

src/libslic3r/Preset.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,9 @@ static std::vector<std::string> s_Preset_print_options {
534534
"gap_fill_enabled",
535535
"gap_fill_flow_match_perimeter",
536536
"gap_fill_last",
537+
"gap_fill_max_width",
537538
"gap_fill_min_area",
539+
"gap_fill_min_width",
538540
"gap_fill_overlap",
539541
"gap_fill_speed",
540542
// fuzzy

src/libslic3r/PrintConfig.cpp

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2587,7 +2587,7 @@ void PrintConfigDef::init_fff_params()
25872587

25882588
def = this->add("gap_fill_flow_match_perimeter", coPercent);
25892589
def->label = L("Cap with perimeter flow");
2590-
def->full_label = L("Cap gapfill speed with perimeter flow");
2590+
def->full_label = L("Gapfill: cap speed with perimeter flow");
25912591
def->category = OptionCategory::output;
25922592
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."
25932593
" 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()
25992599

26002600
def = this->add("gap_fill_last", coBool);
26012601
def->label = L("after last perimeter");
2602-
def->full_label = L("Gapfill after last perimeter");
2602+
def->full_label = L("Gapfill: after last perimeter");
26032603
def->category = OptionCategory::perimeter;
26042604
def->tooltip = L("All gaps, between the last perimeter and the infill, which are thinner than a perimeter will be filled by gapfill.");
26052605
def->mode = comExpert | comSuSi;
26062606
def->set_default_value(new ConfigOptionBool(false));
26072607

2608+
def = this->add("gap_fill_max_width", coFloatOrPercent);
2609+
def->label = L("Max width");
2610+
def->full_label = L("Gapfill: Max width");
2611+
def->category = OptionCategory::perimeter;
2612+
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");
2613+
def->ratio_over = "perimeter_width";
2614+
def->sidetext = L("mm or %");
2615+
def->min = 0;
2616+
def->mode = comExpert | comSuSi;
2617+
def->set_default_value(new ConfigOptionFloatOrPercent{ 0, false });
2618+
26082619
def = this->add("gap_fill_min_area", coFloatOrPercent);
26092620
def->label = L("Min surface");
2610-
def->full_label = L("Min surface for gap filling");
2621+
def->full_label = L("Gapfill: Min surface");
26112622
def->category = OptionCategory::perimeter;
26122623
def->tooltip = L("This setting represents the minimum mm² for a gapfill extrusion to be created.\nCan be a % of (perimeter width)²");
26132624
def->ratio_over = "perimeter_width_square";
2625+
def->sidetext = L("mm² or %");
2626+
def->min = 0;
2627+
def->mode = comExpert | comSuSi;
2628+
def->set_default_value(new ConfigOptionFloatOrPercent{ 100, true });
2629+
2630+
def = this->add("gap_fill_min_width", coFloatOrPercent);
2631+
def->label = L("Min width");
2632+
def->full_label = L("Gapfill: Min width");
2633+
def->category = OptionCategory::perimeter;
2634+
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");
2635+
def->ratio_over = "perimeter_width";
2636+
def->sidetext = L("mm or %");
26142637
def->min = 0;
26152638
def->mode = comExpert | comSuSi;
2616-
def->set_default_value(new ConfigOptionFloatOrPercent{100, true });
2639+
def->set_default_value(new ConfigOptionFloatOrPercent{ 0, false });
26172640

26182641
def = this->add("gap_fill_overlap", coPercent);
26192642
def->label = L("Gap fill overlap");

src/libslic3r/PrintConfig.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -812,7 +812,9 @@ PRINT_CONFIG_CLASS_DEFINE(
812812
((ConfigOptionBool, gap_fill_enabled))
813813
((ConfigOptionPercent, gap_fill_flow_match_perimeter))
814814
((ConfigOptionBool, gap_fill_last))
815+
((ConfigOptionFloatOrPercent, gap_fill_max_width))
815816
((ConfigOptionFloatOrPercent, gap_fill_min_area))
817+
((ConfigOptionFloatOrPercent, gap_fill_min_width))
816818
((ConfigOptionPercent, gap_fill_overlap))
817819
((ConfigOptionFloatOrPercent, gap_fill_speed))
818820
((ConfigOptionFloatOrPercent, infill_anchor))

src/libslic3r/PrintObject.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,7 +714,9 @@ bool PrintObject::invalidate_state_by_config_options(
714714
if (
715715
opt_key == "gap_fill_enabled"
716716
|| opt_key == "gap_fill_last"
717+
|| opt_key == "gap_fill_max_width"
717718
|| opt_key == "gap_fill_min_area"
719+
|| opt_key == "gap_fill_min_width"
718720
|| opt_key == "only_one_perimeter_first_layer"
719721
|| opt_key == "only_one_perimeter_top"
720722
|| opt_key == "only_one_perimeter_top_other_algo"

src/slic3r/GUI/ConfigManipulation.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
345345

346346
toggle_field("perimeter_loop_seam", config->opt_bool("perimeter_loop"));
347347

348-
for (auto el : { "gap_fill_last", "gap_fill_min_area" })
348+
for (auto el : { "gap_fill_last", "gap_fill_max_width", "gap_fill_min_area", "gap_fill_min_width" })
349349
toggle_field(el, config->opt_bool("gap_fill_enabled"));
350350

351351
for (auto el : { "fuzzy_skin_thickness", "fuzzy_skin_point_dist" })

0 commit comments

Comments
 (0)