2017-05-16 13:45:28 +02:00
// Ordering of the tools to minimize tool switches.
#ifndef slic3r_ToolOrdering_hpp_
#define slic3r_ToolOrdering_hpp_
2018-11-26 14:54:23 +01:00
#include "../libslic3r.h"
2017-05-16 13:45:28 +02:00
2020-01-07 14:35:43 +01:00
#include <utility>
2020-01-08 14:58:12 +01:00
#include <boost/container/small_vector.hpp>
2017-05-16 13:45:28 +02:00
namespace Slic3r {
2017-05-25 22:27:53 +02:00
class Print ;
class PrintObject ;
2018-06-26 14:12:25 +02:00
class LayerTools ;
2020-05-26 11:09:38 +02:00
namespace CustomGCode { struct Item ; }
class PrintRegion ;
2018-06-26 14:12:25 +02:00
2017-05-25 22:27:53 +02:00
2018-06-20 12:52:00 +02:00
// Object of this class holds information about whether an extrusion is printed immediately
// after a toolchange (as part of infill/perimeter wiping) or not. One extrusion can be a part
// of several copies - this has to be taken into account.
class WipingExtrusions
{
2018-06-26 14:12:25 +02:00
public :
2018-06-20 12:52:00 +02:00
bool is_anything_overridden () const { // if there are no overrides, all the agenda can be skipped - this function can tell us if that's the case
return something_overridden ;
}
2020-01-08 14:58:12 +01:00
// When allocating extruder overrides of an object's ExtrusionEntity, overrides for maximum 3 copies are allocated in place.
typedef boost :: container :: small_vector < int32_t , 3 > ExtruderPerCopy ;
2018-06-26 14:12:25 +02:00
// This is called from GCode::process_layer - see implementation for further comments:
2020-01-08 14:58:12 +01:00
const ExtruderPerCopy * get_extruder_overrides ( const ExtrusionEntity * entity , int correct_extruder_id , size_t num_of_copies );
2018-06-26 14:12:25 +02:00
// This function goes through all infill entities, decides which ones will be used for wiping and
// marks them by the extruder id. Returns volume that remains to be wiped on the wipe tower:
2018-07-18 11:05:39 +02:00
float mark_wiping_extrusions ( const Print & print , unsigned int old_extruder , unsigned int new_extruder , float volume_to_wipe );
2018-06-26 14:12:25 +02:00
2018-07-11 14:46:13 +02:00
void ensure_perimeters_infills_order ( const Print & print );
2018-06-29 12:26:22 +02:00
2018-06-26 14:12:25 +02:00
bool is_overriddable ( const ExtrusionEntityCollection & ee , const PrintConfig & print_config , const PrintObject & object , const PrintRegion & region ) const ;
2020-01-10 11:26:52 +01:00
bool is_overriddable_and_mark ( const ExtrusionEntityCollection & ee , const PrintConfig & print_config , const PrintObject & object , const PrintRegion & region ) {
bool out = this -> is_overriddable ( ee , print_config , object , region );
this -> something_overridable |= out ;
return out ;
}
2018-06-26 14:12:25 +02:00
2018-07-11 14:46:13 +02:00
void set_layer_tools_ptr ( const LayerTools * lt ) { m_layer_tools = lt ; }
2018-06-26 14:12:25 +02:00
private :
2018-07-11 14:46:13 +02:00
int first_nonsoluble_extruder_on_layer ( const PrintConfig & print_config ) const ;
int last_nonsoluble_extruder_on_layer ( const PrintConfig & print_config ) const ;
2018-06-26 14:12:25 +02:00
// This function is called from mark_wiping_extrusions and sets extruder that it should be printed with (-1 .. as usual)
2020-01-14 10:31:18 +01:00
void set_extruder_override ( const ExtrusionEntity * entity , size_t copy_id , int extruder , size_t num_of_copies );
2018-06-26 14:12:25 +02:00
2018-06-20 12:52:00 +02:00
// Returns true in case that entity is not printed with its usual extruder for a given copy:
2019-09-04 14:56:35 +02:00
bool is_entity_overridden ( const ExtrusionEntity * entity , size_t copy_id ) const {
2020-01-10 11:26:52 +01:00
auto it = entity_map . find ( entity );
return it == entity_map . end () ? false : it -> second [ copy_id ] != - 1 ;
2018-06-20 12:52:00 +02:00
}
2020-01-08 14:58:12 +01:00
std :: map < const ExtrusionEntity * , ExtruderPerCopy > entity_map ; // to keep track of who prints what
2020-01-10 11:26:52 +01:00
bool something_overridable = false ;
2018-06-20 12:52:00 +02:00
bool something_overridden = false ;
2019-11-19 12:44:55 +01:00
const LayerTools * m_layer_tools = nullptr ; // so we know which LayerTools object this belongs to
2018-06-20 12:52:00 +02:00
};
2018-06-26 14:12:25 +02:00
class LayerTools
2017-05-16 13:45:28 +02:00
{
2017-05-23 15:00:01 +02:00
public :
2020-01-14 11:54:09 +01:00
LayerTools ( const coordf_t z ) : print_z ( z ) {}
2017-05-16 13:45:28 +02:00
2018-07-24 11:20:29 +02:00
// Changing these operators to epsilon version can make a problem in cases where support and object layers get close to each other.
// In case someone tries to do it, make sure you know what you're doing and test it properly (slice multiple objects at once with supports).
bool operator < ( const LayerTools & rhs ) const { return print_z < rhs . print_z ; }
bool operator == ( const LayerTools & rhs ) const { return print_z == rhs . print_z ; }
2017-05-16 13:45:28 +02:00
2018-07-13 11:25:22 +02:00
bool is_extruder_order ( unsigned int a , unsigned int b ) const ;
2020-01-08 14:58:12 +01:00
bool has_extruder ( unsigned int extruder ) const { return std :: find ( this -> extruders . begin (), this -> extruders . end (), extruder ) != this -> extruders . end (); }
2018-07-13 11:25:22 +02:00
2020-01-14 10:31:18 +01:00
// Return a zero based extruder from the region, or extruder_override if overriden.
unsigned int perimeter_extruder ( const PrintRegion & region ) const ;
unsigned int infill_extruder ( const PrintRegion & region ) const ;
unsigned int solid_infill_extruder ( const PrintRegion & region ) const ;
// Returns a zero based extruder this eec should be printed with, according to PrintRegion config or extruder_override if overriden.
unsigned int extruder ( const ExtrusionEntityCollection & extrusions , const PrintRegion & region ) const ;
2020-01-14 11:54:09 +01:00
coordf_t print_z = 0. ;
bool has_object = false ;
bool has_support = false ;
2018-06-26 14:12:25 +02:00
// Zero based extruder IDs, ordered to minimize tool switches.
std :: vector < unsigned int > extruders ;
2020-01-14 10:31:18 +01:00
// 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.
2020-01-14 11:54:09 +01:00
unsigned int extruder_override = 0 ;
2018-06-26 14:12:25 +02:00
// Will there be anything extruded on this layer for the wipe tower?
// Due to the support layers possibly interleaving the object layers,
// wipe tower will be disabled for some support only layers.
2020-01-14 11:54:09 +01:00
bool has_wipe_tower = false ;
2018-06-26 14:12:25 +02:00
// Number of wipe tower partitions to support the required number of tool switches
// and to support the wipe tower partitions above this one.
2020-01-14 11:54:09 +01:00
size_t wipe_tower_partitions = 0 ;
coordf_t wipe_tower_layer_height = 0. ;
// Custom G-code (color change, extruder switch, pause) to be performed before this layer starts to print.
2020-01-23 12:49:39 +01:00
const CustomGCode :: Item * custom_gcode = nullptr ;
2018-06-26 14:12:25 +02:00
2018-07-11 14:46:13 +02:00
WipingExtrusions & wiping_extrusions () {
m_wiping_extrusions . set_layer_tools_ptr ( this );
return m_wiping_extrusions ;
}
private :
2018-06-26 14:12:25 +02:00
// This object holds list of extrusion that will be used for extruder wiping
2018-07-11 14:46:13 +02:00
WipingExtrusions m_wiping_extrusions ;
2018-06-26 14:12:25 +02:00
};
2018-06-20 12:52:00 +02:00
2017-05-23 15:00:01 +02:00
2018-06-26 14:12:25 +02:00
class ToolOrdering
{
public :
2019-08-16 16:17:37 +02:00
ToolOrdering () {}
2017-05-23 15:00:01 +02:00
2019-08-16 16:17:37 +02:00
// For the use case when each object is printed separately
// (print.config.complete_objects is true).
2020-01-14 10:31:18 +01:00
ToolOrdering ( const PrintObject & object , unsigned int first_extruder , bool prime_multi_material = false );
2017-05-23 15:00:01 +02:00
2019-08-16 16:17:37 +02:00
// For the use case when all objects are printed at once.
// (print.config.complete_objects is false).
2020-01-14 11:54:09 +01:00
ToolOrdering ( const Print & print , unsigned int first_extruder , bool prime_multi_material = false );
2017-05-23 15:00:01 +02:00
2019-08-16 16:17:37 +02:00
void clear () { m_layer_tools . clear (); }
2017-05-25 22:27:53 +02:00
2020-01-15 16:20:16 +01:00
// Only valid for non-sequential print:
// Assign a pointer to a custom G-code to the respective ToolOrdering::LayerTools.
// Ignore color changes, which are performed on a layer and for such an extruder, that the extruder will not be printing above that layer.
// If multiple events are planned over a span of a single layer, use the last one.
void assign_custom_gcodes ( const Print & print );
2019-08-16 16:17:37 +02:00
// Get the first extruder printing, including the extruder priming areas, returns -1 if there is no layer printed.
unsigned int first_extruder () const { return m_first_printing_extruder ; }
2017-05-23 15:00:01 +02:00
2019-08-16 16:17:37 +02:00
// Get the first extruder printing the layer_tools, returns -1 if there is no layer printed.
unsigned int last_extruder () const { return m_last_printing_extruder ; }
2017-09-01 17:30:18 +02:00
2019-08-16 16:17:37 +02:00
// For a multi-material print, the printing extruders are ordered in the order they shall be primed.
const std :: vector < unsigned int >& all_extruders () const { return m_all_printing_extruders ; }
2017-05-23 15:00:01 +02:00
2019-08-16 16:17:37 +02:00
// Find LayerTools with the closest print_z.
2020-01-07 14:35:43 +01:00
const LayerTools & tools_for_layer ( coordf_t print_z ) const ;
LayerTools & tools_for_layer ( coordf_t print_z ) { return const_cast < LayerTools &> ( std :: as_const ( * this ). tools_for_layer ( print_z )); }
2019-08-16 16:17:37 +02:00
const LayerTools & front () const { return m_layer_tools . front (); }
const LayerTools & back () const { return m_layer_tools . back (); }
std :: vector < LayerTools >:: const_iterator begin () const { return m_layer_tools . begin (); }
std :: vector < LayerTools >:: const_iterator end () const { return m_layer_tools . end (); }
bool empty () const { return m_layer_tools . empty (); }
std :: vector < LayerTools >& layer_tools () { return m_layer_tools ; }
bool has_wipe_tower () const { return ! m_layer_tools . empty () && m_first_printing_extruder != ( unsigned int ) - 1 && m_layer_tools . front (). wipe_tower_partitions > 0 ; }
2017-05-23 15:00:01 +02:00
private :
2019-08-16 16:17:37 +02:00
void initialize_layers ( std :: vector < coordf_t > & zs );
2020-01-14 12:10:01 +01:00
void collect_extruders ( const PrintObject & object , const std :: vector < std :: pair < double , unsigned int >> & per_layer_extruder_switches );
2019-08-16 16:17:37 +02:00
void reorder_extruders ( unsigned int last_extruder_id );
2020-03-27 14:15:09 +01:00
void fill_wipe_tower_partitions ( const PrintConfig & config , coordf_t object_bottom_z , coordf_t max_layer_height );
2018-06-26 14:12:25 +02:00
void collect_extruder_statistics ( bool prime_multi_material );
2017-05-23 15:00:01 +02:00
2018-06-26 14:12:25 +02:00
std :: vector < LayerTools > m_layer_tools ;
// First printing extruder, including the multi-material priming sequence.
unsigned int m_first_printing_extruder = ( unsigned int ) - 1 ;
// Final printing extruder.
unsigned int m_last_printing_extruder = ( unsigned int ) - 1 ;
// All extruders, which extrude some material over m_layer_tools.
std :: vector < unsigned int > m_all_printing_extruders ;
const PrintConfig * m_print_config_ptr = nullptr ;
2017-05-16 13:45:28 +02:00
};
2018-06-26 14:12:25 +02:00
2017-05-16 13:45:28 +02:00
} // namespace SLic3r
#endif /* slic3r_ToolOrdering_hpp_ */