mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-11-02 20:51:23 -07:00 
			
		
		
		
	Fixes of G-code multi-tool ordering.
This commit is contained in:
		
							parent
							
								
									c22b6edeeb
								
							
						
					
					
						commit
						21be680ac2
					
				
					 3 changed files with 106 additions and 45 deletions
				
			
		| 
						 | 
				
			
			@ -292,9 +292,29 @@ bool GCode::do_export(FILE *file, Print &print)
 | 
			
		|||
        boost::ifind_first(print.config.start_gcode.value, std::string("M140")).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));
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    // 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.
 | 
			
		||||
    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());
 | 
			
		||||
    this->_print_first_layer_extruder_temperatures(file, print, true);
 | 
			
		||||
    
 | 
			
		||||
| 
						 | 
				
			
			@ -355,8 +375,8 @@ bool GCode::do_export(FILE *file, Print &print)
 | 
			
		|||
    }
 | 
			
		||||
    
 | 
			
		||||
    // 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.
 | 
			
		||||
    if (print.config.complete_objects.value) {
 | 
			
		||||
        // Print objects from the smallest to the tallest to avoid collisions
 | 
			
		||||
| 
						 | 
				
			
			@ -364,8 +384,19 @@ bool GCode::do_export(FILE *file, Print &print)
 | 
			
		|||
        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; });        
 | 
			
		||||
        size_t finished_objects = 0;
 | 
			
		||||
        for (PrintObject *object : objects) {
 | 
			
		||||
            for (const Point © : object->_shifted_copies) {
 | 
			
		||||
        for (size_t object_id = initial_print_object_id; object_id < objects.size(); ++ object_id) {
 | 
			
		||||
            const PrintObject &object = *print.objects[object_id];
 | 
			
		||||
            for (const Point © : object._shifted_copies) {
 | 
			
		||||
                // Get optimal tool ordering to minimize tool switches of a multi-exruder print.
 | 
			
		||||
                if (object_id != initial_print_object_id || © != 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));
 | 
			
		||||
                if (finished_objects > 0) {
 | 
			
		||||
                    // 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.
 | 
			
		||||
                    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.
 | 
			
		||||
                size_t idx_object_layer  = 0;
 | 
			
		||||
                size_t idx_support_layer = 0;
 | 
			
		||||
                std::vector<LayerToPrint> layers_to_print(1, LayerToPrint());
 | 
			
		||||
                LayerToPrint &layer_to_print = layers_to_print.front();
 | 
			
		||||
                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.support_layer = (idx_support_layer < object->support_layers.size()) ? object->support_layers[idx_support_layer ++] : nullptr;
 | 
			
		||||
                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.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->print_z < layer_to_print.support_layer->print_z) {
 | 
			
		||||
                            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));
 | 
			
		||||
                    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, © - object->_shifted_copies.data());
 | 
			
		||||
                    this->process_layer(file, print, layers_to_print, *it_layer_tools, © - object._shifted_copies.data());
 | 
			
		||||
                }
 | 
			
		||||
                write(file, this->filter(m_cooling_buffer->flush(), true));
 | 
			
		||||
                ++ finished_objects;
 | 
			
		||||
| 
						 | 
				
			
			@ -442,8 +471,6 @@ bool GCode::do_export(FILE *file, Print &print)
 | 
			
		|||
            }
 | 
			
		||||
            ++ 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.
 | 
			
		||||
        if (print.config.single_extruder_multi_material.value && print.config.wipe_tower.value && 
 | 
			
		||||
            ! tool_ordering.empty() && tool_ordering.front().wipe_tower_partitions > 0) {
 | 
			
		||||
| 
						 | 
				
			
			@ -596,9 +623,14 @@ void GCode::process_layer(
 | 
			
		|||
    const size_t                     single_object_idx)
 | 
			
		||||
{
 | 
			
		||||
    assert(! layers.empty());
 | 
			
		||||
    assert(! layer_tools.extruders.empty());
 | 
			
		||||
    // 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);
 | 
			
		||||
 | 
			
		||||
    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.
 | 
			
		||||
    const Layer         *object_layer  = nullptr;
 | 
			
		||||
    const SupportLayer  *support_layer = nullptr;
 | 
			
		||||
| 
						 | 
				
			
			@ -666,11 +698,10 @@ void GCode::process_layer(
 | 
			
		|||
        gcode += pp.process(print.config.layer_gcode.value) + "\n";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (! m_brim_done)
 | 
			
		||||
        // Switch the extruder to the extruder of the perimeters, so the perimeters extruder will be primed
 | 
			
		||||
        // by the skirt before the brim is extruded with the same extruder.
 | 
			
		||||
        gcode += this->set_extruder(layer_tools.extruders.front());
 | 
			
		||||
    
 | 
			
		||||
    if (m_wipe_tower && ! m_wipe_tower->finished() && layer.id() == 0 && m_writer.extruder()->id == layer_tools.extruders.front())
 | 
			
		||||
        // Trigger the tool change explicitely to draw the wipe tower brim always.
 | 
			
		||||
        gcode += this->wipe_tower_tool_change(layer_tools.extruders.front());
 | 
			
		||||
 | 
			
		||||
    // 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.
 | 
			
		||||
    bool extrude_skirt = 
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -64,23 +64,29 @@ static void collect_extruders(const PrintObject &object, std::vector<LayerTools>
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// 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())
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    // Initialize the last_extruder_id with the first non-zero extruder id used for the print.
 | 
			
		||||
    unsigned int last_extruder_id = 0;
 | 
			
		||||
    for (size_t i = 0; i < layers.size() && last_extruder_id == 0; ++ i) {
 | 
			
		||||
        const LayerTools < = layers[i];
 | 
			
		||||
        for (unsigned int extruder_id : lt.extruders)
 | 
			
		||||
            if (extruder_id > 0) {
 | 
			
		||||
                last_extruder_id = extruder_id;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
    }
 | 
			
		||||
    if (last_extruder_id == 0)
 | 
			
		||||
        last_extruder_id = 1;
 | 
			
		||||
    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.
 | 
			
		||||
        last_extruder_id = 0;
 | 
			
		||||
        for (size_t i = 0; i < layers.size() && last_extruder_id == 0; ++ i) {
 | 
			
		||||
            const LayerTools < = layers[i];
 | 
			
		||||
            for (unsigned int extruder_id : lt.extruders)
 | 
			
		||||
                if (extruder_id > 0) {
 | 
			
		||||
                    last_extruder_id = extruder_id;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
        }
 | 
			
		||||
        if (last_extruder_id == 0)
 | 
			
		||||
            // Nothing to extrude.
 | 
			
		||||
            return;
 | 
			
		||||
    } else
 | 
			
		||||
        // 1 based index
 | 
			
		||||
        ++ last_extruder_id;
 | 
			
		||||
 | 
			
		||||
    for (LayerTools < : layers) {
 | 
			
		||||
        if (lt.extruders.empty())
 | 
			
		||||
| 
						 | 
				
			
			@ -117,14 +123,16 @@ static void fill_wipe_tower_partitions(std::vector<LayerTools> &layers)
 | 
			
		|||
        return;
 | 
			
		||||
 | 
			
		||||
    // Count the minimum number of tool changes per layer.
 | 
			
		||||
    for (LayerTools < : layers)
 | 
			
		||||
        lt.wipe_tower_partitions = std::max<int>(0, int(layers.front().extruders.size()) - 1);
 | 
			
		||||
 | 
			
		||||
    // 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.
 | 
			
		||||
    //FIXME this does not minimize the number of tool changes in worst case.
 | 
			
		||||
    for (size_t i = 1; i < layers.size(); ++ i)
 | 
			
		||||
        if (layers[i-1].extruders.back() != layers[i].extruders.front())
 | 
			
		||||
            ++ layers[i].wipe_tower_partitions;
 | 
			
		||||
    size_t last_extruder = size_t(-1);
 | 
			
		||||
    for (LayerTools < : layers) {
 | 
			
		||||
        lt.wipe_tower_partitions = layers.front().extruders.size();
 | 
			
		||||
        if (! lt.extruders.empty()) {
 | 
			
		||||
            if (last_extruder == size_t(-1) || last_extruder == lt.extruders.front())
 | 
			
		||||
                // The first extruder on this layer is equal to the current one, no need to do an initial tool change.
 | 
			
		||||
                -- lt.wipe_tower_partitions;
 | 
			
		||||
            last_extruder = lt.extruders.back();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 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)
 | 
			
		||||
| 
						 | 
				
			
			@ -133,7 +141,7 @@ static void fill_wipe_tower_partitions(std::vector<LayerTools> &layers)
 | 
			
		|||
 | 
			
		||||
// For the use case when each object is printed separately
 | 
			
		||||
// (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.
 | 
			
		||||
    std::vector<LayerTools> layers;
 | 
			
		||||
| 
						 | 
				
			
			@ -153,7 +161,7 @@ std::vector<LayerTools> tool_ordering(PrintObject &object)
 | 
			
		|||
    collect_extruders(object, layers);
 | 
			
		||||
 | 
			
		||||
    // Reorder the extruders to minimize tool switches.
 | 
			
		||||
    reorder_extruders(layers);
 | 
			
		||||
    reorder_extruders(layers, first_extruder);
 | 
			
		||||
 | 
			
		||||
    fill_wipe_tower_partitions(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.
 | 
			
		||||
// (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. 
 | 
			
		||||
    std::vector<LayerTools> layers;
 | 
			
		||||
| 
						 | 
				
			
			@ -184,11 +192,27 @@ std::vector<LayerTools> tool_ordering(const Print &print)
 | 
			
		|||
        collect_extruders(*object, layers);
 | 
			
		||||
 | 
			
		||||
    // Reorder the extruders to minimize tool switches.
 | 
			
		||||
    reorder_extruders(layers);
 | 
			
		||||
    reorder_extruders(layers, first_extruder);
 | 
			
		||||
 | 
			
		||||
    fill_wipe_tower_partitions(layers);
 | 
			
		||||
    return layers;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned int first_extruder(const std::vector<LayerTools> &layer_tools)
 | 
			
		||||
{
 | 
			
		||||
    for (const auto < : 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 Slic3r
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,11 +26,17 @@ struct LayerTools
 | 
			
		|||
 | 
			
		||||
// For the use case when each object is printed separately
 | 
			
		||||
// (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.
 | 
			
		||||
// (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 SLic3r
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue