From b9cce6c179850038c06a57d9bf6a428c25db4fcc Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Thu, 19 Jun 2025 15:19:05 +0800 Subject: [PATCH] Ironing support interfaces (#9548) * Generate support interface iron extrusion * Always ironing last * Add options * Move ironing speed to speed tab * Don't iron places that are covered by upper support layers * Disable support interface spacing settings when support ironing is enabled * Update text --- src/libslic3r/GCode.cpp | 38 +++++++++++++---- src/libslic3r/GCode.hpp | 2 +- src/libslic3r/Preset.cpp | 1 + src/libslic3r/PrintConfig.cpp | 45 ++++++++++++++++++++- src/libslic3r/PrintConfig.hpp | 4 ++ src/libslic3r/PrintObject.cpp | 4 ++ src/libslic3r/Support/SupportCommon.cpp | 44 +++++++++++++++++++- src/libslic3r/Support/SupportParameters.hpp | 16 +++++++- src/slic3r/GUI/ConfigManipulation.cpp | 25 +++++++++++- src/slic3r/GUI/Tab.cpp | 8 +++- 10 files changed, 171 insertions(+), 16 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index d4a69116bd..352e9fdae7 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -4325,10 +4325,16 @@ LayerResult GCode::process_layer( ExtrusionRole support_extrusion_role = instance_to_print.object_by_extruder.support_extrusion_role; bool is_overridden = support_extrusion_role == erSupportMaterialInterface ? support_intf_overridden : support_overridden; - if (is_overridden == (print_wipe_extrusions != 0)) + if (is_overridden == (print_wipe_extrusions != 0)) { gcode += this->extrude_support( // support_extrusion_role is erSupportMaterial, erSupportTransition, erSupportMaterialInterface or erMixed for all extrusion paths. - instance_to_print.object_by_extruder.support->chained_path_from(m_last_pos, support_extrusion_role)); + *instance_to_print.object_by_extruder.support, support_extrusion_role); + + // Make sure ironing is the last + if (support_extrusion_role == erMixed || support_extrusion_role == erSupportMaterialInterface) { + gcode += this->extrude_support(*instance_to_print.object_by_extruder.support, erIroning); + } + } m_layer = layer_to_print.layer(); m_object_layer_over_raft = object_layer_over_raft; @@ -5036,21 +5042,37 @@ std::string GCode::extrude_infill(const Print &print, const std::vectorrole(); + if ((role == support_extrusion_role) || (support_extrusion_role == erMixed && role != erIroning)) { + extrusions.emplace_back(ee); + } + } + if (extrusions.empty()) + return gcode; + + chain_and_reorder_extrusion_entities(extrusions, &m_last_pos); + const double support_speed = m_config.support_speed.value; const double support_interface_speed = m_config.get_abs_value("support_interface_speed"); - for (const ExtrusionEntity *ee : support_fills.entities) { + for (const ExtrusionEntity *ee : extrusions) { ExtrusionRole role = ee->role(); - assert(role == erSupportMaterial || role == erSupportMaterialInterface || role == erSupportTransition); + assert(role == erSupportMaterial || role == erSupportMaterialInterface || role == erSupportTransition || role == erIroning); const char* label = (role == erSupportMaterial) ? support_label : - ((role == erSupportMaterialInterface) ? support_interface_label : support_transition_label); + ((role == erSupportMaterialInterface) ? support_interface_label : + ((role == erIroning) ? support_ironing_label : support_transition_label)); // BBS //const double speed = (role == erSupportMaterial) ? support_speed : support_interface_speed; const double speed = -1.0; @@ -5067,7 +5089,7 @@ std::string GCode::extrude_support(const ExtrusionEntityCollection &support_fill gcode += this->extrude_loop(*loop, label, speed); } else if (collection) { - gcode += extrude_support(*collection); + gcode += extrude_support(*collection, support_extrusion_role); } else { throw Slic3r::InvalidArgument("Unknown extrusion type"); diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 46f6cbde88..b3ef1a0a89 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -449,7 +449,7 @@ private: std::string extrude_perimeters(const Print& print, const std::vector& by_region, bool is_first_layer, bool is_infill_first); std::string extrude_infill(const Print& print, const std::vector& by_region, bool ironing); - std::string extrude_support(const ExtrusionEntityCollection& support_fills); + std::string extrude_support(const ExtrusionEntityCollection& support_fills, const ExtrusionRole support_extrusion_role); // BBS LiftType to_lift_type(ZHopType z_hop_types); diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 5586c4fcff..bd23030506 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -789,6 +789,7 @@ static std::vector s_Preset_print_options { "infill_direction", "solid_infill_direction", "rotate_solid_infill_direction", "counterbore_hole_bridging", "minimum_sparse_infill_area", "reduce_infill_retraction","internal_solid_infill_pattern","gap_fill_target", "ironing_type", "ironing_pattern", "ironing_flow", "ironing_speed", "ironing_spacing", "ironing_angle", "ironing_inset", + "support_ironing", "support_ironing_pattern", "support_ironing_flow", "support_ironing_spacing", "max_travel_detour_distance", "fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_distance", "fuzzy_skin_first_layer", "fuzzy_skin_noise_type", "fuzzy_skin_scale", "fuzzy_skin_octaves", "fuzzy_skin_persistence", "max_volumetric_extrusion_rate_slope", "max_volumetric_extrusion_rate_slope_segment_length","extrusion_rate_smoothing_external_perimeter_only", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index f134902819..0ccc5d2ad2 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -4897,7 +4897,8 @@ void PrintConfigDef::init_fff_params() def = this->add("support_interface_spacing", coFloat); def->label = L("Top interface spacing"); def->category = L("Support"); - def->tooltip = L("Spacing of interface lines. Zero means solid interface."); + def->tooltip = L("Spacing of interface lines. Zero means solid interface.\n" + "Force using solid interface when support ironing is enabled."); def->sidetext = L("mm"); def->min = 0; def->mode = comAdvanced; @@ -5192,6 +5193,48 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("This setting specifies whether to add infill inside large hollows of tree support."); def->mode = comAdvanced; def->set_default_value(new ConfigOptionBool(false)); + + def = this->add("support_ironing", coBool); + def->label = L("Ironing Support Interface"); + def->category = L("Support"); + def->tooltip = L("Ironing is using small flow to print on same height of support interface again to make it more smooth. " + "This setting controls whether support interface being ironed. When enabled, support interface will be extruded as solid too."); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(false)); + + def = this->add("support_ironing_pattern", coEnum); + def->label = L("Support Ironing Pattern"); + def->tooltip = L("The pattern that will be used when ironing."); + def->category = L("Support"); + def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); + def->enum_values.push_back("concentric"); + def->enum_values.push_back("zig-zag"); + def->enum_labels.push_back(L("Concentric")); + def->enum_labels.push_back(L("Rectilinear")); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionEnum(ipRectilinear)); + + def = this->add("support_ironing_flow", coPercent); + def->label = L("Support Ironing flow"); + def->category = L("Support"); + def->tooltip = L("The amount of material to extrude during ironing. Relative to flow of normal support interface layer height. " + "Too high value results in overextrusion on the surface."); + def->sidetext = "%"; + def->ratio_over = "layer_height"; + def->min = 0; + def->max = 100; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionPercent(10)); + + def = this->add("support_ironing_spacing", coFloat); + def->label = L("Support Ironing line spacing"); + def->category = L("Support"); + def->tooltip = L("The distance between the lines of ironing."); + def->sidetext = L("mm"); + def->min = 0; + def->max = 1; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(0.1)); def = this->add("activate_chamber_temp_control",coBools); def->label = L("Activate temperature control"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 92f96761cd..4bb905d614 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -849,6 +849,10 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionFloatOrPercent, support_threshold_overlap)) ((ConfigOptionFloat, support_object_xy_distance)) ((ConfigOptionFloat, support_object_first_layer_gap)) + ((ConfigOptionBool, support_ironing)) + ((ConfigOptionEnum, support_ironing_pattern)) + ((ConfigOptionPercent, support_ironing_flow)) + ((ConfigOptionFloat, support_ironing_spacing)) ((ConfigOptionFloat, xy_hole_compensation)) ((ConfigOptionFloat, xy_contour_compensation)) ((ConfigOptionBool, flush_into_objects)) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 41fcc2819e..be189e0173 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1016,6 +1016,10 @@ bool PrintObject::invalidate_state_by_config_options( //|| opt_key == "independent_support_layer_height" // BBS || opt_key == "support_threshold_angle" || opt_key == "support_threshold_overlap" + || opt_key == "support_ironing" + || opt_key == "support_ironing_pattern" + || opt_key == "support_ironing_flow" + || opt_key == "support_ironing_spacing" || opt_key == "raft_expansion" || opt_key == "raft_first_layer_density" || opt_key == "raft_first_layer_expansion" diff --git a/src/libslic3r/Support/SupportCommon.cpp b/src/libslic3r/Support/SupportCommon.cpp index f4611a175f..0de4067770 100644 --- a/src/libslic3r/Support/SupportCommon.cpp +++ b/src/libslic3r/Support/SupportCommon.cpp @@ -1605,6 +1605,9 @@ void generate_support_toolpaths( SupportGeneratorLayerExtruded base_interface_layer; boost::container::static_vector nonempty; + float ironing_angle; + Polygons polys_to_iron; + void add_nonempty_and_sort() { for (SupportGeneratorLayerExtruded *item : { &bottom_contact_layer, &top_contact_layer, &interface_layer, &base_interface_layer, &base_layer }) if (! item->empty()) @@ -1694,6 +1697,12 @@ void generate_support_toolpaths( base_layer = std::move(top_contact_layer); } } else { + if (support_params.ironing && !top_contact_layer.empty()) { + // Orca: save the top surface to be ironed later + layer_cache.ironing_angle = support_interface_angle; // TODO: should we rotate 90 degrees? + layer_cache.polys_to_iron = top_contact_layer.polygons_to_extrude(); + } + loop_interface_processor.generate(top_contact_layer, support_params.support_material_interface_flow); // If no loops are allowed, we treat the contact layer exactly as a generic interface layer. // Merge interface_layer into top_contact_layer, as the top_contact_layer is not synchronized and therefore it will be used @@ -1886,7 +1895,7 @@ void generate_support_toolpaths( // Now modulate the support layer height in parallel. tbb::parallel_for(tbb::blocked_range(n_raft_layers, support_layers.size()), - [&support_layers, &layer_caches] + [&support_layers, &layer_caches, &support_params, &bbox_object] (const tbb::blocked_range& range) { for (size_t support_layer_id = range.begin(); support_layer_id < range.end(); ++ support_layer_id) { SupportLayer &support_layer = *support_layers[support_layer_id]; @@ -1897,6 +1906,39 @@ void generate_support_toolpaths( modulate_extrusion_by_overlapping_layers(layer_cache_item.layer_extruded->extrusions, *layer_cache_item.layer_extruded->layer, layer_cache_item.overlapping); support_layer.support_fills.append(std::move(layer_cache_item.layer_extruded->extrusions)); } + + // Orca: Generate iron toolpath for contact layer + if (!layer_cache.polys_to_iron.empty()) { + auto f = std::unique_ptr(Fill::new_from_type(support_params.ironing_pattern)); + f->set_bounding_box(bbox_object); + f->layer_id = support_layer.id(); + f->z = support_layer.print_z; + f->overlap = 0; + f->angle = layer_cache.ironing_angle; + f->spacing = support_params.ironing_spacing; + f->link_max_length = (coord_t) scale_(3. * f->spacing); + + ExPolygons polys_to_iron = union_safety_offset_ex(layer_cache.polys_to_iron); + layer_cache.polys_to_iron.clear(); + + // Find the layer above that directly overlaps current layer, clip the overlapped part + if (support_layer_id < support_layers.size() - 1) { + const auto& upper_layer = support_layers[support_layer_id + 1]; + if (!upper_layer->support_islands.empty() && upper_layer->bottom_z() <= support_layer.print_z + EPSILON) { + polys_to_iron = diff_ex(polys_to_iron, upper_layer->support_islands); + } + } + + fill_expolygons_generate_paths( + // Destination + support_layer.support_fills.entities, + // Regions to fill + std::move(polys_to_iron), + // Filler and its parameters + f.get(), 1.f, + // Extrusion parameters + ExtrusionRole::erIroning, support_params.ironing_flow); + } } }); diff --git a/src/libslic3r/Support/SupportParameters.hpp b/src/libslic3r/Support/SupportParameters.hpp index bcc85e2202..655ee0d806 100644 --- a/src/libslic3r/Support/SupportParameters.hpp +++ b/src/libslic3r/Support/SupportParameters.hpp @@ -48,6 +48,11 @@ struct SupportParameters { this->support_material_interface_flow = Slic3r::support_material_interface_flow(&object, float(slicing_params.layer_height)); this->raft_interface_flow = support_material_interface_flow; + this->ironing = object_config.support_ironing; + this->ironing_flow = support_material_interface_flow.with_height(support_material_interface_flow.height() * 0.01 * object_config.support_ironing_flow.value); + this->ironing_spacing = object_config.support_ironing_spacing; + this->ironing_pattern = object_config.support_ironing_pattern; + // Calculate a minimum support layer height as a minimum over all extruders, but not smaller than 10um. this->support_layer_height_min = scaled(0.01); for (auto lh : print_config.min_layer_height.values) @@ -90,9 +95,11 @@ struct SupportParameters { this->base_angle = Geometry::deg2rad(float(object_config.support_angle.value)); this->interface_angle = Geometry::deg2rad(float(object_config.support_angle.value + 90.)); - this->interface_spacing = object_config.support_interface_spacing.value + this->support_material_interface_flow.spacing(); + // Orca: Force solid support interface when using support ironing + this->interface_spacing = (this->ironing ? 0 : object_config.support_interface_spacing.value) + this->support_material_interface_flow.spacing(); this->interface_density = std::min(1., this->support_material_interface_flow.spacing() / this->interface_spacing); - double raft_interface_spacing = object_config.support_interface_spacing.value + this->raft_interface_flow.spacing(); + // Orca: Force solid support interface when using support ironing + double raft_interface_spacing = (this->ironing ? 0 : object_config.support_interface_spacing.value) + this->raft_interface_flow.spacing(); this->raft_interface_density = std::min(1., this->raft_interface_flow.spacing() / raft_interface_spacing); this->support_spacing = object_config.support_base_pattern_spacing.value + this->support_material_flow.spacing(); this->support_density = std::min(1., this->support_material_flow.spacing() / this->support_spacing); @@ -260,6 +267,11 @@ struct SupportParameters { bool independent_layer_height = false; const double thresh_big_overhang = Slic3r::sqr(scale_(10)); + + bool ironing; + Flow ironing_flow; // Flow at the interface ironing. + InfillPattern ironing_pattern; + float ironing_spacing; }; } // namespace Slic3r diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 78d8aaeff0..4910eb346e 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -224,6 +224,17 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con apply(config, &new_conf); is_msg_dlg_already_exist = false; } + if (config->opt_float("support_ironing_spacing") < 0.05) + { + const wxString msg_text = _(L("Too small ironing spacing.\nReset to 0.1")); + MessageDialog dialog(nullptr, msg_text, "", wxICON_WARNING | wxOK); + DynamicPrintConfig new_conf = *config; + is_msg_dlg_already_exist = true; + dialog.ShowModal(); + new_conf.set_key_value("support_ironing_spacing", new ConfigOptionFloat(0.1)); + apply(config, &new_conf); + is_msg_dlg_already_exist = false; + } if (config->option("initial_layer_print_height")->value < EPSILON) { @@ -634,10 +645,18 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co toggle_line("bridge_no_support", !support_is_normal_tree); toggle_line("support_critical_regions_only", is_auto(support_type) && support_is_tree); - for (auto el : { "support_interface_spacing", "support_interface_filament", + for (auto el : { "support_interface_filament", "support_interface_loop_pattern", "support_bottom_interface_spacing" }) toggle_field(el, have_support_material && have_support_interface); + bool can_ironing_support = have_raft || (have_support_material && config->opt_int("support_interface_top_layers") > 0); + toggle_field("support_ironing", can_ironing_support); + bool has_support_ironing = can_ironing_support && config->opt_bool("support_ironing"); + for (auto el : {"support_ironing_pattern", "support_ironing_flow", "support_ironing_spacing" }) + toggle_line(el, has_support_ironing); + // Orca: Force solid support interface when using support ironing + toggle_field("support_interface_spacing", have_support_material && have_support_interface && !has_support_ironing); + bool have_skirt_height = have_skirt && (config->opt_int("skirt_height") > 1 || config->opt_enum("draft_shield") != dsEnabled); toggle_line("support_speed", have_support_material || have_skirt_height); @@ -656,8 +675,10 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co toggle_field(el, have_support_material && !(support_is_normal_tree && !have_raft)); bool has_ironing = (config->opt_enum("ironing_type") != IroningType::NoIroning); - for (auto el : { "ironing_pattern", "ironing_flow", "ironing_spacing", "ironing_speed", "ironing_angle", "ironing_inset"}) + for (auto el : { "ironing_pattern", "ironing_flow", "ironing_spacing", "ironing_angle", "ironing_inset"}) toggle_line(el, has_ironing); + + toggle_line("ironing_speed", has_ironing || has_support_ironing); bool have_sequential_printing = (config->opt_enum("print_sequence") == PrintSequence::ByObject); // for (auto el : { "extruder_clearance_radius", "extruder_clearance_height_to_rod", "extruder_clearance_height_to_lid" }) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 8ee8b60c77..b343930caa 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2090,7 +2090,6 @@ void TabPrint::build() optgroup = page->new_optgroup(L("Ironing"), L"param_ironing"); optgroup->append_single_option_line("ironing_type", "parameter/ironing"); optgroup->append_single_option_line("ironing_pattern"); - optgroup->append_single_option_line("ironing_speed"); optgroup->append_single_option_line("ironing_flow"); optgroup->append_single_option_line("ironing_spacing"); optgroup->append_single_option_line("ironing_inset"); @@ -2203,6 +2202,7 @@ void TabPrint::build() optgroup->append_single_option_line("internal_solid_infill_speed"); optgroup->append_single_option_line("top_surface_speed"); optgroup->append_single_option_line("gap_infill_speed"); + optgroup->append_single_option_line("ironing_speed"); optgroup->append_single_option_line("support_speed"); optgroup->append_single_option_line("support_interface_speed"); optgroup = page->new_optgroup(L("Overhang speed"), L"param_overhang_speed", 15); @@ -2278,6 +2278,12 @@ void TabPrint::build() optgroup->append_single_option_line("support_interface_filament", "support#support-filament"); optgroup->append_single_option_line("support_interface_not_for_body", "support#support-filament"); + optgroup = page->new_optgroup(L("Support ironing"), L"param_ironing"); + optgroup->append_single_option_line("support_ironing"); + optgroup->append_single_option_line("support_ironing_pattern"); + optgroup->append_single_option_line("support_ironing_flow"); + optgroup->append_single_option_line("support_ironing_spacing"); + //optgroup = page->new_optgroup(L("Options for support material and raft")); // Support