mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-12 01:07:57 -06:00
Refactoring of perimeters/infills wiping (ToolOrdering::WipingExtrusions now takes care of the agenda)
Squashed commit of the following: commit 931eb2684103e8571b4a2e9804765fef268361c3 Author: Lukas Matena <lukasmatena@seznam.cz> Date: Wed Jun 20 12:50:27 2018 +0200 ToolOrdering::WipingExtrusions now holds all information necessary for infill/perimeter wiping commit cc8becfbdd771f7e279434c8bd6be147e4b321ee Author: Lukas Matena <lukasmatena@seznam.cz> Date: Tue Jun 19 10:52:03 2018 +0200 Wiping is now done as normal print would be (less extra code in process_layer) commit 1b120754b0691cce46ee5e10f3840480c559ac1f Author: Lukas Matena <lukasmatena@seznam.cz> Date: Fri Jun 15 15:55:15 2018 +0200 Refactoring: ObjectByExtruder changed so that it is aware of the wiping extrusions commit 1641e326bb5e0a0c69d6bfc6efa23153dc2e4543 Author: Lukas Matena <lukasmatena@seznam.cz> Date: Thu Jun 14 12:22:18 2018 +0200 Refactoring: new class WipingExtrusion in ToolOrdering.hpp
This commit is contained in:
parent
29dd305aaa
commit
8a47852be2
8 changed files with 301 additions and 303 deletions
|
@ -93,19 +93,6 @@ public:
|
||||||
virtual Polyline as_polyline() const = 0;
|
virtual Polyline as_polyline() const = 0;
|
||||||
virtual double length() const = 0;
|
virtual double length() const = 0;
|
||||||
virtual double total_volume() const = 0;
|
virtual double total_volume() const = 0;
|
||||||
|
|
||||||
void set_entity_extruder_override(unsigned int copy, int extruder) {
|
|
||||||
if (copy+1 > extruder_override.size())
|
|
||||||
extruder_override.resize(copy+1, -1); // copy is zero-based index
|
|
||||||
extruder_override[copy] = extruder;
|
|
||||||
}
|
|
||||||
virtual int get_extruder_override(unsigned int copy) const { try { return extruder_override.at(copy); } catch (...) { return -1; } }
|
|
||||||
virtual bool is_extruder_overridden(unsigned int copy) const { try { return extruder_override.at(copy) != -1; } catch (...) { return false; } }
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Set this variable to explicitly state you want to use specific extruder for thie EE (used for MM infill wiping)
|
|
||||||
// Each member of the vector corresponds to the respective copy of the object
|
|
||||||
std::vector<int> extruder_override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<ExtrusionEntity*> ExtrusionEntitiesPtr;
|
typedef std::vector<ExtrusionEntity*> ExtrusionEntitiesPtr;
|
||||||
|
|
|
@ -90,13 +90,6 @@ public:
|
||||||
CONFESS("Calling length() on a ExtrusionEntityCollection");
|
CONFESS("Calling length() on a ExtrusionEntityCollection");
|
||||||
return 0.;
|
return 0.;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_extruder_override(unsigned int copy, int extruder) {
|
|
||||||
for (ExtrusionEntity* member : entities)
|
|
||||||
member->set_entity_extruder_override(copy, extruder);
|
|
||||||
}
|
|
||||||
virtual int get_extruder_override(unsigned int copy) const { return entities.front()->get_extruder_override(copy); }
|
|
||||||
virtual bool is_extruder_overridden(unsigned int copy) const { return entities.front()->is_extruder_overridden(copy); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1147,7 +1147,6 @@ void GCode::process_layer(
|
||||||
|
|
||||||
// Group extrusions by an extruder, then by an object, an island and a region.
|
// Group extrusions by an extruder, then by an object, an island and a region.
|
||||||
std::map<unsigned int, std::vector<ObjectByExtruder>> by_extruder;
|
std::map<unsigned int, std::vector<ObjectByExtruder>> by_extruder;
|
||||||
|
|
||||||
for (const LayerToPrint &layer_to_print : layers) {
|
for (const LayerToPrint &layer_to_print : layers) {
|
||||||
if (layer_to_print.support_layer != nullptr) {
|
if (layer_to_print.support_layer != nullptr) {
|
||||||
const SupportLayer &support_layer = *layer_to_print.support_layer;
|
const SupportLayer &support_layer = *layer_to_print.support_layer;
|
||||||
|
@ -1225,92 +1224,63 @@ void GCode::process_layer(
|
||||||
continue;
|
continue;
|
||||||
const PrintRegion ®ion = *print.regions[region_id];
|
const PrintRegion ®ion = *print.regions[region_id];
|
||||||
|
|
||||||
// process perimeters
|
|
||||||
for (const ExtrusionEntity *ee : layerm->perimeters.entities) {
|
|
||||||
// perimeter_coll represents perimeter extrusions of a single island.
|
|
||||||
const auto *perimeter_coll = dynamic_cast<const ExtrusionEntityCollection*>(ee);
|
|
||||||
if (perimeter_coll->entities.empty())
|
|
||||||
// This shouldn't happen but first_point() would fail.
|
|
||||||
continue;
|
|
||||||
// Init by_extruder item only if we actually use the extruder.
|
|
||||||
std::vector<ObjectByExtruder::Island> &islands = object_islands_by_extruder(
|
|
||||||
by_extruder,
|
|
||||||
std::max<int>(region.config.perimeter_extruder.value - 1, 0),
|
|
||||||
&layer_to_print - layers.data(),
|
|
||||||
layers.size(), n_slices+1);
|
|
||||||
for (size_t i = 0; i <= n_slices; ++ i)
|
|
||||||
if (// perimeter_coll->first_point does not fit inside any slice
|
|
||||||
i == n_slices ||
|
|
||||||
// perimeter_coll->first_point fits inside ith slice
|
|
||||||
point_inside_surface(i, perimeter_coll->first_point())) {
|
|
||||||
if (islands[i].by_region.empty())
|
|
||||||
islands[i].by_region.assign(print.regions.size(), ObjectByExtruder::Island::Region());
|
|
||||||
islands[i].by_region[region_id].perimeters.append(perimeter_coll->entities);
|
|
||||||
|
|
||||||
// We just added perimeter_coll->entities.size() entities, if they are not to be printed before the main object (during infill wiping),
|
// Now we must process perimeters and infills and create islands of extrusions in by_region std::map.
|
||||||
// we will note their indices (for each copy separately):
|
// It is also necessary to save which extrusions are part of MM wiping and which are not.
|
||||||
unsigned int first_added_entity_index = islands[i].by_region[region_id].perimeters.entities.size() - perimeter_coll->entities.size();
|
// The process is almost the same for perimeters and infills - we will do it in a cycle that repeats twice:
|
||||||
for (unsigned copy_id = 0; copy_id < layer_to_print.object()->_shifted_copies.size(); ++copy_id) {
|
for (std::string entity_type("infills") ; entity_type != "done" ; entity_type = entity_type=="infills" ? "perimeters" : "done") {
|
||||||
if (islands[i].by_region[region_id].perimeters_per_copy_ids.size() < copy_id + 1) // if this copy isn't in the list yet
|
|
||||||
islands[i].by_region[region_id].perimeters_per_copy_ids.push_back(std::vector<unsigned int>());
|
const ExtrusionEntitiesPtr& source_entities = entity_type=="infills" ? layerm->fills.entities : layerm->perimeters.entities;
|
||||||
if (!perimeter_coll->is_extruder_overridden(copy_id))
|
|
||||||
for (int j=first_added_entity_index; j<islands[i].by_region[region_id].perimeters.entities.size(); ++j)
|
for (const ExtrusionEntity *ee : source_entities) {
|
||||||
islands[i].by_region[region_id].perimeters_per_copy_ids[copy_id].push_back(j);
|
// fill represents infill extrusions of a single island.
|
||||||
|
const auto *fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
|
||||||
|
if (fill->entities.empty()) // This shouldn't happen but first_point() would fail.
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// 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) :
|
||||||
|
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());
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
std::vector<ObjectByExtruder::Island> &islands = object_islands_by_extruder(
|
||||||
|
by_extruder,
|
||||||
|
extruder,
|
||||||
|
&layer_to_print - layers.data(),
|
||||||
|
layers.size(), n_slices+1);
|
||||||
|
for (size_t i = 0; i <= n_slices; ++i)
|
||||||
|
if (// fill->first_point does not fit inside any slice
|
||||||
|
i == n_slices ||
|
||||||
|
// fill->first_point fits inside ith slice
|
||||||
|
point_inside_surface(i, fill->first_point())) {
|
||||||
|
if (islands[i].by_region.empty())
|
||||||
|
islands[i].by_region.assign(print.regions.size(), ObjectByExtruder::Island::Region());
|
||||||
|
islands[i].by_region[region_id].append(entity_type, fill, entity_overrides, layer_to_print.object()->_shifted_copies.size());
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// process infill
|
|
||||||
// layerm->fills is a collection of Slic3r::ExtrusionPath::Collection objects (C++ class ExtrusionEntityCollection),
|
|
||||||
// each one containing the ExtrusionPath objects of a certain infill "group" (also called "surface"
|
|
||||||
// throughout the code). We can redefine the order of such Collections but we have to
|
|
||||||
// do each one completely at once.
|
|
||||||
for (const ExtrusionEntity *ee : layerm->fills.entities) {
|
|
||||||
// fill represents infill extrusions of a single island.
|
|
||||||
const auto *fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
|
|
||||||
if (fill->entities.empty())
|
|
||||||
// This shouldn't happen but first_point() would fail.
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// init by_extruder item only if we actually use the extruder
|
|
||||||
int extruder_id = std::max<int>(0, (is_solid_infill(fill->entities.front()->role()) ? region.config.solid_infill_extruder : region.config.infill_extruder) - 1);
|
|
||||||
// Init by_extruder item only if we actually use the extruder.
|
|
||||||
std::vector<ObjectByExtruder::Island> &islands = object_islands_by_extruder(
|
|
||||||
by_extruder,
|
|
||||||
extruder_id,
|
|
||||||
&layer_to_print - layers.data(),
|
|
||||||
layers.size(), n_slices+1);
|
|
||||||
for (size_t i = 0; i <= n_slices; ++i)
|
|
||||||
if (// fill->first_point does not fit inside any slice
|
|
||||||
i == n_slices ||
|
|
||||||
// fill->first_point fits inside ith slice
|
|
||||||
point_inside_surface(i, fill->first_point())) {
|
|
||||||
if (islands[i].by_region.empty())
|
|
||||||
islands[i].by_region.assign(print.regions.size(), ObjectByExtruder::Island::Region());
|
|
||||||
islands[i].by_region[region_id].infills.append(fill->entities);
|
|
||||||
|
|
||||||
// We just added fill->entities.size() entities, if they are not to be printed before the main object (during infill wiping),
|
|
||||||
// we will note their indices (for each copy separately):
|
|
||||||
unsigned int first_added_entity_index = islands[i].by_region[region_id].infills.entities.size() - fill->entities.size();
|
|
||||||
for (unsigned copy_id = 0; copy_id < layer_to_print.object()->_shifted_copies.size(); ++copy_id) {
|
|
||||||
if (islands[i].by_region[region_id].infills_per_copy_ids.size() < copy_id + 1) // if this copy isn't in the list yet
|
|
||||||
islands[i].by_region[region_id].infills_per_copy_ids.push_back(std::vector<unsigned int>());
|
|
||||||
if (!fill->is_extruder_overridden(copy_id))
|
|
||||||
for (int j=first_added_entity_index; j<islands[i].by_region[region_id].infills.entities.size(); ++j)
|
|
||||||
islands[i].by_region[region_id].infills_per_copy_ids[copy_id].push_back(j);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} // for regions
|
} // for regions
|
||||||
}
|
}
|
||||||
} // for objects
|
} // for objects
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Extrude the skirt, brim, support, perimeters, infill ordered by the extruders.
|
// Extrude the skirt, brim, support, perimeters, infill ordered by the extruders.
|
||||||
std::vector<std::unique_ptr<EdgeGrid::Grid>> lower_layer_edge_grids(layers.size());
|
std::vector<std::unique_ptr<EdgeGrid::Grid>> lower_layer_edge_grids(layers.size());
|
||||||
for (unsigned int extruder_id : layer_tools.extruders)
|
for (unsigned int extruder_id : layer_tools.extruders)
|
||||||
{
|
{
|
||||||
gcode += (layer_tools.has_wipe_tower && m_wipe_tower) ?
|
gcode += (layer_tools.has_wipe_tower && m_wipe_tower) ?
|
||||||
m_wipe_tower->tool_change(*this, extruder_id, extruder_id == layer_tools.extruders.back()) :
|
m_wipe_tower->tool_change(*this, extruder_id, extruder_id == layer_tools.extruders.back()) :
|
||||||
this->set_extruder(extruder_id);
|
this->set_extruder(extruder_id);
|
||||||
|
@ -1335,7 +1305,7 @@ void GCode::process_layer(
|
||||||
for (ExtrusionPath &path : loop.paths) {
|
for (ExtrusionPath &path : loop.paths) {
|
||||||
path.height = (float)layer.height;
|
path.height = (float)layer.height;
|
||||||
path.mm3_per_mm = mm3_per_mm;
|
path.mm3_per_mm = mm3_per_mm;
|
||||||
}
|
}
|
||||||
gcode += this->extrude_loop(loop, "skirt", m_config.support_material_speed.value);
|
gcode += this->extrude_loop(loop, "skirt", m_config.support_material_speed.value);
|
||||||
}
|
}
|
||||||
m_avoid_crossing_perimeters.use_external_mp = false;
|
m_avoid_crossing_perimeters.use_external_mp = false;
|
||||||
|
@ -1344,7 +1314,7 @@ void GCode::process_layer(
|
||||||
m_avoid_crossing_perimeters.disable_once = true;
|
m_avoid_crossing_perimeters.disable_once = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extrude brim with the extruder of the 1st region.
|
// Extrude brim with the extruder of the 1st region.
|
||||||
if (! m_brim_done) {
|
if (! m_brim_done) {
|
||||||
this->set_origin(0., 0.);
|
this->set_origin(0., 0.);
|
||||||
|
@ -1357,100 +1327,59 @@ void GCode::process_layer(
|
||||||
m_avoid_crossing_perimeters.disable_once = true;
|
m_avoid_crossing_perimeters.disable_once = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (layer_tools.has_wipe_tower) // the infill/perimeter wiping to save the material on the wipe tower
|
|
||||||
{
|
|
||||||
gcode += "; INFILL WIPING STARTS\n";
|
|
||||||
if (extruder_id != layer_tools.extruders.front()) { // if this is the first extruder on this layer, there was no toolchange
|
|
||||||
for (const auto& layer_to_print : layers) { // iterate through all objects
|
|
||||||
if (layer_to_print.object_layer == nullptr)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
m_config.apply((layer_to_print.object_layer)->object()->config, true);
|
|
||||||
|
|
||||||
for (unsigned copy_id = 0; copy_id < layer_to_print.object()->copies().size(); ++copy_id) {
|
|
||||||
std::vector<ObjectByExtruder::Island::Region> overridden;
|
|
||||||
for (size_t region_id = 0; region_id < print.regions.size(); ++ region_id) {
|
|
||||||
ObjectByExtruder::Island::Region new_region;
|
|
||||||
overridden.push_back(new_region);
|
|
||||||
for (ExtrusionEntity *ee : (*layer_to_print.object_layer).regions[region_id]->fills.entities) {
|
|
||||||
auto *fill = dynamic_cast<ExtrusionEntityCollection*>(ee);
|
|
||||||
if (fill->get_extruder_override(copy_id) == (int)extruder_id)
|
|
||||||
overridden.back().infills.append(*fill);
|
|
||||||
}
|
|
||||||
for (ExtrusionEntity *ee : (*layer_to_print.object_layer).regions[region_id]->perimeters.entities) {
|
|
||||||
auto *fill = dynamic_cast<ExtrusionEntityCollection*>(ee);
|
|
||||||
if (fill->get_extruder_override(copy_id) == (int)extruder_id)
|
|
||||||
overridden.back().perimeters.append((*fill).entities);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Point copy = (layer_to_print.object_layer)->object()->_shifted_copies[copy_id];
|
|
||||||
this->set_origin(unscale(copy.x), unscale(copy.y));
|
|
||||||
|
|
||||||
|
|
||||||
std::unique_ptr<EdgeGrid::Grid> u;
|
|
||||||
if (print.config.infill_first) {
|
|
||||||
gcode += this->extrude_infill(print, overridden);
|
|
||||||
gcode += this->extrude_perimeters(print, overridden, u);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
gcode += this->extrude_perimeters(print, overridden, u);
|
|
||||||
gcode += this->extrude_infill(print, overridden);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gcode += "; WIPING FINISHED\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
auto objects_by_extruder_it = by_extruder.find(extruder_id);
|
auto objects_by_extruder_it = by_extruder.find(extruder_id);
|
||||||
if (objects_by_extruder_it == by_extruder.end())
|
if (objects_by_extruder_it == by_extruder.end())
|
||||||
continue;
|
continue;
|
||||||
for (ObjectByExtruder &object_by_extruder : objects_by_extruder_it->second) {
|
|
||||||
const size_t layer_id = &object_by_extruder - objects_by_extruder_it->second.data();
|
|
||||||
const PrintObject *print_object = layers[layer_id].object();
|
|
||||||
if (print_object == nullptr)
|
|
||||||
// This layer is empty for this particular object, it has neither object extrusions nor support extrusions at this print_z.
|
|
||||||
continue;
|
|
||||||
|
|
||||||
m_config.apply(print_object->config, true);
|
// We are almost ready to print. However, we must go through all the object twice and only print the overridden extrusions first (infill/primeter wiping feature):
|
||||||
m_layer = layers[layer_id].layer();
|
for (int print_wipe_extrusions=layer_tools.wiping_extrusions.is_anything_overridden(); print_wipe_extrusions>=0; --print_wipe_extrusions) {
|
||||||
if (m_config.avoid_crossing_perimeters)
|
for (ObjectByExtruder &object_by_extruder : objects_by_extruder_it->second) {
|
||||||
m_avoid_crossing_perimeters.init_layer_mp(union_ex(m_layer->slices, true));
|
const size_t layer_id = &object_by_extruder - objects_by_extruder_it->second.data();
|
||||||
Points copies;
|
const PrintObject *print_object = layers[layer_id].object();
|
||||||
if (single_object_idx == size_t(-1))
|
if (print_object == nullptr)
|
||||||
copies = print_object->_shifted_copies;
|
// This layer is empty for this particular object, it has neither object extrusions nor support extrusions at this print_z.
|
||||||
else
|
continue;
|
||||||
copies.push_back(print_object->_shifted_copies[single_object_idx]);
|
|
||||||
// Sort the copies by the closest point starting with the current print position.
|
|
||||||
|
|
||||||
unsigned int copy_id = 0;
|
m_config.apply(print_object->config, true);
|
||||||
for (const Point © : copies) {
|
m_layer = layers[layer_id].layer();
|
||||||
// When starting a new object, use the external motion planner for the first travel move.
|
if (m_config.avoid_crossing_perimeters)
|
||||||
std::pair<const PrintObject*, Point> this_object_copy(print_object, copy);
|
m_avoid_crossing_perimeters.init_layer_mp(union_ex(m_layer->slices, true));
|
||||||
if (m_last_obj_copy != this_object_copy)
|
Points copies;
|
||||||
m_avoid_crossing_perimeters.use_external_mp_once = true;
|
if (single_object_idx == size_t(-1))
|
||||||
m_last_obj_copy = this_object_copy;
|
copies = print_object->_shifted_copies;
|
||||||
this->set_origin(unscale(copy.x), unscale(copy.y));
|
else
|
||||||
if (object_by_extruder.support != nullptr) {
|
copies.push_back(print_object->_shifted_copies[single_object_idx]);
|
||||||
m_layer = layers[layer_id].support_layer;
|
// Sort the copies by the closest point starting with the current print position.
|
||||||
gcode += this->extrude_support(
|
|
||||||
// support_extrusion_role is erSupportMaterial, erSupportMaterialInterface or erMixed for all extrusion paths.
|
unsigned int copy_id = 0;
|
||||||
object_by_extruder.support->chained_path_from(m_last_pos, false, object_by_extruder.support_extrusion_role));
|
for (const Point © : copies) {
|
||||||
m_layer = layers[layer_id].layer();
|
// When starting a new object, use the external motion planner for the first travel move.
|
||||||
}
|
std::pair<const PrintObject*, Point> this_object_copy(print_object, copy);
|
||||||
for (ObjectByExtruder::Island &island : object_by_extruder.islands) {
|
if (m_last_obj_copy != this_object_copy)
|
||||||
if (print.config.infill_first) {
|
m_avoid_crossing_perimeters.use_external_mp_once = true;
|
||||||
gcode += this->extrude_infill(print, island.by_region_per_copy(copy_id));
|
m_last_obj_copy = this_object_copy;
|
||||||
gcode += this->extrude_perimeters(print, island.by_region_per_copy(copy_id), lower_layer_edge_grids[layer_id]);
|
this->set_origin(unscale(copy.x), unscale(copy.y));
|
||||||
} else {
|
if (object_by_extruder.support != nullptr) {
|
||||||
gcode += this->extrude_perimeters(print, island.by_region_per_copy(copy_id), lower_layer_edge_grids[layer_id]);
|
m_layer = layers[layer_id].support_layer;
|
||||||
gcode += this->extrude_infill(print, island.by_region_per_copy(copy_id));
|
gcode += this->extrude_support(
|
||||||
|
// support_extrusion_role is erSupportMaterial, erSupportMaterialInterface or erMixed for all extrusion paths.
|
||||||
|
object_by_extruder.support->chained_path_from(m_last_pos, false, object_by_extruder.support_extrusion_role));
|
||||||
|
m_layer = layers[layer_id].layer();
|
||||||
}
|
}
|
||||||
|
for (ObjectByExtruder::Island &island : object_by_extruder.islands) {
|
||||||
|
const auto& by_region_specific = layer_tools.wiping_extrusions.is_anything_overridden() ? island.by_region_per_copy(copy_id, extruder_id, print_wipe_extrusions) : island.by_region;
|
||||||
|
|
||||||
|
if (print.config.infill_first) {
|
||||||
|
gcode += this->extrude_infill(print, by_region_specific);
|
||||||
|
gcode += this->extrude_perimeters(print, by_region_specific, lower_layer_edge_grids[layer_id]);
|
||||||
|
} else {
|
||||||
|
gcode += this->extrude_perimeters(print, by_region_specific, lower_layer_edge_grids[layer_id]);
|
||||||
|
gcode += this->extrude_infill(print,by_region_specific);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++copy_id;
|
||||||
}
|
}
|
||||||
++copy_id;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2512,29 +2441,61 @@ Point GCode::gcode_to_point(const Pointf &point) const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Goes through by_region std::vector and returns reference to a subvector of entities to be printed in usual time
|
// Goes through by_region std::vector and returns reference to a subvector of entities, that are to be printed
|
||||||
// i.e. not when it's going to be done during infill wiping
|
// during infill/perimeter wiping, or normally (depends on wiping_entities parameter)
|
||||||
const std::vector<GCode::ObjectByExtruder::Island::Region>& GCode::ObjectByExtruder::Island::by_region_per_copy(unsigned int copy)
|
// Returns a reference to member to avoid copying.
|
||||||
|
const std::vector<GCode::ObjectByExtruder::Island::Region>& GCode::ObjectByExtruder::Island::by_region_per_copy(unsigned int copy, int extruder, bool wiping_entities)
|
||||||
{
|
{
|
||||||
if (copy == last_copy)
|
by_region_per_copy_cache.clear();
|
||||||
return by_region_per_copy_cache;
|
|
||||||
else {
|
|
||||||
by_region_per_copy_cache.clear();
|
|
||||||
last_copy = copy;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& reg : by_region) {
|
for (const auto& reg : by_region) {
|
||||||
by_region_per_copy_cache.push_back(ObjectByExtruder::Island::Region());
|
by_region_per_copy_cache.push_back(ObjectByExtruder::Island::Region()); // creates a region in the newly created Island
|
||||||
|
|
||||||
if (!reg.infills_per_copy_ids.empty())
|
// Now we are going to iterate through perimeters and infills and pick ones that are supposed to be printed
|
||||||
for (unsigned int i=0; i<reg.infills_per_copy_ids[copy].size(); ++i)
|
// References are used so that we don't have to repeat the same code
|
||||||
by_region_per_copy_cache.back().infills.append(*(reg.infills.entities[reg.infills_per_copy_ids[copy][i]]));
|
for (int iter = 0; iter < 2; ++iter) {
|
||||||
|
const ExtrusionEntitiesPtr& entities = (iter ? reg.infills.entities : reg.perimeters.entities);
|
||||||
|
ExtrusionEntityCollection& target_eec = (iter ? by_region_per_copy_cache.back().infills : by_region_per_copy_cache.back().perimeters);
|
||||||
|
const std::vector<const ExtruderPerCopy*>& overrides = (iter ? reg.infills_overrides : reg.perimeters_overrides);
|
||||||
|
|
||||||
if (!reg.perimeters_per_copy_ids.empty())
|
// Now the most important thing - which extrusion should we print.
|
||||||
for (unsigned int i=0; i<reg.perimeters_per_copy_ids[copy].size(); ++i)
|
// See function ToolOrdering::get_extruder_overrides for details about the negative numbers hack.
|
||||||
by_region_per_copy_cache.back().perimeters.append(*(reg.perimeters.entities[reg.perimeters_per_copy_ids[copy][i]]));
|
int this_extruder_mark = wiping_entities ? extruder : -extruder-1;
|
||||||
|
|
||||||
|
for (unsigned int i=0;i<entities.size();++i)
|
||||||
|
if (overrides[i]->at(copy) == this_extruder_mark) // this copy should be printed with this extruder
|
||||||
|
target_eec.append((*entities[i]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return by_region_per_copy_cache;
|
return by_region_per_copy_cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// This function takes the eec and appends its entities to either perimeters or infills of this Region (depending on the first parameter)
|
||||||
|
// It also saves pointer to ExtruderPerCopy struct (for each entity), that holds information about which extruders should be used for which copy.
|
||||||
|
void GCode::ObjectByExtruder::Island::Region::append(const std::string& type, const ExtrusionEntityCollection* eec, const ExtruderPerCopy* copies_extruder, unsigned int object_copies_num)
|
||||||
|
{
|
||||||
|
// We are going to manipulate either perimeters or infills, exactly in the same way. Let's create pointers to the proper structure to not repeat ourselves:
|
||||||
|
ExtrusionEntityCollection* perimeters_or_infills = &infills;
|
||||||
|
std::vector<const ExtruderPerCopy*>* perimeters_or_infills_overrides = &infills_overrides;
|
||||||
|
|
||||||
|
if (type == "perimeters") {
|
||||||
|
perimeters_or_infills = &perimeters;
|
||||||
|
perimeters_or_infills_overrides = &perimeters_overrides;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (type != "infills") {
|
||||||
|
CONFESS("Unknown parameter!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// First we append the entities, there are eec->entities.size() of them:
|
||||||
|
perimeters_or_infills->append(eec->entities);
|
||||||
|
|
||||||
|
for (unsigned int i=0;i<eec->entities.size();++i)
|
||||||
|
perimeters_or_infills_overrides->push_back(copies_extruder);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
|
@ -200,6 +200,7 @@ protected:
|
||||||
std::string extrude_multi_path(ExtrusionMultiPath multipath, std::string description = "", double speed = -1.);
|
std::string extrude_multi_path(ExtrusionMultiPath multipath, std::string description = "", double speed = -1.);
|
||||||
std::string extrude_path(ExtrusionPath path, std::string description = "", double speed = -1.);
|
std::string extrude_path(ExtrusionPath path, std::string description = "", double speed = -1.);
|
||||||
|
|
||||||
|
typedef std::vector<int> ExtruderPerCopy;
|
||||||
// Extruding multiple objects with soluble / non-soluble / combined supports
|
// Extruding multiple objects with soluble / non-soluble / combined supports
|
||||||
// on a multi-material printer, trying to minimize tool switches.
|
// on a multi-material printer, trying to minimize tool switches.
|
||||||
// Following structures sort extrusions by the extruder ID, by an order of objects and object islands.
|
// Following structures sort extrusions by the extruder ID, by an order of objects and object islands.
|
||||||
|
@ -215,15 +216,19 @@ protected:
|
||||||
struct Region {
|
struct Region {
|
||||||
ExtrusionEntityCollection perimeters;
|
ExtrusionEntityCollection perimeters;
|
||||||
ExtrusionEntityCollection infills;
|
ExtrusionEntityCollection infills;
|
||||||
std::vector<std::vector<unsigned int>> infills_per_copy_ids; // indices of infill.entities that are not part of infill wiping (an element for each object copy)
|
|
||||||
std::vector<std::vector<unsigned int>> perimeters_per_copy_ids; // indices of infill.entities that are not part of infill wiping (an element for each object copy)
|
std::vector<const ExtruderPerCopy*> infills_overrides;
|
||||||
|
std::vector<const ExtruderPerCopy*> perimeters_overrides;
|
||||||
|
|
||||||
|
// Appends perimeter/infill entities and writes don't indices of those that are not to be extruder as part of perimeter/infill wiping
|
||||||
|
void append(const std::string& type, const ExtrusionEntityCollection* eec, const ExtruderPerCopy* copy_extruders, unsigned int object_copies_num);
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<Region> by_region; // all extrusions for this island, grouped by regions
|
std::vector<Region> by_region; // all extrusions for this island, grouped by regions
|
||||||
const std::vector<Region>& by_region_per_copy(unsigned int copy); // returns reference to subvector of by_region (only extrusions that are NOT printed during wiping into infill for this copy)
|
const std::vector<Region>& by_region_per_copy(unsigned int copy, int extruder, bool wiping_entities = false); // returns reference to subvector of by_region
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<Region> by_region_per_copy_cache; // caches vector generated by function above to avoid copying and recalculating
|
std::vector<Region> by_region_per_copy_cache; // caches vector generated by function above to avoid copying and recalculating
|
||||||
unsigned int last_copy = (unsigned int)(-1); // index of last copy that by_region_per_copy was called for
|
|
||||||
};
|
};
|
||||||
std::vector<Island> islands;
|
std::vector<Island> islands;
|
||||||
};
|
};
|
||||||
|
|
|
@ -330,4 +330,42 @@ 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)
|
||||||
|
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.
|
||||||
|
// 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,
|
||||||
|
// 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,
|
||||||
|
// 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) {
|
||||||
|
auto entity_map_it = entity_map.find(entity);
|
||||||
|
if (entity_map_it == entity_map.end())
|
||||||
|
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:
|
||||||
|
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):
|
||||||
|
std::replace(entity_map_it->second.begin(), entity_map_it->second.end(), -1, -correct_extruder_id-1);
|
||||||
|
|
||||||
|
return &(entity_map_it->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
|
@ -10,6 +10,36 @@ namespace Slic3r {
|
||||||
class Print;
|
class Print;
|
||||||
class PrintObject;
|
class PrintObject;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 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
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 ToolOrdering
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -39,6 +69,11 @@ public:
|
||||||
// and to support the wipe tower partitions above this one.
|
// and to support the wipe tower partitions above this one.
|
||||||
size_t wipe_tower_partitions;
|
size_t wipe_tower_partitions;
|
||||||
coordf_t wipe_tower_layer_height;
|
coordf_t wipe_tower_layer_height;
|
||||||
|
|
||||||
|
|
||||||
|
// This holds list of extrusion that will be used for extruder wiping
|
||||||
|
WipingExtrusions wiping_extrusions;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ToolOrdering() {}
|
ToolOrdering() {}
|
||||||
|
@ -72,7 +107,7 @@ public:
|
||||||
std::vector<LayerTools>::const_iterator begin() const { return m_layer_tools.begin(); }
|
std::vector<LayerTools>::const_iterator begin() const { return m_layer_tools.begin(); }
|
||||||
std::vector<LayerTools>::const_iterator end() const { return m_layer_tools.end(); }
|
std::vector<LayerTools>::const_iterator end() const { return m_layer_tools.end(); }
|
||||||
bool empty() const { return m_layer_tools.empty(); }
|
bool empty() const { return m_layer_tools.empty(); }
|
||||||
const std::vector<LayerTools>& layer_tools() const { return m_layer_tools; }
|
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; }
|
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; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -1121,21 +1121,14 @@ void Print::_make_wipe_tower()
|
||||||
this->config.filament_ramming_parameters.get_at(i),
|
this->config.filament_ramming_parameters.get_at(i),
|
||||||
this->config.nozzle_diameter.get_at(i));
|
this->config.nozzle_diameter.get_at(i));
|
||||||
|
|
||||||
// When printing the first layer's wipe tower, the first extruder is expected to be active and primed.
|
|
||||||
// Therefore the number of wipe sections at the wipe tower will be (m_tool_ordering.front().extruders-1) at the 1st layer.
|
|
||||||
// The following variable is true if the last priming section cannot be squeezed inside the wipe tower.
|
|
||||||
bool last_priming_wipe_full = m_tool_ordering.front().extruders.size() > m_tool_ordering.front().wipe_tower_partitions;
|
|
||||||
|
|
||||||
m_wipe_tower_priming = Slic3r::make_unique<WipeTower::ToolChangeResult>(
|
m_wipe_tower_priming = Slic3r::make_unique<WipeTower::ToolChangeResult>(
|
||||||
wipe_tower.prime(this->skirt_first_layer_height(), m_tool_ordering.all_extruders(), ! last_priming_wipe_full));
|
wipe_tower.prime(this->skirt_first_layer_height(), m_tool_ordering.all_extruders(), false));
|
||||||
|
|
||||||
reset_wiping_extrusions(); // if this is not the first time the wipe tower is generated, some extrusions might remember their last wiping status
|
|
||||||
|
|
||||||
// Lets go through the wipe tower layers and determine pairs of extruder changes for each
|
// Lets go through the wipe tower layers and determine pairs of extruder changes for each
|
||||||
// to pass to wipe_tower (so that it can use it for planning the layout of the tower)
|
// to pass to wipe_tower (so that it can use it for planning the layout of the tower)
|
||||||
{
|
{
|
||||||
unsigned int current_extruder_id = m_tool_ordering.all_extruders().back();
|
unsigned int current_extruder_id = m_tool_ordering.all_extruders().back();
|
||||||
for (const auto &layer_tools : m_tool_ordering.layer_tools()) { // for all layers
|
for (auto &layer_tools : m_tool_ordering.layer_tools()) { // for all layers
|
||||||
if (!layer_tools.has_wipe_tower) continue;
|
if (!layer_tools.has_wipe_tower) continue;
|
||||||
bool first_layer = &layer_tools == &m_tool_ordering.front();
|
bool first_layer = &layer_tools == &m_tool_ordering.front();
|
||||||
wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, current_extruder_id,false);
|
wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, current_extruder_id,false);
|
||||||
|
@ -1180,111 +1173,100 @@ void Print::_make_wipe_tower()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Following function iterates through all extrusions on the layer, remembers those that could be used for wiping after toolchange
|
||||||
void Print::reset_wiping_extrusions() {
|
// and returns volume that is left to be wiped on the wipe tower.
|
||||||
for (size_t i = 0; i < objects.size(); ++ i) {
|
float Print::mark_wiping_extrusions(ToolOrdering::LayerTools& layer_tools, unsigned int new_extruder, float volume_to_wipe)
|
||||||
for (auto& this_layer : objects[i]->layers) {
|
|
||||||
for (size_t region_id = 0; region_id < objects[i]->print()->regions.size(); ++ region_id) {
|
|
||||||
for (unsigned int copy = 0; copy < objects[i]->_shifted_copies.size(); ++copy) {
|
|
||||||
this_layer->regions[region_id]->fills.set_extruder_override(copy, -1);
|
|
||||||
this_layer->regions[region_id]->perimeters.set_extruder_override(copy, -1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
||||||
|
|
||||||
float Print::mark_wiping_extrusions(const 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)) { // Soluble filament cannot be wiped in a random infill
|
if (config.filament_soluble.get_at(new_extruder))
|
||||||
for (size_t i = 0; i < objects.size(); ++ i) { // Let's iterate through all objects...
|
return volume_to_wipe; // Soluble filament cannot be wiped in a random infill
|
||||||
|
|
||||||
if (!objects[i]->config.wipe_into_infill && !objects[i]->config.wipe_into_objects)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Layer* this_layer = nullptr;
|
|
||||||
for (unsigned int a = 0; a < objects[i]->layers.size(); ++a) // Finds this layer
|
|
||||||
if (std::abs(layer_tools.print_z - objects[i]->layers[a]->print_z) < EPSILON) {
|
|
||||||
this_layer = objects[i]->layers[a];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (this_layer == nullptr)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (unsigned int copy = 0; copy < objects[i]->_shifted_copies.size(); ++copy) { // iterate through copies first, so that we mark neighbouring infills
|
for (size_t i = 0; i < objects.size(); ++ i) { // Let's iterate through all objects...
|
||||||
for (size_t region_id = 0; region_id < objects[i]->print()->regions.size(); ++ region_id) {
|
if (!objects[i]->config.wipe_into_infill && !objects[i]->config.wipe_into_objects)
|
||||||
|
continue;
|
||||||
|
|
||||||
unsigned int region_extruder = objects[i]->print()->regions[region_id]->config.infill_extruder - 1; // config value is 1-based
|
Layer* this_layer = nullptr;
|
||||||
if (config.filament_soluble.get_at(region_extruder)) // if this infill is meant to be soluble, keep it that way
|
for (unsigned int a = 0; a < objects[i]->layers.size(); ++a) // Finds this layer
|
||||||
|
if (std::abs(layer_tools.print_z - objects[i]->layers[a]->print_z) < EPSILON) {
|
||||||
|
this_layer = objects[i]->layers[a];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (this_layer == nullptr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
unsigned int num_of_copies = objects[i]->_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 < objects[i]->print()->regions.size(); ++ region_id) {
|
||||||
|
unsigned int region_extruder = objects[i]->print()->regions[region_id]->config.infill_extruder - 1; // config value is 1-based
|
||||||
|
if (config.filament_soluble.get_at(region_extruder)) // if this entity is meant to be soluble, keep it that way
|
||||||
|
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;
|
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)
|
if (objects[i]->config.wipe_into_infill) {
|
||||||
bool unused_yet = false;
|
ExtrusionEntityCollection& eec = this_layer->regions[region_id]->fills;
|
||||||
for (unsigned i = 0; i < layer_tools.extruders.size(); ++i) {
|
for (ExtrusionEntity* ee : eec.entities) { // iterate through all infill Collections
|
||||||
if (layer_tools.extruders[i] == new_extruder)
|
if (volume_to_wipe <= 0.f)
|
||||||
unused_yet = true;
|
|
||||||
if (layer_tools.extruders[i] == region_extruder)
|
|
||||||
break;
|
break;
|
||||||
}
|
auto* fill = dynamic_cast<ExtrusionEntityCollection*>(ee);
|
||||||
if (unused_yet)
|
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
|
||||||
|
layer_tools.wiping_extrusions.set_extruder_override(fill, copy, new_extruder, num_of_copies);
|
||||||
if (objects[i]->config.wipe_into_infill) {
|
volume_to_wipe -= fill->total_volume();
|
||||||
ExtrusionEntityCollection& eec = this_layer->regions[region_id]->fills;
|
|
||||||
for (ExtrusionEntity* ee : eec.entities) { // iterate through all infill Collections
|
|
||||||
auto* fill = dynamic_cast<ExtrusionEntityCollection*>(ee);
|
|
||||||
if (fill->role() == erTopSolidInfill || fill->role() == erGapFill) continue; // these cannot be changed - it is / may be visible
|
|
||||||
if (volume_to_wipe <= 0.f)
|
|
||||||
break;
|
|
||||||
if (!fill->is_extruder_overridden(copy) && fill->total_volume() > min_infill_volume) { // this infill will be used to wipe this extruder
|
|
||||||
fill->set_extruder_override(copy, new_extruder);
|
|
||||||
volume_to_wipe -= fill->total_volume();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (objects[i]->config.wipe_into_objects)
|
if (objects[i]->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
|
||||||
auto* fill = dynamic_cast<ExtrusionEntityCollection*>(ee);
|
if (volume_to_wipe <= 0.f)
|
||||||
if (volume_to_wipe <= 0.f)
|
break;
|
||||||
break;
|
auto* fill = dynamic_cast<ExtrusionEntityCollection*>(ee);
|
||||||
if (!fill->is_extruder_overridden(copy) && fill->total_volume() > min_infill_volume) {
|
if (/*!fill->is_extruder_overridden(copy)*/ !layer_tools.wiping_extrusions.is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume) {
|
||||||
fill->set_extruder_override(copy, new_extruder);
|
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();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::max(0.f, volume_to_wipe);
|
return std::max(0.f, volume_to_wipe);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -317,10 +317,7 @@ private:
|
||||||
|
|
||||||
// This function goes through all infill entities, decides which ones will be used for wiping and
|
// 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:
|
// marks them by the extruder id. Returns volume that remains to be wiped on the wipe tower:
|
||||||
float mark_wiping_extrusions(const ToolOrdering::LayerTools& layer_tools, unsigned int new_extruder, float volume_to_wipe);
|
float mark_wiping_extrusions(ToolOrdering::LayerTools& layer_tools, unsigned int new_extruder, float volume_to_wipe);
|
||||||
|
|
||||||
// A function to go through all entities and unsets their extruder_override flag
|
|
||||||
void reset_wiping_extrusions();
|
|
||||||
|
|
||||||
// Has the calculation been canceled?
|
// Has the calculation been canceled?
|
||||||
tbb::atomic<bool> m_canceled;
|
tbb::atomic<bool> m_canceled;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue