From fbd05d83e0cc2a969df92c81ab4a0a2d238041ed Mon Sep 17 00:00:00 2001 From: supermerill Date: Sun, 24 Jul 2022 23:52:31 +0200 Subject: [PATCH] Add a way to deactivate the anti-hysteresis check for perimeters. supermerill/SuperSlicer#2967 --- src/libslic3r/PerimeterGenerator.cpp | 111 ++++++++++++++------------ src/libslic3r/PrintConfig.cpp | 8 +- src/slic3r/GUI/ConfigManipulation.cpp | 2 +- 3 files changed, 68 insertions(+), 53 deletions(-) diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index d98646445f6..609e9150456 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -514,9 +514,17 @@ void PerimeterGenerator::process() } // allow this perimeter to overlap itself? - float thin_perimeter = perimeter_idx == 0 ? this->config->thin_perimeters.get_abs_value(1) : (this->config->thin_perimeters.get_abs_value(1)==0 ? 0 : this->config->thin_perimeters_all.get_abs_value(1)); - if (thin_perimeter < 0.02) // can create artifacts + float thin_perimeter = this->config->thin_perimeters.get_abs_value(1); + if (perimeter_idx > 0 && thin_perimeter != 0) { + thin_perimeter = this->config->thin_perimeters_all.get_abs_value(1); + } + bool allow_perimeter_anti_hysteresis = thin_perimeter >= 0; + if (thin_perimeter < 0) { + thin_perimeter = -thin_perimeter; + } + if (thin_perimeter < 0.02) { // can create artifacts thin_perimeter = 0; + } // Calculate next onion shell of perimeters. //this variable stored the next onion @@ -525,13 +533,13 @@ void PerimeterGenerator::process() // compute next onion // the minimum thickness of a single loop is: // ext_width/2 + ext_spacing/2 + spacing/2 + width/2 - if (thin_perimeter > 0.98) + if (thin_perimeter > 0.98) { next_onion = offset_ex( last, -(float)(ext_perimeter_width / 2), ClipperLib::JoinType::jtMiter, 3); - else if (thin_perimeter > 0.01) { + } else if (thin_perimeter > 0.01) { next_onion = offset2_ex( last, -(float)(ext_perimeter_width / 2 + (1 - thin_perimeter) * ext_perimeter_spacing / 2 - 1), @@ -560,19 +568,21 @@ void PerimeterGenerator::process() // look for thin walls if (this->config->thin_walls) { // detect edge case where a curve can be split in multiple small chunks. - std::vector divs = { 2.1f, 1.9f, 2.2f, 1.75f, 1.5f }; //don't go too far, it's not possible to print thin wall after that - size_t idx_div = 0; - while (next_onion.size() > last.size() && idx_div < divs.size()) { - float div = divs[idx_div]; - //use a sightly bigger spacing to try to drastically improve the split, that can lead to very thick gapfill - ExPolygons next_onion_secondTry = offset2_ex( - last, - -(float)((ext_perimeter_width / 2) + (ext_perimeter_spacing / div) - 1), - +(float)((ext_perimeter_spacing / div) - 1)); - if (next_onion.size() > next_onion_secondTry.size() * 1.2 && next_onion.size() > next_onion_secondTry.size() + 2) { - next_onion = next_onion_secondTry; + if (allow_perimeter_anti_hysteresis) { + std::vector divs = { 2.1f, 1.9f, 2.2f, 1.75f, 1.5f }; //don't go too far, it's not possible to print thin wall after that + size_t idx_div = 0; + while (next_onion.size() > last.size() && idx_div < divs.size()) { + float div = divs[idx_div]; + //use a sightly bigger spacing to try to drastically improve the split, that can lead to very thick gapfill + ExPolygons next_onion_secondTry = offset2_ex( + last, + -(float)((ext_perimeter_width / 2) + (ext_perimeter_spacing / div) - 1), + +(float)((ext_perimeter_spacing / div) - 1)); + if (next_onion.size() > next_onion_secondTry.size() * 1.2 && next_onion.size() > next_onion_secondTry.size() + 2) { + next_onion = next_onion_secondTry; + } + idx_div++; } - idx_div++; } // the following offset2 ensures almost nothing in @thin_walls is narrower than $min_width @@ -674,46 +684,47 @@ void PerimeterGenerator::process() +(float)((1 - thin_perimeter) * perimeter_spacing / 2 - 1), (round_peri ? ClipperLib::JoinType::jtRound : ClipperLib::JoinType::jtMiter), (round_peri ? min_round_spacing : 3)); - // now try with different min spacing if we fear some hysteresis - //TODO, do that for each polygon from last, instead to do for all of them in one go. - ExPolygons no_thin_onion = offset_ex(last, double(-good_spacing)); - if (last_area < 0) { - last_area = 0; - for (const ExPolygon& expoly : last) { - last_area += expoly.area(); + if (allow_perimeter_anti_hysteresis) { + // now try with different min spacing if we fear some hysteresis + //TODO, do that for each polygon from last, instead to do for all of them in one go. + ExPolygons no_thin_onion = offset_ex(last, double(-good_spacing)); + if (last_area < 0) { + last_area = 0; + for (const ExPolygon& expoly : last) { + last_area += expoly.area(); + } + } + double new_area = 0; + for (const ExPolygon& expoly : next_onion) { + new_area += expoly.area(); } - } - double new_area = 0; - for (const ExPolygon& expoly : next_onion) { - new_area += expoly.area(); - } - std::vector divs{ 1.8f, 1.6f }; //don't over-extrude, so don't use divider >2 - size_t idx_div = 0; - while ((next_onion.size() > no_thin_onion.size() || (new_area != 0 && last_area > new_area * 100)) && idx_div < divs.size()) { - float div = divs[idx_div]; - //use a sightly bigger spacing to try to drastically improve the split, that can lead to very thick gapfill - ExPolygons next_onion_secondTry = offset2_ex( - last, - -(float)(good_spacing + (1 - thin_perimeter) * (perimeter_spacing / div) - 1), - +(float)((1 - thin_perimeter) * (perimeter_spacing / div) - 1)); - if (next_onion.size() > next_onion_secondTry.size() * 1.2 && next_onion.size() > next_onion_secondTry.size() + 2) { - // don't get it if it creates too many - next_onion = next_onion_secondTry; - } else if (next_onion.size() > next_onion_secondTry.size() || last_area > new_area * 100) { - // don't get it if it's too small - double area_new = 0; - for (const ExPolygon& expoly : next_onion_secondTry) { - area_new += expoly.area(); - } - if (last_area > area_new * 100 || new_area == 0) { + std::vector divs{ 1.8f, 1.6f }; //don't over-extrude, so don't use divider >2 + size_t idx_div = 0; + while ((next_onion.size() > no_thin_onion.size() || (new_area != 0 && last_area > new_area * 100)) && idx_div < divs.size()) { + float div = divs[idx_div]; + //use a sightly bigger spacing to try to drastically improve the split, that can lead to very thick gapfill + ExPolygons next_onion_secondTry = offset2_ex( + last, + -(float)(good_spacing + (1 - thin_perimeter) * (perimeter_spacing / div) - 1), + +(float)((1 - thin_perimeter) * (perimeter_spacing / div) - 1)); + if (next_onion.size() > next_onion_secondTry.size() * 1.2 && next_onion.size() > next_onion_secondTry.size() + 2) { + // don't get it if it creates too many next_onion = next_onion_secondTry; + } else if (next_onion.size() > next_onion_secondTry.size() || last_area > new_area * 100) { + // don't get it if it's too small + double area_new = 0; + for (const ExPolygon& expoly : next_onion_secondTry) { + area_new += expoly.area(); + } + if (last_area > area_new * 100 || new_area == 0) { + next_onion = next_onion_secondTry; + } } + idx_div++; } - idx_div++; + last_area = new_area; } - last_area = new_area; - } else { // If "overlapping_perimeters" is enabled, this paths will be entered, which // leads to overflows, as in prusa3d/Slic3r GH #32 diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 5f4c7df26fe..4da5b4cd3ca 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -5213,7 +5213,9 @@ void PrintConfigDef::init_fff_params() def->category = OptionCategory::perimeter; def->tooltip = L("Allow outermost perimeter to overlap itself to avoid the use of thin walls. Note that flow isn't adjusted and so this will result in over-extruding and undefined behavior." "\n100% means that perimeters can overlap completly on top of each other." - "\n0% will deactivate this setting"); + "\n0% will deactivate this setting." + "\nValues below 2% don't have any effect." + "\n-1% will also deactivate the anti-hysteris checks for external perimeters."); def->sidetext = "%"; def->mode = comExpert | comSuSi; def->set_default_value(new ConfigOptionPercent(80)); @@ -5224,7 +5226,9 @@ void PrintConfigDef::init_fff_params() def->category = OptionCategory::perimeter; def->tooltip = L("Allow all perimeters to overlap, instead of just external ones." "\n100% means that perimeters can overlap completly on top of each other." - "\n0% will deactivate this setting"); + "\n0% will deactivate this setting." + "\nValues below 2% don't have any effect." + "\n-1% will also deactivate the anti-hysteris checks for internal perimeters."); def->sidetext = "%"; def->mode = comExpert | comSuSi; def->set_default_value(new ConfigOptionPercent(20)); diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 0d0b2523358..93f85d10352 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -332,7 +332,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) toggle_field("overhangs_width", config->option("overhangs_width_speed")->value > 0); toggle_field("overhangs_reverse_threshold", have_perimeters && config->opt_bool("overhangs_reverse")); toggle_field("min_width_top_surface", have_perimeters && config->opt_bool("only_one_perimeter_top")); - toggle_field("thin_perimeters_all", have_perimeters && config->option("thin_perimeters")->getFloat() > 0); + toggle_field("thin_perimeters_all", have_perimeters && config->option("thin_perimeters")->getFloat() != 0); for (auto el : { "external_perimeters_vase", "external_perimeters_nothole", "external_perimeters_hole", "perimeter_bonding"}) toggle_field(el, config->opt_bool("external_perimeters_first"));