From 0eb2a2cf0479eb50075c8db41883d30f2d3a6f98 Mon Sep 17 00:00:00 2001 From: PavelMikus Date: Mon, 27 Mar 2023 13:26:57 +0200 Subject: [PATCH] Disable "infill only where needed" option Note: only commented out for now. --- src/libslic3r/LayerRegion.cpp | 2 +- src/libslic3r/Preset.cpp | 2 +- src/libslic3r/PrintConfig.cpp | 18 ++-- src/libslic3r/PrintConfig.hpp | 2 +- src/libslic3r/PrintObject.cpp | 184 +++++++++++++++++----------------- src/slic3r/GUI/Tab.cpp | 2 +- tests/fff_print/test_fill.cpp | 148 +++++++++++++-------------- 7 files changed, 180 insertions(+), 178 deletions(-) diff --git a/src/libslic3r/LayerRegion.cpp b/src/libslic3r/LayerRegion.cpp index 6374766cd..d722f1e9c 100644 --- a/src/libslic3r/LayerRegion.cpp +++ b/src/libslic3r/LayerRegion.cpp @@ -727,7 +727,7 @@ void LayerRegion::prepare_fill_surfaces() if (! spiral_vase && this->region().config().top_solid_layers == 0) { for (Surface &surface : m_fill_surfaces) if (surface.is_top()) - surface.surface_type = this->layer()->object()->config().infill_only_where_needed && this->region().config().fill_pattern != ipLightning ? stInternalVoid : stInternal; + surface.surface_type = /*this->layer()->object()->config().infill_only_where_needed && this->region().config().fill_pattern != ipLightning ? stInternalVoid :*/ stInternal; } if (this->region().config().bottom_solid_layers == 0) { for (Surface &surface : m_fill_surfaces) diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 464bb7daa..23f1438c4 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -425,7 +425,7 @@ static std::vector s_Preset_print_options { "top_solid_layers", "top_solid_min_thickness", "bottom_solid_layers", "bottom_solid_min_thickness", "extra_perimeters", "extra_perimeters_on_overhangs", "avoid_crossing_curled_overhangs", "avoid_crossing_perimeters", "thin_walls", "overhangs", "seam_position","staggered_inner_seams", "external_perimeters_first", "fill_density", "fill_pattern", "top_fill_pattern", "bottom_fill_pattern", - "infill_every_layers", "infill_only_where_needed", "solid_infill_every_layers", "fill_angle", "bridge_angle", + "infill_every_layers", /*"infill_only_where_needed",*/ "solid_infill_every_layers", "fill_angle", "bridge_angle", "solid_infill_below_area", "only_retract_when_crossing_perimeters", "infill_first", "ironing", "ironing_type", "ironing_flowrate", "ironing_speed", "ironing_spacing", "max_print_speed", "max_volumetric_speed", "avoid_crossing_perimeters_max_detour", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 60717b68c..2fb2b877a 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1560,14 +1560,14 @@ void PrintConfigDef::init_fff_params() def->mode = comExpert; def->set_default_value(new ConfigOptionBool(false)); - def = this->add("infill_only_where_needed", coBool); - def->label = L("Only infill where needed"); - def->category = L("Infill"); - def->tooltip = L("This option will limit infill to the areas actually needed for supporting ceilings " - "(it will act as internal support material). If enabled, slows down the G-code generation " - "due to the multiple checks involved."); - def->mode = comAdvanced; - def->set_default_value(new ConfigOptionBool(false)); + // def = this->add("infill_only_where_needed", coBool); + // def->label = L("Only infill where needed"); + // def->category = L("Infill"); + // def->tooltip = L("This option will limit infill to the areas actually needed for supporting ceilings " + // "(it will act as internal support material). If enabled, slows down the G-code generation " + // "due to the multiple checks involved."); + // def->mode = comAdvanced; + // def->set_default_value(new ConfigOptionBool(false)); def = this->add("infill_overlap", coFloatOrPercent); def->label = L("Infill/perimeters overlap"); @@ -4154,6 +4154,8 @@ static std::set PrintConfigDef_ignore = { "wall_add_middle_threshold", "wall_split_middle_threshold", // Replaced by new concentric ensuring in 2.6.0-alpha5 "ensure_vertical_shell_thickness", + // Disabled in 2.6.0-alpha6, this option is problematic + "infill_only_where_needed", }; void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &value) diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index d29afe5e7..08f3bcd2f 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -495,7 +495,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionFloatOrPercent, extrusion_width)) ((ConfigOptionFloat, first_layer_acceleration_over_raft)) ((ConfigOptionFloatOrPercent, first_layer_speed_over_raft)) - ((ConfigOptionBool, infill_only_where_needed)) + // ((ConfigOptionBool, infill_only_where_needed)) // Force the generation of solid shells between adjacent materials/volumes. ((ConfigOptionBool, interface_shells)) ((ConfigOptionFloat, layer_height)) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 7136617d8..493bb9070 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -348,8 +348,8 @@ void PrintObject::prepare_infill() //FIXME The surfaces are supported by a sparse infill, but the sparse infill is only as large as the area to support. // Likely the sparse infill will not be anchored correctly, so it will not work as intended. // Also one wishes the perimeters to be supported by a full infill. - this->clip_fill_surfaces(); - m_print->throw_if_canceled(); + // this->clip_fill_surfaces(); + // m_print->throw_if_canceled(); #ifdef SLIC3R_DEBUG_SLICE_PROCESSING for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) { @@ -2419,98 +2419,98 @@ bool PrintObject::update_layer_height_profile(const ModelObject &model_object, c // Also one wishes the perimeters to be supported by a full infill. // Idempotence of this method is guaranteed by the fact that we don't remove things from // fill_surfaces but we only turn them into VOID surfaces, thus preserving the boundaries. -void PrintObject::clip_fill_surfaces() -{ - bool has_lightning_infill = false; - for (size_t region_id = 0; region_id < this->num_printing_regions(); ++region_id) - if (const PrintRegionConfig &config = this->printing_region(region_id).config(); config.fill_density > 0 && config.fill_pattern == ipLightning) - has_lightning_infill = true; +// void PrintObject::clip_fill_surfaces() +// { +// bool has_lightning_infill = false; +// for (size_t region_id = 0; region_id < this->num_printing_regions(); ++region_id) +// if (const PrintRegionConfig &config = this->printing_region(region_id).config(); config.fill_density > 0 && config.fill_pattern == ipLightning) +// has_lightning_infill = true; - // For Lightning infill, infill_only_where_needed is ignored because both - // do a similar thing, and their combination doesn't make much sense. - if (! m_config.infill_only_where_needed.value || has_lightning_infill) - return; - bool has_infill = false; - for (size_t i = 0; i < this->num_printing_regions(); ++ i) - if (this->printing_region(i).config().fill_density > 0) { - has_infill = true; - break; - } - if (! has_infill) - return; +// // For Lightning infill, infill_only_where_needed is ignored because both +// // do a similar thing, and their combination doesn't make much sense. +// if (! m_config.infill_only_where_needed.value || has_lightning_infill) +// return; +// bool has_infill = false; +// for (size_t i = 0; i < this->num_printing_regions(); ++ i) +// if (this->printing_region(i).config().fill_density > 0) { +// has_infill = true; +// break; +// } +// if (! has_infill) +// return; - // We only want infill under ceilings; this is almost like an - // internal support material. - // Proceed top-down, skipping the bottom layer. - Polygons upper_internal; - for (int layer_id = int(m_layers.size()) - 1; layer_id > 0; -- layer_id) { - Layer *layer = m_layers[layer_id]; - Layer *lower_layer = m_layers[layer_id - 1]; - // Detect things that we need to support. - // Cummulative fill surfaces. - Polygons fill_surfaces; - // Solid surfaces to be supported. - Polygons overhangs; - for (const LayerRegion *layerm : layer->m_regions) - for (const Surface &surface : layerm->fill_surfaces()) { - Polygons polygons = to_polygons(surface.expolygon); - if (surface.is_solid()) - polygons_append(overhangs, polygons); - polygons_append(fill_surfaces, std::move(polygons)); - } - Polygons lower_layer_fill_surfaces; - Polygons lower_layer_internal_surfaces; - for (const LayerRegion *layerm : lower_layer->m_regions) - for (const Surface &surface : layerm->fill_surfaces()) { - Polygons polygons = to_polygons(surface.expolygon); - if (surface.surface_type == stInternal || surface.surface_type == stInternalVoid) - polygons_append(lower_layer_internal_surfaces, polygons); - polygons_append(lower_layer_fill_surfaces, std::move(polygons)); - } - // We also need to support perimeters when there's at least one full unsupported loop - { - // Get perimeters area as the difference between slices and fill_surfaces - // Only consider the area that is not supported by lower perimeters - Polygons perimeters = intersection(diff(layer->lslices, fill_surfaces), lower_layer_fill_surfaces); - // Only consider perimeter areas that are at least one extrusion width thick. - //FIXME Offset2 eats out from both sides, while the perimeters are create outside in. - //Should the pw not be half of the current value? - float pw = FLT_MAX; - for (const LayerRegion *layerm : layer->m_regions) - pw = std::min(pw, (float)layerm->flow(frPerimeter).scaled_width()); - // Append such thick perimeters to the areas that need support - polygons_append(overhangs, opening(perimeters, pw)); - } - // Merge the new overhangs, find new internal infill. - polygons_append(upper_internal, std::move(overhangs)); - static constexpr const auto closing_radius = scaled(2.f); - upper_internal = intersection( - // Regularize the overhang regions, so that the infill areas will not become excessively jagged. - smooth_outward( - closing(upper_internal, closing_radius, ClipperLib::jtSquare, 0.), - scaled(0.1)), - lower_layer_internal_surfaces); - // Apply new internal infill to regions. - for (LayerRegion *layerm : lower_layer->m_regions) { - if (layerm->region().config().fill_density.value == 0) - continue; - Polygons internal; - for (Surface &surface : layerm->m_fill_surfaces.surfaces) - if (surface.surface_type == stInternal || surface.surface_type == stInternalVoid) - polygons_append(internal, std::move(surface.expolygon)); - layerm->m_fill_surfaces.remove_types({ stInternal, stInternalVoid }); - layerm->m_fill_surfaces.append(intersection_ex(internal, upper_internal, ApplySafetyOffset::Yes), stInternal); - layerm->m_fill_surfaces.append(diff_ex (internal, upper_internal, ApplySafetyOffset::Yes), stInternalVoid); - // If there are voids it means that our internal infill is not adjacent to - // perimeters. In this case it would be nice to add a loop around infill to - // make it more robust and nicer. TODO. -#ifdef SLIC3R_DEBUG_SLICE_PROCESSING - layerm->export_region_fill_surfaces_to_svg_debug("6_clip_fill_surfaces"); -#endif - } - m_print->throw_if_canceled(); - } -} // void PrintObject::clip_fill_surfaces() +// // We only want infill under ceilings; this is almost like an +// // internal support material. +// // Proceed top-down, skipping the bottom layer. +// Polygons upper_internal; +// for (int layer_id = int(m_layers.size()) - 1; layer_id > 0; -- layer_id) { +// Layer *layer = m_layers[layer_id]; +// Layer *lower_layer = m_layers[layer_id - 1]; +// // Detect things that we need to support. +// // Cummulative fill surfaces. +// Polygons fill_surfaces; +// // Solid surfaces to be supported. +// Polygons overhangs; +// for (const LayerRegion *layerm : layer->m_regions) +// for (const Surface &surface : layerm->fill_surfaces()) { +// Polygons polygons = to_polygons(surface.expolygon); +// if (surface.is_solid()) +// polygons_append(overhangs, polygons); +// polygons_append(fill_surfaces, std::move(polygons)); +// } +// Polygons lower_layer_fill_surfaces; +// Polygons lower_layer_internal_surfaces; +// for (const LayerRegion *layerm : lower_layer->m_regions) +// for (const Surface &surface : layerm->fill_surfaces()) { +// Polygons polygons = to_polygons(surface.expolygon); +// if (surface.surface_type == stInternal || surface.surface_type == stInternalVoid) +// polygons_append(lower_layer_internal_surfaces, polygons); +// polygons_append(lower_layer_fill_surfaces, std::move(polygons)); +// } +// // We also need to support perimeters when there's at least one full unsupported loop +// { +// // Get perimeters area as the difference between slices and fill_surfaces +// // Only consider the area that is not supported by lower perimeters +// Polygons perimeters = intersection(diff(layer->lslices, fill_surfaces), lower_layer_fill_surfaces); +// // Only consider perimeter areas that are at least one extrusion width thick. +// //FIXME Offset2 eats out from both sides, while the perimeters are create outside in. +// //Should the pw not be half of the current value? +// float pw = FLT_MAX; +// for (const LayerRegion *layerm : layer->m_regions) +// pw = std::min(pw, (float)layerm->flow(frPerimeter).scaled_width()); +// // Append such thick perimeters to the areas that need support +// polygons_append(overhangs, opening(perimeters, pw)); +// } +// // Merge the new overhangs, find new internal infill. +// polygons_append(upper_internal, std::move(overhangs)); +// static constexpr const auto closing_radius = scaled(2.f); +// upper_internal = intersection( +// // Regularize the overhang regions, so that the infill areas will not become excessively jagged. +// smooth_outward( +// closing(upper_internal, closing_radius, ClipperLib::jtSquare, 0.), +// scaled(0.1)), +// lower_layer_internal_surfaces); +// // Apply new internal infill to regions. +// for (LayerRegion *layerm : lower_layer->m_regions) { +// if (layerm->region().config().fill_density.value == 0) +// continue; +// Polygons internal; +// for (Surface &surface : layerm->m_fill_surfaces.surfaces) +// if (surface.surface_type == stInternal || surface.surface_type == stInternalVoid) +// polygons_append(internal, std::move(surface.expolygon)); +// layerm->m_fill_surfaces.remove_types({ stInternal, stInternalVoid }); +// layerm->m_fill_surfaces.append(intersection_ex(internal, upper_internal, ApplySafetyOffset::Yes), stInternal); +// layerm->m_fill_surfaces.append(diff_ex (internal, upper_internal, ApplySafetyOffset::Yes), stInternalVoid); +// // If there are voids it means that our internal infill is not adjacent to +// // perimeters. In this case it would be nice to add a loop around infill to +// // make it more robust and nicer. TODO. +// #ifdef SLIC3R_DEBUG_SLICE_PROCESSING +// layerm->export_region_fill_surfaces_to_svg_debug("6_clip_fill_surfaces"); +// #endif +// } +// m_print->throw_if_canceled(); +// } +// } // void PrintObject::clip_fill_surfaces() void PrintObject::discover_horizontal_shells() { diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index b095d4ea2..1b2a1ba81 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1469,7 +1469,7 @@ void TabPrint::build() optgroup = page->new_optgroup(L("Reducing printing time")); category_path = "infill_42#"; optgroup->append_single_option_line("infill_every_layers", category_path + "combine-infill-every-x-layers"); - optgroup->append_single_option_line("infill_only_where_needed", category_path + "only-infill-where-needed"); + // optgroup->append_single_option_line("infill_only_where_needed", category_path + "only-infill-where-needed"); optgroup = page->new_optgroup(L("Advanced")); optgroup->append_single_option_line("solid_infill_every_layers", category_path + "solid-infill-every-x-layers"); diff --git a/tests/fff_print/test_fill.cpp b/tests/fff_print/test_fill.cpp index 8f024102d..6d8422c82 100644 --- a/tests/fff_print/test_fill.cpp +++ b/tests/fff_print/test_fill.cpp @@ -252,85 +252,85 @@ SCENARIO("Infill does not exceed perimeters", "[Fill]") GIVEN("Concentric") { test("concentric"sv); } } -SCENARIO("Infill only where needed", "[Fill]") -{ - DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config(); - config.set_deserialize_strict({ - { "nozzle_diameter", "0.4, 0.4, 0.4, 0.4" }, - { "infill_only_where_needed", true }, - { "bottom_solid_layers", 0 }, - { "infill_extruder", 2 }, - { "infill_extrusion_width", 0.5 }, - { "wipe_into_infill", false }, - { "fill_density", 0.4 }, - // for preventing speeds from being altered - { "cooling", "0, 0, 0, 0" }, - // for preventing speeds from being altered - { "first_layer_speed", "100%" } - }); +// SCENARIO("Infill only where needed", "[Fill]") +// { +// DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config(); +// config.set_deserialize_strict({ +// { "nozzle_diameter", "0.4, 0.4, 0.4, 0.4" }, +// { "infill_only_where_needed", true }, +// { "bottom_solid_layers", 0 }, +// { "infill_extruder", 2 }, +// { "infill_extrusion_width", 0.5 }, +// { "wipe_into_infill", false }, +// { "fill_density", 0.4 }, +// // for preventing speeds from being altered +// { "cooling", "0, 0, 0, 0" }, +// // for preventing speeds from being altered +// { "first_layer_speed", "100%" } +// }); - auto test = [&config]() -> double { - TriangleMesh pyramid = Test::mesh(Slic3r::Test::TestMesh::pyramid); - // Arachne doesn't use "Detect thin walls," and because of this, it filters out tiny infill areas differently. - // So, for Arachne, we cut the pyramid model to achieve similar results. - if (config.opt_enum("perimeter_generator") == Slic3r::PerimeterGeneratorType::Arachne) { - indexed_triangle_set lower{}; - cut_mesh(pyramid.its, 35, nullptr, &lower); - pyramid = TriangleMesh(lower); - } - std::string gcode = Slic3r::Test::slice({ pyramid }, config); - THEN("gcode not empty") { - REQUIRE(! gcode.empty()); - } +// auto test = [&config]() -> double { +// TriangleMesh pyramid = Test::mesh(Slic3r::Test::TestMesh::pyramid); +// // Arachne doesn't use "Detect thin walls," and because of this, it filters out tiny infill areas differently. +// // So, for Arachne, we cut the pyramid model to achieve similar results. +// if (config.opt_enum("perimeter_generator") == Slic3r::PerimeterGeneratorType::Arachne) { +// indexed_triangle_set lower{}; +// cut_mesh(pyramid.its, 35, nullptr, &lower); +// pyramid = TriangleMesh(lower); +// } +// std::string gcode = Slic3r::Test::slice({ pyramid }, config); +// THEN("gcode not empty") { +// REQUIRE(! gcode.empty()); +// } - GCodeReader parser; - int tool = -1; - const int infill_extruder = config.opt_int("infill_extruder"); - Points infill_points; - parser.parse_buffer(gcode, [&tool, &infill_points, infill_extruder](Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) - { - // if the command is a T command, set the the current tool - if (boost::starts_with(line.cmd(), "T")) { - tool = atoi(line.cmd().data() + 1) + 1; - } else if (line.cmd() == "G1" && line.extruding(self) && line.dist_XY(self) > 0) { - if (tool == infill_extruder) { - infill_points.emplace_back(self.xy_scaled()); - infill_points.emplace_back(line.new_XY_scaled(self)); - } - } - }); - // prevent calling convex_hull() with no points - THEN("infill not empty") { - REQUIRE(! infill_points.empty()); - } +// GCodeReader parser; +// int tool = -1; +// const int infill_extruder = config.opt_int("infill_extruder"); +// Points infill_points; +// parser.parse_buffer(gcode, [&tool, &infill_points, infill_extruder](Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) +// { +// // if the command is a T command, set the the current tool +// if (boost::starts_with(line.cmd(), "T")) { +// tool = atoi(line.cmd().data() + 1) + 1; +// } else if (line.cmd() == "G1" && line.extruding(self) && line.dist_XY(self) > 0) { +// if (tool == infill_extruder) { +// infill_points.emplace_back(self.xy_scaled()); +// infill_points.emplace_back(line.new_XY_scaled(self)); +// } +// } +// }); +// // prevent calling convex_hull() with no points +// THEN("infill not empty") { +// REQUIRE(! infill_points.empty()); +// } - auto opt_width = config.opt("infill_extrusion_width"); - REQUIRE(! opt_width->percent); - Polygons convex_hull = expand(Geometry::convex_hull(infill_points), scaled(opt_width->value / 2)); - return SCALING_FACTOR * SCALING_FACTOR * std::accumulate(convex_hull.begin(), convex_hull.end(), 0., [](double acc, const Polygon &poly){ return acc + poly.area(); }); - }; +// auto opt_width = config.opt("infill_extrusion_width"); +// REQUIRE(! opt_width->percent); +// Polygons convex_hull = expand(Geometry::convex_hull(infill_points), scaled(opt_width->value / 2)); +// return SCALING_FACTOR * SCALING_FACTOR * std::accumulate(convex_hull.begin(), convex_hull.end(), 0., [](double acc, const Polygon &poly){ return acc + poly.area(); }); +// }; - double tolerance = 5; // mm^2 +// double tolerance = 5; // mm^2 - // GIVEN("solid_infill_below_area == 0") { - // config.opt_float("solid_infill_below_area") = 0; - // WHEN("pyramid is sliced ") { - // auto area = test(); - // THEN("no infill is generated when using infill_only_where_needed on a pyramid") { - // REQUIRE(area < tolerance); - // } - // } - // } - // GIVEN("solid_infill_below_area == 70") { - // config.opt_float("solid_infill_below_area") = 70; - // WHEN("pyramid is sliced ") { - // auto area = test(); - // THEN("infill is only generated under the forced solid shells") { - // REQUIRE(std::abs(area - 70) < tolerance); - // } - // } - // } -} +// // GIVEN("solid_infill_below_area == 0") { +// // config.opt_float("solid_infill_below_area") = 0; +// // WHEN("pyramid is sliced ") { +// // auto area = test(); +// // THEN("no infill is generated when using infill_only_where_needed on a pyramid") { +// // REQUIRE(area < tolerance); +// // } +// // } +// // } +// // GIVEN("solid_infill_below_area == 70") { +// // config.opt_float("solid_infill_below_area") = 70; +// // WHEN("pyramid is sliced ") { +// // auto area = test(); +// // THEN("infill is only generated under the forced solid shells") { +// // REQUIRE(std::abs(area - 70) < tolerance); +// // } +// // } +// // } +// } SCENARIO("Combine infill", "[Fill]") {