From 131fb94c6bebe0a6abb3ca28d4a162aacbe75f40 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Tue, 26 Sep 2023 07:55:44 +0800 Subject: [PATCH] Sync PressureEq with latest PrusaSlicer --- src/libslic3r/GCode/PressureEqualizer.cpp | 117 +++++----------------- src/libslic3r/GCode/PressureEqualizer.hpp | 5 +- 2 files changed, 29 insertions(+), 93 deletions(-) diff --git a/src/libslic3r/GCode/PressureEqualizer.cpp b/src/libslic3r/GCode/PressureEqualizer.cpp index 67e23c914e..416ab929d3 100644 --- a/src/libslic3r/GCode/PressureEqualizer.cpp +++ b/src/libslic3r/GCode/PressureEqualizer.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include "../libslic3r.h" #include "../PrintConfig.hpp" @@ -29,12 +28,6 @@ static const std::string EXTERNAL_PERIMETER_TAG = ";_EXTERNAL_PERIMETER"; // affect how distant will be propagated a flow rate adjustment. static constexpr int max_look_back_limit = 128; -// Max non-extruding XY distance (travel move) in mm between two continous extrusions where we pretend -// its all one continous extruded line. Above this distance we assume extruder pressure hits 0 -// This exists because often there's tiny travel moves between stuff like infill -// lines where some extruder pressure will remain (so we should equalize between these small travels) -static constexpr long max_ignored_gap_between_extruding_segments = 3; - PressureEqualizer::PressureEqualizer(const Slic3r::GCodeConfig &config) : m_use_relative_e_distances(config.use_relative_e_distances.value) { // Preallocate some data, so that output_buffer.data() will return an empty string. @@ -48,8 +41,10 @@ PressureEqualizer::PressureEqualizer(const Slic3r::GCodeConfig &config) : m_use_ m_current_extrusion_role = GCodeExtrusionRole::None; // Expect the first command to fill the nozzle (deretract). m_retracted = true; - - m_max_segment_length = 2.f; + + // Maximum segment length to split a long segment if the initial and the final flow rate differ. + // Smaller value means a smoother transition between two different flow rates. + m_max_segment_length = 5.f; // Calculate filamet crossections for the multiple extruders. m_filament_crossections.clear(); @@ -64,17 +59,17 @@ PressureEqualizer::PressureEqualizer(const Slic3r::GCodeConfig &config) : m_use_ if(config.max_volumetric_extrusion_rate_slope.value > 0){ m_max_volumetric_extrusion_rate_slope_positive = float(config.max_volumetric_extrusion_rate_slope.value) * 60.f * 60.f; - m_max_volumetric_extrusion_rate_slope_negative = float(config.max_volumetric_extrusion_rate_slope.value) * 60.f * 60.f; - m_max_segment_length = float(config.max_volumetric_extrusion_rate_slope_segment_length.value); + m_max_volumetric_extrusion_rate_slope_negative = float(config.max_volumetric_extrusion_rate_slope.value) * 60.f * 60.f; + m_max_segment_length = float(config.max_volumetric_extrusion_rate_slope_segment_length.value); } for (ExtrusionRateSlope &extrusion_rate_slope : m_max_volumetric_extrusion_rate_slopes) { extrusion_rate_slope.negative = m_max_volumetric_extrusion_rate_slope_negative; extrusion_rate_slope.positive = m_max_volumetric_extrusion_rate_slope_positive; } - - // Don't regulate the pressure before and after ironing. - for (const GCodeExtrusionRole er : {GCodeExtrusionRole::Ironing}) { + + // Don't regulate the pressure before and after gap-fill and ironing. + for (const GCodeExtrusionRole er : {GCodeExtrusionRole::GapFill, GCodeExtrusionRole::Ironing}) { m_max_volumetric_extrusion_rate_slopes[size_t(er)].negative = 0; m_max_volumetric_extrusion_rate_slopes[size_t(er)].positive = 0; } @@ -111,67 +106,6 @@ void PressureEqualizer::process_layer(const std::string &gcode) } assert(!this->opened_extrude_set_speed_block); } - - // at this point, we have an entire layer of gcode lines loaded into m_gcode_lines - // now we will split the mix of travels and extrudes into segments of continous extrusion and process those - // We skip over large travels, and pretend small ones are part of a continous extrusion segment - long idx_end_current_extrusion = 0; - while (idx_end_current_extrusion < m_gcode_lines.size()) { - // find beginning of next extrusion segment from current pos - const long idx_begin_current_extrusion = find_if(m_gcode_lines.begin() + idx_end_current_extrusion, m_gcode_lines.end(), - [](GCodeLine line) { return line.extruding(); }) - m_gcode_lines.begin(); - // (extrusion begin idx = extrusion end idx) here because we start with extrusion length of zero - idx_end_current_extrusion = idx_begin_current_extrusion; - - // inner loop extends the extrusion segment over small travel moves - while (idx_end_current_extrusion < m_gcode_lines.size()) { - // find end of the current extrusion segment - const auto just_after_end_extrusion = find_if(m_gcode_lines.begin() + idx_end_current_extrusion, m_gcode_lines.end(), - [](GCodeLine line) { return !line.extruding(); }); - idx_end_current_extrusion = std::max(0,(just_after_end_extrusion - m_gcode_lines.begin()) - 1); - const long idx_begin_segment_continuation = advance_segment_beyond_small_gap(idx_end_current_extrusion); - if (idx_begin_segment_continuation > idx_end_current_extrusion) { - // extend the continous line over the small gap - idx_end_current_extrusion = idx_begin_segment_continuation; - continue; // keep going, loop again to find new end of extrusion segment - } else { - // gap to next extrude is too big, stop looking forward. We've found end of this segment - break; - } - } - - // now run the pressure equalizer across the segment like a streamroller - // it operates on a sliding window that moves forward across gcode line by line - for (int i = idx_begin_current_extrusion; i < idx_end_current_extrusion; ++i) { - // feed pressure equalizer past lines, going back to max_look_back_limit (or start of segment) - const auto start_idx = std::max(idx_begin_current_extrusion, i - max_look_back_limit); - adjust_volumetric_rate(start_idx, i); - } - // current extrusion is all done processing so advance beyond it for next loop - idx_end_current_extrusion++; - } -} - -long PressureEqualizer::advance_segment_beyond_small_gap(const long idx_orig) -{ - // this should only be run on the last extruding line before a gap - assert(m_gcode_lines[idx_cur_pos].extruding()); - double distance_traveled = 0.0; - // start at beginning of gap, advance till extrusion found or gap too big - for (auto idx_cur_pos = idx_orig + 1; idx_cur_pos < m_gcode_lines.size(); idx_cur_pos++) { - // started extruding again! return segment extension - if (m_gcode_lines[idx_cur_pos].extruding()) { - return idx_cur_pos; - } - - distance_traveled += m_gcode_lines[idx_cur_pos].dist_xy(); - // gap too big, dont extend segment - if (distance_traveled > max_ignored_gap_between_extruding_segments) { - return idx_orig; - } - } - // looped until end of layer and couldn't extend extrusion - return idx_orig; } LayerResult PressureEqualizer::process_layer(LayerResult &&input) @@ -465,6 +399,8 @@ bool PressureEqualizer::process_line(const char *line, const char *line_end, GCo buf.extruder_id = m_current_extruder; memcpy(buf.pos_end, m_current_pos, sizeof(float)*5); + + adjust_volumetric_rate(); #ifdef PRESSURE_EQUALIZER_DEBUG ++line_idx; #endif @@ -579,12 +515,14 @@ void PressureEqualizer::output_gcode_line(const size_t line_idx) } } -void PressureEqualizer::adjust_volumetric_rate(const size_t fist_line_idx, const size_t last_line_idx) +void PressureEqualizer::adjust_volumetric_rate() { - // don't bother adjusting volumetric rate if there's no gcode to adjust - if (last_line_idx-fist_line_idx < 2) + if (m_gcode_lines.size() < 2) return; + // Go back from the current circular_buffer_pos and lower the feedtrate to decrease the slope of the extrusion rate changes. + size_t fist_line_idx = size_t(std::max(0, int(m_gcode_lines.size()) - max_look_back_limit)); + const size_t last_line_idx = m_gcode_lines.size() - 1; size_t line_idx = last_line_idx; if (line_idx == fist_line_idx || !m_gcode_lines[line_idx].extruding()) // Nothing to do, the last move is not extruding. @@ -599,8 +537,9 @@ void PressureEqualizer::adjust_volumetric_rate(const size_t fist_line_idx, const for (; !m_gcode_lines[idx_prev].extruding() && idx_prev != fist_line_idx; --idx_prev); if (!m_gcode_lines[idx_prev].extruding()) break; - // Don't decelerate before ironing. - if (m_gcode_lines[line_idx].extrusion_role == GCodeExtrusionRole::Ironing) { line_idx = idx_prev; + // Don't decelerate before ironing and gap-fill. + if (m_gcode_lines[line_idx].extrusion_role == GCodeExtrusionRole::Ironing || m_gcode_lines[line_idx].extrusion_role == GCodeExtrusionRole::GapFill) { + line_idx = idx_prev; continue; } // Volumetric extrusion rate at the start of the succeding segment. @@ -619,8 +558,7 @@ void PressureEqualizer::adjust_volumetric_rate(const size_t fist_line_idx, const // Limit by the succeeding volumetric flow rate. rate_end = rate_succ; - // don't alter the flow rate for these extrusion types - if (!line.adjustable_flow || line.extrusion_role == GCodeExtrusionRole::BridgeInfill || line.extrusion_role == GCodeExtrusionRole::Ironing) { + if (!line.adjustable_flow || line.extrusion_role == GCodeExtrusionRole::ExternalPerimeter || line.extrusion_role == GCodeExtrusionRole::GapFill || line.extrusion_role == GCodeExtrusionRole::BridgeInfill || line.extrusion_role == GCodeExtrusionRole::Ironing) { rate_end = line.volumetric_extrusion_rate_end; } else if (line.volumetric_extrusion_rate_end > rate_end) { line.volumetric_extrusion_rate_end = rate_end; @@ -643,8 +581,8 @@ void PressureEqualizer::adjust_volumetric_rate(const size_t fist_line_idx, const } } // feedrate_per_extrusion_role[iRole] = (iRole == line.extrusion_role) ? line.volumetric_extrusion_rate_start : rate_start; - // Don't store feed rate for ironing - if (line.extrusion_role != GCodeExtrusionRole::Ironing) + // Don't store feed rate for ironing and gap-fill. + if (line.extrusion_role != GCodeExtrusionRole::Ironing && line.extrusion_role != GCodeExtrusionRole::GapFill) feedrate_per_extrusion_role[iRole] = line.volumetric_extrusion_rate_start; } } @@ -658,8 +596,8 @@ void PressureEqualizer::adjust_volumetric_rate(const size_t fist_line_idx, const for (; !m_gcode_lines[idx_next].extruding() && idx_next != last_line_idx; ++idx_next); if (!m_gcode_lines[idx_next].extruding()) break; - // Don't accelerate after ironing. - if (m_gcode_lines[line_idx].extrusion_role == GCodeExtrusionRole::Ironing) { + // Don't accelerate after ironing and gap-fill. + if (m_gcode_lines[line_idx].extrusion_role == GCodeExtrusionRole::Ironing || m_gcode_lines[line_idx].extrusion_role == GCodeExtrusionRole::GapFill) { line_idx = idx_next; continue; } @@ -674,8 +612,7 @@ void PressureEqualizer::adjust_volumetric_rate(const size_t fist_line_idx, const continue; // The positive rate is unlimited or the rate for GCodeExtrusionRole iRole is unlimited. float rate_start = feedrate_per_extrusion_role[iRole]; - // don't alter the flow rate for these extrusion types - if (!line.adjustable_flow || line.extrusion_role == GCodeExtrusionRole::BridgeInfill || line.extrusion_role == GCodeExtrusionRole::Ironing) { + if (!line.adjustable_flow || line.extrusion_role == GCodeExtrusionRole::ExternalPerimeter || line.extrusion_role == GCodeExtrusionRole::GapFill || line.extrusion_role == GCodeExtrusionRole::BridgeInfill || line.extrusion_role == GCodeExtrusionRole::Ironing) { rate_start = line.volumetric_extrusion_rate_start; } else if (iRole == size_t(line.extrusion_role) && rate_prec < rate_start) rate_start = rate_prec; @@ -700,8 +637,8 @@ void PressureEqualizer::adjust_volumetric_rate(const size_t fist_line_idx, const } } // feedrate_per_extrusion_role[iRole] = (iRole == line.extrusion_role) ? line.volumetric_extrusion_rate_end : rate_end; - // Don't store feed rate for ironing - if (line.extrusion_role != GCodeExtrusionRole::Ironing) + // Don't store feed rate for ironing and gap-fill. + if (line.extrusion_role != GCodeExtrusionRole::Ironing && line.extrusion_role != GCodeExtrusionRole::GapFill) feedrate_per_extrusion_role[iRole] = line.volumetric_extrusion_rate_end; } } diff --git a/src/libslic3r/GCode/PressureEqualizer.hpp b/src/libslic3r/GCode/PressureEqualizer.hpp index 1e9f013396..88c0c921e4 100644 --- a/src/libslic3r/GCode/PressureEqualizer.hpp +++ b/src/libslic3r/GCode/PressureEqualizer.hpp @@ -86,7 +86,7 @@ private: bool m_retracted; bool m_use_relative_e_distances; - // Maximum segment length to split a long segment if the initial and the final flow rate differ. +// Maximum segment length to split a long segment if the initial and the final flow rate differ. // Smaller value means a smoother transition between two different flow rates. float m_max_segment_length; @@ -189,12 +189,11 @@ private: #endif bool process_line(const char *line, const char *line_end, GCodeLine &buf); - long advance_segment_beyond_small_gap(long idx_cur_pos); void output_gcode_line(size_t line_idx); // Go back from the current circular_buffer_pos and lower the feedtrate to decrease the slope of the extrusion rate changes. // Then go forward and adjust the feedrate to decrease the slope of the extrusion rate changes. - void adjust_volumetric_rate(size_t first_line_idx, size_t last_line_idx); + void adjust_volumetric_rate(); // Push the text to the end of the output_buffer. inline void push_to_output(GCodeG1Formatter &formatter);