OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::PressureEqualizer Class Reference

#include </home/runner/work/OrcaSlicer/OrcaSlicer/src/libslic3r/GCode/PressureEqualizer.hpp>

Collaboration diagram for Slic3r::PressureEqualizer:

Classes

struct  ExtrusionRateSlope
struct  GCodeLine

Public Member Functions

 PressureEqualizer ()=delete
 PressureEqualizer (const Slic3r::GCodeConfig &config)
 ~PressureEqualizer ()=default
LayerResult process_layer (LayerResult &&input)

Public Attributes

std::queue< LayerResult * > m_layer_results
std::vector< GCodeLine > m_gcode_lines

Private Types

enum  GCodeLineType {
  GCODELINETYPE_INVALID , GCODELINETYPE_NOOP , GCODELINETYPE_OTHER , GCODELINETYPE_RETRACT ,
  GCODELINETYPE_UNRETRACT , GCODELINETYPE_TOOL_CHANGE , GCODELINETYPE_MOVE , GCODELINETYPE_EXTRUDE
}

Private Member Functions

void process_layer (const std::string &gcode)
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)
void adjust_volumetric_rate (size_t first_line_idx, size_t last_line_idx)
void push_to_output (GCodeG1Formatter &formatter)
void push_to_output (const std::string &text, bool add_eol)
void push_to_output (const char *text, size_t len, bool add_eol=true)
void push_line_to_output (size_t line_idx, float new_feedrate, const char *comment)

Private Attributes

ExtrusionRateSlope m_max_volumetric_extrusion_rate_slopes [size_t(ExtrusionRole::erCount)]
float m_max_volumetric_extrusion_rate_slope_positive
float m_max_volumetric_extrusion_rate_slope_negative
std::vector< float > m_filament_crossections
float m_current_pos [5]
size_t m_current_extruder
ExtrusionRole m_current_extrusion_role
bool m_retracted
bool m_use_relative_e_distances
bool m_high_precision
float m_max_segment_length
bool m_extrusion_rate_smoothing_external_perimeter_only
bool opened_extrude_set_speed_block = false
std::vector< char > output_buffer
size_t output_buffer_length
size_t output_buffer_prev_length

Detailed Description


Class Documentation

◆ Slic3r::PressureEqualizer::ExtrusionRateSlope

struct Slic3r::PressureEqualizer::ExtrusionRateSlope
Class Members
float negative
float positive

Member Enumeration Documentation

◆ GCodeLineType

Enumerator
GCODELINETYPE_INVALID 
GCODELINETYPE_NOOP 
GCODELINETYPE_OTHER 
GCODELINETYPE_RETRACT 
GCODELINETYPE_UNRETRACT 
GCODELINETYPE_TOOL_CHANGE 
GCODELINETYPE_MOVE 
GCODELINETYPE_EXTRUDE 
101 {
110 };
@ GCODELINETYPE_INVALID
Definition PressureEqualizer.hpp:102
@ GCODELINETYPE_RETRACT
Definition PressureEqualizer.hpp:105
@ GCODELINETYPE_EXTRUDE
Definition PressureEqualizer.hpp:109
@ GCODELINETYPE_TOOL_CHANGE
Definition PressureEqualizer.hpp:107
@ GCODELINETYPE_OTHER
Definition PressureEqualizer.hpp:104
@ GCODELINETYPE_MOVE
Definition PressureEqualizer.hpp:108
@ GCODELINETYPE_UNRETRACT
Definition PressureEqualizer.hpp:106
@ GCODELINETYPE_NOOP
Definition PressureEqualizer.hpp:103

Constructor & Destructor Documentation

◆ PressureEqualizer() [1/2]

Slic3r::PressureEqualizer::PressureEqualizer ( )
delete

References Slic3r::GCodeConfig.

◆ PressureEqualizer() [2/2]

Slic3r::PressureEqualizer::PressureEqualizer ( const Slic3r::GCodeConfig & config)
explicit
45 : m_use_relative_e_distances(config.use_relative_e_distances.value),
46 m_high_precision(config.high_precision_gcode.value)
47{
48 // Preallocate some data, so that output_buffer.data() will return an empty string.
49 output_buffer.assign(32, 0);
52
54 // Zero the position of the XYZE axes + the current feed
55 memset(m_current_pos, 0, sizeof(float) * 5);
57 // Expect the first command to fill the nozzle (deretract).
58 m_retracted = true;
59
61
62 // Calculate filamet crossections for the multiple extruders.
64 for (double r : config.filament_diameter.values) {
65 double a = 0.25f * M_PI * r * r;
66 m_filament_crossections.push_back(float(a));
67 }
68
69 // Volumetric rate of a 0.45mm x 0.2mm extrusion at 60mm/s XY movement: 0.45*0.2*60*60=5.4*60 = 324 mm^3/min
70 // Volumetric rate of a 0.45mm x 0.2mm extrusion at 20mm/s XY movement: 0.45*0.2*20*60=1.8*60 = 108 mm^3/min
71 // Slope of the volumetric rate, changing from 20mm/s to 60mm/s over 2 seconds: (5.4-1.8)*60*60/2=60*60*1.8 = 6480 mm^3/min^2 = 1.8 mm^3/s^2
72
73 if(config.max_volumetric_extrusion_rate_slope.value > 0){
74 m_max_volumetric_extrusion_rate_slope_positive = float(config.max_volumetric_extrusion_rate_slope.value) * 60.f * 60.f;
75 m_max_volumetric_extrusion_rate_slope_negative = float(config.max_volumetric_extrusion_rate_slope.value) * 60.f * 60.f;
76 m_max_segment_length = float(config.max_volumetric_extrusion_rate_slope_segment_length.value);
77 m_extrusion_rate_smoothing_external_perimeter_only = bool(config.extrusion_rate_smoothing_external_perimeter_only.value);
78 }
79
81 extrusion_rate_slope.negative = m_max_volumetric_extrusion_rate_slope_negative;
82 extrusion_rate_slope.positive = m_max_volumetric_extrusion_rate_slope_positive;
83 }
84
85 // Don't regulate the pressure before and after ironing.
86 for (const ExtrusionRole er : {ExtrusionRole::erIroning}) {
87 m_max_volumetric_extrusion_rate_slopes[size_t(er)].negative = 0;
88 m_max_volumetric_extrusion_rate_slopes[size_t(er)].positive = 0;
89 }
90
92
93#ifdef PRESSURE_EQUALIZER_STATISTIC
94 m_stat.reset();
95#endif
96
97#ifdef PRESSURE_EQUALIZER_DEBUG
98 line_idx = 0;
99#endif
100}
#define M_PI
Definition ExtrusionSimulator.cpp:31
std::vector< char > output_buffer
Definition PressureEqualizer.hpp:186
bool m_use_relative_e_distances
Definition PressureEqualizer.hpp:87
float m_max_volumetric_extrusion_rate_slope_negative
Definition PressureEqualizer.hpp:75
ExtrusionRateSlope m_max_volumetric_extrusion_rate_slopes[size_t(ExtrusionRole::erCount)]
Definition PressureEqualizer.hpp:73
float m_max_volumetric_extrusion_rate_slope_positive
Definition PressureEqualizer.hpp:74
size_t output_buffer_length
Definition PressureEqualizer.hpp:187
bool m_high_precision
Definition PressureEqualizer.hpp:88
float m_current_pos[5]
Definition PressureEqualizer.hpp:83
bool opened_extrude_set_speed_block
Definition PressureEqualizer.hpp:99
bool m_extrusion_rate_smoothing_external_perimeter_only
Definition PressureEqualizer.hpp:95
float m_max_segment_length
Definition PressureEqualizer.hpp:92
size_t output_buffer_prev_length
Definition PressureEqualizer.hpp:188
bool m_retracted
Definition PressureEqualizer.hpp:86
ExtrusionRole m_current_extrusion_role
Definition PressureEqualizer.hpp:85
size_t m_current_extruder
Definition PressureEqualizer.hpp:84
std::vector< float > m_filament_crossections
Definition PressureEqualizer.hpp:79
Definition PressureEqualizer.hpp:69
ExtrusionRole
Definition ExtrusionEntity.hpp:26
@ erNone
Definition ExtrusionEntity.hpp:27
@ erIroning
Definition ExtrusionEntity.hpp:35

References Slic3r::erIroning, Slic3r::erNone, Slic3r::GCodeConfig, Slic3r::high_precision_gcode(), m_current_extruder, m_current_extrusion_role, m_current_pos, m_extrusion_rate_smoothing_external_perimeter_only, m_filament_crossections, m_high_precision, m_max_segment_length, m_max_volumetric_extrusion_rate_slope_negative, m_max_volumetric_extrusion_rate_slope_positive, m_max_volumetric_extrusion_rate_slopes, M_PI, m_retracted, m_use_relative_e_distances, opened_extrude_set_speed_block, output_buffer, output_buffer_length, and output_buffer_prev_length.

Here is the call graph for this function:

◆ ~PressureEqualizer()

Slic3r::PressureEqualizer::~PressureEqualizer ( )
default

Member Function Documentation

◆ adjust_volumetric_rate()

void Slic3r::PressureEqualizer::adjust_volumetric_rate ( size_t first_line_idx,
size_t last_line_idx )
private
735{
736 // don't bother adjusting volumetric rate if there's no gcode to adjust
737 if (last_line_idx - first_line_idx < 2)
738 return;
739
740 size_t line_idx = last_line_idx;
741 if (line_idx == first_line_idx || !m_gcode_lines[line_idx].extruding())
742 // Nothing to do, the last move is not extruding.
743 return;
744
745 std::array<float, size_t(ExtrusionRole::erCount)> feedrate_per_extrusion_role{};
746 feedrate_per_extrusion_role.fill(std::numeric_limits<float>::max());
747 feedrate_per_extrusion_role[int(m_gcode_lines[line_idx].extrusion_role)] = m_gcode_lines[line_idx].volumetric_extrusion_rate_start;
748
749 while (line_idx != first_line_idx) {
750 size_t idx_prev = line_idx - 1;
751 for (; !m_gcode_lines[idx_prev].extruding() && idx_prev != first_line_idx; --idx_prev);
752 if (!m_gcode_lines[idx_prev].extruding())
753 break;
754 // Don't decelerate before ironing.
755 if (m_gcode_lines[line_idx].extrusion_role == ExtrusionRole::erIroning) {
756 line_idx = idx_prev;
757 continue;
758 }
759 // Volumetric extrusion rate at the start of the succeeding segment.
760 float rate_succ = m_gcode_lines[line_idx].volumetric_extrusion_rate_start;
761 // What is the gradient of the extrusion rate between idx_prev and idx?
762 line_idx = idx_prev;
763 GCodeLine &line = m_gcode_lines[line_idx];
764
765 for (size_t iRole = 1; iRole < size_t(ExtrusionRole::erCount); ++ iRole) {
766 const float &rate_slope = m_max_volumetric_extrusion_rate_slopes[iRole].negative;
767 if (rate_slope == 0 || feedrate_per_extrusion_role[iRole] == std::numeric_limits<float>::max())
768 continue; // The negative rate is unlimited or the rate for ExtrusionRole iRole is unlimited.
769
770 float rate_end = feedrate_per_extrusion_role[iRole];
771 if (iRole == size_t(line.extrusion_role) && rate_succ < rate_end)
772 // Limit by the succeeding volumetric flow rate.
773 rate_end = rate_succ;
774
775 // don't alter the flow rate for these extrusion types
776 if (!line.adjustable_flow || line.extrusion_role == ExtrusionRole::erBridgeInfill || line.extrusion_role == ExtrusionRole::erIroning ||
777 // Orca: Limit ERS to external perimeters and overhangs if option selected by user
779 rate_end = line.volumetric_extrusion_rate_end;
780 } else if (line.volumetric_extrusion_rate_end > rate_end) {
781 line.volumetric_extrusion_rate_end = rate_end;
782 line.max_volumetric_extrusion_rate_slope_negative = rate_slope;
783 line.modified = true;
784 } else if (iRole == size_t(line.extrusion_role)) {
785 rate_end = line.volumetric_extrusion_rate_end;
786 } else {
787 // Use the original, 'floating' extrusion rate as a starting point for the limiter.
788 }
789
790 if (line.adjustable_flow) {
791 float rate_start = sqrt(rate_end * rate_end + 2 * line.volumetric_extrusion_rate * line.dist_xyz() * rate_slope / line.feedrate());
792 if (rate_start < line.volumetric_extrusion_rate_start) {
793 // Limit the volumetric extrusion rate at the start of this segment due to a segment
794 // of ExtrusionType iRole, which will be extruded in the future.
795 line.volumetric_extrusion_rate_start = rate_start;
796 line.max_volumetric_extrusion_rate_slope_negative = rate_slope;
797 line.modified = true;
798 }
799 }
800// feedrate_per_extrusion_role[iRole] = (iRole == line.extrusion_role) ? line.volumetric_extrusion_rate_start : rate_start;
801 // Don't store feed rate for ironing
802 if (line.extrusion_role != ExtrusionRole::erIroning)
803 feedrate_per_extrusion_role[iRole] = line.volumetric_extrusion_rate_start;
804 }
805 }
806
807 feedrate_per_extrusion_role.fill(std::numeric_limits<float>::max());
808 feedrate_per_extrusion_role[size_t(m_gcode_lines[line_idx].extrusion_role)] = m_gcode_lines[line_idx].volumetric_extrusion_rate_end;
809
810 assert(m_gcode_lines[line_idx].extruding());
811 while (line_idx != last_line_idx) {
812 size_t idx_next = line_idx + 1;
813 for (; !m_gcode_lines[idx_next].extruding() && idx_next != last_line_idx; ++idx_next);
814 if (!m_gcode_lines[idx_next].extruding())
815 break;
816 // Don't accelerate after ironing.
817 if (m_gcode_lines[line_idx].extrusion_role == ExtrusionRole::erIroning) {
818 line_idx = idx_next;
819 continue;
820 }
821 float rate_prec = m_gcode_lines[line_idx].volumetric_extrusion_rate_end;
822 // What is the gradient of the extrusion rate between idx_prev and idx?
823 line_idx = idx_next;
824 GCodeLine &line = m_gcode_lines[line_idx];
825
826 for (size_t iRole = 1; iRole < size_t(ExtrusionRole::erCount); ++ iRole) {
827 const float &rate_slope = m_max_volumetric_extrusion_rate_slopes[iRole].positive;
828 if (rate_slope == 0 || feedrate_per_extrusion_role[iRole] == std::numeric_limits<float>::max())
829 continue; // The positive rate is unlimited or the rate for ExtrusionRole iRole is unlimited.
830
831 float rate_start = feedrate_per_extrusion_role[iRole];
832 // don't alter the flow rate for these extrusion types
833 if (!line.adjustable_flow || line.extrusion_role == ExtrusionRole::erBridgeInfill || line.extrusion_role == ExtrusionRole::erIroning ||
834 // Orca: Limit ERS to external perimeters and overhangs if option selected by user
836 rate_start = line.volumetric_extrusion_rate_start;
837 } else if (iRole == size_t(line.extrusion_role) && rate_prec < rate_start)
838 rate_start = rate_prec;
839
840 if (line.volumetric_extrusion_rate_start > rate_start) {
841 line.volumetric_extrusion_rate_start = rate_start;
842 line.max_volumetric_extrusion_rate_slope_positive = rate_slope;
843 line.modified = true;
844 } else if (iRole == size_t(line.extrusion_role)) {
845 rate_start = line.volumetric_extrusion_rate_start;
846 } else {
847 // Use the original, 'floating' extrusion rate as a starting point for the limiter.
848 }
849
850 if (line.adjustable_flow) {
851 float rate_end = sqrt(rate_start * rate_start + 2 * line.volumetric_extrusion_rate * line.dist_xyz() * rate_slope / line.feedrate());
852 if (rate_end < line.volumetric_extrusion_rate_end) {
853 // Limit the volumetric extrusion rate at the start of this segment due to a segment
854 // of ExtrusionType iRole, which was extruded before.
855 line.volumetric_extrusion_rate_end = rate_end;
856 line.max_volumetric_extrusion_rate_slope_positive = rate_slope;
857 line.modified = true;
858 }
859 }
860// feedrate_per_extrusion_role[iRole] = (iRole == line.extrusion_role) ? line.volumetric_extrusion_rate_end : rate_end;
861 // Don't store feed rate for ironing
862 if (line.extrusion_role != ExtrusionRole::erIroning)
863 feedrate_per_extrusion_role[iRole] = line.volumetric_extrusion_rate_end;
864 }
865 }
866}
std::vector< GCodeLine > m_gcode_lines
Definition PressureEqualizer.hpp:213
@ erCount
Definition ExtrusionEntity.hpp:48
@ erExternalPerimeter
Definition ExtrusionEntity.hpp:29
@ erBridgeInfill
Definition ExtrusionEntity.hpp:36
@ erOverhangPerimeter
Definition ExtrusionEntity.hpp:30
Definition PressureEqualizer.hpp:113

References Slic3r::PressureEqualizer::GCodeLine::adjustable_flow, Slic3r::PressureEqualizer::GCodeLine::dist_xyz(), Slic3r::erBridgeInfill, Slic3r::erCount, Slic3r::erExternalPerimeter, Slic3r::erIroning, Slic3r::erOverhangPerimeter, Slic3r::PressureEqualizer::GCodeLine::extrusion_role, Slic3r::PressureEqualizer::GCodeLine::feedrate(), m_extrusion_rate_smoothing_external_perimeter_only, m_gcode_lines, m_max_volumetric_extrusion_rate_slopes, Slic3r::PressureEqualizer::GCodeLine::max_volumetric_extrusion_rate_slope_negative, Slic3r::PressureEqualizer::GCodeLine::max_volumetric_extrusion_rate_slope_positive, Slic3r::PressureEqualizer::GCodeLine::modified, Slic3r::PressureEqualizer::GCodeLine::volumetric_extrusion_rate, Slic3r::PressureEqualizer::GCodeLine::volumetric_extrusion_rate_end, and Slic3r::PressureEqualizer::GCodeLine::volumetric_extrusion_rate_start.

Referenced by process_layer().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ advance_segment_beyond_small_gap()

long Slic3r::PressureEqualizer::advance_segment_beyond_small_gap ( long idx_cur_pos)
private
165{
166 // this should only be run on the last extruding line before a gap
167 assert(m_gcode_lines[idx_orig].extruding());
168 double distance_traveled = 0.0;
169 // start at beginning of gap, advance till extrusion found or gap too big
170 for (auto idx_cur_pos = idx_orig + 1; idx_cur_pos < m_gcode_lines.size(); idx_cur_pos++) {
171 // started extruding again! return segment extension
172 if (m_gcode_lines[idx_cur_pos].extruding()) {
173 return idx_cur_pos;
174 }
175
176 distance_traveled += m_gcode_lines[idx_cur_pos].dist_xy();
177 // gap too big, dont extend segment
178 if (distance_traveled > max_ignored_gap_between_extruding_segments) {
179 return idx_orig;
180 }
181 }
182 // looped until end of layer and couldn't extend extrusion
183 return idx_orig;
184}
static constexpr long max_ignored_gap_between_extruding_segments
Definition PressureEqualizer.cpp:42

References m_gcode_lines, and Slic3r::max_ignored_gap_between_extruding_segments.

Referenced by process_layer().

Here is the caller graph for this function:

◆ output_gcode_line()

void Slic3r::PressureEqualizer::output_gcode_line ( size_t line_idx)
private
484{
485 GCodeLine &line = m_gcode_lines[line_idx];
486 if (!line.modified) {
487 push_to_output(line.raw.data(), line.raw_length, true);
488 return;
489 }
490
491 // The line was modified.
492 // Find the comment.
493 const char *comment = line.raw.data();
494 while (*comment != ';' && *comment != 0) ++comment;
495 if (*comment != ';')
496 comment = nullptr;
497
498 // get the gcode line length
499 float l = line.dist_xyz();
500 // number of segments this line can be broken down to
501 auto nSegments = size_t(ceil(l / m_max_segment_length));
502
503 // Orca:
504 // Calculate the absolute difference in volumetric extrusion rate between the start and end point of the line.
505 // Quantize it to 1mm3/min (0.016mm3/sec).
506 int delta_volumetric_rate = std::round(std::max({
507 fabs(line.volumetric_extrusion_rate_end - line.volumetric_extrusion_rate_start),
508 // For line with accel-then-decel, we also calc the max difference to the peak
509 fabs(line.volumetric_extrusion_rate - line.volumetric_extrusion_rate_start),
510 fabs(line.volumetric_extrusion_rate - line.volumetric_extrusion_rate_end),
511 }));
512
513 // Emit the line with lowered extrusion rates.
514 // Orca:
515 // First, check if the change in volumetric extrusion rate is trivial (less than 10mm3/min -> 0.16mm3/sec (5mm/sec speed for a 0.25 mm nozzle).
516 // Or if the line size is equal in length with the smallest segment.
517 // If so, then emit the line as a single extrusion, i.e. dont split into segments.
518 constexpr int NON_TRIVIAL_RATE_DELTA = 10;
519 if (nSegments == 1 || delta_volumetric_rate < NON_TRIVIAL_RATE_DELTA) {
520 push_line_to_output(line_idx, line.feedrate() * line.volumetric_correction_avg(), comment);
521 } else // The line needs to be split the line into segments and apply extrusion rate smoothing
522 {
523 const float original_feedrate = line.feedrate();
524 // Update the initial and final feed rate values.
525 line.pos_start[4] = line.volumetric_extrusion_rate_start * line.pos_end[4] / line.volumetric_extrusion_rate;
526 line.pos_end [4] = line.volumetric_extrusion_rate_end * line.pos_end[4] / line.volumetric_extrusion_rate;
527
528 // Handle special case where both start & end extrusion rates are smaller than the original extrusion rate,
529 // which means we need to do an accel-then-decel movements to achieve potentially max print speed
530 if (line.volumetric_extrusion_rate > line.volumetric_extrusion_rate_start &&
531 line.volumetric_extrusion_rate > line.volumetric_extrusion_rate_end) {
532 // total extrusion amount of the original line
533 const double original_extrusion = (double) l * line.volumetric_extrusion_rate / original_feedrate;
534
535 // make sure there is a steady segment that's no shorter than `m_max_segment_length`
536 const double min_steady_extrusion = original_extrusion * m_max_segment_length / l;
537 const double max_sloped_extrusion = original_extrusion - min_steady_extrusion;
538 assert(max_sloped_extrusion > 0);
539
540 // Calculate the maximum possible peak extrusion rate
541 // amount of extrusion if accelerate from volumetric_extrusion_rate_start to volumetric_extrusion_rate then
542 // decelerate from volumetric_extrusion_rate to volumetric_extrusion_rate_end with max slope rate
543 const auto pow2 = [](const double x) { return x * x; };
544 const double e_2 = pow2(line.volumetric_extrusion_rate);
545 const double e0_2 = pow2(line.volumetric_extrusion_rate_start);
546 const double e1_2 = pow2(line.volumetric_extrusion_rate_end);
547 const double sp = line.max_volumetric_extrusion_rate_slope_positive;
548 const double sn = line.max_volumetric_extrusion_rate_slope_negative;
549 const double sloped_extrusion = (e_2 - e0_2) / 2 / sp + (e_2 - e1_2) / 2 / sn;
550
551 double target_max_extrusion_rate = line.volumetric_extrusion_rate;
552 if (sloped_extrusion > max_sloped_extrusion) {
553 // We don't have enough time to accel to max possible extrusion rate
554 // now we calculate the actual possible value
555 target_max_extrusion_rate = std::sqrt((2 * max_sloped_extrusion * sp * sn + sn * e0_2 + sp * e1_2) / (sp + sn));
556
557 // Worst case: we don't have enough time to do an accl-steady-decel movement at all, fallback to the old fashion
558 // single slope mode
559 if (target_max_extrusion_rate <= line.volumetric_extrusion_rate_start ||
560 target_max_extrusion_rate <= line.volumetric_extrusion_rate_end) {
561 goto single_slope_fallback; // TODO: FIXIT: better way than a goto?
562 }
563 }
564 assert(target_max_extrusion_rate > line.volumetric_extrusion_rate_start);
565 assert(target_max_extrusion_rate > line.volumetric_extrusion_rate_end);
566 assert(target_max_extrusion_rate <= line.volumetric_extrusion_rate);
567
568 // if the extrusion rate change is trivial, then ignore this algorithm and use the single sloped version instead
569 delta_volumetric_rate = std::round(std::min({ // important! it's MIN here not max!
570 fabs(target_max_extrusion_rate - line.volumetric_extrusion_rate_start),
571 fabs(target_max_extrusion_rate - line.volumetric_extrusion_rate_end),
572 }));
573
574 if (delta_volumetric_rate >= NON_TRIVIAL_RATE_DELTA) {
575 // we then have the target max feedrate when we reach target_max_extrusion_rate
576 const double target_max_feedrate = original_feedrate * target_max_extrusion_rate / line.volumetric_extrusion_rate;
577 assert(target_max_feedrate <= original_feedrate);
578
579 // calculate the accel and deccel time & length
580 const double t_acc = (target_max_extrusion_rate - line.volumetric_extrusion_rate_start) / sp;
581 const double l_acc = t_acc * (target_max_feedrate + line.pos_start[4]) / 2;
582 const double t_dec = (target_max_extrusion_rate - line.volumetric_extrusion_rate_end) / sn;
583 const double l_dec = t_dec * (target_max_feedrate + line.pos_end[4]) / 2;
584
585 float pos_end_bak[5];
586 memcpy(pos_end_bak, line.pos_end, sizeof(float) * 5); // backup the final pos
587 float pos_start[5];
588 float pos_end[5];
589 memcpy(pos_start, line.pos_start, sizeof(float) * 5);
590 memcpy(pos_end, line.pos_end, sizeof(float) * 5);
591
592 // calculate the end pos of the accel slope
593 float t = l_acc / l;
594 for (int i = 0; i < 4; ++i) {
595 pos_end[i] = pos_start[i] + (pos_end_bak[i] - pos_start[i]) * t;
596 line.pos_provided[i] = true;
597 }
598 // emit accel slope in nSegments
599 nSegments = size_t(ceil(l_acc / m_max_segment_length));
600 assert(nSegments > 0);
601 for (size_t i = 1; i <= nSegments; ++i) {
602 t = float(i) / float(nSegments);
603 for (size_t j = 0; j < 4; ++j) {
604 line.pos_end[j] = pos_start[j] + (pos_end[j] - pos_start[j]) * t;
605 line.pos_provided[j] = true;
606 }
607 // Interpolate the feed rate at the center of the segment.
608 push_line_to_output(line_idx, pos_start[4] + (target_max_feedrate - pos_start[4]) * (float(i) - 0.5f) / float(nSegments), comment);
609 comment = nullptr;
610 memcpy(line.pos_start, line.pos_end, sizeof(float)*5);
611 }
612
613 // calculate the end pos of the steady segment
614 t = (l - l_dec) / l;
615 for (int i = 0; i < 4; ++i) {
616 line.pos_end[i] = pos_start[i] + (pos_end_bak[i] - pos_start[i]) * t;
617 }
618 // emit the steady feed rate segment
619 push_line_to_output(line_idx, target_max_feedrate, nullptr);
620 memcpy(line.pos_start, line.pos_end, sizeof(float) * 5);
621
622 // calculate the start pos of the decl slope
623 memcpy(pos_start, line.pos_end, sizeof(float) * 5);
624 line.pos_start[4] = target_max_feedrate;
625 pos_start[4] = target_max_feedrate;
626 // emit deccel slope in nSegments
627 nSegments = size_t(ceil(l_dec / m_max_segment_length));
628 assert(nSegments > 0);
629 for (size_t i = 1; i <= nSegments; ++ i) {
630 t = float(i) / float(nSegments);
631 for (size_t j = 0; j < 4; ++ j) {
632 line.pos_end[j] = pos_start[j] + (pos_end_bak[j] - pos_start[j]) * t;
633 }
634 // Interpolate the feed rate at the center of the segment.
635 push_line_to_output(line_idx, pos_start[4] + (pos_end_bak[4] - pos_start[4]) * (float(i) - 0.5f) / float(nSegments), nullptr);
636 memcpy(line.pos_start, line.pos_end, sizeof(float)*5);
637 }
638
639 // finish the movement by moving to end pos
640 for (int i = 0; i < 4; ++i) {
641 line.pos_end[i] = pos_end_bak[i];
642 }
643 push_line_to_output(line_idx, pos_end_bak[4], nullptr);
644
645 return;
646 }
647 }
648single_slope_fallback:
649 bool accelerating = line.volumetric_extrusion_rate_start < line.volumetric_extrusion_rate_end;
650 float feed_avg = 0.5f * (line.pos_start[4] + line.pos_end[4]);
651 // Limiting volumetric extrusion rate slope for this segment.
652 float max_volumetric_extrusion_rate_slope = accelerating ? line.max_volumetric_extrusion_rate_slope_positive :
653 line.max_volumetric_extrusion_rate_slope_negative;
654 // Total time for the segment, corrected for the possibly lowered volumetric feed rate,
655 // if accelerating / decelerating over the complete segment.
656 float t_total = line.dist_xyz() / feed_avg;
657 // Time of the acceleration / deceleration part of the segment, if accelerating / decelerating
658 // with the maximum volumetric extrusion rate slope.
659 float t_acc = std::fabs(line.volumetric_extrusion_rate_start - line.volumetric_extrusion_rate_end) / max_volumetric_extrusion_rate_slope;
660 float l_acc = l;
661 float l_steady = 0.f;
662 if (t_acc < t_total) {
663 // One may achieve higher print speeds if part of the segment is not speed limited.
664 l_acc = t_acc * feed_avg;
665 l_steady = l - l_acc;
666 if (l_steady < 0.5f * m_max_segment_length) {
667 l_acc = l;
668 l_steady = 0.f;
669 } else
670 nSegments = size_t(ceil(l_acc / m_max_segment_length));
671 }
672 float pos_start[5];
673 float pos_end[5];
674 float pos_end2[4];
675 memcpy(pos_start, line.pos_start, sizeof(float) * 5);
676 memcpy(pos_end, line.pos_end, sizeof(float) * 5);
677 if (l_steady > 0.f) {
678 // There will be a steady feed segment emitted.
679 if (accelerating) {
680 // Prepare the final steady feed rate segment.
681 memcpy(pos_end2, pos_end, sizeof(float)*4);
682 float t = l_acc / l;
683 for (int i = 0; i < 4; ++ i) {
684 pos_end[i] = pos_start[i] + (pos_end[i] - pos_start[i]) * t;
685 line.pos_provided[i] = true;
686 }
687 } else {
688 // Emit the steady feed rate segment.
689 float t = l_steady / l;
690 for (int i = 0; i < 4; ++ i) {
691 line.pos_end[i] = pos_start[i] + (pos_end[i] - pos_start[i]) * t;
692 line.pos_provided[i] = true;
693 }
694 push_line_to_output(line_idx, pos_start[4], comment);
695 comment = nullptr;
696
697 float new_pos_start_feedrate = pos_start[4];
698
699 memcpy(line.pos_start, line.pos_end, sizeof(float)*5);
700 memcpy(pos_start, line.pos_end, sizeof(float)*5);
701
702 line.pos_start[4] = new_pos_start_feedrate;
703 pos_start[4] = new_pos_start_feedrate;
704 }
705 }
706 // Split the segment into pieces.
707 for (size_t i = 1; i < nSegments; ++ i) {
708 float t = float(i) / float(nSegments);
709 for (size_t j = 0; j < 4; ++ j) {
710 line.pos_end[j] = pos_start[j] + (pos_end[j] - pos_start[j]) * t;
711 line.pos_provided[j] = true;
712 }
713 // Interpolate the feed rate at the center of the segment.
714 push_line_to_output(line_idx, pos_start[4] + (pos_end[4] - pos_start[4]) * (float(i) - 0.5f) / float(nSegments), comment);
715 comment = nullptr;
716 memcpy(line.pos_start, line.pos_end, sizeof(float)*5);
717 }
718 if (l_steady > 0.f && accelerating) {
719 for (int i = 0; i < 4; ++ i) {
720 line.pos_end[i] = pos_end2[i];
721 line.pos_provided[i] = true;
722 }
723 push_line_to_output(line_idx, pos_end[4], comment);
724 } else {
725 for (int i = 0; i < 4; ++ i) {
726 line.pos_end[i] = pos_end[i];
727 line.pos_provided[i] = true;
728 }
729 push_line_to_output(line_idx, pos_end[4], comment);
730 }
731 }
732}
void push_line_to_output(size_t line_idx, float new_feedrate, const char *comment)
Definition PressureEqualizer.cpp:930
void push_to_output(GCodeG1Formatter &formatter)
Definition PressureEqualizer.cpp:868
zaa_minimize_perimeter_height max_volumetric_extrusion_rate_slope((ConfigOptionFloat, max_volumetric_extrusion_rate_slope_segment_length))((ConfigOptionBool

References Slic3r::PressureEqualizer::GCodeLine::dist_xyz(), Slic3r::PressureEqualizer::GCodeLine::feedrate(), m_gcode_lines, m_max_segment_length, Slic3r::max_volumetric_extrusion_rate_slope(), Slic3r::PressureEqualizer::GCodeLine::max_volumetric_extrusion_rate_slope_negative, Slic3r::PressureEqualizer::GCodeLine::max_volumetric_extrusion_rate_slope_positive, Slic3r::PressureEqualizer::GCodeLine::modified, Slic3r::PressureEqualizer::GCodeLine::pos_end, Slic3r::PressureEqualizer::GCodeLine::pos_provided, Slic3r::PressureEqualizer::GCodeLine::pos_start, push_line_to_output(), push_to_output(), Slic3r::PressureEqualizer::GCodeLine::raw, Slic3r::PressureEqualizer::GCodeLine::raw_length, Slic3r::PressureEqualizer::GCodeLine::volumetric_correction_avg(), Slic3r::PressureEqualizer::GCodeLine::volumetric_extrusion_rate, Slic3r::PressureEqualizer::GCodeLine::volumetric_extrusion_rate_end, and Slic3r::PressureEqualizer::GCodeLine::volumetric_extrusion_rate_start.

Referenced by process_layer().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_layer() [1/2]

void Slic3r::PressureEqualizer::process_layer ( const std::string & gcode)
private
103{
104 if (!gcode.empty()) {
105 const char *gcode_begin = gcode.c_str();
106 while (*gcode_begin != 0) {
107 // Find end of the line.
108 const char *gcode_end = gcode_begin;
109 // Slic3r always generates end of lines in a Unix style.
110 for (; *gcode_end != 0 && *gcode_end != '\n'; ++gcode_end);
111
112 m_gcode_lines.emplace_back();
113 if (!this->process_line(gcode_begin, gcode_end, m_gcode_lines.back())) {
114 // The line has to be forgotten. It contains comment marks, which shall be filtered out of the target g-code.
115 m_gcode_lines.pop_back();
116 }
117 gcode_begin = gcode_end;
118 if (*gcode_begin == '\n')
119 ++gcode_begin;
120 }
121 assert(!this->opened_extrude_set_speed_block);
122 }
123
124 // at this point, we have an entire layer of gcode lines loaded into m_gcode_lines
125 // now we will split the mix of travels and extrudes into segments of continous extrusion and process those
126 // We skip over large travels, and pretend small ones are part of a continous extrusion segment
127 long idx_end_current_extrusion = 0;
128 while (idx_end_current_extrusion < m_gcode_lines.size()) {
129 // find beginning of next extrusion segment from current pos
130 const long idx_begin_current_extrusion = find_if(m_gcode_lines.begin() + idx_end_current_extrusion, m_gcode_lines.end(),
131 [](GCodeLine line) { return line.extruding(); }) - m_gcode_lines.begin();
132 // (extrusion begin idx = extrusion end idx) here because we start with extrusion length of zero
133 idx_end_current_extrusion = idx_begin_current_extrusion;
134
135 // inner loop extends the extrusion segment over small travel moves
136 while (idx_end_current_extrusion < m_gcode_lines.size()) {
137 // find end of the current extrusion segment
138 const auto just_after_end_extrusion = find_if(m_gcode_lines.begin() + idx_end_current_extrusion, m_gcode_lines.end(),
139 [](GCodeLine line) { return !line.extruding(); });
140 idx_end_current_extrusion = std::max<long>(0,(just_after_end_extrusion - m_gcode_lines.begin()) - 1);
141 const long idx_begin_segment_continuation = advance_segment_beyond_small_gap(idx_end_current_extrusion);
142 if (idx_begin_segment_continuation > idx_end_current_extrusion) {
143 // extend the continous line over the small gap
144 idx_end_current_extrusion = idx_begin_segment_continuation;
145 continue; // keep going, loop again to find new end of extrusion segment
146 } else {
147 // gap to next extrude is too big, stop looking forward. We've found end of this segment
148 break;
149 }
150 }
151
152 // now run the pressure equalizer across the segment like a streamroller
153 // it operates on a sliding window that moves forward across gcode line by line
154 for (int i = idx_begin_current_extrusion; i < idx_end_current_extrusion; ++i) {
155 // feed pressure equalizer past lines, going back to max_look_back_limit (or start of segment)
156 const auto start_idx = std::max<long>(idx_begin_current_extrusion, i - max_look_back_limit);
157 adjust_volumetric_rate(start_idx, i);
158 }
159 // current extrusion is all done processing so advance beyond it for next loop
160 idx_end_current_extrusion++;
161 }
162}
void adjust_volumetric_rate(size_t first_line_idx, size_t last_line_idx)
Definition PressureEqualizer.cpp:734
bool process_line(const char *line, const char *line_end, GCodeLine &buf)
Definition PressureEqualizer.cpp:266
long advance_segment_beyond_small_gap(long idx_cur_pos)
Definition PressureEqualizer.cpp:164
@ gcode
Definition Time.hpp:14
static constexpr int max_look_back_limit
Definition PressureEqualizer.cpp:36

References adjust_volumetric_rate(), advance_segment_beyond_small_gap(), m_gcode_lines, Slic3r::max_look_back_limit, opened_extrude_set_speed_block, and process_line().

Here is the call graph for this function:

◆ process_layer() [2/2]

LayerResult Slic3r::PressureEqualizer::process_layer ( LayerResult && input)
187{
188 const bool is_first_layer = m_layer_results.empty();
189 const size_t next_layer_first_idx = m_gcode_lines.size();
190
191 if (!input.nop_layer_result) {
192 this->process_layer(input.gcode);
193 input.gcode.clear(); // GCode is already processed, so it isn't needed to store it.
194 m_layer_results.emplace(new LayerResult(input));
195 }
196
197 if (is_first_layer) // Buffer previous input result and output NOP.
199
200 // Export previous layer.
201 LayerResult *prev_layer_result = m_layer_results.front();
202 m_layer_results.pop();
203
206 for (size_t line_idx = 0; line_idx < next_layer_first_idx; ++line_idx)
207 output_gcode_line(line_idx);
208 m_gcode_lines.erase(m_gcode_lines.begin(), m_gcode_lines.begin() + int(next_layer_first_idx));
209
210 if (output_buffer_length > 0)
211 prev_layer_result->gcode = std::string(output_buffer.data());
212
213 assert(!input.nop_layer_result || m_layer_results.empty());
214 LayerResult out = *prev_layer_result;
215 delete prev_layer_result;
216 return out;
217}
std::queue< LayerResult * > m_layer_results
Definition PressureEqualizer.hpp:211
LayerResult process_layer(LayerResult &&input)
Definition PressureEqualizer.cpp:186
void output_gcode_line(size_t line_idx)
Definition PressureEqualizer.cpp:483
static LayerResult make_nop_layer_result()
Definition GCode.hpp:225

References Slic3r::LayerResult::gcode, m_gcode_lines, m_layer_results, Slic3r::LayerResult::make_nop_layer_result(), output_buffer, output_buffer_length, output_buffer_prev_length, output_gcode_line(), and process_layer().

Referenced by process_layer().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_line()

bool Slic3r::PressureEqualizer::process_line ( const char * line,
const char * line_end,
GCodeLine & buf )
private
267{
268 const size_t len = line_end - line;
269 if (strncmp(line, EXTRUSION_ROLE_TAG.data(), EXTRUSION_ROLE_TAG.length()) == 0) {
270 line += EXTRUSION_ROLE_TAG.length();
271 int role = atoi(line);
273#ifdef PRESSURE_EQUALIZER_DEBUG
274 ++line_idx;
275#endif
276 return false;
277 }
278
279 // Set the type, copy the line to the buffer.
280 buf.type = GCODELINETYPE_OTHER;
281 buf.modified = false;
282 if (buf.raw.size() < len + 1)
283 buf.raw.assign(line, line + len + 1);
284 else
285 memcpy(buf.raw.data(), line, len);
286 buf.raw[len] = 0;
287 buf.raw_length = len;
288
289 memcpy(buf.pos_start, m_current_pos, sizeof(float)*5);
290 memcpy(buf.pos_end, m_current_pos, sizeof(float)*5);
291 memset(buf.pos_provided, 0, 5);
292
293 buf.volumetric_extrusion_rate = 0.f;
294 buf.volumetric_extrusion_rate_start = 0.f;
295 buf.volumetric_extrusion_rate_end = 0.f;
296 buf.max_volumetric_extrusion_rate_slope_positive = 0.f;
297 buf.max_volumetric_extrusion_rate_slope_negative = 0.f;
298 buf.extrusion_role = m_current_extrusion_role;
299
300 std::string str_line(line, line_end);
301 const bool found_extrude_set_speed_tag = boost::contains(str_line, EXTRUDE_SET_SPEED_TAG);
302 const bool found_extrude_end_tag = boost::contains(str_line, EXTRUDE_END_TAG);
303 assert(!found_extrude_set_speed_tag || !found_extrude_end_tag);
304
305 if (found_extrude_set_speed_tag)
307 else if (found_extrude_end_tag)
308 this->opened_extrude_set_speed_block = false;
309
310 // Parse the G-code line, store the result into the buf.
311 switch (toupper(*line ++)) {
312 case 'G': {
313 int gcode = -1;
314 try {
315 gcode = parse_int(line);
316 } catch (Slic3r::InvalidArgument &) {
317 // Ignore invalid GCodes.
318 eatws(line);
319 break;
320 }
321
322 assert(gcode != -1);
323 eatws(line);
324 switch (gcode) {
325 case 0:
326 case 1:
327 {
328 // G0, G1: A FFF 3D printer does not make a difference between the two.
329 buf.adjustable_flow = this->opened_extrude_set_speed_block;
330 buf.extrude_set_speed_tag = found_extrude_set_speed_tag;
331 buf.extrude_end_tag = found_extrude_end_tag;
332 float new_pos[5];
333 memcpy(new_pos, m_current_pos, sizeof(float)*5);
334 bool changed[5] = { false, false, false, false, false };
335 while (!is_eol(*line)) {
336 const char axis = toupper(*line++);
337 int i = -1;
338 switch (axis) {
339 case 'X':
340 case 'Y':
341 case 'Z':
342 i = axis - 'X';
343 break;
344 case 'E':
345 i = 3;
346 break;
347 case 'F':
348 i = 4;
349 break;
350 default:
351 break;
352 }
353 if (i != -1) {
354 buf.pos_provided[i] = true;
355 new_pos[i] = parse_float(line, line_end - line);
356 if (i == 3 && m_use_relative_e_distances)
357 new_pos[i] += m_current_pos[i];
358 changed[i] = new_pos[i] != m_current_pos[i];
359 eatws(line);
360 }
361 }
362 if (changed[3]) {
363 // Extrusion, retract or unretract.
364 float diff = new_pos[3] - m_current_pos[3];
365 if (diff < 0) {
366 buf.type = GCODELINETYPE_RETRACT;
367 m_retracted = true;
368 } else if (! changed[0] && ! changed[1] && ! changed[2]) {
369 // assert(m_retracted);
370 buf.type = GCODELINETYPE_UNRETRACT;
371 m_retracted = false;
372 } else {
373 assert(changed[0] || changed[1]);
374 // Moving in XY plane.
375 buf.type = GCODELINETYPE_EXTRUDE;
376 // Calculate the volumetric extrusion rate.
377 float diff[4];
378 for (size_t i = 0; i < 4; ++ i)
379 diff[i] = new_pos[i] - m_current_pos[i];
380 // volumetric extrusion rate = A_filament * F_xyz * L_e / L_xyz [mm^3/min]
381 float len2 = diff[0]*diff[0]+diff[1]*diff[1]+diff[2]*diff[2];
382 float rate = m_filament_crossections[m_current_extruder] * new_pos[4] * sqrt((diff[3]*diff[3])/len2);
383 buf.volumetric_extrusion_rate = rate;
384 buf.volumetric_extrusion_rate_start = rate;
385 buf.volumetric_extrusion_rate_end = rate;
386
387#ifdef PRESSURE_EQUALIZER_STATISTIC
388 m_stat.update(rate, sqrt(len2));
389#endif
390#ifdef PRESSURE_EQUALIZER_DEBUG
391 if (rate < 40.f) {
392 printf("Extremely low flow rate: %f. Line %d, Length: %f, extrusion: %f Old position: (%f, %f, %f), new position: (%f, %f, %f)\n",
393 rate, int(line_idx), sqrt(len2), sqrt((diff[3] * diff[3]) / len2), m_current_pos[0], m_current_pos[1], m_current_pos[2],
394 new_pos[0], new_pos[1], new_pos[2]);
395 }
396#endif
397 }
398 } else if (changed[0] || changed[1] || changed[2]) {
399 // Moving without extrusion.
400 buf.type = GCODELINETYPE_MOVE;
401 }
402 memcpy(m_current_pos, new_pos, sizeof(float) * 5);
403 break;
404 }
405 case 92:
406 {
407 // G92 : Set Position
408 // Set a logical coordinate position to a new value without actually moving the machine motors.
409 // Which axes to set?
410 while (!is_eol(*line)) {
411 const char axis = toupper(*line++);
412 switch (axis) {
413 case 'X':
414 case 'Y':
415 case 'Z':
416 m_current_pos[axis - 'X'] = (!is_ws_or_eol(*line)) ? parse_float(line, line_end - line) : 0.f;
417 break;
418 case 'E':
419 m_current_pos[3] = (!is_ws_or_eol(*line)) ? parse_float(line, line_end - line) : 0.f;
420 break;
421 default:
422 break;
423 }
424 eatws(line);
425 }
426 break;
427 }
428 case 10:
429 case 22:
430 // Firmware retract.
431 buf.type = GCODELINETYPE_RETRACT;
432 m_retracted = true;
433 break;
434 case 11:
435 case 23:
436 // Firmware unretract.
437 buf.type = GCODELINETYPE_UNRETRACT;
438 m_retracted = false;
439 break;
440 default:
441 // Ignore the rest.
442 break;
443 }
444 break;
445 }
446 case 'M': {
447 eatws(line);
448 // Ignore the rest of the M-codes.
449 break;
450 }
451 case 'T':
452 {
453 // Activate an extruder head.
454 int new_extruder = -1;
455 try {
456 new_extruder = parse_int(line);
457 } catch (Slic3r::InvalidArgument &) {
458 // Ignore invalid GCodes starting with T.
459 eatws(line);
460 break;
461 }
462 assert(new_extruder != -1);
463
464 if (new_extruder != int(m_current_extruder)) {
465 m_current_extruder = new_extruder;
466 m_retracted = true;
467 buf.type = GCODELINETYPE_TOOL_CHANGE;
468 } else {
469 buf.type = GCODELINETYPE_NOOP;
470 }
471 break;
472 }
473 }
474
475 buf.extruder_id = m_current_extruder;
476 memcpy(buf.pos_end, m_current_pos, sizeof(float)*5);
477#ifdef PRESSURE_EQUALIZER_DEBUG
478 ++line_idx;
479#endif
480 return true;
481}
static const std::string EXTRUDE_SET_SPEED_TAG
Definition PressureEqualizer.cpp:30
static int parse_int(const char *&line)
Definition PressureEqualizer.cpp:235
static void eatws(const char *&line)
Definition PressureEqualizer.cpp:227
static const std::string EXTRUDE_END_TAG
Definition PressureEqualizer.cpp:29
static bool is_ws_or_eol(const char c)
Definition PressureEqualizer.cpp:224
static bool is_eol(const char c)
Definition PressureEqualizer.cpp:222
static float parse_float(const char *&line, const size_t line_length)
Definition PressureEqualizer.cpp:256
static const std::string EXTRUSION_ROLE_TAG
Definition PressureEqualizer.cpp:28
Slic3r::Polygons diff(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:731

References Slic3r::PressureEqualizer::GCodeLine::adjustable_flow, Slic3r::diff(), Slic3r::eatws(), Slic3r::EXTRUDE_END_TAG, Slic3r::PressureEqualizer::GCodeLine::extrude_end_tag, Slic3r::EXTRUDE_SET_SPEED_TAG, Slic3r::PressureEqualizer::GCodeLine::extrude_set_speed_tag, Slic3r::PressureEqualizer::GCodeLine::extruder_id, Slic3r::PressureEqualizer::GCodeLine::extrusion_role, Slic3r::EXTRUSION_ROLE_TAG, GCODELINETYPE_EXTRUDE, GCODELINETYPE_MOVE, GCODELINETYPE_NOOP, GCODELINETYPE_OTHER, GCODELINETYPE_RETRACT, GCODELINETYPE_TOOL_CHANGE, GCODELINETYPE_UNRETRACT, Slic3r::is_eol(), Slic3r::is_ws_or_eol(), m_current_extruder, m_current_extrusion_role, m_current_pos, m_filament_crossections, m_retracted, m_use_relative_e_distances, Slic3r::PressureEqualizer::GCodeLine::max_volumetric_extrusion_rate_slope_negative, Slic3r::PressureEqualizer::GCodeLine::max_volumetric_extrusion_rate_slope_positive, Slic3r::PressureEqualizer::GCodeLine::modified, opened_extrude_set_speed_block, Slic3r::parse_float(), Slic3r::parse_int(), Slic3r::PressureEqualizer::GCodeLine::pos_end, Slic3r::PressureEqualizer::GCodeLine::pos_provided, Slic3r::PressureEqualizer::GCodeLine::pos_start, Slic3r::PressureEqualizer::GCodeLine::raw, Slic3r::PressureEqualizer::GCodeLine::raw_length, Slic3r::PressureEqualizer::GCodeLine::type, Slic3r::PressureEqualizer::GCodeLine::volumetric_extrusion_rate, Slic3r::PressureEqualizer::GCodeLine::volumetric_extrusion_rate_end, and Slic3r::PressureEqualizer::GCodeLine::volumetric_extrusion_rate_start.

Referenced by process_layer().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ push_line_to_output()

void Slic3r::PressureEqualizer::push_line_to_output ( size_t line_idx,
float new_feedrate,
const char * comment )
private
931{
932 // Orca: sanity check, 1 mm/s is the minimum feedrate.
933 if (new_feedrate < 60)
934 new_feedrate = 60;
935 // Quantize speed changes to a minimum of 1mm/sec, to reduce gcode volume for trivial speed changes.
936 new_feedrate = std::round(new_feedrate / 60.0) * 60.0;
937 const GCodeLine &line = m_gcode_lines[line_idx];
938 if (line_idx > 0 && output_buffer_length > 0) {
939 const std::string prev_line_str = std::string(output_buffer.begin() + int(this->output_buffer_prev_length),
940 output_buffer.begin() + int(this->output_buffer_length) + 1);
942 this->output_buffer_length = this->output_buffer_prev_length; // Remove the last line because it only sets the speed for an empty block of g-code lines, so it is useless.
943 else
944 push_to_output(EXTRUDE_END_TAG.data(), EXTRUDE_END_TAG.length(), true);
945 } else
946 push_to_output(EXTRUDE_END_TAG.data(), EXTRUDE_END_TAG.length(), true);
947
948 // Supports keep the standard precision, see GCode::extrude_support().
949 const bool high_precision = m_high_precision && !is_support(line.extrusion_role);
950 GCodeG1Formatter feedrate_formatter(high_precision);
951 feedrate_formatter.emit_f(new_feedrate);
952 feedrate_formatter.emit_string(std::string(EXTRUDE_SET_SPEED_TAG.data(), EXTRUDE_SET_SPEED_TAG.length()));
953 if (line.extrusion_role == ExtrusionRole::erExternalPerimeter)
954 feedrate_formatter.emit_string(std::string(EXTERNAL_PERIMETER_TAG.data(), EXTERNAL_PERIMETER_TAG.length()));
955 push_to_output(feedrate_formatter);
956
957 GCodeG1Formatter extrusion_formatter(high_precision);
958 for (size_t axis_idx = 0; axis_idx < 3; ++axis_idx)
959 if (line.pos_provided[axis_idx])
960 extrusion_formatter.emit_axis(char('X' + axis_idx), line.pos_end[axis_idx], GCodeFormatter::xyz_digits(high_precision));
961 extrusion_formatter.emit_e(m_use_relative_e_distances ? (line.pos_end[3] - line.pos_start[3]) : line.pos_end[3]);
962
963 if (comment != nullptr)
964 extrusion_formatter.emit_string(std::string(comment));
965
966 push_to_output(extrusion_formatter);
967}
static constexpr int xyz_digits(bool high_precision)
Definition GCodeWriter.hpp:334
static const std::string EXTERNAL_PERIMETER_TAG
Definition PressureEqualizer.cpp:31
bool is_just_line_with_extrude_set_speed_tag(const std::string &line)
Definition PressureEqualizer.cpp:911
bool is_support(ExtrusionRole role)
Definition ExtrusionEntity.hpp:113

References Slic3r::GCodeFormatter::emit_axis(), Slic3r::GCodeFormatter::emit_e(), Slic3r::GCodeFormatter::emit_f(), Slic3r::GCodeFormatter::emit_string(), Slic3r::erExternalPerimeter, Slic3r::EXTERNAL_PERIMETER_TAG, Slic3r::EXTRUDE_END_TAG, Slic3r::EXTRUDE_SET_SPEED_TAG, Slic3r::PressureEqualizer::GCodeLine::extrusion_role, Slic3r::is_just_line_with_extrude_set_speed_tag(), Slic3r::is_support(), m_gcode_lines, m_high_precision, m_use_relative_e_distances, output_buffer, output_buffer_length, output_buffer_prev_length, Slic3r::PressureEqualizer::GCodeLine::pos_end, Slic3r::PressureEqualizer::GCodeLine::pos_provided, Slic3r::PressureEqualizer::GCodeLine::pos_start, push_to_output(), and Slic3r::GCodeFormatter::xyz_digits().

Referenced by output_gcode_line().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ push_to_output() [1/3]

void Slic3r::PressureEqualizer::push_to_output ( const char * text,
size_t len,
bool add_eol = true )
inlineprivate
879{
880 // New length of the output buffer content.
881 size_t len_new = output_buffer_length + len + 1;
882 if (add_eol)
883 ++len_new;
884
885 // Resize the output buffer to a power of 2 higher than the required memory.
886 if (output_buffer.size() < len_new) {
887 size_t v = len_new;
888 // Compute the next highest power of 2 of 32-bit v
889 // http://graphics.stanford.edu/~seander/bithacks.html
890 v--;
891 v |= v >> 1;
892 v |= v >> 2;
893 v |= v >> 4;
894 v |= v >> 8;
895 v |= v >> 16;
896 v++;
897 output_buffer.resize(v);
898 }
899
900 // Copy the text to the output.
901 if (len != 0) {
902 memcpy(output_buffer.data() + output_buffer_length, text, len);
905 }
906 if (add_eol)
909}

References output_buffer, output_buffer_length, and output_buffer_prev_length.

◆ push_to_output() [2/3]

void Slic3r::PressureEqualizer::push_to_output ( const std::string & text,
bool add_eol )
inlineprivate
874{
875 return this->push_to_output(text.data(), text.size(), add_eol);
876}

References push_to_output().

Here is the call graph for this function:

◆ push_to_output() [3/3]

void Slic3r::PressureEqualizer::push_to_output ( GCodeG1Formatter & formatter)
inlineprivate
869{
870 return this->push_to_output(formatter.string(), false);
871}

References push_to_output(), and Slic3r::GCodeFormatter::string().

Referenced by output_gcode_line(), push_line_to_output(), push_to_output(), and push_to_output().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ m_current_extruder

size_t Slic3r::PressureEqualizer::m_current_extruder
private

Referenced by PressureEqualizer(), and process_line().

◆ m_current_extrusion_role

ExtrusionRole Slic3r::PressureEqualizer::m_current_extrusion_role
private

Referenced by PressureEqualizer(), and process_line().

◆ m_current_pos

float Slic3r::PressureEqualizer::m_current_pos[5]
private

Referenced by PressureEqualizer(), and process_line().

◆ m_extrusion_rate_smoothing_external_perimeter_only

bool Slic3r::PressureEqualizer::m_extrusion_rate_smoothing_external_perimeter_only
private

◆ m_filament_crossections

std::vector<float> Slic3r::PressureEqualizer::m_filament_crossections
private

Referenced by PressureEqualizer(), and process_line().

◆ m_gcode_lines

◆ m_high_precision

bool Slic3r::PressureEqualizer::m_high_precision
private

◆ m_layer_results

std::queue<LayerResult*> Slic3r::PressureEqualizer::m_layer_results

Referenced by process_layer().

◆ m_max_segment_length

float Slic3r::PressureEqualizer::m_max_segment_length
private

◆ m_max_volumetric_extrusion_rate_slope_negative

float Slic3r::PressureEqualizer::m_max_volumetric_extrusion_rate_slope_negative
private

Referenced by PressureEqualizer().

◆ m_max_volumetric_extrusion_rate_slope_positive

float Slic3r::PressureEqualizer::m_max_volumetric_extrusion_rate_slope_positive
private

Referenced by PressureEqualizer().

◆ m_max_volumetric_extrusion_rate_slopes

ExtrusionRateSlope Slic3r::PressureEqualizer::m_max_volumetric_extrusion_rate_slopes[size_t(ExtrusionRole::erCount)]
private

◆ m_retracted

bool Slic3r::PressureEqualizer::m_retracted
private

Referenced by PressureEqualizer(), and process_line().

◆ m_use_relative_e_distances

bool Slic3r::PressureEqualizer::m_use_relative_e_distances
private

◆ opened_extrude_set_speed_block

bool Slic3r::PressureEqualizer::opened_extrude_set_speed_block = false
private

◆ output_buffer

std::vector<char> Slic3r::PressureEqualizer::output_buffer
private

◆ output_buffer_length

size_t Slic3r::PressureEqualizer::output_buffer_length
private

◆ output_buffer_prev_length

size_t Slic3r::PressureEqualizer::output_buffer_prev_length
private

The documentation for this class was generated from the following files: