Reworked pressure equalizer and GCode processing pipeline to make pressure equalizer always returns one whole layer at once.
Now pressure equalizer is returning one layer back (the previous layer). GCode produced by pressure equalizer now has the same number of decimal places as non-processed GCode. Pressure equalizer was disabled for external perimeters and gap-fill.
This commit is contained in:
parent
a497769558
commit
9c07218d82
4 changed files with 253 additions and 252 deletions
|
@ -1529,11 +1529,18 @@ void GCode::process_layers(
|
||||||
{
|
{
|
||||||
// The pipeline is variable: The vase mode filter is optional.
|
// The pipeline is variable: The vase mode filter is optional.
|
||||||
size_t layer_to_print_idx = 0;
|
size_t layer_to_print_idx = 0;
|
||||||
const auto generator = tbb::make_filter<void, GCode::LayerResult>(slic3r_tbb_filtermode::serial_in_order,
|
const auto generator = tbb::make_filter<void, LayerResult>(slic3r_tbb_filtermode::serial_in_order,
|
||||||
[this, &print, &tool_ordering, &print_object_instances_ordering, &layers_to_print, &layer_to_print_idx](tbb::flow_control& fc) -> GCode::LayerResult {
|
[this, &print, &tool_ordering, &print_object_instances_ordering, &layers_to_print, &layer_to_print_idx](tbb::flow_control& fc) -> LayerResult {
|
||||||
if (layer_to_print_idx == layers_to_print.size()) {
|
if (layer_to_print_idx >= layers_to_print.size()) {
|
||||||
fc.stop();
|
if ((!m_pressure_equalizer && layer_to_print_idx == layers_to_print.size()) || (m_pressure_equalizer && layer_to_print_idx == (layers_to_print.size() + 1))) {
|
||||||
return {};
|
fc.stop();
|
||||||
|
return {};
|
||||||
|
} else {
|
||||||
|
// Pressure equalizer need insert empty input. Because it returns one layer back.
|
||||||
|
// Insert NOP (no operation) layer;
|
||||||
|
++layer_to_print_idx;
|
||||||
|
return LayerResult::make_nop_layer_result();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
const std::pair<coordf_t, std::vector<LayerToPrint>>& layer = layers_to_print[layer_to_print_idx++];
|
const std::pair<coordf_t, std::vector<LayerToPrint>>& layer = layers_to_print[layer_to_print_idx++];
|
||||||
const LayerTools& layer_tools = tool_ordering.tools_for_layer(layer.first);
|
const LayerTools& layer_tools = tool_ordering.tools_for_layer(layer.first);
|
||||||
|
@ -1543,17 +1550,23 @@ void GCode::process_layers(
|
||||||
return this->process_layer(print, layer.second, layer_tools, &layer == &layers_to_print.back(), &print_object_instances_ordering, size_t(-1));
|
return this->process_layer(print, layer.second, layer_tools, &layer == &layers_to_print.back(), &print_object_instances_ordering, size_t(-1));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const auto spiral_vase = tbb::make_filter<GCode::LayerResult, GCode::LayerResult>(slic3r_tbb_filtermode::serial_in_order,
|
const auto spiral_vase = tbb::make_filter<LayerResult, LayerResult>(slic3r_tbb_filtermode::serial_in_order,
|
||||||
[&spiral_vase = *this->m_spiral_vase](GCode::LayerResult in) -> GCode::LayerResult {
|
[&spiral_vase = *this->m_spiral_vase](LayerResult in) -> LayerResult {
|
||||||
|
if (in.nop_layer_result)
|
||||||
|
return in;
|
||||||
|
|
||||||
spiral_vase.enable(in.spiral_vase_enable);
|
spiral_vase.enable(in.spiral_vase_enable);
|
||||||
return { spiral_vase.process_layer(std::move(in.gcode)), in.layer_id, in.spiral_vase_enable, in.cooling_buffer_flush, in.pressure_equalizer_buffer_flush };
|
return { spiral_vase.process_layer(std::move(in.gcode)), in.layer_id, in.spiral_vase_enable, in.cooling_buffer_flush};
|
||||||
});
|
});
|
||||||
const auto pressure_equalizer = tbb::make_filter<GCode::LayerResult, GCode::LayerResult>(slic3r_tbb_filtermode::serial_in_order,
|
const auto pressure_equalizer = tbb::make_filter<LayerResult, LayerResult>(slic3r_tbb_filtermode::serial_in_order,
|
||||||
[&pressure_equalizer = *this->m_pressure_equalizer](GCode::LayerResult in) -> GCode::LayerResult {
|
[&pressure_equalizer = *this->m_pressure_equalizer](LayerResult in) -> LayerResult {
|
||||||
return { std::string(pressure_equalizer.process_layer(std::move(in.gcode.c_str()), in.pressure_equalizer_buffer_flush)), in.layer_id, in.spiral_vase_enable, in.cooling_buffer_flush, in.pressure_equalizer_buffer_flush };
|
return pressure_equalizer.process_layer(std::move(in));
|
||||||
});
|
});
|
||||||
const auto cooling = tbb::make_filter<GCode::LayerResult, std::string>(slic3r_tbb_filtermode::serial_in_order,
|
const auto cooling = tbb::make_filter<LayerResult, std::string>(slic3r_tbb_filtermode::serial_in_order,
|
||||||
[&cooling_buffer = *this->m_cooling_buffer](GCode::LayerResult in) -> std::string {
|
[&cooling_buffer = *this->m_cooling_buffer](LayerResult in) -> std::string {
|
||||||
|
if (in.nop_layer_result)
|
||||||
|
return in.gcode;
|
||||||
|
|
||||||
return cooling_buffer.process_layer(std::move(in.gcode), in.layer_id, in.cooling_buffer_flush);
|
return cooling_buffer.process_layer(std::move(in.gcode), in.layer_id, in.cooling_buffer_flush);
|
||||||
});
|
});
|
||||||
const auto find_replace = tbb::make_filter<std::string, std::string>(slic3r_tbb_filtermode::serial_in_order,
|
const auto find_replace = tbb::make_filter<std::string, std::string>(slic3r_tbb_filtermode::serial_in_order,
|
||||||
|
@ -1601,28 +1614,39 @@ void GCode::process_layers(
|
||||||
{
|
{
|
||||||
// The pipeline is variable: The vase mode filter is optional.
|
// The pipeline is variable: The vase mode filter is optional.
|
||||||
size_t layer_to_print_idx = 0;
|
size_t layer_to_print_idx = 0;
|
||||||
const auto generator = tbb::make_filter<void, GCode::LayerResult>(slic3r_tbb_filtermode::serial_in_order,
|
const auto generator = tbb::make_filter<void, LayerResult>(slic3r_tbb_filtermode::serial_in_order,
|
||||||
[this, &print, &tool_ordering, &layers_to_print, &layer_to_print_idx, single_object_idx](tbb::flow_control& fc) -> GCode::LayerResult {
|
[this, &print, &tool_ordering, &layers_to_print, &layer_to_print_idx, single_object_idx](tbb::flow_control& fc) -> LayerResult {
|
||||||
if (layer_to_print_idx == layers_to_print.size()) {
|
if (layer_to_print_idx >= layers_to_print.size()) {
|
||||||
fc.stop();
|
if ((!m_pressure_equalizer && layer_to_print_idx == layers_to_print.size()) || (m_pressure_equalizer && layer_to_print_idx == (layers_to_print.size() + 1))) {
|
||||||
return {};
|
fc.stop();
|
||||||
|
return {};
|
||||||
|
} else {
|
||||||
|
// Pressure equalizer need insert empty input. Because it returns one layer back.
|
||||||
|
// Insert NOP (no operation) layer;
|
||||||
|
++layer_to_print_idx;
|
||||||
|
return LayerResult::make_nop_layer_result();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
LayerToPrint &layer = layers_to_print[layer_to_print_idx ++];
|
LayerToPrint &layer = layers_to_print[layer_to_print_idx ++];
|
||||||
print.throw_if_canceled();
|
print.throw_if_canceled();
|
||||||
return this->process_layer(print, { std::move(layer) }, tool_ordering.tools_for_layer(layer.print_z()), &layer == &layers_to_print.back(), nullptr, single_object_idx);
|
return this->process_layer(print, { std::move(layer) }, tool_ordering.tools_for_layer(layer.print_z()), &layer == &layers_to_print.back(), nullptr, single_object_idx);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const auto spiral_vase = tbb::make_filter<GCode::LayerResult, GCode::LayerResult>(slic3r_tbb_filtermode::serial_in_order,
|
const auto spiral_vase = tbb::make_filter<LayerResult, LayerResult>(slic3r_tbb_filtermode::serial_in_order,
|
||||||
[&spiral_vase = *this->m_spiral_vase](GCode::LayerResult in)->GCode::LayerResult {
|
[&spiral_vase = *this->m_spiral_vase](LayerResult in)->LayerResult {
|
||||||
|
if (in.nop_layer_result)
|
||||||
|
return in;
|
||||||
spiral_vase.enable(in.spiral_vase_enable);
|
spiral_vase.enable(in.spiral_vase_enable);
|
||||||
return { spiral_vase.process_layer(std::move(in.gcode)), in.layer_id, in.spiral_vase_enable, in.cooling_buffer_flush, in.pressure_equalizer_buffer_flush };
|
return { spiral_vase.process_layer(std::move(in.gcode)), in.layer_id, in.spiral_vase_enable, in.cooling_buffer_flush };
|
||||||
});
|
});
|
||||||
const auto pressure_equalizer = tbb::make_filter<GCode::LayerResult, GCode::LayerResult>(slic3r_tbb_filtermode::serial_in_order,
|
const auto pressure_equalizer = tbb::make_filter<LayerResult, LayerResult>(slic3r_tbb_filtermode::serial_in_order,
|
||||||
[&pressure_equalizer = *this->m_pressure_equalizer](GCode::LayerResult in) -> GCode::LayerResult {
|
[&pressure_equalizer = *this->m_pressure_equalizer](LayerResult in) -> LayerResult {
|
||||||
return { std::string(pressure_equalizer.process_layer(std::move(in.gcode.c_str()), in.pressure_equalizer_buffer_flush)), in.layer_id, in.spiral_vase_enable, in.cooling_buffer_flush, in.pressure_equalizer_buffer_flush };
|
return pressure_equalizer.process_layer(std::move(in));
|
||||||
});
|
});
|
||||||
const auto cooling = tbb::make_filter<GCode::LayerResult, std::string>(slic3r_tbb_filtermode::serial_in_order,
|
const auto cooling = tbb::make_filter<LayerResult, std::string>(slic3r_tbb_filtermode::serial_in_order,
|
||||||
[&cooling_buffer = *this->m_cooling_buffer](GCode::LayerResult in)->std::string {
|
[&cooling_buffer = *this->m_cooling_buffer](LayerResult in)->std::string {
|
||||||
|
if (in.nop_layer_result)
|
||||||
|
return in.gcode;
|
||||||
return cooling_buffer.process_layer(std::move(in.gcode), in.layer_id, in.cooling_buffer_flush);
|
return cooling_buffer.process_layer(std::move(in.gcode), in.layer_id, in.cooling_buffer_flush);
|
||||||
});
|
});
|
||||||
const auto find_replace = tbb::make_filter<std::string, std::string>(slic3r_tbb_filtermode::serial_in_order,
|
const auto find_replace = tbb::make_filter<std::string, std::string>(slic3r_tbb_filtermode::serial_in_order,
|
||||||
|
@ -2079,7 +2103,7 @@ namespace Skirt {
|
||||||
// In non-sequential mode, process_layer is called per each print_z height with all object and support layers accumulated.
|
// In non-sequential mode, process_layer is called per each print_z height with all object and support layers accumulated.
|
||||||
// For multi-material prints, this routine minimizes extruder switches by gathering extruder specific extrusion paths
|
// For multi-material prints, this routine minimizes extruder switches by gathering extruder specific extrusion paths
|
||||||
// and performing the extruder specific extrusions together.
|
// and performing the extruder specific extrusions together.
|
||||||
GCode::LayerResult GCode::process_layer(
|
LayerResult GCode::process_layer(
|
||||||
const Print &print,
|
const Print &print,
|
||||||
// Set of object & print layers of the same PrintObject and with the same print_z.
|
// Set of object & print layers of the same PrintObject and with the same print_z.
|
||||||
const std::vector<LayerToPrint> &layers,
|
const std::vector<LayerToPrint> &layers,
|
||||||
|
@ -2110,7 +2134,7 @@ GCode::LayerResult GCode::process_layer(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const Layer &layer = (object_layer != nullptr) ? *object_layer : *support_layer;
|
const Layer &layer = (object_layer != nullptr) ? *object_layer : *support_layer;
|
||||||
GCode::LayerResult result { {}, layer.id(), false, last_layer, last_layer};
|
LayerResult result { {}, layer.id(), false, last_layer, false};
|
||||||
if (layer_tools.extruders.empty())
|
if (layer_tools.extruders.empty())
|
||||||
// Nothing to extrude.
|
// Nothing to extrude.
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -114,6 +114,20 @@ public:
|
||||||
static const std::vector<std::string>& get() { return Colors; }
|
static const std::vector<std::string>& get() { return Colors; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct LayerResult {
|
||||||
|
std::string gcode;
|
||||||
|
size_t layer_id;
|
||||||
|
// Is spiral vase post processing enabled for this layer?
|
||||||
|
bool spiral_vase_enable { false };
|
||||||
|
// Should the cooling buffer content be flushed at the end of this layer?
|
||||||
|
bool cooling_buffer_flush { false };
|
||||||
|
// Is indicating if this LayerResult should be processed, or it is just inserted artificial LayerResult.
|
||||||
|
// It is used for the pressure equalizer because it needs to buffer one layer back.
|
||||||
|
bool nop_layer_result { false };
|
||||||
|
|
||||||
|
static LayerResult make_nop_layer_result() { return {"", std::numeric_limits<coord_t>::max(), false, false, true}; }
|
||||||
|
};
|
||||||
|
|
||||||
class GCode {
|
class GCode {
|
||||||
public:
|
public:
|
||||||
GCode() :
|
GCode() :
|
||||||
|
@ -226,16 +240,6 @@ private:
|
||||||
static std::vector<LayerToPrint> collect_layers_to_print(const PrintObject &object);
|
static std::vector<LayerToPrint> collect_layers_to_print(const PrintObject &object);
|
||||||
static std::vector<std::pair<coordf_t, std::vector<LayerToPrint>>> collect_layers_to_print(const Print &print);
|
static std::vector<std::pair<coordf_t, std::vector<LayerToPrint>>> collect_layers_to_print(const Print &print);
|
||||||
|
|
||||||
struct LayerResult {
|
|
||||||
std::string gcode;
|
|
||||||
size_t layer_id;
|
|
||||||
// Is spiral vase post processing enabled for this layer?
|
|
||||||
bool spiral_vase_enable { false };
|
|
||||||
// Should the cooling buffer content be flushed at the end of this layer?
|
|
||||||
bool cooling_buffer_flush { false };
|
|
||||||
// Should the PressureEqualizer buffer content be flushed at the end of this layer?
|
|
||||||
bool pressure_equalizer_buffer_flush { false };
|
|
||||||
};
|
|
||||||
LayerResult process_layer(
|
LayerResult process_layer(
|
||||||
const Print &print,
|
const Print &print,
|
||||||
// Set of object & print layers of the same PrintObject and with the same print_z.
|
// Set of object & print layers of the same PrintObject and with the same print_z.
|
||||||
|
@ -446,6 +450,7 @@ private:
|
||||||
|
|
||||||
friend class Wipe;
|
friend class Wipe;
|
||||||
friend class WipeTowerIntegration;
|
friend class WipeTowerIntegration;
|
||||||
|
friend class PressureEqualizer;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<const PrintInstance*> sort_object_instances_by_model_order(const Print& print);
|
std::vector<const PrintInstance*> sort_object_instances_by_model_order(const Print& print);
|
||||||
|
|
|
@ -5,36 +5,24 @@
|
||||||
#include "../libslic3r.h"
|
#include "../libslic3r.h"
|
||||||
#include "../PrintConfig.hpp"
|
#include "../PrintConfig.hpp"
|
||||||
#include "../LocalesUtils.hpp"
|
#include "../LocalesUtils.hpp"
|
||||||
|
#include "../GCode.hpp"
|
||||||
|
|
||||||
#include "PressureEqualizer.hpp"
|
#include "PressureEqualizer.hpp"
|
||||||
#include "fast_float/fast_float.h"
|
#include "fast_float/fast_float.h"
|
||||||
|
#include "GCodeWriter.hpp"
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
static constexpr const std::array<char, 18> EXTRUSION_ROLE_TAG = {";_EXTRUSION_ROLE:"};
|
static const std::string EXTRUSION_ROLE_TAG = ";_EXTRUSION_ROLE:";
|
||||||
static constexpr const size_t EXTRUSION_ROLE_TAG_LENGTH = EXTRUSION_ROLE_TAG.size() - 1;
|
static const std::string EXTRUDE_END_TAG = ";_EXTRUDE_END";
|
||||||
static constexpr const std::array<char, 14> EXTRUDE_END_TAG = {";_EXTRUDE_END"};
|
static const std::string EXTRUDE_SET_SPEED_TAG = ";_EXTRUDE_SET_SPEED";
|
||||||
static constexpr const size_t EXTRUDE_END_TAG_LENGTH = EXTRUDE_END_TAG.size() - 1;
|
static const std::string EXTERNAL_PERIMETER_TAG = ";_EXTERNAL_PERIMETER";
|
||||||
static constexpr const std::array<char, 20> EXTRUDE_SET_SPEED_TAG = {";_EXTRUDE_SET_SPEED"};
|
|
||||||
static constexpr const size_t EXTRUDE_SET_SPEED_TAG_LENGTH = EXTRUDE_SET_SPEED_TAG.size() - 1;
|
|
||||||
static constexpr const std::array<char, 21> EXTERNAL_PERIMETER_TAG = {";_EXTERNAL_PERIMETER"};
|
|
||||||
static constexpr const size_t EXTERNAL_PERIMETER_TAG_LENGTH = EXTERNAL_PERIMETER_TAG.size() - 1;
|
|
||||||
|
|
||||||
PressureEqualizer::PressureEqualizer(const Slic3r::GCodeConfig &config) : m_config(config)
|
PressureEqualizer::PressureEqualizer(const Slic3r::GCodeConfig &config) : m_use_relative_e_distances(config.use_relative_e_distances.value)
|
||||||
{
|
{
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PressureEqualizer::reset()
|
|
||||||
{
|
|
||||||
circular_buffer_pos = 0;
|
|
||||||
circular_buffer_size = 100;
|
|
||||||
circular_buffer_items = 0;
|
|
||||||
circular_buffer.assign(circular_buffer_size, GCodeLine());
|
|
||||||
|
|
||||||
// Preallocate some data, so that output_buffer.data() will return an empty string.
|
// Preallocate some data, so that output_buffer.data() will return an empty string.
|
||||||
output_buffer.assign(32, 0);
|
output_buffer.assign(32, 0);
|
||||||
output_buffer_length = 0;
|
output_buffer_length = 0;
|
||||||
|
|
||||||
m_current_extruder = 0;
|
m_current_extruder = 0;
|
||||||
// Zero the position of the XYZE axes + the current feed
|
// Zero the position of the XYZE axes + the current feed
|
||||||
|
@ -45,7 +33,7 @@ void PressureEqualizer::reset()
|
||||||
|
|
||||||
// Calculate filamet crossections for the multiple extruders.
|
// Calculate filamet crossections for the multiple extruders.
|
||||||
m_filament_crossections.clear();
|
m_filament_crossections.clear();
|
||||||
for (double r : m_config.filament_diameter.values) {
|
for (double r : config.filament_diameter.values) {
|
||||||
double a = 0.25f * M_PI * r * r;
|
double a = 0.25f * M_PI * r * r;
|
||||||
m_filament_crossections.push_back(float(a));
|
m_filament_crossections.push_back(float(a));
|
||||||
}
|
}
|
||||||
|
@ -54,86 +42,82 @@ void PressureEqualizer::reset()
|
||||||
// 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
|
// 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
|
||||||
// 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
|
// 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
|
||||||
// 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
|
// 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
|
||||||
m_max_volumetric_extrusion_rate_slope_positive = float(m_config.max_volumetric_extrusion_rate_slope_positive.value) * 60.f * 60.f;
|
m_max_volumetric_extrusion_rate_slope_positive = float(config.max_volumetric_extrusion_rate_slope_positive.value) * 60.f * 60.f;
|
||||||
m_max_volumetric_extrusion_rate_slope_negative = float(m_config.max_volumetric_extrusion_rate_slope_negative.value) * 60.f * 60.f;
|
m_max_volumetric_extrusion_rate_slope_negative = float(config.max_volumetric_extrusion_rate_slope_negative.value) * 60.f * 60.f;
|
||||||
|
|
||||||
for (size_t i = 0; i < numExtrusionRoles; ++ i) {
|
for (ExtrusionRateSlope &extrusion_rate_slope : m_max_volumetric_extrusion_rate_slopes) {
|
||||||
m_max_volumetric_extrusion_rate_slopes[i].negative = m_max_volumetric_extrusion_rate_slope_negative;
|
extrusion_rate_slope.negative = m_max_volumetric_extrusion_rate_slope_negative;
|
||||||
m_max_volumetric_extrusion_rate_slopes[i].positive = m_max_volumetric_extrusion_rate_slope_positive;
|
extrusion_rate_slope.positive = m_max_volumetric_extrusion_rate_slope_positive;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't regulate the pressure in infill.
|
// Don't regulate the pressure in infill and gap fill.
|
||||||
m_max_volumetric_extrusion_rate_slopes[erBridgeInfill].negative = 0;
|
// TODO: Do we want to regulate pressure in erWipeTower, erCustom and erMixed?
|
||||||
m_max_volumetric_extrusion_rate_slopes[erBridgeInfill].positive = 0;
|
for (const ExtrusionRole er : {erBridgeInfill, erGapFill}) {
|
||||||
// Don't regulate the pressure in gap fill.
|
m_max_volumetric_extrusion_rate_slopes[er].negative = 0;
|
||||||
m_max_volumetric_extrusion_rate_slopes[erGapFill].negative = 0;
|
m_max_volumetric_extrusion_rate_slopes[er].positive = 0;
|
||||||
m_max_volumetric_extrusion_rate_slopes[erGapFill].positive = 0;
|
}
|
||||||
|
|
||||||
#ifdef PRESSURE_EQUALIZER_STATISTIC
|
#ifdef PRESSURE_EQUALIZER_STATISTIC
|
||||||
m_stat.reset();
|
m_stat.reset();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef PRESSURE_EQUALIZER_DEBUG
|
||||||
line_idx = 0;
|
line_idx = 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* PressureEqualizer::process_layer(const char *szGCode, bool flush)
|
void PressureEqualizer::process_layer(const std::string &gcode)
|
||||||
{
|
{
|
||||||
// Reset length of the output_buffer.
|
if (!gcode.empty()) {
|
||||||
output_buffer_length = 0;
|
const char *gcode_begin = gcode.c_str();
|
||||||
|
while (*gcode_begin != 0) {
|
||||||
if (szGCode != nullptr) {
|
|
||||||
const char *p = szGCode;
|
|
||||||
while (*p != 0) {
|
|
||||||
// Find end of the line.
|
// Find end of the line.
|
||||||
const char *endl = p;
|
const char *gcode_end = gcode_begin;
|
||||||
// Slic3r always generates end of lines in a Unix style.
|
// Slic3r always generates end of lines in a Unix style.
|
||||||
for (; *endl != 0 && *endl != '\n'; ++ endl) ;
|
for (; *gcode_end != 0 && *gcode_end != '\n'; ++gcode_end);
|
||||||
if (circular_buffer_items == circular_buffer_size)
|
|
||||||
// Buffer is full. Push out the oldest line.
|
m_gcode_lines.emplace_back();
|
||||||
output_gcode_line(circular_buffer[circular_buffer_pos]);
|
if (!this->process_line(gcode_begin, gcode_end, m_gcode_lines.back())) {
|
||||||
else
|
// The line has to be forgotten. It contains comment marks, which shall be filtered out of the target g-code.
|
||||||
++ circular_buffer_items;
|
m_gcode_lines.pop_back();
|
||||||
// Process a G-code line, store it into the provided GCodeLine object.
|
|
||||||
size_t idx_tail = circular_buffer_pos;
|
|
||||||
circular_buffer_pos = circular_buffer_idx_next(circular_buffer_pos);
|
|
||||||
if (! process_line(p, endl, circular_buffer[idx_tail])) {
|
|
||||||
// The line has to be forgotten. It contains comment marks, which shall be
|
|
||||||
// filtered out of the target g-code.
|
|
||||||
circular_buffer_pos = idx_tail;
|
|
||||||
-- circular_buffer_items;
|
|
||||||
}
|
}
|
||||||
p = endl;
|
gcode_begin = gcode_end;
|
||||||
if (*p == '\n')
|
if (*gcode_begin == '\n')
|
||||||
++ p;
|
++gcode_begin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (flush) {
|
LayerResult PressureEqualizer::process_layer(LayerResult &&input)
|
||||||
// Flush the remaining valid lines of the circular buffer.
|
{
|
||||||
for (size_t idx = circular_buffer_idx_head(); circular_buffer_items > 0; -- circular_buffer_items) {
|
const bool is_first_layer = m_layer_results.empty();
|
||||||
output_gcode_line(circular_buffer[idx]);
|
const size_t next_layer_first_idx = m_gcode_lines.size();
|
||||||
if (++ idx == circular_buffer_size)
|
|
||||||
idx = 0;
|
|
||||||
}
|
|
||||||
// Reset the index pointer.
|
|
||||||
assert(circular_buffer_items == 0);
|
|
||||||
circular_buffer_pos = 0;
|
|
||||||
|
|
||||||
#ifdef PRESSURE_EQUALIZER_STATISTIC
|
if (!input.nop_layer_result) {
|
||||||
printf("Statistics: \n");
|
this->process_layer(input.gcode);
|
||||||
printf("Minimum volumetric extrusion rate: %f\n", m_stat.volumetric_extrusion_rate_min);
|
input.gcode.clear(); // GCode is already processed, so it isn't needed to store it.
|
||||||
printf("Maximum volumetric extrusion rate: %f\n", m_stat.volumetric_extrusion_rate_max);
|
m_layer_results.emplace(new LayerResult(input));
|
||||||
if (m_stat.extrusion_length > 0)
|
}
|
||||||
m_stat.volumetric_extrusion_rate_avg /= m_stat.extrusion_length;
|
|
||||||
printf("Average volumetric extrusion rate: %f\n", m_stat.volumetric_extrusion_rate_avg);
|
if (is_first_layer) // Buffer previous input result and output NOP.
|
||||||
m_stat.reset();
|
return LayerResult::make_nop_layer_result();
|
||||||
#endif
|
|
||||||
}
|
// Export previous layer.
|
||||||
|
LayerResult *prev_layer_result = m_layer_results.front();
|
||||||
|
m_layer_results.pop();
|
||||||
|
|
||||||
|
output_buffer_length = 0;
|
||||||
|
for (size_t line_idx = 0; line_idx < next_layer_first_idx; ++line_idx)
|
||||||
|
output_gcode_line(m_gcode_lines[line_idx]);
|
||||||
|
m_gcode_lines.erase(m_gcode_lines.begin(), m_gcode_lines.begin() + int(next_layer_first_idx));
|
||||||
|
|
||||||
if (output_buffer_length > 0)
|
if (output_buffer_length > 0)
|
||||||
return output_buffer.data();
|
prev_layer_result->gcode = std::string(output_buffer.data());
|
||||||
|
|
||||||
return "\0";
|
assert(!input.nop_layer_result || m_layer_results.empty());
|
||||||
|
LayerResult out = *prev_layer_result;
|
||||||
|
delete prev_layer_result;
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is a white space?
|
// Is a white space?
|
||||||
|
@ -186,12 +170,13 @@ static inline float parse_float(const char *&line, const size_t line_length)
|
||||||
bool PressureEqualizer::process_line(const char *line, const char *line_end, GCodeLine &buf)
|
bool PressureEqualizer::process_line(const char *line, const char *line_end, GCodeLine &buf)
|
||||||
{
|
{
|
||||||
const size_t len = line_end - line;
|
const size_t len = line_end - line;
|
||||||
|
if (strncmp(line, EXTRUSION_ROLE_TAG.data(), EXTRUSION_ROLE_TAG.length()) == 0) {
|
||||||
if (strncmp(line, EXTRUSION_ROLE_TAG.data(), EXTRUSION_ROLE_TAG_LENGTH) == 0) {
|
line += EXTRUSION_ROLE_TAG.length();
|
||||||
line += EXTRUSION_ROLE_TAG_LENGTH;
|
|
||||||
int role = atoi(line);
|
int role = atoi(line);
|
||||||
m_current_extrusion_role = ExtrusionRole(role);
|
m_current_extrusion_role = ExtrusionRole(role);
|
||||||
++ line_idx;
|
#ifdef PRESSURE_EQUALIZER_DEBUG
|
||||||
|
++line_idx;
|
||||||
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,7 +236,7 @@ bool PressureEqualizer::process_line(const char *line, const char *line_end, GCo
|
||||||
throw Slic3r::RuntimeError(std::string("GCode::PressureEqualizer: Invalid axis for G0/G1: ") + axis);
|
throw Slic3r::RuntimeError(std::string("GCode::PressureEqualizer: Invalid axis for G0/G1: ") + axis);
|
||||||
buf.pos_provided[i] = true;
|
buf.pos_provided[i] = true;
|
||||||
new_pos[i] = parse_float(line, line_end - line);
|
new_pos[i] = parse_float(line, line_end - line);
|
||||||
if (i == 3 && m_config.use_relative_e_distances.value)
|
if (i == 3 && m_use_relative_e_distances)
|
||||||
new_pos[i] += m_current_pos[i];
|
new_pos[i] += m_current_pos[i];
|
||||||
changed[i] = new_pos[i] != m_current_pos[i];
|
changed[i] = new_pos[i] != m_current_pos[i];
|
||||||
eatws(line);
|
eatws(line);
|
||||||
|
@ -358,7 +343,7 @@ bool PressureEqualizer::process_line(const char *line, const char *line_end, GCo
|
||||||
{
|
{
|
||||||
// Activate an extruder head.
|
// Activate an extruder head.
|
||||||
int new_extruder = parse_int(line);
|
int new_extruder = parse_int(line);
|
||||||
if (new_extruder != m_current_extruder) {
|
if (new_extruder != int(m_current_extruder)) {
|
||||||
m_current_extruder = new_extruder;
|
m_current_extruder = new_extruder;
|
||||||
m_retracted = true;
|
m_retracted = true;
|
||||||
buf.type = GCODELINETYPE_TOOL_CHANGE;
|
buf.type = GCODELINETYPE_TOOL_CHANGE;
|
||||||
|
@ -373,8 +358,10 @@ bool PressureEqualizer::process_line(const char *line, const char *line_end, GCo
|
||||||
memcpy(buf.pos_end, m_current_pos, sizeof(float)*5);
|
memcpy(buf.pos_end, m_current_pos, sizeof(float)*5);
|
||||||
|
|
||||||
adjust_volumetric_rate();
|
adjust_volumetric_rate();
|
||||||
++ line_idx;
|
#ifdef PRESSURE_EQUALIZER_DEBUG
|
||||||
return true;
|
++line_idx;
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PressureEqualizer::output_gcode_line(GCodeLine &line)
|
void PressureEqualizer::output_gcode_line(GCodeLine &line)
|
||||||
|
@ -486,55 +473,56 @@ void PressureEqualizer::output_gcode_line(GCodeLine &line)
|
||||||
|
|
||||||
void PressureEqualizer::adjust_volumetric_rate()
|
void PressureEqualizer::adjust_volumetric_rate()
|
||||||
{
|
{
|
||||||
if (circular_buffer_items < 2)
|
if (m_gcode_lines.size() < 2)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Go back from the current circular_buffer_pos and lower the feedtrate to decrease the slope of the extrusion rate changes.
|
// Go back from the current circular_buffer_pos and lower the feedtrate to decrease the slope of the extrusion rate changes.
|
||||||
const size_t idx_head = circular_buffer_idx_head();
|
// size_t fist_line_idx = size_t(std::max<int>(0, int(m_gcode_lines.size()) - 100));
|
||||||
const size_t idx_tail = circular_buffer_idx_prev(circular_buffer_idx_tail());
|
size_t fist_line_idx = 0;
|
||||||
size_t idx = idx_tail;
|
const size_t last_line_idx = m_gcode_lines.size() - 1;
|
||||||
if (idx == idx_head || ! circular_buffer[idx].extruding())
|
|
||||||
|
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.
|
// Nothing to do, the last move is not extruding.
|
||||||
return;
|
return;
|
||||||
|
|
||||||
float feedrate_per_extrusion_role[numExtrusionRoles];
|
std::array<float, erCount> feedrate_per_extrusion_role{};
|
||||||
for (size_t i = 0; i < numExtrusionRoles; ++ i)
|
feedrate_per_extrusion_role.fill(std::numeric_limits<float>::max());
|
||||||
feedrate_per_extrusion_role[i] = FLT_MAX;
|
feedrate_per_extrusion_role[m_gcode_lines[line_idx].extrusion_role] = m_gcode_lines[line_idx].volumetric_extrusion_rate_start;
|
||||||
feedrate_per_extrusion_role[circular_buffer[idx].extrusion_role] = circular_buffer[idx].volumetric_extrusion_rate_start;
|
|
||||||
|
|
||||||
bool modified = true;
|
while (line_idx != fist_line_idx) {
|
||||||
while (modified && idx != idx_head) {
|
size_t idx_prev = line_idx - 1;
|
||||||
size_t idx_prev = circular_buffer_idx_prev(idx);
|
for (; !m_gcode_lines[idx_prev].extruding() && idx_prev != fist_line_idx; --idx_prev);
|
||||||
for (; !circular_buffer[idx_prev].extruding() && idx_prev != idx_head; idx_prev = circular_buffer_idx_prev(idx_prev));
|
if (!m_gcode_lines[idx_prev].extruding())
|
||||||
if (!circular_buffer[idx_prev].extruding())
|
|
||||||
break;
|
break;
|
||||||
// Volumetric extrusion rate at the start of the succeding segment.
|
// Volumetric extrusion rate at the start of the succeding segment.
|
||||||
float rate_succ = circular_buffer[idx].volumetric_extrusion_rate_start;
|
float rate_succ = m_gcode_lines[line_idx].volumetric_extrusion_rate_start;
|
||||||
// What is the gradient of the extrusion rate between idx_prev and idx?
|
// What is the gradient of the extrusion rate between idx_prev and idx?
|
||||||
idx = idx_prev;
|
line_idx = idx_prev;
|
||||||
GCodeLine &line = circular_buffer[idx];
|
GCodeLine &line = m_gcode_lines[line_idx];
|
||||||
for (size_t iRole = 1; iRole < numExtrusionRoles; ++ iRole) {
|
|
||||||
float rate_slope = m_max_volumetric_extrusion_rate_slopes[iRole].negative;
|
for (size_t iRole = 1; iRole < erCount; ++ iRole) {
|
||||||
if (rate_slope == 0)
|
const float &rate_slope = m_max_volumetric_extrusion_rate_slopes[iRole].negative;
|
||||||
// The negative rate is unlimited.
|
if (rate_slope == 0 || feedrate_per_extrusion_role[iRole] == std::numeric_limits<float>::max())
|
||||||
continue;
|
continue; // The negative rate is unlimited or the rate for ExtrusionRole iRole is unlimited.
|
||||||
|
|
||||||
float rate_end = feedrate_per_extrusion_role[iRole];
|
float rate_end = feedrate_per_extrusion_role[iRole];
|
||||||
if (iRole == line.extrusion_role && rate_succ < rate_end)
|
if (iRole == line.extrusion_role && rate_succ < rate_end)
|
||||||
// Limit by the succeeding volumetric flow rate.
|
// Limit by the succeeding volumetric flow rate.
|
||||||
rate_end = rate_succ;
|
rate_end = rate_succ;
|
||||||
if (line.volumetric_extrusion_rate_end > rate_end) {
|
|
||||||
|
if (line.extrusion_role == erExternalPerimeter || line.extrusion_role == erGapFill || line.extrusion_role == erBridgeInfill) {
|
||||||
|
rate_end = line.volumetric_extrusion_rate_end;
|
||||||
|
} else if (line.volumetric_extrusion_rate_end > rate_end) {
|
||||||
line.volumetric_extrusion_rate_end = rate_end;
|
line.volumetric_extrusion_rate_end = rate_end;
|
||||||
line.max_volumetric_extrusion_rate_slope_negative = rate_slope;
|
line.max_volumetric_extrusion_rate_slope_negative = rate_slope;
|
||||||
line.modified = true;
|
line.modified = true;
|
||||||
} else if (iRole == line.extrusion_role) {
|
} else if (iRole == line.extrusion_role) {
|
||||||
rate_end = line.volumetric_extrusion_rate_end;
|
rate_end = line.volumetric_extrusion_rate_end;
|
||||||
} else if (rate_end == FLT_MAX) {
|
|
||||||
// The rate for ExtrusionRole iRole is unlimited.
|
|
||||||
continue;
|
|
||||||
} else {
|
} else {
|
||||||
// Use the original, 'floating' extrusion rate as a starting point for the limiter.
|
// Use the original, 'floating' extrusion rate as a starting point for the limiter.
|
||||||
}
|
}
|
||||||
// modified = false;
|
|
||||||
float rate_start = rate_end + rate_slope * line.time_corrected();
|
float rate_start = rate_end + rate_slope * line.time_corrected();
|
||||||
if (rate_start < line.volumetric_extrusion_rate_start) {
|
if (rate_start < line.volumetric_extrusion_rate_start) {
|
||||||
// Limit the volumetric extrusion rate at the start of this segment due to a segment
|
// Limit the volumetric extrusion rate at the start of this segment due to a segment
|
||||||
|
@ -542,34 +530,35 @@ void PressureEqualizer::adjust_volumetric_rate()
|
||||||
line.volumetric_extrusion_rate_start = rate_start;
|
line.volumetric_extrusion_rate_start = rate_start;
|
||||||
line.max_volumetric_extrusion_rate_slope_negative = rate_slope;
|
line.max_volumetric_extrusion_rate_slope_negative = rate_slope;
|
||||||
line.modified = true;
|
line.modified = true;
|
||||||
// modified = true;
|
|
||||||
}
|
}
|
||||||
feedrate_per_extrusion_role[iRole] = (iRole == line.extrusion_role) ? line.volumetric_extrusion_rate_start : rate_start;
|
// feedrate_per_extrusion_role[iRole] = (iRole == line.extrusion_role) ? line.volumetric_extrusion_rate_start : rate_start;
|
||||||
|
feedrate_per_extrusion_role[iRole] = line.volumetric_extrusion_rate_start;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Go forward and adjust the feedrate to decrease the slope of the extrusion rate changes.
|
feedrate_per_extrusion_role.fill(std::numeric_limits<float>::max());
|
||||||
for (size_t i = 0; i < numExtrusionRoles; ++i)
|
feedrate_per_extrusion_role[m_gcode_lines[line_idx].extrusion_role] = m_gcode_lines[line_idx].volumetric_extrusion_rate_end;
|
||||||
feedrate_per_extrusion_role[i] = FLT_MAX;
|
|
||||||
feedrate_per_extrusion_role[circular_buffer[idx].extrusion_role] = circular_buffer[idx].volumetric_extrusion_rate_end;
|
|
||||||
|
|
||||||
assert(circular_buffer[idx].extruding());
|
assert(m_gcode_lines[line_idx].extruding());
|
||||||
while (idx != idx_tail) {
|
while (line_idx != last_line_idx) {
|
||||||
size_t idx_next = circular_buffer_idx_next(idx);
|
size_t idx_next = line_idx + 1;
|
||||||
for (; !circular_buffer[idx_next].extruding() && idx_next != idx_tail; idx_next = circular_buffer_idx_next(idx_next));
|
for (; !m_gcode_lines[idx_next].extruding() && idx_next != last_line_idx; ++idx_next);
|
||||||
if (!circular_buffer[idx_next].extruding())
|
if (!m_gcode_lines[idx_next].extruding())
|
||||||
break;
|
break;
|
||||||
float rate_prec = circular_buffer[idx].volumetric_extrusion_rate_end;
|
float rate_prec = m_gcode_lines[line_idx].volumetric_extrusion_rate_end;
|
||||||
// What is the gradient of the extrusion rate between idx_prev and idx?
|
// What is the gradient of the extrusion rate between idx_prev and idx?
|
||||||
idx = idx_next;
|
line_idx = idx_next;
|
||||||
GCodeLine &line = circular_buffer[idx];
|
GCodeLine &line = m_gcode_lines[line_idx];
|
||||||
for (size_t iRole = 1; iRole < numExtrusionRoles; ++ iRole) {
|
|
||||||
float rate_slope = m_max_volumetric_extrusion_rate_slopes[iRole].positive;
|
for (size_t iRole = 1; iRole < erCount; ++ iRole) {
|
||||||
if (rate_slope == 0)
|
const float &rate_slope = m_max_volumetric_extrusion_rate_slopes[iRole].positive;
|
||||||
// The positive rate is unlimited.
|
if (rate_slope == 0 || feedrate_per_extrusion_role[iRole] == std::numeric_limits<float>::max())
|
||||||
continue;
|
continue; // The positive rate is unlimited or the rate for ExtrusionRole iRole is unlimited.
|
||||||
|
|
||||||
float rate_start = feedrate_per_extrusion_role[iRole];
|
float rate_start = feedrate_per_extrusion_role[iRole];
|
||||||
if (iRole == line.extrusion_role && rate_prec < rate_start)
|
if (line.extrusion_role == erExternalPerimeter || line.extrusion_role == erGapFill || line.extrusion_role == erBridgeInfill) {
|
||||||
|
rate_start = line.volumetric_extrusion_rate_start;
|
||||||
|
} else if (iRole == line.extrusion_role && rate_prec < rate_start)
|
||||||
rate_start = rate_prec;
|
rate_start = rate_prec;
|
||||||
if (line.volumetric_extrusion_rate_start > rate_start) {
|
if (line.volumetric_extrusion_rate_start > rate_start) {
|
||||||
line.volumetric_extrusion_rate_start = rate_start;
|
line.volumetric_extrusion_rate_start = rate_start;
|
||||||
|
@ -577,13 +566,10 @@ void PressureEqualizer::adjust_volumetric_rate()
|
||||||
line.modified = true;
|
line.modified = true;
|
||||||
} else if (iRole == line.extrusion_role) {
|
} else if (iRole == line.extrusion_role) {
|
||||||
rate_start = line.volumetric_extrusion_rate_start;
|
rate_start = line.volumetric_extrusion_rate_start;
|
||||||
} else if (rate_start == FLT_MAX) {
|
|
||||||
// The rate for ExtrusionRole iRole is unlimited.
|
|
||||||
continue;
|
|
||||||
} else {
|
} else {
|
||||||
// Use the original, 'floating' extrusion rate as a starting point for the limiter.
|
// Use the original, 'floating' extrusion rate as a starting point for the limiter.
|
||||||
}
|
}
|
||||||
float rate_end = (rate_slope == 0) ? FLT_MAX : rate_start + rate_slope * line.time_corrected();
|
float rate_end = rate_start + rate_slope * line.time_corrected();
|
||||||
if (rate_end < line.volumetric_extrusion_rate_end) {
|
if (rate_end < line.volumetric_extrusion_rate_end) {
|
||||||
// Limit the volumetric extrusion rate at the start of this segment due to a segment
|
// Limit the volumetric extrusion rate at the start of this segment due to a segment
|
||||||
// of ExtrusionType iRole, which was extruded before.
|
// of ExtrusionType iRole, which was extruded before.
|
||||||
|
@ -591,24 +577,28 @@ void PressureEqualizer::adjust_volumetric_rate()
|
||||||
line.max_volumetric_extrusion_rate_slope_positive = rate_slope;
|
line.max_volumetric_extrusion_rate_slope_positive = rate_slope;
|
||||||
line.modified = true;
|
line.modified = true;
|
||||||
}
|
}
|
||||||
feedrate_per_extrusion_role[iRole] = (iRole == line.extrusion_role) ? line.volumetric_extrusion_rate_end : rate_end;
|
// feedrate_per_extrusion_role[iRole] = (iRole == line.extrusion_role) ? line.volumetric_extrusion_rate_end : rate_end;
|
||||||
|
feedrate_per_extrusion_role[iRole] = line.volumetric_extrusion_rate_end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PressureEqualizer::push_axis_to_output(const char axis, const float value, bool add_eol)
|
inline void PressureEqualizer::push_to_output(GCodeG1Formatter &formatter)
|
||||||
{
|
{
|
||||||
char buf[2048];
|
return this->push_to_output(formatter.string(), false);
|
||||||
int len = sprintf(buf, (axis == 'E') ? " %c%.3f" : " %c%.5f", axis, value);
|
|
||||||
push_to_output(buf, len, add_eol);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PressureEqualizer::push_to_output(const char *text, const size_t len, bool add_eol)
|
inline void PressureEqualizer::push_to_output(const std::string &text, bool add_eol)
|
||||||
|
{
|
||||||
|
return this->push_to_output(text.data(), text.size(), add_eol);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void PressureEqualizer::push_to_output(const char *text, const size_t len, bool add_eol)
|
||||||
{
|
{
|
||||||
// New length of the output buffer content.
|
// New length of the output buffer content.
|
||||||
size_t len_new = output_buffer_length + len + 1;
|
size_t len_new = output_buffer_length + len + 1;
|
||||||
if (add_eol)
|
if (add_eol)
|
||||||
++ len_new;
|
++len_new;
|
||||||
|
|
||||||
// Resize the output buffer to a power of 2 higher than the required memory.
|
// Resize the output buffer to a power of 2 higher than the required memory.
|
||||||
if (output_buffer.size() < len_new) {
|
if (output_buffer.size() < len_new) {
|
||||||
|
@ -631,29 +621,31 @@ void PressureEqualizer::push_to_output(const char *text, const size_t len, bool
|
||||||
output_buffer_length += len;
|
output_buffer_length += len;
|
||||||
}
|
}
|
||||||
if (add_eol)
|
if (add_eol)
|
||||||
output_buffer[output_buffer_length ++] = '\n';
|
output_buffer[output_buffer_length++] = '\n';
|
||||||
output_buffer[output_buffer_length] = 0;
|
output_buffer[output_buffer_length] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PressureEqualizer::push_line_to_output(const GCodeLine &line, const float new_feedrate, const char *comment)
|
void PressureEqualizer::push_line_to_output(const GCodeLine &line, const float new_feedrate, const char *comment)
|
||||||
{
|
{
|
||||||
push_to_output(EXTRUDE_END_TAG.data(), EXTRUDE_END_TAG_LENGTH, true);
|
push_to_output(EXTRUDE_END_TAG.data(), EXTRUDE_END_TAG.length(), true);
|
||||||
|
|
||||||
push_to_output("G1", 2, false);
|
GCodeG1Formatter feedrate_formatter;
|
||||||
push_axis_to_output('F', new_feedrate);
|
feedrate_formatter.emit_f(new_feedrate);
|
||||||
|
feedrate_formatter.emit_string(std::string(EXTRUDE_SET_SPEED_TAG.data(), EXTRUDE_SET_SPEED_TAG.length()));
|
||||||
push_to_output(EXTRUDE_SET_SPEED_TAG.data(), EXTRUDE_SET_SPEED_TAG_LENGTH, line.extrusion_role != erExternalPerimeter);
|
|
||||||
if (line.extrusion_role == erExternalPerimeter)
|
if (line.extrusion_role == erExternalPerimeter)
|
||||||
push_to_output(EXTERNAL_PERIMETER_TAG.data(), EXTERNAL_PERIMETER_TAG_LENGTH, true);
|
feedrate_formatter.emit_string(std::string(EXTERNAL_PERIMETER_TAG.data(), EXTERNAL_PERIMETER_TAG.length()));
|
||||||
|
push_to_output(feedrate_formatter);
|
||||||
|
|
||||||
push_to_output("G1", 2, false);
|
GCodeG1Formatter extrusion_formatter;
|
||||||
for (char i = 0; i < 3; ++ i)
|
for (size_t axis_idx = 0; axis_idx < 3; ++axis_idx)
|
||||||
if (line.pos_provided[i])
|
if (line.pos_provided[axis_idx])
|
||||||
push_axis_to_output('X'+i, line.pos_end[i]);
|
extrusion_formatter.emit_axis(char('X' + axis_idx), line.pos_end[axis_idx], GCodeFormatter::XYZF_EXPORT_DIGITS);
|
||||||
push_axis_to_output('E', m_config.use_relative_e_distances.value ? (line.pos_end[3] - line.pos_start[3]) : line.pos_end[3]);
|
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);
|
||||||
|
|
||||||
// output comment and EOL
|
if (comment != nullptr)
|
||||||
push_to_output(comment, (comment == nullptr) ? 0 : strlen(comment), true);
|
extrusion_formatter.emit_string(std::string(comment));
|
||||||
|
|
||||||
|
push_to_output(extrusion_formatter);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
|
@ -5,8 +5,14 @@
|
||||||
#include "../PrintConfig.hpp"
|
#include "../PrintConfig.hpp"
|
||||||
#include "../ExtrusionEntity.hpp"
|
#include "../ExtrusionEntity.hpp"
|
||||||
|
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
|
struct LayerResult;
|
||||||
|
|
||||||
|
class GCodeG1Formatter;
|
||||||
|
|
||||||
//#define PRESSURE_EQUALIZER_STATISTIC
|
//#define PRESSURE_EQUALIZER_STATISTIC
|
||||||
//#define PRESSURE_EQUALIZER_DEBUG
|
//#define PRESSURE_EQUALIZER_DEBUG
|
||||||
|
|
||||||
|
@ -15,30 +21,34 @@ namespace Slic3r {
|
||||||
class PressureEqualizer
|
class PressureEqualizer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
PressureEqualizer() = delete;
|
||||||
explicit PressureEqualizer(const Slic3r::GCodeConfig &config);
|
explicit PressureEqualizer(const Slic3r::GCodeConfig &config);
|
||||||
~PressureEqualizer() = default;
|
~PressureEqualizer() = default;
|
||||||
|
|
||||||
void reset();
|
// Process a next batch of G-code lines.
|
||||||
|
// The last LayerResult must be LayerResult::make_nop_layer_result() because it always returns GCode for the previous layer.
|
||||||
// Process a next batch of G-code lines. Flush the internal buffers if asked for.
|
// When process_layer is called for the first layer, then LayerResult::make_nop_layer_result() is returned.
|
||||||
const char* process_layer(const char *szGCode, bool flush);
|
LayerResult process_layer(LayerResult &&input);
|
||||||
|
|
||||||
size_t get_output_buffer_length() const { return output_buffer_length; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
void process_layer(const std::string &gcode);
|
||||||
|
|
||||||
|
#ifdef PRESSURE_EQUALIZER_STATISTIC
|
||||||
struct Statistics
|
struct Statistics
|
||||||
{
|
{
|
||||||
void reset() {
|
void reset()
|
||||||
volumetric_extrusion_rate_min = std::numeric_limits<float>::max();
|
{
|
||||||
|
volumetric_extrusion_rate_min = std::numeric_limits<float>::max();
|
||||||
volumetric_extrusion_rate_max = 0.f;
|
volumetric_extrusion_rate_max = 0.f;
|
||||||
volumetric_extrusion_rate_avg = 0.f;
|
volumetric_extrusion_rate_avg = 0.f;
|
||||||
extrusion_length = 0.f;
|
extrusion_length = 0.f;
|
||||||
}
|
}
|
||||||
void update(float volumetric_extrusion_rate, float length) {
|
void update(float volumetric_extrusion_rate, float length)
|
||||||
volumetric_extrusion_rate_min = std::min(volumetric_extrusion_rate_min, volumetric_extrusion_rate);
|
{
|
||||||
volumetric_extrusion_rate_max = std::max(volumetric_extrusion_rate_max, volumetric_extrusion_rate);
|
volumetric_extrusion_rate_min = std::min(volumetric_extrusion_rate_min, volumetric_extrusion_rate);
|
||||||
|
volumetric_extrusion_rate_max = std::max(volumetric_extrusion_rate_max, volumetric_extrusion_rate);
|
||||||
volumetric_extrusion_rate_avg += volumetric_extrusion_rate * length;
|
volumetric_extrusion_rate_avg += volumetric_extrusion_rate * length;
|
||||||
extrusion_length += length;
|
extrusion_length += length;
|
||||||
}
|
}
|
||||||
float volumetric_extrusion_rate_min;
|
float volumetric_extrusion_rate_min;
|
||||||
float volumetric_extrusion_rate_max;
|
float volumetric_extrusion_rate_max;
|
||||||
|
@ -46,21 +56,16 @@ private:
|
||||||
float extrusion_length;
|
float extrusion_length;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef PRESSURE_EQUALIZER_STATISTIC
|
|
||||||
struct Statistics m_stat;
|
struct Statistics m_stat;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Keeps the reference, does not own the config.
|
|
||||||
const Slic3r::GCodeConfig &m_config;
|
|
||||||
|
|
||||||
// Private configuration values
|
// Private configuration values
|
||||||
// How fast could the volumetric extrusion rate increase / decrase? mm^3/sec^2
|
// How fast could the volumetric extrusion rate increase / decrase? mm^3/sec^2
|
||||||
struct ExtrusionRateSlope {
|
struct ExtrusionRateSlope {
|
||||||
float positive;
|
float positive;
|
||||||
float negative;
|
float negative;
|
||||||
};
|
};
|
||||||
enum { numExtrusionRoles = erSupportMaterialInterface + 1 };
|
ExtrusionRateSlope m_max_volumetric_extrusion_rate_slopes[erCount];
|
||||||
ExtrusionRateSlope m_max_volumetric_extrusion_rate_slopes[numExtrusionRoles];
|
|
||||||
float m_max_volumetric_extrusion_rate_slope_positive;
|
float m_max_volumetric_extrusion_rate_slope_positive;
|
||||||
float m_max_volumetric_extrusion_rate_slope_negative;
|
float m_max_volumetric_extrusion_rate_slope_negative;
|
||||||
// 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.
|
||||||
|
@ -76,6 +81,7 @@ private:
|
||||||
size_t m_current_extruder;
|
size_t m_current_extruder;
|
||||||
ExtrusionRole m_current_extrusion_role;
|
ExtrusionRole m_current_extrusion_role;
|
||||||
bool m_retracted;
|
bool m_retracted;
|
||||||
|
bool m_use_relative_e_distances;
|
||||||
|
|
||||||
enum GCodeLineType {
|
enum GCodeLineType {
|
||||||
GCODELINETYPE_INVALID,
|
GCODELINETYPE_INVALID,
|
||||||
|
@ -132,8 +138,6 @@ private:
|
||||||
// or maybe the line needs to be split into multiple lines.
|
// or maybe the line needs to be split into multiple lines.
|
||||||
bool modified;
|
bool modified;
|
||||||
|
|
||||||
// float timeStart;
|
|
||||||
// float timeEnd;
|
|
||||||
// X,Y,Z,E,F. Storing the state of the currently active extruder only.
|
// X,Y,Z,E,F. Storing the state of the currently active extruder only.
|
||||||
float pos_start[5];
|
float pos_start[5];
|
||||||
float pos_end[5];
|
float pos_end[5];
|
||||||
|
@ -158,21 +162,14 @@ private:
|
||||||
float max_volumetric_extrusion_rate_slope_negative;
|
float max_volumetric_extrusion_rate_slope_negative;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Circular buffer of GCode lines. The circular buffer size will be limited to circular_buffer_size.
|
|
||||||
std::vector<GCodeLine> circular_buffer;
|
|
||||||
// Current position of the circular buffer (index, where to write the next line to, the line has to be pushed out before it is overwritten).
|
|
||||||
size_t circular_buffer_pos;
|
|
||||||
// Circular buffer size, configuration value.
|
|
||||||
size_t circular_buffer_size;
|
|
||||||
// Number of valid lines in the circular buffer. Lower or equal to circular_buffer_size.
|
|
||||||
size_t circular_buffer_items;
|
|
||||||
|
|
||||||
// Output buffer will only grow. It will not be reallocated over and over.
|
// Output buffer will only grow. It will not be reallocated over and over.
|
||||||
std::vector<char> output_buffer;
|
std::vector<char> output_buffer;
|
||||||
size_t output_buffer_length;
|
size_t output_buffer_length;
|
||||||
|
|
||||||
|
#ifdef PRESSURE_EQUALIZER_DEBUG
|
||||||
// For debugging purposes. Index of the G-code line processed.
|
// For debugging purposes. Index of the G-code line processed.
|
||||||
size_t line_idx;
|
size_t line_idx;
|
||||||
|
#endif
|
||||||
|
|
||||||
bool process_line(const char *line, const char *line_end, GCodeLine &buf);
|
bool process_line(const char *line, const char *line_end, GCodeLine &buf);
|
||||||
void output_gcode_line(GCodeLine &buf);
|
void output_gcode_line(GCodeLine &buf);
|
||||||
|
@ -182,33 +179,16 @@ private:
|
||||||
void adjust_volumetric_rate();
|
void adjust_volumetric_rate();
|
||||||
|
|
||||||
// Push the text to the end of the output_buffer.
|
// Push the text to the end of the output_buffer.
|
||||||
void push_to_output(const char *text, size_t len, bool add_eol = true);
|
inline void push_to_output(GCodeG1Formatter &formatter);
|
||||||
// Push an axis assignment to the end of the output buffer.
|
inline void push_to_output(const std::string &text, bool add_eol);
|
||||||
void push_axis_to_output(char axis, float value, bool add_eol = false);
|
inline void push_to_output(const char *text, size_t len, bool add_eol = true);
|
||||||
// Push a G-code line to the output,
|
// Push a G-code line to the output.
|
||||||
void push_line_to_output(const GCodeLine &line, float new_feedrate, const char *comment);
|
void push_line_to_output(const GCodeLine &line, float new_feedrate, const char *comment);
|
||||||
|
|
||||||
size_t circular_buffer_idx_head() const {
|
public:
|
||||||
size_t idx = circular_buffer_pos + circular_buffer_size - circular_buffer_items;
|
std::queue<LayerResult*> m_layer_results;
|
||||||
if (idx >= circular_buffer_size)
|
|
||||||
idx -= circular_buffer_size;
|
|
||||||
return idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t circular_buffer_idx_tail() const { return circular_buffer_pos; }
|
std::vector<GCodeLine> m_gcode_lines;
|
||||||
|
|
||||||
size_t circular_buffer_idx_prev(size_t idx) const {
|
|
||||||
idx += circular_buffer_size - 1;
|
|
||||||
if (idx >= circular_buffer_size)
|
|
||||||
idx -= circular_buffer_size;
|
|
||||||
return idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t circular_buffer_idx_next(size_t idx) const {
|
|
||||||
if (++ idx >= circular_buffer_size)
|
|
||||||
idx -= circular_buffer_size;
|
|
||||||
return idx;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
Loading…
Reference in a new issue