Ironing support interfaces (#9548)
Some checks are pending
Build all / Build All (push) Waiting to run
Build all / Flatpak (push) Waiting to run

* 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
This commit is contained in:
Noisyfox 2025-06-19 15:19:05 +08:00 committed by GitHub
parent 961b73c6be
commit b9cce6c179
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 171 additions and 16 deletions

View file

@ -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::vector<ObjectBy
return gcode;
}
std::string GCode::extrude_support(const ExtrusionEntityCollection &support_fills)
std::string GCode::extrude_support(const ExtrusionEntityCollection &support_fills, const ExtrusionRole support_extrusion_role)
{
static constexpr const char *support_label = "support material";
static constexpr const char *support_interface_label = "support material interface";
const char* support_transition_label = "support transition";
static constexpr const char* support_transition_label = "support transition";
static constexpr const char* support_ironing_label = "support ironing";
std::string gcode;
if (! support_fills.entities.empty()) {
ExtrusionEntitiesPtr extrusions;
extrusions.reserve(support_fills.entities.size());
for (ExtrusionEntity* ee : support_fills.entities) {
const auto role = ee->role();
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");

View file

@ -449,7 +449,7 @@ private:
std::string extrude_perimeters(const Print& print, const std::vector<ObjectByExtruder::Island::Region>& by_region, bool is_first_layer, bool is_infill_first);
std::string extrude_infill(const Print& print, const std::vector<ObjectByExtruder::Island::Region>& 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);

View file

@ -789,6 +789,7 @@ static std::vector<std::string> 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",

View file

@ -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<InfillPattern>::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<InfillPattern>(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");

View file

@ -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<InfillPattern>, support_ironing_pattern))
((ConfigOptionPercent, support_ironing_flow))
((ConfigOptionFloat, support_ironing_spacing))
((ConfigOptionFloat, xy_hole_compensation))
((ConfigOptionFloat, xy_contour_compensation))
((ConfigOptionBool, flush_into_objects))

View file

@ -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"

View file

@ -1605,6 +1605,9 @@ void generate_support_toolpaths(
SupportGeneratorLayerExtruded base_interface_layer;
boost::container::static_vector<LayerCacheItem, 5> 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<size_t>(n_raft_layers, support_layers.size()),
[&support_layers, &layer_caches]
[&support_layers, &layer_caches, &support_params, &bbox_object]
(const tbb::blocked_range<size_t>& 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>(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);
}
}
});

View file

@ -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<coord_t>(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

View file

@ -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<ConfigOptionFloat>("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<DraftShield>("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<IroningType>("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<PrintSequence>("print_sequence") == PrintSequence::ByObject);
// for (auto el : { "extruder_clearance_radius", "extruder_clearance_height_to_rod", "extruder_clearance_height_to_lid" })

View file

@ -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