From a7d7b7cd22010dbf826d8396ce212dc0da842782 Mon Sep 17 00:00:00 2001 From: supermerill Date: Sun, 30 Jun 2024 17:03:49 +0200 Subject: [PATCH 1/3] Change gapfill for bottom bridge to support type. allow gapfill to be bridge. --- src/libslic3r/Fill/FillBase.hpp | 6 +++--- src/libslic3r/Fill/FillConcentric.cpp | 11 +++++++---- src/libslic3r/Geometry/MedialAxis.cpp | 12 ++++++++++-- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/libslic3r/Fill/FillBase.hpp b/src/libslic3r/Fill/FillBase.hpp index cdcfb3d8f51..1d0277d72d8 100644 --- a/src/libslic3r/Fill/FillBase.hpp +++ b/src/libslic3r/Fill/FillBase.hpp @@ -267,9 +267,9 @@ class ExtrusionSetRole : public ExtrusionVisitor { ExtrusionSetRole(ExtrusionRole role) : new_role(role) {} void use(ExtrusionPath &path) override { path.set_role(new_role); } void use(ExtrusionPath3D &path3D) override { path3D.set_role(new_role); } - void use(ExtrusionMultiPath &multipath) override { for (ExtrusionPath path : multipath.paths) path.set_role(new_role); } - void use(ExtrusionMultiPath3D &multipath) override { for (ExtrusionPath path : multipath.paths) path.set_role(new_role); } - void use(ExtrusionLoop &loop) override { for (ExtrusionPath path : loop.paths) path.set_role(new_role); } + void use(ExtrusionMultiPath &multipath) override { for (ExtrusionPath &path : multipath.paths) path.set_role(new_role); } + void use(ExtrusionMultiPath3D &multipath) override { for (ExtrusionPath &path : multipath.paths) path.set_role(new_role); } + void use(ExtrusionLoop &loop) override { for (ExtrusionPath &path : loop.paths) path.set_role(new_role); } void use(ExtrusionEntityCollection &collection) override { for (ExtrusionEntity *entity : collection.entities()) entity->visit(*this); } }; diff --git a/src/libslic3r/Fill/FillConcentric.cpp b/src/libslic3r/Fill/FillConcentric.cpp index ad5208c183a..66262843b83 100644 --- a/src/libslic3r/Fill/FillConcentric.cpp +++ b/src/libslic3r/Fill/FillConcentric.cpp @@ -363,11 +363,14 @@ FillConcentricWGapFill::fill_surface_extrusion( // } // //goto_next_polyline: //} - if (!polylines.empty() && !is_bridge(good_role)) { + bool fill_bridge = is_bridge(good_role) || params.flow.bridge(); + // allow bridged gapfill, mostly for support bottom interface. + assert(!is_bridge(good_role)); + if (!polylines.empty()) { ExtrusionEntitiesPtr gap_fill_entities = Geometry::thin_variable_width(polylines, erGapFill, params.flow, scale_t(params.config->get_computed_value("resolution_internal")), true); if (!gap_fill_entities.empty()) { - //set role if needed - if (good_role != erSolidInfill) { + // set role if needed + if (fill_bridge || (good_role != erSolidInfill && good_role != erTopSolidInfill)) { ExtrusionSetRole set_good_role(good_role); for (ExtrusionEntity* ptr : gap_fill_entities) ptr->visit(set_good_role); @@ -395,7 +398,7 @@ FillConcentricWGapFill::fill_surface_extrusion( // external gapfill ExPolygons gapfill_areas = diff_ex(ExPolygons{ surface->expolygon }, offset_ex(expp, double(scale_(0.5 * this->get_spacing())))); gapfill_areas = union_safety_offset_ex(gapfill_areas); - if (gapfill_areas.size() > 0) { + if (gapfill_areas.size() > 0 && no_overlap_expolygons.size() > 0) { double minarea = double(params.flow.scaled_width()) * double(params.flow.scaled_width()); if (params.config != nullptr) minarea = scale_d(params.config->gap_fill_min_area.get_abs_value(params.flow.width())) * double(params.flow.scaled_width()); for (int i = 0; i < gapfill_areas.size(); i++) { diff --git a/src/libslic3r/Geometry/MedialAxis.cpp b/src/libslic3r/Geometry/MedialAxis.cpp index f1d8788f780..080a74bbda8 100644 --- a/src/libslic3r/Geometry/MedialAxis.cpp +++ b/src/libslic3r/Geometry/MedialAxis.cpp @@ -3177,7 +3177,11 @@ unsafe_variable_width(const ThickPolyline& polyline, const ExtrusionRole role, c if (path.polyline.empty()) { if (wanted_width != current_flow.width()) { - current_flow = current_flow.with_width((float)wanted_width); + if (current_flow.bridge()) { + current_flow = Flow::bridging_flow(current_flow.height(), (float) wanted_width); + } else { + current_flow = current_flow.with_width((float) wanted_width); + } } path.polyline.append(line.a); path.polyline.append(line.b); @@ -3198,7 +3202,11 @@ unsafe_variable_width(const ThickPolyline& polyline, const ExtrusionRole role, c paths.push_back(path); path = ExtrusionPath(role, false); if (wanted_width != current_flow.width()) { - current_flow = current_flow.with_width(wanted_width); + if (current_flow.bridge()) { + current_flow = Flow::bridging_flow(current_flow.height(), (float) wanted_width); + } else { + current_flow = current_flow.with_width((float) wanted_width); + } } path.polyline.append(line.a); path.polyline.append(line.b); From cff9d4a2e126c66627bf025e8e7be4d6fa61bc73 Mon Sep 17 00:00:00 2001 From: supermerill Date: Sun, 30 Jun 2024 20:16:01 +0200 Subject: [PATCH 2/3] Fix thin wall merge with perimeter creating 0-extrusion size perimeters supermerill/SuperSlicer#4330 --- src/libslic3r/PerimeterGenerator.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index 3f9b0130ddf..12fc4b05b2b 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -3687,9 +3687,12 @@ void PerimeterGenerator::_merge_thin_walls(ExtrusionEntityCollection &extrusions if (searcher.search_result.path != nullptr) { #if _DEBUG searcher.search_result.loop->visit(LoopAssertVisitor{}); + ExtrusionLoop orig_loop = *searcher.search_result.loop; #endif if (!searcher.search_result.from_start) tw.reverse(); + //save old path, as it may be destroyed before being re-created and we want to keep its parameters. + ExtrusionPath path_to_split = *searcher.search_result.path; // TODO: 2.7: just save hte pathsettigns //get the point Point point = tw.front().projection_onto(searcher.search_result.line); //we have to create 3 paths: 1: thinwall extusion, 2: thinwall return, 3: end of the path @@ -3749,7 +3752,7 @@ void PerimeterGenerator::_merge_thin_walls(ExtrusionEntityCollection &extrusions } else { assert(poly_after.length() > SCALED_EPSILON); searcher.search_result.loop->paths.insert(searcher.search_result.loop->paths.begin() + idx_path_to_add, - ExtrusionPath(poly_after, *searcher.search_result.path)); + ExtrusionPath(poly_after, path_to_split)); } assert(idx_path_before > searcher.search_result.loop->paths.size() || searcher.search_result.loop->paths[idx_path_before].polyline.size() > 1); assert(poly_after.size() > 0); From 76110a564fefb8f55a8f8d349831f7d1edfa7a15 Mon Sep 17 00:00:00 2001 From: supermerill Date: Sun, 30 Jun 2024 20:17:13 +0200 Subject: [PATCH 3/3] more granular thin wall taper --- src/libslic3r/Geometry/MedialAxis.cpp | 55 ++++++++++++--------------- src/libslic3r/PerimeterGenerator.cpp | 4 +- 2 files changed, 27 insertions(+), 32 deletions(-) diff --git a/src/libslic3r/Geometry/MedialAxis.cpp b/src/libslic3r/Geometry/MedialAxis.cpp index 080a74bbda8..c6164b8cb01 100644 --- a/src/libslic3r/Geometry/MedialAxis.cpp +++ b/src/libslic3r/Geometry/MedialAxis.cpp @@ -2636,17 +2636,15 @@ MedialAxis::taper_ends(ThickPolylines& pp) if (polyline.length() < length * 2.2) continue; if (polyline.endpoints.first) { polyline.points_width[0] = min_size; - coord_t current_dist = min_size; - coord_t last_dist = min_size; + coord_t current_dist = 0; + coord_t last_dist = 0; for (size_t i = 1; i < polyline.points_width.size(); ++i) { current_dist += (coord_t)polyline.points[i - 1].distance_to(polyline.points[i]); if (current_dist > length) { //create a new point if not near enough - if (current_dist > length + coordf_t(this->m_resolution)) { - coordf_t percent_dist = (length - last_dist) / (current_dist - last_dist); - polyline.points.insert(polyline.points.begin() + i, polyline.points[i - 1].interpolate(percent_dist, polyline.points[i])); - polyline.points_width.insert(polyline.points_width.begin() + i, polyline.points_width[i]); - } + coordf_t percent_dist = (length - last_dist) / (current_dist - last_dist); + polyline.points.insert(polyline.points.begin() + i, polyline.points[i - 1].interpolate(percent_dist, polyline.points[i])); + polyline.points_width.insert(polyline.points_width.begin() + i, polyline.points_width[i]); break; } polyline.points_width[i] = std::max((coordf_t)min_size, min_size + (polyline.points_width[i] - min_size) * current_dist / length); @@ -2655,17 +2653,15 @@ MedialAxis::taper_ends(ThickPolylines& pp) } if (polyline.endpoints.second) { polyline.points_width[polyline.points_width.size() - 1] = min_size; - coord_t current_dist = min_size; - coord_t last_dist = min_size; + coord_t current_dist = 0; + coord_t last_dist = 0; for (size_t i = polyline.points_width.size() - 1; i > 0; --i) { current_dist += (coord_t)polyline.points[i].distance_to(polyline.points[i - 1]); if (current_dist > length) { //create new point if not near enough - if (current_dist > length + coordf_t(this->m_resolution)) { - coordf_t percent_dist = (length - last_dist) / (current_dist - last_dist); - polyline.points.insert(polyline.points.begin() + i, polyline.points[i].interpolate(percent_dist, polyline.points[i - 1])); - polyline.points_width.insert(polyline.points_width.begin() + i, polyline.points_width[i - 1]); - } + coordf_t percent_dist = (length - last_dist) / (current_dist - last_dist); + polyline.points.insert(polyline.points.begin() + i, polyline.points[i].interpolate(percent_dist, polyline.points[i - 1])); + polyline.points_width.insert(polyline.points_width.begin() + i, polyline.points_width[i - 1]); break; } polyline.points_width[i - 1] = std::max((coordf_t)min_size, min_size + (polyline.points_width[i - 1] - min_size) * current_dist / length); @@ -3114,25 +3110,23 @@ unsafe_variable_width(const ThickPolyline& polyline, const ExtrusionRole role, c continue; } } else if (i > 0 && resolution_internal > line_len + prev_line_len) { + assert(prev_line_len > 0 && line_len > 0); //merge lines? //if it's a loop, merge only if the distance is high enough if (polyline.first_point() == polyline.last_point() && polyline.length() < (line_len + prev_line_len) * 6) continue; ThickLine& prev_line = lines[i - 1]; + const coordf_t sum_length = prev_line_len + line_len; + const coordf_t new_length = prev_line.a.distance_to(line.b); + assert(sum_length - new_length > -0.0000000001); + // only merge if the distance is almost the sum (90° = 0.707) + if(new_length < sum_length * 0.9) + continue; + assert(new_length > prev_line_len && new_length > line_len); coordf_t width = prev_line_len * (prev_line.a_width + prev_line.b_width) / 2; width += line_len * (line.a_width + line.b_width) / 2; + width /= (prev_line_len + line_len); prev_line.b = line.b; - const coordf_t new_length = prev_line.length(); - if (new_length < SCALED_EPSILON) { - // too short, remove it and restart - if (i > 1) { - line.a = lines[i - 2].b; - } - lines.erase(lines.begin() + i - 1); - i -= 2; - continue; - } - width /= new_length; prev_line.a_width = width; prev_line.b_width = width; saved_line_len = new_length; @@ -3154,6 +3148,7 @@ unsafe_variable_width(const ThickPolyline& polyline, const ExtrusionRole role, c // but we can't extrude with a negative spacing, so we have to gradually fall back to spacing if the width is too small. // default: extrude a thin wall that doesn't go outside of the specified width. + assert(line.a_width == line.b_width); double wanted_width = unscaled(line.a_width); //if gapfill or arachne, the width is in fact the spacing. if (role != erThinWall) { @@ -3163,16 +3158,16 @@ unsafe_variable_width(const ThickPolyline& polyline, const ExtrusionRole role, c } else { // Convert from spacing to extrusion width based on the extrusion model // of a square extrusion ended with semi circles. - wanted_width = Flow::rounded_rectangle_extrusion_width_from_spacing(unscaled(line.a_width), flow.height(), flow.spacing_ratio()); + wanted_width = Flow::rounded_rectangle_extrusion_width_from_spacing(wanted_width, flow.height(), flow.spacing_ratio()); } } // check if the width isn't too small (negative spacing) // 1.f spacing ratio, because it's to get the really minimum. 0 spacing ratio will makes that irrelevant. - if (unscale(line.a_width) < 2 * Flow::rounded_rectangle_extrusion_width_from_spacing(0.f, flow.height(), 1.f)) { + if (wanted_width < 2 * Flow::rounded_rectangle_extrusion_width_from_spacing(0.f, flow.height(), 1.f)) { //width (too) small, be sure to not extrude with negative spacing. //we began to fall back to spacing gradually even before the spacing go into the negative - // to make extrusion1 < extrusion2 if width1 < width2 even if width2 is too small. - wanted_width = unscaled(line.a_width) * 0.35 + 1.3 * Flow::rounded_rectangle_extrusion_width_from_spacing(0.f, flow.height(), 1.f); + // to make extrusion1 < extrusion2 if width1 < width2 even if width2 is too small. + wanted_width = wanted_width * 0.35 + 1.3 * Flow::rounded_rectangle_extrusion_width_from_spacing(0.f, flow.height(), 1.f); } if (path.polyline.empty()) { @@ -3234,7 +3229,7 @@ ExtrusionEntitiesPtr // this value determines granularity of adaptive width, as G-code does not allow // variable extrusion within a single move; this value shall only affect the amount // of segments, and any pruning shall be performed before we apply this tolerance - const coord_t tolerance = flow.scaled_width() / 10;//scale_(0.05); + const coord_t tolerance = flow.scaled_width() / 20;//scale_(0.05); ExtrusionEntitiesPtr coll; for (const ThickPolyline& p : polylines) { ExtrusionMultiPath multi_paths = variable_width(p, role, flow, resolution_internal, tolerance, can_reverse); diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index 12fc4b05b2b..a9a030e91ac 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -1579,7 +1579,7 @@ ProcessSurfaceResult PerimeterGenerator::process_classic(int& contour_count, int bound.remove_point_too_near(ext_perimeter_width / 10); // the maximum thickness of our thin wall area is equal to the minimum thickness of a single loop (*1.2 because of circles approx. and enlrgment from 'div') Slic3r::Geometry::MedialAxis ma{ thin[0], (coord_t)((ext_perimeter_width + ext_perimeter_spacing) * 1.2), - min_width, coord_t(this->layer->height) }; + min_width, scale_t(this->layer->height) }; ma.use_bounds(bound) .use_min_real_width(scale_t(this->ext_perimeter_flow.nozzle_diameter())) .use_tapers(thin_walls_overlap) @@ -3759,7 +3759,7 @@ void PerimeterGenerator::_merge_thin_walls(ExtrusionEntityCollection &extrusions //create thin wall path exttrusion ExtrusionEntityCollection tws; - tws.append(Geometry::thin_variable_width({ tw }, erThinWall, this->ext_perimeter_flow, std::max(ext_perimeter_flow.scaled_width() / 4, scale_t(this->print_config->resolution)), false)); + tws.append(Geometry::thin_variable_width({ tw }, erThinWall, this->ext_perimeter_flow, std::max(ext_perimeter_flow.scaled_width() / 10, scale_t(this->print_config->resolution)), false)); assert(!tws.entities().empty()); #if _DEBUG tws.visit(LoopAssertVisitor{});