diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index b06232a92..1271ee9ee 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -764,7 +764,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) } // Extrude the layers. for (auto &layer : layers_to_print) { - const ToolOrdering::LayerTools &layer_tools = tool_ordering.tools_for_layer(layer.first); + const LayerTools &layer_tools = tool_ordering.tools_for_layer(layer.first); if (m_wipe_tower && layer_tools.has_wipe_tower) m_wipe_tower->next_layer(); this->process_layer(file, print, layer.second, layer_tools, size_t(-1)); @@ -1009,7 +1009,7 @@ void GCode::process_layer( const Print &print, // Set of object & print layers of the same PrintObject and with the same print_z. const std::vector<LayerToPrint> &layers, - const ToolOrdering::LayerTools &layer_tools, + const LayerTools &layer_tools, // If set to size_t(-1), then print all copies of all objects. // Otherwise print a single copy of a single object. const size_t single_object_idx) @@ -1239,18 +1239,20 @@ void GCode::process_layer( continue; // This extrusion is part of certain Region, which tells us which extruder should be used for it: - 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) : + 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); // Let's recover vector of extruder overrides: - const ExtruderPerCopy* entity_overrides = const_cast<ToolOrdering::LayerTools&>(layer_tools).wiping_extrusions.get_extruder_overrides(fill, correct_extruder_id, layer_to_print.object()->_shifted_copies.size()); + const ExtruderPerCopy* entity_overrides = const_cast<LayerTools&>(layer_tools).wiping_extrusions.get_extruder_overrides(fill, correct_extruder_id, layer_to_print.object()->_shifted_copies.size()); // Now we must add this extrusion into the by_extruder map, once for each extruder that will print it: for (unsigned int extruder : layer_tools.extruders) { // Init by_extruder item only if we actually use the extruder: - if (std::find(entity_overrides->begin(), entity_overrides->end(), extruder) != entity_overrides->end() || // at least one copy is overridden to use this extruder - std::find(entity_overrides->begin(), entity_overrides->end(), -extruder-1) != entity_overrides->end()) // at least one copy would normally be printed with this extruder (see get_extruder_overrides function for explanation) + if (std::find(entity_overrides->begin(), entity_overrides->end(), extruder) != entity_overrides->end() || // at least one copy is overridden to use this extruder + std::find(entity_overrides->begin(), entity_overrides->end(), -extruder-1) != entity_overrides->end() || // at least one copy would normally be printed with this extruder (see get_extruder_overrides function for explanation) + (std::find(layer_tools.extruders.begin(), layer_tools.extruders.end(), correct_extruder_id) == layer_tools.extruders.end() && extruder == layer_tools.extruders.back())) // this entity is not overridden, but its extruder is not in layer_tools - we'll print it + //by last extruder on this layer (could happen e.g. when a wiping object is taller than others - dontcare extruders are eradicated from layer_tools) { std::vector<ObjectByExtruder::Island> &islands = object_islands_by_extruder( by_extruder, diff --git a/xs/src/libslic3r/GCode.hpp b/xs/src/libslic3r/GCode.hpp index ad3f1e26b..a5c63f208 100644 --- a/xs/src/libslic3r/GCode.hpp +++ b/xs/src/libslic3r/GCode.hpp @@ -185,7 +185,7 @@ protected: const Print &print, // Set of object & print layers of the same PrintObject and with the same print_z. const std::vector<LayerToPrint> &layers, - const ToolOrdering::LayerTools &layer_tools, + const LayerTools &layer_tools, // If set to size_t(-1), then print all copies of all objects. // Otherwise print a single copy of a single object. const size_t single_object_idx = size_t(-1)); diff --git a/xs/src/libslic3r/GCode/ToolOrdering.cpp b/xs/src/libslic3r/GCode/ToolOrdering.cpp index 719f7a97a..34bb32e65 100644 --- a/xs/src/libslic3r/GCode/ToolOrdering.cpp +++ b/xs/src/libslic3r/GCode/ToolOrdering.cpp @@ -48,6 +48,7 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude // (print.config.complete_objects is false). ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool prime_multi_material) { + m_print_config_ptr = &print.config; // Initialize the print layers for all objects and all layers. coordf_t object_bottom_z = 0.; { @@ -77,9 +78,9 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool } -ToolOrdering::LayerTools& ToolOrdering::tools_for_layer(coordf_t print_z) +LayerTools& ToolOrdering::tools_for_layer(coordf_t print_z) { - auto it_layer_tools = std::lower_bound(m_layer_tools.begin(), m_layer_tools.end(), ToolOrdering::LayerTools(print_z - EPSILON)); + auto it_layer_tools = std::lower_bound(m_layer_tools.begin(), m_layer_tools.end(), LayerTools(print_z - EPSILON)); assert(it_layer_tools != m_layer_tools.end()); coordf_t dist_min = std::abs(it_layer_tools->print_z - print_z); for (++ it_layer_tools; it_layer_tools != m_layer_tools.end(); ++it_layer_tools) { @@ -103,7 +104,7 @@ void ToolOrdering::initialize_layers(std::vector<coordf_t> &zs) coordf_t zmax = zs[i] + EPSILON; for (; j < zs.size() && zs[j] <= zmax; ++ j) ; // Assign an average print_z to the set of layers with nearly equal print_z. - m_layer_tools.emplace_back(LayerTools(0.5 * (zs[i] + zs[j-1]))); + m_layer_tools.emplace_back(LayerTools(0.5 * (zs[i] + zs[j-1]), m_print_config_ptr)); i = j; } } @@ -135,12 +136,25 @@ void ToolOrdering::collect_extruders(const PrintObject &object) if (layerm == nullptr) continue; const PrintRegion ®ion = *object.print()->regions[region_id]; + if (! layerm->perimeters.entities.empty()) { - layer_tools.extruders.push_back(region.config.perimeter_extruder.value); + bool something_nonoverriddable = false; + for (const auto& eec : layerm->perimeters.entities) // let's check if there are nonoverriddable entities + if (!layer_tools.wiping_extrusions.is_overriddable(dynamic_cast<const ExtrusionEntityCollection&>(*eec), *m_print_config_ptr, object, region)) { + something_nonoverriddable = true; + break; + } + + if (something_nonoverriddable) + layer_tools.extruders.push_back(region.config.perimeter_extruder.value); + layer_tools.has_object = true; } + + bool has_infill = false; bool has_solid_infill = false; + bool something_nonoverriddable = false; for (const ExtrusionEntity *ee : layerm->fills.entities) { // fill represents infill extrusions of a single island. const auto *fill = dynamic_cast<const ExtrusionEntityCollection*>(ee); @@ -149,19 +163,32 @@ void ToolOrdering::collect_extruders(const PrintObject &object) has_solid_infill = true; else if (role != erNone) has_infill = true; + + if (!something_nonoverriddable && !layer_tools.wiping_extrusions.is_overriddable(*fill, *m_print_config_ptr, object, region)) + something_nonoverriddable = true; + } + if (something_nonoverriddable) + { + if (has_solid_infill) + layer_tools.extruders.push_back(region.config.solid_infill_extruder); + if (has_infill) + layer_tools.extruders.push_back(region.config.infill_extruder); } - if (has_solid_infill) - layer_tools.extruders.push_back(region.config.solid_infill_extruder); - if (has_infill) - layer_tools.extruders.push_back(region.config.infill_extruder); if (has_solid_infill || has_infill) layer_tools.has_object = true; } } - // Sort and remove duplicates - for (LayerTools < : m_layer_tools) - sort_remove_duplicates(lt.extruders); + // Sort and remove duplicates, make sure that there are some tools for each object layer (e.g. tall wiping object will result in empty extruders vector) + for (auto lt_it=m_layer_tools.begin(); lt_it != m_layer_tools.end(); ++lt_it) { + sort_remove_duplicates(lt_it->extruders); + + if (lt_it->extruders.empty() && lt_it->has_object) + if (lt_it != m_layer_tools.begin()) + lt_it->extruders.push_back(std::prev(lt_it)->extruders.back()); + else + lt_it->extruders.push_back(1); + } } // Reorder extruders to minimize layer changes. @@ -348,6 +375,151 @@ void WipingExtrusions::set_extruder_override(const ExtrusionEntity* entity, unsi } +// Finds last non-soluble extruder on the layer +bool WipingExtrusions::is_last_nonsoluble_on_layer(const PrintConfig& print_config, const LayerTools& lt, unsigned int extruder) const { + for (auto extruders_it = lt.extruders.rbegin(); extruders_it != lt.extruders.rend(); ++extruders_it) + if (!print_config.filament_soluble.get_at(*extruders_it)) + return (*extruders_it == extruder); + return false; +} + + +// Decides whether this entity could be overridden +bool WipingExtrusions::is_overriddable(const ExtrusionEntityCollection& eec, const PrintConfig& print_config, const PrintObject& object, const PrintRegion& region) const { + if ((!is_infill(eec.role()) && !object.config.wipe_into_objects) || + ((eec.role() == erTopSolidInfill || eec.role() == erGapFill) && !object.config.wipe_into_objects) || + (is_infill(eec.role()) && !region.config.wipe_into_infill) || + (print_config.filament_soluble.get_at(get_extruder(eec, region))) ) + return false; + + return true; +} + + +// Following function iterates through all extrusions on the layer, remembers those that could be used for wiping after toolchange +// and returns volume that is left to be wiped on the wipe tower. +float WipingExtrusions::mark_wiping_extrusions(const Print& print, const LayerTools& layer_tools, unsigned int new_extruder, float volume_to_wipe) +{ + const float min_infill_volume = 0.f; // ignore infill with smaller volume than this + + if (print.config.filament_soluble.get_at(new_extruder)) + return volume_to_wipe; // Soluble filament cannot be wiped in a random infill + + bool last_nonsoluble = is_last_nonsoluble_on_layer(print.config, layer_tools, new_extruder); + + // we will sort objects so that dedicated for wiping are at the beginning: + PrintObjectPtrs object_list = print.objects; + std::sort(object_list.begin(), object_list.end(), [](const PrintObject* a, const PrintObject* b) { return a->config.wipe_into_objects; }); + + + // We will now iterate through + // - first the dedicated objects 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 all the others to mark infills (in case that !infill_first, we must also check that the perimeter is finished already + // this is controlled by the following variable: + bool perimeters_done = false; + + for (int i=0 ; i<(int)object_list.size() ; ++i) { + const auto& object = object_list[i]; + + if (!perimeters_done && (i+1==(int)object_list.size() || !object_list[i]->config.wipe_into_objects)) { // we passed the last dedicated object in list + perimeters_done = true; + i=-1; // let's go from the start again + continue; + } + + // 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 (this_layer_it == object->layers.end()) + continue; + const Layer* this_layer = *this_layer_it; + 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 (size_t region_id = 0; region_id < object->print()->regions.size(); ++ region_id) { + const auto& region = *object->print()->regions[region_id]; + + if (!region.config.wipe_into_infill && !object->config.wipe_into_objects) + continue; + + + if (((!print.config.infill_first ? perimeters_done : !perimeters_done) || !object->config.wipe_into_objects) && region.config.wipe_into_infill) { + const ExtrusionEntityCollection& eec = this_layer->regions[region_id]->fills; + for (const ExtrusionEntity* ee : eec.entities) { // iterate through all infill Collections + auto* fill = dynamic_cast<const ExtrusionEntityCollection*>(ee); + + if (fill->role() == erTopSolidInfill || fill->role() == erGapFill) // these cannot be changed - such infill is / may be visible + continue; + + // What extruder would this normally be printed with? + unsigned int correct_extruder = get_extruder(*fill, region); + + bool force_override = false; + // If the extruder is not in layer tools - we MUST override it. This happens whenever all extrusions, that would normally + // be printed with this extruder on this layer are "dont care" (part of infill/perimeter wiping): + if (last_nonsoluble && std::find(layer_tools.extruders.begin(), layer_tools.extruders.end(), correct_extruder) == layer_tools.extruders.end()) + force_override = true; + if (!force_override && volume_to_wipe<=0) + continue; + + if (!is_overriddable(*fill, print.config, *object, region)) + continue; + + if (!object->config.wipe_into_objects && !print.config.infill_first && !force_override) { + // 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 ((!print.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 (force_override || (!is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume)) { // this infill will be used to wipe this extruder + set_extruder_override(fill, copy, new_extruder, num_of_copies); + volume_to_wipe -= fill->total_volume(); + } + } + } + + + if (object->config.wipe_into_objects && (print.config.infill_first ? perimeters_done : !perimeters_done)) + { + const ExtrusionEntityCollection& eec = this_layer->regions[region_id]->perimeters; + for (const ExtrusionEntity* ee : eec.entities) { // iterate through all perimeter Collections + auto* fill = dynamic_cast<const ExtrusionEntityCollection*>(ee); + // What extruder would this normally be printed with? + unsigned int correct_extruder = get_extruder(*fill, region); + bool force_override = false; + if (last_nonsoluble && std::find(layer_tools.extruders.begin(), layer_tools.extruders.end(), correct_extruder) == layer_tools.extruders.end()) + force_override = true; + if (!force_override && volume_to_wipe<=0) + continue; + + if (!is_overriddable(*fill, print.config, *object, region)) + continue; + + if (force_override || (!is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume)) { + set_extruder_override(fill, copy, new_extruder, num_of_copies); + volume_to_wipe -= fill->total_volume(); + } + } + } + } + } + } + return std::max(0.f, volume_to_wipe); +} + + + // 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 diff --git a/xs/src/libslic3r/GCode/ToolOrdering.hpp b/xs/src/libslic3r/GCode/ToolOrdering.hpp index 241567a75..862b58f67 100644 --- a/xs/src/libslic3r/GCode/ToolOrdering.hpp +++ b/xs/src/libslic3r/GCode/ToolOrdering.hpp @@ -9,6 +9,8 @@ namespace Slic3r { class Print; class PrintObject; +class LayerTools; + // Object of this class holds information about whether an extrusion is printed immediately @@ -16,65 +18,74 @@ class PrintObject; // of several copies - this has to be taken into account. class WipingExtrusions { - public: +public: 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; } + // 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: + float mark_wiping_extrusions(const Print& print, const LayerTools& layer_tools, unsigned int new_extruder, float volume_to_wipe); + + bool is_overriddable(const ExtrusionEntityCollection& ee, const PrintConfig& print_config, const PrintObject& object, const PrintRegion& region) const; + +private: + bool is_last_nonsoluble_on_layer(const PrintConfig& print_config, const LayerTools& lt, unsigned int extruder) const; + + // 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); + // 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); } - // This function is called from Print::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); - - // 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); - -private: std::map<const ExtrusionEntity*, std::vector<int>> entity_map; // to keep track of who prints what bool something_overridden = false; }; -class ToolOrdering +class LayerTools { public: - struct LayerTools - { - LayerTools(const coordf_t z) : - print_z(z), - has_object(false), - has_support(false), - has_wipe_tower(false), - wipe_tower_partitions(0), - wipe_tower_layer_height(0.) {} + 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.) {} - bool operator< (const LayerTools &rhs) const { return print_z < rhs.print_z; } - bool operator==(const LayerTools &rhs) const { return print_z == rhs.print_z; } + bool operator< (const LayerTools &rhs) const { return print_z - EPSILON < rhs.print_z; } + bool operator==(const LayerTools &rhs) const { return std::abs(print_z - rhs.print_z) < EPSILON; } - 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; + 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; + + // This object holds list of extrusion that will be used for extruder wiping + WipingExtrusions wiping_extrusions; +}; - // This holds list of extrusion that will be used for extruder wiping - WipingExtrusions wiping_extrusions; - - }; +class ToolOrdering +{ +public: ToolOrdering() {} // For the use case when each object is printed separately @@ -114,17 +125,22 @@ private: 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); - void collect_extruder_statistics(bool prime_multi_material); + 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; + 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; }; + + } // namespace SLic3r #endif /* slic3r_ToolOrdering_hpp_ */ diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index dac48bfd3..fcbe74b85 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -1064,7 +1064,7 @@ void Print::_make_wipe_tower() size_t idx_end = m_tool_ordering.layer_tools().size(); // Find the first wipe tower layer, which does not have a counterpart in an object or a support layer. for (size_t i = 0; i < idx_end; ++ i) { - const ToolOrdering::LayerTools < = m_tool_ordering.layer_tools()[i]; + const LayerTools < = m_tool_ordering.layer_tools()[i]; if (lt.has_wipe_tower && ! lt.has_object && ! lt.has_support) { idx_begin = i; break; @@ -1078,7 +1078,7 @@ void Print::_make_wipe_tower() for (; it_layer != it_end && (*it_layer)->print_z - EPSILON < wipe_tower_new_layer_print_z_first; ++ it_layer); // Find the stopper of the sequence of wipe tower layers, which do not have a counterpart in an object or a support layer. for (size_t i = idx_begin; i < idx_end; ++ i) { - ToolOrdering::LayerTools < = const_cast<ToolOrdering::LayerTools&>(m_tool_ordering.layer_tools()[i]); + LayerTools < = const_cast<LayerTools&>(m_tool_ordering.layer_tools()[i]); if (! (lt.has_wipe_tower && ! lt.has_object && ! lt.has_support)) break; lt.has_support = true; @@ -1137,7 +1137,7 @@ void Print::_make_wipe_tower() float volume_to_wipe = wipe_volumes[current_extruder_id][extruder_id]; // total volume to wipe after this toolchange if (!first_layer) // unless we're on the first layer, try to assign some infills/objects for the wiping: - volume_to_wipe = mark_wiping_extrusions(layer_tools, extruder_id, wipe_volumes[current_extruder_id][extruder_id]); + volume_to_wipe = layer_tools.wiping_extrusions.mark_wiping_extrusions(*this, layer_tools, extruder_id, wipe_volumes[current_extruder_id][extruder_id]); wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, extruder_id, first_layer && extruder_id == m_tool_ordering.all_extruders().back(), volume_to_wipe); current_extruder_id = extruder_id; @@ -1173,114 +1173,7 @@ void Print::_make_wipe_tower() } -// Following function iterates through all extrusions on the layer, remembers those that could be used for wiping after toolchange -// 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) -{ - const float min_infill_volume = 0.f; // ignore infill with smaller volume than this - if (config.filament_soluble.get_at(new_extruder)) - 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; }); - - - // We will now iterate through 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==object_list.size() || !object_list[i]->config.wipe_into_objects)) { // we passed the last dedicated object in list - perimeters_done = true; - i=-1; // let's go from the start again - continue; - } - - // 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 (this_layer_it == object->layers.end()) - continue; - const Layer* this_layer = *this_layer_it; - 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 (size_t region_id = 0; region_id < object->print()->regions.size(); ++ region_id) { - const auto& region = *object->print()->regions[region_id]; - - if (!region.config.wipe_into_infill && !object->config.wipe_into_objects) - continue; - - - 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; - for (ExtrusionEntity* ee : eec.entities) { // iterate through all infill Collections - if (volume_to_wipe <= 0.f) - return 0.f; - auto* fill = dynamic_cast<ExtrusionEntityCollection*>(ee); - if (fill->role() == erTopSolidInfill || fill->role() == erGapFill) // these cannot be changed - such infill is / may be visible - continue; - - // 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); - volume_to_wipe -= fill->total_volume(); - } - } - } - - - if (object->config.wipe_into_objects && (config.infill_first ? perimeters_done : !perimeters_done)) - { - ExtrusionEntityCollection& eec = this_layer->regions[region_id]->perimeters; - for (ExtrusionEntity* ee : eec.entities) { // iterate through all perimeter Collections - if (volume_to_wipe <= 0.f) - return 0.f; - auto* fill = dynamic_cast<ExtrusionEntityCollection*>(ee); - // 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); - volume_to_wipe -= fill->total_volume(); - } - } - } - } - } - } - return std::max(0.f, volume_to_wipe); -} std::string Print::output_filename() diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp index 8ae9b3689..f90fb500f 100644 --- a/xs/src/libslic3r/Print.hpp +++ b/xs/src/libslic3r/Print.hpp @@ -318,19 +318,15 @@ private: bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys); PrintRegionConfig _region_config_from_model_volume(const ModelVolume &volume); - // 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: - float mark_wiping_extrusions(ToolOrdering::LayerTools& layer_tools, unsigned int new_extruder, float volume_to_wipe); - // Has the calculation been 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 ®ion) { - 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); +static int get_extruder(const ExtrusionEntityCollection& fill, const PrintRegion ®ion) { + 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); }