add parameters: fill_top_flow_ratio & fill_smooth_width

bugfix flow inaccuracies in FillSmooth.
TODO: do something about surface too small to be printed, particularly when 'only one perimeter top' -> don't extract them or use gapfill
This commit is contained in:
supermerill 2019-10-07 18:31:51 +02:00
parent b05618c883
commit 89b2e62381
18 changed files with 227 additions and 230 deletions

View File

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

View File

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

View File

@ -1734,7 +1734,11 @@ public:
int opt_int(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast<const ConfigOptionInts*>(this->option(opt_key))->get_at(idx); }
template<typename ENUM>
ENUM opt_enum(const t_config_option_key &opt_key) const { return (ENUM)dynamic_cast<const ConfigOptionEnumGeneric*>(this->option(opt_key))->value; }
ENUM opt_enum(const t_config_option_key &opt_key) const {
auto v1 = this->option<ConfigOptionEnumGeneric>(opt_key);
auto v2 = this->option<ConfigOptionEnum<ENUM>>(opt_key);
return v1==nullptr? v2->value : (ENUM)v1->value;
}
bool opt_bool(const t_config_option_key &opt_key) const { return this->option<ConfigOptionBool>(opt_key)->value != 0; }
bool opt_bool(const t_config_option_key &opt_key, unsigned int idx) const { return this->option<ConfigOptionBools>(opt_key)->get_at(idx) != 0; }

View File

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

View File

@ -214,7 +214,7 @@ void Fill::fill_surface_extrusion(const Surface *surface, const FillParams &para
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());

View File

@ -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<FillParams>::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 &params);
void do_gap_fill(const ExPolygons &gapfill_areas, const FillParams &params, ExtrusionEntitiesPtr &coll_out);
ExtrusionRole getRoleFromSurfaceType(const FillParams &params, const Surface *surface){
if (params.role == erNone || params.role == erCustom) {
return params.flow->bridge ?

View File

@ -1767,22 +1767,39 @@ FillRectilinearSawtooth::fill_surface_extrusion(const Surface *surface, const Fi
}
void
FillRectilinear2WGapFill::fill_surface_extrusion(const Surface *surface, const FillParams &params, 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 &params, 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 &params, 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,12 +1872,29 @@ FillRectilinear2WGapFill::fill_surface_extrusion(const Surface *surface, const F
//gapfill
if (gapfill_areas.size() > 0) {
FillParams params2{ params };
params2.role = good_role;
do_gap_fill(gapfill_areas, params2, coll_nosort->entities);
}
// === end ===
if (!coll_nosort->empty()) {
out.push_back(coll_nosort);
} else {
delete coll_nosort;
}
}
void
Fill::do_gap_fill(const ExPolygons &gapfill_areas, const FillParams &params, 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()));
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)),
@ -1873,20 +1907,22 @@ FillRectilinear2WGapFill::fill_surface_extrusion(const Surface *surface, const F
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) {
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::cout << "ERRROR!!!! recti gapfill width = " << unscaled(width) << " > max_width = " << (params.flow->width * 2) << "\n";
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 (good_role != erSolidInfill) {
ExtrusionSetRole set_good_role(good_role);
if (params.role != erSolidInfill) {
ExtrusionSetRole set_good_role(params.role);
gap_fill.visit(set_good_role);
}
//move them into the collection
@ -1894,18 +1930,9 @@ FillRectilinear2WGapFill::fill_surface_extrusion(const Surface *surface, const F
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);
coll_out.push_back(coll_gapfill);
}
}
}
// === end ===
if (!coll_nosort->empty()) {
out.push_back(coll_nosort);
} else {
delete coll_nosort;
}
}

View File

@ -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 &params, ExtrusionEntitiesPtr &out) override;
static void split_polygon_gap_fill(const Surface &surface, const FillParams &params, ExPolygons &rectilinear, ExPolygons &gapfill);
};

View File

@ -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 &params, 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 &params, const double volume){
std::unique_ptr<Fill> f2 = std::unique_ptr<Fill>(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())

View File

@ -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 &params, 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 &params, const double volume);
};

View File

@ -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<InfillPattern>(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");
@ -3757,14 +3773,6 @@ std::string FullPrintConfig::validate()
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)
return "Invalid value for --extruder-clearance-radius";
@ -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<const ConfigOptionFloat*>(opt);
out_of_range = fopt->value < optdef->min || fopt->value > optdef->max;
break;
}
case coPercent:
case coFloatOrPercent:
{
auto *fopt = static_cast<const ConfigOptionPercent*>(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<const ConfigOptionVector<double>*>(opt)->values)
if (v < optdef->min || v > optdef->max) {
out_of_range = true;
break;
}
break;
case coPercents:
for (double v : static_cast<const ConfigOptionVector<double>*>(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<const ConfigOptionInt*>(opt);

View File

@ -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<InfillPattern> bottom_fill_pattern;
ConfigOptionFloatOrPercent bridged_infill_margin;
ConfigOptionFloat bridge_speed;
@ -591,6 +591,8 @@ public:
ConfigOptionFloat fill_angle;
ConfigOptionPercent fill_density;
ConfigOptionEnum<InfillPattern> 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);

View File

@ -558,6 +558,8 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector<t_config_
|| opt_key == "enforce_full_fill_volume"
|| opt_key == "fill_angle"
|| opt_key == "fill_pattern"
|| opt_key == "fill_top_flow_ratio"
|| opt_key == "fill_smooth_width"
|| opt_key == "top_infill_extrusion_width"
|| opt_key == "first_layer_extrusion_width") {
steps.emplace_back(posInfill);
@ -1683,7 +1685,7 @@ PrintObject::replaceSurfaceType(SurfaceType st_to_replace, SurfaceType st_replac
const PrintRegion &region = *m_print->regions()[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

View File

@ -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 &region_config, std::vector<unsigned int> &object_extruders)

View File

@ -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<InfillPattern>("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);

View File

@ -382,6 +382,8 @@ const std::vector<std::string>& 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",

View File

@ -1138,6 +1138,11 @@ void TabPrint::build()
optgroup->append_line(line);
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")));
@ -1247,6 +1252,7 @@ void TabPrint::build()
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");

View File

@ -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<EFBFBD> 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<EFBFBD> rotated tooths")
{
}