diff --git a/resources/profiles/Basic.ini b/resources/profiles/Basic.ini index b6c90dddb..75856f038 100644 --- a/resources/profiles/Basic.ini +++ b/resources/profiles/Basic.ini @@ -178,8 +178,9 @@ printer_model = Custom_1.75mm avoid_crossing_perimeters = 0 bridge_acceleration = 1000 bridge_angle = 0 -bridge_flow_ratio = 0.8 -over_bridge_flow_ratio = 1.05 +bridge_flow_ratio = 80% +over_bridge_flow_ratio = 105% +fill_top_flow_ratio = 100% bridge_speed = 20 brim_width = 0 clip_multipart_objects = 1 @@ -291,148 +292,60 @@ perimeters = 6 infill_overlap = 40% first_layer_height = 0.1 compatible_printers_condition = nozzle_diameter[0]==0.15 -extrusion_width = 0.16 -external_perimeter_extrusion_width = 0.16 -first_layer_extrusion_width = 0.2 -infill_extrusion_width = 0.17 -perimeter_extrusion_width = 0.17 -solid_infill_extrusion_width = 0.17 -top_infill_extrusion_width = 0.16 -support_material_extrusion_width = 0.17 [print:*0.2nozzle*] perimeters = 5 infill_overlap = 35% first_layer_height = 0.14 compatible_printers_condition = nozzle_diameter[0]==0.2 -extrusion_width = 0.21 -external_perimeter_extrusion_width = 0.22 -first_layer_extrusion_width = 0.3 -infill_extrusion_width = 0.22 -perimeter_extrusion_width = 0.22 -solid_infill_extrusion_width = 0.22 -top_infill_extrusion_width = 0.21 -support_material_extrusion_width = 0.22 [print:*0.25nozzle*] perimeters = 4 infill_overlap = 30% first_layer_height = 0.17 compatible_printers_condition = nozzle_diameter[0]==0.25 -extrusion_width = 0.26 -external_perimeter_extrusion_width = 0.26 -first_layer_extrusion_width = 0.35 -infill_extrusion_width = 0.27 -perimeter_extrusion_width = 0.27 -solid_infill_extrusion_width = 0.27 -top_infill_extrusion_width = 0.26 -support_material_extrusion_width = 0.27 [print:*0.3nozzle*] perimeters = 4 infill_overlap = 25% first_layer_height = 0.2 compatible_printers_condition = nozzle_diameter[0]==0.3 -extrusion_width = 0.32 -external_perimeter_extrusion_width = 0.32 -first_layer_extrusion_width = 0.45 -infill_extrusion_width = 0.33 -perimeter_extrusion_width = 0.33 -solid_infill_extrusion_width = 0.33 -top_infill_extrusion_width = 0.32 -support_material_extrusion_width = 0.33 [print:*0.35nozzle*] perimeters = 3 infill_overlap = 25% first_layer_height = 0.2 compatible_printers_condition = nozzle_diameter[0]==0.35 -extrusion_width = 0.37 -external_perimeter_extrusion_width = 0.37 -first_layer_extrusion_width = 0.5 -infill_extrusion_width = 0.39 -perimeter_extrusion_width = 0.39 -solid_infill_extrusion_width = 0.39 -top_infill_extrusion_width = 0.37 -support_material_extrusion_width = 0.39 [print:*0.4nozzle*] perimeters = 3 infill_overlap = 25% compatible_printers_condition = nozzle_diameter[0]==0.4 -extrusion_width = 0.42 -external_perimeter_extrusion_width = 0.42 -first_layer_extrusion_width = 0.6 -infill_extrusion_width = 0.44 -perimeter_extrusion_width = 0.44 -solid_infill_extrusion_width = 0.44 -top_infill_extrusion_width = 0.42 -support_material_extrusion_width = 0.44 [print:*0.5nozzle*] perimeters = 3 infill_overlap = 20% compatible_printers_condition = nozzle_diameter[0]==0.5 -extrusion_width = 0.52 -external_perimeter_extrusion_width = 0.52 -first_layer_extrusion_width = 0.7 -infill_extrusion_width = 0.55 -perimeter_extrusion_width = 0.55 -solid_infill_extrusion_width = 0.55 -top_infill_extrusion_width = 0.52 -support_material_extrusion_width = 0.52 [print:*0.6nozzle*] perimeters = 2 infill_overlap = 15% compatible_printers_condition = nozzle_diameter[0]==0.6 -extrusion_width = 0.63 -external_perimeter_extrusion_width = 0.63 -first_layer_extrusion_width = 0.8 -infill_extrusion_width = 0.66 -perimeter_extrusion_width = 0.66 -solid_infill_extrusion_width = 0.66 -top_infill_extrusion_width = 0.63 -support_material_extrusion_width = 0.66 [print:*0.8nozzle*] perimeters = 2 infill_overlap = 15% compatible_printers_condition = nozzle_diameter[0]==0.8 -extrusion_width = 0.84 -external_perimeter_extrusion_width = 0.84 -first_layer_extrusion_width = 1 -infill_extrusion_width = 0.88 -perimeter_extrusion_width = 0.88 -solid_infill_extrusion_width = 0.88 -top_infill_extrusion_width = 0.84 -support_material_extrusion_width = 0.88 [print:*1.0nozzle*] perimeters = 1 infill_overlap = 10% compatible_printers_condition = nozzle_diameter[0]==1 -extrusion_width = 1.05 -external_perimeter_extrusion_width = 1.05 -first_layer_extrusion_width = 1.2 -infill_extrusion_width = 1.1 -perimeter_extrusion_width = 1.1 -solid_infill_extrusion_width = 1.1 -top_infill_extrusion_width = 1.05 -support_material_extrusion_width = 1.1 [print:*1.2nozzle*] perimeters = 1 infill_overlap = 10% compatible_printers_condition = nozzle_diameter[0]==1.2 -extrusion_width = 1.25 -external_perimeter_extrusion_width = 1.25 -first_layer_extrusion_width = 1.4 -infill_extrusion_width = 1.3 -perimeter_extrusion_width = 1.3 -solid_infill_extrusion_width = 1.3 -top_infill_extrusion_width = 1.25 -support_material_extrusion_width = 1.3 [print:*0.08mm*] inherits = *common* diff --git a/resources/profiles/PrusaResearch.ini b/resources/profiles/PrusaResearch.ini index 130913b43..45b6c7231 100644 --- a/resources/profiles/PrusaResearch.ini +++ b/resources/profiles/PrusaResearch.ini @@ -94,8 +94,9 @@ family = SL1 avoid_crossing_perimeters = 0 bridge_acceleration = 1000 bridge_angle = 0 -bridge_flow_ratio = 0.8 -over_bridge_flow_ratio = 1.2 +bridge_flow_ratio = 80% +over_bridge_flow_ratio = 120% +fill_top_flow_ratio = 120% bridge_speed = 20 brim_width = 0 clip_multipart_objects = 1 diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index 2acdf159b..253648ba6 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -1734,7 +1734,11 @@ public: int opt_int(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast(this->option(opt_key))->get_at(idx); } template - ENUM opt_enum(const t_config_option_key &opt_key) const { return (ENUM)dynamic_cast(this->option(opt_key))->value; } + ENUM opt_enum(const t_config_option_key &opt_key) const { + auto v1 = this->option(opt_key); + auto v2 = this->option>(opt_key); + return v1==nullptr? v2->value : (ENUM)v1->value; + } bool opt_bool(const t_config_option_key &opt_key) const { return this->option(opt_key)->value != 0; } bool opt_bool(const t_config_option_key &opt_key, unsigned int idx) const { return this->option(opt_key)->get_at(idx) != 0; } diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index 04d7420cb..acc83272b 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -315,13 +315,18 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out) flow = Flow::new_from_spacing(f->spacing, flow.nozzle_diameter, (float)h, is_bridge || f->use_bridge_flow()); } + //adjust flow (to over-extrude when needed) float flow_percent = 1; + if (surface.has_pos_top()) flow_percent *= layerm.region()->config().fill_top_flow_ratio.get_abs_value(1); + params.flow_mult = flow_percent; + + //adjust spacing (to over-extrude when needed) if (surface.has_mod_overBridge()){ - params.density = layerm.region()->config().over_bridge_flow_ratio; - //params.flow_mult = layerm.region()->config().over_bridge_flow_ratio; + params.density = layerm.region()->config().over_bridge_flow_ratio.get_abs_value(1); } - + params.flow = &flow; + params.config = &layerm.region()->config(); f->fill_surface_extrusion(&surface, params, out.entities); } diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index be18ffe79..20e678300 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -214,7 +214,7 @@ void Fill::fill_surface_extrusion(const Surface *surface, const FillParams ¶ eec->entities, std::move(polylines), good_role, params.flow->mm3_per_mm() * params.flow_mult * multFlow, - params.flow->width * params.flow_mult * multFlow, + (float)(params.flow->width * params.flow_mult * multFlow), (float)params.flow->height); } @@ -277,9 +277,10 @@ void cut_polygon(Polyline &poly, size_t idx_1, Point p1, Point p2) { /// it use equally_spaced_points with width/2 precision, so don't worry with pts_to_check number of points. /// it use the given polylines_blocker points, be sure to put enough of them to be reliable. /// complexity : N(pts_to_check.equally_spaced_points(width / 2)) x N(polylines_blocker.points) -bool collision(const Points &pts_to_check, const Polylines &polylines_blocker, const coordf_t width) { +bool collision(const Points &pts_to_check, const Polylines &polylines_blocker, const coord_t width) { //check if it's not too close to a polyline - coordf_t min_dist_square = width * width * 0.9 - SCALED_EPSILON; + //convert to double to allow ² operation + double min_dist_square = (double)width * (double)width * 0.9 - SCALED_EPSILON; Polyline better_polylines(pts_to_check); Points better_pts = better_polylines.equally_spaced_points(width / 2); for (const Point &p : better_pts) { @@ -298,6 +299,8 @@ bool collision(const Points &pts_to_check, const Polylines &polylines_blocker, c /// width if the width of the extrusion /// polylines_blockers are the array of polylines to check if the path isn't blocked by something. /// complexity: N(polylines.points) + a collision check after that if we finded a path: N(2(p2-p1)/width) x N(polylines_blocker.points) +/// @param width is scaled +/// @param max_size is scaled Points getFrontier(Polylines &polylines, const Point& p1, const Point& p2, const coord_t width, const Polylines &polylines_blockers, coord_t max_size = -1) { for (size_t idx_poly = 0; idx_poly < polylines.size(); ++idx_poly) { Polyline &poly = polylines[idx_poly]; @@ -486,8 +489,8 @@ void Fill::connect_infill(const Polylines &infill_ordered, const ExPolygon &boun for (const Polyline &polyline : infill_ordered) { if (polyline.length() > 2.01 * clip_size) { polylines_blocker.push_back(polyline); - polylines_blocker.back().clip_end(clip_size); - polylines_blocker.back().clip_start(clip_size); + polylines_blocker.back().clip_end((double)clip_size); + polylines_blocker.back().clip_start((double)clip_size); } } @@ -503,7 +506,7 @@ void Fill::connect_infill(const Polylines &infill_ordered, const ExPolygon &boun const Point &last_point = pts_end.back(); const Point &first_point = polyline.points.front(); if (last_point.distance_to(first_point) < scale_(this->spacing) * 10) { - Points pts_frontier = getFrontier(polylines_frontier, last_point, first_point, scale_(this->spacing), polylines_blocker, (coord_t)scale_(ideal_length) * 2); + Points pts_frontier = getFrontier(polylines_frontier, last_point, first_point, scale_(this->spacing), polylines_blocker, scale_(ideal_length) * 2); if (!pts_frontier.empty()) { // The lines can be connected. pts_end.insert(pts_end.end(), pts_frontier.begin(), pts_frontier.end()); diff --git a/src/libslic3r/Fill/FillBase.hpp b/src/libslic3r/Fill/FillBase.hpp index ff524c30d..987473717 100644 --- a/src/libslic3r/Fill/FillBase.hpp +++ b/src/libslic3r/Fill/FillBase.hpp @@ -30,6 +30,7 @@ struct FillParams fill_exactly = false; role = erNone; flow = NULL; + config = NULL; } bool full_infill() const { return density > 0.9999f && density < 1.0001f; } @@ -59,6 +60,9 @@ struct FillParams //flow to use Flow const *flow; + + //full configuration for the region, to avoid copying every bit that is needed. Use this for process-specific parameters. + PrintRegionConfig const *config; }; static_assert(IsTriviallyCopyable::value, "FillParams class is not POD (and it should be - see constructor)."); @@ -135,6 +139,8 @@ protected: void connect_infill(const Polylines &infill_ordered, const ExPolygon &boundary, Polylines &polylines_out, const FillParams ¶ms); + void do_gap_fill(const ExPolygons &gapfill_areas, const FillParams ¶ms, ExtrusionEntitiesPtr &coll_out); + ExtrusionRole getRoleFromSurfaceType(const FillParams ¶ms, const Surface *surface){ if (params.role == erNone || params.role == erCustom) { return params.flow->bridge ? diff --git a/src/libslic3r/Fill/FillRectilinear2.cpp b/src/libslic3r/Fill/FillRectilinear2.cpp index 27b19daf8..9ae6aca50 100644 --- a/src/libslic3r/Fill/FillRectilinear2.cpp +++ b/src/libslic3r/Fill/FillRectilinear2.cpp @@ -1767,22 +1767,39 @@ FillRectilinearSawtooth::fill_surface_extrusion(const Surface *surface, const Fi } -void -FillRectilinear2WGapFill::fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, ExtrusionEntitiesPtr &out) { - ExtrusionEntityCollection *coll_nosort = new ExtrusionEntityCollection(); - coll_nosort->no_sort = true; //can be sorted inside the pass - ExtrusionRole good_role = getRoleFromSurfaceType(params, surface); +void FillRectilinear2WGapFill::split_polygon_gap_fill(const Surface &surface, const FillParams ¶ms, ExPolygons &rectilinear, ExPolygons &gapfill) { // remove areas for gapfill // factor=0.5 : remove area smaller than a spacing. factor=1 : max spacing for the gapfill (but not the width) //choose between 2 to avoid dotted line effect. float factor1 = 0.99f; float factor2 = 0.7f; - ExPolygons rectilinear_areas1 = offset2_ex(ExPolygons{ surface->expolygon }, -params.flow->scaled_spacing() * factor1, params.flow->scaled_spacing() * factor1); - ExPolygons rectilinear_areas2 = offset2_ex(ExPolygons{ surface->expolygon }, -params.flow->scaled_spacing() * factor2, params.flow->scaled_spacing() * factor2); - std::cout << "FillRectilinear2WGapFill use " << (rectilinear_areas1.size() <= rectilinear_areas2.size() + 1 ? "1" : "2") << "\n"; - ExPolygons &rectilinear_areas = rectilinear_areas1.size() <= rectilinear_areas2.size() + 1 ? rectilinear_areas1 : rectilinear_areas2; - ExPolygons gapfill_areas = diff_ex(ExPolygons{ surface->expolygon }, rectilinear_areas); + ExPolygons rectilinear_areas1 = offset2_ex(ExPolygons{ surface.expolygon }, -params.flow->scaled_spacing() * factor1, params.flow->scaled_spacing() * factor1); + ExPolygons rectilinear_areas2 = offset2_ex(ExPolygons{ surface.expolygon }, -params.flow->scaled_spacing() * factor2, params.flow->scaled_spacing() * factor2); + //choose the best one + rectilinear = rectilinear_areas1.size() <= rectilinear_areas2.size() + 1 || rectilinear_areas2.empty() ? rectilinear_areas1 : rectilinear_areas2; + //get gapfill + gapfill = diff_ex(ExPolygons{ surface.expolygon }, rectilinear); +} + +void +FillRectilinear2WGapFill::fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, ExtrusionEntitiesPtr &out) { + ExtrusionEntityCollection *coll_nosort = new ExtrusionEntityCollection(); + coll_nosort->no_sort = true; //can be sorted inside the pass + ExtrusionRole good_role = getRoleFromSurfaceType(params, surface); + + //// remove areas for gapfill + //// factor=0.5 : remove area smaller than a spacing. factor=1 : max spacing for the gapfill (but not the width) + ////choose between 2 to avoid dotted line effect. + //float factor1 = 0.99f; + //float factor2 = 0.7f; + //ExPolygons rectilinear_areas1 = offset2_ex(ExPolygons{ surface->expolygon }, -params.flow->scaled_spacing() * factor1, params.flow->scaled_spacing() * factor1); + //ExPolygons rectilinear_areas2 = offset2_ex(ExPolygons{ surface->expolygon }, -params.flow->scaled_spacing() * factor2, params.flow->scaled_spacing() * factor2); + //std::cout << "FillRectilinear2WGapFill use " << (rectilinear_areas1.size() <= rectilinear_areas2.size() + 1 ? "1" : "2") << "\n"; + //ExPolygons &rectilinear_areas = rectilinear_areas1.size() <= rectilinear_areas2.size() + 1 ? rectilinear_areas1 : rectilinear_areas2; + //ExPolygons gapfill_areas = diff_ex(ExPolygons{ surface->expolygon }, rectilinear_areas); + ExPolygons rectilinear_areas, gapfill_areas; + split_polygon_gap_fill(*surface, params, rectilinear_areas, gapfill_areas); double rec_area = 0; for (ExPolygon &p : rectilinear_areas)rec_area += p.area(); double gf_area = 0; @@ -1793,7 +1810,7 @@ FillRectilinear2WGapFill::fill_surface_extrusion(const Surface *surface, const F Polylines polylines_rectilinear; Surface rectilinear_surface{ *surface }; for (const ExPolygon &rectilinear_area : rectilinear_areas) { - rectilinear_surface.expolygon = rectilinear_area; + rectilinear_surface.expolygon = rectilinear_area, 0 - 0.5 * params.flow->scaled_spacing(); if (!fill_surface_by_lines(&rectilinear_surface, params, 0.f, 0.f, polylines_rectilinear)) { printf("FillRectilinear2::fill_surface() failed to fill a region.\n"); } @@ -1855,48 +1872,9 @@ FillRectilinear2WGapFill::fill_surface_extrusion(const Surface *surface, const F //gapfill if (gapfill_areas.size() > 0) { - ThickPolylines polylines_gapfill; - double min = 0.4 * scale_(params.flow->nozzle_diameter) * (1 - INSET_OVERLAP_TOLERANCE); - double max = 2. * params.flow->scaled_width(); - // collapse - //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, params.flow->nozzle_diameter , params.flow->height, false).scaled_width())); - //ExPolygons gapfill_areas_collapsed = diff_ex( - // offset2_ex(gapfill_areas, double(-min / 2), double(+min / 2)), - // offset2_ex(gapfill_areas, double(-max / 2), double(+max / 2)), - // true); - ExPolygons gapfill_areas_collapsed = offset2_ex(gapfill_areas, double(-min / 2), double(+min / 2)); - for (const ExPolygon &ex : gapfill_areas_collapsed) { - //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_(params.flow->nozzle_diameter)*scale_(params.flow->nozzle_diameter) * 2) { - MedialAxis{ ex, params.flow->scaled_width() * 2, params.flow->scaled_width() / 5, coord_t(params.flow->height) }.build(polylines_gapfill); - } - } - if (!polylines_gapfill.empty() && good_role != erBridgeInfill) { - //test - for (ThickPolyline poly : polylines_gapfill) { - for (coordf_t width : poly.width) { - if (width > params.flow->scaled_width() * 2.2) { - std::cout << "ERRROR!!!! recti gapfill width = " << unscaled(width) << " > max_width = " << (params.flow->width * 2) << "\n"; - } - } - } - - ExtrusionEntityCollection gap_fill = thin_variable_width(polylines_gapfill, erGapFill, *params.flow); - //set role if needed - if (good_role != erSolidInfill) { - ExtrusionSetRole set_good_role(good_role); - gap_fill.visit(set_good_role); - } - //move them into the collection - if (!gap_fill.entities.empty()) { - ExtrusionEntityCollection *coll_gapfill = new ExtrusionEntityCollection(); - coll_gapfill->no_sort = this->no_sort(); - coll_gapfill->append(std::move(gap_fill.entities)); - coll_nosort->entities.push_back(coll_gapfill); - } - } + FillParams params2{ params }; + params2.role = good_role; + do_gap_fill(gapfill_areas, params2, coll_nosort->entities); } // === end === @@ -1908,6 +1886,55 @@ FillRectilinear2WGapFill::fill_surface_extrusion(const Surface *surface, const F } +void +Fill::do_gap_fill(const ExPolygons &gapfill_areas, const FillParams ¶ms, ExtrusionEntitiesPtr &coll_out) { + + ThickPolylines polylines_gapfill; + double min = 0.4 * scale_(params.flow->nozzle_diameter) * (1 - INSET_OVERLAP_TOLERANCE); + double max = 2. * params.flow->scaled_width(); + // collapse + //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, params.flow->nozzle_diameter, params.flow->height, false).scaled_width())); + //ExPolygons gapfill_areas_collapsed = diff_ex( + // offset2_ex(gapfill_areas, double(-min / 2), double(+min / 2)), + // offset2_ex(gapfill_areas, double(-max / 2), double(+max / 2)), + // true); + ExPolygons gapfill_areas_collapsed = offset2_ex(gapfill_areas, double(-min / 2), double(+min / 2)); + for (const ExPolygon &ex : gapfill_areas_collapsed) { + //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_(params.flow->nozzle_diameter)*scale_(params.flow->nozzle_diameter) * 2) { + MedialAxis{ ex, params.flow->scaled_width() * 2, params.flow->scaled_width() / 5, coord_t(params.flow->height) }.build(polylines_gapfill); + } + } + if (!polylines_gapfill.empty() && params.role != erBridgeInfill) { + //test +#ifdef _DEBUG + for (ThickPolyline poly : polylines_gapfill) { + for (coordf_t width : poly.width) { + if (width > params.flow->scaled_width() * 2.2) { + std::cerr << "ERRROR!!!! recti gapfill width = " << unscaled(width) << " > max_width = " << (params.flow->width * 2) << "\n"; + } + } + } +#endif + + ExtrusionEntityCollection gap_fill = thin_variable_width(polylines_gapfill, erGapFill, *params.flow); + //set role if needed + if (params.role != erSolidInfill) { + ExtrusionSetRole set_good_role(params.role); + gap_fill.visit(set_good_role); + } + //move them into the collection + if (!gap_fill.entities.empty()) { + ExtrusionEntityCollection *coll_gapfill = new ExtrusionEntityCollection(); + coll_gapfill->no_sort = this->no_sort(); + coll_gapfill->append(std::move(gap_fill.entities)); + coll_out.push_back(coll_gapfill); + } + } +} + } // namespace Slic3r diff --git a/src/libslic3r/Fill/FillRectilinear2.hpp b/src/libslic3r/Fill/FillRectilinear2.hpp index 9b33a6af1..7300d965e 100644 --- a/src/libslic3r/Fill/FillRectilinear2.hpp +++ b/src/libslic3r/Fill/FillRectilinear2.hpp @@ -118,6 +118,7 @@ public: virtual Fill* clone() const { return new FillRectilinear2WGapFill(*this); }; virtual ~FillRectilinear2WGapFill() {} virtual void fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, ExtrusionEntitiesPtr &out) override; + static void split_polygon_gap_fill(const Surface &surface, const FillParams ¶ms, ExPolygons &rectilinear, ExPolygons &gapfill); }; diff --git a/src/libslic3r/Fill/FillSmooth.cpp b/src/libslic3r/Fill/FillSmooth.cpp index c93e0dffc..00b6e03af 100644 --- a/src/libslic3r/Fill/FillSmooth.cpp +++ b/src/libslic3r/Fill/FillSmooth.cpp @@ -18,7 +18,7 @@ namespace Slic3r { return polylines_out; } - void FillSmooth::performSingleFill(const int idx, ExtrusionEntityCollection &eecroot, const Surface &srf_source, + void FillSmooth::perform_single_fill(const int idx, ExtrusionEntityCollection &eecroot, const Surface &srf_source, const FillParams ¶ms, const double volume){ if (srf_source.expolygon.empty()) return; @@ -26,17 +26,23 @@ namespace Slic3r { ExtrusionEntityCollection *eec = new ExtrusionEntityCollection(); eec->no_sort = false; FillParams params_modifided = params; - params_modifided.density *= percentWidth[idx]; + if (params.config != NULL && rolePass[idx] == ExtrusionRole::erTopSolidInfill) params_modifided.density /= (float)params.config->fill_smooth_width.get_abs_value(1); + else params_modifided.density *= (float)percentWidth[idx]; + // reduce flow for each increase in density + params_modifided.flow_mult *= params.density; + params_modifided.flow_mult /= params_modifided.density; + // split the flow between steps + params_modifided.flow_mult *= (float)percentFlow[idx]; if ((params.flow->bridge && idx == 0) || has_overlap[idx]){ - this->fillExPolygon(idx, *eec, srf_source, params_modifided, volume); + this->fill_expolygon(idx, *eec, srf_source, params_modifided, volume); } else{ Surface surfaceNoOverlap(srf_source); for (ExPolygon &poly : this->no_overlap_expolygons) { if (poly.empty()) continue; surfaceNoOverlap.expolygon = poly; - this->fillExPolygon(idx, *eec, surfaceNoOverlap, params_modifided, volume); + this->fill_expolygon(idx, *eec, surfaceNoOverlap, params_modifided, volume); } } @@ -44,7 +50,7 @@ namespace Slic3r { else eecroot.entities.push_back(eec); } - void FillSmooth::fillExPolygon(const int idx, ExtrusionEntityCollection &eec, const Surface &srf_to_fill, + void FillSmooth::fill_expolygon(const int idx, ExtrusionEntityCollection &eec, const Surface &srf_to_fill, const FillParams ¶ms, const double volume){ std::unique_ptr f2 = std::unique_ptr(Fill::new_from_type(fillPattern[idx])); @@ -59,41 +65,35 @@ namespace Slic3r { f2->loop_clipping = this->loop_clipping; Polylines polylines_layer = f2->fill_surface(&srf_to_fill, params); - if (!polylines_layer.empty()){ - /*if (fillPattern[idx] == InfillPattern::ipRectilinear && polylines_layer[0].points.size() > 3){ - polylines_layer[0].points.erase(polylines_layer[0].points.begin()); - polylines_layer[polylines_layer.size() - 1].points.pop_back(); - }*/ + if (!polylines_layer.empty()) { //compute the path of the nozzle double lengthTot = 0; int nbLines = 0; - for (Polyline &pline : polylines_layer){ + for (Polyline &pline : polylines_layer) { Lines lines = pline.lines(); - for (Line &line : lines){ + for (Line &line : lines) { lengthTot += unscaled(line.length()); nbLines++; } } - double extrudedVolume = params.flow->mm3_per_mm() * lengthTot; + double extrudedVolume = params.flow->mm3_per_mm() * lengthTot / params.density; if (extrudedVolume == 0) extrudedVolume = volume; //get the role ExtrusionRole good_role = params.role; if (good_role == erNone || good_role == erCustom) { - good_role = params.flow->bridge && idx==0 ? erBridgeInfill : rolePass[idx]; + good_role = params.flow->bridge && idx == 0 ? erBridgeInfill : rolePass[idx]; } - // print thin + // print + float mult_flow = (params.fill_exactly && idx == 0 ? std::min(2., volume / extrudedVolume) : 1); + std::cout << "mult_flow =" << mult_flow << " \n"; extrusion_entities_append_paths( eec.entities, std::move(polylines_layer), good_role, - params.flow_mult * params.flow->mm3_per_mm() * percentFlow[idx] * - (params.fill_exactly ? std::min(2., volume / extrudedVolume) : 1), + params.flow_mult * params.flow->mm3_per_mm() * mult_flow, //min-reduced flow width for a better view (it's only a gui thing) - (float)(params.flow->width*(percentFlow[idx] < 0.1 ? 0.1 : percentFlow[idx])), (float)params.flow->height); - } - else{ - return; + (float)(params.flow->width * (params.flow_mult* mult_flow < 0.1 ? 0.1 : params.flow_mult * mult_flow)), (float)params.flow->height); } } @@ -118,28 +118,23 @@ namespace Slic3r { //extruded volume: see http://manual.slic3r.org/advanced/flow-math, and we need to remove a circle at an end (as the flow continue) volumeToOccupy += poylineVolume; } - //if (polylines_layer1.empty() && polylines_layer2.empty() && polylines_layer3.empty()) - // return; //create root node ExtrusionEntityCollection *eecroot = new ExtrusionEntityCollection(); //you don't want to sort the extrusions: big infill first, small second eecroot->no_sort = true; - ExtrusionEntityCollection *eec; - - // first infill - performSingleFill(0, *eecroot, *surface, params, volumeToOccupy); + perform_single_fill(0, *eecroot, *surface, params, volumeToOccupy); //second infill if (nbPass > 1){ - performSingleFill(1, *eecroot, *surface, params, volumeToOccupy); + perform_single_fill(1, *eecroot, *surface, params, volumeToOccupy); } // third infill if (nbPass > 2){ - performSingleFill(2, *eecroot, *surface, params, volumeToOccupy); + perform_single_fill(2, *eecroot, *surface, params, volumeToOccupy); } if (!eecroot->entities.empty()) diff --git a/src/libslic3r/Fill/FillSmooth.hpp b/src/libslic3r/Fill/FillSmooth.hpp index af27bb89e..efc982d57 100644 --- a/src/libslic3r/Fill/FillSmooth.hpp +++ b/src/libslic3r/Fill/FillSmooth.hpp @@ -15,17 +15,17 @@ public: anglePass[0] = 0; anglePass[1] = float(M_PI/2); anglePass[2] = 0; - fillPattern[0] = InfillPattern::ipRectilinear; + fillPattern[0] = InfillPattern::ipRectilinearWGapFill; fillPattern[1] = InfillPattern::ipRectilinear; fillPattern[2] = InfillPattern::ipRectilinear; rolePass[0] = erSolidInfill; rolePass[1] = erTopSolidInfill; - rolePass[2] = erSolidInfill; - percentWidth[0] = 0.9; + rolePass[2] = erTopSolidInfill; + percentWidth[0] = 1; percentWidth[1] = 2; percentWidth[2] = 1.0; - percentFlow[0] = 0.7; - percentFlow[1] = 0.3; + percentFlow[0] = 0.8; + percentFlow[1] = 0.2; percentFlow[2] = 0.0; double extrusionMult = 1.0; percentFlow[0] *= extrusionMult; @@ -42,16 +42,22 @@ public: protected: int nbPass=2; + // this parameter is now erased by fill_smooth_width when available. double percentWidth[3]; + // this parameter is now modified by fill_top_flow_ratio when available. double percentFlow[3]; + //angle to add to base angle float anglePass[3]; + //if false, it won't overlap inside the perimeters bool has_overlap[3]; + // profile for base width, speed, etc. ExtrusionRole rolePass[3]; + //fill algorithm to call InfillPattern fillPattern[3]; - void performSingleFill(const int idx, ExtrusionEntityCollection &eecroot, const Surface &srf_source, + void perform_single_fill(const int idx, ExtrusionEntityCollection &eecroot, const Surface &srf_source, const FillParams ¶ms, const double volume); - void fillExPolygon(const int idx, ExtrusionEntityCollection &eec, const Surface &srf_to_fill, + void fill_expolygon(const int idx, ExtrusionEntityCollection &eec, const Surface &srf_to_fill, const FillParams ¶ms, const double volume); }; diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 8524ec160..6d4eeb09f 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -205,7 +205,7 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionInts{ 100 }); - def = this->add("bridge_flow_ratio", coFloat); + def = this->add("bridge_flow_ratio", coFloatOrPercent); def->label = L("Bridge"); def->full_label = L("Bridge flow ratio"); def->category = L("Advanced"); @@ -216,18 +216,18 @@ void PrintConfigDef::init_fff_params() def->min = 0; def->max = 2; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(1)); + def->set_default_value(new ConfigOptionFloatOrPercent(100, true)); - def = this->add("over_bridge_flow_ratio", coFloat); + def = this->add("over_bridge_flow_ratio", coFloatOrPercent); def->label = L("Above the bridges"); def->full_label = L("Above bridge flow ratio"); def->category = L("Advanced"); def->tooltip = L("Flow ratio to compensate for the gaps in a bridged top surface. Used for ironing infill" "pattern to prevent regions where the low-flow pass does not provide a smooth surface due to a lack of plastic." - " You can increase it slightly to pull the top layer at the correct height. Recommended maximum: 1.2."); + " You can increase it slightly to pull the top layer at the correct height. Recommended maximum: 120%."); def->min = 0; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(1)); + def->set_default_value(new ConfigOptionFloatOrPercent(100, true)); def = this->add("bridge_speed", coFloat); def->label = L("Bridges"); @@ -1145,6 +1145,22 @@ void PrintConfigDef::init_fff_params() def->enum_labels.push_back(L("Scattered Rectilinear")); def->set_default_value( new ConfigOptionEnum(ipStars)); + def = this->add("fill_top_flow_ratio", coFloatOrPercent); + def->label = L(" Top fill"); + def->full_label = L("Top fill flow"); + def->tooltip = L("You can increase this to over-extrude on the top layer if there are not enough plastic to makle a fill."); + def->min = 0; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloatOrPercent(100, true)); + + def = this->add("fill_smooth_width", coFloatOrPercent); + def->label = L("width"); + def->full_label = L("Ironing width"); + def->tooltip = L("This is the width of the ironing pass, in a % of the top width, should be no more than 50%."); + def->min = 0; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloatOrPercent(50, true)); + def = this->add("first_layer_acceleration", coFloat); def->label = L("First layer"); def->full_label = L("First layer acceleration"); @@ -3756,14 +3772,6 @@ std::string FullPrintConfig::validate() // --skirt-height if (this->skirt_height < -1) // -1 means as tall as the object return "Invalid value for --skirt-height"; - - // --bridge-flow-ratio - if (this->bridge_flow_ratio <= 0) - return "Invalid value for --bridge-flow-ratio"; - - // --over-bridge-flow-ratio - if (this->over_bridge_flow_ratio <= 0) - return "Invalid value for --over-bridge-flow-ratio"; // extruder clearance if (this->extruder_clearance_radius <= 0) @@ -3824,21 +3832,32 @@ std::string FullPrintConfig::validate() bool out_of_range = false; switch (opt->type()) { case coFloat: - case coPercent: - case coFloatOrPercent: { auto *fopt = static_cast(opt); out_of_range = fopt->value < optdef->min || fopt->value > optdef->max; break; } + case coPercent: + case coFloatOrPercent: + { + auto *fopt = static_cast(opt); + out_of_range = fopt->get_abs_value(1) < optdef->min || fopt->get_abs_value(1) > optdef->max; + break; + } case coFloats: - case coPercents: for (double v : static_cast*>(opt)->values) if (v < optdef->min || v > optdef->max) { out_of_range = true; break; } break; + case coPercents: + for (double v : static_cast*>(opt)->values) + if (v*0.01 < optdef->min || v * 0.01 > optdef->max) { + out_of_range = true; + break; + } + break; case coInt: { auto *iopt = static_cast(opt); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index b7f0847b1..e4bd57a6c 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -571,8 +571,8 @@ class PrintRegionConfig : public StaticPrintConfig public: ConfigOptionFloat bridge_angle; ConfigOptionInt bottom_solid_layers; - ConfigOptionFloat bridge_flow_ratio; - ConfigOptionFloat over_bridge_flow_ratio; + ConfigOptionFloatOrPercent bridge_flow_ratio; + ConfigOptionFloatOrPercent over_bridge_flow_ratio; ConfigOptionEnum bottom_fill_pattern; ConfigOptionFloatOrPercent bridged_infill_margin; ConfigOptionFloat bridge_speed; @@ -591,6 +591,8 @@ public: ConfigOptionFloat fill_angle; ConfigOptionPercent fill_density; ConfigOptionEnum fill_pattern; + ConfigOptionFloatOrPercent fill_top_flow_ratio; + ConfigOptionFloatOrPercent fill_smooth_width; ConfigOptionBool gap_fill; ConfigOptionFloatOrPercent gap_fill_min_area; ConfigOptionFloat gap_fill_speed; @@ -655,6 +657,8 @@ protected: OPT_PTR(fill_angle); OPT_PTR(fill_density); OPT_PTR(fill_pattern); + OPT_PTR(fill_top_flow_ratio); + OPT_PTR(fill_smooth_width); OPT_PTR(gap_fill); OPT_PTR(gap_fill_min_area); OPT_PTR(gap_fill_speed); diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 4aa23561b..af08f00b2 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -558,6 +558,8 @@ bool PrintObject::invalidate_state_by_config_options(const std::vectorregions()[region_id]; // skip over-bridging in case there are no modification - if (region.config().over_bridge_flow_ratio.value == 1) continue; + if (region.config().over_bridge_flow_ratio.get_abs_value(1) == 1) continue; for (LayerPtrs::iterator layer_it = m_layers.begin(); layer_it != m_layers.end(); ++layer_it) { // skip first layer diff --git a/src/libslic3r/PrintRegion.cpp b/src/libslic3r/PrintRegion.cpp index b3ac6a4a5..cfc62a311 100644 --- a/src/libslic3r/PrintRegion.cpp +++ b/src/libslic3r/PrintRegion.cpp @@ -50,7 +50,7 @@ Flow PrintRegion::flow(FlowRole role, double layer_height, bool bridge, bool fir // Get the configured nozzle_diameter for the extruder associated to the flow role requested. // Here this->extruder(role) - 1 may underflow to MAX_INT, but then the get_at() will follback to zero'th element, so everything is all right. double nozzle_diameter = m_print->config().nozzle_diameter.get_at(this->extruder(role) - 1); - return Flow::new_from_config_width(role, config_width, (float)nozzle_diameter, (float)layer_height, bridge ? (float)m_config.bridge_flow_ratio : 0.0f); + return Flow::new_from_config_width(role, config_width, (float)nozzle_diameter, (float)layer_height, bridge ? (float)m_config.bridge_flow_ratio.get_abs_value(1) : 0.0f); } coordf_t PrintRegion::nozzle_dmr_avg(const PrintConfig &print_config) const @@ -62,7 +62,7 @@ coordf_t PrintRegion::nozzle_dmr_avg(const PrintConfig &print_config) const coordf_t PrintRegion::bridging_height_avg(const PrintConfig &print_config) const { - return this->nozzle_dmr_avg(print_config) * sqrt(m_config.bridge_flow_ratio.value); + return this->nozzle_dmr_avg(print_config) * sqrt(m_config.bridge_flow_ratio.get_abs_value(1)); } void PrintRegion::collect_object_printing_extruders(const PrintConfig &print_config, const PrintRegionConfig ®ion_config, std::vector &object_extruders) diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 48335fcb2..c9b9a9a68 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -279,6 +279,9 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) // gap fill can appear in infill //toggle_field("gap_fill_speed", have_perimeters && config->opt_bool("gap_fill")); + for (auto el : {"fill_smooth_width" }) + toggle_field(el, config->opt_enum("top_fill_pattern") == InfillPattern::ipSmooth); + bool have_top_solid_infill = config->opt_int("top_solid_layers") > 0; for (auto el : { "top_infill_extrusion_width", "top_solid_infill_speed" }) toggle_field(el, have_top_solid_infill); diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index 9db11767a..af633c12f 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -382,6 +382,8 @@ const std::vector& Preset::print_options() "extra_perimeters", "only_one_perimeter_top", "ensure_vertical_shell_thickness", "avoid_crossing_perimeters", "thin_walls", "overhangs", "seam_position", "external_perimeters_first", "fill_density" , "fill_pattern" + , "fill_top_flow_ratio" + , "fill_smooth_width" , "top_fill_pattern" , "bottom_fill_pattern" , "solid_fill_pattern", diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index ec19031c9..ccfb103ff 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1125,9 +1125,9 @@ void TabPrint::build() line.append_option(optgroup->get_option("infill_dense_algo")); optgroup->append_line(line); - optgroup = page->new_optgroup(_(L("Advanced"))); - optgroup->append_single_option_line("solid_infill_every_layers"); - optgroup->append_single_option_line("solid_infill_below_area"); + optgroup = page->new_optgroup(_(L("Advanced"))); + optgroup->append_single_option_line("solid_infill_every_layers"); + optgroup->append_single_option_line("solid_infill_below_area"); line = { _(L("Angle")), "" }; line.append_option(optgroup->get_option("fill_angle")); line.append_option(optgroup->get_option("bridge_angle")); @@ -1136,8 +1136,13 @@ void TabPrint::build() line.append_option(optgroup->get_option("external_infill_margin")); line.append_option(optgroup->get_option("bridged_infill_margin")); optgroup->append_line(line); - optgroup->append_single_option_line("only_retract_when_crossing_perimeters"); + optgroup->append_single_option_line("only_retract_when_crossing_perimeters"); optgroup->append_single_option_line("infill_first"); + line = { _(L("Ironing tuning")), "" }; + + optgroup = page->new_optgroup(_(L("Advanced Infill"))); + line.append_option(optgroup->get_option("fill_smooth_width")); + optgroup->append_line(line); page = add_options_page(_(L("Skirt and brim")), "skirt+brim"); optgroup = page->new_optgroup(_(L("Skirt"))); @@ -1229,24 +1234,25 @@ void TabPrint::build() optgroup->append_single_option_line("max_volumetric_extrusion_rate_slope_negative"); #endif /* HAS_PRESSURE_EQUALIZER */ - page = add_options_page(_(L("Width & flow")), "width"); - optgroup = page->new_optgroup(_(L("Extrusion width"))); - optgroup->append_single_option_line("extrusion_width"); - optgroup->append_single_option_line("first_layer_extrusion_width"); - optgroup->append_single_option_line("perimeter_extrusion_width"); - optgroup->append_single_option_line("external_perimeter_extrusion_width"); - optgroup->append_single_option_line("infill_extrusion_width"); - optgroup->append_single_option_line("solid_infill_extrusion_width"); - optgroup->append_single_option_line("top_infill_extrusion_width"); - optgroup->append_single_option_line("support_material_extrusion_width"); + page = add_options_page(_(L("Width & flow")), "width"); + optgroup = page->new_optgroup(_(L("Extrusion width"))); + optgroup->append_single_option_line("extrusion_width"); + optgroup->append_single_option_line("first_layer_extrusion_width"); + optgroup->append_single_option_line("perimeter_extrusion_width"); + optgroup->append_single_option_line("external_perimeter_extrusion_width"); + optgroup->append_single_option_line("infill_extrusion_width"); + optgroup->append_single_option_line("solid_infill_extrusion_width"); + optgroup->append_single_option_line("top_infill_extrusion_width"); + optgroup->append_single_option_line("support_material_extrusion_width"); - optgroup = page->new_optgroup(_(L("Overlap"))); - optgroup->append_single_option_line("infill_overlap"); + optgroup = page->new_optgroup(_(L("Overlap"))); + optgroup->append_single_option_line("infill_overlap"); optgroup = page->new_optgroup(_(L("Flow"))); line = { _(L("Flow ratio")), "" }; line.append_option(optgroup->get_option("bridge_flow_ratio")); line.append_option(optgroup->get_option("over_bridge_flow_ratio")); + line.append_option(optgroup->get_option("fill_top_flow_ratio")); optgroup->append_line(line); page = add_options_page(_(L("Multiple extruders")), "funnel"); diff --git a/src/test/libslic3r/test_thin.cpp b/src/test/libslic3r/test_thin.cpp index 7a9cf8c39..ab32db5ff 100644 --- a/src/test/libslic3r/test_thin.cpp +++ b/src/test/libslic3r/test_thin.cpp @@ -310,7 +310,7 @@ SCENARIO("thin walls: ") REQUIRE(std::abs(max_width - nozzle_diam) > SCALED_EPSILON); } //compute the length of the tapers - THEN("medial axis has a 45° taper and a shorter one") { + THEN("medial axis has a 45� taper and a shorter one") { int l1 = 0; for (size_t idx = 0; idx < res[0].width.size() - 1 && res[0].width[idx] - scale_(1.2) < SCALED_EPSILON; ++idx) l1 += res[0].lines()[idx].length(); @@ -328,7 +328,7 @@ SCENARIO("thin walls: ") } - GIVEN("1° rotated tooths") + GIVEN("1� rotated tooths") { }