diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 620b658f96..a440bb87a0 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -4414,11 +4414,6 @@ struct PrecomputedLayer }; } // namespace -template static bool any_enabled(const BoolsOption &option) -{ - return std::any_of(option.values.begin(), option.values.end(), [](unsigned char enabled) { return enabled != 0; }); -} - // Whether process_layer() prepares the overhang estimator for `layer`. template static bool prepares_overhang_estimator(const Layer &layer, bool overhang_fan, OverhangSpeed overhang_speed) diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 0a478d66dc..68e35db40d 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -789,6 +789,12 @@ class StaticPrintConfig; // Minimum object distance for arrangement, based on printer technology. double min_object_distance(const ConfigBase &cfg); +// Whether any value is set, a nil value included. +template bool any_enabled(const ConfigOptionBoolsTempl &option) +{ + return std::any_of(option.values.begin(), option.values.end(), [](unsigned char enabled) { return enabled != 0; }); +} + // One (extruder type x nozzle volume type) parameter variant a filament prints through, plus a // representative physical extruder observed using it. Ordering (and set-dedup identity) covers // the variant pair only, so the same variant reached through two extruders keeps one config slot. diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 05d608f935..17ca44d526 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1025,10 +1025,13 @@ void PrintObject::generate_support_material() void PrintObject::estimate_curled_extrusions() { if (this->set_started(posEstimateCurledExtrusions)) { - if ( std::any_of(this->print()->m_print_regions.begin(), this->print()->m_print_regions.end(), [](const PrintRegion* region) { - const auto& cfg = region->config().enable_overhang_speed.values; - return std::any_of(cfg.begin(), cfg.end(), [](const unsigned char v) { return (bool) v; }); - })) { + const auto any_region_enables = [this](ConfigOptionBoolsNullable PrintRegionConfig::*option) { + return std::any_of(this->print()->m_print_regions.begin(), this->print()->m_print_regions.end(), + [option](const PrintRegion* region) { return any_enabled(region->config().*option); }); + }; + // Only the slowdown for curled perimeters reads the curled lines, and they stay empty unless some region has overhang speed on. + if (any_region_enables(&PrintRegionConfig::enable_overhang_speed) && + any_region_enables(&PrintRegionConfig::slowdown_for_curled_perimeters)) { // Estimate curling of support material and add it to the malformaition lines of each layer float support_flow_width = support_material_flow(this, this->config().layer_height).width(); @@ -1038,6 +1041,9 @@ void PrintObject::estimate_curled_extrusions() float(this->config().brim_width.getFloat())}; SupportSpotsGenerator::estimate_malformations(this->layers(), params); m_print->throw_if_canceled(); + } else { + for (Layer *layer : m_layers) + layer->curled_lines.clear(); } //this->set_done(posEstimateCurledExtrusions); } diff --git a/tests/fff_print/test_extrusion_processor.cpp b/tests/fff_print/test_extrusion_processor.cpp index bd6a203290..95a9d03f8a 100644 --- a/tests/fff_print/test_extrusion_processor.cpp +++ b/tests/fff_print/test_extrusion_processor.cpp @@ -566,6 +566,12 @@ struct SlicedCage using Walls = std::vector>; +bool has_curled_lines(const PrintObject &object) +{ + const auto layers = object.layers(); + return std::any_of(layers.begin(), layers.end(), [](const Layer *layer) { return !layer->curled_lines.empty(); }); +} + // Estimates every wall of `layer` against whatever layer `estimator` was last prepared with before it. Walls estimate_walls(ExtrusionQualityEstimator &estimator, const PrintObject *object, const Layer &layer) { @@ -707,6 +713,53 @@ TEST_CASE("Precomputed overhang data has the curled-line tree exactly when a reg CHECK((precomputed.front().lower_curled_lines != nullptr) == slowdown); } +TEST_CASE("Curled walls are estimated only when overhang speed and the slowdown for curled perimeters are both on", "[ExtrusionProcessor]") +{ + const auto [overhang_speed, slowdown, estimated] = GENERATE(table({ + {true, true, true}, + {true, false, false}, + {false, true, false}, + })); + DynamicPrintConfig config = caged_overhang_config("classic"); + config.set_deserialize_strict({{"enable_overhang_speed", overhang_speed ? "1" : "0"}, + {"slowdown_for_curled_perimeters", slowdown ? "1" : "0"}}); + const SlicedCage cage(config); + + CHECK(has_curled_lines(*cage.object) == estimated); +} + +TEST_CASE("Curled walls are estimated when overhang speed and the slowdown for curled perimeters are on in different objects", "[ExtrusionProcessor]") +{ + const std::vector> overrides{ + {{"enable_overhang_speed", "1"}, {"slowdown_for_curled_perimeters", "0"}}, + {{"enable_overhang_speed", "0"}, {"slowdown_for_curled_perimeters", "1"}}, + }; + Print print; + Model model; + init_print(std::vector{caged_overhang_mesh(), caged_overhang_mesh()}, print, model, caged_overhang_config("classic"), + &overrides); + print.process(); + + REQUIRE(print.objects().size() == 2); + for (const PrintObject *object : print.objects()) + CHECK(has_curled_lines(*object)); +} + +TEST_CASE("Curled walls from an earlier slice are dropped once overhang speed is off", "[ExtrusionProcessor]") +{ + DynamicPrintConfig config = caged_overhang_config("classic"); + config.set_deserialize_strict("slowdown_for_curled_perimeters", "1"); + SlicedCage cage(config); + const Layer *first_layer = cage.print.objects().front()->layers().front(); + REQUIRE(has_curled_lines(*cage.print.objects().front())); + + config.set_deserialize_strict("enable_overhang_speed", "0"); + cage.print.apply(cage.model, config); + cage.print.process(); + REQUIRE(cage.print.objects().front()->layers().front() == first_layer); + CHECK_FALSE(has_curled_lines(*cage.print.objects().front())); +} + TEST_CASE("Caged external overhangs are slowed when printed by object or through the pressure equalizer", "[ExtrusionProcessor]") { const auto [key, value] = GENERATE(table({