Assigning of wiping extrusions improved

This commit is contained in:
Lukas Matena 2018-06-21 10:16:52 +02:00
parent 8a47852be2
commit bc5bd1b42b
6 changed files with 101 additions and 78 deletions

View File

@ -1239,7 +1239,7 @@ void GCode::process_layer(
continue; continue;
// This extrusion is part of certain Region, which tells us which extruder should be used for it: // This extrusion is part of certain Region, which tells us which extruder should be used for it:
int correct_extruder_id = entity_type=="infills" ? std::max<int>(0, (is_solid_infill(fill->entities.front()->role()) ? region.config.solid_infill_extruder : region.config.infill_extruder) - 1) : int correct_extruder_id = get_extruder(fill, region); entity_type=="infills" ? std::max<int>(0, (is_solid_infill(fill->entities.front()->role()) ? region.config.solid_infill_extruder : region.config.infill_extruder) - 1) :
std::max<int>(region.config.perimeter_extruder.value - 1, 0); std::max<int>(region.config.perimeter_extruder.value - 1, 0);
// Let's recover vector of extruder overrides: // Let's recover vector of extruder overrides:

View File

@ -330,42 +330,44 @@ void ToolOrdering::collect_extruder_statistics(bool prime_multi_material)
} }
} }
// This function is called from Print::mark_wiping_extrusions and sets extruder that it should be printed with (-1 .. as usual)
void WipingExtrusions::set_extruder_override(const ExtrusionEntity* entity, unsigned int copy_id, int extruder, unsigned int num_of_copies) {
something_overridden = true;
auto entity_map_it = (entity_map.insert(std::make_pair(entity, std::vector<int>()))).first; // (add and) return iterator
auto& copies_vector = entity_map_it->second;
if (copies_vector.size() < num_of_copies)
copies_vector.resize(num_of_copies, -1);
if (copies_vector[copy_id] != -1) // This function is called from Print::mark_wiping_extrusions and sets extruder this entity should be printed with (-1 .. as usual)
std::cout << "ERROR: Entity extruder overriden multiple times!!!\n"; // A debugging message - this must never happen. void WipingExtrusions::set_extruder_override(const ExtrusionEntity* entity, unsigned int copy_id, int extruder, unsigned int num_of_copies) {
something_overridden = true;
copies_vector[copy_id] = extruder; auto entity_map_it = (entity_map.insert(std::make_pair(entity, std::vector<int>()))).first; // (add and) return iterator
} auto& copies_vector = entity_map_it->second;
if (copies_vector.size() < num_of_copies)
copies_vector.resize(num_of_copies, -1);
if (copies_vector[copy_id] != -1)
std::cout << "ERROR: Entity extruder overriden multiple times!!!\n"; // A debugging message - this must never happen.
copies_vector[copy_id] = extruder;
}
// Following function is called from process_layer and returns pointer to vector with information about which extruders should be used for given copy of this entity. // Following function is called from process_layer and returns pointer to vector with information about which extruders should be used for given copy of this entity.
// It first makes sure the pointer is valid (creates the vector if it does not exist) and contains a record for each copy // It first makes sure the pointer is valid (creates the vector if it does not exist) and contains a record for each copy
// It also modifies the vector in place and changes all -1 to correct_extruder_id (at the time the overrides were created, correct extruders were not known, // It also modifies the vector in place and changes all -1 to correct_extruder_id (at the time the overrides were created, correct extruders were not known,
// so -1 was used as "print as usual". // so -1 was used as "print as usual".
// The resulting vector has to keep track of which extrusions are the ones that were overridden and which were not. In the extruder is used as overridden, // The resulting vector has to keep track of which extrusions are the ones that were overridden and which were not. In the extruder is used as overridden,
// its number is saved as it is (zero-based index). Usual extrusions are saved as -number-1 (unfortunately there is no negative zero). // its number is saved as it is (zero-based index). Usual extrusions are saved as -number-1 (unfortunately there is no negative zero).
const std::vector<int>* WipingExtrusions::get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, int num_of_copies) { const std::vector<int>* WipingExtrusions::get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, int num_of_copies) {
auto entity_map_it = entity_map.find(entity); auto entity_map_it = entity_map.find(entity);
if (entity_map_it == entity_map.end()) if (entity_map_it == entity_map.end())
entity_map_it = (entity_map.insert(std::make_pair(entity, std::vector<int>()))).first; entity_map_it = (entity_map.insert(std::make_pair(entity, std::vector<int>()))).first;
// Now the entity_map_it should be valid, let's make sure the vector is long enough: // Now the entity_map_it should be valid, let's make sure the vector is long enough:
entity_map_it->second.resize(num_of_copies, -1); entity_map_it->second.resize(num_of_copies, -1);
// Each -1 now means "print as usual" - we will replace it with actual extruder id (shifted it so we don't lose that information): // Each -1 now means "print as usual" - we will replace it with actual extruder id (shifted it so we don't lose that information):
std::replace(entity_map_it->second.begin(), entity_map_it->second.end(), -1, -correct_extruder_id-1); std::replace(entity_map_it->second.begin(), entity_map_it->second.end(), -1, -correct_extruder_id-1);
return &(entity_map_it->second); return &(entity_map_it->second);
} }
} // namespace Slic3r } // namespace Slic3r

View File

@ -11,7 +11,6 @@ class Print;
class PrintObject; class PrintObject;
// Object of this class holds information about whether an extrusion is printed immediately // 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 // 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. // of several copies - this has to be taken into account.

View File

@ -1177,66 +1177,50 @@ void Print::_make_wipe_tower()
// and returns volume that is left to be wiped on the wipe tower. // and returns volume that is left to be wiped on the wipe tower.
float Print::mark_wiping_extrusions(ToolOrdering::LayerTools& layer_tools, unsigned int new_extruder, float volume_to_wipe) float Print::mark_wiping_extrusions(ToolOrdering::LayerTools& layer_tools, unsigned int new_extruder, float volume_to_wipe)
{ {
// Strategy for wiping (TODO):
// if !infill_first
// start with dedicated objects
// print a perimeter and its corresponding infill immediately after
// repeat until there are no dedicated objects left
// if there are some left and this is the last toolchange on the layer, mark all remaining extrusions of the object (so we don't have to travel back to it later)
// move to normal objects
// start with one object and start assigning its infill, if their perimeters ARE ALREADY EXTRUDED
// never touch perimeters
//
// if infill first
// start with dedicated objects
// print an infill and its corresponding perimeter immediately after
// repeat until you run out of infills
// move to normal objects
// start assigning infills (one copy after another)
// repeat until you run out of infills, leave perimeters be
const float min_infill_volume = 0.f; // ignore infill with smaller volume than this const float min_infill_volume = 0.f; // ignore infill with smaller volume than this
if (config.filament_soluble.get_at(new_extruder)) if (config.filament_soluble.get_at(new_extruder))
return volume_to_wipe; // Soluble filament cannot be wiped in a random infill return volume_to_wipe; // Soluble filament cannot be wiped in a random infill
PrintObjectPtrs object_list = objects;
// sort objects so that dedicated for wiping are at the beginning:
std::sort(object_list.begin(), object_list.end(), [](const PrintObject* a, const PrintObject* b) { return a->config.wipe_into_objects; });
for (size_t i = 0; i < objects.size(); ++ i) { // Let's iterate through all objects... // We will now iterate through objects
if (!objects[i]->config.wipe_into_infill && !objects[i]->config.wipe_into_objects) // - first through the dedicated ones to mark perimeters or infills (depending on infill_first)
// - second through the dedicated ones again to mark infills or perimeters (depending on infill_first)
// - then for the others to mark infills
// this is controlled by the following variable:
bool perimeters_done = false;
for (int i=0 ; i<(int)object_list.size() ; ++i) { // Let's iterate through all objects...
const auto& object = object_list[i];
if (!perimeters_done && (i+1==objects.size() || !objects[i+1]->config.wipe_into_objects)) { // last dedicated object in list
perimeters_done = true;
i=-1; // let's go from the start again
continue; continue;
}
Layer* this_layer = nullptr; // Finds this layer:
for (unsigned int a = 0; a < objects[i]->layers.size(); ++a) // Finds this layer auto this_layer_it = std::find_if(object->layers.begin(), object->layers.end(), [&layer_tools](const Layer* lay) { return std::abs(layer_tools.print_z - lay->print_z)<EPSILON; });
if (std::abs(layer_tools.print_z - objects[i]->layers[a]->print_z) < EPSILON) { if (this_layer_it == object->layers.end())
this_layer = objects[i]->layers[a];
break;
}
if (this_layer == nullptr)
continue; continue;
const Layer* this_layer = *this_layer_it;
unsigned int num_of_copies = objects[i]->_shifted_copies.size(); unsigned int num_of_copies = object->_shifted_copies.size();
for (unsigned int copy = 0; copy < num_of_copies; ++copy) { // iterate through copies first, so that we mark neighbouring infills to minimize travel moves for (unsigned int copy = 0; copy < num_of_copies; ++copy) { // iterate through copies first, so that we mark neighbouring infills to minimize travel moves
for (size_t region_id = 0; region_id < objects[i]->print()->regions.size(); ++ region_id) { for (size_t region_id = 0; region_id < object->print()->regions.size(); ++ region_id) {
unsigned int region_extruder = objects[i]->print()->regions[region_id]->config.infill_extruder - 1; // config value is 1-based const auto& region = *object->print()->regions[region_id];
if (config.filament_soluble.get_at(region_extruder)) // if this entity is meant to be soluble, keep it that way
if (!region.config.wipe_into_infill && !object->config.wipe_into_objects)
continue; continue;
if (!config.infill_first) { // in this case we must verify that region_extruder was already used at this layer (and perimeters of the infill are therefore extruded)
bool unused_yet = false;
for (unsigned i = 0; i < layer_tools.extruders.size(); ++i) {
if (layer_tools.extruders[i] == new_extruder)
unused_yet = true;
if (layer_tools.extruders[i] == region_extruder)
break;
}
if (unused_yet)
continue;
}
if (objects[i]->config.wipe_into_infill) { if (((!config.infill_first ? perimeters_done : !perimeters_done) || !object->config.wipe_into_objects) && region.config.wipe_into_infill) {
ExtrusionEntityCollection& eec = this_layer->regions[region_id]->fills; ExtrusionEntityCollection& eec = this_layer->regions[region_id]->fills;
for (ExtrusionEntity* ee : eec.entities) { // iterate through all infill Collections for (ExtrusionEntity* ee : eec.entities) { // iterate through all infill Collections
if (volume_to_wipe <= 0.f) if (volume_to_wipe <= 0.f)
@ -1244,21 +1228,49 @@ float Print::mark_wiping_extrusions(ToolOrdering::LayerTools& layer_tools, unsig
auto* fill = dynamic_cast<ExtrusionEntityCollection*>(ee); auto* fill = dynamic_cast<ExtrusionEntityCollection*>(ee);
if (fill->role() == erTopSolidInfill || fill->role() == erGapFill) // these cannot be changed - such infill is / may be visible if (fill->role() == erTopSolidInfill || fill->role() == erGapFill) // these cannot be changed - such infill is / may be visible
continue; continue;
if (/*!fill->is_extruder_overridden(copy)*/ !layer_tools.wiping_extrusions.is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume) { // this infill will be used to wipe this extruder
// What extruder would this normally be printed with?
unsigned int correct_extruder = get_extruder(fill, region);
if (config.filament_soluble.get_at(correct_extruder)) // if this entity is meant to be soluble, keep it that way
continue;
if (!object->config.wipe_into_objects && !config.infill_first) {
// In this case we must check that the original extruder is used on this layer before the one we are overridding
// (and the perimeters will be finished before the infill is printed):
if (!config.infill_first && region.config.wipe_into_infill) {
bool unused_yet = false;
for (unsigned i = 0; i < layer_tools.extruders.size(); ++i) {
if (layer_tools.extruders[i] == new_extruder)
unused_yet = true;
if (layer_tools.extruders[i] == correct_extruder)
break;
}
if (unused_yet)
continue;
}
}
if (!layer_tools.wiping_extrusions.is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume) { // this infill will be used to wipe this extruder
layer_tools.wiping_extrusions.set_extruder_override(fill, copy, new_extruder, num_of_copies); layer_tools.wiping_extrusions.set_extruder_override(fill, copy, new_extruder, num_of_copies);
volume_to_wipe -= fill->total_volume(); volume_to_wipe -= fill->total_volume();
} }
} }
} }
if (objects[i]->config.wipe_into_objects)
if ((config.infill_first ? perimeters_done : !perimeters_done) && object->config.wipe_into_objects)
{ {
ExtrusionEntityCollection& eec = this_layer->regions[region_id]->perimeters; ExtrusionEntityCollection& eec = this_layer->regions[region_id]->perimeters;
for (ExtrusionEntity* ee : eec.entities) { // iterate through all perimeter Collections for (ExtrusionEntity* ee : eec.entities) { // iterate through all perimeter Collections
if (volume_to_wipe <= 0.f) if (volume_to_wipe <= 0.f)
break; break;
auto* fill = dynamic_cast<ExtrusionEntityCollection*>(ee); auto* fill = dynamic_cast<ExtrusionEntityCollection*>(ee);
if (/*!fill->is_extruder_overridden(copy)*/ !layer_tools.wiping_extrusions.is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume) { // What extruder would this normally be printed with?
unsigned int correct_extruder = get_extruder(fill, region);
if (config.filament_soluble.get_at(correct_extruder)) // if this entity is meant to be soluble, keep it that way
continue;
if (!layer_tools.wiping_extrusions.is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume) {
layer_tools.wiping_extrusions.set_extruder_override(fill, copy, new_extruder, num_of_copies); layer_tools.wiping_extrusions.set_extruder_override(fill, copy, new_extruder, num_of_copies);
volume_to_wipe -= fill->total_volume(); volume_to_wipe -= fill->total_volume();
} }

View File

@ -24,6 +24,7 @@ class Print;
class PrintObject; class PrintObject;
class ModelObject; class ModelObject;
// Print step IDs for keeping track of the print state. // Print step IDs for keeping track of the print state.
enum PrintStep { enum PrintStep {
psSkirt, psBrim, psWipeTower, psCount, psSkirt, psBrim, psWipeTower, psCount,
@ -323,6 +324,15 @@ private:
tbb::atomic<bool> m_canceled; tbb::atomic<bool> m_canceled;
}; };
// Returns extruder this eec should be printed with, according to PrintRegion config
static int get_extruder(const ExtrusionEntityCollection* fill, const PrintRegion &region) {
return is_infill(fill->role()) ? std::max<int>(0, (is_solid_infill(fill->entities.front()->role()) ? region.config.solid_infill_extruder : region.config.infill_extruder) - 1) :
std::max<int>(region.config.perimeter_extruder.value - 1, 0);
}
#define FOREACH_BASE(type, container, iterator) for (type::const_iterator iterator = (container).begin(); iterator != (container).end(); ++iterator) #define FOREACH_BASE(type, container, iterator) for (type::const_iterator iterator = (container).begin(); iterator != (container).end(); ++iterator)
#define FOREACH_REGION(print, region) FOREACH_BASE(PrintRegionPtrs, (print)->regions, region) #define FOREACH_REGION(print, region) FOREACH_BASE(PrintRegionPtrs, (print)->regions, region)
#define FOREACH_OBJECT(print, object) FOREACH_BASE(PrintObjectPtrs, (print)->objects, object) #define FOREACH_OBJECT(print, object) FOREACH_BASE(PrintObjectPtrs, (print)->objects, object)

View File

@ -337,7 +337,6 @@ public:
ConfigOptionFloatOrPercent support_material_xy_spacing; ConfigOptionFloatOrPercent support_material_xy_spacing;
ConfigOptionFloat xy_size_compensation; ConfigOptionFloat xy_size_compensation;
ConfigOptionBool wipe_into_objects; ConfigOptionBool wipe_into_objects;
ConfigOptionBool wipe_into_infill;
protected: protected:
void initialize(StaticCacheBase &cache, const char *base_ptr) void initialize(StaticCacheBase &cache, const char *base_ptr)
@ -375,7 +374,6 @@ protected:
OPT_PTR(support_material_with_sheath); OPT_PTR(support_material_with_sheath);
OPT_PTR(xy_size_compensation); OPT_PTR(xy_size_compensation);
OPT_PTR(wipe_into_objects); OPT_PTR(wipe_into_objects);
OPT_PTR(wipe_into_infill);
} }
}; };
@ -418,6 +416,7 @@ public:
ConfigOptionFloatOrPercent top_infill_extrusion_width; ConfigOptionFloatOrPercent top_infill_extrusion_width;
ConfigOptionInt top_solid_layers; ConfigOptionInt top_solid_layers;
ConfigOptionFloatOrPercent top_solid_infill_speed; ConfigOptionFloatOrPercent top_solid_infill_speed;
ConfigOptionBool wipe_into_infill;
protected: protected:
void initialize(StaticCacheBase &cache, const char *base_ptr) void initialize(StaticCacheBase &cache, const char *base_ptr)
@ -456,6 +455,7 @@ protected:
OPT_PTR(top_infill_extrusion_width); OPT_PTR(top_infill_extrusion_width);
OPT_PTR(top_solid_infill_speed); OPT_PTR(top_solid_infill_speed);
OPT_PTR(top_solid_layers); OPT_PTR(top_solid_layers);
OPT_PTR(wipe_into_infill);
} }
}; };