Prusa Slicer 2.6.0
Loading...
Searching...
No Matches
Slic3r::PressureEqualizer Class Reference

#include <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< GCodeLinem_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)
 
void output_gcode_line (size_t line_idx)
 
void adjust_volumetric_rate ()
 
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(GCodeExtrusionRole::Count)]
 
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
 
GCodeExtrusionRole m_current_extrusion_role
 
bool m_retracted
 
bool m_use_relative_e_distances
 
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 
88 {
97 };
@ GCODELINETYPE_INVALID
Definition PressureEqualizer.hpp:89
@ GCODELINETYPE_RETRACT
Definition PressureEqualizer.hpp:92
@ GCODELINETYPE_EXTRUDE
Definition PressureEqualizer.hpp:96
@ GCODELINETYPE_TOOL_CHANGE
Definition PressureEqualizer.hpp:94
@ GCODELINETYPE_OTHER
Definition PressureEqualizer.hpp:91
@ GCODELINETYPE_MOVE
Definition PressureEqualizer.hpp:95
@ GCODELINETYPE_UNRETRACT
Definition PressureEqualizer.hpp:93
@ GCODELINETYPE_NOOP
Definition PressureEqualizer.hpp:90

Constructor & Destructor Documentation

◆ PressureEqualizer() [1/2]

Slic3r::PressureEqualizer::PressureEqualizer ( )
delete

◆ PressureEqualizer() [2/2]

Slic3r::PressureEqualizer::PressureEqualizer ( const Slic3r::GCodeConfig &  config)
explicit
30 : m_use_relative_e_distances(config.use_relative_e_distances.value)
31{
32 // Preallocate some data, so that output_buffer.data() will return an empty string.
33 output_buffer.assign(32, 0);
36
38 // Zero the position of the XYZE axes + the current feed
39 memset(m_current_pos, 0, sizeof(float) * 5);
41 // Expect the first command to fill the nozzle (deretract).
42 m_retracted = true;
43
44 // Calculate filamet crossections for the multiple extruders.
46 for (double r : config.filament_diameter.values) {
47 double a = 0.25f * M_PI * r * r;
48 m_filament_crossections.push_back(float(a));
49 }
50
51 // 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
52 // 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
53 // 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
54 m_max_volumetric_extrusion_rate_slope_positive = float(config.max_volumetric_extrusion_rate_slope_positive.value) * 60.f * 60.f;
55 m_max_volumetric_extrusion_rate_slope_negative = float(config.max_volumetric_extrusion_rate_slope_negative.value) * 60.f * 60.f;
56
57 for (ExtrusionRateSlope &extrusion_rate_slope : m_max_volumetric_extrusion_rate_slopes) {
58 extrusion_rate_slope.negative = m_max_volumetric_extrusion_rate_slope_negative;
59 extrusion_rate_slope.positive = m_max_volumetric_extrusion_rate_slope_positive;
60 }
61
62 // Don't regulate the pressure before and after gap-fill and ironing.
66 }
67
69
70#ifdef PRESSURE_EQUALIZER_STATISTIC
71 m_stat.reset();
72#endif
73
74#ifdef PRESSURE_EQUALIZER_DEBUG
75 line_idx = 0;
76#endif
77}
#define M_PI
Definition ExtrusionSimulator.cpp:20
float positive
Definition PressureEqualizer.hpp:65
std::vector< char > output_buffer
Definition PressureEqualizer.hpp:173
bool m_use_relative_e_distances
Definition PressureEqualizer.hpp:82
float m_max_volumetric_extrusion_rate_slope_negative
Definition PressureEqualizer.hpp:70
GCodeExtrusionRole m_current_extrusion_role
Definition PressureEqualizer.hpp:80
float negative
Definition PressureEqualizer.hpp:66
float m_max_volumetric_extrusion_rate_slope_positive
Definition PressureEqualizer.hpp:69
size_t output_buffer_length
Definition PressureEqualizer.hpp:174
float m_current_pos[5]
Definition PressureEqualizer.hpp:78
bool opened_extrude_set_speed_block
Definition PressureEqualizer.hpp:86
ExtrusionRateSlope m_max_volumetric_extrusion_rate_slopes[size_t(GCodeExtrusionRole::Count)]
Definition PressureEqualizer.hpp:68
size_t output_buffer_prev_length
Definition PressureEqualizer.hpp:175
bool m_retracted
Definition PressureEqualizer.hpp:81
size_t m_current_extruder
Definition PressureEqualizer.hpp:79
std::vector< float > m_filament_crossections
Definition PressureEqualizer.hpp:74
filament_diameter((ConfigOptionFloats, filament_density))((ConfigOptionStrings
GCodeExtrusionRole
Definition ExtrusionRole.hpp:104

References Slic3r::GapFill, Slic3r::Ironing, m_current_extruder, m_current_extrusion_role, m_current_pos, m_filament_crossections, m_max_volumetric_extrusion_rate_slope_negative, m_max_volumetric_extrusion_rate_slope_positive, m_max_volumetric_extrusion_rate_slopes, M_PI, m_retracted, Slic3r::PressureEqualizer::ExtrusionRateSlope::negative, Slic3r::None, opened_extrude_set_speed_block, output_buffer, output_buffer_length, output_buffer_prev_length, and Slic3r::PressureEqualizer::ExtrusionRateSlope::positive.

◆ ~PressureEqualizer()

Slic3r::PressureEqualizer::~PressureEqualizer ( )
default

Member Function Documentation

◆ adjust_volumetric_rate()

void Slic3r::PressureEqualizer::adjust_volumetric_rate ( )
private
510{
511 if (m_gcode_lines.size() < 2)
512 return;
513
514 // Go back from the current circular_buffer_pos and lower the feedtrate to decrease the slope of the extrusion rate changes.
515 size_t fist_line_idx = size_t(std::max<int>(0, int(m_gcode_lines.size()) - max_look_back_limit));
516 const size_t last_line_idx = m_gcode_lines.size() - 1;
517 size_t line_idx = last_line_idx;
518 if (line_idx == fist_line_idx || !m_gcode_lines[line_idx].extruding())
519 // Nothing to do, the last move is not extruding.
520 return;
521
522 std::array<float, size_t(GCodeExtrusionRole::Count)> feedrate_per_extrusion_role{};
523 feedrate_per_extrusion_role.fill(std::numeric_limits<float>::max());
524 feedrate_per_extrusion_role[int(m_gcode_lines[line_idx].extrusion_role)] = m_gcode_lines[line_idx].volumetric_extrusion_rate_start;
525
526 while (line_idx != fist_line_idx) {
527 size_t idx_prev = line_idx - 1;
528 for (; !m_gcode_lines[idx_prev].extruding() && idx_prev != fist_line_idx; --idx_prev);
529 if (!m_gcode_lines[idx_prev].extruding())
530 break;
531 // Don't decelerate before ironing and gap-fill.
532 if (m_gcode_lines[line_idx].extrusion_role == GCodeExtrusionRole::Ironing || m_gcode_lines[line_idx].extrusion_role == GCodeExtrusionRole::GapFill) {
533 line_idx = idx_prev;
534 continue;
535 }
536 // Volumetric extrusion rate at the start of the succeding segment.
537 float rate_succ = m_gcode_lines[line_idx].volumetric_extrusion_rate_start;
538 // What is the gradient of the extrusion rate between idx_prev and idx?
539 line_idx = idx_prev;
540 GCodeLine &line = m_gcode_lines[line_idx];
541
542 for (size_t iRole = 1; iRole < size_t(GCodeExtrusionRole::Count); ++ iRole) {
543 const float &rate_slope = m_max_volumetric_extrusion_rate_slopes[iRole].negative;
544 if (rate_slope == 0 || feedrate_per_extrusion_role[iRole] == std::numeric_limits<float>::max())
545 continue; // The negative rate is unlimited or the rate for GCodeExtrusionRole iRole is unlimited.
546
547 float rate_end = feedrate_per_extrusion_role[iRole];
548 if (iRole == size_t(line.extrusion_role) && rate_succ < rate_end)
549 // Limit by the succeeding volumetric flow rate.
550 rate_end = rate_succ;
551
552 if (!line.adjustable_flow || line.extrusion_role == GCodeExtrusionRole::ExternalPerimeter || line.extrusion_role == GCodeExtrusionRole::GapFill || line.extrusion_role == GCodeExtrusionRole::BridgeInfill || line.extrusion_role == GCodeExtrusionRole::Ironing) {
553 rate_end = line.volumetric_extrusion_rate_end;
554 } else if (line.volumetric_extrusion_rate_end > rate_end) {
555 line.volumetric_extrusion_rate_end = rate_end;
556 line.max_volumetric_extrusion_rate_slope_negative = rate_slope;
557 line.modified = true;
558 } else if (iRole == size_t(line.extrusion_role)) {
559 rate_end = line.volumetric_extrusion_rate_end;
560 } else {
561 // Use the original, 'floating' extrusion rate as a starting point for the limiter.
562 }
563
564 if (line.adjustable_flow) {
565 float rate_start = rate_end + rate_slope * line.time_corrected();
566 if (rate_start < line.volumetric_extrusion_rate_start) {
567 // Limit the volumetric extrusion rate at the start of this segment due to a segment
568 // of ExtrusionType iRole, which will be extruded in the future.
569 line.volumetric_extrusion_rate_start = rate_start;
570 line.max_volumetric_extrusion_rate_slope_negative = rate_slope;
571 line.modified = true;
572 }
573 }
574// feedrate_per_extrusion_role[iRole] = (iRole == line.extrusion_role) ? line.volumetric_extrusion_rate_start : rate_start;
575 // Don't store feed rate for ironing and gap-fill.
576 if (line.extrusion_role != GCodeExtrusionRole::Ironing && line.extrusion_role != GCodeExtrusionRole::GapFill)
577 feedrate_per_extrusion_role[iRole] = line.volumetric_extrusion_rate_start;
578 }
579 }
580
581 feedrate_per_extrusion_role.fill(std::numeric_limits<float>::max());
582 feedrate_per_extrusion_role[size_t(m_gcode_lines[line_idx].extrusion_role)] = m_gcode_lines[line_idx].volumetric_extrusion_rate_end;
583
584 assert(m_gcode_lines[line_idx].extruding());
585 while (line_idx != last_line_idx) {
586 size_t idx_next = line_idx + 1;
587 for (; !m_gcode_lines[idx_next].extruding() && idx_next != last_line_idx; ++idx_next);
588 if (!m_gcode_lines[idx_next].extruding())
589 break;
590 // Don't accelerate after ironing and gap-fill.
591 if (m_gcode_lines[line_idx].extrusion_role == GCodeExtrusionRole::Ironing || m_gcode_lines[line_idx].extrusion_role == GCodeExtrusionRole::GapFill) {
592 line_idx = idx_next;
593 continue;
594 }
595 float rate_prec = m_gcode_lines[line_idx].volumetric_extrusion_rate_end;
596 // What is the gradient of the extrusion rate between idx_prev and idx?
597 line_idx = idx_next;
598 GCodeLine &line = m_gcode_lines[line_idx];
599
600 for (size_t iRole = 1; iRole < size_t(GCodeExtrusionRole::Count); ++ iRole) {
601 const float &rate_slope = m_max_volumetric_extrusion_rate_slopes[iRole].positive;
602 if (rate_slope == 0 || feedrate_per_extrusion_role[iRole] == std::numeric_limits<float>::max())
603 continue; // The positive rate is unlimited or the rate for GCodeExtrusionRole iRole is unlimited.
604
605 float rate_start = feedrate_per_extrusion_role[iRole];
606 if (!line.adjustable_flow || line.extrusion_role == GCodeExtrusionRole::ExternalPerimeter || line.extrusion_role == GCodeExtrusionRole::GapFill || line.extrusion_role == GCodeExtrusionRole::BridgeInfill || line.extrusion_role == GCodeExtrusionRole::Ironing) {
607 rate_start = line.volumetric_extrusion_rate_start;
608 } else if (iRole == size_t(line.extrusion_role) && rate_prec < rate_start)
609 rate_start = rate_prec;
610 if (line.volumetric_extrusion_rate_start > rate_start) {
611 line.volumetric_extrusion_rate_start = rate_start;
612 line.max_volumetric_extrusion_rate_slope_positive = rate_slope;
613 line.modified = true;
614 } else if (iRole == size_t(line.extrusion_role)) {
615 rate_start = line.volumetric_extrusion_rate_start;
616 } else {
617 // Use the original, 'floating' extrusion rate as a starting point for the limiter.
618 }
619
620 if (line.adjustable_flow) {
621 float rate_end = rate_start + rate_slope * line.time_corrected();
622 if (rate_end < line.volumetric_extrusion_rate_end) {
623 // Limit the volumetric extrusion rate at the start of this segment due to a segment
624 // of ExtrusionType iRole, which was extruded before.
625 line.volumetric_extrusion_rate_end = rate_end;
626 line.max_volumetric_extrusion_rate_slope_positive = rate_slope;
627 line.modified = true;
628 }
629 }
630// feedrate_per_extrusion_role[iRole] = (iRole == line.extrusion_role) ? line.volumetric_extrusion_rate_end : rate_end;
631 // Don't store feed rate for ironing and gap-fill.
632 if (line.extrusion_role != GCodeExtrusionRole::Ironing && line.extrusion_role != GCodeExtrusionRole::GapFill)
633 feedrate_per_extrusion_role[iRole] = line.volumetric_extrusion_rate_end;
634 }
635 }
636}
std::vector< GCodeLine > m_gcode_lines
Definition PressureEqualizer.hpp:199
static constexpr int max_look_back_limit
Definition PressureEqualizer.cpp:28

References Slic3r::PressureEqualizer::GCodeLine::adjustable_flow, Slic3r::BridgeInfill, Slic3r::Count, Slic3r::ExternalPerimeter, Slic3r::PressureEqualizer::GCodeLine::extrusion_role, Slic3r::GapFill, Slic3r::Ironing, m_gcode_lines, m_max_volumetric_extrusion_rate_slopes, Slic3r::max_look_back_limit, Slic3r::PressureEqualizer::GCodeLine::max_volumetric_extrusion_rate_slope_negative, Slic3r::PressureEqualizer::GCodeLine::max_volumetric_extrusion_rate_slope_positive, Slic3r::PressureEqualizer::GCodeLine::modified, Slic3r::PressureEqualizer::ExtrusionRateSlope::negative, Slic3r::PressureEqualizer::ExtrusionRateSlope::positive, Slic3r::PressureEqualizer::GCodeLine::time_corrected(), Slic3r::PressureEqualizer::GCodeLine::volumetric_extrusion_rate_end, and Slic3r::PressureEqualizer::GCodeLine::volumetric_extrusion_rate_start.

Referenced by process_line().

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

◆ output_gcode_line()

void Slic3r::PressureEqualizer::output_gcode_line ( size_t  line_idx)
private
402{
403 GCodeLine &line = m_gcode_lines[line_idx];
404 if (!line.modified) {
405 push_to_output(line.raw.data(), line.raw_length, true);
406 return;
407 }
408
409 // The line was modified.
410 // Find the comment.
411 const char *comment = line.raw.data();
412 while (*comment != ';' && *comment != 0) ++comment;
413 if (*comment != ';')
414 comment = nullptr;
415
416 // Emit the line with lowered extrusion rates.
417 float l = line.dist_xyz();
418 if (auto nSegments = size_t(ceil(l / max_segment_length)); nSegments == 1) { // Just update this segment.
419 push_line_to_output(line_idx, line.feedrate() * line.volumetric_correction_avg(), comment);
420 } else {
421 bool accelerating = line.volumetric_extrusion_rate_start < line.volumetric_extrusion_rate_end;
422 // Update the initial and final feed rate values.
423 line.pos_start[4] = line.volumetric_extrusion_rate_start * line.pos_end[4] / line.volumetric_extrusion_rate;
424 line.pos_end [4] = line.volumetric_extrusion_rate_end * line.pos_end[4] / line.volumetric_extrusion_rate;
425 float feed_avg = 0.5f * (line.pos_start[4] + line.pos_end[4]);
426 // Limiting volumetric extrusion rate slope for this segment.
427 float max_volumetric_extrusion_rate_slope = accelerating ? line.max_volumetric_extrusion_rate_slope_positive :
428 line.max_volumetric_extrusion_rate_slope_negative;
429 // Total time for the segment, corrected for the possibly lowered volumetric feed rate,
430 // if accelerating / decelerating over the complete segment.
431 float t_total = line.dist_xyz() / feed_avg;
432 // Time of the acceleration / deceleration part of the segment, if accelerating / decelerating
433 // with the maximum volumetric extrusion rate slope.
434 float t_acc = 0.5f * (line.volumetric_extrusion_rate_start + line.volumetric_extrusion_rate_end) / max_volumetric_extrusion_rate_slope;
435 float l_acc = l;
436 float l_steady = 0.f;
437 if (t_acc < t_total) {
438 // One may achieve higher print speeds if part of the segment is not speed limited.
439 l_acc = t_acc * feed_avg;
440 l_steady = l - l_acc;
441 if (l_steady < 0.5f * max_segment_length) {
442 l_acc = l;
443 l_steady = 0.f;
444 } else
445 nSegments = size_t(ceil(l_acc / max_segment_length));
446 }
447 float pos_start[5];
448 float pos_end[5];
449 float pos_end2[4];
450 memcpy(pos_start, line.pos_start, sizeof(float) * 5);
451 memcpy(pos_end, line.pos_end, sizeof(float) * 5);
452 if (l_steady > 0.f) {
453 // There will be a steady feed segment emitted.
454 if (accelerating) {
455 // Prepare the final steady feed rate segment.
456 memcpy(pos_end2, pos_end, sizeof(float)*4);
457 float t = l_acc / l;
458 for (int i = 0; i < 4; ++ i) {
459 pos_end[i] = pos_start[i] + (pos_end[i] - pos_start[i]) * t;
460 line.pos_provided[i] = true;
461 }
462 } else {
463 // Emit the steady feed rate segment.
464 float t = l_steady / l;
465 for (int i = 0; i < 4; ++ i) {
466 line.pos_end[i] = pos_start[i] + (pos_end[i] - pos_start[i]) * t;
467 line.pos_provided[i] = true;
468 }
469 push_line_to_output(line_idx, pos_start[4], comment);
470 comment = nullptr;
471
472 float new_pos_start_feedrate = pos_start[4];
473
474 memcpy(line.pos_start, line.pos_end, sizeof(float)*5);
475 memcpy(pos_start, line.pos_end, sizeof(float)*5);
476
477 line.pos_start[4] = new_pos_start_feedrate;
478 pos_start[4] = new_pos_start_feedrate;
479 }
480 }
481 // Split the segment into pieces.
482 for (size_t i = 1; i < nSegments; ++ i) {
483 float t = float(i) / float(nSegments);
484 for (size_t j = 0; j < 4; ++ j) {
485 line.pos_end[j] = pos_start[j] + (pos_end[j] - pos_start[j]) * t;
486 line.pos_provided[j] = true;
487 }
488 // Interpolate the feed rate at the center of the segment.
489 push_line_to_output(line_idx, pos_start[4] + (pos_end[4] - pos_start[4]) * (float(i) - 0.5f) / float(nSegments), comment);
490 comment = nullptr;
491 memcpy(line.pos_start, line.pos_end, sizeof(float)*5);
492 }
493 if (l_steady > 0.f && accelerating) {
494 for (int i = 0; i < 4; ++ i) {
495 line.pos_end[i] = pos_end2[i];
496 line.pos_provided[i] = true;
497 }
498 push_line_to_output(line_idx, pos_end[4], comment);
499 } else {
500 for (int i = 0; i < 4; ++ i) {
501 line.pos_end[i] = pos_end[i];
502 line.pos_provided[i] = true;
503 }
504 push_line_to_output(line_idx, pos_end[4], comment);
505 }
506 }
507}
EIGEN_DEVICE_FUNC const CeilReturnType ceil() const
Definition ArrayCwiseUnaryOps.h:402
void push_line_to_output(size_t line_idx, float new_feedrate, const char *comment)
Definition PressureEqualizer.cpp:700
void push_to_output(GCodeG1Formatter &formatter)
Definition PressureEqualizer.cpp:638
#define comment
Definition lexer.c:1004
static constexpr float max_segment_length
Definition PressureEqualizer.cpp:23

References ceil(), comment, Slic3r::PressureEqualizer::GCodeLine::dist_xyz(), Slic3r::PressureEqualizer::GCodeLine::feedrate(), m_gcode_lines, Slic3r::max_segment_length, 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
80{
81 if (!gcode.empty()) {
82 const char *gcode_begin = gcode.c_str();
83 while (*gcode_begin != 0) {
84 // Find end of the line.
85 const char *gcode_end = gcode_begin;
86 // Slic3r always generates end of lines in a Unix style.
87 for (; *gcode_end != 0 && *gcode_end != '\n'; ++gcode_end);
88
89 m_gcode_lines.emplace_back();
90 if (!this->process_line(gcode_begin, gcode_end, m_gcode_lines.back())) {
91 // The line has to be forgotten. It contains comment marks, which shall be filtered out of the target g-code.
92 m_gcode_lines.pop_back();
93 }
94 gcode_begin = gcode_end;
95 if (*gcode_begin == '\n')
96 ++gcode_begin;
97 }
98 assert(!this->opened_extrude_set_speed_block);
99 }
100}
bool process_line(const char *line, const char *line_end, GCodeLine &buf)
Definition PressureEqualizer.cpp:182

References m_gcode_lines, 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)
103{
104 const bool is_first_layer = m_layer_results.empty();
105 const size_t next_layer_first_idx = m_gcode_lines.size();
106
107 if (!input.nop_layer_result) {
108 this->process_layer(input.gcode);
109 input.gcode.clear(); // GCode is already processed, so it isn't needed to store it.
110 m_layer_results.emplace(new LayerResult(input));
111 }
112
113 if (is_first_layer) // Buffer previous input result and output NOP.
115
116 // Export previous layer.
117 LayerResult *prev_layer_result = m_layer_results.front();
118 m_layer_results.pop();
119
122 for (size_t line_idx = 0; line_idx < next_layer_first_idx; ++line_idx)
123 output_gcode_line(line_idx);
124 m_gcode_lines.erase(m_gcode_lines.begin(), m_gcode_lines.begin() + int(next_layer_first_idx));
125
126 if (output_buffer_length > 0)
127 prev_layer_result->gcode = std::string(output_buffer.data());
128
129 assert(!input.nop_layer_result || m_layer_results.empty());
130 LayerResult out = *prev_layer_result;
131 delete prev_layer_result;
132 return out;
133}
std::queue< LayerResult * > m_layer_results
Definition PressureEqualizer.hpp:197
LayerResult process_layer(LayerResult &&input)
Definition PressureEqualizer.cpp:102
void output_gcode_line(size_t line_idx)
Definition PressureEqualizer.cpp:401
static int input(void)
static LayerResult make_nop_layer_result()
Definition GCode.hpp:129

References Slic3r::LayerResult::gcode, input(), 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
183{
184 const size_t len = line_end - line;
185 if (strncmp(line, EXTRUSION_ROLE_TAG.data(), EXTRUSION_ROLE_TAG.length()) == 0) {
186 line += EXTRUSION_ROLE_TAG.length();
187 int role = atoi(line);
189#ifdef PRESSURE_EQUALIZER_DEBUG
190 ++line_idx;
191#endif
192 return false;
193 }
194
195 // Set the type, copy the line to the buffer.
196 buf.type = GCODELINETYPE_OTHER;
197 buf.modified = false;
198 if (buf.raw.size() < len + 1)
199 buf.raw.assign(line, line + len + 1);
200 else
201 memcpy(buf.raw.data(), line, len);
202 buf.raw[len] = 0;
203 buf.raw_length = len;
204
205 memcpy(buf.pos_start, m_current_pos, sizeof(float)*5);
206 memcpy(buf.pos_end, m_current_pos, sizeof(float)*5);
207 memset(buf.pos_provided, 0, 5);
208
209 buf.volumetric_extrusion_rate = 0.f;
210 buf.volumetric_extrusion_rate_start = 0.f;
211 buf.volumetric_extrusion_rate_end = 0.f;
212 buf.max_volumetric_extrusion_rate_slope_positive = 0.f;
213 buf.max_volumetric_extrusion_rate_slope_negative = 0.f;
214 buf.extrusion_role = m_current_extrusion_role;
215
216 std::string str_line(line, line_end);
217 const bool found_extrude_set_speed_tag = boost::contains(str_line, EXTRUDE_SET_SPEED_TAG);
218 const bool found_extrude_end_tag = boost::contains(str_line, EXTRUDE_END_TAG);
219 assert(!found_extrude_set_speed_tag || !found_extrude_end_tag);
220
221 if (found_extrude_set_speed_tag)
223 else if (found_extrude_end_tag)
224 this->opened_extrude_set_speed_block = false;
225
226 // Parse the G-code line, store the result into the buf.
227 switch (toupper(*line ++)) {
228 case 'G': {
229 int gcode = -1;
230 try {
231 gcode = parse_int(line);
232 } catch (Slic3r::InvalidArgument &) {
233 // Ignore invalid GCodes.
234 eatws(line);
235 break;
236 }
237
238 assert(gcode != -1);
239 eatws(line);
240 switch (gcode) {
241 case 0:
242 case 1:
243 {
244 // G0, G1: A FFF 3D printer does not make a difference between the two.
245 buf.adjustable_flow = this->opened_extrude_set_speed_block;
246 buf.extrude_set_speed_tag = found_extrude_set_speed_tag;
247 buf.extrude_end_tag = found_extrude_end_tag;
248 float new_pos[5];
249 memcpy(new_pos, m_current_pos, sizeof(float)*5);
250 bool changed[5] = { false, false, false, false, false };
251 while (!is_eol(*line)) {
252 const char axis = toupper(*line++);
253 int i = -1;
254 switch (axis) {
255 case 'X':
256 case 'Y':
257 case 'Z':
258 i = axis - 'X';
259 break;
260 case 'E':
261 i = 3;
262 break;
263 case 'F':
264 i = 4;
265 break;
266 default:
267 break;
268 }
269 if (i != -1) {
270 buf.pos_provided[i] = true;
271 new_pos[i] = parse_float(line, line_end - line);
272 if (i == 3 && m_use_relative_e_distances)
273 new_pos[i] += m_current_pos[i];
274 changed[i] = new_pos[i] != m_current_pos[i];
275 eatws(line);
276 }
277 }
278 if (changed[3]) {
279 // Extrusion, retract or unretract.
280 float diff = new_pos[3] - m_current_pos[3];
281 if (diff < 0) {
282 buf.type = GCODELINETYPE_RETRACT;
283 m_retracted = true;
284 } else if (! changed[0] && ! changed[1] && ! changed[2]) {
285 // assert(m_retracted);
286 buf.type = GCODELINETYPE_UNRETRACT;
287 m_retracted = false;
288 } else {
289 assert(changed[0] || changed[1]);
290 // Moving in XY plane.
291 buf.type = GCODELINETYPE_EXTRUDE;
292 // Calculate the volumetric extrusion rate.
293 float diff[4];
294 for (size_t i = 0; i < 4; ++ i)
295 diff[i] = new_pos[i] - m_current_pos[i];
296 // volumetric extrusion rate = A_filament * F_xyz * L_e / L_xyz [mm^3/min]
297 float len2 = diff[0]*diff[0]+diff[1]*diff[1]+diff[2]*diff[2];
298 float rate = m_filament_crossections[m_current_extruder] * new_pos[4] * sqrt((diff[3]*diff[3])/len2);
299 buf.volumetric_extrusion_rate = rate;
300 buf.volumetric_extrusion_rate_start = rate;
301 buf.volumetric_extrusion_rate_end = rate;
302
303#ifdef PRESSURE_EQUALIZER_STATISTIC
304 m_stat.update(rate, sqrt(len2));
305#endif
306#ifdef PRESSURE_EQUALIZER_DEBUG
307 if (rate < 40.f) {
308 printf("Extremely low flow rate: %f. Line %d, Length: %f, extrusion: %f Old position: (%f, %f, %f), new position: (%f, %f, %f)\n",
309 rate, int(line_idx), sqrt(len2), sqrt((diff[3] * diff[3]) / len2), m_current_pos[0], m_current_pos[1], m_current_pos[2],
310 new_pos[0], new_pos[1], new_pos[2]);
311 }
312#endif
313 }
314 } else if (changed[0] || changed[1] || changed[2]) {
315 // Moving without extrusion.
316 buf.type = GCODELINETYPE_MOVE;
317 }
318 memcpy(m_current_pos, new_pos, sizeof(float) * 5);
319 break;
320 }
321 case 92:
322 {
323 // G92 : Set Position
324 // Set a logical coordinate position to a new value without actually moving the machine motors.
325 // Which axes to set?
326 while (!is_eol(*line)) {
327 const char axis = toupper(*line++);
328 switch (axis) {
329 case 'X':
330 case 'Y':
331 case 'Z':
332 m_current_pos[axis - 'X'] = (!is_ws_or_eol(*line)) ? parse_float(line, line_end - line) : 0.f;
333 break;
334 case 'E':
335 m_current_pos[3] = (!is_ws_or_eol(*line)) ? parse_float(line, line_end - line) : 0.f;
336 break;
337 default:
338 break;
339 }
340 eatws(line);
341 }
342 break;
343 }
344 case 10:
345 case 22:
346 // Firmware retract.
347 buf.type = GCODELINETYPE_RETRACT;
348 m_retracted = true;
349 break;
350 case 11:
351 case 23:
352 // Firmware unretract.
353 buf.type = GCODELINETYPE_UNRETRACT;
354 m_retracted = false;
355 break;
356 default:
357 // Ignore the rest.
358 break;
359 }
360 break;
361 }
362 case 'M': {
363 eatws(line);
364 // Ignore the rest of the M-codes.
365 break;
366 }
367 case 'T':
368 {
369 // Activate an extruder head.
370 int new_extruder = -1;
371 try {
372 new_extruder = parse_int(line);
373 } catch (Slic3r::InvalidArgument &) {
374 // Ignore invalid GCodes starting with T.
375 eatws(line);
376 break;
377 }
378 assert(new_extruder != -1);
379
380 if (new_extruder != int(m_current_extruder)) {
381 m_current_extruder = new_extruder;
382 m_retracted = true;
383 buf.type = GCODELINETYPE_TOOL_CHANGE;
384 } else {
385 buf.type = GCODELINETYPE_NOOP;
386 }
387 break;
388 }
389 }
390
391 buf.extruder_id = m_current_extruder;
392 memcpy(buf.pos_end, m_current_pos, sizeof(float)*5);
393
395#ifdef PRESSURE_EQUALIZER_DEBUG
396 ++line_idx;
397#endif
398 return true;
399}
EIGEN_DEVICE_FUNC const SqrtReturnType sqrt() const
Definition ArrayCwiseUnaryOps.h:152
void adjust_volumetric_rate()
Definition PressureEqualizer.cpp:509
static const std::string EXTRUDE_SET_SPEED_TAG
Definition PressureEqualizer.cpp:18
static int parse_int(const char *&line)
Definition PressureEqualizer.cpp:151
static void eatws(const char *&line)
Definition PressureEqualizer.cpp:143
static const std::string EXTRUDE_END_TAG
Definition PressureEqualizer.cpp:17
static bool is_ws_or_eol(const char c)
Definition PressureEqualizer.cpp:140
static bool is_eol(const char c)
Definition PressureEqualizer.cpp:138
static float parse_float(const char *&line, const size_t line_length)
Definition PressureEqualizer.cpp:172
static const std::string EXTRUSION_ROLE_TAG
Definition PressureEqualizer.cpp:16
Slic3r::Polygons diff(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:672

References adjust_volumetric_rate(), 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, sqrt(), 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
701{
702 const GCodeLine &line = m_gcode_lines[line_idx];
703 if (line_idx > 0 && output_buffer_length > 0) {
704 const std::string prev_line_str = std::string(output_buffer.begin() + int(this->output_buffer_prev_length),
705 output_buffer.begin() + int(this->output_buffer_length) + 1);
707 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.
708 else
709 push_to_output(EXTRUDE_END_TAG.data(), EXTRUDE_END_TAG.length(), true);
710 } else
711 push_to_output(EXTRUDE_END_TAG.data(), EXTRUDE_END_TAG.length(), true);
712
713 GCodeG1Formatter feedrate_formatter;
714 feedrate_formatter.emit_f(new_feedrate);
715 feedrate_formatter.emit_string(std::string(EXTRUDE_SET_SPEED_TAG.data(), EXTRUDE_SET_SPEED_TAG.length()));
716 if (line.extrusion_role == GCodeExtrusionRole::ExternalPerimeter)
717 feedrate_formatter.emit_string(std::string(EXTERNAL_PERIMETER_TAG.data(), EXTERNAL_PERIMETER_TAG.length()));
718 push_to_output(feedrate_formatter);
719
720 GCodeG1Formatter extrusion_formatter;
721 for (size_t axis_idx = 0; axis_idx < 3; ++axis_idx)
722 if (line.pos_provided[axis_idx])
723 extrusion_formatter.emit_axis(char('X' + axis_idx), line.pos_end[axis_idx], GCodeFormatter::XYZF_EXPORT_DIGITS);
724 extrusion_formatter.emit_axis('E', m_use_relative_e_distances ? (line.pos_end[3] - line.pos_start[3]) : line.pos_end[3], GCodeFormatter::E_EXPORT_DIGITS);
725
726 if (comment != nullptr)
727 extrusion_formatter.emit_string(std::string(comment));
728
729 push_to_output(extrusion_formatter);
730}
static constexpr const int XYZF_EXPORT_DIGITS
Definition GCodeWriter.hpp:137
static const std::string EXTERNAL_PERIMETER_TAG
Definition PressureEqualizer.cpp:19
bool is_just_line_with_extrude_set_speed_tag(const std::string &line)
Definition PressureEqualizer.cpp:681

References comment, Slic3r::GCodeFormatter::E_EXPORT_DIGITS, Slic3r::GCodeFormatter::emit_axis(), Slic3r::GCodeFormatter::emit_f(), Slic3r::GCodeFormatter::emit_string(), Slic3r::EXTERNAL_PERIMETER_TAG, Slic3r::ExternalPerimeter, Slic3r::EXTRUDE_END_TAG, Slic3r::EXTRUDE_SET_SPEED_TAG, Slic3r::PressureEqualizer::GCodeLine::extrusion_role, Slic3r::is_just_line_with_extrude_set_speed_tag(), m_gcode_lines, 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::XYZF_EXPORT_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
649{
650 // New length of the output buffer content.
651 size_t len_new = output_buffer_length + len + 1;
652 if (add_eol)
653 ++len_new;
654
655 // Resize the output buffer to a power of 2 higher than the required memory.
656 if (output_buffer.size() < len_new) {
657 size_t v = len_new;
658 // Compute the next highest power of 2 of 32-bit v
659 // http://graphics.stanford.edu/~seander/bithacks.html
660 v--;
661 v |= v >> 1;
662 v |= v >> 2;
663 v |= v >> 4;
664 v |= v >> 8;
665 v |= v >> 16;
666 v++;
667 output_buffer.resize(v);
668 }
669
670 // Copy the text to the output.
671 if (len != 0) {
672 memcpy(output_buffer.data() + output_buffer_length, text, len);
675 }
676 if (add_eol)
679}

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
644{
645 return this->push_to_output(text.data(), text.size(), add_eol);
646}

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
639{
640 return this->push_to_output(formatter.string(), false);
641}

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

GCodeExtrusionRole 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_filament_crossections

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

Referenced by PressureEqualizer(), and process_line().

◆ m_gcode_lines

std::vector<GCodeLine> Slic3r::PressureEqualizer::m_gcode_lines

◆ m_layer_results

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

Referenced by process_layer().

◆ 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(GCodeExtrusionRole::Count)]
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: