Fixes of G-code multi-tool ordering.

This commit is contained in:
bubnikv 2017-05-16 15:30:03 +02:00
parent c22b6edeeb
commit 21be680ac2
3 changed files with 106 additions and 45 deletions

View file

@ -293,8 +293,28 @@ bool GCode::do_export(FILE *file, Print &print)
boost::ifind_first(print.config.start_gcode.value, std::string("M190")).empty()) boost::ifind_first(print.config.start_gcode.value, std::string("M190")).empty())
write(file, m_writer.set_bed_temperature(print.config.first_layer_bed_temperature.value, true)); write(file, m_writer.set_bed_temperature(print.config.first_layer_bed_temperature.value, true));
// Get optimal tool ordering to minimize tool switches of a multi-exruder print.
// For a print by objects, find the 1st printing object.
std::vector<ToolOrdering::LayerTools> tool_ordering;
unsigned int initial_extruder_id = (unsigned int)-1;
size_t initial_print_object_id = 0;
if (print.config.complete_objects.value) {
tool_ordering = ToolOrdering::tool_ordering(print, initial_extruder_id);
initial_extruder_id = ToolOrdering::first_extruder(tool_ordering);
} else {
for (; initial_print_object_id < print.objects.size() && initial_extruder_id == (unsigned int)-1; ++ initial_print_object_id) {
tool_ordering = ToolOrdering::tool_ordering(*print.objects[initial_print_object_id], initial_extruder_id);
initial_extruder_id = ToolOrdering::first_extruder(tool_ordering);
}
}
if (initial_extruder_id == (unsigned int)-1)
// Nothing to print!
initial_extruder_id = 0;
// Set extruder(s) temperature before and after start G-code. // Set extruder(s) temperature before and after start G-code.
this->_print_first_layer_extruder_temperatures(file, print, false); this->_print_first_layer_extruder_temperatures(file, print, false);
// Let the start-up script prime the 1st printing tool.
m_placeholder_parser.set("initial_tool", initial_extruder_id);
fprintf(file, "%s\n", m_placeholder_parser.process(print.config.start_gcode.value).c_str()); fprintf(file, "%s\n", m_placeholder_parser.process(print.config.start_gcode.value).c_str());
this->_print_first_layer_extruder_temperatures(file, print, true); this->_print_first_layer_extruder_temperatures(file, print, true);
@ -355,7 +375,7 @@ bool GCode::do_export(FILE *file, Print &print)
} }
// Set initial extruder only after custom start G-code. // Set initial extruder only after custom start G-code.
write(file, this->set_extruder(print.extruders().front())); write(file, this->set_extruder(initial_extruder_id));
// Do all objects for each layer. // Do all objects for each layer.
if (print.config.complete_objects.value) { if (print.config.complete_objects.value) {
@ -364,8 +384,19 @@ bool GCode::do_export(FILE *file, Print &print)
std::vector<PrintObject*> objects(print.objects); std::vector<PrintObject*> objects(print.objects);
std::sort(objects.begin(), objects.end(), [](const PrintObject* po1, const PrintObject* po2) { return po1->size.z < po2->size.z; }); std::sort(objects.begin(), objects.end(), [](const PrintObject* po1, const PrintObject* po2) { return po1->size.z < po2->size.z; });
size_t finished_objects = 0; size_t finished_objects = 0;
for (PrintObject *object : objects) { for (size_t object_id = initial_print_object_id; object_id < objects.size(); ++ object_id) {
for (const Point &copy : object->_shifted_copies) { const PrintObject &object = *print.objects[object_id];
for (const Point &copy : object._shifted_copies) {
// Get optimal tool ordering to minimize tool switches of a multi-exruder print.
if (object_id != initial_print_object_id || &copy != object._shifted_copies.data()) {
// Don't initialize for the first object and first copy.
tool_ordering = ToolOrdering::tool_ordering(object, initial_extruder_id);
unsigned int new_extruder_id = ToolOrdering::first_extruder(tool_ordering);
if (new_extruder_id == (unsigned int)-1)
// Skip this object.
continue;
initial_extruder_id = new_extruder_id;
}
this->set_origin(unscale(copy.x), unscale(copy.y)); this->set_origin(unscale(copy.x), unscale(copy.y));
if (finished_objects > 0) { if (finished_objects > 0) {
// Move to the origin position for the copy we're going to print. // Move to the origin position for the copy we're going to print.
@ -385,16 +416,14 @@ bool GCode::do_export(FILE *file, Print &print)
// Set first layer extruder. // Set first layer extruder.
this->_print_first_layer_extruder_temperatures(file, print, false); this->_print_first_layer_extruder_temperatures(file, print, false);
} }
// Get optimal tool ordering to minimize tool switches of a multi-exruder print.
std::vector<ToolOrdering::LayerTools> tool_ordering = ToolOrdering::tool_ordering(*object);
// Pair the object layers with the support layers by z, extrude them. // Pair the object layers with the support layers by z, extrude them.
size_t idx_object_layer = 0; size_t idx_object_layer = 0;
size_t idx_support_layer = 0; size_t idx_support_layer = 0;
std::vector<LayerToPrint> layers_to_print(1, LayerToPrint()); std::vector<LayerToPrint> layers_to_print(1, LayerToPrint());
LayerToPrint &layer_to_print = layers_to_print.front(); LayerToPrint &layer_to_print = layers_to_print.front();
while (idx_object_layer < object->layers.size() || idx_support_layer < object->support_layers.size()) { while (idx_object_layer < object.layers.size() || idx_support_layer < object.support_layers.size()) {
layer_to_print.object_layer = (idx_object_layer < object->layers.size()) ? object->layers[idx_object_layer ++] : nullptr; layer_to_print.object_layer = (idx_object_layer < object.layers.size()) ? object.layers[idx_object_layer ++] : nullptr;
layer_to_print.support_layer = (idx_support_layer < object->support_layers.size()) ? object->support_layers[idx_support_layer ++] : nullptr; layer_to_print.support_layer = (idx_support_layer < object.support_layers.size()) ? object.support_layers[idx_support_layer ++] : nullptr;
if (layer_to_print.object_layer && layer_to_print.support_layer) { if (layer_to_print.object_layer && layer_to_print.support_layer) {
if (layer_to_print.object_layer->print_z < layer_to_print.support_layer->print_z) { if (layer_to_print.object_layer->print_z < layer_to_print.support_layer->print_z) {
layer_to_print.support_layer = nullptr; layer_to_print.support_layer = nullptr;
@ -406,7 +435,7 @@ bool GCode::do_export(FILE *file, Print &print)
} }
auto it_layer_tools = std::lower_bound(tool_ordering.begin(), tool_ordering.end(), ToolOrdering::LayerTools(layer_to_print.layer()->print_z)); auto it_layer_tools = std::lower_bound(tool_ordering.begin(), tool_ordering.end(), ToolOrdering::LayerTools(layer_to_print.layer()->print_z));
assert(it_layer_tools != tool_ordering.end() && it_layer_tools->print_z == layer_to_print.layer()->print_z); assert(it_layer_tools != tool_ordering.end() && it_layer_tools->print_z == layer_to_print.layer()->print_z);
this->process_layer(file, print, layers_to_print, *it_layer_tools, &copy - object->_shifted_copies.data()); this->process_layer(file, print, layers_to_print, *it_layer_tools, &copy - object._shifted_copies.data());
} }
write(file, this->filter(m_cooling_buffer->flush(), true)); write(file, this->filter(m_cooling_buffer->flush(), true));
++ finished_objects; ++ finished_objects;
@ -442,8 +471,6 @@ bool GCode::do_export(FILE *file, Print &print)
} }
++ object_order; ++ object_order;
} }
// Get optimal tool ordering to minimize tool switches of a multi-exruder print.
std::vector<ToolOrdering::LayerTools> tool_ordering = ToolOrdering::tool_ordering(print);
// Prusa Multi-Material wipe tower. // Prusa Multi-Material wipe tower.
if (print.config.single_extruder_multi_material.value && print.config.wipe_tower.value && if (print.config.single_extruder_multi_material.value && print.config.wipe_tower.value &&
! tool_ordering.empty() && tool_ordering.front().wipe_tower_partitions > 0) { ! tool_ordering.empty() && tool_ordering.front().wipe_tower_partitions > 0) {
@ -596,9 +623,14 @@ void GCode::process_layer(
const size_t single_object_idx) const size_t single_object_idx)
{ {
assert(! layers.empty()); assert(! layers.empty());
assert(! layer_tools.extruders.empty());
// Either printing all copies of all objects, or just a single copy of a single object. // Either printing all copies of all objects, or just a single copy of a single object.
assert(single_object_idx == size_t(-1) || layers.size() == 1); assert(single_object_idx == size_t(-1) || layers.size() == 1);
if (layer_tools.extruders.empty())
// Nothing to extrude.
return;
// Extract 1st object_layer and support_layer of this set of layers with an equal print_z. // Extract 1st object_layer and support_layer of this set of layers with an equal print_z.
const Layer *object_layer = nullptr; const Layer *object_layer = nullptr;
const SupportLayer *support_layer = nullptr; const SupportLayer *support_layer = nullptr;
@ -666,10 +698,9 @@ void GCode::process_layer(
gcode += pp.process(print.config.layer_gcode.value) + "\n"; gcode += pp.process(print.config.layer_gcode.value) + "\n";
} }
if (! m_brim_done) if (m_wipe_tower && ! m_wipe_tower->finished() && layer.id() == 0 && m_writer.extruder()->id == layer_tools.extruders.front())
// Switch the extruder to the extruder of the perimeters, so the perimeters extruder will be primed // Trigger the tool change explicitely to draw the wipe tower brim always.
// by the skirt before the brim is extruded with the same extruder. gcode += this->wipe_tower_tool_change(layer_tools.extruders.front());
gcode += this->set_extruder(layer_tools.extruders.front());
// Extrude skirt at the print_z of the raft layers and normal object layers // 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. // not at the print_z of the interlaced support material layers.

View file

@ -64,13 +64,15 @@ static void collect_extruders(const PrintObject &object, std::vector<LayerTools>
} }
// Reorder extruders to minimize layer changes. // Reorder extruders to minimize layer changes.
static void reorder_extruders(std::vector<LayerTools> &layers) static void reorder_extruders(std::vector<LayerTools> &layers, unsigned int last_extruder_id)
{ {
if (layers.empty()) if (layers.empty())
return; return;
if (last_extruder_id == (unsigned int)-1) {
// The initial print extruder has not been decided yet.
// Initialize the last_extruder_id with the first non-zero extruder id used for the print. // Initialize the last_extruder_id with the first non-zero extruder id used for the print.
unsigned int last_extruder_id = 0; last_extruder_id = 0;
for (size_t i = 0; i < layers.size() && last_extruder_id == 0; ++ i) { for (size_t i = 0; i < layers.size() && last_extruder_id == 0; ++ i) {
const LayerTools &lt = layers[i]; const LayerTools &lt = layers[i];
for (unsigned int extruder_id : lt.extruders) for (unsigned int extruder_id : lt.extruders)
@ -80,7 +82,11 @@ static void reorder_extruders(std::vector<LayerTools> &layers)
} }
} }
if (last_extruder_id == 0) if (last_extruder_id == 0)
last_extruder_id = 1; // Nothing to extrude.
return;
} else
// 1 based index
++ last_extruder_id;
for (LayerTools &lt : layers) { for (LayerTools &lt : layers) {
if (lt.extruders.empty()) if (lt.extruders.empty())
@ -117,14 +123,16 @@ static void fill_wipe_tower_partitions(std::vector<LayerTools> &layers)
return; return;
// Count the minimum number of tool changes per layer. // Count the minimum number of tool changes per layer.
for (LayerTools &lt : layers) size_t last_extruder = size_t(-1);
lt.wipe_tower_partitions = std::max<int>(0, int(layers.front().extruders.size()) - 1); for (LayerTools &lt : layers) {
lt.wipe_tower_partitions = layers.front().extruders.size();
// In case a distinct set of tools are used between two layers, there will be an additional tool change at the start of a layer. if (! lt.extruders.empty()) {
//FIXME this does not minimize the number of tool changes in worst case. if (last_extruder == size_t(-1) || last_extruder == lt.extruders.front())
for (size_t i = 1; i < layers.size(); ++ i) // The first extruder on this layer is equal to the current one, no need to do an initial tool change.
if (layers[i-1].extruders.back() != layers[i].extruders.front()) -- lt.wipe_tower_partitions;
++ layers[i].wipe_tower_partitions; last_extruder = lt.extruders.back();
}
}
// Propagate the wipe tower partitions down to support the upper partitions by the lower partitions. // Propagate the wipe tower partitions down to support the upper partitions by the lower partitions.
for (int i = int(layers.size()) - 2; i >= 0; -- i) for (int i = int(layers.size()) - 2; i >= 0; -- i)
@ -133,7 +141,7 @@ static void fill_wipe_tower_partitions(std::vector<LayerTools> &layers)
// For the use case when each object is printed separately // For the use case when each object is printed separately
// (print.config.complete_objects is true). // (print.config.complete_objects is true).
std::vector<LayerTools> tool_ordering(PrintObject &object) std::vector<LayerTools> tool_ordering(const PrintObject &object, unsigned int first_extruder)
{ {
// Initialize the print layers for just a single object. // Initialize the print layers for just a single object.
std::vector<LayerTools> layers; std::vector<LayerTools> layers;
@ -153,7 +161,7 @@ std::vector<LayerTools> tool_ordering(PrintObject &object)
collect_extruders(object, layers); collect_extruders(object, layers);
// Reorder the extruders to minimize tool switches. // Reorder the extruders to minimize tool switches.
reorder_extruders(layers); reorder_extruders(layers, first_extruder);
fill_wipe_tower_partitions(layers); fill_wipe_tower_partitions(layers);
return layers; return layers;
@ -161,7 +169,7 @@ std::vector<LayerTools> tool_ordering(PrintObject &object)
// For the use case when all objects are printed at once. // For the use case when all objects are printed at once.
// (print.config.complete_objects is false). // (print.config.complete_objects is false).
std::vector<LayerTools> tool_ordering(const Print &print) std::vector<LayerTools> tool_ordering(const Print &print, unsigned int first_extruder)
{ {
// Initialize the print layers for all objects and all layers. // Initialize the print layers for all objects and all layers.
std::vector<LayerTools> layers; std::vector<LayerTools> layers;
@ -184,11 +192,27 @@ std::vector<LayerTools> tool_ordering(const Print &print)
collect_extruders(*object, layers); collect_extruders(*object, layers);
// Reorder the extruders to minimize tool switches. // Reorder the extruders to minimize tool switches.
reorder_extruders(layers); reorder_extruders(layers, first_extruder);
fill_wipe_tower_partitions(layers); fill_wipe_tower_partitions(layers);
return layers; return layers;
} }
unsigned int first_extruder(const std::vector<LayerTools> &layer_tools)
{
for (const auto &lt : layer_tools)
if (! lt.extruders.empty())
return lt.extruders.front();
return (unsigned int)-1;
}
unsigned int last_extruder(const std::vector<LayerTools> &layer_tools)
{
for (auto lt_it = layer_tools.rend(); lt_it != layer_tools.rbegin(); ++ lt_it)
if (! lt_it->extruders.empty())
return lt_it->extruders.back();
return (unsigned int)-1;
}
} // namespace ToolOrdering } // namespace ToolOrdering
} // namespace Slic3r } // namespace Slic3r

View file

@ -26,11 +26,17 @@ struct LayerTools
// For the use case when each object is printed separately // For the use case when each object is printed separately
// (print.config.complete_objects is true). // (print.config.complete_objects is true).
extern std::vector<LayerTools> tool_ordering(PrintObject &object); extern std::vector<LayerTools> tool_ordering(const PrintObject &object, unsigned int first_extruder = (unsigned int)-1);
// For the use case when all objects are printed at once. // For the use case when all objects are printed at once.
// (print.config.complete_objects is false). // (print.config.complete_objects is false).
extern std::vector<LayerTools> tool_ordering(const Print &print); extern std::vector<LayerTools> tool_ordering(const Print &print, unsigned int first_extruder = (unsigned int)-1);
// Get the first extruder printing the layer_tools, returns -1 if there is no layer printed.
extern unsigned int first_extruder(const std::vector<LayerTools> &layer_tools);
// Get the first extruder printing the layer_tools, returns -1 if there is no layer printed.
extern unsigned int last_extruder(const std::vector<LayerTools> &layer_tools);
} // namespace ToolOrdering } // namespace ToolOrdering
} // namespace SLic3r } // namespace SLic3r