Prusa Slicer 2.6.0
Loading...
Searching...
No Matches
Slic3r::ToolOrdering Class Reference

#include <src/libslic3r/GCode/ToolOrdering.hpp>

+ Collaboration diagram for Slic3r::ToolOrdering:

Public Member Functions

 ToolOrdering ()=default
 
 ToolOrdering (const PrintObject &object, unsigned int first_extruder, bool prime_multi_material=false)
 
 ToolOrdering (const Print &print, unsigned int first_extruder, bool prime_multi_material=false)
 
void clear ()
 
void assign_custom_gcodes (const Print &print)
 
unsigned int first_extruder () const
 
unsigned int last_extruder () const
 
const std::vector< unsigned int > & all_extruders () const
 
const LayerToolstools_for_layer (coordf_t print_z) const
 
LayerToolstools_for_layer (coordf_t print_z)
 
const LayerToolsfront () const
 
const LayerToolsback () const
 
std::vector< LayerTools >::const_iterator begin () const
 
std::vector< LayerTools >::const_iterator end () const
 
bool empty () const
 
std::vector< LayerTools > & layer_tools ()
 
bool has_wipe_tower () const
 

Private Member Functions

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 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 ()
 
void mark_skirt_layers (const PrintConfig &config, coordf_t max_layer_height)
 
void collect_extruder_statistics (bool prime_multi_material)
 

Private Attributes

std::vector< LayerToolsm_layer_tools
 
unsigned int m_first_printing_extruder = (unsigned int)-1
 
unsigned int m_last_printing_extruder = (unsigned int)-1
 
std::vector< unsigned int > m_all_printing_extruders
 
const PrintConfig * m_print_config_ptr = nullptr
 

Detailed Description

Constructor & Destructor Documentation

◆ ToolOrdering() [1/3]

Slic3r::ToolOrdering::ToolOrdering ( )
default

◆ ToolOrdering() [2/3]

Slic3r::ToolOrdering::ToolOrdering ( const PrintObject object,
unsigned int  first_extruder,
bool  prime_multi_material = false 
)
91{
92 if (object.layers().empty())
93 return;
94
95 // Initialize the print layers for just a single object.
96 {
97 std::vector<coordf_t> zs;
98 zs.reserve(zs.size() + object.layers().size() + object.support_layers().size());
99 for (auto layer : object.layers())
100 zs.emplace_back(layer->print_z);
101 for (auto layer : object.support_layers())
102 zs.emplace_back(layer->print_z);
103 this->initialize_layers(zs);
104 }
105 double max_layer_height = calc_max_layer_height(object.print()->config(), object.config().layer_height);
106
107 // Collect extruders required to print the layers.
108 this->collect_extruders(object, std::vector<std::pair<double, unsigned int>>());
109
110 // Reorder the extruders to minimize tool switches.
112
113 this->fill_wipe_tower_partitions(object.print()->config(), object.layers().front()->print_z - object.layers().front()->height, max_layer_height);
114
115 this->collect_extruder_statistics(prime_multi_material);
116
117 this->mark_skirt_layers(object.print()->config(), max_layer_height);
118}
void collect_extruders(const PrintObject &object, const std::vector< std::pair< double, unsigned int > > &per_layer_extruder_switches)
Definition ToolOrdering.cpp:212
void mark_skirt_layers(const PrintConfig &config, coordf_t max_layer_height)
Definition ToolOrdering.cpp:526
void collect_extruder_statistics(bool prime_multi_material)
Definition ToolOrdering.cpp:491
void initialize_layers(std::vector< coordf_t > &zs)
Definition ToolOrdering.cpp:181
void reorder_extruders(unsigned int last_extruder_id)
Definition ToolOrdering.cpp:313
const LayerTools & front() const
Definition ToolOrdering.hpp:157
unsigned int first_extruder() const
Definition ToolOrdering.hpp:145
void fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z, coordf_t max_layer_height)
Definition ToolOrdering.cpp:376
bool empty() const
Definition ToolOrdering.hpp:161
layer_height((ConfigOptionInt, faded_layers))((ConfigOptionFloat
static double calc_max_layer_height(const PrintConfig &config, double max_object_layer_height)
Definition ToolOrdering.cpp:74

References Slic3r::calc_max_layer_height(), collect_extruder_statistics(), collect_extruders(), empty(), fill_wipe_tower_partitions(), front(), initialize_layers(), Slic3r::layer_height(), mark_skirt_layers(), and reorder_extruders().

+ Here is the call graph for this function:

◆ ToolOrdering() [3/3]

Slic3r::ToolOrdering::ToolOrdering ( const Print print,
unsigned int  first_extruder,
bool  prime_multi_material = false 
)
123{
124 m_print_config_ptr = &print.config();
125
126 // Initialize the print layers for all objects and all layers.
127 coordf_t object_bottom_z = 0.;
128 coordf_t max_layer_height = 0.;
129 {
130 std::vector<coordf_t> zs;
131 for (auto object : print.objects()) {
132 zs.reserve(zs.size() + object->layers().size() + object->support_layers().size());
133 for (auto layer : object->layers())
134 zs.emplace_back(layer->print_z);
135 for (auto layer : object->support_layers())
136 zs.emplace_back(layer->print_z);
137
138 // Find first object layer that is not empty and save its print_z
139 for (const Layer* layer : object->layers())
140 if (layer->has_extrusions()) {
141 object_bottom_z = layer->print_z - layer->height;
142 break;
143 }
144
145 max_layer_height = std::max(max_layer_height, object->config().layer_height.value);
146 }
147 this->initialize_layers(zs);
148 }
149 max_layer_height = calc_max_layer_height(print.config(), max_layer_height);
150
151 // Use the extruder switches from Model::custom_gcode_per_print_z to override the extruder to print the object.
152 // Do it only if all the objects were configured to be printed with a single extruder.
153 std::vector<std::pair<double, unsigned int>> per_layer_extruder_switches;
154 if (auto num_extruders = unsigned(print.config().nozzle_diameter.size());
155 num_extruders > 1 && print.object_extruders().size() == 1 && // the current Print's configuration is CustomGCode::MultiAsSingle
156 print.model().custom_gcode_per_print_z.mode == CustomGCode::MultiAsSingle) {
157 // Printing a single extruder platter on a printer with more than 1 extruder (or single-extruder multi-material).
158 // There may be custom per-layer tool changes available at the model.
159 per_layer_extruder_switches = custom_tool_changes(print.model().custom_gcode_per_print_z, num_extruders);
160 }
161
162 // Collect extruders reuqired to print the layers.
163 for (auto object : print.objects())
164 this->collect_extruders(*object, per_layer_extruder_switches);
165
166 // Reorder the extruders to minimize tool switches.
168
169 this->fill_wipe_tower_partitions(print.config(), object_bottom_z, max_layer_height);
170
171 if (this->insert_wipe_tower_extruder()) {
173 this->fill_wipe_tower_partitions(print.config(), object_bottom_z, max_layer_height);
174 }
175
176 this->collect_extruder_statistics(prime_multi_material);
177
178 this->mark_skirt_layers(print.config(), max_layer_height);
179}
const PrintConfig * m_print_config_ptr
Definition ToolOrdering.hpp:182
bool insert_wipe_tower_extruder()
Definition ToolOrdering.cpp:470
if(!(yy_init))
Definition lexer.c:1190
double coordf_t
Definition libslic3r.h:45
std::vector< std::pair< double, unsigned int > > custom_tool_changes(const Info &custom_gcode_per_print_z, size_t num_extruders)
Definition CustomGCode.cpp:59
@ MultiAsSingle
Definition CustomGCode.hpp:51

References Slic3r::calc_max_layer_height(), collect_extruder_statistics(), collect_extruders(), Slic3r::Print::config(), Slic3r::Model::custom_gcode_per_print_z, Slic3r::CustomGCode::custom_tool_changes(), fill_wipe_tower_partitions(), initialize_layers(), insert_wipe_tower_extruder(), m_print_config_ptr, mark_skirt_layers(), Slic3r::CustomGCode::Info::mode, Slic3r::PrintBase::model(), Slic3r::CustomGCode::MultiAsSingle, Slic3r::Print::object_extruders(), Slic3r::Print::objects(), and reorder_extruders().

+ Here is the call graph for this function:

Member Function Documentation

◆ all_extruders()

const std::vector< unsigned int > & Slic3r::ToolOrdering::all_extruders ( ) const
inline
151{ return m_all_printing_extruders; }
std::vector< unsigned int > m_all_printing_extruders
Definition ToolOrdering.hpp:180

References m_all_printing_extruders.

Referenced by Slic3r::GCode::_do_export(), and Slic3r::Print::_make_wipe_tower().

+ Here is the caller graph for this function:

◆ assign_custom_gcodes()

void Slic3r::ToolOrdering::assign_custom_gcodes ( const Print print)
571{
572 // Only valid for non-sequential print.
573 assert(! print.config().complete_objects.value);
574
575 const CustomGCode::Info &custom_gcode_per_print_z = print.model().custom_gcode_per_print_z;
576 if (custom_gcode_per_print_z.gcodes.empty())
577 return;
578
579 auto num_extruders = unsigned(print.config().nozzle_diameter.size());
581 (num_extruders == 1) ? CustomGCode::SingleExtruder :
582 print.object_extruders().size() == 1 ? CustomGCode::MultiAsSingle : CustomGCode::MultiExtruder;
583 CustomGCode::Mode model_mode = print.model().custom_gcode_per_print_z.mode;
584 std::vector<unsigned char> extruder_printing_above(num_extruders, false);
585 auto custom_gcode_it = custom_gcode_per_print_z.gcodes.rbegin();
586 // Tool changes and color changes will be ignored, if the model's tool/color changes were entered in mm mode and the print is in non mm mode
587 // or vice versa.
588 bool ignore_tool_and_color_changes = (mode == CustomGCode::MultiExtruder) != (model_mode == CustomGCode::MultiExtruder);
589 // If printing on a single extruder machine, make the tool changes trigger color change (M600) events.
590 bool tool_changes_as_color_changes = mode == CustomGCode::SingleExtruder && model_mode == CustomGCode::MultiAsSingle;
591
592 // From the last layer to the first one:
593 for (auto it_lt = m_layer_tools.rbegin(); it_lt != m_layer_tools.rend(); ++ it_lt) {
594 LayerTools &lt = *it_lt;
595 // Add the extruders of the current layer to the set of extruders printing at and above this print_z.
596 for (unsigned int i : lt.extruders)
597 extruder_printing_above[i] = true;
598 // Skip all custom G-codes above this layer and skip all extruder switches.
599 for (; custom_gcode_it != custom_gcode_per_print_z.gcodes.rend() && (custom_gcode_it->print_z > lt.print_z + EPSILON || custom_gcode_it->type == CustomGCode::ToolChange); ++ custom_gcode_it);
600 if (custom_gcode_it == custom_gcode_per_print_z.gcodes.rend())
601 // Custom G-codes were processed.
602 break;
603 // Some custom G-code is configured for this layer or a layer below.
604 const CustomGCode::Item &custom_gcode = *custom_gcode_it;
605 // print_z of the layer below the current layer.
606 coordf_t print_z_below = 0.;
607 if (auto it_lt_below = it_lt; ++ it_lt_below != m_layer_tools.rend())
608 print_z_below = it_lt_below->print_z;
609 if (custom_gcode.print_z > print_z_below + 0.5 * EPSILON) {
610 // The custom G-code applies to the current layer.
611 bool color_change = custom_gcode.type == CustomGCode::ColorChange;
612 bool tool_change = custom_gcode.type == CustomGCode::ToolChange;
613 bool pause_or_custom_gcode = ! color_change && ! tool_change;
614 bool apply_color_change = ! ignore_tool_and_color_changes &&
615 // If it is color change, it will actually be useful as the exturder above will print.
616 (color_change ?
618 (custom_gcode.extruder <= int(num_extruders) && extruder_printing_above[unsigned(custom_gcode.extruder - 1)]) :
619 tool_change && tool_changes_as_color_changes);
620 if (pause_or_custom_gcode || apply_color_change)
621 lt.custom_gcode = &custom_gcode;
622 // Consume that custom G-code event.
623 ++ custom_gcode_it;
624 }
625 }
626}
std::vector< LayerTools > m_layer_tools
Definition ToolOrdering.hpp:174
static constexpr double EPSILON
Definition libslic3r.h:51
Mode
Definition CustomGCode.hpp:48
@ SingleExtruder
Definition CustomGCode.hpp:50
@ MultiExtruder
Definition CustomGCode.hpp:54
@ ToolChange
Definition CustomGCode.hpp:17
@ ColorChange
Definition CustomGCode.hpp:15
constexpr auto size(const C &c) -> decltype(c.size())
Definition span.hpp:183
IGL_INLINE void mode(const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > &X, const int d, Eigen::Matrix< T, Eigen::Dynamic, 1 > &M)
Definition mode.cpp:14

References Slic3r::CustomGCode::ColorChange, Slic3r::Print::config(), Slic3r::LayerTools::custom_gcode, Slic3r::Model::custom_gcode_per_print_z, EPSILON, Slic3r::CustomGCode::Item::extruder, Slic3r::LayerTools::extruders, Slic3r::CustomGCode::Info::gcodes, m_layer_tools, Slic3r::CustomGCode::Info::mode, Slic3r::PrintBase::model(), Slic3r::CustomGCode::MultiAsSingle, Slic3r::CustomGCode::MultiExtruder, Slic3r::Print::object_extruders(), Slic3r::CustomGCode::Item::print_z, Slic3r::LayerTools::print_z, Slic3r::CustomGCode::SingleExtruder, Slic3r::CustomGCode::ToolChange, and Slic3r::CustomGCode::Item::type.

Referenced by Slic3r::GCode::_do_export().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ back()

const LayerTools & Slic3r::ToolOrdering::back ( ) const
inline
158{ return m_layer_tools.back(); }

References m_layer_tools.

Referenced by Slic3r::Print::_make_wipe_tower().

+ Here is the caller graph for this function:

◆ begin()

std::vector< LayerTools >::const_iterator Slic3r::ToolOrdering::begin ( ) const
inline
159{ return m_layer_tools.begin(); }

References m_layer_tools.

Referenced by Slic3r::DoubleSlider::TickCodeInfo::get_used_extruders_for_tick().

+ Here is the caller graph for this function:

◆ clear()

void Slic3r::ToolOrdering::clear ( )
inline
136{ m_layer_tools.clear(); }

References m_layer_tools.

Referenced by Slic3r::Print::process().

+ Here is the caller graph for this function:

◆ collect_extruder_statistics()

void Slic3r::ToolOrdering::collect_extruder_statistics ( bool  prime_multi_material)
private
492{
493 m_first_printing_extruder = (unsigned int)-1;
494 for (const auto &lt : m_layer_tools)
495 if (! lt.extruders.empty()) {
496 m_first_printing_extruder = lt.extruders.front();
497 break;
498 }
499
500 m_last_printing_extruder = (unsigned int)-1;
501 for (auto lt_it = m_layer_tools.rbegin(); lt_it != m_layer_tools.rend(); ++ lt_it)
502 if (! lt_it->extruders.empty()) {
503 m_last_printing_extruder = lt_it->extruders.back();
504 break;
505 }
506
508 for (const auto &lt : m_layer_tools) {
509 append(m_all_printing_extruders, lt.extruders);
511 }
512
513 if (prime_multi_material && ! m_all_printing_extruders.empty()) {
514 // Reorder m_all_printing_extruders in the sequence they will be primed, the last one will be m_first_printing_extruder.
515 // Then set m_first_printing_extruder to the 1st extruder primed.
517 std::remove_if(m_all_printing_extruders.begin(), m_all_printing_extruders.end(),
518 [ this ](const unsigned int eid) { return eid == m_first_printing_extruder; }),
522 }
523}
unsigned int m_last_printing_extruder
Definition ToolOrdering.hpp:178
unsigned int m_first_printing_extruder
Definition ToolOrdering.hpp:176
void sort_remove_duplicates(std::vector< T > &vec)
Definition libslic3r.h:188
void append(std::vector< T, Alloc > &dest, const std::vector< T, Alloc2 > &src)
Definition libslic3r.h:110

References Slic3r::append(), m_all_printing_extruders, m_first_printing_extruder, m_last_printing_extruder, m_layer_tools, and Slic3r::sort_remove_duplicates().

Referenced by ToolOrdering(), and ToolOrdering().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ collect_extruders()

void Slic3r::ToolOrdering::collect_extruders ( const PrintObject object,
const std::vector< std::pair< double, unsigned int > > &  per_layer_extruder_switches 
)
private
213{
214 // Collect the support extruders.
215 for (auto support_layer : object.support_layers()) {
216 LayerTools &layer_tools = this->tools_for_layer(support_layer->print_z);
217 ExtrusionRole role = support_layer->support_fills.role();
218 bool has_support = role == ExtrusionRole::Mixed || role == ExtrusionRole::SupportMaterial;
219 bool has_interface = role == ExtrusionRole::Mixed || role == ExtrusionRole::SupportMaterialInterface;
220 unsigned int extruder_support = object.config().support_material_extruder.value;
221 unsigned int extruder_interface = object.config().support_material_interface_extruder.value;
222 if (has_support)
223 layer_tools.extruders.push_back(extruder_support);
224 if (has_interface)
225 layer_tools.extruders.push_back(extruder_interface);
226 if (has_support || has_interface)
227 layer_tools.has_support = true;
228 }
229
230 // Extruder overrides are ordered by print_z.
231 std::vector<std::pair<double, unsigned int>>::const_iterator it_per_layer_extruder_override;
232 it_per_layer_extruder_override = per_layer_extruder_switches.begin();
233 unsigned int extruder_override = 0;
234
235 // Collect the object extruders.
236 for (auto layer : object.layers()) {
237 LayerTools &layer_tools = this->tools_for_layer(layer->print_z);
238
239 // Override extruder with the next
240 for (; it_per_layer_extruder_override != per_layer_extruder_switches.end() && it_per_layer_extruder_override->first < layer->print_z + EPSILON; ++ it_per_layer_extruder_override)
241 extruder_override = (int)it_per_layer_extruder_override->second;
242
243 // Store the current extruder override (set to zero if no overriden), so that layer_tools.wiping_extrusions().is_overridable_and_mark() will use it.
244 layer_tools.extruder_override = extruder_override;
245
246 // What extruders are required to print this object layer?
247 for (const LayerRegion *layerm : layer->regions()) {
248 const PrintRegion &region = layerm->region();
249
250 if (! layerm->perimeters().empty()) {
251 bool something_nonoverriddable = true;
252
253 if (m_print_config_ptr) { // in this case complete_objects is false (see ToolOrdering constructors)
254 something_nonoverriddable = false;
255 for (const ExtrusionEntity *eec : layerm->perimeters()) // let's check if there are nonoverriddable entities
256 if (is_overriddable(dynamic_cast<const ExtrusionEntityCollection&>(*eec), layer_tools, *m_print_config_ptr, object, region))
257 layer_tools.wiping_extrusions_nonconst().set_something_overridable();
258 else
259 something_nonoverriddable = true;
260 }
261
262 if (something_nonoverriddable)
263 layer_tools.extruders.emplace_back(extruder_override == 0 ? region.config().perimeter_extruder.value : extruder_override);
264
265 layer_tools.has_object = true;
266 }
267
268 bool has_infill = false;
269 bool has_solid_infill = false;
270 bool something_nonoverriddable = false;
271 for (const ExtrusionEntity *ee : layerm->fills()) {
272 // fill represents infill extrusions of a single island.
273 const auto *fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
274 ExtrusionRole role = fill->entities.empty() ? ExtrusionRole::None : fill->entities.front()->role();
275 if (role.is_solid_infill())
276 has_solid_infill = true;
277 else if (role != ExtrusionRole::None)
278 has_infill = true;
279
280 if (m_print_config_ptr) {
281 if (is_overriddable(*fill, layer_tools, *m_print_config_ptr, object, region))
282 layer_tools.wiping_extrusions_nonconst().set_something_overridable();
283 else
284 something_nonoverriddable = true;
285 }
286 }
287
288 if (something_nonoverriddable || !m_print_config_ptr) {
289 if (extruder_override == 0) {
290 if (has_solid_infill)
291 layer_tools.extruders.emplace_back(region.config().solid_infill_extruder);
292 if (has_infill)
293 layer_tools.extruders.emplace_back(region.config().infill_extruder);
294 } else if (has_solid_infill || has_infill)
295 layer_tools.extruders.emplace_back(extruder_override);
296 }
297 if (has_solid_infill || has_infill)
298 layer_tools.has_object = true;
299 }
300 }
301
302 for (auto& layer : m_layer_tools) {
303 // Sort and remove duplicates
304 sort_remove_duplicates(layer.extruders);
305
306 // make sure that there are some tools for each object layer (e.g. tall wiping object will result in empty extruders vector)
307 if (layer.extruders.empty() && layer.has_object)
308 layer.extruders.emplace_back(0); // 0="dontcare" extruder - it will be taken care of in reorder_extruders
309 }
310}
const LayerTools & tools_for_layer(coordf_t print_z) const
Definition ToolOrdering.cpp:628
std::vector< LayerTools > & layer_tools()
Definition ToolOrdering.hpp:162
#define const
Definition getopt.c:38
static bool is_overriddable(const ExtrusionEntityCollection &eec, const LayerTools &lt, const PrintConfig &print_config, const PrintObject &object, const PrintRegion &region)
Definition ToolOrdering.cpp:197
static constexpr const ExtrusionRoleModifiers SupportMaterial
Definition ExtrusionRole.hpp:73
static constexpr const ExtrusionRoleModifiers SupportMaterialInterface
Definition ExtrusionRole.hpp:75
static constexpr const ExtrusionRoleModifiers None
Definition ExtrusionRole.hpp:47
static constexpr const ExtrusionRoleModifiers Mixed
Definition ExtrusionRole.hpp:79

References Slic3r::PrintRegion::config(), EPSILON, Slic3r::is_overriddable(), Slic3r::ExtrusionRole::is_solid_infill(), layer_tools(), m_layer_tools, m_print_config_ptr, Slic3r::ExtrusionRole::Mixed, Slic3r::ExtrusionRole::None, Slic3r::sort_remove_duplicates(), Slic3r::ExtrusionRole::SupportMaterial, Slic3r::ExtrusionRole::SupportMaterialInterface, and tools_for_layer().

Referenced by ToolOrdering(), and ToolOrdering().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ empty()

bool Slic3r::ToolOrdering::empty ( ) const
inline
161{ return m_layer_tools.empty(); }

References m_layer_tools.

Referenced by ToolOrdering(), Slic3r::DoubleSlider::TickCodeInfo::get_used_extruders_for_tick(), and Slic3r::Print::process().

+ Here is the caller graph for this function:

◆ end()

std::vector< LayerTools >::const_iterator Slic3r::ToolOrdering::end ( ) const
inline
160{ return m_layer_tools.end(); }

References m_layer_tools.

Referenced by Slic3r::DoubleSlider::TickCodeInfo::get_used_extruders_for_tick().

+ Here is the caller graph for this function:

◆ fill_wipe_tower_partitions()

void Slic3r::ToolOrdering::fill_wipe_tower_partitions ( const PrintConfig &  config,
coordf_t  object_bottom_z,
coordf_t  max_layer_height 
)
private
377{
378 if (m_layer_tools.empty())
379 return;
380
381 // Count the minimum number of tool changes per layer.
382 size_t last_extruder = size_t(-1);
383 for (LayerTools &lt : m_layer_tools) {
384 lt.wipe_tower_partitions = lt.extruders.size();
385 if (! lt.extruders.empty()) {
386 if (last_extruder == size_t(-1) || last_extruder == lt.extruders.front())
387 // The first extruder on this layer is equal to the current one, no need to do an initial tool change.
388 -- lt.wipe_tower_partitions;
389 last_extruder = lt.extruders.back();
390 }
391 }
392
393 // Propagate the wipe tower partitions down to support the upper partitions by the lower partitions.
394 for (int i = int(m_layer_tools.size()) - 2; i >= 0; -- i)
395 m_layer_tools[i].wipe_tower_partitions = std::max(m_layer_tools[i + 1].wipe_tower_partitions, m_layer_tools[i].wipe_tower_partitions);
396
397 //FIXME this is a hack to get the ball rolling.
398 for (LayerTools &lt : m_layer_tools)
399 lt.has_wipe_tower = (lt.has_object && lt.wipe_tower_partitions > 0) || lt.print_z < object_bottom_z + EPSILON;
400
401 // Test for a raft, insert additional wipe tower layer to fill in the raft separation gap.
402 for (size_t i = 0; i + 1 < m_layer_tools.size(); ++ i) {
403 const LayerTools &lt = m_layer_tools[i];
404 const LayerTools &lt_next = m_layer_tools[i + 1];
405 if (lt.print_z < object_bottom_z + EPSILON && lt_next.print_z >= object_bottom_z + EPSILON) {
406 // lt is the last raft layer. Find the 1st object layer.
407 size_t j = i + 1;
408 for (; j < m_layer_tools.size() && ! m_layer_tools[j].has_wipe_tower; ++ j);
409 if (j < m_layer_tools.size()) {
410 const LayerTools &lt_object = m_layer_tools[j];
411 coordf_t gap = lt_object.print_z - lt.print_z;
412 assert(gap > 0.f);
413 if (gap > max_layer_height + EPSILON) {
414 // Insert one additional wipe tower layer between lh.print_z and lt_object.print_z.
415 LayerTools lt_new(0.5f * (lt.print_z + lt_object.print_z));
416 // Find the 1st layer above lt_new.
417 for (j = i + 1; j < m_layer_tools.size() && m_layer_tools[j].print_z < lt_new.print_z - EPSILON; ++ j);
418 if (std::abs(m_layer_tools[j].print_z - lt_new.print_z) < EPSILON) {
419 m_layer_tools[j].has_wipe_tower = true;
420 } else {
421 LayerTools &lt_extra = *m_layer_tools.insert(m_layer_tools.begin() + j, lt_new);
422 //LayerTools &lt_prev = m_layer_tools[j];
423 LayerTools &lt_next = m_layer_tools[j + 1];
424 assert(! m_layer_tools[j - 1].extruders.empty() && ! lt_next.extruders.empty());
425 // FIXME: Following assert tripped when running combine_infill.t. I decided to comment it out for now.
426 // If it is a bug, it's likely not critical, because this code is unchanged for a long time. It might
427 // still be worth looking into it more and decide if it is a bug or an obsolete assert.
428 //assert(lt_prev.extruders.back() == lt_next.extruders.front());
429 lt_extra.has_wipe_tower = true;
430 lt_extra.extruders.push_back(lt_next.extruders.front());
431 lt_extra.wipe_tower_partitions = lt_next.wipe_tower_partitions;
432 }
433 }
434 }
435 break;
436 }
437 }
438
439 // If the model contains empty layers (such as https://github.com/prusa3d/Slic3r/issues/1266), there might be layers
440 // that were not marked as has_wipe_tower, even when they should have been. This produces a crash with soluble supports
441 // and maybe other problems. We will therefore go through layer_tools and detect and fix this.
442 // So, if there is a non-object layer starting with different extruder than the last one ended with (or containing more than one extruder),
443 // we'll mark it with has_wipe tower.
444 for (unsigned int i=0; i+1<m_layer_tools.size(); ++i) {
445 LayerTools& lt = m_layer_tools[i];
446 LayerTools& lt_next = m_layer_tools[i+1];
447 if (lt.extruders.empty() || lt_next.extruders.empty())
448 break;
449 if (!lt_next.has_wipe_tower && (lt_next.extruders.front() != lt.extruders.back() || lt_next.extruders.size() > 1))
450 lt_next.has_wipe_tower = true;
451 // We should also check that the next wipe tower layer is no further than max_layer_height:
452 unsigned int j = i+1;
453 double last_wipe_tower_print_z = lt_next.print_z;
454 while (++j < m_layer_tools.size()-1 && !m_layer_tools[j].has_wipe_tower)
455 if (m_layer_tools[j+1].print_z - last_wipe_tower_print_z > max_layer_height + EPSILON) {
456 m_layer_tools[j].has_wipe_tower = true;
457 last_wipe_tower_print_z = m_layer_tools[j].print_z;
458 }
459 }
460
461 // Calculate the wipe_tower_layer_height values.
462 coordf_t wipe_tower_print_z_last = 0.;
463 for (LayerTools &lt : m_layer_tools)
464 if (lt.has_wipe_tower) {
465 lt.wipe_tower_layer_height = lt.print_z - wipe_tower_print_z_last;
466 wipe_tower_print_z_last = lt.print_z;
467 }
468}
bool has_wipe_tower() const
Definition ToolOrdering.hpp:163
unsigned int last_extruder() const
Definition ToolOrdering.hpp:148

References EPSILON, Slic3r::LayerTools::extruders, Slic3r::LayerTools::has_wipe_tower, last_extruder(), m_layer_tools, Slic3r::LayerTools::print_z, and Slic3r::LayerTools::wipe_tower_partitions.

Referenced by ToolOrdering(), and ToolOrdering().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ first_extruder()

unsigned int Slic3r::ToolOrdering::first_extruder ( ) const
inline

References m_first_printing_extruder.

Referenced by Slic3r::GCode::_do_export(), and Slic3r::Print::_make_wipe_tower().

+ Here is the caller graph for this function:

◆ front()

const LayerTools & Slic3r::ToolOrdering::front ( ) const
inline
157{ return m_layer_tools.front(); }

References m_layer_tools.

Referenced by ToolOrdering(), and Slic3r::Print::_make_wipe_tower().

+ Here is the caller graph for this function:

◆ has_wipe_tower()

bool Slic3r::ToolOrdering::has_wipe_tower ( ) const
inline
163{ return ! m_layer_tools.empty() && m_first_printing_extruder != (unsigned int)-1 && m_layer_tools.front().wipe_tower_partitions > 0; }

References m_first_printing_extruder, and m_layer_tools.

Referenced by Slic3r::GCode::_do_export(), and Slic3r::Print::_make_wipe_tower().

+ Here is the caller graph for this function:

◆ initialize_layers()

void Slic3r::ToolOrdering::initialize_layers ( std::vector< coordf_t > &  zs)
private
182{
184 // Merge numerically very close Z values.
185 for (size_t i = 0; i < zs.size();) {
186 // Find the last layer with roughly the same print_z.
187 size_t j = i + 1;
188 coordf_t zmax = zs[i] + EPSILON;
189 for (; j < zs.size() && zs[j] <= zmax; ++ j) ;
190 // Assign an average print_z to the set of layers with nearly equal print_z.
191 m_layer_tools.emplace_back(LayerTools(0.5 * (zs[i] + zs[j-1])));
192 i = j;
193 }
194}

References EPSILON, m_layer_tools, and Slic3r::sort_remove_duplicates().

Referenced by ToolOrdering(), and ToolOrdering().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ insert_wipe_tower_extruder()

bool Slic3r::ToolOrdering::insert_wipe_tower_extruder ( )
private
471{
472 // In case that wipe_tower_extruder is set to non-zero, we must make sure that the extruder will be in the list.
473 bool changed = false;
474 if (m_print_config_ptr->wipe_tower_extruder != 0) {
475 for (LayerTools& lt : m_layer_tools) {
476 if (lt.wipe_tower_partitions > 0) {
477 lt.extruders.emplace_back(m_print_config_ptr->wipe_tower_extruder - 1);
478 sort_remove_duplicates(lt.extruders);
479 changed = true;
480 }
481 }
482 // Now convert the 0-based list to 1-based again.
483 for (LayerTools& lt : m_layer_tools) {
484 for (auto& extruder : lt.extruders)
485 ++extruder;
486 }
487 }
488 return changed;
489}

References m_layer_tools, m_print_config_ptr, and Slic3r::sort_remove_duplicates().

Referenced by ToolOrdering().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ last_extruder()

unsigned int Slic3r::ToolOrdering::last_extruder ( ) const
inline
148{ return m_last_printing_extruder; }

References m_last_printing_extruder.

Referenced by Slic3r::GCode::_do_export(), fill_wipe_tower_partitions(), and Slic3r::Print::process().

+ Here is the caller graph for this function:

◆ layer_tools()

std::vector< LayerTools > & Slic3r::ToolOrdering::layer_tools ( )
inline
162{ return m_layer_tools; }

References m_layer_tools.

Referenced by Slic3r::GCode::_do_export(), Slic3r::Print::_make_wipe_tower(), and collect_extruders().

+ Here is the caller graph for this function:

◆ mark_skirt_layers()

void Slic3r::ToolOrdering::mark_skirt_layers ( const PrintConfig &  config,
coordf_t  max_layer_height 
)
private
527{
528 if (m_layer_tools.empty())
529 return;
530
531 if (m_layer_tools.front().extruders.empty()) {
532 // Empty first layer, no skirt will be printed.
533 //FIXME throw an exception?
534 return;
535 }
536
537 size_t i = 0;
538 for (;;) {
539 m_layer_tools[i].has_skirt = true;
540 size_t j = i + 1;
541 for (; j < m_layer_tools.size() && ! m_layer_tools[j].has_object; ++ j);
542 // i and j are two successive layers printing an object.
543 if (j == m_layer_tools.size())
544 // Don't print skirt above the last object layer.
545 break;
546 // Mark some printing intermediate layers as having skirt.
547 double last_z = m_layer_tools[i].print_z;
548 for (size_t k = i + 1; k < j; ++ k) {
549 if (m_layer_tools[k + 1].print_z - last_z > max_layer_height + EPSILON) {
550 // Layer k is the last one not violating the maximum layer height.
551 // Don't extrude skirt on empty layers.
552 while (m_layer_tools[k].extruders.empty())
553 -- k;
554 if (m_layer_tools[k].has_skirt) {
555 // Skirt cannot be generated due to empty layers, there would be a missing layer in the skirt.
556 //FIXME throw an exception?
557 break;
558 }
559 m_layer_tools[k].has_skirt = true;
560 last_z = m_layer_tools[k].print_z;
561 }
562 }
563 i = j;
564 }
565}

References EPSILON, and m_layer_tools.

Referenced by ToolOrdering(), and ToolOrdering().

+ Here is the caller graph for this function:

◆ reorder_extruders()

void Slic3r::ToolOrdering::reorder_extruders ( unsigned int  last_extruder_id)
private
314{
315 if (m_layer_tools.empty())
316 return;
317
318 if (last_extruder_id == (unsigned int)-1) {
319 // The initial print extruder has not been decided yet.
320 // Initialize the last_extruder_id with the first non-zero extruder id used for the print.
321 last_extruder_id = 0;
322 for (size_t i = 0; i < m_layer_tools.size() && last_extruder_id == 0; ++ i) {
323 const LayerTools &lt = m_layer_tools[i];
324 for (unsigned int extruder_id : lt.extruders)
325 if (extruder_id > 0) {
326 last_extruder_id = extruder_id;
327 break;
328 }
329 }
330 if (last_extruder_id == 0)
331 // Nothing to extrude.
332 return;
333 } else
334 // 1 based index
335 ++ last_extruder_id;
336
337 for (LayerTools &lt : m_layer_tools) {
338 if (lt.extruders.empty())
339 continue;
340 if (lt.extruders.size() == 1 && lt.extruders.front() == 0)
341 lt.extruders.front() = last_extruder_id;
342 else {
343 if (lt.extruders.front() == 0)
344 // Pop the "don't care" extruder, the "don't care" region will be merged with the next one.
345 lt.extruders.erase(lt.extruders.begin());
346 // Reorder the extruders to start with the last one.
347 for (size_t i = 1; i < lt.extruders.size(); ++ i)
348 if (lt.extruders[i] == last_extruder_id) {
349 // Move the last extruder to the front.
350 memmove(lt.extruders.data() + 1, lt.extruders.data(), i * sizeof(unsigned int));
351 lt.extruders.front() = last_extruder_id;
352 break;
353 }
354
355 // On first layer with wipe tower, prefer a soluble extruder
356 // at the beginning, so it is not wiped on the first layer.
357 if (lt == m_layer_tools[0] && m_print_config_ptr && m_print_config_ptr->wipe_tower) {
358 for (size_t i = 0; i<lt.extruders.size(); ++i)
359 if (m_print_config_ptr->filament_soluble.get_at(lt.extruders[i]-1)) { // 1-based...
360 std::swap(lt.extruders[i], lt.extruders.front());
361 break;
362 }
363 }
364 }
365 last_extruder_id = lt.extruders.back();
366 }
367
368 // Reindex the extruders, so they are zero based, not 1 based.
369 for (LayerTools &lt : m_layer_tools)
370 for (unsigned int &extruder_id : lt.extruders) {
371 assert(extruder_id > 0);
372 -- extruder_id;
373 }
374}

References Slic3r::LayerTools::extruders, m_layer_tools, and m_print_config_ptr.

Referenced by ToolOrdering(), and ToolOrdering().

+ Here is the caller graph for this function:

◆ tools_for_layer() [1/2]

LayerTools & Slic3r::ToolOrdering::tools_for_layer ( coordf_t  print_z)
inline
155{ return const_cast<LayerTools&>(std::as_const(*this).tools_for_layer(print_z)); }

◆ tools_for_layer() [2/2]

const LayerTools & Slic3r::ToolOrdering::tools_for_layer ( coordf_t  print_z) const
629{
630 auto it_layer_tools = std::lower_bound(m_layer_tools.begin(), m_layer_tools.end(), LayerTools(print_z - EPSILON));
631 assert(it_layer_tools != m_layer_tools.end());
632 coordf_t dist_min = std::abs(it_layer_tools->print_z - print_z);
633 for (++ it_layer_tools; it_layer_tools != m_layer_tools.end(); ++ it_layer_tools) {
634 coordf_t d = std::abs(it_layer_tools->print_z - print_z);
635 if (d >= dist_min)
636 break;
637 dist_min = d;
638 }
639 -- it_layer_tools;
640 assert(dist_min < EPSILON);
641 return *it_layer_tools;
642}

References EPSILON, and m_layer_tools.

Referenced by collect_extruders(), Slic3r::GCode::process_layers(), and Slic3r::GCode::process_layers().

+ Here is the caller graph for this function:

Member Data Documentation

◆ m_all_printing_extruders

std::vector<unsigned int> Slic3r::ToolOrdering::m_all_printing_extruders
private

◆ m_first_printing_extruder

unsigned int Slic3r::ToolOrdering::m_first_printing_extruder = (unsigned int)-1
private

◆ m_last_printing_extruder

unsigned int Slic3r::ToolOrdering::m_last_printing_extruder = (unsigned int)-1
private

◆ m_layer_tools

◆ m_print_config_ptr

const PrintConfig* Slic3r::ToolOrdering::m_print_config_ptr = nullptr
private

The documentation for this class was generated from the following files: