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

@@ -99,7 +99,7 @@ static const std::string lift_gcode_after_printing_object = "{if toolchange_coun
Vec2d travel_point_1;
Vec2d travel_point_2;
Vec2d travel_point_3;
static bool is_used_travel_avoid_perimeter = true;
static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
{
// give safe value in case there is no start_end_points in config
@@ -404,6 +404,19 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
return gcode_out;
}
float get_wipe_avoid_pos_x(const Vec2f &wt_ori, float wt_width, float offset, bool is_default)
{
float left = 100, right = 250;
float default_value = 110.f;
float a = 0.f, b = 0.f;
if (is_default) return default_value;
a = wt_ori.x() + wt_width + offset;
b = wt_ori.x() - offset;
if (a > left && a < right) return a;
if (b > left && b < right) return b;
return default_value;
}
std::string Wipe::wipe(GCode& gcodegen,double length, bool toolchange, bool is_last)
{
std::string gcode;
@@ -503,6 +516,138 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
return outer_wall_volumetric_speed;
}
// BBS
// start_pos refers to the last position before the wipe_tower.
// end_pos refers to the wipe tower's start_pos.
// using the print coordinate system
std::string WipeTowerIntegration::generate_path_to_wipe_tower(
GCode &gcodegen, const Point &wipe_tower_left_front, const Point &start_pos, const Point &end_pos, int width, int depth, int brim_width) const
{
std::string gcode;
int alpha = scaled(2.f); // offset distance
BoundingBox wipe_tower_offset_bbx(wipe_tower_left_front, wipe_tower_left_front + Point(width, depth));
wipe_tower_offset_bbx.offset(brim_width);
wipe_tower_offset_bbx.offset(alpha);
Polygon wipe_tower_offset_polygon = wipe_tower_offset_bbx.polygon();
Polygon bed_polygon;
for (size_t i = 0; i < gcodegen.m_config.printable_area.values.size(); i++) {
bed_polygon.points.push_back(
wipe_tower_point_to_object_point(gcodegen, gcodegen.m_config.printable_area.values[i].cast<float>() + Vec2f{m_plate_origin[0], m_plate_origin[1]}));
} // gcode coordinate system to printing coordinate system
Vec2f v(1, 0); // the first print direction of end_pos.
if (abs(end_pos[0] - wipe_tower_left_front[0]) < width / 2) v = -v; // judge whether the wipe tower's infill goes to the left or right.
// Judge whether the wipe_tower_bbx_offset is outside the bed_boundary.
// If so, do nothing and just go directly to the end_pos.
bool is_bbx_in_bed = true;
for (auto &wipe_tower_bbx_p : wipe_tower_offset_polygon.points) {
if (ClipperLib::PointInPolygon(wipe_tower_bbx_p, bed_polygon.points) != 1) {
is_bbx_in_bed = false;
break;
}
}
if (!is_bbx_in_bed) {
gcode += gcodegen.travel_to(end_pos, erMixed, "Move to start pos");
check_add_eol(gcode);
return gcode;
}
// Ray-Line Segment Intersection
auto ray_intersetion_line = [](const Vec2d &a, const Vec2d &v1, const Vec2d &b, const Vec2d &c) -> std::pair<bool, Point> {
const Vec2d v2 = c - b;
double denom = cross2(v1, v2);
if (fabs(denom) < EPSILON) return {false, Point(0, 0)};
const Vec2d v12 = (a - b);
double nume_a = cross2(v2, v12);
double nume_b = cross2(v1, v12);
double t1 = nume_a / denom;
double t2 = nume_b / denom;
if (t1 >= 0 && t2 >= 0 && t2 <= 1.) {
// Get the intersection point.
Vec2d res = a + t1 * v1;
return std::pair<bool, Point>(true, scaled(res));
}
return std::pair<bool, Point>(false, {0, 0});
};
struct Inter_info
{
int inter_idx0 = -1;
Point inter_p;
};
auto calc_path_len = [](Points &points, Inter_info &beg_info, Inter_info &end_info, bool is_add) -> std::pair<std::vector<Point>, double> {
int beg = is_add ? (beg_info.inter_idx0 + 1) % points.size() : beg_info.inter_idx0;
int end = is_add ? end_info.inter_idx0 : (end_info.inter_idx0 + 1) % points.size();
int i = beg;
double len = 0;
std::vector<Point> path;
path.push_back(beg_info.inter_p);
len += (unscale(beg_info.inter_p) - unscale(points[beg])).squaredNorm();
while (i != end) {
int ni = is_add ? (i + 1) % points.size() : (i - 1 + points.size()) % points.size();
auto a = unscale(points[i]);
auto b = unscale(points[ni]);
len += (a - b).squaredNorm();
path.push_back(points[i]);
i = ni;
}
path.push_back(points[end]);
path.push_back(end_info.inter_p);
len += (unscale(end_info.inter_p) - unscale(points[end])).squaredNorm();
return {path, len};
};
// calculate the intersection point of end_pos along vector v with the wipe_tower_offset_polygon.
// store in inter_info.
// represent this intersection by 'p'.
Inter_info inter_info;
for (size_t i = 0; i < wipe_tower_offset_polygon.points.size(); i++) {
auto &a = wipe_tower_offset_polygon[i];
auto &b = wipe_tower_offset_polygon[(i + 1) % wipe_tower_offset_polygon.points.size()];
auto [is_inter, inter_p] = ray_intersetion_line(unscale(end_pos), v.cast<double>(), unscale(a), unscale(b));
if (is_inter) {
inter_info.inter_idx0 = i;
inter_info.inter_p = inter_p;
break;
}
}
if (inter_info.inter_idx0 == -1) {
gcode += gcodegen.travel_to(end_pos, erMixed, "Move to start pos");
check_add_eol(gcode);
return gcode;
}
// calculate the other intersection of start_to_p with the wipe_tower_offset_polygon.
// represent this intersection by 'p_'.
Inter_info inter_info2;
Linef start_to_p(unscale(start_pos), unscale(inter_info.inter_p));
for (size_t i = 0; i < wipe_tower_offset_polygon.points.size(); i++) {
if (i == inter_info.inter_idx0) continue;
Vec2d a = unscale(wipe_tower_offset_polygon.points[i]);
Vec2d b = unscale(wipe_tower_offset_polygon.points[(i + 1) % wipe_tower_offset_polygon.points.size()]);
Linef tower_edge(a, b);
Vec2d inter;
if (line_alg::intersection(start_to_p, tower_edge, &inter)) {
inter_info2.inter_p = scaled(inter);
inter_info2.inter_idx0 = i;
break;
}
}
// if p_ does not exist, go directly to p.
// else p travels along the shorter path on the wipe_tower_offset_polygon to p_
if (inter_info2.inter_idx0 == -1) {
gcode += gcodegen.travel_to(inter_info.inter_p, erMixed, "Move to start pos");
check_add_eol(gcode);
} else {
std::vector<Point> path;
auto [path1, len1] = calc_path_len(wipe_tower_offset_polygon.points, inter_info2, inter_info, true);
auto [path2, len2] = calc_path_len(wipe_tower_offset_polygon.points, inter_info2, inter_info, false);
path = len1 < len2 ? path1 : path2;
for (size_t i = 0; i < path.size(); i++) {
gcode += gcodegen.travel_to(path[i], erMixed, "Move to start pos");
check_add_eol(gcode);
}
}
gcode += gcodegen.travel_to(end_pos, erMixed, "Move to start pos");
check_add_eol(gcode);
return gcode;
}
std::string WipeTowerIntegration::append_tcr(GCode& gcodegen, const WipeTower::ToolChangeResult& tcr, int new_filament_id, double z) const
{
if (new_filament_id != -1 && new_filament_id != tcr.new_tool)
@@ -642,6 +787,7 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
old_filament_e_feedrate = old_filament_e_feedrate == 0 ? 100 : old_filament_e_feedrate;
int new_filament_e_feedrate = (int)(60.0 * full_config.filament_max_volumetric_speed.get_at(new_filament_id) / filament_area);
new_filament_e_feedrate = new_filament_e_feedrate == 0 ? 100 : new_filament_e_feedrate;
float wipe_avoid_pos_x = get_wipe_avoid_pos_x(m_wipe_tower_pos, gcodegen.m_config.prime_tower_width.value, 3.f + gcodegen.m_config.prime_tower_brim_width.value,false);
config.set_key_value("max_layer_z", new ConfigOptionFloat(gcodegen.m_max_layer_z));
config.set_key_value("relative_e_axis", new ConfigOptionBool(full_config.use_relative_e_distances));
@@ -670,6 +816,8 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
config.set_key_value("travel_point_3_y", new ConfigOptionFloat(float(travel_point_3.y())));
config.set_key_value("flush_length", new ConfigOptionFloat(purge_length));
config.set_key_value("wipe_avoid_perimeter", new ConfigOptionBool(is_used_travel_avoid_perimeter));
config.set_key_value("wipe_avoid_pos_x", new ConfigOptionFloat(wipe_avoid_pos_x));
int flush_count = std::min(g_max_flush_count, (int) std::round(purge_volume / g_purge_volume_one_time));
float flush_unit = purge_length / flush_count;
@@ -706,9 +854,23 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
}
// move to start_pos for wiping after toolchange
std::string start_pos_str = gcodegen.travel_to(wipe_tower_point_to_object_point(gcodegen, start_pos + plate_origin_2d), erMixed, "Move to start pos");
check_add_eol(start_pos_str);
toolchange_gcode_str += start_pos_str;
if (!is_used_travel_avoid_perimeter) {
std::string start_pos_str = gcodegen.travel_to(wipe_tower_point_to_object_point(gcodegen, start_pos + plate_origin_2d), erMixed, "Move to start pos");
check_add_eol(start_pos_str);
toolchange_gcode_str += start_pos_str;
} else {
// BBS:change travel_path
Vec3f gcode_last_pos;
GCodeProcessor::get_last_position_from_gcode(toolchange_gcode_str, gcode_last_pos);
Vec2f gcode_last_pos2d{gcode_last_pos[0], gcode_last_pos[1]};
Point gcode_last_pos2d_object = gcodegen.gcode_to_point(gcode_last_pos2d.cast<double>() + plate_origin_2d.cast<double>());
Point start_wipe_pos = wipe_tower_point_to_object_point(gcodegen, start_pos + plate_origin_2d);
std::string travel_to_wipe_tower_gcode = generate_path_to_wipe_tower(gcodegen, wipe_tower_point_to_object_point(gcodegen, m_wipe_tower_pos + plate_origin_2d),
gcode_last_pos2d_object, start_wipe_pos, scaled(gcodegen.m_config.prime_tower_width.value),
scaled(m_wipe_tower_depth), scaled(gcodegen.m_config.prime_tower_brim_width.value));
toolchange_gcode_str += travel_to_wipe_tower_gcode;
gcodegen.set_last_pos(start_wipe_pos);
}
}
std::string toolchange_command;
@@ -2658,7 +2820,9 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
std::vector<std::pair<coordf_t, std::vector<LayerToPrint>>> layers_to_print = collect_layers_to_print(print);
// Prusa Multi-Material wipe tower.
if (has_wipe_tower && ! layers_to_print.empty()) {
m_wipe_tower.reset(new WipeTowerIntegration(print.config(), print.get_plate_index(), print.get_plate_origin(), * print.wipe_tower_data().priming.get(), print.wipe_tower_data().tool_changes, *print.wipe_tower_data().final_purge.get()));
m_wipe_tower.reset(new WipeTowerIntegration(print.config(), print.get_plate_index(), print.get_plate_origin(), *print.wipe_tower_data().priming.get(),
print.wipe_tower_data().tool_changes, *print.wipe_tower_data().final_purge.get()));
m_wipe_tower->set_wipe_tower_depth(print.get_wipe_tower_depth());
//BBS
file.write(m_writer.travel_to_z(initial_layer_print_height + m_config.z_offset.value, "Move to the first layer height"));
@@ -6680,7 +6844,7 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo
// set volumetric speed of outer wall ,ignore per obejct,just use default setting
float outer_wall_volumetric_speed = get_outer_wall_volumetric_speed(m_config, *m_print, new_filament_id, get_extruder_id(new_filament_id));
float wipe_avoid_pos_x = get_wipe_avoid_pos_x(Vec2f{0, 0}, 0, 0, true);
DynamicConfig dyn_config;
dyn_config.set_key_value("outer_wall_volumetric_speed", new ConfigOptionFloat(outer_wall_volumetric_speed));
dyn_config.set_key_value("previous_extruder", new ConfigOptionInt(old_filament_id));
@@ -6712,6 +6876,8 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo
dyn_config.set_key_value("travel_point_2_y", new ConfigOptionFloat(float(travel_point_2.y())));
dyn_config.set_key_value("travel_point_3_x", new ConfigOptionFloat(float(travel_point_3.x())));
dyn_config.set_key_value("travel_point_3_y", new ConfigOptionFloat(float(travel_point_3.y())));
dyn_config.set_key_value("wipe_avoid_perimeter", new ConfigOptionBool(is_used_travel_avoid_perimeter));
dyn_config.set_key_value("wipe_avoid_pos_x", new ConfigOptionFloat(wipe_avoid_pos_x));
dyn_config.set_key_value("flush_length", new ConfigOptionFloat(wipe_length));

View File

@@ -113,10 +113,12 @@ public:
void set_is_first_print(bool is) { m_is_first_print = is; }
bool enable_timelapse_print() const { return m_enable_timelapse_print; }
void set_wipe_tower_depth(float depth) { m_wipe_tower_depth = depth; }
private:
WipeTowerIntegration& operator=(const WipeTowerIntegration&);
std::string append_tcr(GCode &gcodegen, const WipeTower::ToolChangeResult &tcr, int new_extruder_id, double z = -1.) const;
std::string generate_path_to_wipe_tower(GCode &gcodegen, const Point &wipe_tower_left_front, const Point &start_pos, const Point &end_pos, int width, int depth, int brim_width) const;
std::string append_tcr2(GCode &gcodegen, const WipeTower::ToolChangeResult &tcr, int new_extruder_id, double z = -1.) const;
// Postprocesses gcode: rotates and moves G1 extrusions and returns result
@@ -143,6 +145,7 @@ private:
bool m_enable_timelapse_print;
bool m_is_first_print;
const PrintConfig * m_print_config;
float m_wipe_tower_depth;
};
class ColorPrintColors

View File

@@ -2840,6 +2840,98 @@ bool GCodeProcessor::get_last_z_from_gcode(const std::string& gcode_str, double&
return is_z_changed;
}
bool GCodeProcessor::get_last_position_from_gcode(const std::string &gcode_str, Vec3f &pos)
{
int str_size = gcode_str.size();
int start_index = 0;
int end_index = 0;
bool is_z_changed = false;
while (end_index < str_size) {
// find a full line
if (gcode_str[end_index] != '\n') {
end_index++;
continue;
}
// parse the line
if (end_index > start_index) {
std::string line_str = gcode_str.substr(start_index, end_index - start_index);
line_str.erase(0, line_str.find_first_not_of(" "));
line_str.erase(line_str.find_last_not_of(";") + 1);
line_str.erase(line_str.find_last_not_of(" ") + 1);
// command which may have z movement
if (line_str.size() > 5 && (line_str.find("G0 ") == 0 || line_str.find("G1 ") == 0 || line_str.find("G2 ") == 0 || line_str.find("G3 ") == 0)) {
{
float &x = pos.x();
auto z_pos = line_str.find(" X");
float temp_z = 0;
if (z_pos != line_str.npos && z_pos + 2 < line_str.size()) {
// Try to parse the numeric value.
std::string z_sub = line_str.substr(z_pos + 2);
char *c = &z_sub[0];
char *end = c + sizeof(z_sub.c_str());
auto is_end_of_word = [](char c) { return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == 0 || c == ';'; };
auto [pend, ec] = fast_float::from_chars(c, end, temp_z);
if (pend != c && is_end_of_word(*pend)) {
// The axis value has been parsed correctly.
x = temp_z;
is_z_changed = true;
}
}
}
{
float &y = pos.y();
auto z_pos = line_str.find(" Y");
float temp_z = 0;
if (z_pos != line_str.npos && z_pos + 2 < line_str.size()) {
// Try to parse the numeric value.
std::string z_sub = line_str.substr(z_pos + 2);
char *c = &z_sub[0];
char *end = c + sizeof(z_sub.c_str());
auto is_end_of_word = [](char c) { return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == 0 || c == ';'; };
auto [pend, ec] = fast_float::from_chars(c, end, temp_z);
if (pend != c && is_end_of_word(*pend)) {
// The axis value has been parsed correctly.
y = temp_z;
is_z_changed = true;
}
}
}
{
float &z = pos.z();
auto z_pos = line_str.find(" Z");
float temp_z = 0;
if (z_pos != line_str.npos && z_pos + 2 < line_str.size()) {
// Try to parse the numeric value.
std::string z_sub = line_str.substr(z_pos + 2);
char *c = &z_sub[0];
char *end = c + sizeof(z_sub.c_str());
auto is_end_of_word = [](char c) { return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == 0 || c == ';'; };
auto [pend, ec] = fast_float::from_chars(c, end, temp_z);
if (pend != c && is_end_of_word(*pend)) {
// The axis value has been parsed correctly.
z = temp_z;
is_z_changed = true;
}
}
}
}
}
// loop to handle next line
start_index = end_index + 1;
end_index = start_index;
}
return is_z_changed;
}
void GCodeProcessor::process_tags(const std::string_view comment, bool producers_enabled)
{
// producers tags

View File

@@ -347,6 +347,7 @@ class Print;
static int get_gcode_last_filament(const std::string &gcode_str);
static bool get_last_z_from_gcode(const std::string& gcode_str, double& z);
static bool get_last_position_from_gcode(const std::string &gcode_str, Vec3f &pos);
static const float Wipe_Width;
static const float Wipe_Height;

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;

View File

@@ -175,6 +175,7 @@ public:
void generate(std::vector<std::vector<ToolChangeResult>> &result);
WipeTower::ToolChangeResult only_generate_out_wall(bool is_new_mode = false);
Polygon generate_support_wall(WipeTowerWriter &writer, const box_coordinates &wt_box, double feedrate, bool first_layer);
float get_depth() const { return m_wipe_tower_depth; }
float get_brim_width() const { return m_wipe_tower_brim_width_real; }
@@ -438,6 +439,7 @@ private:
float m_extra_spacing = 1.f;
float m_tpu_fixed_spacing = 2;
std::vector<Vec2f> m_wall_skip_points;
bool is_first_layer() const { return size_t(m_layer_info - m_plan.begin()) == m_first_layer_idx; }
// Calculates length of extrusion line to extrude given volume
@@ -522,6 +524,7 @@ private:
WipeTowerWriter &writer,
const box_coordinates &cleaning_box,
float wipe_volume);
void get_wall_skip_points(const WipeTowerInfo &layer);
};

View File

@@ -306,7 +306,7 @@ struct Segment
bool is_valid() const { return start.y() < end.y(); }
};
std::vector<Segment> remove_points_from_segment(const Segment& segment, const std::vector<Vec2f>& skip_points, double range)
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);

View File

@@ -1038,7 +1038,7 @@ public:
void set_calib_params(const Calib_Params& params);
const Calib_Params& calib_params() const { return m_calib_params; }
Vec2d translate_to_print_space(const Vec2d &point) const;
float get_wipe_tower_depth() const { return m_wipe_tower_data.depth; }
// scaled point
Vec2d translate_to_print_space(const Point &point) const;