Separate extrusions ordering and extrusions exporting into two for loops

This commit is contained in:
Martin Šach 2024-06-14 20:27:35 +02:00 committed by Lukas Matena
parent fe1b8134d6
commit 17dc776109
5 changed files with 100 additions and 49 deletions

View File

@ -2462,39 +2462,44 @@ LayerResult GCodeGenerator::process_layer(
} }
} }
// Extrude the skirt, brim, support, perimeters, infill ordered by the extruders. using GCode::ExtrusionOrder::NormalExtrusions;
for (unsigned int extruder_id : layer_tools.extruders) struct ExtruderExtrusions {
unsigned extruder_id;
std::vector<std::pair<std::size_t, const ExtrusionEntity *>> skirt;
ExtrusionEntitiesPtr brim;
std::vector<std::vector<SliceExtrusions>> overriden_extrusions;
std::vector<NormalExtrusions> normal_extrusions;
};
unsigned current_extruder_id{this->m_writer.extruder()->id()};
unsigned toolchange_number{0};
std::optional<Point> previous_position{this->last_position};
std::vector<ExtruderExtrusions> extrusions;
for (const unsigned int extruder_id : layer_tools.extruders)
{ {
gcode += (layer_tools.has_wipe_tower && m_wipe_tower) ? if (layer_tools.has_wipe_tower && m_wipe_tower) {
m_wipe_tower->tool_change(*this, extruder_id, extruder_id == layer_tools.extruders.back()) : if (is_toolchange_required(first_layer, layer_tools.extruders.back(), extruder_id, current_extruder_id)) {
this->set_extruder(extruder_id, print_z); const WipeTower::ToolChangeResult tool_change{m_wipe_tower->get_toolchange(toolchange_number++)};
previous_position = this->gcode_to_point(m_wipe_tower->transform_wt_pt(tool_change.end_pos).cast<double>());
// let analyzer tag generator aware of a role type change current_extruder_id = tool_change.new_tool;
if (layer_tools.has_wipe_tower && m_wipe_tower) }
m_last_processor_extrusion_role = GCodeExtrusionRole::WipeTower;
if (has_custom_gcode_to_emit && extruder_id_for_custom_gcode == int(extruder_id)) {
assert(m_writer.extruder()->id() == extruder_id_for_custom_gcode);
assert(m_pending_pre_extrusion_gcode.empty());
// Now we have picked the right extruder, so we can emit the custom g-code.
gcode += ProcessLayer::emit_custom_gcode_per_print_z(*this, *layer_tools.custom_gcode, m_writer.extruder()->id(), first_extruder_id, print.config());
} }
std::optional<Point> previous_position{this->last_position}; ExtruderExtrusions extruder_extrusions{extruder_id};
std::vector<std::pair<std::size_t, const ExtrusionEntity *>> skirt;
if (auto loops_it = skirt_loops_per_extruder.find(extruder_id); loops_it != skirt_loops_per_extruder.end()) { if (auto loops_it = skirt_loops_per_extruder.find(extruder_id); loops_it != skirt_loops_per_extruder.end()) {
const std::pair<size_t, size_t> loops = loops_it->second; const std::pair<size_t, size_t> loops = loops_it->second;
for (std::size_t i = loops.first; i < loops.second; ++i) { for (std::size_t i = loops.first; i < loops.second; ++i) {
skirt.emplace_back(i, print.skirt().entities[i]); extruder_extrusions.skirt.emplace_back(i, print.skirt().entities[i]);
} }
} }
using GCode::ExtrusionOrder::get_last_position; using GCode::ExtrusionOrder::get_last_position;
ExtrusionEntitiesPtr brim;
if (!m_brim_done) { if (!m_brim_done) {
brim = print.brim().entities; extruder_extrusions.brim = print.brim().entities;
previous_position = get_last_position(brim); previous_position = get_last_position(extruder_extrusions.brim);
m_brim_done = true;
} }
@ -2519,22 +2524,40 @@ LayerResult GCodeGenerator::process_layer(
using GCode::ExtrusionOrder::get_overriden_extrusions; using GCode::ExtrusionOrder::get_overriden_extrusions;
bool is_anything_overridden = layer_tools.wiping_extrusions().is_anything_overridden(); bool is_anything_overridden = layer_tools.wiping_extrusions().is_anything_overridden();
std::vector<std::vector<SliceExtrusions>> overriden_extrusions;
if (is_anything_overridden) { if (is_anything_overridden) {
overriden_extrusions = get_overriden_extrusions( extruder_extrusions.overriden_extrusions = get_overriden_extrusions(
print, layers, layer_tools, instances_to_print, extruder_id, place_seam, print, layers, layer_tools, instances_to_print, extruder_id, place_seam,
previous_position previous_position
); );
} }
using GCode::ExtrusionOrder::get_normal_extrusions; using GCode::ExtrusionOrder::get_normal_extrusions;
using GCode::ExtrusionOrder::NormalExtrusions; extruder_extrusions.normal_extrusions = get_normal_extrusions(
const std::vector<NormalExtrusions> normal_extrusions{get_normal_extrusions(
print, layers, layer_tools, instances_to_print, extruder_id, place_seam, print, layers, layer_tools, instances_to_print, extruder_id, place_seam,
previous_position previous_position
)}; );
extrusions.push_back(std::move(extruder_extrusions));
}
if (!skirt.empty()) { // Extrude the skirt, brim, support, perimeters, infill ordered by the extruders.
for (const ExtruderExtrusions &extruder_extrusions : extrusions)
{
gcode += (layer_tools.has_wipe_tower && m_wipe_tower) ?
m_wipe_tower->tool_change(*this, extruder_extrusions.extruder_id, extruder_extrusions.extruder_id == layer_tools.extruders.back()) :
this->set_extruder(extruder_extrusions.extruder_id, print_z);
// let analyzer tag generator aware of a role type change
if (layer_tools.has_wipe_tower && m_wipe_tower)
m_last_processor_extrusion_role = GCodeExtrusionRole::WipeTower;
if (has_custom_gcode_to_emit && extruder_id_for_custom_gcode == int(extruder_extrusions.extruder_id)) {
assert(m_writer.extruder()->id() == extruder_id_for_custom_gcode);
assert(m_pending_pre_extrusion_gcode.empty());
// Now we have picked the right extruder, so we can emit the custom g-code.
gcode += ProcessLayer::emit_custom_gcode_per_print_z(*this, *layer_tools.custom_gcode, m_writer.extruder()->id(), first_extruder_id, print.config());
}
if (!extruder_extrusions.skirt.empty()) {
if (!this->m_config.complete_objects.value) { if (!this->m_config.complete_objects.value) {
gcode += this->m_label_objects.maybe_stop_instance(); gcode += this->m_label_objects.maybe_stop_instance();
} }
@ -2544,7 +2567,7 @@ LayerResult GCodeGenerator::process_layer(
m_avoid_crossing_perimeters.use_external_mp(); m_avoid_crossing_perimeters.use_external_mp();
Flow layer_skirt_flow = print.skirt_flow().with_height(float(m_skirt_done.back() - (m_skirt_done.size() == 1 ? 0. : m_skirt_done[m_skirt_done.size() - 2]))); Flow layer_skirt_flow = print.skirt_flow().with_height(float(m_skirt_done.back() - (m_skirt_done.size() == 1 ? 0. : m_skirt_done[m_skirt_done.size() - 2])));
double mm3_per_mm = layer_skirt_flow.mm3_per_mm(); double mm3_per_mm = layer_skirt_flow.mm3_per_mm();
for (const auto&[_, loop_entity] : skirt) { for (const auto&[_, loop_entity] : extruder_extrusions.skirt) {
// Adjust flow according to this layer's layer height. // Adjust flow according to this layer's layer height.
//FIXME using the support_material_speed of the 1st object printed. //FIXME using the support_material_speed of the 1st object printed.
gcode += this->extrude_skirt(dynamic_cast<const ExtrusionLoop&>(*loop_entity), gcode += this->extrude_skirt(dynamic_cast<const ExtrusionLoop&>(*loop_entity),
@ -2554,13 +2577,13 @@ LayerResult GCodeGenerator::process_layer(
} }
m_avoid_crossing_perimeters.use_external_mp(false); m_avoid_crossing_perimeters.use_external_mp(false);
// Allow a straight travel move to the first object point if this is the first layer (but don't in next layers). // Allow a straight travel move to the first object point if this is the first layer (but don't in next layers).
if (first_layer && skirt.front().first == 0) if (first_layer && extruder_extrusions.skirt.front().first == 0)
m_avoid_crossing_perimeters.disable_once(); m_avoid_crossing_perimeters.disable_once();
} }
// Extrude brim with the extruder of the 1st region. // Extrude brim with the extruder of the 1st region.
if (!brim.empty()) { if (!extruder_extrusions.brim.empty()) {
if (!this->m_config.complete_objects.value) { if (!this->m_config.complete_objects.value) {
gcode += this->m_label_objects.maybe_stop_instance(); gcode += this->m_label_objects.maybe_stop_instance();
@ -2569,17 +2592,16 @@ LayerResult GCodeGenerator::process_layer(
this->set_origin(0., 0.); this->set_origin(0., 0.);
m_avoid_crossing_perimeters.use_external_mp(); m_avoid_crossing_perimeters.use_external_mp();
for (const ExtrusionEntity *ee : brim) { for (const ExtrusionEntity *ee : extruder_extrusions.brim) {
gcode += this->extrude_entity({ *ee, false }, smooth_path_caches.global(), "brim"sv, m_config.support_material_speed.value); gcode += this->extrude_entity({ *ee, false }, smooth_path_caches.global(), "brim"sv, m_config.support_material_speed.value);
} }
m_brim_done = true;
m_avoid_crossing_perimeters.use_external_mp(false); m_avoid_crossing_perimeters.use_external_mp(false);
// Allow a straight travel move to the first object point. // Allow a straight travel move to the first object point.
m_avoid_crossing_perimeters.disable_once(); m_avoid_crossing_perimeters.disable_once();
} }
this->m_label_objects.update(first_instance); this->m_label_objects.update(first_instance);
if (!overriden_extrusions.empty()) { if (!extruder_extrusions.overriden_extrusions.empty()) {
// Extrude wipes. // Extrude wipes.
size_t gcode_size_old = gcode.size(); size_t gcode_size_old = gcode.size();
for (std::size_t i{0}; i < instances_to_print.size(); ++i) { for (std::size_t i{0}; i < instances_to_print.size(); ++i) {
@ -2587,7 +2609,7 @@ LayerResult GCodeGenerator::process_layer(
this->process_layer_single_object( this->process_layer_single_object(
gcode, instance, layers[instance.object_layer_to_print_id], gcode, instance, layers[instance.object_layer_to_print_id],
smooth_path_caches.layer_local(), {}, overriden_extrusions[i] smooth_path_caches.layer_local(), {}, extruder_extrusions.overriden_extrusions[i]
); );
} }
if (gcode_size_old < gcode.size()) { if (gcode_size_old < gcode.size()) {
@ -2601,8 +2623,8 @@ LayerResult GCodeGenerator::process_layer(
this->process_layer_single_object( this->process_layer_single_object(
gcode, instance, layers[instance.object_layer_to_print_id], gcode, instance, layers[instance.object_layer_to_print_id],
smooth_path_caches.layer_local(), normal_extrusions[i].support_extrusions, smooth_path_caches.layer_local(), extruder_extrusions.normal_extrusions[i].support_extrusions,
normal_extrusions[i].slices_extrusions extruder_extrusions.normal_extrusions[i].slices_extrusions
); );
} }
} }

View File

@ -34,15 +34,6 @@ std::string WipeTowerIntegration::append_tcr(GCodeGenerator &gcodegen, const Wip
std::string gcode; std::string gcode;
// Toolchangeresult.gcode assumes the wipe tower corner is at the origin (except for priming lines)
// We want to rotate and shift all extrusions (gcode postprocessing) and starting and ending position
float alpha = m_wipe_tower_rotation / 180.f * float(M_PI);
auto transform_wt_pt = [&alpha, this](const Vec2f& pt) -> Vec2f {
Vec2f out = Eigen::Rotation2Df(alpha) * pt;
out += m_wipe_tower_pos;
return out;
};
Vec2f start_pos = tcr.start_pos; Vec2f start_pos = tcr.start_pos;
Vec2f end_pos = tcr.end_pos; Vec2f end_pos = tcr.end_pos;
@ -52,7 +43,7 @@ std::string WipeTowerIntegration::append_tcr(GCodeGenerator &gcodegen, const Wip
} }
Vec2f wipe_tower_offset = tcr.priming ? Vec2f::Zero() : m_wipe_tower_pos; Vec2f wipe_tower_offset = tcr.priming ? Vec2f::Zero() : m_wipe_tower_pos;
float wipe_tower_rotation = tcr.priming ? 0.f : alpha; float wipe_tower_rotation = tcr.priming ? 0.f : this->get_alpha();
std::string tcr_rotated_gcode = post_process_wipe_tower_moves(tcr, wipe_tower_offset, wipe_tower_rotation); std::string tcr_rotated_gcode = post_process_wipe_tower_moves(tcr, wipe_tower_offset, wipe_tower_rotation);
@ -145,7 +136,7 @@ std::string WipeTowerIntegration::append_tcr(GCodeGenerator &gcodegen, const Wip
Geometry::ArcWelder::Path path; Geometry::ArcWelder::Path path;
path.reserve(tcr.wipe_path.size()); path.reserve(tcr.wipe_path.size());
std::transform(tcr.wipe_path.begin(), tcr.wipe_path.end(), std::back_inserter(path), std::transform(tcr.wipe_path.begin(), tcr.wipe_path.end(), std::back_inserter(path),
[&gcodegen, &transform_wt_pt](const Vec2f &wipe_pt) { [&gcodegen, this](const Vec2f &wipe_pt) {
return Geometry::ArcWelder::Segment{ wipe_tower_point_to_object_point(gcodegen, transform_wt_pt(wipe_pt)) }; return Geometry::ArcWelder::Segment{ wipe_tower_point_to_object_point(gcodegen, transform_wt_pt(wipe_pt)) };
}); });
// Pass to the wipe cache. // Pass to the wipe cache.

View File

@ -39,8 +39,23 @@ public:
std::string tool_change(GCodeGenerator &gcodegen, int extruder_id, bool finish_layer); std::string tool_change(GCodeGenerator &gcodegen, int extruder_id, bool finish_layer);
std::string finalize(GCodeGenerator &gcodegen); std::string finalize(GCodeGenerator &gcodegen);
std::vector<float> used_filament_length() const; std::vector<float> used_filament_length() const;
WipeTower::ToolChangeResult get_toolchange(std::size_t index) {
return m_tool_changes.at(m_layer_idx).at(index);
}
Vec2f transform_wt_pt(const Vec2f& pt) const {
Vec2f out = Eigen::Rotation2Df(this->get_alpha()) * pt;
out += m_wipe_tower_pos;
return out;
};
private: private:
// Toolchangeresult.gcode assumes the wipe tower corner is at the origin (except for priming lines)
// We want to rotate and shift all extrusions (gcode postprocessing) and starting and ending position
float get_alpha() const {
return m_wipe_tower_rotation / 180.f * float(M_PI);
}
WipeTowerIntegration& operator=(const WipeTowerIntegration&); WipeTowerIntegration& operator=(const WipeTowerIntegration&);
std::string append_tcr(GCodeGenerator &gcodegen, const WipeTower::ToolChangeResult &tcr, int new_extruder_id, double z = -1.) const; std::string append_tcr(GCodeGenerator &gcodegen, const WipeTower::ToolChangeResult &tcr, int new_extruder_id, double z = -1.) const;

View File

@ -1484,6 +1484,21 @@ const WipeTowerData& Print::wipe_tower_data(size_t extruders_cnt) const
return m_wipe_tower_data; return m_wipe_tower_data;
} }
bool is_toolchange_required(
const bool first_layer,
const unsigned last_extruder_id,
const unsigned extruder_id,
const unsigned current_extruder_id
) {
if (first_layer && extruder_id == last_extruder_id) {
return true;
}
if (extruder_id != current_extruder_id) {
return true;
}
return false;
}
void Print::_make_wipe_tower() void Print::_make_wipe_tower()
{ {
m_wipe_tower_data.clear(); m_wipe_tower_data.clear();
@ -1552,10 +1567,11 @@ void Print::_make_wipe_tower()
unsigned int current_extruder_id = m_wipe_tower_data.tool_ordering.all_extruders().back(); unsigned int current_extruder_id = m_wipe_tower_data.tool_ordering.all_extruders().back();
for (auto &layer_tools : m_wipe_tower_data.tool_ordering.layer_tools()) { // for all layers for (auto &layer_tools : m_wipe_tower_data.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_wipe_tower_data.tool_ordering.front();
wipe_tower.plan_toolchange((float)layer_tools.print_z, (float)layer_tools.wipe_tower_layer_height, current_extruder_id, current_extruder_id, false); wipe_tower.plan_toolchange((float)layer_tools.print_z, (float)layer_tools.wipe_tower_layer_height, current_extruder_id, current_extruder_id, false);
for (const auto extruder_id : layer_tools.extruders) { for (const auto extruder_id : layer_tools.extruders) {
if ((first_layer && extruder_id == m_wipe_tower_data.tool_ordering.all_extruders().back()) || extruder_id != current_extruder_id) { const bool first_layer{&layer_tools == &m_wipe_tower_data.tool_ordering.front()};
const unsigned last_extruder_id{m_wipe_tower_data.tool_ordering.all_extruders().back()};
if (is_toolchange_required(first_layer, last_extruder_id, extruder_id, current_extruder_id)) {
float volume_to_wipe = wipe_volumes[current_extruder_id][extruder_id]; // total volume to wipe after this toolchange float volume_to_wipe = wipe_volumes[current_extruder_id][extruder_id]; // total volume to wipe after this toolchange
// Not all of that can be used for infill purging: // Not all of that can be used for infill purging:
volume_to_wipe -= (float)m_config.filament_minimal_purge_on_wipe_tower.get_at(extruder_id); volume_to_wipe -= (float)m_config.filament_minimal_purge_on_wipe_tower.get_at(extruder_id);

View File

@ -493,6 +493,13 @@ private:
WipeTowerData &operator=(const WipeTowerData & /* rhs */) = delete; WipeTowerData &operator=(const WipeTowerData & /* rhs */) = delete;
}; };
bool is_toolchange_required(
const bool first_layer,
const unsigned last_extruder_id,
const unsigned extruder_id,
const unsigned current_extruder_id
);
struct PrintStatistics struct PrintStatistics
{ {
PrintStatistics() { clear(); } PrintStatistics() { clear(); }