ENH: Add gaps in the outer wall of the wipe_tower

and modify the path of travel to the wipe_tower after flushing

jira:none

Change-Id: Id4b0571fd12372c59cf522c13e256c7cc4ac3565
(cherry picked from commit 17771d0fbf753dd22411ce490586958bd643264e)
This commit is contained in:
jiangkai.zhao 2025-01-02 17:20:53 +08:00 committed by Noisyfox
parent 4e0e04af96
commit 70151fed7c
9 changed files with 499 additions and 24 deletions

View file

@ -15,7 +15,8 @@
namespace Slic3r
{
static const double wipe_tower_wall_infill_overlap = 0.0;
static const double wipe_tower_wall_infill_overlap_new = -0.2;
static bool is_used_gap_wall = true;
inline float align_round(float value, float base)
{
return std::round(value / base) * base;
@ -60,6 +61,39 @@ static bool is_valid_gcode(const std::string &gcode)
return is_valid;
}
struct Segment
{
Vec2f start;
Vec2f end;
Segment(const Vec2f &s, const Vec2f &e) : start(s), end(e) {}
bool is_valid() const { return start.y() < end.y(); }
};
static std::vector<Segment> remove_points_from_segment(const Segment &segment, const std::vector<Vec2f> &skip_points, double range)
{
std::vector<Segment> result;
result.push_back(segment);
float x = segment.start.x();
for (const Vec2f &point : skip_points) {
std::vector<Segment> newResult;
for (const auto &seg : result) {
if (point.y() + range <= seg.start.y() || point.y() - range >= seg.end.y()) {
newResult.push_back(seg);
} else {
if (point.y() - range > seg.start.y()) { newResult.push_back(Segment(Vec2f(x, seg.start.y()), Vec2f(x, point.y() - range))); }
if (point.y() + range < seg.end.y()) { newResult.push_back(Segment(Vec2f(x, point.y() + range), Vec2f(x, seg.end.y()))); }
}
}
result = newResult;
}
result.erase(std::remove_if(result.begin(), result.end(), [](const Segment &seg) { return !seg.is_valid(); }), result.end());
return result;
}
class WipeTowerWriter
{
public:
@ -773,18 +807,19 @@ Vec2f WipeTower::get_next_pos(const WipeTower::box_coordinates &cleaning_box, fl
Vec2f res;
int index = m_cur_layer_id % 4;
Vec2f offset = is_used_gap_wall ? Vec2f(5 * m_perimeter_width, 0) : Vec2f{0, 0};
switch (index % 4) {
case 0:
res = cleaning_box.ld + pos_offset;
res = offset +cleaning_box.ld + pos_offset;
break;
case 1:
res = cleaning_box.rd + pos_offset + Vec2f(0, y_offset);
res = -offset +cleaning_box.rd + pos_offset + Vec2f(0, y_offset);
break;
case 2:
res = cleaning_box.rd + pos_offset;
res = -offset+ cleaning_box.rd + pos_offset;
break;
case 3:
res = cleaning_box.ld + pos_offset + Vec2f(0, y_offset);
res = offset+cleaning_box.ld + pos_offset + Vec2f(0, y_offset);
break;
default: break;
}
@ -1821,7 +1856,7 @@ static WipeTower::ToolChangeResult merge_tcr(WipeTower::ToolChangeResult& first,
{
assert(first.new_tool == second.initial_tool);
WipeTower::ToolChangeResult out = first;
if (first.end_pos != second.start_pos)
if ((first.end_pos - second.start_pos).norm()> (float)EPSILON)
out.gcode += "G1 X" + Slic3r::float_to_string_decimal_point(second.start_pos.x(), 3)
+ " Y" + Slic3r::float_to_string_decimal_point(second.start_pos.y(), 3)
+ " F7200\n";
@ -1842,6 +1877,50 @@ static WipeTower::ToolChangeResult merge_tcr(WipeTower::ToolChangeResult& first,
return out;
}
void WipeTower::get_wall_skip_points(const WipeTowerInfo &layer)
{
m_wall_skip_points.clear();
std::unordered_map<int, float> cur_block_depth;
for (int i = 0; i < int(layer.tool_changes.size()); ++i) {
const WipeTowerInfo::ToolChange &tool_change = layer.tool_changes[i];
size_t old_filament = tool_change.old_tool;
size_t new_filament = tool_change.new_tool;
float spacing = m_layer_info->extra_spacing;
if (has_tpu_filament() && m_layer_info->extra_spacing < m_tpu_fixed_spacing) spacing = 1;
float nozzle_change_depth = tool_change.nozzle_change_depth * spacing;
//float nozzle_change_depth = tool_change.nozzle_change_depth * (has_tpu_filament() ? m_tpu_fixed_spacing : layer.extra_spacing);
auto &block = get_block_by_category(m_filpar[new_filament].category);
float wipe_depth = tool_change.required_depth - nozzle_change_depth;
float process_depth = 0.f;
if (!cur_block_depth.count(m_filpar[new_filament].category))
cur_block_depth[m_filpar[new_filament].category] = block.start_depth;
process_depth = cur_block_depth[m_filpar[new_filament].category];
if (!m_filament_map.empty() && new_filament < m_filament_map.size() && m_filament_map[old_filament] != m_filament_map[new_filament]) {
if (m_filament_categories[new_filament] == m_filament_categories[old_filament])
process_depth += nozzle_change_depth;
else {
if (!cur_block_depth.count(m_filpar[old_filament].category))
cur_block_depth[m_filpar[old_filament].category]=m_perimeter_width; //Here, it is assumed that the bottom-most lines of the blocks are adjacent to the previous line.
cur_block_depth[m_filpar[old_filament].category] += nozzle_change_depth;
}
}
{
Vec2f res;
int index = m_cur_layer_id % 4;
switch (index % 4) {
case 0: res = Vec2f(0, process_depth); break;
case 1: res = Vec2f(m_wipe_tower_width, process_depth + wipe_depth - layer.extra_spacing*m_perimeter_width); break;
case 2: res = Vec2f(m_wipe_tower_width, process_depth); break;
case 3: res = Vec2f(0, process_depth + wipe_depth - layer.extra_spacing * m_perimeter_width); break;
default: break;
}
m_wall_skip_points.emplace_back(res);
}
cur_block_depth[m_filpar[new_filament].category] = process_depth + wipe_depth ;
}
}
WipeTower::ToolChangeResult WipeTower::tool_change_new(size_t new_tool)
{
m_nozzle_change_result.gcode.clear();
@ -1930,7 +2009,6 @@ WipeTower::ToolChangeResult WipeTower::tool_change_new(size_t new_tool)
Vec2f initial_position = get_next_pos(cleaning_box, wipe_length);
//Vec2f initial_position = cleaning_box.ld;
writer.set_initial_position(initial_position + Vec2f(m_perimeter_width, m_perimeter_width), m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation);
writer.travel(initial_position);
toolchange_wipe_new(writer, cleaning_box, wipe_length);
@ -2164,7 +2242,10 @@ WipeTower::ToolChangeResult WipeTower::finish_layer_new(bool extrude_perimeter,
box_coordinates wt_box(Vec2f(0.f, 0.f), m_wipe_tower_width, wipe_tower_depth);
wt_box = align_perimeter(wt_box);
if (extrude_perimeter) {
writer.rectangle(wt_box, feedrate);
if (is_used_gap_wall)
generate_support_wall(writer, wt_box, feedrate, first_layer);
else
writer.rectangle(wt_box, feedrate);
}
// brim chamfer
@ -2436,10 +2517,33 @@ void WipeTower::toolchange_wipe_new(WipeTowerWriter &writer, const box_coordinat
need_change_flow = true;
}
if (m_left_to_right)
writer.extrude(xr + wipe_tower_wall_infill_overlap * m_perimeter_width, writer.y(), wipe_speed);
else
writer.extrude(xl - wipe_tower_wall_infill_overlap * m_perimeter_width, writer.y(), wipe_speed);
float ironing_length = 3.;
if (i == 0 && is_used_gap_wall) { // BBS: add ironing after extruding start
if (m_left_to_right) {
float dx = xr + wipe_tower_wall_infill_overlap_new * m_perimeter_width - writer.pos().x();
if (abs(dx) < ironing_length) ironing_length = abs(dx);
writer.extrude(writer.x() + ironing_length, writer.y(), wipe_speed);
writer.retract(0.8, 1800.);
writer.travel(writer.x() - 1.5 * ironing_length, writer.y(), 600.);
writer.travel(writer.x() + 1.5 * ironing_length, writer.y(), 240.);
writer.retract(-0.8, 1800.);
writer.extrude(xr + wipe_tower_wall_infill_overlap_new * m_perimeter_width, writer.y(), wipe_speed);
} else {
float dx = xl - wipe_tower_wall_infill_overlap_new * m_perimeter_width - writer.pos().x();
if (abs(dx) < ironing_length) ironing_length = abs(dx);
writer.extrude(writer.x() - ironing_length, writer.y(), wipe_speed);
writer.retract(0.8, 1800.);
writer.travel(writer.x() + 1.5 * ironing_length, writer.y(), 600.);
writer.travel(writer.x() - 1.5 * ironing_length, writer.y(), 240.);
writer.retract(-0.8, 1800.);
writer.extrude(xl - wipe_tower_wall_infill_overlap_new * m_perimeter_width, writer.y(), wipe_speed);
}
} else {
if (m_left_to_right)
writer.extrude(xr + wipe_tower_wall_infill_overlap * m_perimeter_width, writer.y(), wipe_speed);
else
writer.extrude(xl - wipe_tower_wall_infill_overlap * m_perimeter_width, writer.y(), wipe_speed);
}
// BBS: recover the flow in non-bridging area
if (need_change_flow) {
@ -2782,7 +2886,6 @@ void WipeTower::generate_new(std::vector<std::vector<WipeTower::ToolChangeResult
{
if (m_plan.empty())
return;
m_extra_spacing = 1.f;
plan_tower_new();
@ -2820,6 +2923,8 @@ void WipeTower::generate_new(std::vector<std::vector<WipeTower::ToolChangeResult
}
}
get_wall_skip_points(layer);
ToolChangeResult finish_layer_tcr;
ToolChangeResult timelapse_wall;
@ -2957,7 +3062,6 @@ void WipeTower::generate_new(std::vector<std::vector<WipeTower::ToolChangeResult
if (m_enable_timelapse_print) {
layer_result.insert(layer_result.begin(), std::move(timelapse_wall));
}
result.emplace_back(std::move(layer_result));
}
}
@ -3103,7 +3207,10 @@ WipeTower::ToolChangeResult WipeTower::only_generate_out_wall(bool is_new_mode)
wipe_tower_depth = m_wipe_tower_width;
box_coordinates wt_box(Vec2f(0.f, (m_current_shape == SHAPE_REVERSED ? m_layer_info->toolchanges_depth() : 0.f)), m_wipe_tower_width, wipe_tower_depth);
wt_box = align_perimeter(wt_box);
writer.rectangle(wt_box, feedrate);
if (is_used_gap_wall)
generate_support_wall(writer, wt_box, feedrate, first_layer);
else
writer.rectangle(wt_box, feedrate);
// 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)));
@ -3119,6 +3226,109 @@ WipeTower::ToolChangeResult WipeTower::only_generate_out_wall(bool is_new_mode)
return construct_tcr(writer, false, old_tool, true, 0.f);
}
Polygon WipeTower::generate_support_wall(WipeTowerWriter &writer, const box_coordinates &wt_box, double feedrate, bool first_layer)
{
bool is_left = false;
bool is_right = false;
for (auto pt : m_wall_skip_points) {
if (abs(pt.x()) < EPSILON) {
is_left = true;
} else if (abs(pt.x() - m_wipe_tower_width) < EPSILON) {
is_right = true;
}
}
if (is_left && is_right) {
Vec2f *p = nullptr;
p->x();
}
if (!is_left && !is_right) {
Vec2f *p = nullptr;
p->x();
}
// 3 ------------- 2
// | |
// | |
// 0 ------------- 1
int index = 0;
Vec2f cur_pos = writer.pos();
if (abs(cur_pos.x() - wt_box.ld.x()) > abs(cur_pos.x() - wt_box.rd.x())) {
if (abs(cur_pos.y() - wt_box.ld.y()) > abs(cur_pos.y() - wt_box.lu.y())) {
index = 2;
} else {
index = 1;
}
} else {
if (abs(cur_pos.y() - wt_box.ld.y()) > abs(cur_pos.y() - wt_box.lu.y())) {
index = 3;
} else {
index = 0;
}
}
std::vector<Vec2f> points;
points.emplace_back(wt_box.ld);
points.emplace_back(wt_box.rd);
points.emplace_back(wt_box.ru);
points.emplace_back(wt_box.lu);
writer.travel(points[index]);
int extruded_nums = 0;
while (extruded_nums < 4) {
index = (index + 1) % 4;
if (index == 2) {
if (is_right) {
std::vector<Segment> break_segments = remove_points_from_segment(Segment(wt_box.rd, wt_box.ru), m_wall_skip_points, 2.5 * m_perimeter_width);
for (auto iter = break_segments.begin(); iter != break_segments.end(); ++iter) {
float dx = iter->start.x() - writer.pos().x();
float dy = iter->start.y() - writer.pos().y();
float len = std::sqrt(dx * dx + dy * dy);
if (len > 0) {
writer.retract(0.8, 1800.);
writer.travel(iter->start, 600.);
writer.retract(-0.8, 1800.);
} else
writer.travel(iter->start, 600.);
writer.extrude(iter->end, feedrate);
}
writer.travel(wt_box.ru, feedrate);
} else {
writer.extrude(wt_box.ru, feedrate);
}
} else if (index == 0) {
if (is_left) {
std::vector<Segment> break_segments = remove_points_from_segment(Segment(wt_box.ld, wt_box.lu), m_wall_skip_points, 2.5 * m_perimeter_width);
for (auto iter = break_segments.rbegin(); iter != break_segments.rend(); ++iter) {
float dx = iter->end.x() - writer.pos().x();
float dy = iter->end.y() - writer.pos().y();
float len = std::sqrt(dx * dx + dy * dy);
if (len > 0) {
writer.retract(0.8, 1800.);
writer.travel(iter->end, 600.);
writer.retract(-0.8, 1800.);
} else
writer.travel(iter->end, 600.);
writer.extrude(iter->start, feedrate);
}
writer.travel(wt_box.ld, feedrate);
} else {
writer.extrude(wt_box.ld, feedrate);
}
} else {
writer.extrude(points[index], feedrate);
}
extruded_nums++;
}
return Polygon();
}
bool WipeTower::get_floating_area(float &start_pos_y, float &end_pos_y) const {
if (m_layer_info == m_plan.begin() || (m_layer_info - 1) == m_plan.begin())
return false;