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.
This commit is contained in:
supermerill 2020-05-07 20:33:38 +02:00
parent e380bd9176
commit daa891aa9b
3 changed files with 112 additions and 7 deletions

View File

@ -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<size_t> 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) {

View File

@ -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.

View File

@ -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)