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);