diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index c7b2c8f78..26a206247 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1803,7 +1803,6 @@ namespace Skirt { static std::map> make_skirt_loops_per_extruder_1st_layer( const Print &print, - const std::vector & /*layers */, const LayerTools &layer_tools, // Heights (print_z) at which the skirt has already been extruded. std::vector &skirt_done) @@ -1811,7 +1810,8 @@ namespace Skirt { // Extrude skirt at the print_z of the raft layers and normal object layers // 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()) { + assert(skirt_done.empty()); + if (skirt_done.empty() && print.has_skirt() && ! print.skirt().entities.empty() && layer_tools.has_skirt) { skirt_loops_per_extruder_all_printing(print, layer_tools, skirt_loops_per_extruder_out); skirt_done.emplace_back(layer_tools.print_z); } @@ -1820,36 +1820,34 @@ namespace Skirt { static std::map> make_skirt_loops_per_extruder_other_layers( const Print &print, - const std::vector &layers, const LayerTools &layer_tools, - // First non-empty support layer. - const SupportLayer *support_layer, // Heights (print_z) at which the skirt has already been extruded. std::vector &skirt_done) { // Extrude skirt at the print_z of the raft layers and normal object layers // not at the print_z of the interlaced support material layers. std::map> skirt_loops_per_extruder_out; - if (print.has_skirt() && ! print.skirt().entities.empty() && + if (print.has_skirt() && ! print.skirt().entities.empty() && layer_tools.has_skirt && // Not enough skirt layers printed yet. //FIXME infinite or high skirt does not make sense for sequential print! - (skirt_done.size() < (size_t)print.config().skirt_height.value || print.has_infinite_skirt()) && + (skirt_done.size() < (size_t)print.config().skirt_height.value || print.has_infinite_skirt())) { + bool valid = ! skirt_done.empty() && skirt_done.back() < layer_tools.print_z - EPSILON; + assert(valid); // This print_z has not been extruded yet (sequential print) // FIXME: The skirt_done should not be empty at this point. The check is a workaround // of https://github.com/prusa3d/PrusaSlicer/issues/5652, but it deserves a real fix. - (! skirt_done.empty() && skirt_done.back() < layer_tools.print_z - EPSILON) && - // and this layer is an object layer, or it is a raft layer. - (layer_tools.has_object || support_layer->id() < (size_t)support_layer->object()->config().raft_layers.value)) { + if (valid) { #if 0 - // Prime just the first printing extruder. This is original Slic3r's implementation. - skirt_loops_per_extruder_out[layer_tools.extruders.front()] = std::pair(0, print.config().skirts.value); + // Prime just the first printing extruder. This is original Slic3r's implementation. + skirt_loops_per_extruder_out[layer_tools.extruders.front()] = std::pair(0, print.config().skirts.value); #else - // Prime all extruders planned for this layer, see - // https://github.com/prusa3d/PrusaSlicer/issues/469#issuecomment-322450619 - skirt_loops_per_extruder_all_printing(print, layer_tools, skirt_loops_per_extruder_out); + // Prime all extruders planned for this layer, see + // https://github.com/prusa3d/PrusaSlicer/issues/469#issuecomment-322450619 + skirt_loops_per_extruder_all_printing(print, layer_tools, skirt_loops_per_extruder_out); #endif - assert(!skirt_done.empty()); - skirt_done.emplace_back(layer_tools.print_z); + assert(!skirt_done.empty()); + skirt_done.emplace_back(layer_tools.print_z); + } } return skirt_loops_per_extruder_out; } @@ -1992,8 +1990,8 @@ void GCode::process_layer( // Extrude skirt at the print_z of the raft layers and normal object layers // not at the print_z of the interlaced support material layers. skirt_loops_per_extruder = first_layer ? - Skirt::make_skirt_loops_per_extruder_1st_layer(print, layers, layer_tools, m_skirt_done) : - Skirt::make_skirt_loops_per_extruder_other_layers(print, layers, layer_tools, support_layer, m_skirt_done); + Skirt::make_skirt_loops_per_extruder_1st_layer(print, layer_tools, m_skirt_done) : + Skirt::make_skirt_loops_per_extruder_other_layers(print, layer_tools, m_skirt_done); // Group extrusions by an extruder, then by an object, an island and a region. std::map> by_extruder; diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index fae4028de..8520cf35b 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -70,6 +70,20 @@ unsigned int LayerTools::extruder(const ExtrusionEntityCollection &extrusions, c return (extruder == 0) ? 0 : extruder - 1; } +static double calc_max_layer_height(const PrintConfig &config, double max_object_layer_height) +{ + double max_layer_height = std::numeric_limits::max(); + for (size_t i = 0; i < config.nozzle_diameter.values.size(); ++ i) { + double mlh = config.max_layer_height.values[i]; + if (mlh == 0.) + mlh = 0.75 * config.nozzle_diameter.values[i]; + max_layer_height = std::min(max_layer_height, mlh); + } + // The Prusa3D Fast (0.35mm layer height) print profile sets a higher layer height than what is normally allowed + // by the nozzle. This is a hack and it works by increasing extrusion width. See GH #3919. + return std::max(max_layer_height, max_object_layer_height); +} + // For the use case when each object is printed separately // (print.config().complete_objects is true). ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extruder, bool prime_multi_material) @@ -87,6 +101,7 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude zs.emplace_back(layer->print_z); this->initialize_layers(zs); } + double max_layer_height = calc_max_layer_height(object.print()->config(), object.config().layer_height); // Collect extruders reuqired to print the layers. this->collect_extruders(object, std::vector>()); @@ -94,9 +109,11 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude // Reorder the extruders to minimize tool switches. this->reorder_extruders(first_extruder); - this->fill_wipe_tower_partitions(object.print()->config(), object.layers().front()->print_z - object.layers().front()->height, object.config().layer_height); + this->fill_wipe_tower_partitions(object.print()->config(), object.layers().front()->print_z - object.layers().front()->height, max_layer_height); this->collect_extruder_statistics(prime_multi_material); + + this->mark_skirt_layers(object.print()->config(), max_layer_height); } // For the use case when all objects are printed at once. @@ -128,6 +145,7 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool } this->initialize_layers(zs); } + max_layer_height = calc_max_layer_height(print.config(), max_layer_height); // Use the extruder switches from Model::custom_gcode_per_print_z to override the extruder to print the object. // Do it only if all the objects were configured to be printed with a single extruder. @@ -150,6 +168,8 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool this->fill_wipe_tower_partitions(print.config(), object_bottom_z, max_layer_height); this->collect_extruder_statistics(prime_multi_material); + + this->mark_skirt_layers(print.config(), max_layer_height); } void ToolOrdering::initialize_layers(std::vector &zs) @@ -321,7 +341,7 @@ void ToolOrdering::reorder_extruders(unsigned int last_extruder_id) } } -void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z, coordf_t max_object_layer_height) +void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z, coordf_t max_layer_height) { if (m_layer_tools.empty()) return; @@ -347,17 +367,6 @@ void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_ lt.has_wipe_tower = (lt.has_object && lt.wipe_tower_partitions > 0) || lt.print_z < object_bottom_z + EPSILON; // Test for a raft, insert additional wipe tower layer to fill in the raft separation gap. - double max_layer_height = std::numeric_limits::max(); - for (size_t i = 0; i < config.nozzle_diameter.values.size(); ++ i) { - double mlh = config.max_layer_height.values[i]; - if (mlh == 0.) - mlh = 0.75 * config.nozzle_diameter.values[i]; - max_layer_height = std::min(max_layer_height, mlh); - } - // The Prusa3D Fast (0.35mm layer height) print profile sets a higher layer height than what is normally allowed - // by the nozzle. This is a hack and it works by increasing extrusion width. See GH #3919. - max_layer_height = std::max(max_layer_height, max_object_layer_height); - for (size_t i = 0; i + 1 < m_layer_tools.size(); ++ i) { const LayerTools < = m_layer_tools[i]; const LayerTools <_next = m_layer_tools[i + 1]; @@ -460,6 +469,48 @@ void ToolOrdering::collect_extruder_statistics(bool prime_multi_material) } } +// Layers are marked for infinite skirt aka draft shield. Not all the layers have to be printed. +void ToolOrdering::mark_skirt_layers(const PrintConfig &config, coordf_t max_layer_height) +{ + if (m_layer_tools.empty()) + return; + + if (m_layer_tools.front().extruders.empty()) { + // Empty first layer, no skirt will be printed. + //FIXME throw an exception? + return; + } + + size_t i = 0; + for (;;) { + m_layer_tools[i].has_skirt = true; + size_t j = i + 1; + for (; j < m_layer_tools.size() && ! m_layer_tools[j].has_object; ++ j); + // i and j are two successive layers printing an object. + if (j == m_layer_tools.size()) + // Don't print skirt above the last object layer. + break; + // Mark some printing intermediate layers as having skirt. + double last_z = m_layer_tools[i].print_z; + for (size_t k = i + 1; k < j; ++ k) { + if (m_layer_tools[k + 1].print_z - last_z > max_layer_height + EPSILON) { + // Layer k is the last one not violating the maximum layer height. + // Don't extrude skirt on empty layers. + while (m_layer_tools[k].extruders.empty()) + -- k; + if (m_layer_tools[k].has_skirt) { + // Skirt cannot be generated due to empty layers, there would be a missing layer in the skirt. + //FIXME throw an exception? + break; + } + m_layer_tools[k].has_skirt = true; + last_z = m_layer_tools[k].print_z; + } + } + i = j; + } +} + // Assign a pointer to a custom G-code to the respective ToolOrdering::LayerTools. // Ignore color changes, which are performed on a layer and for such an extruder, that the extruder will not be printing above that layer. // If multiple events are planned over a span of a single layer, use the last one. diff --git a/src/libslic3r/GCode/ToolOrdering.hpp b/src/libslic3r/GCode/ToolOrdering.hpp index e2e07533f..036730325 100644 --- a/src/libslic3r/GCode/ToolOrdering.hpp +++ b/src/libslic3r/GCode/ToolOrdering.hpp @@ -17,8 +17,6 @@ class LayerTools; namespace CustomGCode { struct Item; } class PrintRegion; - - // Object of this class holds information about whether an extrusion is printed immediately // after a toolchange (as part of infill/perimeter wiping) or not. One extrusion can be a part // of several copies - this has to be taken into account. @@ -69,8 +67,6 @@ private: const LayerTools* m_layer_tools = nullptr; // so we know which LayerTools object this belongs to }; - - class LayerTools { public: @@ -99,6 +95,9 @@ public: // If per layer extruder switches are inserted by the G-code preview slider, this value contains the new (1 based) extruder, with which the whole object layer is being printed with. // If not overriden, it is set to 0. unsigned int extruder_override = 0; + // Should a skirt be printed at this layer? + // Layers are marked for infinite skirt aka draft shield. Not all the layers have to be printed. + bool has_skirt = false; // Will there be anything extruded on this layer for the wipe tower? // Due to the support layers possibly interleaving the object layers, // wipe tower will be disabled for some support only layers. @@ -120,12 +119,10 @@ private: WipingExtrusions m_wiping_extrusions; }; - - class ToolOrdering { public: - ToolOrdering() {} + ToolOrdering() = default; // For the use case when each object is printed separately // (print.config.complete_objects is true). @@ -169,6 +166,7 @@ private: void collect_extruders(const PrintObject &object, const std::vector> &per_layer_extruder_switches); void reorder_extruders(unsigned int last_extruder_id); void fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z, coordf_t max_layer_height); + void mark_skirt_layers(const PrintConfig &config, coordf_t max_layer_height); void collect_extruder_statistics(bool prime_multi_material); std::vector m_layer_tools; @@ -182,8 +180,6 @@ private: const PrintConfig* m_print_config_ptr = nullptr; }; - - } // namespace SLic3r #endif /* slic3r_ToolOrdering_hpp_ */ diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 84fdf3f62..c963418c3 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -418,7 +418,7 @@ void PrintObject::generate_support_material() { if (this->set_started(posSupportMaterial)) { this->clear_support_layers(); - if (this->has_support_material() && m_layers.size() > 1) { + if ((this->has_support() && m_layers.size() > 1) || (this->has_raft() && ! m_layers.empty())) { m_print->set_status(85, L("Generating support material")); this->_generate_support_material(); m_print->throw_if_canceled();