#4 perimeter overlaps : total control over perimeter width vs spacing.

- add a spacing_ratio in flow, but it's only sed for two spacing in perimeter_generator, not sure about the usefulness of it.
 - external_perimeter_overlap now use the spacing_ratio to compute
 - add perimeter_overlap, using the spacing_ratio to compute
 - add perimeter_bonding, that shrink the external-internal spacing, without growing the infill polygons.
This commit is contained in:
supermerill 2020-06-11 12:19:06 +02:00
parent 498c48580a
commit bbbb4d9396
9 changed files with 96 additions and 37 deletions

View File

@ -54,16 +54,18 @@ group:Advanced
setting:seam_position
setting:seam_travel
end_line
line:External Perimeter
setting:external_perimeters_first
setting:external_perimeters_vase
setting:external_perimeters_nothole
setting:external_perimeters_hole
end_line
line:Looping perimeter
setting:perimeter_loop
setting:perimeter_loop_seam
end_line
group: External perimeter first
setting:label$Activate:external_perimeters_first
line:Apply on
setting:external_perimeters_nothole
setting:external_perimeters_hole
end_line
setting:external_perimeters_vase
setting:perimeter_bonding
page:Slicing:layers
group:Layer height
@ -230,9 +232,12 @@ group:Extrusion width
setting:top_infill_extrusion_width
setting:support_material_extrusion_width
group:Overlap
line:Perimeter overlap
setting:label$External:external_perimeter_overlap
setting:label$Inner:perimeter_overlap
end_line
setting:infill_overlap
setting:bridge_overlap
setting:external_perimeter_overlap
group:Flow
line:Flow ratio
setting:bridge_flow_ratio

View File

@ -172,7 +172,7 @@ float Flow::spacing() const
float min_flow_spacing = this->width - this->height * (1. - 0.25 * PI);
float res = this->width - PERIMETER_LINE_OVERLAP_FACTOR * (this->width - min_flow_spacing);
#else
float res = float(this->bridge ? (this->width + BRIDGE_EXTRA_SPACING_MULT * nozzle_diameter) : (this->width - this->height * (1. - 0.25 * PI)));
float res = float(this->bridge ? (this->width + BRIDGE_EXTRA_SPACING_MULT * nozzle_diameter) : (this->width - this->height * (1. - 0.25 * PI) * spacing_ratio));
#endif
// assert(res > 0.f);
if (res <= 0.f)

View File

@ -65,6 +65,8 @@ public:
float nozzle_diameter;
// Is it a bridge?
bool bridge;
// % of spacing taken into account 1=>all/default, 0=> width=spacing
float spacing_ratio = 1;
Flow(float _w, float _h, float _nd, bool _bridge = false) :
width(_w), height(_h), nozzle_diameter(_nd), bridge(_bridge) {}

View File

@ -37,6 +37,10 @@ namespace Slic3r {
void PerimeterGenerator::process()
{
//set spacing
this->perimeter_flow.spacing_ratio = this->object_config->perimeter_overlap.get_abs_value(1);
this->ext_perimeter_flow.spacing_ratio = this->object_config->external_perimeter_overlap.get_abs_value(1);
// other perimeters
this->_mm3_per_mm = this->perimeter_flow.mm3_per_mm();
coord_t perimeter_width = this->perimeter_flow.scaled_width();
@ -50,23 +54,31 @@ void PerimeterGenerator::process()
coord_t ext_perimeter_spacing = this->ext_perimeter_flow.scaled_spacing();
//spacing between external perimeter and the second
coord_t ext_perimeter_spacing2 = this->ext_perimeter_flow.scaled_spacing(this->perimeter_flow);
//external_perimeter_overlap effect: change distance between the extrenal periemter and the other ones.
if (this->config->external_perimeter_overlap.get_abs_value(1) != 1) {
//choose between the normal spacing and "don't touch it".
ext_perimeter_spacing2 =
ext_perimeter_spacing2 * this->config->external_perimeter_overlap.get_abs_value(1)
+ (ext_perimeter_width + perimeter_width) * 0.5f * (1 - this->config->external_perimeter_overlap.get_abs_value(1));
}
// overhang perimeters
this->_mm3_per_mm_overhang = this->overhang_flow.mm3_per_mm();
this->_mm3_per_mm_overhang = this->overhang_flow.mm3_per_mm();
// solid infill
coord_t solid_infill_spacing = this->solid_infill_flow.scaled_spacing();
coord_t solid_infill_spacing = this->solid_infill_flow.scaled_spacing();
//infill / perimeter
coord_t infill_peri_overlap = (coord_t)scale_(this->config->get_abs_value("infill_overlap", unscale<coordf_t>(perimeter_spacing + solid_infill_spacing) / 2));
// infill gap to add vs periemter (useful if using perimeter bonding)
coord_t infill_gap = 0;
// nozzle diameter
const double nozzle_diameter = this->print_config->nozzle_diameter.get_at(this->config->perimeter_extruder - 1);
// perimeter conding set.
if (this->perimeter_flow.spacing_ratio == 1
&& this->ext_perimeter_flow.spacing_ratio == 1
&& this->config->external_perimeters_first
&& this->object_config->perimeter_bonding.value > 0) {
infill_gap = (1 - this->object_config->perimeter_bonding.get_abs_value(1)) * ext_perimeter_spacing;
ext_perimeter_spacing2 -= infill_gap;
}
// Calculate the minimum required spacing between two adjacent traces.
// This should be equal to the nominal flow spacing but we experiment
// with some tolerance in order to avoid triggering medial axis when
@ -88,7 +100,7 @@ void PerimeterGenerator::process()
this->_lower_slices_p = offset(*this->lower_slices, double(scale_(config->overhangs_width.get_abs_value(nozzle_diameter))));
}
// have to grown the periemters if mill post-process
// have to grown the perimeters if mill post-process
MillingPostProcess miller(this->slices, this->lower_slices, config, object_config, print_config);
bool have_to_grow_for_miller = miller.can_be_milled(layer) && config->milling_extra_size.get_abs_value(1) > 0;
ExPolygons unmillable;
@ -218,7 +230,6 @@ void PerimeterGenerator::process()
//it's not dangerous as it will be intersected by 'unsupported' later
//FIXME: add overlap in this->fill_surfaces->append
//FIXME: it overlap inside unsuppported not-bridgeable area!
double overlap = scale_(this->config->get_abs_value("infill_overlap", unscale<double>(perimeter_spacing)));
//bridgeable_simplified = offset2_ex(bridgeable_simplified, (double)-perimeter_spacing, (double)perimeter_spacing * 2);
//ExPolygons unbridgeable = offset_ex(diff_ex(unsupported, bridgeable_simplified), perimeter_spacing * 3 / 2);
@ -391,7 +402,7 @@ void PerimeterGenerator::process()
if ( this->config->extra_perimeters_overhangs && !last.empty() && !overhangs_unsupported.empty()) {
overhangs_unsupported = intersection_ex(overhangs_unsupported, last, true);
if (overhangs_unsupported.size() > 0) {
//please don't stop adding periemter yet.
//please don't stop adding perimeter yet.
has_overhang = true;
}
}
@ -456,9 +467,9 @@ void PerimeterGenerator::process()
ExPolygons thin = offset_ex(half_thin, double(min_width / 2));
assert(thin.size() <= 1);
if (thin.empty()) continue;
coord_t overlap = (coord_t)scale_(this->config->thin_walls_overlap.get_abs_value(this->ext_perimeter_flow.nozzle_diameter));
coord_t thin_walls_overlap = (coord_t)scale_(this->config->thin_walls_overlap.get_abs_value(this->ext_perimeter_flow.nozzle_diameter));
ExPolygons anchor = intersection_ex(offset_ex(half_thin, double(min_width / 2) +
(float)(overlap), jtSquare), no_thin_zone, true);
(float)(thin_walls_overlap), jtSquare), no_thin_zone, true);
ExPolygons bounds = union_ex(thin, anchor, true);
for (ExPolygon &bound : bounds) {
if (!intersection_ex(thin[0], bound).empty()) {
@ -472,7 +483,7 @@ void PerimeterGenerator::process()
min_width, coord_t(this->layer->height) };
ma.use_bounds(bound)
.use_min_real_width((coord_t)scale_(this->ext_perimeter_flow.nozzle_diameter))
.use_tapers(overlap)
.use_tapers(thin_walls_overlap)
.build(thin_walls);
}
break;
@ -818,7 +829,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.
//TODO: if a gapfill extrusion is a loop and with width always >= perimeter 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)
@ -832,9 +843,8 @@ void PerimeterGenerator::process()
// two or more loops?
perimeter_spacing / 2;
// only apply infill overlap if we actually have one perimeter
coord_t overlap = 0;
if (inset > 0) {
overlap = (coord_t)scale_(this->config->get_abs_value("infill_overlap", unscale<coordf_t>(inset + solid_infill_spacing / 2)));
if (inset == 0) {
infill_peri_overlap = 0;
}
// simplify infill contours according to resolution
Polygons not_filled_p;
@ -846,14 +856,14 @@ void PerimeterGenerator::process()
// append infill areas to fill_surfaces
//auto it_surf = this->fill_surfaces->surfaces.end();
ExPolygons infill_exp = offset2_ex(not_filled_exp,
-inset - min_perimeter_infill_spacing / 2 + overlap,
-inset - min_perimeter_infill_spacing / 2 + infill_peri_overlap - infill_gap,
(float)min_perimeter_infill_spacing / 2);
this->fill_surfaces->append(infill_exp, stPosInternal | stDensSparse);
if (overlap != 0) {
if (infill_peri_overlap != 0) {
ExPolygons polyWithoutOverlap = offset2_ex(
not_filled_exp,
-inset - min_perimeter_infill_spacing / 2,
-inset - infill_gap - min_perimeter_infill_spacing / 2,
(float) min_perimeter_infill_spacing / 2);
this->fill_no_overlap.insert(this->fill_no_overlap.end(), polyWithoutOverlap.begin(), polyWithoutOverlap.end());
}

View File

@ -729,12 +729,45 @@ void PrintConfigDef::init_fff_params()
def->label = L("external perimeter overlap");
def->full_label = L("Ext. peri. overlap");
def->category = OptionCategory::width;
def->tooltip = L("This perimeter allow you to reduce the overlap between the perimeters and the external one, to reduce the impact of the perimeters artifacts."
def->tooltip = L("This setting allow you to reduce the overlap between the perimeters and the external one, to reduce the impact of the perimeters artifacts."
" 100% means that no gaps is left, and 0% means that the external perimeter isn't contributing to the overlap with the 'inner' one."
"\nIt's very experimental, please report about the usefulness. It may be removed if there is no use of it.");
def->sidetext = L("%");
def->min = 0;
def->max = 100;
def->mode = comExpert;
def->set_default_value(new ConfigOptionPercent(100));
def = this->add("perimeter_overlap", coPercent);
def->label = L("perimeter overlap");
def->full_label = L("Perimeter overlap");
def->category = OptionCategory::width;
def->tooltip = L("This setting allow you to reduce the overlap between the perimeters, to reduce the impact of the perimeters artifacts."
" 100% means that no gaps is left, and 0% means that perimeters are not touching each other anymore."
"\nIt's very experimental, please report about the usefulness. It may be removed if there is no use for it.");
def->sidetext = L("%");
def->min = 0;
def->max = 100;
def->mode = comExpert;
def->set_default_value(new ConfigOptionPercent(100));
def = this->add("perimeter_bonding", coPercent);
def->label = L("Better bonding");
def->full_label = L("Perimeter bonding");
def->category = OptionCategory::perimeter;
def->tooltip = L("This setting may degrad a bit the quality of your external perimeter, in exchange for a better bonding between perimeters."
"Use it if you have great difficulties with perimeter bonding, for example with high temperature filaments."
"\nThis percentage is the % of overlap between perimeters, a bit like perimeter_overlap and external_perimeter_overlap, but in reverse."
" You have to set perimeter_overlap and external_perimeter_overlap to 100%, or this setting has no effect."
" 0: no effect, 50%: half of the nozzle will be over an already extruded perimeter while extruding a new one"
", unless it's an external ones)."
"\nIt's very experimental, please report about the usefulness. It may be removed if there is no use for it.");
def->sidetext = L("%");
def->min = 0;
def->max = 50;
def->mode = comExpert;
def->set_default_value(new ConfigOptionPercent(0));
def = this->add("external_perimeter_speed", coFloatOrPercent);
def->label = L("External");
def->full_label = L("External perimeters speed");
@ -2022,7 +2055,7 @@ void PrintConfigDef::init_fff_params()
def->label = L("minimum top width for infill");
def->category = OptionCategory::speed;
def->tooltip = L("If a top surface has to be printed and it's partially covered by an other layer, it won't be considered at a top layer where his width is below this value."
" This can be useful to not let the 'one perimeter on top' trigger on surface that should be covered only by periemters."
" This can be useful to not let the 'one perimeter on top' trigger on surface that should be covered only by perimeters."
" This value can be a mm or a % of the perimeter extrusion width.");
def->sidetext = L("mm or %");
def->ratio_over = "perimeter_extrusion_width";

View File

@ -494,6 +494,7 @@ public:
ConfigOptionBool dont_support_bridges;
ConfigOptionPercent external_perimeter_cut_corners;
ConfigOptionBool exact_last_layer_height;
ConfigOptionPercent external_perimeter_overlap;
ConfigOptionFloatOrPercent extrusion_width;
ConfigOptionFloatOrPercent first_layer_height;
ConfigOptionFloat first_layer_size_compensation;
@ -503,6 +504,8 @@ public:
ConfigOptionBool interface_shells;
ConfigOptionFloat layer_height;
ConfigOptionFloat model_precision;
ConfigOptionPercent perimeter_bonding;
ConfigOptionPercent perimeter_overlap;
ConfigOptionInt raft_layers;
ConfigOptionEnum<SeamPosition> seam_position;
ConfigOptionBool seam_travel;
@ -555,6 +558,7 @@ protected:
OPT_PTR(dont_support_bridges);
OPT_PTR(external_perimeter_cut_corners);
OPT_PTR(exact_last_layer_height);
OPT_PTR(external_perimeter_overlap);
OPT_PTR(extrusion_width);
OPT_PTR(hole_size_compensation);
OPT_PTR(first_layer_height);
@ -563,6 +567,8 @@ protected:
OPT_PTR(interface_shells);
OPT_PTR(layer_height);
OPT_PTR(model_precision);
OPT_PTR(perimeter_bonding);
OPT_PTR(perimeter_overlap);
OPT_PTR(raft_layers);
OPT_PTR(seam_position);
OPT_PTR(seam_travel);
@ -621,7 +627,6 @@ public:
ConfigOptionBool enforce_full_fill_volume;
ConfigOptionFloatOrPercent external_infill_margin;
ConfigOptionFloatOrPercent external_perimeter_extrusion_width;
ConfigOptionPercent external_perimeter_overlap;
ConfigOptionFloatOrPercent external_perimeter_speed;
ConfigOptionBool external_perimeters_first;
ConfigOptionBool external_perimeters_vase;
@ -709,7 +714,6 @@ protected:
OPT_PTR(enforce_full_fill_volume);
OPT_PTR(external_infill_margin);
OPT_PTR(external_perimeter_extrusion_width);
OPT_PTR(external_perimeter_overlap);
OPT_PTR(external_perimeter_speed);
OPT_PTR(external_perimeters_first);
OPT_PTR(external_perimeters_vase);

View File

@ -305,7 +305,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
toggle_field("overhangs_reverse_threshold", config->opt_bool("overhangs_reverse"));
toggle_field("min_width_top_surface", config->opt_bool("only_one_perimeter_top"));
for (auto el : { "external_perimeters_vase", "external_perimeters_nothole", "external_perimeters_hole"})
for (auto el : { "external_perimeters_vase", "external_perimeters_nothole", "external_perimeters_hole", "perimeter_bonding"})
toggle_field(el, config->opt_bool("external_perimeters_first"));
for (auto el : { "thin_walls_min_width", "thin_walls_overlap" })

View File

@ -536,6 +536,8 @@ const std::vector<std::string>& Preset::print_options()
"print_extrusion_multiplier",
"external_perimeter_cut_corners",
"external_perimeter_overlap",
"perimeter_bonding",
"perimeter_overlap",
"milling_after_z",
"milling_post_process",
"milling_extra_size",

View File

@ -319,6 +319,9 @@ std::string PresetHints::recommended_thin_wall_thickness(const PresetBundle &pre
*print_config.opt<ConfigOptionFloatOrPercent>("perimeter_extrusion_width"),
nozzle_diameter, layer_height, false);
//set spacing
external_perimeter_flow.spacing_ratio = print_config.opt<ConfigOptionPercent>("external_perimeter_overlap")->get_abs_value(1);
perimeter_flow.spacing_ratio = print_config.opt<ConfigOptionPercent>("perimeter_overlap")->get_abs_value(1);
if (num_perimeters > 0) {
int num_lines = std::min(num_perimeters, 6);