From daa891aa9b00cc0403a37845f1fcd8d1e6e56b39 Mon Sep 17 00:00:00 2001 From: supermerill Date: Thu, 7 May 2020 20:33:38 +0200 Subject: [PATCH] gap fill: remove gap fill if it's too thin to make a continuous curve. thinwall/gapfill: remove harmful bits that sticks out of the main line without going outside of it. --- src/libslic3r/MedialAxis.cpp | 67 +++++++++++++++++++++++++++- src/libslic3r/MedialAxis.hpp | 2 + src/libslic3r/PerimeterGenerator.cpp | 50 ++++++++++++++++++--- 3 files changed, 112 insertions(+), 7 deletions(-) diff --git a/src/libslic3r/MedialAxis.cpp b/src/libslic3r/MedialAxis.cpp index dd74f8ad2..41f8f8d2d 100644 --- a/src/libslic3r/MedialAxis.cpp +++ b/src/libslic3r/MedialAxis.cpp @@ -558,6 +558,67 @@ MedialAxis::fusion_curve(ThickPolylines &pp) } } +void +MedialAxis::remove_bits(ThickPolylines &pp) +{ + + //remove small bits that stick out of the path + bool changes = false; + for (size_t i = 0; i < pp.size(); ++i) { + ThickPolyline& polyline = pp[i]; + // only consider polyline with 0-end + if (polyline.endpoints.first) polyline.reverse(); + else if (!polyline.endpoints.second) continue; + if (polyline.width.back() > 0) continue; + + //check my length is small + coord_t length = (coord_t)polyline.length(); + if (length > max_width*1.5) { + continue; + } + + // look if other end is a cross point with multiple other branch + std::vector crosspoint; + for (size_t j = 0; j < pp.size(); ++j) { + if (j == i) continue; + ThickPolyline& other = pp[j]; + if (polyline.first_point().coincides_with(other.last_point())) { + other.reverse(); + crosspoint.push_back(j); + } else if (polyline.first_point().coincides_with(other.first_point())) { + crosspoint.push_back(j); + } + } + if (crosspoint.size() < 2) continue; + + //check if is smaller or the other ones are not endpoits + int nb_better_than_me = 0; + for (int i = 0; i < crosspoint.size(); i++) { + if (!pp[crosspoint[0]].endpoints.second || length <= pp[crosspoint[0]].length()) + nb_better_than_me++; + } + if (nb_better_than_me < 2) continue; + + //check if the length of the polyline is small vs width of the other lines + double max_width = 0; + for (int i = 0; i < crosspoint.size(); i++) { + max_width = std::max(max_width, pp[crosspoint[i]].width[0]); + } + if (length > max_width + min_width) + continue; + + //delete the now unused polyline + pp.erase(pp.begin() + i); + --i; + changes = true; + } + if (changes) { + concatThickPolylines(pp); + ///reorder, in case of change + std::sort(pp.begin(), pp.end(), [](const ThickPolyline & a, const ThickPolyline & b) { return a.length() < b.length(); }); + } +} + void MedialAxis::fusion_corners(ThickPolylines &pp) { @@ -567,7 +628,7 @@ MedialAxis::fusion_corners(ThickPolylines &pp) for (size_t i = 0; i < pp.size(); ++i) { ThickPolyline& polyline = pp[i]; // only consider polyline with 0-end - if (polyline.points.size() != 2) continue; + //if (polyline.points.size() != 2) continue; // maybe we should have something to merge X-point to 2-point if it's near enough. if (polyline.endpoints.first) polyline.reverse(); else if (!polyline.endpoints.second) continue; if (polyline.width.back() > 0) continue; @@ -1717,6 +1778,10 @@ MedialAxis::build(ThickPolylines &polylines_out) // svg.Close(); //} + remove_bits(pp); + + //sort_polylines(pp); + //for (auto &p : pp) { // std::cout << " polyline : "; // for (auto &w : p.width) { diff --git a/src/libslic3r/MedialAxis.hpp b/src/libslic3r/MedialAxis.hpp index c09cc970c..734f5164a 100644 --- a/src/libslic3r/MedialAxis.hpp +++ b/src/libslic3r/MedialAxis.hpp @@ -112,6 +112,8 @@ class MedialAxis { void taper_ends(ThickPolylines& pp); //cleaning method void check_width(ThickPolylines& pp, double max_width, std::string msg); + //removing small extrusion that won't be useful and will harm print. A bit like fusion_corners but more lenient and with just del. + void remove_bits(ThickPolylines& pp); }; /// create a ExtrusionEntityCollection from ThickPolylines, discretizing the variable width into little sections (of 4*SCALED_RESOLUTION length) where needed. diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index b179035b5..5b3d0a93d 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -677,18 +677,55 @@ void PerimeterGenerator::process() //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(EPSILON, nozzle_diameter, this->layer_height, false).scaled_width())); double max = 2.2 * perimeter_spacing; - ExPolygons gaps_ex = diff_ex( - offset2_ex(gaps, double(-min / 2), double(+min / 2)), + //remove areas that are too big (shouldn't occur...) + ExPolygons gaps_ex_to_test = diff_ex( + gaps, offset2_ex(gaps, double(-max / 2), double(+max / 2)), true); - ThickPolylines polylines; - for (const ExPolygon &ex : gaps_ex) { + ExPolygons gaps_ex; + const double minarea = scale_(scale_(this->config->gap_fill_min_area.get_abs_value(unscaled(perimeter_width)*unscaled(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. //ie one that are smaller than an extrusion with width of min and a length of max. - if (ex.area() > scale_(scale_(this->config->gap_fill_min_area.get_abs_value(unscaled(perimeter_width)*unscaled(perimeter_width))))) { - MedialAxis{ ex, coord_t(max*1.1), coord_t(min), coord_t(this->layer_height) }.build(polylines); + if (expoly.area() > minarea) { + ExPolygons expoly_after_shrink_test = offset_ex(ExPolygons{ expoly }, double(-min * 0.5)); + //if the shrink split the area in multipe bits + if (expoly_after_shrink_test.size() > 1) { + //remove too small bits + for (int i = 0; i < expoly_after_shrink_test.size(); i++) + if (offset_ex(ExPolygons{ expoly_after_shrink_test[i] }, min*0.5)[0].area() < minarea) { + expoly_after_shrink_test.erase(expoly_after_shrink_test.begin() + i); + i--; + } + //maybe some areas are a just bit too thin, try with just a little more offset to remove them. + ExPolygons expoly_after_shrink_test2 = offset_ex(ExPolygons{ expoly }, double(-min *0.8)); + for (int i = 0; i < expoly_after_shrink_test2.size(); i++) + if (offset_ex(ExPolygons{ expoly_after_shrink_test2[i] }, min*0.5)[0].area() < minarea) { + expoly_after_shrink_test2.erase(expoly_after_shrink_test2.begin() + i); + i--; + } + //it's better if there are significantly less extrusions + if (expoly_after_shrink_test.size()/1.42 > expoly_after_shrink_test2.size()) { + expoly_after_shrink_test2 = offset_ex(expoly_after_shrink_test2, double(min * 0.8)); + //insert with move instead of copy + std::move(expoly_after_shrink_test2.begin(), expoly_after_shrink_test2.end(), std::back_inserter(gaps_ex)); + } else { + expoly_after_shrink_test = offset_ex(expoly_after_shrink_test, double(min * 0.8)); + std::move(expoly_after_shrink_test.begin(), expoly_after_shrink_test.end(), std::back_inserter(gaps_ex)); + } + } else { + expoly_after_shrink_test = offset_ex(expoly_after_shrink_test, double(min * 0.8)); + std::move(expoly_after_shrink_test.begin(), expoly_after_shrink_test.end(), std::back_inserter(gaps_ex)); + } } } + // create lines from the area + ThickPolylines polylines; + for (const ExPolygon &ex : gaps_ex) { + MedialAxis{ ex, coord_t(max*1.1), coord_t(min), coord_t(this->layer_height) }.build(polylines); + } + // create extrusion from lines if (!polylines.empty()) { ExtrusionEntityCollection gap_fill = thin_variable_width(polylines, erGapFill, this->solid_infill_flow); @@ -704,6 +741,7 @@ void PerimeterGenerator::process() last = diff_ex(to_polygons(last), gap_fill.polygons_covered_by_width(10.f)); } } + //TODO: if a gapfill extrusion is a loop and with width always >= periemter width then change the type to perimeter and put it at the right place in the loops vector. // create one more offset to be used as boundary for fill // we offset by half the perimeter spacing (to get to the actual infill boundary)