Merge branch 'lh_m600' into master_27x

This commit is contained in:
Lukáš Hejl 2024-02-06 11:27:04 +01:00
commit ad61f74e3f
7 changed files with 192 additions and 104 deletions

View File

@ -72,6 +72,22 @@ std::vector<std::pair<double, unsigned int>> custom_tool_changes(const Info& cus
return custom_tool_changes;
}
// Return pairs of <print_z, 1-based extruder ID> sorted by increasing print_z from custom_gcode_per_print_z.
// Where print_z corresponds to the layer on which we perform a color change for the specified extruder.
std::vector<std::pair<double, unsigned int>> custom_color_changes(const Info& custom_gcode_per_print_z, size_t num_extruders)
{
std::vector<std::pair<double, unsigned int>> custom_color_changes;
for (const Item& custom_gcode : custom_gcode_per_print_z.gcodes)
if (custom_gcode.type == ColorChange) {
// If extruder count in PrinterSettings was changed, ignore custom g-codes for extruder ids bigger than num_extruders.
assert(custom_gcode.extruder >= 0);
if (size_t(custom_gcode.extruder) <= num_extruders) {
custom_color_changes.emplace_back(custom_gcode.print_z, static_cast<unsigned int>(custom_gcode.extruder));
}
}
return custom_color_changes;
}
} // namespace CustomGCode
} // namespace Slic3r

View File

@ -91,6 +91,10 @@ extern void check_mode_for_custom_gcode_per_print_z(Info& info);
// print_z corresponds to the first layer printed with the new extruder.
std::vector<std::pair<double, unsigned int>> custom_tool_changes(const Info& custom_gcode_per_print_z, size_t num_extruders);
// Return pairs of <print_z, 1-based extruder ID> sorted by increasing print_z from custom_gcode_per_print_z.
// Where print_z corresponds to the layer on which we perform a color change for the specified extruder.
std::vector<std::pair<double, unsigned int>> custom_color_changes(const Info& custom_gcode_per_print_z, size_t num_extruders);
} // namespace CustomGCode
} // namespace Slic3r

View File

@ -1901,84 +1901,92 @@ std::vector<GCodeGenerator::InstanceToPrint> GCodeGenerator::sort_print_object_i
namespace ProcessLayer
{
static std::string emit_custom_color_change_gcode_per_print_z(
GCodeGenerator &gcodegen,
const CustomGCode::Item &custom_gcode,
unsigned int current_extruder_id,
unsigned int first_extruder_id, // ID of the first extruder printing this layer.
const PrintConfig &config
) {
const bool single_extruder_multi_material = config.single_extruder_multi_material;
const bool single_extruder_printer = config.nozzle_diameter.size() == 1;
const bool color_change = custom_gcode.type == CustomGCode::ColorChange;
std::string gcode;
int color_change_extruder = -1;
if (color_change && custom_gcode.extruder > 0)
color_change_extruder = custom_gcode.extruder - 1;
assert(color_change_extruder >= 0);
// Color Change or Tool Change as Color Change.
// add tag for processor
gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Color_Change) + ",T" + std::to_string(color_change_extruder) + "," + custom_gcode.color + "\n";
DynamicConfig cfg;
cfg.set_key_value("color_change_extruder", new ConfigOptionInt(color_change_extruder));
if (single_extruder_multi_material && !single_extruder_printer && color_change_extruder >= 0 && first_extruder_id != unsigned(color_change_extruder)) {
//! FIXME_in_fw show message during print pause
// FIXME: Why is pause_print_gcode here? Why is it supplied "color_change_extruder"?
gcode += gcodegen.placeholder_parser_process("pause_print_gcode", config.pause_print_gcode, current_extruder_id, &cfg);
gcode += "\n";
gcode += "M117 Change filament for Extruder " + std::to_string(color_change_extruder) + "\n";
} else {
gcode += gcodegen.placeholder_parser_process("color_change_gcode", config.color_change_gcode, current_extruder_id, &cfg);
gcode += "\n";
//FIXME Tell G-code writer that M600 filled the extruder, thus the G-code writer shall reset the extruder to unretracted state after
// return from M600. Thus the G-code generated by the following line is ignored.
// see GH issue #6362
gcodegen.writer().unretract();
}
return gcode;
}
static std::string emit_custom_gcode_per_print_z(
GCodeGenerator &gcodegen,
const CustomGCode::Item *custom_gcode,
const CustomGCode::Item &custom_gcode,
unsigned int current_extruder_id,
// ID of the first extruder printing this layer.
unsigned int first_extruder_id,
const PrintConfig &config)
{
std::string gcode;
bool single_extruder_printer = config.nozzle_diameter.size() == 1;
if (custom_gcode != nullptr) {
// Extruder switches are processed by LayerTools, they should be filtered out.
assert(custom_gcode->type != CustomGCode::ToolChange);
// Extruder switches are processed by LayerTools, they should be filtered out.
assert(custom_gcode.type != CustomGCode::ToolChange);
CustomGCode::Type gcode_type = custom_gcode->type;
bool color_change = gcode_type == CustomGCode::ColorChange;
bool tool_change = gcode_type == CustomGCode::ToolChange;
// Tool Change is applied as Color Change for a single extruder printer only.
assert(! tool_change || single_extruder_printer);
CustomGCode::Type gcode_type = custom_gcode.type;
const bool color_change = gcode_type == CustomGCode::ColorChange;
const bool tool_change = gcode_type == CustomGCode::ToolChange;
// Tool Change is applied as Color Change for a single extruder printer only.
assert(!tool_change || config.nozzle_diameter.size() == 1);
std::string pause_print_msg;
int m600_extruder_before_layer = -1;
if (color_change && custom_gcode->extruder > 0)
m600_extruder_before_layer = custom_gcode->extruder - 1;
else if (gcode_type == CustomGCode::PausePrint)
pause_print_msg = custom_gcode->extra;
// we should add or not colorprint_change in respect to nozzle_diameter count instead of really used extruders count
if (color_change || tool_change) {
gcode += emit_custom_color_change_gcode_per_print_z(gcodegen, custom_gcode, current_extruder_id, first_extruder_id, config);
} else {
if (gcode_type == CustomGCode::PausePrint) { // Pause print
const std::string pause_print_msg = custom_gcode.extra;
// we should add or not colorprint_change in respect to nozzle_diameter count instead of really used extruders count
if (color_change || tool_change)
{
assert(m600_extruder_before_layer >= 0);
// Color Change or Tool Change as Color Change.
// add tag for processor
gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Color_Change) + ",T" + std::to_string(m600_extruder_before_layer) + "," + custom_gcode->color + "\n";
gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Pause_Print) + "\n";
//! FIXME_in_fw show message during print pause
if (!pause_print_msg.empty())
gcode += "M117 " + pause_print_msg + "\n";
if (!single_extruder_printer && m600_extruder_before_layer >= 0 && first_extruder_id != (unsigned)m600_extruder_before_layer
// && !MMU1
) {
//! FIXME_in_fw show message during print pause
// FIXME: Why is pause_print_gcode here? Why is it supplied "color_change_extruder"? Why is that not
// passed to color_change_gcode below?
DynamicConfig cfg;
cfg.set_key_value("color_change_extruder", new ConfigOptionInt(m600_extruder_before_layer));
gcode += gcodegen.placeholder_parser_process("pause_print_gcode", config.pause_print_gcode, current_extruder_id, &cfg);
gcode += "\n";
gcode += "M117 Change filament for Extruder " + std::to_string(m600_extruder_before_layer) + "\n";
}
else {
gcode += gcodegen.placeholder_parser_process("color_change_gcode", config.color_change_gcode, current_extruder_id);
gcode += "\n";
//FIXME Tell G-code writer that M600 filled the extruder, thus the G-code writer shall reset the extruder to unretracted state after
// return from M600. Thus the G-code generated by the following line is ignored.
// see GH issue #6362
gcodegen.writer().unretract();
}
}
else {
if (gcode_type == CustomGCode::PausePrint) // Pause print
{
// add tag for processor
gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Pause_Print) + "\n";
//! FIXME_in_fw show message during print pause
if (!pause_print_msg.empty())
gcode += "M117 " + pause_print_msg + "\n";
gcode += gcodegen.placeholder_parser_process("pause_print_gcode", config.pause_print_gcode, current_extruder_id);
}
else {
// add tag for processor
gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Custom_Code) + "\n";
if (gcode_type == CustomGCode::Template) // Template Custom Gcode
gcode += gcodegen.placeholder_parser_process("template_custom_gcode", config.template_custom_gcode, current_extruder_id);
else // custom Gcode
gcode += custom_gcode->extra;
}
gcode += "\n";
DynamicConfig cfg;
cfg.set_key_value("color_change_extruder", new ConfigOptionInt(int(current_extruder_id)));
gcode += gcodegen.placeholder_parser_process("pause_print_gcode", config.pause_print_gcode, current_extruder_id, &cfg);
} else {
// add tag for processor
gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Custom_Code) + "\n";
if (gcode_type == CustomGCode::Template) // Template Custom Gcode
gcode += gcodegen.placeholder_parser_process("template_custom_gcode", config.template_custom_gcode, current_extruder_id);
else // custom Gcode
gcode += custom_gcode.extra;
}
gcode += "\n";
}
return gcode;
@ -2247,16 +2255,6 @@ LayerResult GCodeGenerator::process_layer(
// Map from extruder ID to <begin, end> index of skirt loops to be extruded with that extruder.
std::map<unsigned int, std::pair<size_t, size_t>> skirt_loops_per_extruder;
if (single_object_instance_idx == size_t(-1)) {
// Normal (non-sequential) print.
std::string custom_gcode = ProcessLayer::emit_custom_gcode_per_print_z(*this, layer_tools.custom_gcode, m_writer.extruder()->id(), first_extruder_id, print.config());
if (layer_tools.custom_gcode != nullptr && layer_tools.custom_gcode->type == CustomGCode::ColorChange) {
// We have a color change to do on this layer, but we want to do it immediately before the first extrusion instead of now, in order to fix GH #2672
m_pending_pre_extrusion_gcode = custom_gcode;
} else {
gcode += custom_gcode;
}
}
// Extrude skirt at the print_z of the raft layers and normal object layers
// not at the print_z of the interlaced support material layers.
skirt_loops_per_extruder = first_layer ?
@ -2275,6 +2273,23 @@ LayerResult GCodeGenerator::process_layer(
}
}
const bool has_custom_gcode_to_emit = single_object_instance_idx == size_t(-1) && layer_tools.custom_gcode != nullptr;
const int extruder_id_for_custom_gcode = int(layer_tools.extruder_needed_for_color_changer) - 1;
if (has_custom_gcode_to_emit && extruder_id_for_custom_gcode == -1) {
// Normal (non-sequential) print with some custom code without picking a specific extruder before it.
// If we don't need to pick a specific extruder before the color change, we can just emit a custom g-code.
// Otherwise, we will emit the g-code after picking the specific extruder.
std::string custom_gcode = ProcessLayer::emit_custom_gcode_per_print_z(*this, *layer_tools.custom_gcode, m_writer.extruder()->id(), first_extruder_id, print.config());
if (layer_tools.custom_gcode->type == CustomGCode::ColorChange) {
// We have a color change to do on this layer, but we want to do it immediately before the first extrusion instead of now, in order to fix GH #2672.
m_pending_pre_extrusion_gcode = custom_gcode;
} else {
gcode += custom_gcode;
}
}
// Extrude the skirt, brim, support, perimeters, infill ordered by the extruders.
for (unsigned int extruder_id : layer_tools.extruders)
{
@ -2286,6 +2301,13 @@ LayerResult GCodeGenerator::process_layer(
if (layer_tools.has_wipe_tower && m_wipe_tower)
m_last_processor_extrusion_role = GCodeExtrusionRole::WipeTower;
if (has_custom_gcode_to_emit && extruder_id_for_custom_gcode == int(extruder_id)) {
assert(m_writer.extruder()->id() == extruder_id_for_custom_gcode);
assert(m_pending_pre_extrusion_gcode.empty());
// Now we have picked the right extruder, so we can emit the custom g-code.
gcode += ProcessLayer::emit_custom_gcode_per_print_z(*this, *layer_tools.custom_gcode, m_writer.extruder()->id(), first_extruder_id, print.config());
}
if (auto loops_it = skirt_loops_per_extruder.find(extruder_id); loops_it != skirt_loops_per_extruder.end()) {
const std::pair<size_t, size_t> loops = loops_it->second;
this->set_origin(0., 0.);

View File

@ -110,7 +110,7 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude
double max_layer_height = calc_max_layer_height(object.print()->config(), object.config().layer_height);
// Collect extruders required to print the layers.
this->collect_extruders(object, std::vector<std::pair<double, unsigned int>>());
this->collect_extruders(object, std::vector<std::pair<double, unsigned int>>(), std::vector<std::pair<double, unsigned int>>());
// Reorder the extruders to minimize tool switches.
this->reorder_extruders(first_extruder);
@ -156,17 +156,24 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool
// Use the extruder switches from Model::custom_gcode_per_print_z to override the extruder to print the object.
// Do it only if all the objects were configured to be printed with a single extruder.
std::vector<std::pair<double, unsigned int>> per_layer_extruder_switches;
if (auto num_extruders = unsigned(print.config().nozzle_diameter.size());
num_extruders > 1 && print.object_extruders().size() == 1 && // the current Print's configuration is CustomGCode::MultiAsSingle
auto num_extruders = unsigned(print.config().nozzle_diameter.size());
if (num_extruders > 1 && print.object_extruders().size() == 1 && // the current Print's configuration is CustomGCode::MultiAsSingle
print.model().custom_gcode_per_print_z.mode == CustomGCode::MultiAsSingle) {
// Printing a single extruder platter on a printer with more than 1 extruder (or single-extruder multi-material).
// There may be custom per-layer tool changes available at the model.
per_layer_extruder_switches = custom_tool_changes(print.model().custom_gcode_per_print_z, num_extruders);
}
// Collect extruders reuqired to print the layers.
// Color changes for each layer to determine which extruder needs to be picked before color change.
// This is done just for multi-extruder printers without enabled Single Extruder Multi Material (tool changer printers).
std::vector<std::pair<double, unsigned int>> per_layer_color_changes;
if (num_extruders > 1 && print.model().custom_gcode_per_print_z.mode == CustomGCode::MultiExtruder && !print.config().single_extruder_multi_material) {
per_layer_color_changes = custom_color_changes(print.model().custom_gcode_per_print_z, num_extruders);
}
// Collect extruders required to print the layers.
for (auto object : print.objects())
this->collect_extruders(*object, per_layer_extruder_switches);
this->collect_extruders(*object, per_layer_extruder_switches, per_layer_color_changes);
// Reorder the extruders to minimize tool switches.
this->reorder_extruders(first_extruder);
@ -219,8 +226,11 @@ void ToolOrdering::initialize_layers(std::vector<coordf_t> &zs)
}
// Collect extruders reuqired to print layers.
void ToolOrdering::collect_extruders(const PrintObject &object, const std::vector<std::pair<double, unsigned int>> &per_layer_extruder_switches)
{
void ToolOrdering::collect_extruders(
const PrintObject &object,
const std::vector<std::pair<double, unsigned int>> &per_layer_extruder_switches,
const std::vector<std::pair<double, unsigned int>> &per_layer_color_changes
) {
// Collect the support extruders.
for (auto support_layer : object.support_layers()) {
LayerTools &layer_tools = this->tools_for_layer(support_layer->print_z);
@ -238,10 +248,11 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
}
// Extruder overrides are ordered by print_z.
std::vector<std::pair<double, unsigned int>>::const_iterator it_per_layer_extruder_override;
it_per_layer_extruder_override = per_layer_extruder_switches.begin();
std::vector<std::pair<double, unsigned int>>::const_iterator it_per_layer_extruder_override = per_layer_extruder_switches.begin();
unsigned int extruder_override = 0;
std::vector<std::pair<double, unsigned int>>::const_iterator it_per_layer_color_changes = per_layer_color_changes.begin();
// Collect the object extruders.
for (auto layer : object.layers()) {
LayerTools &layer_tools = this->tools_for_layer(layer->print_z);
@ -253,6 +264,15 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
// Store the current extruder override (set to zero if no overriden), so that layer_tools.wiping_extrusions().is_overridable_and_mark() will use it.
layer_tools.extruder_override = extruder_override;
// Append the extruder needed to be picked before performing the color change.
for (; it_per_layer_color_changes != per_layer_color_changes.end() && it_per_layer_color_changes->first < layer->print_z + EPSILON; ++it_per_layer_color_changes) {
if (std::abs(it_per_layer_color_changes->first - layer->print_z) < EPSILON) {
assert(layer_tools.extruder_needed_for_color_changer == 0); // Just on color change per layer is allowed.
layer_tools.extruder_needed_for_color_changer = it_per_layer_color_changes->second;
layer_tools.extruders.emplace_back(it_per_layer_color_changes->second);
}
}
// What extruders are required to print this object layer?
for (const LayerRegion *layerm : layer->regions()) {
const PrintRegion &region = layerm->region();
@ -370,6 +390,11 @@ void ToolOrdering::reorder_extruders(unsigned int last_extruder_id)
std::swap(lt.extruders[i], lt.extruders.front());
break;
}
} else if (lt.extruder_needed_for_color_changer != 0) {
// Put the extruder needed for performing the color change at the beginning.
auto it = std::find(lt.extruders.begin(), lt.extruders.end(), lt.extruder_needed_for_color_changer);
assert(it != lt.extruders.end());
std::rotate(lt.extruders.begin(), it, it + 1);
}
}
last_extruder_id = lt.extruders.back();

View File

@ -98,6 +98,9 @@ public:
// If per layer extruder switches are inserted by the G-code preview slider, this value contains the new (1 based) extruder, with which the whole object layer is being printed with.
// If not overriden, it is set to 0.
unsigned int extruder_override = 0;
// For multi-extruder printers, when there is a color change, this contains an extruder (1 based) on which the color change will be performed.
// Otherwise, it is set to 0.
unsigned int extruder_needed_for_color_changer = 0;
// Should a skirt be printed at this layer?
// Layers are marked for infinite skirt aka draft shield. Not all the layers have to be printed.
bool has_skirt = false;
@ -169,7 +172,7 @@ public:
private:
void initialize_layers(std::vector<coordf_t> &zs);
void collect_extruders(const PrintObject &object, const std::vector<std::pair<double, unsigned int>> &per_layer_extruder_switches);
void collect_extruders(const PrintObject &object, const std::vector<std::pair<double, unsigned int>> &per_layer_extruder_switches, const std::vector<std::pair<double, unsigned int>> &per_layer_color_changes);
void reorder_extruders(unsigned int last_extruder_id);
void fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z, coordf_t max_layer_height);
bool insert_wipe_tower_extruder();

View File

@ -1,7 +1,7 @@
///|/ Copyright (c) Prusa Research 2021 - 2023 Enrico Turri @enricoturri1966, Vojtěch Bubník @bubnikv, Pavel Mikuš @Godrak, Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, Lukáš Hejl @hejllukas, Roman Beránek @zavorka
///|/
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
///|/
///|/ Copyright (c) Prusa Research 2021 - 2023 Enrico Turri @enricoturri1966, Vojtěch Bubník @bubnikv, Pavel Mikuš @Godrak, Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, Lukáš Hejl @hejllukas, Roman Beránek @zavorka
///|/
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
///|/
#include "Model.hpp"
#include "Print.hpp"
@ -169,34 +169,37 @@ static bool layer_height_ranges_equal(const t_layer_config_ranges &lr1, const t_
return true;
}
// Returns true if va == vb when all CustomGCode items that are not ToolChangeCode are ignored.
static bool custom_per_printz_gcodes_tool_changes_differ(const std::vector<CustomGCode::Item> &va, const std::vector<CustomGCode::Item> &vb)
{
// Returns true if va == vb when all CustomGCode items that are not the specified type (not_ignore_type) are ignored.
static bool custom_per_printz_gcodes_tool_changes_differ(
const std::vector<CustomGCode::Item> &va,
const std::vector<CustomGCode::Item> &vb,
CustomGCode::Type not_ignore_type
) {
auto it_a = va.begin();
auto it_b = vb.begin();
while (it_a != va.end() || it_b != vb.end()) {
if (it_a != va.end() && it_a->type != CustomGCode::ToolChange) {
// Skip any CustomGCode items, which are not tool changes.
if (it_a != va.end() && it_a->type != not_ignore_type) {
// Skip any CustomGCode items, which are not equal to not_ignore_type.
++ it_a;
continue;
}
if (it_b != vb.end() && it_b->type != CustomGCode::ToolChange) {
// Skip any CustomGCode items, which are not tool changes.
if (it_b != vb.end() && it_b->type != not_ignore_type) {
// Skip any CustomGCode items, which are not equal to not_ignore_type.
++ it_b;
continue;
}
if (it_a == va.end() || it_b == vb.end())
// va or vb contains more Tool Changes than the other.
// va or vb contains more items of not_ignore_type than the other.
return true;
assert(it_a->type == CustomGCode::ToolChange);
assert(it_b->type == CustomGCode::ToolChange);
assert(it_a->type == not_ignore_type);
assert(it_b->type == not_ignore_type);
if (*it_a != *it_b)
// The two Tool Changes differ.
// The two items of not_ignore_type differ.
return true;
++ it_a;
++ it_b;
}
// There is no change in custom Tool Changes.
// There is no change in specified not_ignore_type items.
return false;
}
@ -1059,11 +1062,20 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
model_object_status_db.add(*model_object, ModelObjectStatus::New);
} else {
if (m_model.custom_gcode_per_print_z != model.custom_gcode_per_print_z) {
update_apply_status(num_extruders_changed ||
// Tool change G-codes are applied as color changes for a single extruder printer, no need to invalidate tool ordering.
//FIXME The tool ordering may be invalidated unnecessarily if the custom_gcode_per_print_z.mode is not applicable
// to the active print / model state, and then it is reset, so it is being applicable, but empty, thus the effect is the same.
(num_extruders > 1 && custom_per_printz_gcodes_tool_changes_differ(m_model.custom_gcode_per_print_z.gcodes, model.custom_gcode_per_print_z.gcodes)) ?
const CustomGCode::Mode current_mode = m_model.custom_gcode_per_print_z.mode;
const CustomGCode::Mode next_mode = model.custom_gcode_per_print_z.mode;
const bool multi_extruder_differ = (current_mode == next_mode) && (current_mode == CustomGCode::MultiExtruder || next_mode == CustomGCode::MultiExtruder);
// Tool change G-codes are applied as color changes for a single extruder printer, no need to invalidate tool ordering.
// FIXME The tool ordering may be invalidated unnecessarily if the custom_gcode_per_print_z.mode is not applicable
// to the active print / model state, and then it is reset, so it is being applicable, but empty, thus the effect is the same.
const bool tool_change_differ = num_extruders > 1 && custom_per_printz_gcodes_tool_changes_differ(m_model.custom_gcode_per_print_z.gcodes, model.custom_gcode_per_print_z.gcodes, CustomGCode::ToolChange);
// For multi-extruder printers, we perform a tool change before a color change.
// So, in that case, we must invalidate tool ordering and wipe tower even if custom color change g-codes differ.
const bool color_change_differ = num_extruders > 1 && (next_mode == CustomGCode::MultiExtruder) && custom_per_printz_gcodes_tool_changes_differ(m_model.custom_gcode_per_print_z.gcodes, model.custom_gcode_per_print_z.gcodes, CustomGCode::ColorChange);
update_apply_status(
(num_extruders_changed || tool_change_differ || multi_extruder_differ || color_change_differ) ?
// The Tool Ordering and the Wipe Tower are no more valid.
this->invalidate_steps({ psWipeTower, psGCodeExport }) :
// There is no change in Tool Changes stored in custom_gcode_per_print_z, therefore there is no need to update Tool Ordering.

View File

@ -5397,6 +5397,8 @@ static std::map<t_custom_gcode_key, t_config_option_keys> s_CustomGcodeSpecificP
{"before_layer_gcode", {"layer_num", "layer_z", "max_layer_z"}},
{"layer_gcode", {"layer_num", "layer_z", "max_layer_z"}},
{"toolchange_gcode", {"layer_num", "layer_z", "max_layer_z", "previous_extruder", "next_extruder", "toolchange_z"}},
{"color_change_gcode", {"color_change_extruder"}},
{"pause_print_gcode", {"color_change_extruder"}},
};
const std::map<t_custom_gcode_key, t_config_option_keys>& custom_gcode_specific_placeholders()
@ -5435,6 +5437,10 @@ CustomGcodeSpecificConfigDef::CustomGcodeSpecificConfigDef()
def = this->add("toolchange_z", coFloat);
def->label = L("Toolchange Z");
def->tooltip = L("Height above the print bed when the toolchange takes place. Usually the same as layer_z, but can be different.");
def = this->add("color_change_extruder", coInt);
def->label = L("Color change extruder");
def->tooltip = L("Index of the extruder for which color change will be performed. The index is zero based (first extruder has index 0).");
}
const CustomGcodeSpecificConfigDef custom_gcode_specific_config_def;