Skip to content

Commit

Permalink
Add a way to deactivate the anti-hysteresis check for perimeters.
Browse files Browse the repository at this point in the history
  • Loading branch information
supermerill committed Jul 24, 2022
1 parent 2c4fd30 commit fbd05d8
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 53 deletions.
111 changes: 61 additions & 50 deletions src/libslic3r/PerimeterGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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),
Expand Down Expand Up @@ -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<float> 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<float> 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
Expand Down Expand Up @@ -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<float> 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<float> 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
Expand Down
8 changes: 6 additions & 2 deletions src/libslic3r/PrintConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -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));
Expand Down
2 changes: 1 addition & 1 deletion src/slic3r/GUI/ConfigManipulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
toggle_field("overhangs_width", config->option<ConfigOptionFloatOrPercent>("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"));
Expand Down

0 comments on commit fbd05d8

Please sign in to comment.