ENH: wipe tower add solid infill for support filament

jira: none

Change-Id: I438e06b5e50259d5a9caefbc0d8580187c2b7051
This commit is contained in:
zhimin.zeng 2025-01-01 12:02:53 +08:00 committed by lane.wei
parent c87f7a5957
commit 8a6b9851db
2 changed files with 144 additions and 16 deletions

View File

@ -2092,17 +2092,24 @@ WipeTower::ToolChangeResult WipeTower::finish_layer_new(bool extrude_perimeter,
bool toolchanges_on_layer = m_layer_info->toolchanges_depth() > WT_EPSILON; bool toolchanges_on_layer = m_layer_info->toolchanges_depth() > WT_EPSILON;
std::vector<Vec2f> finish_rect_wipe_path;
if (extrude_fill_wall) { if (extrude_fill_wall) {
// inner perimeter of the sparse section, if there is space for it: // inner perimeter of the sparse section, if there is space for it:
if (fill_box.ru.y() - fill_box.rd.y() > m_perimeter_width - WT_EPSILON) if (fill_box.ru.y() - fill_box.rd.y() > m_perimeter_width - WT_EPSILON) {
writer.rectangle_fill_box(this, fill_box.ld, fill_box.rd.x() - fill_box.ld.x(), fill_box.ru.y() - fill_box.rd.y(), feedrate); writer.rectangle_fill_box(this, fill_box.ld, fill_box.rd.x() - fill_box.ld.x(), fill_box.ru.y() - fill_box.rd.y(), feedrate);
Vec2f target = (writer.pos() == fill_box.ld ? fill_box.rd :
(writer.pos() == fill_box.rd ? fill_box.ru :
(writer.pos() == fill_box.ru ? fill_box.lu :
fill_box.ld)));
finish_rect_wipe_path.emplace_back(writer.pos());
finish_rect_wipe_path.emplace_back(target);
}
} }
// Extrude infill to support the material to be printed above. // Extrude infill to support the material to be printed above.
const float dy = (fill_box.lu.y() - fill_box.ld.y() - m_perimeter_width); const float dy = (fill_box.lu.y() - fill_box.ld.y() - m_perimeter_width);
float left = fill_box.lu.x() + 2 * m_perimeter_width; float left = fill_box.lu.x() + 2 * m_perimeter_width;
float right = fill_box.ru.x() - 2 * m_perimeter_width; float right = fill_box.ru.x() - 2 * m_perimeter_width;
std::vector<Vec2f> finish_rect_wipe_path;
if (extrude_fill && dy > m_perimeter_width) { if (extrude_fill && dy > m_perimeter_width) {
writer.travel(fill_box.ld + Vec2f(m_perimeter_width * 2, 0.f)) writer.travel(fill_box.ld + Vec2f(m_perimeter_width * 2, 0.f))
.append(";--------------------\n" .append(";--------------------\n"
@ -2144,6 +2151,8 @@ WipeTower::ToolChangeResult WipeTower::finish_layer_new(bool extrude_perimeter,
writer.travel(x, writer.y()); writer.travel(x, writer.y());
writer.extrude(x, i % 2 ? fill_box.rd.y() : fill_box.ru.y()); writer.extrude(x, i % 2 ? fill_box.rd.y() : fill_box.ru.y());
} }
finish_rect_wipe_path.clear();
// BBS: add wipe_path for this case: only with finish rectangle // BBS: add wipe_path for this case: only with finish rectangle
finish_rect_wipe_path.emplace_back(writer.pos()); finish_rect_wipe_path.emplace_back(writer.pos());
finish_rect_wipe_path.emplace_back(Vec2f(left + dx * n, n % 2 ? fill_box.ru.y() : fill_box.rd.y())); finish_rect_wipe_path.emplace_back(Vec2f(left + dx * n, n % 2 ? fill_box.ru.y() : fill_box.rd.y()));
@ -2217,7 +2226,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer_new(bool extrude_perimeter,
return construct_tcr(writer, false, m_current_tool, true, 0.f); return construct_tcr(writer, false, m_current_tool, true, 0.f);
} }
WipeTower::ToolChangeResult WipeTower::finish_block(const WipeTowerBlock &block, int filament_id, bool extrude_perimeter, bool extrude_fill) WipeTower::ToolChangeResult WipeTower::finish_block(const WipeTowerBlock &block, int filament_id, bool extrude_fill)
{ {
WipeTowerWriter writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar); WipeTowerWriter writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar);
writer.set_extrusion_flow(m_extrusion_flow) writer.set_extrusion_flow(m_extrusion_flow)
@ -2239,15 +2248,21 @@ WipeTower::ToolChangeResult WipeTower::finish_block(const WipeTowerBlock &block,
bool toolchanges_on_layer = m_layer_info->toolchanges_depth() > WT_EPSILON; bool toolchanges_on_layer = m_layer_info->toolchanges_depth() > WT_EPSILON;
std::vector<Vec2f> finish_rect_wipe_path;
// inner perimeter of the sparse section, if there is space for it: // inner perimeter of the sparse section, if there is space for it:
if (fill_box.ru.y() - fill_box.rd.y() > m_perimeter_width - WT_EPSILON) if (fill_box.ru.y() - fill_box.rd.y() > m_perimeter_width - WT_EPSILON) {
writer.rectangle_fill_box(this, fill_box.ld, fill_box.rd.x() - fill_box.ld.x(), fill_box.ru.y() - fill_box.rd.y(), feedrate); writer.rectangle_fill_box(this, fill_box.ld, fill_box.rd.x() - fill_box.ld.x(), fill_box.ru.y() - fill_box.rd.y(), feedrate);
Vec2f target = (writer.pos() == fill_box.ld ? fill_box.rd :
(writer.pos() == fill_box.rd ? fill_box.ru :
(writer.pos() == fill_box.ru ? fill_box.lu : fill_box.ld)));
finish_rect_wipe_path.emplace_back(writer.pos());
finish_rect_wipe_path.emplace_back(target);
}
// Extrude infill to support the material to be printed above. // Extrude infill to support the material to be printed above.
const float dy = (fill_box.lu.y() - fill_box.ld.y() - m_perimeter_width); const float dy = (fill_box.lu.y() - fill_box.ld.y() - m_perimeter_width);
float left = fill_box.lu.x() + 2 * m_perimeter_width; float left = fill_box.lu.x() + 2 * m_perimeter_width;
float right = fill_box.ru.x() - 2 * m_perimeter_width; float right = fill_box.ru.x() - 2 * m_perimeter_width;
std::vector<Vec2f> finish_rect_wipe_path;
if (extrude_fill && dy > m_perimeter_width) { if (extrude_fill && dy > m_perimeter_width) {
writer.travel(fill_box.ld + Vec2f(m_perimeter_width * 2, 0.f)) writer.travel(fill_box.ld + Vec2f(m_perimeter_width * 2, 0.f))
.append(";--------------------\n" .append(";--------------------\n"
@ -2289,6 +2304,7 @@ WipeTower::ToolChangeResult WipeTower::finish_block(const WipeTowerBlock &block,
writer.travel(x, writer.y()); writer.travel(x, writer.y());
writer.extrude(x, i % 2 ? fill_box.rd.y() : fill_box.ru.y()); writer.extrude(x, i % 2 ? fill_box.rd.y() : fill_box.ru.y());
} }
finish_rect_wipe_path.clear();
// BBS: add wipe_path for this case: only with finish rectangle // BBS: add wipe_path for this case: only with finish rectangle
finish_rect_wipe_path.emplace_back(writer.pos()); finish_rect_wipe_path.emplace_back(writer.pos());
finish_rect_wipe_path.emplace_back(Vec2f(left + dx * n, n % 2 ? fill_box.ru.y() : fill_box.rd.y())); finish_rect_wipe_path.emplace_back(Vec2f(left + dx * n, n % 2 ? fill_box.ru.y() : fill_box.rd.y()));
@ -2302,9 +2318,6 @@ WipeTower::ToolChangeResult WipeTower::finish_block(const WipeTowerBlock &block,
// BBS // BBS
box_coordinates wt_box(Vec2f(0.f, 0.f), m_wipe_tower_width, m_layer_info->depth + m_perimeter_width); box_coordinates wt_box(Vec2f(0.f, 0.f), m_wipe_tower_width, m_layer_info->depth + m_perimeter_width);
wt_box = align_perimeter(wt_box); wt_box = align_perimeter(wt_box);
if (extrude_perimeter) {
writer.rectangle(wt_box, feedrate);
}
// Now prepare future wipe. box contains rectangle that was extruded last (ccw). // Now prepare future wipe. box contains rectangle that was extruded last (ccw).
Vec2f target = (writer.pos() == wt_box.ld ? wt_box.rd : (writer.pos() == wt_box.rd ? wt_box.ru : (writer.pos() == wt_box.ru ? wt_box.lu : wt_box.ld))); Vec2f target = (writer.pos() == wt_box.ld ? wt_box.rd : (writer.pos() == wt_box.rd ? wt_box.ru : (writer.pos() == wt_box.ru ? wt_box.lu : wt_box.ld)));
@ -2325,6 +2338,69 @@ WipeTower::ToolChangeResult WipeTower::finish_block(const WipeTowerBlock &block,
return construct_block_tcr(writer, false, filament_id, true, 0.f); return construct_block_tcr(writer, false, filament_id, true, 0.f);
} }
WipeTower::ToolChangeResult WipeTower::finish_block_solid(const WipeTowerBlock &block, int filament_id, bool extrude_fill)
{
WipeTowerWriter writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar);
writer.set_extrusion_flow(m_extrusion_flow)
.set_z(m_z_pos)
.set_initial_tool(filament_id)
.set_y_shift(m_y_shift - (m_current_shape == SHAPE_REVERSED ? m_layer_info->toolchanges_depth() : 0.f));
writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_Start) + "\n");
// Slow down on the 1st layer.
bool first_layer = is_first_layer();
// BBS: speed up perimeter speed to 90mm/s for non-first layer
float feedrate = first_layer ? std::min(m_first_layer_speed * 60.f, 5400.f) : std::min(60.0f * m_filpar[filament_id].max_e_speed / m_extrusion_flow, 5400.f);
box_coordinates fill_box(Vec2f(0, 0), 0, 0);
fill_box = box_coordinates(Vec2f(m_perimeter_width, block.cur_depth), m_wipe_tower_width - 2 * m_perimeter_width,
block.start_depth + block.layer_depths[m_cur_layer_id] - block.cur_depth - m_perimeter_width);
writer.set_initial_position((m_left_to_right ? fill_box.rd : fill_box.ld), m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation);
m_left_to_right = !m_left_to_right;
bool toolchanges_on_layer = m_layer_info->toolchanges_depth() > WT_EPSILON;
// Extrude infill to support the material to be printed above.
const float dy = (fill_box.lu.y() - fill_box.ld.y());
float left = fill_box.lu.x();
float right = fill_box.ru.x();
std::vector<Vec2f> finish_rect_wipe_path;
{
writer.append(";--------------------\n"
"; CP EMPTY GRID START\n")
.comment_with_value(" layer #", m_num_layer_changes + 1);
float y = fill_box.ld.y();
int n = (dy + 0.25 * m_perimeter_width) / m_perimeter_width + 1;
float spacing = m_perimeter_width;
int i = 0;
for (i = 0; i < n; ++i) {
writer.extrude(m_left_to_right ? right : left, writer.y(), feedrate);
if (i == n - 1) {
writer.add_wipe_point(writer.pos()).add_wipe_point(Vec2f(m_left_to_right ? left : right, writer.y()));
break;
}
m_left_to_right = !m_left_to_right;
y = y + spacing;
writer.extrude(writer.x(), y, feedrate);
}
writer.append("; CP EMPTY GRID END\n"
";------------------\n\n\n\n\n\n\n");
}
writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_End) + "\n");
// Ask our writer about how much material was consumed.
// Skip this in case the layer is sparse and config option to not print sparse layers is enabled.
if (!m_no_sparse_layers || toolchanges_on_layer)
if (filament_id < m_used_filament_length.size())
m_used_filament_length[filament_id] += writer.get_and_reset_used_filament_length();
return construct_block_tcr(writer, false, filament_id, true, 0.f);
}
void WipeTower::toolchange_wipe_new(WipeTowerWriter &writer, const box_coordinates &cleaning_box, float wipe_length) void WipeTower::toolchange_wipe_new(WipeTowerWriter &writer, const box_coordinates &cleaning_box, float wipe_length)
{ {
writer.set_extrusion_flow(m_extrusion_flow * (is_first_layer() ? 1.15f : 1.f)).append("; CP TOOLCHANGE WIPE\n"); writer.set_extrusion_flow(m_extrusion_flow * (is_first_layer() ? 1.15f : 1.f)).append("; CP TOOLCHANGE WIPE\n");
@ -2511,8 +2587,8 @@ void WipeTower::generate_wipe_tower_blocks()
for (auto& info : m_plan) { for (auto& info : m_plan) {
for (const WipeTowerInfo::ToolChange &tool_change : info.tool_changes) { for (const WipeTowerInfo::ToolChange &tool_change : info.tool_changes) {
if (is_in_same_extruder(tool_change.old_tool, tool_change.new_tool)) { if (is_in_same_extruder(tool_change.old_tool, tool_change.new_tool)) {
int filament_category = get_filament_category(tool_change.old_tool); int filament_category = get_filament_category(tool_change.new_tool);
add_depth_to_block(tool_change.old_tool, filament_category, tool_change.required_depth); add_depth_to_block(tool_change.new_tool, filament_category, tool_change.required_depth);
} }
else { else {
int old_filament_category = get_filament_category(tool_change.old_tool); int old_filament_category = get_filament_category(tool_change.old_tool);
@ -2541,13 +2617,36 @@ void WipeTower::generate_wipe_tower_blocks()
const auto &layer_category_depths = all_layer_category_to_depth[layer_id]; const auto &layer_category_depths = all_layer_category_to_depth[layer_id];
for (auto iter = layer_category_depths.begin(); iter != layer_category_depths.end(); ++iter) { for (auto iter = layer_category_depths.begin(); iter != layer_category_depths.end(); ++iter) {
auto& block = get_block_by_category(iter->first); auto& block = get_block_by_category(iter->first);
if (block.layer_depths.empty()) if (block.layer_depths.empty()) {
block.layer_depths.resize(all_layer_category_to_depth.size(), 0); block.layer_depths.resize(all_layer_category_to_depth.size(), 0);
block.solid_infill.resize(all_layer_category_to_depth.size(), false);
}
block.depth = std::max(block.depth, iter->second); block.depth = std::max(block.depth, iter->second);
block.layer_depths[layer_id] = iter->second; block.layer_depths[layer_id] = iter->second;
} }
} }
// add solid infill flag
int solid_infill_layer = 2;
for (WipeTowerBlock& block : m_wipe_tower_blocks) {
for (int layer_id = 0; layer_id < all_layer_category_to_depth.size(); ++layer_id) {
std::unordered_map<int, float> &category_to_depth = all_layer_category_to_depth[layer_id];
if (is_approx(category_to_depth[block.filament_category], 0.f)) {
int layer_count = solid_infill_layer;
while (layer_count > 0) {
if (layer_id + layer_count < all_layer_category_to_depth.size()) {
std::unordered_map<int, float>& up_layer_depth = all_layer_category_to_depth[layer_id + layer_count];
if (!is_approx(up_layer_depth[block.filament_category], 0.f)) {
block.solid_infill[layer_id] = true;
break;
}
}
--layer_count;
}
}
}
}
// 4. get real depth for every layer // 4. get real depth for every layer
for (int layer_id = m_plan.size() - 1; layer_id >= 0; --layer_id) { for (int layer_id = m_plan.size() - 1; layer_id >= 0; --layer_id) {
m_plan[layer_id].depth = 0; m_plan[layer_id].depth = 0;
@ -2757,10 +2856,22 @@ void WipeTower::generate_new(std::vector<std::vector<WipeTower::ToolChangeResult
// this layer has no tool_change // this layer has no tool_change
if (wall_idx == -1) { if (wall_idx == -1) {
if (m_enable_timelapse_print) { bool need_insert_solid_infill = false;
timelapse_wall = only_generate_out_wall(true); for (const WipeTowerBlock &block : m_wipe_tower_blocks) {
if (block.solid_infill[m_cur_layer_id] && (block.filament_category != m_filament_categories[m_current_tool])) {
need_insert_solid_infill = true;
break;
}
}
if (need_insert_solid_infill) {
wall_idx = m_current_tool;
} else {
if (m_enable_timelapse_print) {
timelapse_wall = only_generate_out_wall(true);
}
finish_layer_tcr = finish_layer_new(m_enable_timelapse_print ? false : true, layer.extruder_fill);
} }
finish_layer_tcr = finish_layer_new(m_enable_timelapse_print ? false : true, layer.extruder_fill);
} }
// generate tool change // generate tool change
@ -2789,6 +2900,10 @@ void WipeTower::generate_new(std::vector<std::vector<WipeTower::ToolChangeResult
// insert finish block // insert finish block
if (wall_idx != -1) { if (wall_idx != -1) {
if (layer.tool_changes.empty()) {
finish_layer_tcr = finish_layer_new(true, false, false);
}
for (const WipeTowerBlock& block : m_wipe_tower_blocks) { for (const WipeTowerBlock& block : m_wipe_tower_blocks) {
if (block.cur_depth + EPSILON >= block.start_depth + block.layer_depths[m_cur_layer_id]) { if (block.cur_depth + EPSILON >= block.start_depth + block.layer_depths[m_cur_layer_id]) {
continue; continue;
@ -2801,7 +2916,11 @@ void WipeTower::generate_new(std::vector<std::vector<WipeTower::ToolChangeResult
finish_layer_filament = block.last_nozzle_change_id; finish_layer_filament = block.last_nozzle_change_id;
} }
ToolChangeResult finish_block_tcr = finish_block(block, finish_layer_filament, false, layer.extruder_fill); ToolChangeResult finish_block_tcr;
if (block.solid_infill[m_cur_layer_id] && block.filament_category != m_filament_categories[wall_idx])
finish_block_tcr = finish_block_solid(block, finish_layer_filament, layer.extruder_fill);
else
finish_block_tcr = finish_block(block, finish_layer_filament, layer.extruder_fill);
bool has_inserted = false; bool has_inserted = false;
{ {
@ -2821,6 +2940,13 @@ void WipeTower::generate_new(std::vector<std::vector<WipeTower::ToolChangeResult
has_inserted = true; has_inserted = true;
} }
} }
if (!has_inserted) {
if (finish_block_tcr.gcode.empty())
finish_block_tcr = finish_block_tcr;
else
finish_layer_tcr = merge_tcr(finish_layer_tcr, finish_block_tcr);
}
assert(has_inserted); assert(has_inserted);
} }
} }

View File

@ -308,6 +308,7 @@ public:
int block_id{0}; int block_id{0};
int filament_category{0}; int filament_category{0};
std::vector<float> layer_depths; std::vector<float> layer_depths;
std::vector<bool> solid_infill;
float depth{0}; float depth{0};
float start_depth{0}; float start_depth{0};
float cur_depth{0}; float cur_depth{0};
@ -343,7 +344,8 @@ public:
ToolChangeResult tool_change_new(size_t new_tool); ToolChangeResult tool_change_new(size_t new_tool);
NozzleChangeResult nozzle_change_new(int old_filament_id, int new_filament_id); NozzleChangeResult nozzle_change_new(int old_filament_id, int new_filament_id);
ToolChangeResult finish_layer_new(bool extrude_perimeter = true, bool extrude_fill = true, bool extrude_fill_wall = true); ToolChangeResult finish_layer_new(bool extrude_perimeter = true, bool extrude_fill = true, bool extrude_fill_wall = true);
ToolChangeResult finish_block(const WipeTowerBlock &block, int filament_id, bool extrude_perimeter = true, bool extrude_fill = true); ToolChangeResult finish_block(const WipeTowerBlock &block, int filament_id, bool extrude_fill = true);
ToolChangeResult finish_block_solid(const WipeTowerBlock &block, int filament_id, bool extrude_fill = true);
void toolchange_wipe_new(WipeTowerWriter &writer, const box_coordinates &cleaning_box, float wipe_length); void toolchange_wipe_new(WipeTowerWriter &writer, const box_coordinates &cleaning_box, float wipe_length);
private: private: