PlaceholderParser & G-code export: Exchange of position & extrusion status between custom G-codes and slicer, extension of script syntax.
Newly each custom G-code block may exchange the following values with slicer: Position and Z-hop: position (read/write)- 3 element vector (X, Y, Z) of current G-code position. Z element contains the current Z hop. zhop (read only)- initial zhop value Extruders: vector variables, one element per extruder: e_position (read/write) - absolute E position, only available with absolute extruder addressing e_retracted (read/write) - current retraction state e_restart_extra (read/write) - current planned extra deretraction when starting printing For readibility, script's if / elsif / else / endif syntax was modified: {if cond then block elsif cond then block else block endif} Semicolon is not required after else or endif.
This commit is contained in:
parent
f1dd85309b
commit
59552a8aee
6 changed files with 243 additions and 50 deletions
|
@ -37,6 +37,7 @@ std::pair<double, double> Extruder::extrude(double dE)
|
|||
value supplied will overwrite the previous one if any. */
|
||||
std::pair<double, double> Extruder::retract(double retract_length, double restart_extra)
|
||||
{
|
||||
assert(restart_extra >= 0);
|
||||
// in case of relative E distances we always reset to 0 before any output
|
||||
if (m_config->use_relative_e_distances)
|
||||
m_E = 0.;
|
||||
|
@ -64,6 +65,24 @@ std::pair<double, double> Extruder::unretract()
|
|||
return std::make_pair(dE, emitE);
|
||||
}
|
||||
|
||||
// Setting the retract state from the script.
|
||||
// Sets current retraction value & restart extra filament amount if retracted > 0.
|
||||
void Extruder::set_retracted(double retracted, double restart_extra)
|
||||
{
|
||||
if (retracted < - EPSILON)
|
||||
throw Slic3r::RuntimeError("Custom G-code reports negative z_retracted.");
|
||||
if (restart_extra < - EPSILON)
|
||||
throw Slic3r::RuntimeError("Custom G-code reports negative z_restart_extra.");
|
||||
|
||||
if (retracted > EPSILON) {
|
||||
m_retracted = retracted;
|
||||
m_restart_extra = restart_extra < EPSILON ? 0 : restart_extra;
|
||||
} else {
|
||||
m_retracted = 0;
|
||||
m_restart_extra = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Used filament volume in mm^3.
|
||||
double Extruder::extruded_volume() const
|
||||
{
|
||||
|
|
|
@ -36,6 +36,19 @@ public:
|
|||
double extruded_volume() const;
|
||||
// Used filament length in mm.
|
||||
double used_filament() const;
|
||||
|
||||
// Getters for the PlaceholderParser.
|
||||
// Get current extruder position. Only applicable with absolute extruder addressing.
|
||||
double position() const { return m_E; }
|
||||
// Get current retraction value. Only non-negative values.
|
||||
double retracted() const { return m_retracted; }
|
||||
// Get extra retraction planned after
|
||||
double restart_extra() const { return m_restart_extra; }
|
||||
// Setters for the PlaceholderParser.
|
||||
// Set current extruder position. Only applicable with absolute extruder addressing.
|
||||
void set_position(double e) { m_E = e; }
|
||||
// Sets current retraction value & restart extra filament amount if retracted > 0.
|
||||
void set_retracted(double retracted, double restart_extra);
|
||||
|
||||
double filament_diameter() const;
|
||||
double filament_crossection() const { return this->filament_diameter() * this->filament_diameter() * 0.25 * PI; }
|
||||
|
|
|
@ -419,7 +419,7 @@ namespace Slic3r {
|
|||
std::string WipeTowerIntegration::finalize(GCode& gcodegen)
|
||||
{
|
||||
std::string gcode;
|
||||
if (std::abs(gcodegen.writer().get_position()(2) - m_final_purge.print_z) > EPSILON)
|
||||
if (std::abs(gcodegen.writer().get_position().z() - m_final_purge.print_z) > EPSILON)
|
||||
gcode += gcodegen.change_layer(m_final_purge.print_z);
|
||||
gcode += append_tcr(gcodegen, m_final_purge, -1);
|
||||
return gcode;
|
||||
|
@ -429,6 +429,90 @@ namespace Slic3r {
|
|||
|
||||
#define EXTRUDER_CONFIG(OPT) m_config.OPT.get_at(m_writer.extruder()->id())
|
||||
|
||||
void GCode::PlaceholderParserIntegration::reset()
|
||||
{
|
||||
this->failed_templates.clear();
|
||||
this->output_config.clear();
|
||||
this->opt_position = nullptr;
|
||||
this->opt_zhop = nullptr;
|
||||
this->opt_e_position = nullptr;
|
||||
this->opt_e_retracted = nullptr;
|
||||
this->opt_e_restart_extra = nullptr;
|
||||
this->num_extruders = 0;
|
||||
this->position.clear();
|
||||
this->e_position.clear();
|
||||
this->e_retracted.clear();
|
||||
this->e_restart_extra.clear();
|
||||
}
|
||||
|
||||
void GCode::PlaceholderParserIntegration::init(const GCodeWriter &writer)
|
||||
{
|
||||
this->reset();
|
||||
const std::vector<Extruder> &extruders = writer.extruders();
|
||||
if (! extruders.empty()) {
|
||||
this->num_extruders = extruders.back().id() + 1;
|
||||
this->e_retracted.assign(num_extruders, 0);
|
||||
this->e_restart_extra.assign(num_extruders, 0);
|
||||
this->opt_e_retracted = new ConfigOptionFloats(e_retracted);
|
||||
this->opt_e_restart_extra = new ConfigOptionFloats(e_restart_extra);
|
||||
this->output_config.set_key_value("e_retracted", this->opt_e_retracted);
|
||||
this->output_config.set_key_value("e_restart_extra", this->opt_e_restart_extra);
|
||||
if (! writer.config.use_relative_e_distances) {
|
||||
e_position.assign(num_extruders, 0);
|
||||
opt_e_position = new ConfigOptionFloats(e_position);
|
||||
this->output_config.set_key_value("e_position", opt_e_position);
|
||||
}
|
||||
}
|
||||
|
||||
// Reserve buffer for current position.
|
||||
this->position.assign(3, 0);
|
||||
this->opt_position = new ConfigOptionFloats(this->position);
|
||||
// Store zhop variable into the parser itself, it is a read-only variable to the script.
|
||||
this->opt_zhop = new ConfigOptionFloat(writer.get_zhop());
|
||||
this->parser.set("zhop", this->opt_zhop);
|
||||
}
|
||||
|
||||
void GCode::PlaceholderParserIntegration::update_from_gcodewriter(const GCodeWriter &writer)
|
||||
{
|
||||
memcpy(this->position.data(), writer.get_position().data(), sizeof(double) * 3);
|
||||
this->opt_position->values = this->position;
|
||||
this->opt_zhop->value = writer.get_zhop();
|
||||
|
||||
if (this->num_extruders > 0) {
|
||||
const std::vector<Extruder> &extruders = writer.extruders();
|
||||
assert(! extruders.empty() && num_extruders == extruders.back().id() + 1);
|
||||
this->e_retracted.assign(num_extruders, 0);
|
||||
this->e_restart_extra.assign(num_extruders, 0);
|
||||
for (const Extruder &e : extruders) {
|
||||
this->e_retracted[e.id()] = e.retracted();
|
||||
this->e_restart_extra[e.id()] = e.restart_extra();
|
||||
}
|
||||
opt_e_retracted->values = this->e_retracted;
|
||||
opt_e_restart_extra->values = this->e_restart_extra;
|
||||
if (! writer.config.use_relative_e_distances) {
|
||||
this->e_position.assign(num_extruders, 0);
|
||||
for (const Extruder &e : extruders)
|
||||
this->e_position[e.id()] = e.position();
|
||||
this->opt_e_position->values = this->e_position;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Throw if any of the output vector variables were resized by the script.
|
||||
void GCode::PlaceholderParserIntegration::validate_output_vector_variables()
|
||||
{
|
||||
if (this->opt_position->values.size() != 3)
|
||||
throw Slic3r::RuntimeError("\"position\" output variable must not be resized by the script.");
|
||||
if (this->num_extruders > 0) {
|
||||
if (this->opt_e_position && this->opt_e_position->values.size() != this->num_extruders)
|
||||
throw Slic3r::RuntimeError("\"e_position\" output variable must not be resized by the script.");
|
||||
if (this->opt_e_retracted->values.size() != this->num_extruders)
|
||||
throw Slic3r::RuntimeError("\"e_retracted\" output variable must not be resized by the script.");
|
||||
if (this->opt_e_restart_extra->values.size() != this->num_extruders)
|
||||
throw Slic3r::RuntimeError("\"e_restart_extra\" output variable must not be resized by the script.");
|
||||
}
|
||||
}
|
||||
|
||||
// Collect pairs of object_layer + support_layer sorted by print_z.
|
||||
// object_layer & support_layer are considered to be on the same print_z, if they are not further than EPSILON.
|
||||
GCode::ObjectsLayerToPrint GCode::collect_layers_to_print(const PrintObject& object)
|
||||
|
@ -728,7 +812,6 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
|
|||
throw Slic3r::RuntimeError(std::string("G-code export to ") + path + " failed.\nCannot open the file for writing.\n");
|
||||
|
||||
try {
|
||||
m_placeholder_parser_failed_templates.clear();
|
||||
this->_do_export(*print, file, thumbnail_cb);
|
||||
file.flush();
|
||||
if (file.is_error()) {
|
||||
|
@ -745,11 +828,11 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
|
|||
}
|
||||
file.close();
|
||||
|
||||
if (! m_placeholder_parser_failed_templates.empty()) {
|
||||
if (! m_placeholder_parser_integration.failed_templates.empty()) {
|
||||
// G-code export proceeded, but some of the PlaceholderParser substitutions failed.
|
||||
//FIXME localize!
|
||||
std::string msg = std::string("G-code export to ") + path + " failed due to invalid custom G-code sections:\n\n";
|
||||
for (const auto &name_and_error : m_placeholder_parser_failed_templates)
|
||||
for (const auto &name_and_error : m_placeholder_parser_integration.failed_templates)
|
||||
msg += name_and_error.first + "\n" + name_and_error.second + "\n";
|
||||
msg += "\nPlease inspect the file ";
|
||||
msg += path_tmp + " for error messages enclosed between\n";
|
||||
|
@ -1078,12 +1161,12 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
|||
file.find_replace_enable();
|
||||
|
||||
// Prepare the helper object for replacing placeholders in custom G-code and output filename.
|
||||
m_placeholder_parser = print.placeholder_parser();
|
||||
m_placeholder_parser.update_timestamp();
|
||||
m_placeholder_parser_context.rng = std::mt19937(std::chrono::high_resolution_clock::now().time_since_epoch().count());
|
||||
m_placeholder_parser_integration.parser = print.placeholder_parser();
|
||||
m_placeholder_parser_integration.parser.update_timestamp();
|
||||
m_placeholder_parser_integration.context.rng = std::mt19937(std::chrono::high_resolution_clock::now().time_since_epoch().count());
|
||||
// Enable passing global variables between PlaceholderParser invocations.
|
||||
m_placeholder_parser_context.global_config = std::make_unique<DynamicConfig>();
|
||||
print.update_object_placeholders(m_placeholder_parser.config_writable(), ".gcode");
|
||||
m_placeholder_parser_integration.context.global_config = std::make_unique<DynamicConfig>();
|
||||
print.update_object_placeholders(m_placeholder_parser_integration.parser.config_writable(), ".gcode");
|
||||
|
||||
// Get optimal tool ordering to minimize tool switches of a multi-exruder print.
|
||||
// For a print by objects, find the 1st printing object.
|
||||
|
@ -1147,23 +1230,25 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
|||
// Emit machine envelope limits for the Marlin firmware.
|
||||
this->print_machine_envelope(file, print);
|
||||
|
||||
// Update output variables after the extruders were initialized.
|
||||
m_placeholder_parser_integration.init(m_writer);
|
||||
// Let the start-up script prime the 1st printing tool.
|
||||
m_placeholder_parser.set("initial_tool", initial_extruder_id);
|
||||
m_placeholder_parser.set("initial_extruder", initial_extruder_id);
|
||||
m_placeholder_parser.set("current_extruder", initial_extruder_id);
|
||||
this->placeholder_parser().set("initial_tool", initial_extruder_id);
|
||||
this->placeholder_parser().set("initial_extruder", initial_extruder_id);
|
||||
this->placeholder_parser().set("current_extruder", initial_extruder_id);
|
||||
//Set variable for total layer count so it can be used in custom gcode.
|
||||
m_placeholder_parser.set("total_layer_count", m_layer_count);
|
||||
this->placeholder_parser().set("total_layer_count", m_layer_count);
|
||||
// Useful for sequential prints.
|
||||
m_placeholder_parser.set("current_object_idx", 0);
|
||||
this->placeholder_parser().set("current_object_idx", 0);
|
||||
// For the start / end G-code to do the priming and final filament pull in case there is no wipe tower provided.
|
||||
m_placeholder_parser.set("has_wipe_tower", has_wipe_tower);
|
||||
m_placeholder_parser.set("has_single_extruder_multi_material_priming", has_wipe_tower && print.config().single_extruder_multi_material_priming);
|
||||
m_placeholder_parser.set("total_toolchanges", std::max(0, print.wipe_tower_data().number_of_toolchanges)); // Check for negative toolchanges (single extruder mode) and set to 0 (no tool change).
|
||||
this->placeholder_parser().set("has_wipe_tower", has_wipe_tower);
|
||||
this->placeholder_parser().set("has_single_extruder_multi_material_priming", has_wipe_tower && print.config().single_extruder_multi_material_priming);
|
||||
this->placeholder_parser().set("total_toolchanges", std::max(0, print.wipe_tower_data().number_of_toolchanges)); // Check for negative toolchanges (single extruder mode) and set to 0 (no tool change).
|
||||
{
|
||||
BoundingBoxf bbox(print.config().bed_shape.values);
|
||||
m_placeholder_parser.set("print_bed_min", new ConfigOptionFloats({ bbox.min.x(), bbox.min.y() }));
|
||||
m_placeholder_parser.set("print_bed_max", new ConfigOptionFloats({ bbox.max.x(), bbox.max.y() }));
|
||||
m_placeholder_parser.set("print_bed_size", new ConfigOptionFloats({ bbox.size().x(), bbox.size().y() }));
|
||||
this->placeholder_parser().set("print_bed_min", new ConfigOptionFloats({ bbox.min.x(), bbox.min.y() }));
|
||||
this->placeholder_parser().set("print_bed_max", new ConfigOptionFloats({ bbox.max.x(), bbox.max.y() }));
|
||||
this->placeholder_parser().set("print_bed_size", new ConfigOptionFloats({ bbox.size().x(), bbox.size().y() }));
|
||||
}
|
||||
{
|
||||
// Convex hull of the 1st layer extrusions, for bed leveling and placing the initial purge line.
|
||||
|
@ -1176,15 +1261,15 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
|||
for (const Point &pt : print.first_layer_convex_hull().points)
|
||||
pts->values.emplace_back(unscale(pt));
|
||||
BoundingBoxf bbox(pts->values);
|
||||
m_placeholder_parser.set("first_layer_print_convex_hull", pts.release());
|
||||
m_placeholder_parser.set("first_layer_print_min", new ConfigOptionFloats({ bbox.min.x(), bbox.min.y() }));
|
||||
m_placeholder_parser.set("first_layer_print_max", new ConfigOptionFloats({ bbox.max.x(), bbox.max.y() }));
|
||||
m_placeholder_parser.set("first_layer_print_size", new ConfigOptionFloats({ bbox.size().x(), bbox.size().y() }));
|
||||
this->placeholder_parser().set("first_layer_print_convex_hull", pts.release());
|
||||
this->placeholder_parser().set("first_layer_print_min", new ConfigOptionFloats({ bbox.min.x(), bbox.min.y() }));
|
||||
this->placeholder_parser().set("first_layer_print_max", new ConfigOptionFloats({ bbox.max.x(), bbox.max.y() }));
|
||||
this->placeholder_parser().set("first_layer_print_size", new ConfigOptionFloats({ bbox.size().x(), bbox.size().y() }));
|
||||
|
||||
std::vector<unsigned char> is_extruder_used(print.config().nozzle_diameter.size(), 0);
|
||||
for (unsigned int extruder_id : tool_ordering.all_extruders())
|
||||
is_extruder_used[extruder_id] = true;
|
||||
m_placeholder_parser.set("is_extruder_used", new ConfigOptionBools(is_extruder_used));
|
||||
this->placeholder_parser().set("is_extruder_used", new ConfigOptionBools(is_extruder_used));
|
||||
}
|
||||
|
||||
// Enable ooze prevention if configured so.
|
||||
|
@ -1251,7 +1336,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
|||
// Ff we are printing the bottom layer of an object, and we have already finished
|
||||
// another one, set first layer temperatures. This happens before the Z move
|
||||
// is triggered, so machine has more time to reach such temperatures.
|
||||
m_placeholder_parser.set("current_object_idx", int(finished_objects));
|
||||
this->placeholder_parser().set("current_object_idx", int(finished_objects));
|
||||
std::string between_objects_gcode = this->placeholder_parser_process("between_objects_gcode", print.config().between_objects_gcode.value, initial_extruder_id);
|
||||
// Set first layer bed and extruder temperatures, don't wait for it to reach the temperature.
|
||||
this->_print_first_layer_bed_temperature(file, print, between_objects_gcode, initial_extruder_id, false);
|
||||
|
@ -1337,7 +1422,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
|||
{
|
||||
DynamicConfig config;
|
||||
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
|
||||
config.set_key_value("layer_z", new ConfigOptionFloat(m_writer.get_position()(2) - m_config.z_offset.value));
|
||||
config.set_key_value("layer_z", new ConfigOptionFloat(m_writer.get_position().z() - m_config.z_offset.value));
|
||||
config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
|
||||
if (print.config().single_extruder_multi_material) {
|
||||
// Process the end_filament_gcode for the active filament only.
|
||||
|
@ -1560,17 +1645,46 @@ void GCode::process_layers(
|
|||
output_stream.find_replace_enable();
|
||||
}
|
||||
|
||||
std::string GCode::placeholder_parser_process(const std::string &name, const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override)
|
||||
std::string GCode::placeholder_parser_process(
|
||||
const std::string &name,
|
||||
const std::string &templ,
|
||||
unsigned int current_extruder_id,
|
||||
const DynamicConfig *config_override)
|
||||
{
|
||||
PlaceholderParserIntegration &ppi = m_placeholder_parser_integration;
|
||||
try {
|
||||
return m_placeholder_parser.process(templ, current_extruder_id, config_override, &m_placeholder_parser_context);
|
||||
} catch (std::runtime_error &err) {
|
||||
ppi.update_from_gcodewriter(m_writer);
|
||||
std::string output = ppi.parser.process(templ, current_extruder_id, config_override, &ppi.output_config, &ppi.context);
|
||||
ppi.validate_output_vector_variables();
|
||||
|
||||
if (const std::vector<double> &pos = ppi.opt_position->values; ppi.position != pos) {
|
||||
// Update G-code writer.
|
||||
m_writer.update_position({ pos[0], pos[1], pos[2] });
|
||||
this->set_last_pos(this->gcode_to_point({ pos[0], pos[1] }));
|
||||
}
|
||||
|
||||
for (const Extruder &e : m_writer.extruders()) {
|
||||
unsigned int eid = e.id();
|
||||
assert(eid < ppi.num_extruders);
|
||||
if ( eid < ppi.num_extruders) {
|
||||
if (! m_writer.config.use_relative_e_distances && ! is_approx(ppi.e_position[eid], ppi.opt_e_position->values[eid]))
|
||||
const_cast<Extruder&>(e).set_position(ppi.opt_e_position->values[eid]);
|
||||
if (! is_approx(ppi.e_retracted[eid], ppi.opt_e_retracted->values[eid]) ||
|
||||
! is_approx(ppi.e_restart_extra[eid], ppi.opt_e_restart_extra->values[eid]))
|
||||
const_cast<Extruder&>(e).set_retracted(ppi.opt_e_retracted->values[eid], ppi.opt_e_restart_extra->values[eid]);
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
catch (std::runtime_error &err)
|
||||
{
|
||||
// Collect the names of failed template substitutions for error reporting.
|
||||
auto it = m_placeholder_parser_failed_templates.find(name);
|
||||
if (it == m_placeholder_parser_failed_templates.end())
|
||||
auto it = ppi.failed_templates.find(name);
|
||||
if (it == ppi.failed_templates.end())
|
||||
// Only if there was no error reported for this template, store the first error message into the map to be reported.
|
||||
// We don't want to collect error message for each and every occurence of a single custom G-code section.
|
||||
m_placeholder_parser_failed_templates.insert(it, std::make_pair(name, std::string(err.what())));
|
||||
ppi.failed_templates.insert(it, std::make_pair(name, std::string(err.what())));
|
||||
// Insert the macro error message into the G-code.
|
||||
return
|
||||
std::string("\n!!!!! Failed to process the custom G-code template ") + name + "\n" +
|
||||
|
@ -3160,7 +3274,7 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
|
|||
|
||||
// if we are running a single-extruder setup, just set the extruder and return nothing
|
||||
if (!m_writer.multiple_extruders) {
|
||||
m_placeholder_parser.set("current_extruder", extruder_id);
|
||||
this->placeholder_parser().set("current_extruder", extruder_id);
|
||||
|
||||
std::string gcode;
|
||||
// Append the filament start G-code.
|
||||
|
@ -3169,7 +3283,7 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
|
|||
// Process the start_filament_gcode for the filament.
|
||||
DynamicConfig config;
|
||||
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
|
||||
config.set_key_value("layer_z", new ConfigOptionFloat(this->writer().get_position()(2) - m_config.z_offset.value));
|
||||
config.set_key_value("layer_z", new ConfigOptionFloat(this->writer().get_position().z() - m_config.z_offset.value));
|
||||
config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
|
||||
config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(extruder_id)));
|
||||
gcode += this->placeholder_parser_process("start_filament_gcode", start_filament_gcode, extruder_id, &config);
|
||||
|
@ -3233,7 +3347,7 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
|
|||
gcode += m_writer.set_temperature(temp, false);
|
||||
}
|
||||
|
||||
m_placeholder_parser.set("current_extruder", extruder_id);
|
||||
this->placeholder_parser().set("current_extruder", extruder_id);
|
||||
|
||||
// Append the filament start G-code.
|
||||
const std::string &start_filament_gcode = m_config.start_filament_gcode.get_at(extruder_id);
|
||||
|
@ -3241,7 +3355,7 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
|
|||
// Process the start_filament_gcode for the new filament.
|
||||
DynamicConfig config;
|
||||
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
|
||||
config.set_key_value("layer_z", new ConfigOptionFloat(this->writer().get_position()(2) - m_config.z_offset.value));
|
||||
config.set_key_value("layer_z", new ConfigOptionFloat(this->writer().get_position().z() - m_config.z_offset.value));
|
||||
config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
|
||||
config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(extruder_id)));
|
||||
gcode += this->placeholder_parser_process("start_filament_gcode", start_filament_gcode, extruder_id, &config);
|
||||
|
|
|
@ -173,8 +173,8 @@ public:
|
|||
const Layer* layer() const { return m_layer; }
|
||||
GCodeWriter& writer() { return m_writer; }
|
||||
const GCodeWriter& writer() const { return m_writer; }
|
||||
PlaceholderParser& placeholder_parser() { return m_placeholder_parser; }
|
||||
const PlaceholderParser& placeholder_parser() const { return m_placeholder_parser; }
|
||||
PlaceholderParser& placeholder_parser() { return m_placeholder_parser_integration.parser; }
|
||||
const PlaceholderParser& placeholder_parser() const { return m_placeholder_parser_integration.parser; }
|
||||
// Process a template through the placeholder parser, collect error messages to be reported
|
||||
// inside the generated string and after the G-code export finishes.
|
||||
std::string placeholder_parser_process(const std::string &name, const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override = nullptr);
|
||||
|
@ -343,11 +343,33 @@ private:
|
|||
// scaled G-code resolution
|
||||
double m_scaled_resolution;
|
||||
GCodeWriter m_writer;
|
||||
PlaceholderParser m_placeholder_parser;
|
||||
// For random number generator etc.
|
||||
PlaceholderParser::ContextData m_placeholder_parser_context;
|
||||
// Collection of templates, on which the placeholder substitution failed.
|
||||
std::map<std::string, std::string> m_placeholder_parser_failed_templates;
|
||||
|
||||
struct PlaceholderParserIntegration {
|
||||
void reset();
|
||||
void init(const GCodeWriter &config);
|
||||
void update_from_gcodewriter(const GCodeWriter &writer);
|
||||
void validate_output_vector_variables();
|
||||
|
||||
PlaceholderParser parser;
|
||||
// For random number generator etc.
|
||||
PlaceholderParser::ContextData context;
|
||||
// Collection of templates, on which the placeholder substitution failed.
|
||||
std::map<std::string, std::string> failed_templates;
|
||||
// Input/output from/to custom G-code block, for returning position, retraction etc.
|
||||
DynamicConfig output_config;
|
||||
ConfigOptionFloats *opt_position { nullptr };
|
||||
ConfigOptionFloat *opt_zhop { nullptr };
|
||||
ConfigOptionFloats *opt_e_position { nullptr };
|
||||
ConfigOptionFloats *opt_e_retracted { nullptr };
|
||||
ConfigOptionFloats *opt_e_restart_extra { nullptr };
|
||||
// Caches of the data passed to the script.
|
||||
size_t num_extruders;
|
||||
std::vector<double> position;
|
||||
std::vector<double> e_position;
|
||||
std::vector<double> e_retracted;
|
||||
std::vector<double> e_restart_extra;
|
||||
} m_placeholder_parser_integration;
|
||||
|
||||
OozePrevention m_ooze_prevention;
|
||||
Wipe m_wipe;
|
||||
AvoidCrossingPerimeters m_avoid_crossing_perimeters;
|
||||
|
@ -403,15 +425,15 @@ private:
|
|||
// Index of a last object copy extruded.
|
||||
std::pair<const PrintObject*, Point> m_last_obj_copy;
|
||||
|
||||
bool m_silent_time_estimator_enabled;
|
||||
bool m_silent_time_estimator_enabled;
|
||||
|
||||
// Processor
|
||||
GCodeProcessor m_processor;
|
||||
GCodeProcessor m_processor;
|
||||
|
||||
std::string _extrude(const ExtrusionPath &path, const std::string_view description, double speed = -1);
|
||||
void print_machine_envelope(GCodeOutputStream &file, Print &print);
|
||||
void _print_first_layer_bed_temperature(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait);
|
||||
void _print_first_layer_extruder_temperatures(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait);
|
||||
std::string _extrude(const ExtrusionPath &path, const std::string_view description, double speed = -1);
|
||||
void print_machine_envelope(GCodeOutputStream &file, Print &print);
|
||||
void _print_first_layer_bed_temperature(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait);
|
||||
void _print_first_layer_extruder_temperatures(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait);
|
||||
// On the first printing layer. This flag triggers first layer speeds.
|
||||
bool on_first_layer() const { return m_layer != nullptr && m_layer->id() == 0; }
|
||||
// To control print speed of 1st object layer over raft interface.
|
||||
|
|
|
@ -486,6 +486,20 @@ std::string GCodeWriter::unlift()
|
|||
return gcode;
|
||||
}
|
||||
|
||||
void GCodeWriter::update_position(const Vec3d &new_pos)
|
||||
{
|
||||
assert(this->m_lifted >= 0);
|
||||
const double nominal_z = m_pos.z() - m_lifted;
|
||||
m_lifted = new_pos.z() - nominal_z;
|
||||
if (m_lifted < - EPSILON)
|
||||
throw Slic3r::RuntimeError("Custom G-code reports negative Z-hop. Final Z position is below the print_z height.");
|
||||
// In case that retract_lift == layer_height we could end up with almost zero in_m_lifted
|
||||
// and a retract could be skipped (https://github.com/prusa3d/PrusaSlicer/issues/2154
|
||||
if (m_lifted < EPSILON)
|
||||
m_lifted = 0.;
|
||||
m_pos = new_pos;
|
||||
}
|
||||
|
||||
std::string GCodeWriter::set_fan(const GCodeFlavor gcode_flavor, bool gcode_comments, unsigned int speed)
|
||||
{
|
||||
std::ostringstream gcode;
|
||||
|
|
|
@ -68,7 +68,18 @@ public:
|
|||
std::string unretract();
|
||||
std::string lift();
|
||||
std::string unlift();
|
||||
|
||||
// Current position of the printer, in G-code coordinates.
|
||||
// Z coordinate of current position contains zhop. If zhop is applied (this->zhop() > 0),
|
||||
// then the print_z = this->get_position().z() - this->zhop().
|
||||
Vec3d get_position() const { return m_pos; }
|
||||
// Current Z hop value.
|
||||
double get_zhop() const { return m_lifted; }
|
||||
// Update position of the print head based on the final position returned by a custom G-code block.
|
||||
// The new position Z coordinate contains the Z-hop.
|
||||
// GCodeWriter expects the custom script to NOT change print_z, only Z-hop, thus the print_z is maintained
|
||||
// by this function while the current Z-hop accumulator is updated.
|
||||
void update_position(const Vec3d &new_pos);
|
||||
|
||||
// Returns whether this flavor supports separate print and travel acceleration.
|
||||
static bool supports_separate_travel_acceleration(GCodeFlavor flavor);
|
||||
|
|
Loading…
Reference in a new issue