From 2d4f7a7437b7b4f6ba3df17377bb1c7975e78049 Mon Sep 17 00:00:00 2001 From: Florian Date: Sun, 5 Jul 2026 04:03:36 +0200 Subject: [PATCH] added option to limit polyhole edges (#12349) Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com> --- src/libslic3r/Preset.cpp | 1 + src/libslic3r/PrintConfig.cpp | 9 +++++++++ src/libslic3r/PrintConfig.hpp | 2 ++ src/libslic3r/PrintObject.cpp | 20 +++++++++++--------- src/slic3r/GUI/ConfigManipulation.cpp | 2 +- src/slic3r/GUI/Tab.cpp | 1 + 6 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index c8c00b7b1c..98a5a4fcb6 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -1279,6 +1279,7 @@ static std::vector s_Preset_print_options{ "hole_to_polyhole", "hole_to_polyhole_threshold", "hole_to_polyhole_twisted", + "hole_to_polyhole_max_edges", "mmu_segmented_region_max_width", "mmu_segmented_region_interlocking_depth", "small_area_infill_flow_compensation", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index c83d065809..bfc7c88861 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -7137,6 +7137,15 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionBool(true)); + def = this->add("hole_to_polyhole_max_edges", coInt); + def->label = L("Maximum Polyhole edge count"); + def->category = L("Quality"); + def->tooltip = L("Maximum number of polyhole edges" + "\nThis setting limits the amount of edges a polyhole can have"); + def->mode = comExpert; + def->min = 3; + def->set_default_value(new ConfigOptionInt(50)); + def = this->add("thumbnails", coString); def->label = L("G-code thumbnails"); def->tooltip = L("Picture sizes to be stored into a .gcode and .sl1 / .sl1s files, in the following format: \"XxY, XxY, ...\""); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 619d8f5c78..3b8b809c78 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1225,6 +1225,8 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionBool, hole_to_polyhole)) ((ConfigOptionFloatOrPercent, hole_to_polyhole_threshold)) ((ConfigOptionBool, hole_to_polyhole_twisted)) + ((ConfigOptionInt, hole_to_polyhole_max_edges)) + ((ConfigOptionBool, overhang_reverse)) ((ConfigOptionBool, overhang_reverse_internal_only)) ((ConfigOptionFloatOrPercent, overhang_reverse_threshold)) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index c1caa3b0d9..13d7297f93 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -157,10 +157,10 @@ std::vector> PrintObject::all_regions( return out; } -Polygons create_polyholes(const Point center, const coord_t radius, const coord_t nozzle_diameter, bool multiple) +Polygons create_polyholes(const Point center, const coord_t radius, const coord_t nozzle_diameter, bool multiple, int max_edges) { // n = max(round(2 * d), 3); // for 0.4mm nozzle - size_t nb_edges = (int)std::max(3, (int)std::round(4.0 * unscaled(radius) * 0.4 / unscaled(nozzle_diameter))); + size_t nb_edges = (int)std::min(max_edges, std::max(3, (int)std::round(4.0 * unscaled(radius) * 0.4 / unscaled(nozzle_diameter)))); // cylinder(h = h, r = d / cos (180 / n), $fn = n); //create x polyholes by rotation if multiple int nb_polyhole = 1; @@ -190,8 +190,8 @@ void PrintObject::_transform_hole_to_polyholes() { // get all circular holes for each layer // the id is center-diameter-extruderid - //the tuple is Point center; float diameter_max; int extruder_id; coord_t max_variation; bool twist; - std::vector, Polygon*>>> layerid2center; + //the tuple is Point center; float diameter_max; int extruder_id; coord_t max_variation; bool twist; int max_edges; + std::vector, Polygon*>>> layerid2center; for (size_t i = 0; i < this->m_layers.size(); i++) layerid2center.emplace_back(); tbb::parallel_for( tbb::blocked_range(0, m_layers.size()), @@ -230,9 +230,10 @@ void PrintObject::_transform_hole_to_polyholes() // SCALED_EPSILON was a bit too harsh. Now using a config, as some may want some harsh setting and some don't. coord_t max_variation = std::max(SCALED_EPSILON, scale_(this->m_layers[layer_idx]->m_regions[region_idx]->region().config().hole_to_polyhole_threshold.get_abs_value(unscaled(diameter_sum / hole.points.size())))); bool twist = this->m_layers[layer_idx]->m_regions[region_idx]->region().config().hole_to_polyhole_twisted.value; + int max_edges = this->m_layers[layer_idx]->m_regions[region_idx]->region().config().hole_to_polyhole_max_edges.value; if (diameter_max - diameter_min < max_variation * 2 && diameter_line_max - diameter_line_min < max_variation * 2) { layerid2center[layer_idx].emplace_back( - std::tuple{center, diameter_max, layer->m_regions[region_idx]->region().config().outer_wall_filament_id.value, max_variation, twist}, & hole); + std::tuple{center, diameter_max, layer->m_regions[region_idx]->region().config().outer_wall_filament_id.value, max_variation, twist, max_edges}, & hole); } } } @@ -243,14 +244,14 @@ void PrintObject::_transform_hole_to_polyholes() } }); //sort holes per center-diameter - std::map, std::vector>> id2layerz2hole; + std::map, std::vector>> id2layerz2hole; //search & find hole that span at least X layers const size_t min_nb_layers = 2; for (size_t layer_idx = 0; layer_idx < this->m_layers.size(); ++layer_idx) { for (size_t hole_idx = 0; hole_idx < layerid2center[layer_idx].size(); ++hole_idx) { //get all other same polygons - std::tuple& id = layerid2center[layer_idx][hole_idx].first; + std::tuple& id = layerid2center[layer_idx][hole_idx].first; float max_z = layers()[layer_idx]->print_z; std::vector> holes; holes.emplace_back(layerid2center[layer_idx][hole_idx].second, layer_idx); @@ -258,7 +259,7 @@ void PrintObject::_transform_hole_to_polyholes() if (layers()[search_layer_idx]->print_z - layers()[search_layer_idx]->height - max_z > EPSILON) break; //search an other polygon with same id for (size_t search_hole_idx = 0; search_hole_idx < layerid2center[search_layer_idx].size(); ++search_hole_idx) { - std::tuple& search_id = layerid2center[search_layer_idx][search_hole_idx].first; + std::tuple& search_id = layerid2center[search_layer_idx][search_hole_idx].first; if (std::get<2>(id) == std::get<2>(search_id) && std::get<0>(id).distance_to(std::get<0>(search_id)) < std::get<3>(id) && std::abs(std::get<1>(id) - std::get<1>(search_id)) < std::get<3>(id) @@ -279,7 +280,7 @@ void PrintObject::_transform_hole_to_polyholes() } //create a polyhole per id and replace holes points by it. for (auto entry : id2layerz2hole) { - Polygons polyholes = create_polyholes(std::get<0>(entry.first), std::get<1>(entry.first), scale_(print()->config().nozzle_diameter.get_at(std::get<2>(entry.first) - 1)), std::get<4>(entry.first)); + Polygons polyholes = create_polyholes(std::get<0>(entry.first), std::get<1>(entry.first), scale_(print()->config().nozzle_diameter.get_at(std::get<2>(entry.first) - 1)), std::get<4>(entry.first), std::get<5>(entry.first)); for (auto& poly_to_replace : entry.second) { Polygon polyhole = polyholes[poly_to_replace.second % polyholes.size()]; //search the clone in layers->slices @@ -1205,6 +1206,7 @@ bool PrintObject::invalidate_state_by_config_options( || opt_key == "hole_to_polyhole" || opt_key == "hole_to_polyhole_threshold" || opt_key == "hole_to_polyhole_twisted" + || opt_key == "hole_to_polyhole_max_edges" ) { steps.emplace_back(posSlice); } else if (opt_key == "enable_support") { diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 006b2a009f..46758e3e64 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -980,7 +980,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, in toggle_line("min_width_top_surface", config->opt_bool("only_one_wall_top") || ((config->opt_float("min_length_factor") > 0.5f) && have_arachne)); // 0.5 is default value - for (auto el : { "hole_to_polyhole_threshold", "hole_to_polyhole_twisted" }) + for (auto el : { "hole_to_polyhole_threshold", "hole_to_polyhole_twisted", "hole_to_polyhole_max_edges" }) toggle_line(el, config->opt_bool("hole_to_polyhole")); bool has_detect_overhang_wall = config->opt_bool("detect_overhang_wall"); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index aea72d601f..52537d9331 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2647,6 +2647,7 @@ void TabPrint::build() optgroup->append_single_option_line("hole_to_polyhole", "quality_settings_precision#polyholes"); optgroup->append_single_option_line("hole_to_polyhole_threshold", "quality_settings_precision#polyholes"); optgroup->append_single_option_line("hole_to_polyhole_twisted", "quality_settings_precision#polyholes"); + optgroup->append_single_option_line("hole_to_polyhole_max_edges", "quality_settings_precision#polyholes"); optgroup = page->new_optgroup(L("Ironing"), L"param_ironing"); optgroup->append_single_option_line("ironing_type", "quality_settings_ironing#type");