Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CURA-12265 the wiping movement goes in the wrong direction #2170

Merged
18 changes: 16 additions & 2 deletions include/LayerPlan.h
Original file line number Diff line number Diff line change
Expand Up @@ -881,9 +881,10 @@ class LayerPlan : public NoCopy
* \param compute_distance_to_bridge_start Whether we should compute the distance to start of bridge. This is
* possible only if PathType is ExtrusionLine and will be ignored otherwise.
* \param func_add_segment The function to be called to actually add an extrusion segment with the given parameters
* \return The index of the last traversed point, and the final position with the scarf seam
*/
template<class PathType>
void addSplitWall(
std::tuple<size_t, Point2LL> addSplitWall(
const PathAdapter<PathType>& wall,
const coord_t wall_length,
const size_t start_idx,
Expand Down Expand Up @@ -926,9 +927,10 @@ class LayerPlan : public NoCopy
* \param scarf_seam Indicates whether we may use a scarf seam for the path
* \param smooth_speed Indicates whether we may use a speed gradient for the path
* \param func_add_segment The function to be called to actually add an extrusion segment with the given parameters
* \return The index of the last traversed point, and the final position with the scarf seam
*/
template<class PathType>
void addWallWithScarfSeam(
std::tuple<size_t, Point2LL> addWallWithScarfSeam(
const PathAdapter<PathType>& wall,
size_t start_idx,
const Settings& settings,
Expand All @@ -942,6 +944,18 @@ class LayerPlan : public NoCopy
const bool smooth_speed,
const AddExtrusionSegmentFunction& func_add_segment);

/*!
* \brief Add a wipe travel after the given path has been extruded
* \tparam PathType The type of path to be processed, either ExtrusionLine or some subclass of Polyline
* \param path The path that has just been extruded
* \param wipe_distance The length of the wipe move to be added
* \param backwards Indicates if the path has been processed backwards
* \param start_index The index of the point where o start printing the path
* \param last_path_position The actual last position of the extruder, which may be slightly forwards on the last printed segment
*/
template<class PathType>
void addWipeTravel(const PathAdapter<PathType>& path, const coord_t wipe_distance, const bool backwards, const size_t start_index, const Point2LL& last_path_position);

/*!
* Pre-calculates the coasting to be applied on the paths
*
Expand Down
146 changes: 76 additions & 70 deletions src/LayerPlan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,45 @@ void LayerPlan::addExtrusionMove(
last_planned_position_ = p.toPoint2LL();
}

template<class PathType>
void LayerPlan::addWipeTravel(const PathAdapter<PathType>& path, const coord_t wipe_distance, const bool backwards, const size_t start_index, const Point2LL& last_path_position)
{
if (path.size() >= 2 && wipe_distance > 0)
{
const int direction = backwards ? -1 : 1;
Point2LL p0 = last_path_position;
int distance_traversed = 0;
size_t index = start_index;
while (distance_traversed < wipe_distance)
{
index = static_cast<size_t>((index + direction + path.size()) % path.size());
if (index == start_index && distance_traversed == 0)
{
// Wall has a total circumference of 0. This loop would never end.
break;
}

const Point2LL& p1 = path.pointAt(index);
const int p0p1_dist = vSize(p1 - p0);
if (distance_traversed + p0p1_dist >= wipe_distance)
{
Point2LL vector = p1 - p0;
Point2LL half_way = p0 + normal(vector, wipe_distance - distance_traversed);
addTravel_simple(half_way);
}
else
{
addTravel_simple(p1);
}

distance_traversed += p0p1_dist;
p0 = p1;
}

forceNewPathStart();
}
}

void LayerPlan::addPolygon(
const Polygon& polygon,
int start_idx,
Expand All @@ -569,12 +608,13 @@ void LayerPlan::addPolygon(
{
constexpr bool is_closed = true;
constexpr bool is_candidate_small_feature = false;
const PathAdapter path_adapter(polygon, config.getLineWidth());

Point2LL p0 = polygon[start_idx];
addTravel(p0, always_retract, config.z_offset);

addWallWithScarfSeam(
PathAdapter(polygon, config.getLineWidth()),
const std::tuple<size_t, Point2LL> add_wall_result = addWallWithScarfSeam(
path_adapter,
start_idx,
settings,
config,
Expand Down Expand Up @@ -602,31 +642,7 @@ void LayerPlan::addPolygon(

if (polygon.size() > 2)
{
if (wall_0_wipe_dist > 0)
{ // apply outer wall wipe
p0 = polygon[start_idx];
const int direction = backwards ? -1 : 1;
int distance_traversed = 0;
for (size_t point_idx = 1;; point_idx++)
{
Point2LL p1 = polygon[(start_idx + point_idx * direction + polygon.size()) % polygon.size()];
int p0p1_dist = vSize(p1 - p0);
if (distance_traversed + p0p1_dist >= wall_0_wipe_dist)
{
Point2LL vector = p1 - p0;
Point2LL half_way = p0 + normal(vector, wall_0_wipe_dist - distance_traversed);
addTravel_simple(half_way);
break;
}
else
{
addTravel_simple(p1);
distance_traversed += p0p1_dist;
}
p0 = p1;
}
forceNewPathStart();
}
addWipeTravel(path_adapter, wall_0_wipe_dist, backwards, get<0>(add_wall_result), get<1>(add_wall_result));
}
else
{
Expand Down Expand Up @@ -1039,7 +1055,7 @@ void LayerPlan::addWall(
}

template<class PathType>
void LayerPlan::addSplitWall(
std::tuple<size_t, Point2LL> LayerPlan::addSplitWall(
const PathAdapter<PathType>& wall,
const coord_t wall_length,
const size_t start_idx,
Expand Down Expand Up @@ -1083,10 +1099,14 @@ void LayerPlan::addSplitWall(
double accelerate_factor_origin = 0.0; // Interpolation factor at the current point for the acceleration
double decelerate_factor_origin = 0.0; // Interpolation factor at the current point for the deceleration
const coord_t start_decelerate_position = wall_length - decelerate_length;
Point3LL split_destination = p0;
size_t previous_point_index = start_idx;
bool keep_processing = true;

for (size_t point_idx = 1; point_idx < max_index; point_idx++)
for (size_t point_idx = 1; point_idx < max_index && keep_processing; point_idx++)
{
const size_t actual_point_index = (wall.size() + start_idx + point_idx * direction) % wall.size();
previous_point_index = (wall.size() + start_idx + (point_idx - 1) * direction) % wall.size();
const Point2LL& p1 = wall.pointAt(actual_point_index);
const coord_t w1 = wall.lineWidthAt(actual_point_index);
coord_t segment_processed_distance = 0;
Expand Down Expand Up @@ -1137,7 +1157,7 @@ void LayerPlan::addSplitWall(
const size_t pieces = std::max(size_t(1), std::min(pieces_limit_deviation, pieces_limit_resolution)); // Resolution overrides deviation, if resolution is a constraint.
const coord_t piece_length = round_divide(line_length, pieces);

for (size_t piece = 0; piece < pieces; ++piece)
for (size_t piece = 0; piece < pieces && keep_processing; ++piece)
{
const double average_progress = (double(piece) + 0.5) / pieces; // How far along this line to sample the line width in the middle of this piece.
// Round the line_width value to overcome floating point rounding issues, otherwise we may end up with slightly different values
Expand All @@ -1155,7 +1175,7 @@ void LayerPlan::addSplitWall(
coord_t piece_remaining_distance = piece_length;

// Cut piece into smaller parts for scarf seam and acceleration/deceleration
while (piece_remaining_distance > 0 && (! is_scarf_closure || wall_processed_distance < scarf_seam_length))
while (piece_remaining_distance > 0 && keep_processing)
{
// Make a list of all the possible incoming positions where we would eventually want to stop next
// The positions are expressed in distance from wall start along the wall segments
Expand Down Expand Up @@ -1193,7 +1213,7 @@ void LayerPlan::addSplitWall(
const coord_t destination_position = *std::min_element(split_positions.begin(), split_positions.end());
const coord_t length_to_process = destination_position - wall_processed_distance;
const double destination_factor = static_cast<double>(segment_processed_distance + length_to_process) / line_length;
Point3LL split_destination = cura::lerp(p0, p1, destination_factor);
split_destination = cura::lerp(p0, p1, destination_factor);

double scarf_segment_flow_ratio = 1.0;
double scarf_factor_destination = 1.0; // Out of range, scarf is done => 1.0
Expand Down Expand Up @@ -1266,13 +1286,20 @@ void LayerPlan::addSplitWall(
scarf_factor_origin = scarf_factor_destination;
accelerate_factor_origin = accelerate_factor_destination;
decelerate_factor_origin = decelerate_factor_destination;

if (is_scarf_closure)
{
keep_processing = wall_processed_distance < scarf_seam_length;
}
}
}
}

p0 = p1;
w0 = w1;
}

return { previous_point_index, split_destination.toPoint2LL() };
}

std::vector<LayerPlan::PathCoasting>
Expand Down Expand Up @@ -1460,7 +1487,7 @@ coord_t LayerPlan::computeDistanceToBridgeStart(const ExtrusionLine& wall, const
}

template<class PathType>
void LayerPlan::addWallWithScarfSeam(
std::tuple<size_t, Point2LL> LayerPlan::addWallWithScarfSeam(
const PathAdapter<PathType>& wall,
size_t start_idx,
const Settings& settings,
Expand All @@ -1476,10 +1503,10 @@ void LayerPlan::addWallWithScarfSeam(
{
if (wall.empty())
{
return;
return { start_idx, Point2LL() };
}

const bool actual_scarf_seam = scarf_seam && is_closed;
const bool actual_scarf_seam = scarf_seam && is_closed && layer_nr_ > 0;

const coord_t min_bridge_line_len = settings.get<coord_t>("bridge_wall_min_length");

Expand All @@ -1496,7 +1523,7 @@ void LayerPlan::addWallWithScarfSeam(
const int direction = is_reversed ? -1 : 1;
const size_t max_index = is_closed ? wall.size() + 1 : wall.size();

const auto scarf_seam_length = std::min(wall_length, actual_scarf_seam ? settings.get<coord_t>("scarf_joint_seam_length") : 0);
const coord_t scarf_seam_length = std::min(wall_length, actual_scarf_seam ? settings.get<coord_t>("scarf_joint_seam_length") : 0);
const auto scarf_seam_start_ratio = actual_scarf_seam ? settings.get<Ratio>("scarf_joint_seam_start_height_ratio") : 1.0_r;
const auto scarf_split_distance = settings.get<coord_t>("scarf_split_distance");
const coord_t scarf_max_z_offset = static_cast<coord_t>(-(1.0 - scarf_seam_start_ratio) * static_cast<double>(layer_thickness_));
Expand All @@ -1513,11 +1540,11 @@ void LayerPlan::addWallWithScarfSeam(
const Velocity end_speed = top_speed * end_speed_ratio; // mm/s
const coord_t decelerate_length = (smooth_speed && end_speed_ratio < 1.0) ? MM2INT((square(top_speed) - square(end_speed)) / (2.0 * deceleration)) : 0; // µm

auto addSplitWallPass = [&](bool is_scarf_closure)
auto addSplitWallPass = [&](bool is_scarf_closure) -> std::tuple<size_t, Point2LL>
{
constexpr bool compute_distance_to_bridge_start = true;

addSplitWall(
return addSplitWall(
PathAdapter(wall),
wall_length,
start_idx,
Expand All @@ -1532,7 +1559,7 @@ void LayerPlan::addWallWithScarfSeam(
flow_ratio,
nominal_line_width,
min_bridge_line_len,
layer_nr_ > 0 ? scarf_seam_length : 0,
scarf_seam_length,
scarf_seam_start_ratio,
scarf_split_distance,
scarf_max_z_offset,
Expand All @@ -1547,13 +1574,15 @@ void LayerPlan::addWallWithScarfSeam(
};

// First pass to add the wall with the scarf beginning and acceleration
addSplitWallPass(false);
std::tuple<size_t, Point2LL> result = addSplitWallPass(false);

if (scarf_seam_length > 0)
{
// Second pass to add the scarf closure
addSplitWallPass(true);
result = addSplitWallPass(true);
}

return result;
}

void LayerPlan::addWall(
Expand All @@ -1579,9 +1608,10 @@ void LayerPlan::addWall(

double non_bridge_line_volume = max_non_bridge_line_volume; // assume extruder is fully pressurised before first non-bridge line is output
const coord_t min_bridge_line_len = settings.get<coord_t>("bridge_wall_min_length");
const PathAdapter path_adapter(wall);

addWallWithScarfSeam(
PathAdapter(wall),
const std::tuple<size_t, Point2LL> add_wall_result = addWallWithScarfSeam(
path_adapter,
start_idx,
settings,
default_config,
Expand Down Expand Up @@ -1623,33 +1653,9 @@ void LayerPlan::addWall(
computeDistanceToBridgeStart(wall, (start_idx + wall.size() - 1) % wall.size(), min_bridge_line_len);
}

if (wall_0_wipe_dist > 0 && ! is_linked_path)
{ // apply outer wall wipe
ExtrusionJunction p0 = wall[start_idx];
coord_t distance_traversed = 0;
for (unsigned int point_idx = 1;; point_idx++)
{
if (point_idx > wall.size() && distance_traversed == 0) // Wall has a total circumference of 0. This loop would never end.
{
break; // No wipe if the wall has no circumference.
}
ExtrusionJunction p1 = wall[(start_idx + point_idx) % wall.size()];
coord_t p0p1_dist = vSize(p1 - p0);
if (distance_traversed + p0p1_dist >= wall_0_wipe_dist)
{
Point2LL vector = p1.p_ - p0.p_;
Point2LL half_way = p0.p_ + normal(vector, wall_0_wipe_dist - distance_traversed);
addTravel_simple(half_way);
break;
}
else
{
addTravel_simple(p1.p_);
distance_traversed += p0p1_dist;
}
p0 = p1;
}
forceNewPathStart();
if (! is_linked_path)
{
addWipeTravel(path_adapter, wall_0_wipe_dist, is_reversed, get<0>(add_wall_result), get<1>(add_wall_result));
}
}
else
Expand Down
Loading