diff --git a/resources/ui_layout/print.ui b/resources/ui_layout/print.ui index 9c9c62a04..e5e6298ea 100644 --- a/resources/ui_layout/print.ui +++ b/resources/ui_layout/print.ui @@ -177,6 +177,7 @@ group:Skirt setting:skirt_distance setting:skirt_height setting:draft_shield + setting:skirt_brim setting:min_skirt_length group:Brim setting:brim_width diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 48a60af38..8121e3f43 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -833,6 +833,8 @@ namespace DoExport { } if (compute_min_mm3_per_mm.is_compatible({ erSkirt })) { mm3_per_mm.push_back(compute_min_mm3_per_mm.reset_use_get(print.skirt())); + if(print.skirt_first_layer()) + mm3_per_mm.push_back(compute_min_mm3_per_mm.reset_use_get(*print.skirt_first_layer())); mm3_per_mm.push_back(compute_min_mm3_per_mm.reset_use_get(print.brim())); } // filter out 0-width segments @@ -2082,7 +2084,14 @@ namespace Skirt { // not at the print_z of the interlaced support material layers. std::map> skirt_loops_per_extruder_out; if (skirt_done.empty() && print.has_skirt() && ! print.skirt().entities.empty()) { - skirt_loops_per_extruder_all_printing(print, layer_tools, skirt_loops_per_extruder_out); + if (print.skirt_first_layer()) { + size_t n_loops = print.skirt_first_layer()->entities.size(); + size_t n_tools = layer_tools.extruders.size(); + size_t lines_per_extruder = (n_loops + n_tools - 1) / n_tools; + for (size_t i = 0; i < n_loops; i += lines_per_extruder) + skirt_loops_per_extruder_out[layer_tools.extruders[i / lines_per_extruder]] = std::pair(i, std::min(i + lines_per_extruder, n_loops)); + } else + skirt_loops_per_extruder_all_printing(print, layer_tools, skirt_loops_per_extruder_out); skirt_done.emplace_back(layer_tools.print_z); } return skirt_loops_per_extruder_out; @@ -2443,9 +2452,10 @@ void GCode::process_layer( Flow layer_skirt_flow(print.skirt_flow(extruder_id)); layer_skirt_flow.height = float(m_skirt_done.back() - (m_skirt_done.size() == 1 ? 0. : m_skirt_done[m_skirt_done.size() - 2])); double mm3_per_mm = layer_skirt_flow.mm3_per_mm(); + const ExtrusionEntityCollection& coll = first_layer && print.skirt_first_layer() ? *print.skirt_first_layer() : print.skirt(); for (size_t i = loops.first; i < loops.second; ++i) { // Adjust flow according to this layer's layer height. - ExtrusionLoop loop = *dynamic_cast(print.skirt().entities[i]); + ExtrusionLoop loop = *dynamic_cast(coll.entities[i]); for (ExtrusionPath &path : loop.paths) { assert(layer_skirt_flow.height == layer_skirt_flow.height); assert(mm3_per_mm == mm3_per_mm); @@ -2475,6 +2485,7 @@ void GCode::process_layer( m_avoid_crossing_perimeters.disable_once(); } //extrude object-only skirt + //TODO: use it also for wiping like the other one (as they are exlusiev) if (single_object_instance_idx != size_t(-1) && !layers.front().object()->skirt().empty() && extruder_id == layer_tools.extruders.front()) { //if first layer, ask for a bigger lift for travel to object, to be on the safe side @@ -2483,8 +2494,12 @@ void GCode::process_layer( const PrintObject *print_object = layers.front().object(); this->set_origin(unscale(print_object->instances()[single_object_instance_idx].shift)); if (this->m_layer != nullptr && (this->m_layer->id() < m_config.skirt_height || print.has_infinite_skirt() )) { - for (const ExtrusionEntity *ee : print_object->skirt().entities) - gcode += this->extrude_entity(*ee, "", m_config.support_material_speed.value); + if(first_layer && print.skirt_first_layer()) + for (const ExtrusionEntity* ee : print_object->skirt_first_layer()->entities) + gcode += this->extrude_entity(*ee, "", m_config.support_material_speed.value); + else + for (const ExtrusionEntity *ee : print_object->skirt().entities) + gcode += this->extrude_entity(*ee, "", m_config.support_material_speed.value); } } //extrude object-only brim diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 4cf464fdd..2353609f8 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -528,6 +528,7 @@ const std::vector& Preset::print_options() "travel_acceleration", // skirt "skirts", "skirt_distance", "skirt_height", + "skirt_brim", "skirt_extrusion_width", "min_skirt_length", "draft_shield", diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 38883733d..2eb70fa20 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -200,6 +200,7 @@ bool Print::invalidate_state_by_config_options(const std::vectorhas_skirt()) { - int skirts = m_config.skirts.value; + int skirts = m_config.skirts.value + m_config.skirt_brim.value; if (skirts == 0 && this->has_infinite_skirt()) skirts = 1; Flow skirt_flow = this->skirt_flow(); extra = std::max( @@ -1748,11 +1749,13 @@ void Print::process() } if (this->set_started(psSkirt)) { m_skirt.clear(); + m_skirt_first_layer.reset(); m_skirt_convex_hull.clear(); m_first_layer_convex_hull.points.clear(); for (PrintObject *obj : m_objects) { obj->m_skirt.clear(); + obj->m_skirt_first_layer.reset(); } if (this->has_skirt()) { this->set_status(88, L("Generating skirt")); @@ -1762,11 +1765,11 @@ void Print::process() const std::vector copies{ obj->instances() }; obj->m_instances.clear(); obj->m_instances.emplace_back(); - this->_make_skirt({ obj }, obj->m_skirt); + this->_make_skirt({ obj }, obj->m_skirt, obj->m_skirt_first_layer); obj->m_instances = copies; } } else { - this->_make_skirt(m_objects, m_skirt); + this->_make_skirt(m_objects, m_skirt, m_skirt_first_layer); } } this->set_done(psSkirt); @@ -1888,7 +1891,7 @@ std::string Print::export_gcode(const std::string& path_template, GCodeProcessor return path.c_str(); } -void Print::_make_skirt(const PrintObjectPtrs &objects, ExtrusionEntityCollection &out) +void Print::_make_skirt(const PrintObjectPtrs &objects, ExtrusionEntityCollection &out, std::optional& out_first_layer) { // First off we need to decide how tall the skirt must be. // The skirt_height option from config is expressed in layers, but our @@ -1973,9 +1976,11 @@ void Print::_make_skirt(const PrintObjectPtrs &objects, ExtrusionEntityCollectio // Number of skirt loops per skirt layer. size_t n_skirts = m_config.skirts.value; + size_t n_skirts_first_layer = n_skirts + m_config.skirt_brim.value; if (this->has_infinite_skirt() && n_skirts == 0) n_skirts = 1; - + if (m_config.skirt_brim.value > 0) + out_first_layer.emplace(); // Initial offset of the brim inner edge from the object (possible with a support & raft). // The skirt will touch the brim if the brim is extruded. auto distance = float(scale_(m_config.skirt_distance.value) - this->skirt_flow(extruders[extruders.size()-1]).spacing()/2.); @@ -1986,7 +1991,8 @@ void Print::_make_skirt(const PrintObjectPtrs &objects, ExtrusionEntityCollectio // Draw outlines from outside to inside. // Loop while we have less skirts than required or any extruder hasn't reached the min length if any. std::vector extruded_length(extruders.size(), 0.); - for (size_t i = n_skirts, extruder_idx = 0, nb_skirts = 1; i > 0; -- i) { + for (size_t i = std::max(n_skirts, n_skirts_first_layer), extruder_idx = 0, nb_skirts = 1; i > 0; -- i) { + bool first_layer_only = i <= (n_skirts_first_layer - n_skirts); Flow flow = this->skirt_flow(extruders[extruders.size() - (1+ extruder_idx)]); float spacing = flow.spacing(); double mm3_per_mm = flow.mm3_per_mm(); @@ -2016,8 +2022,11 @@ void Print::_make_skirt(const PrintObjectPtrs &objects, ExtrusionEntityCollectio eloop.paths.back().polyline = loop.split_at_first_point(); //we make it clowkwise, but as it will be reversed, it will be ccw eloop.make_clockwise(); - out.append(eloop); - if (m_config.min_skirt_length.value > 0) { + if(!first_layer_only) + out.append(eloop); + if(out_first_layer) + out_first_layer->append(eloop); + if (m_config.min_skirt_length.value > 0 && !first_layer_only) { // The skirt length is limited. Sum the total amount of filament length extruded, in mm. extruded_length[extruder_idx] += unscale(loop.length()) * extruders_e_per_mm[extruder_idx]; if (extruded_length[extruder_idx] < m_config.min_skirt_length.value) { @@ -2043,6 +2052,8 @@ void Print::_make_skirt(const PrintObjectPtrs &objects, ExtrusionEntityCollectio } // Brims were generated inside out, reverse to print the outmost contour first. out.reverse(); + if (out_first_layer) + out_first_layer->reverse(); // Remember the outer edge of the last skirt line extruded as m_skirt_convex_hull. for (Polygon &poly : offset(convex_hull, distance + 0.5f * float(this->skirt_flow(extruders[extruders.size() - 1]).scaled_spacing()), ClipperLib::jtRound, float(scale_(0.1)))) diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index ba79a4db5..300029d02 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -202,6 +202,7 @@ public: void project_and_append_custom_facets(bool seam, EnforcerBlockerType type, std::vector& expolys) const; /// skirts if done per copy and not per platter + const std::optional& skirt_first_layer() const { return m_skirt_first_layer; } const ExtrusionEntityCollection& skirt() const { return m_skirt; } const ExtrusionEntityCollection& brim() const { return m_brim; } @@ -271,6 +272,7 @@ private: // Ordered collections of extrusion paths to build skirt loops and brim. // have to be duplicated per copy + std::optional m_skirt_first_layer; ExtrusionEntityCollection m_skirt; ExtrusionEntityCollection m_brim; @@ -460,6 +462,7 @@ public: // If zero, then the print is empty and the print shall not be executed. uint16_t num_object_instances() const; + const std::optional& skirt_first_layer() const { return m_skirt_first_layer; } const ExtrusionEntityCollection& skirt() const { return m_skirt; } const ExtrusionEntityCollection& brim() const { return m_brim; } // Convex hull of the 1st layer extrusions, for bed leveling and placing the initial purge line. @@ -501,7 +504,7 @@ private: t_config_option_keys &full_config_diff, DynamicPrintConfig &filament_overrides) const; - void _make_skirt(const PrintObjectPtrs &objects, ExtrusionEntityCollection &out); + void _make_skirt(const PrintObjectPtrs &objects, ExtrusionEntityCollection &out, std::optional &out_first_layer); void _make_brim(const Flow &flow, const PrintObjectPtrs &objects, ExPolygons &unbrimmable, ExtrusionEntityCollection &out); void _make_brim_ears(const Flow &flow, const PrintObjectPtrs &objects, ExPolygons &unbrimmable, ExtrusionEntityCollection &out); void _make_brim_interior(const Flow &flow, const PrintObjectPtrs &objects, ExPolygons &unbrimmable, ExtrusionEntityCollection &out); @@ -525,6 +528,7 @@ private: PrintRegionPtrs m_regions; // Ordered collections of extrusion paths to build skirt loops and brim. + std::optional m_skirt_first_layer; ExtrusionEntityCollection m_skirt; ExtrusionEntityCollection m_brim; // Convex hull of the 1st layer extrusions. diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 565160bbd..7c1448627 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -674,6 +674,13 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionBool(true)); + def = this->add("draft_shield", coBool); + def->label = L("Draft shield"); + def->tooltip = L("If enabled, the skirt will be as tall as a highest printed object. " + "This is useful to protect an ABS or ASA print from warping and detaching from print bed due to wind draft."); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(false)); + def = this->add("duplicate_distance", coFloat); def->label = L("Distance between objects"); def->category = OptionCategory::output; @@ -3272,6 +3279,14 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionFloat(30); def->set_default_value(new ConfigOptionFloat(30)); #endif + def = this->add("skirt_brim", coInt); + def->label = L("Brim"); + def->full_label = L("Skirt brim"); + def->category = OptionCategory::skirtBrim; + def->tooltip = L("Extra skirt lines on the first layer."); + def->sidetext = L("lines"); + def->mode = comExpert; + def->set_default_value(new ConfigOptionInt(0)); def = this->add("skirt_distance", coFloat); def->label = L("Distance from object"); @@ -3287,7 +3302,7 @@ void PrintConfigDef::init_fff_params() def->label = L("Skirt height"); def->category = OptionCategory::skirtBrim; def->tooltip = L("Height of skirt expressed in layers. Set this to a tall value to use skirt " - "as a shield against drafts."); + "as a shield against drafts."); def->sidetext = L("layers"); def->mode = comAdvanced; def->set_default_value(new ConfigOptionInt(1)); @@ -3306,13 +3321,6 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloatOrPercent(0, false)); - def = this->add("draft_shield", coBool); - def->label = L("Draft shield"); - def->tooltip = L("If enabled, the skirt will be as tall as a highest printed object. " - "This is useful to protect an ABS or ASA print from warping and detaching from print bed due to wind draft."); - def->mode = comAdvanced; - def->set_default_value(new ConfigOptionBool(false)); - def = this->add("skirts", coInt); def->label = L("Loops (minimum)"); def->full_label = L("Skirt Loops"); @@ -5530,6 +5538,7 @@ void PrintConfigDef::to_prusa(t_config_option_key& opt_key, std::string& value, "retract_lift_top", "seam_angle_cost", "seam_travel_cost", +"skirt_brim", "skirt_extrusion_width", "small_perimeter_min_length", "small_perimeter_max_length", @@ -5754,7 +5763,10 @@ double PrintConfig::min_object_distance(const ConfigBase *config, double ref_hei const double first_layer_height = config->get_abs_value("first_layer_height"); //add the skirt - if (config->option("skirts")->getInt() > 0 && config->option("skirt_height")->getInt() >= 1 && !config->option("complete_objects_one_skirt")->getBool()) { + int skirts = config->option("skirts")->getInt(); + if (skirts > 0 && ref_height == 0) + skirts += config->option("skirt_brim")->getInt(); + if (skirts > 0 && config->option("skirt_height")->getInt() >= 1 && !config->option("complete_objects_one_skirt")->getBool()) { if (ref_height == 0) { skirt_dist = config->option("skirt_distance")->getFloat(); Flow skirt_flow = Flow::new_from_config_width( @@ -5763,7 +5775,7 @@ double PrintConfig::min_object_distance(const ConfigBase *config, double ref_hei (float)max_nozzle_diam, (float)first_layer_height ); - skirt_dist += skirt_flow.width + (skirt_flow.spacing() * ((double)config->option("skirts")->getInt() - 1)); + skirt_dist += skirt_flow.width + (skirt_flow.spacing() * ((double)skirts - 1)); base_dist = std::max(base_dist, skirt_dist + 1); //set to 0 becasue it's incorporated into the base_dist, so we don't want to be added in to it again. skirt_dist = 0; @@ -5777,7 +5789,7 @@ double PrintConfig::min_object_distance(const ConfigBase *config, double ref_hei (float)max_nozzle_diam, (float)first_layer_height ); - skirt_dist += skirt_flow.width + (skirt_flow.spacing() * ((double)config->option("skirts")->getInt() - 1)); + skirt_dist += skirt_flow.width + (skirt_flow.spacing() * ((double)skirts - 1)); } } } diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 80975546c..8953a294a 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1329,6 +1329,7 @@ public: ConfigOptionFloat resolution; ConfigOptionFloats retract_before_travel; ConfigOptionBools retract_layer_change; + ConfigOptionInt skirt_brim; ConfigOptionFloat skirt_distance; ConfigOptionInt skirt_height; ConfigOptionFloatOrPercent skirt_extrusion_width; @@ -1426,6 +1427,7 @@ protected: OPT_PTR(resolution); OPT_PTR(retract_before_travel); OPT_PTR(retract_layer_change); + OPT_PTR(skirt_brim); OPT_PTR(skirt_distance); OPT_PTR(skirt_extrusion_width); OPT_PTR(skirt_height); diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 2a302515c..6daccab2a 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -440,7 +440,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) bool have_skirt = config->opt_int("skirts") > 0; toggle_field("skirt_height", have_skirt && !config->opt_bool("draft_shield")); toggle_field("skirt_width", have_skirt); - for (auto el : { "skirt_distance", "draft_shield", "min_skirt_length" }) + for (auto el : { "skirt_distance", "skirt_brim", "draft_shield", "min_skirt_length" }) toggle_field(el, have_skirt); bool have_brim = config->opt_float("brim_width") > 0 || config->opt_float("brim_width_interior") > 0; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 3edd7a578..92811abb4 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5793,9 +5793,27 @@ void GLCanvas3D::_load_print_toolpaths() volume->print_zs.emplace_back(print_zs[i]); volume->offsets.emplace_back(volume->indexed_vertex_array.quad_indices.size()); volume->offsets.emplace_back(volume->indexed_vertex_array.triangle_indices.size()); - if (i == 0) + if (i == 0) { + //skirt & brim from print _3DScene::extrusionentity_to_verts(print->brim(), print_zs[i], Point(0, 0), *volume); - _3DScene::extrusionentity_to_verts(print->skirt(), print_zs[i], Point(0, 0), *volume); + if(print->skirt_first_layer()) + _3DScene::extrusionentity_to_verts(*print->skirt_first_layer(), print_zs[i], Point(0, 0), *volume); + //skirt & brim from objects + for (const PrintObject* print_object : print->objects()) { + if (!print_object->brim().empty()) + _3DScene::extrusionentity_to_verts(print_object->brim(), print_zs[i], Point(0, 0), *volume); + if (print_object->skirt_first_layer()) + _3DScene::extrusionentity_to_verts(*print_object->skirt_first_layer(), print_zs[i], Point(0, 0), *volume); + } + } + //skirts from print + if (i != 0 || !print->skirt_first_layer()) + _3DScene::extrusionentity_to_verts(print->skirt(), print_zs[i], Point(0, 0), *volume); + //skirts from objects + for (const PrintObject* print_object : print->objects()) { + if ( !print_object->skirt().empty() && (i != 0 || !print_object->skirt_first_layer())) + _3DScene::extrusionentity_to_verts(print_object->skirt(), print_zs[i], Point(0, 0), *volume); + } // Ensure that no volume grows over the limits. If the volume is too large, allocate a new one. if (volume->indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) { GLVolume &vol = *volume; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index f51a4edc5..5e00f67a1 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1984,7 +1984,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) "first_layer_extrusion_width", "perimeter_extrusion_width", "extrusion_width", - "skirts", "skirt_distance", "skirt_height", "draft_shield", + "skirts", "skirt_brim", "skirt_distance", "skirt_height", "draft_shield", "brim_width", "variable_layer_height", "nozzle_diameter", "single_extruder_multi_material", "wipe_tower", "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_brim",