diff --git a/lib/Slic3r/Print/GCode.pm b/lib/Slic3r/Print/GCode.pm index ad7967e39..a5bbbd556 100644 --- a/lib/Slic3r/Print/GCode.pm +++ b/lib/Slic3r/Print/GCode.pm @@ -480,7 +480,9 @@ sub process_layer { # and also because we avoid travelling on other things when printing it if ($layer->isa('Slic3r::Layer::Support')) { if ($layer->support_interface_fills->count > 0) { - $gcode .= $self->_gcodegen->set_extruder($object->config->support_material_interface_extruder-1); + # Don't change extruder if the extruder is set to 0. Use the current extruder instead. + $gcode .= $self->_gcodegen->set_extruder($object->config->support_material_interface_extruder-1) + if ($object->config->support_material_interface_extruder > 0); for my $path (@{$layer->support_interface_fills->chained_path_from($self->_gcodegen->last_pos, 0)}) { if ($path->isa('Slic3r::ExtrusionMultiPath')) { $gcode .= $self->_gcodegen->extrude_multipath($path, 'support material interface', $object->config->get_abs_value('support_material_interface_speed')); @@ -490,7 +492,9 @@ sub process_layer { } } if ($layer->support_fills->count > 0) { - $gcode .= $self->_gcodegen->set_extruder($object->config->support_material_extruder-1); + # Don't change extruder if the extruder is set to 0. Use the current extruder instead. + $gcode .= $self->_gcodegen->set_extruder($object->config->support_material_extruder-1) + if ($object->config->support_material_extruder > 0); for my $path (@{$layer->support_fills->chained_path_from($self->_gcodegen->last_pos, 0)}) { if ($path->isa('Slic3r::ExtrusionMultiPath')) { $gcode .= $self->_gcodegen->extrude_multipath($path, 'support material', $object->config->get_abs_value('support_material_speed')); diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index c0d80629c..3e79a3857 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -150,6 +150,7 @@ sub prepare_infill { # Decide what surfaces are to be filled. # Here the S_TYPE_TOP / S_TYPE_BOTTOMBRIDGE / S_TYPE_BOTTOM infill is turned to just S_TYPE_INTERNAL if zero top / bottom infill layers are configured. # Also tiny S_TYPE_INTERNAL surfaces are turned to S_TYPE_INTERNAL_SOLID. +# BOOST_LOG_TRIVIAL(info) << "Preparing fill surfaces..."; $_->prepare_fill_surfaces for map @{$_->regions}, @{$self->layers}; # this will detect bridges and reverse bridges @@ -262,28 +263,8 @@ sub generate_support_material { if (($self->config->support_material || $self->config->raft_layers > 0) && scalar(@{$self->layers}) > 1) { $self->print->status_cb->(85, "Generating support material"); - if (0) { - # Old supports, Perl implementation. - my $first_layer_flow = Slic3r::Flow->new_from_width( - width => ($self->print->config->first_layer_extrusion_width || $self->config->support_material_extrusion_width), - role => FLOW_ROLE_SUPPORT_MATERIAL, - nozzle_diameter => $self->print->config->nozzle_diameter->[ $self->config->support_material_extruder-1 ] - // $self->print->config->nozzle_diameter->[0], - layer_height => $self->config->get_abs_value('first_layer_height'), - bridge_flow_ratio => 0, - ); - my $support_material = Slic3r::Print::SupportMaterial->new( - print_config => $self->print->config, - object_config => $self->config, - first_layer_flow => $first_layer_flow, - flow => $self->support_material_flow, - interface_flow => $self->support_material_flow(FLOW_ROLE_SUPPORT_MATERIAL_INTERFACE), - ); - $support_material->generate($self); - } else { - # New supports, C++ implementation. - $self->_generate_support_material; - } + # New supports, C++ implementation. + $self->_generate_support_material; } $self->set_step_done(STEP_SUPPORTMATERIAL); @@ -727,6 +708,8 @@ sub _simplify_slices { } } +# Used by t/support.t and by GCode.pm to export support line width as a comment. +# To be removed. sub support_material_flow { my ($self, $role) = @_; diff --git a/slic3r.pl b/slic3r.pl index a593f93c9..aa6540546 100755 --- a/slic3r.pl +++ b/slic3r.pl @@ -540,9 +540,11 @@ $j --infill-extruder Extruder to use for infill (1+, default: $config->{infill_extruder}) --solid-infill-extruder Extruder to use for solid infill (1+, default: $config->{solid_infill_extruder}) --support-material-extruder - Extruder to use for support material, raft and skirt (1+, default: $config->{support_material_extruder}) + Extruder to use for support material, raft and skirt + (1+, 0 to use the current extruder to minimize tool changes, default: $config->{support_material_extruder}) --support-material-interface-extruder - Extruder to use for support material interface (1+, default: $config->{support_material_interface_extruder}) + Extruder to use for support material interface + (1+, 0 to use the current extruder to minimize tool changes, default: $config->{support_material_interface_extruder}) --ooze-prevention Drop temperature and park extruders outside a full skirt for automatic wiping (default: no) --standby-temperature-delta diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index e04d4ac79..6e2fdb4f3 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -323,13 +323,26 @@ std::set Print::support_material_extruders() const { std::set extruders; - + bool support_uses_current_extruder = false; + FOREACH_OBJECT(this, object) { if ((*object)->has_support_material()) { - extruders.insert((*object)->config.support_material_extruder - 1); - extruders.insert((*object)->config.support_material_interface_extruder - 1); + if ((*object)->config.support_material_extruder == 0) + support_uses_current_extruder = true; + else + extruders.insert((*object)->config.support_material_extruder - 1); + if ((*object)->config.support_material_interface_extruder == 0) + support_uses_current_extruder = true; + else + extruders.insert((*object)->config.support_material_interface_extruder - 1); } } + + if (support_uses_current_extruder) { + // Add all object extruders to the support extruders as it is not know which one will be used to print supports. + std::set object_extruders = this->object_extruders(); + extruders.insert(object_extruders.begin(), object_extruders.end()); + } return extruders; } @@ -653,6 +666,17 @@ Print::validate() const FOREACH_OBJECT(this, i_object) { PrintObject* object = *i_object; + + if ((object->config.support_material_extruder == -1 || object->config.support_material_interface_extruder == -1) && + (object->config.raft_layers > 0 || object->config.support_material.value)) { + // The object has some form of support and either support_material_extruder or support_material_interface_extruder + // will be printed with the current tool without a forced tool change. Play safe, assert that all object nozzles + // are of the same diameter. + if (nozzle_diameters.size() > 1) + return "Printing with multiple extruders of differing nozzle diameters. " + "If support is to be printed with the current extruder (support_material_extruder == 0 or support_material_interface_extruder == 0), ", + "all nozzles have to be of the same diameter."; + } // validate first_layer_height double first_layer_height = object->config.get_abs_value("first_layer_height"); @@ -662,7 +686,9 @@ Print::validate() const size_t first_layer_extruder = object->config.raft_layers == 1 ? object->config.support_material_interface_extruder-1 : object->config.support_material_extruder-1; - first_layer_min_nozzle_diameter = this->config.nozzle_diameter.get_at(first_layer_extruder); + first_layer_min_nozzle_diameter = (first_layer_extruder == size_t(-1)) ? + min_nozzle_diameter : + this->config.nozzle_diameter.get_at(first_layer_extruder); } else { // if we don't have raft layers, any nozzle diameter is potentially used in first layer first_layer_min_nozzle_diameter = min_nozzle_diameter; diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index b11ada955..1f58d308d 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -1176,9 +1176,9 @@ PrintConfigDef::PrintConfigDef() def = this->add("support_material_extruder", coInt); def->label = "Support material/raft/skirt extruder"; def->category = "Extruders"; - def->tooltip = "The extruder to use when printing support material, raft and skirt."; + def->tooltip = "The extruder to use when printing support material, raft and skirt (1+, 0 to use the current extruder to minimize tool changes)."; def->cli = "support-material-extruder=i"; - def->min = 1; + def->min = 0; def->default_value = new ConfigOptionInt(1); def = this->add("support_material_extrusion_width", coFloatOrPercent); @@ -1199,9 +1199,9 @@ PrintConfigDef::PrintConfigDef() def = this->add("support_material_interface_extruder", coInt); def->label = "Support material/raft interface extruder"; def->category = "Extruders"; - def->tooltip = "The extruder to use when printing support material interface. This affects raft too."; + def->tooltip = "The extruder to use when printing support material interface (1+, 0 to use the current extruder to minimize tool changes). This affects raft too."; def->cli = "support-material-interface-extruder=i"; - def->min = 1; + def->min = 0; def->default_value = new ConfigOptionInt(1); def = this->add("support_material_interface_layers", coInt); diff --git a/xs/src/libslic3r/Slicing.cpp b/xs/src/libslic3r/Slicing.cpp index 8c3902ba3..2a070438b 100644 --- a/xs/src/libslic3r/Slicing.cpp +++ b/xs/src/libslic3r/Slicing.cpp @@ -27,6 +27,11 @@ SlicingParameters SlicingParameters::create_from_config( coordf_t first_layer_height = (object_config.first_layer_height.value <= 0) ? object_config.layer_height.value : object_config.first_layer_height.get_abs_value(object_config.layer_height.value); + // If object_config.support_material_extruder == 0 resp. object_config.support_material_interface_extruder == 0, + // print_config.nozzle_diameter.get_at(size_t(-1)) returns the 0th nozzle diameter, + // which is consistent with the requirement that if support_material_extruder == 0 resp. support_material_interface_extruder == 0, + // support will not trigger tool change, but it will use the current nozzle instead. + // In that case all the nozzles have to be of the same diameter. coordf_t support_material_extruder_dmr = print_config.nozzle_diameter.get_at(object_config.support_material_extruder.value - 1); coordf_t support_material_interface_extruder_dmr = print_config.nozzle_diameter.get_at(object_config.support_material_interface_extruder.value - 1); bool soluble_interface = object_config.support_material_contact_distance.value == 0.; diff --git a/xs/src/libslic3r/SupportMaterial.cpp b/xs/src/libslic3r/SupportMaterial.cpp index 6f9991a51..48d19715a 100644 --- a/xs/src/libslic3r/SupportMaterial.cpp +++ b/xs/src/libslic3r/SupportMaterial.cpp @@ -150,6 +150,7 @@ PrintObjectSupportMaterial::PrintObjectSupportMaterial(const PrintObject *object frSupportMaterial, // The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution. (object->config.support_material_extrusion_width.value > 0) ? object->config.support_material_extrusion_width : object->config.extrusion_width, + // if object->config.support_material_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), get_at will return the 0th component. float(object->print()->config.nozzle_diameter.get_at(object->config.support_material_extruder-1)), float(slicing_params.layer_height), false)), @@ -157,6 +158,7 @@ PrintObjectSupportMaterial::PrintObjectSupportMaterial(const PrintObject *object frSupportMaterialInterface, // The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution. (object->config.support_material_extrusion_width > 0) ? object->config.support_material_extrusion_width : object->config.extrusion_width, + // if object->config.support_material_interface_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), get_at will return the 0th component. float(object->print()->config.nozzle_diameter.get_at(object->config.support_material_interface_extruder-1)), float(slicing_params.layer_height), false)), @@ -636,7 +638,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ #ifdef SLIC3R_DEBUG Slic3r::SVG::export_expolygons( - debug_out_path("support-top-contacts-filtered-run%d-layer%d-region%d.svg", iRun, layer_id, it_layerm - layer.regions.begin()), + debug_out_path("support-top-contacts-filtered-run%d-layer%d-region%d-z%f.svg", iRun, layer_id, it_layerm - layer.regions.begin(), layer.print_z), union_ex(diff_polygons, false)); #endif /* SLIC3R_DEBUG */ @@ -758,7 +760,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ bbox.align_to_grid(grid_resolution); grid.set_bbox(bbox); grid.create(contact_polygons, grid_resolution); - grid.calculate_sdf(); + grid.calculate_sdf(); // Extract a bounding contour from the grid, trim by the object. // 1) infill polygons, expand them by half the extrusion width + a tiny bit of extra. new_layer.polygons = diff( @@ -772,6 +774,9 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ false)); } #endif + // Even after the contact layer was expanded into a grid, some of the contact islands may be too tiny to be extruded. + // Remove those tiny islands from new_layer.polygons and new_layer.contact_polygons. + // Store the overhang polygons. // The overhang polygons are used in the path generator for planning of the contact loops. @@ -2182,33 +2187,20 @@ void PrintObjectSupportMaterial::generate_toolpaths( MyLayerExtruded top_contact_layer; MyLayerExtruded base_layer; MyLayerExtruded interface_layer; - MyLayerExtrudedPtrs mylayers; - // Increment the layer indices to find a layer at support_layer.print_z. for (; idx_layer_bottom_contact < bottom_contacts .size() && bottom_contacts [idx_layer_bottom_contact]->print_z < support_layer.print_z - EPSILON; ++ idx_layer_bottom_contact) ; for (; idx_layer_top_contact < top_contacts .size() && top_contacts [idx_layer_top_contact ]->print_z < support_layer.print_z - EPSILON; ++ idx_layer_top_contact ) ; for (; idx_layer_intermediate < intermediate_layers.size() && intermediate_layers[idx_layer_intermediate ]->print_z < support_layer.print_z - EPSILON; ++ idx_layer_intermediate ) ; for (; idx_layer_inteface < interface_layers .size() && interface_layers [idx_layer_inteface ]->print_z < support_layer.print_z - EPSILON; ++ idx_layer_inteface ) ; // Copy polygons from the layers. - mylayers.reserve(4); - if (idx_layer_bottom_contact < bottom_contacts.size() && bottom_contacts[idx_layer_bottom_contact]->print_z < support_layer.print_z + EPSILON) { + if (idx_layer_bottom_contact < bottom_contacts.size() && bottom_contacts[idx_layer_bottom_contact]->print_z < support_layer.print_z + EPSILON) bottom_contact_layer.layer = bottom_contacts[idx_layer_bottom_contact]; - mylayers.push_back(&bottom_contact_layer); - } - if (idx_layer_top_contact < top_contacts.size() && top_contacts[idx_layer_top_contact]->print_z < support_layer.print_z + EPSILON) { + if (idx_layer_top_contact < top_contacts.size() && top_contacts[idx_layer_top_contact]->print_z < support_layer.print_z + EPSILON) top_contact_layer.layer = top_contacts[idx_layer_top_contact]; - mylayers.push_back(&top_contact_layer); - } - if (idx_layer_inteface < interface_layers.size() && interface_layers[idx_layer_inteface]->print_z < support_layer.print_z + EPSILON) { + if (idx_layer_inteface < interface_layers.size() && interface_layers[idx_layer_inteface]->print_z < support_layer.print_z + EPSILON) interface_layer.layer = interface_layers[idx_layer_inteface]; - mylayers.push_back(&interface_layer); - } - if (idx_layer_intermediate < intermediate_layers.size() && intermediate_layers[idx_layer_intermediate]->print_z < support_layer.print_z + EPSILON) { + if (idx_layer_intermediate < intermediate_layers.size() && intermediate_layers[idx_layer_intermediate]->print_z < support_layer.print_z + EPSILON) base_layer.layer = intermediate_layers[idx_layer_intermediate]; - mylayers.push_back(&base_layer); - } - // Sort the layers with the same print_z coordinate by their heights, thickest first. - std::sort(mylayers.begin(), mylayers.end(), [](const MyLayerExtruded *p1, const MyLayerExtruded *p2) { return p1->layer->height > p2->layer->height; }); if (m_object_config->support_material_interface_layers == 0) { // If no interface layers were requested, we treat the contact layer exactly as a generic base layer. @@ -2316,6 +2308,18 @@ void PrintObjectSupportMaterial::generate_toolpaths( erSupportMaterial, flow); } + MyLayerExtrudedPtrs mylayers; + mylayers.reserve(4); + if (! bottom_contact_layer.empty()) + mylayers.push_back(&bottom_contact_layer); + if (! top_contact_layer.empty()) + mylayers.push_back(&top_contact_layer); + if (! interface_layer.empty()) + mylayers.push_back(&interface_layer); + if (! base_layer.empty()) + mylayers.push_back(&base_layer); + // Sort the layers with the same print_z coordinate by their heights, thickest first. + std::sort(mylayers.begin(), mylayers.end(), [](const MyLayerExtruded *p1, const MyLayerExtruded *p2) { return p1->layer->height > p2->layer->height; }); // Collect the support areas with this print_z into islands, as there is no need // for retraction over these islands. Polygons polys;