2017-05-16 11:45:28 +00:00
|
|
|
// Ordering of the tools to minimize tool switches.
|
|
|
|
|
|
|
|
#ifndef slic3r_ToolOrdering_hpp_
|
|
|
|
#define slic3r_ToolOrdering_hpp_
|
|
|
|
|
2018-11-26 13:54:23 +00:00
|
|
|
#include "../libslic3r.h"
|
2017-05-16 11:45:28 +00:00
|
|
|
|
|
|
|
namespace Slic3r {
|
|
|
|
|
2017-05-25 20:27:53 +00:00
|
|
|
class Print;
|
|
|
|
class PrintObject;
|
2018-06-26 12:12:25 +00:00
|
|
|
class LayerTools;
|
|
|
|
|
2017-05-25 20:27:53 +00:00
|
|
|
|
2018-06-20 10:52:00 +00: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 12:12:25 +00:00
|
|
|
public:
|
2018-06-20 10:52:00 +00: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;
|
|
|
|
}
|
|
|
|
|
2018-06-26 12:12:25 +00:00
|
|
|
// This is called from GCode::process_layer - see implementation for further comments:
|
|
|
|
const std::vector<int>* get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, int num_of_copies);
|
|
|
|
|
|
|
|
// 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 09:05:39 +00:00
|
|
|
float mark_wiping_extrusions(const Print& print, unsigned int old_extruder, unsigned int new_extruder, float volume_to_wipe);
|
2018-06-26 12:12:25 +00:00
|
|
|
|
2018-07-11 12:46:13 +00:00
|
|
|
void ensure_perimeters_infills_order(const Print& print);
|
2018-06-29 10:26:22 +00:00
|
|
|
|
2018-06-26 12:12:25 +00:00
|
|
|
bool is_overriddable(const ExtrusionEntityCollection& ee, const PrintConfig& print_config, const PrintObject& object, const PrintRegion& region) const;
|
|
|
|
|
2018-07-11 12:46:13 +00:00
|
|
|
void set_layer_tools_ptr(const LayerTools* lt) { m_layer_tools = lt; }
|
|
|
|
|
2018-06-26 12:12:25 +00:00
|
|
|
private:
|
2018-07-11 12:46:13 +00: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 12:12:25 +00:00
|
|
|
|
|
|
|
// This function is called from mark_wiping_extrusions and sets extruder that it should be printed with (-1 .. as usual)
|
|
|
|
void set_extruder_override(const ExtrusionEntity* entity, unsigned int copy_id, int extruder, unsigned int num_of_copies);
|
|
|
|
|
2018-06-20 10:52:00 +00:00
|
|
|
// Returns true in case that entity is not printed with its usual extruder for a given copy:
|
|
|
|
bool is_entity_overridden(const ExtrusionEntity* entity, int copy_id) const {
|
|
|
|
return (entity_map.find(entity) == entity_map.end() ? false : entity_map.at(entity).at(copy_id) != -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::map<const ExtrusionEntity*, std::vector<int>> entity_map; // to keep track of who prints what
|
|
|
|
bool something_overridden = false;
|
2018-07-11 12:46:13 +00:00
|
|
|
const LayerTools* m_layer_tools; // so we know which LayerTools object this belongs to
|
2018-06-20 10:52:00 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-06-26 12:12:25 +00:00
|
|
|
class LayerTools
|
2017-05-16 11:45:28 +00:00
|
|
|
{
|
2017-05-23 13:00:01 +00:00
|
|
|
public:
|
2018-06-26 12:12:25 +00:00
|
|
|
LayerTools(const coordf_t z, const PrintConfig* print_config_ptr = nullptr) :
|
|
|
|
print_z(z),
|
|
|
|
has_object(false),
|
|
|
|
has_support(false),
|
|
|
|
has_wipe_tower(false),
|
|
|
|
wipe_tower_partitions(0),
|
|
|
|
wipe_tower_layer_height(0.) {}
|
|
|
|
|
2018-07-24 09:20:29 +00: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; }
|
2018-06-26 12:12:25 +00:00
|
|
|
|
2018-07-13 09:25:22 +00:00
|
|
|
bool is_extruder_order(unsigned int a, unsigned int b) const;
|
|
|
|
|
2018-06-26 12:12:25 +00:00
|
|
|
coordf_t print_z;
|
|
|
|
bool has_object;
|
|
|
|
bool has_support;
|
|
|
|
// Zero based extruder IDs, ordered to minimize tool switches.
|
|
|
|
std::vector<unsigned int> extruders;
|
|
|
|
// 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.
|
|
|
|
bool has_wipe_tower;
|
|
|
|
// Number of wipe tower partitions to support the required number of tool switches
|
|
|
|
// and to support the wipe tower partitions above this one.
|
|
|
|
size_t wipe_tower_partitions;
|
|
|
|
coordf_t wipe_tower_layer_height;
|
|
|
|
|
2018-07-11 12:46:13 +00:00
|
|
|
WipingExtrusions& wiping_extrusions() {
|
|
|
|
m_wiping_extrusions.set_layer_tools_ptr(this);
|
|
|
|
return m_wiping_extrusions;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2018-06-26 12:12:25 +00:00
|
|
|
// This object holds list of extrusion that will be used for extruder wiping
|
2018-07-11 12:46:13 +00:00
|
|
|
WipingExtrusions m_wiping_extrusions;
|
2018-06-26 12:12:25 +00:00
|
|
|
};
|
2017-05-23 13:00:01 +00:00
|
|
|
|
2018-06-26 12:12:25 +00:00
|
|
|
|
|
|
|
|
|
|
|
class ToolOrdering
|
|
|
|
{
|
|
|
|
public:
|
2019-08-16 14:17:37 +00:00
|
|
|
ToolOrdering() {}
|
|
|
|
|
|
|
|
// For the use case when each object is printed separately
|
|
|
|
// (print.config.complete_objects is true).
|
|
|
|
ToolOrdering(const PrintObject &object, unsigned int first_extruder = (unsigned int)-1, bool prime_multi_material = false);
|
|
|
|
|
|
|
|
// For the use case when all objects are printed at once.
|
|
|
|
// (print.config.complete_objects is false).
|
|
|
|
ToolOrdering(const Print &print, unsigned int first_extruder = (unsigned int)-1, bool prime_multi_material = false);
|
|
|
|
|
|
|
|
void clear() { m_layer_tools.clear(); }
|
|
|
|
|
|
|
|
// 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; }
|
|
|
|
|
|
|
|
// 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; }
|
|
|
|
|
|
|
|
// 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; }
|
|
|
|
|
|
|
|
template<class Self> static auto tools_for_layer(Self& self, coordf_t print_z) -> decltype (*self.m_layer_tools.begin())
|
|
|
|
{
|
|
|
|
auto it_layer_tools = std::lower_bound(self.m_layer_tools.begin(), self.m_layer_tools.end(), LayerTools(print_z - EPSILON));
|
|
|
|
assert(it_layer_tools != self.m_layer_tools.end());
|
|
|
|
coordf_t dist_min = std::abs(it_layer_tools->print_z - print_z);
|
|
|
|
for (++ it_layer_tools; it_layer_tools != self.m_layer_tools.end(); ++it_layer_tools) {
|
|
|
|
coordf_t d = std::abs(it_layer_tools->print_z - print_z);
|
|
|
|
if (d >= dist_min)
|
|
|
|
break;
|
|
|
|
dist_min = d;
|
|
|
|
}
|
|
|
|
-- it_layer_tools;
|
|
|
|
assert(dist_min < EPSILON);
|
|
|
|
return *it_layer_tools;
|
|
|
|
}
|
2017-05-16 13:30:03 +00:00
|
|
|
|
2019-08-16 14:17:37 +00:00
|
|
|
// Find LayerTools with the closest print_z.
|
|
|
|
LayerTools& tools_for_layer(coordf_t print_z) { return tools_for_layer(*this, print_z); }
|
|
|
|
const LayerTools& tools_for_layer(coordf_t print_z) const { return tools_for_layer(*this, print_z); }
|
2017-05-23 13:00:01 +00:00
|
|
|
|
2019-08-16 14:17:37 +00: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 13:00:01 +00:00
|
|
|
|
|
|
|
private:
|
2019-08-16 14:17:37 +00:00
|
|
|
void initialize_layers(std::vector<coordf_t> &zs);
|
|
|
|
void collect_extruders(const PrintObject &object);
|
|
|
|
void reorder_extruders(unsigned int last_extruder_id);
|
|
|
|
void fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z);
|
2018-06-26 12:12:25 +00:00
|
|
|
void collect_extruder_statistics(bool prime_multi_material);
|
|
|
|
|
|
|
|
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-23 13:00:01 +00:00
|
|
|
};
|
2017-05-16 11:45:28 +00:00
|
|
|
|
2018-06-26 12:12:25 +00:00
|
|
|
|
|
|
|
|
2017-05-16 11:45:28 +00:00
|
|
|
} // namespace SLic3r
|
|
|
|
|
|
|
|
#endif /* slic3r_ToolOrdering_hpp_ */
|