From c61c25b15b8127ae1c9b88567e139a793a4dd891 Mon Sep 17 00:00:00 2001 From: Joseph Lenox Date: Sun, 14 Mar 2021 20:56:24 -0500 Subject: [PATCH] Throw a runtime error if the number of solid layers grows above the total possible layers. Edit the loop syntax to need the current shell thickness to be less than the minimum to add more layers (avoid infinite loop). Add test to cover normal operation and regression for this layer arrangement. Fixes #5019 --- src/test/libslic3r/test_printobject.cpp | 99 +++++++++++++++++++++++++ xs/src/libslic3r/PrintObject.cpp | 17 ++++- 2 files changed, 114 insertions(+), 2 deletions(-) diff --git a/src/test/libslic3r/test_printobject.cpp b/src/test/libslic3r/test_printobject.cpp index 52046f81e..96557332f 100644 --- a/src/test/libslic3r/test_printobject.cpp +++ b/src/test/libslic3r/test_printobject.cpp @@ -1,6 +1,7 @@ #include #include #include "test_data.hpp" +#include "Log.hpp" #include "libslic3r.h" using namespace Slic3r::Test; @@ -77,3 +78,101 @@ SCENARIO("PrintObject: object layer heights") { } } + +SCENARIO("PrintObject: minimum horizontal shells") { + GIVEN("20mm cube and default initial config, initial layer height of 0.1mm") { + auto config {Slic3r::Config::new_from_defaults()}; + TestMesh m { TestMesh::cube_20x20x20 }; + Slic3r::Model model; + + config->set("nozzle_diameter", "3"); + config->set("bottom_solid_layers", 1); + config->set("perimeters", 1); + config->set("first_layer_height", 0.1); + config->set("layer_height", 0.1); + config->set("fill_density", "0%"); + config->set("min_top_bottom_shell_thickness", 1.0); + + WHEN("min shell thickness is 1.0 with layer height of 0.1") { + config->set("min_top_bottom_shell_thickness", 1.0); + auto print {Slic3r::Test::init_print({m}, model, config)}; + slic3r_log->set_level(log_t::DEBUG); + print->objects[0]->prepare_infill(); + for (int i = 0; i < 12; i++) + print->objects[0]->layers[i]->make_fills(); + THEN("Layers 0-9 are solid (Z < 1.0) (all fill_surfaces are solid)") { + for (int i = 0; i < 10; i++) { + CHECK(print->objects[0]->layers[i]->print_z <= (i+1 * 0.1)); + for (auto* r : print->objects[0]->layers[i]->regions) { + for (auto s : r->fill_surfaces) { + REQUIRE(s.is_solid()); + } + } + } + } + AND_THEN("Layer 10 (Z > 1.0) is not solid.") { + for (auto* r : print->objects[0]->layers[10]->regions) { + bool all_solid = true; + for (auto s : r->fill_surfaces) { + REQUIRE(!s.is_solid()); + } + } + } + } + WHEN("min shell thickness is 1.22 with layer height of 0.1") { + config->set("min_top_bottom_shell_thickness", 1.22); + config->set("layer_height", 0.1); + auto print {Slic3r::Test::init_print({m}, model, config)}; + slic3r_log->set_level(log_t::DEBUG); + print->objects[0]->prepare_infill(); + for (int i = 0; i < 20; i++) + print->objects[0]->layers[i]->make_fills(); + AND_THEN("Layers 0-12 are solid (bottom of layer >= 1.22) (all fill_surfaces are solid)") { + for (int i = 0; i < 13; i++) { + CHECK(print->objects[0]->layers[i]->print_z <= (i+1 * 0.1)); + for (auto* r : print->objects[0]->layers[i]->regions) { + for (auto s : r->fill_surfaces) { + REQUIRE(s.is_solid()); + } + } + } + } + AND_THEN("Layer 13 (Z > 1.0) is not solid.") { + for (auto* r : print->objects[0]->layers[13]->regions) { + bool all_solid = true; + for (auto s : r->fill_surfaces) { + REQUIRE(!s.is_solid()); + } + } + } + } + WHEN("min shell thickness is 1.22 14 bottom layers") { + config->set("min_top_bottom_shell_thickness", 1.22); + config->set("bottom_solid_layers", 14); + config->set("layer_height", 0.1); + auto print {Slic3r::Test::init_print({m}, model, config)}; + slic3r_log->set_level(log_t::DEBUG); + print->objects[0]->prepare_infill(); + for (int i = 0; i < 20; i++) + print->objects[0]->layers[i]->make_fills(); + AND_THEN("Layers 0-13 are solid (bottom of layer >= 1.22) (all fill_surfaces are solid)") { + for (int i = 0; i < 14; i++) { + CHECK(print->objects[0]->layers[i]->print_z <= (i+1 * 0.1)); + for (auto* r : print->objects[0]->layers[i]->regions) { + for (auto s : r->fill_surfaces) { + REQUIRE(s.is_solid()); + } + } + } + } + AND_THEN("Layer 14 is not solid.") { + for (auto* r : print->objects[0]->layers[14]->regions) { + bool all_solid = true; + for (auto s : r->fill_surfaces) { + REQUIRE(!s.is_solid()); + } + } + } + } + } +} diff --git a/xs/src/libslic3r/PrintObject.cpp b/xs/src/libslic3r/PrintObject.cpp index 79d0b22b4..23a49dcee 100644 --- a/xs/src/libslic3r/PrintObject.cpp +++ b/xs/src/libslic3r/PrintObject.cpp @@ -11,6 +11,7 @@ #include #include #include +#include namespace Slic3r { @@ -1537,16 +1538,28 @@ PrintObject::_discover_external_horizontal_shells(LayerRegion* layerm, const siz std::cout << "Layer " << i << " has " << (type == stTop ? "top" : "bottom") << " surfaces" << std::endl; #endif - auto solid_layers = type == stTop + size_t solid_layers = type == stTop ? region_config.top_solid_layers() : region_config.bottom_solid_layers(); + solid_layers = min(solid_layers, this->layers.size()); if (region_config.min_top_bottom_shell_thickness() > 0) { auto current_shell_thickness = static_cast(solid_layers) * this->get_layer(i)->height; const auto min_shell_thickness = region_config.min_top_bottom_shell_thickness(); - while (std::abs(min_shell_thickness - current_shell_thickness) > Slic3r::Geometry::epsilon) { + Slic3r::Log::debug("vertical_shell_thickness") << "Initial shell thickness for layer " << i << " " + << current_shell_thickness << " " + << "Minimum: " << min_shell_thickness << "\n"; + while (std::abs(min_shell_thickness - current_shell_thickness) > Slic3r::Geometry::epsilon && current_shell_thickness < min_shell_thickness) { solid_layers++; current_shell_thickness = static_cast(solid_layers) * this->get_layer(i)->height; + Slic3r::Log::debug("vertical_shell_thickness") << "Solid layer count: " + << solid_layers << "; " + << "current_shell_thickness: " + << current_shell_thickness + << "\n"; + if (solid_layers > this->layers.size()) { + throw std::runtime_error("Infinite loop when determining vertical shell thickness"); + } } } _discover_neighbor_horizontal_shells(layerm, i, region_id, type, solid, solid_layers);