Disabling wipe for avoid crossing perimeters
This commit is contained in:
parent
7f94e9fa59
commit
ef9de07740
4 changed files with 119 additions and 32 deletions
|
@ -2662,14 +2662,16 @@ std::string GCode::travel_to(const Point &point, ExtrusionRole role, std::string
|
||||||
travel.append(point);
|
travel.append(point);
|
||||||
|
|
||||||
// check whether a straight travel move would need retraction
|
// check whether a straight travel move would need retraction
|
||||||
bool needs_retraction = this->needs_retraction(travel, role);
|
bool needs_retraction = this->needs_retraction(travel, role);
|
||||||
|
// check whether wipe could be disabled without causing visible stringing
|
||||||
|
bool could_be_wipe_disabled = false;
|
||||||
|
|
||||||
// if a retraction would be needed, try to use avoid_crossing_perimeters to plan a
|
// if a retraction would be needed, try to use avoid_crossing_perimeters to plan a
|
||||||
// multi-hop travel path inside the configuration space
|
// multi-hop travel path inside the configuration space
|
||||||
if (needs_retraction
|
if (needs_retraction
|
||||||
&& m_config.avoid_crossing_perimeters
|
&& m_config.avoid_crossing_perimeters
|
||||||
&& ! m_avoid_crossing_perimeters.disable_once) {
|
&& ! m_avoid_crossing_perimeters.disable_once) {
|
||||||
travel = m_avoid_crossing_perimeters.travel_to(*this, point);
|
travel = m_avoid_crossing_perimeters.travel_to(*this, point, &could_be_wipe_disabled);
|
||||||
|
|
||||||
// check again whether the new travel path still needs a retraction
|
// check again whether the new travel path still needs a retraction
|
||||||
needs_retraction = this->needs_retraction(travel, role);
|
needs_retraction = this->needs_retraction(travel, role);
|
||||||
|
@ -2683,6 +2685,9 @@ std::string GCode::travel_to(const Point &point, ExtrusionRole role, std::string
|
||||||
// generate G-code for the travel move
|
// generate G-code for the travel move
|
||||||
std::string gcode;
|
std::string gcode;
|
||||||
if (needs_retraction) {
|
if (needs_retraction) {
|
||||||
|
if (m_config.avoid_crossing_perimeters && !m_avoid_crossing_perimeters.disable_once && could_be_wipe_disabled)
|
||||||
|
m_wipe.reset_path();
|
||||||
|
|
||||||
Point last_post_before_retract = this->last_pos();
|
Point last_post_before_retract = this->last_pos();
|
||||||
gcode += this->retract();
|
gcode += this->retract();
|
||||||
// When "Wipe while retracting" is enabled, then extruder moves to another position, and travel from this position can cross perimeters.
|
// When "Wipe while retracting" is enabled, then extruder moves to another position, and travel from this position can cross perimeters.
|
||||||
|
|
|
@ -156,6 +156,7 @@ public:
|
||||||
const FullPrintConfig &config() const { return m_config; }
|
const FullPrintConfig &config() const { return m_config; }
|
||||||
const Layer* layer() const { return m_layer; }
|
const Layer* layer() const { return m_layer; }
|
||||||
GCodeWriter& writer() { return m_writer; }
|
GCodeWriter& writer() { return m_writer; }
|
||||||
|
const GCodeWriter& writer() const { return m_writer; }
|
||||||
PlaceholderParser& placeholder_parser() { return m_placeholder_parser; }
|
PlaceholderParser& placeholder_parser() { return m_placeholder_parser; }
|
||||||
const PlaceholderParser& placeholder_parser() const { return m_placeholder_parser; }
|
const PlaceholderParser& placeholder_parser() const { return m_placeholder_parser; }
|
||||||
// Process a template through the placeholder parser, collect error messages to be reported
|
// Process a template through the placeholder parser, collect error messages to be reported
|
||||||
|
|
|
@ -115,6 +115,7 @@ static Matrix2d rotation_by_direction(const Point &direction)
|
||||||
|
|
||||||
static Point find_first_different_vertex(const Polygon &polygon, const size_t point_idx, const Point &point, bool forward)
|
static Point find_first_different_vertex(const Polygon &polygon, const size_t point_idx, const Point &point, bool forward)
|
||||||
{
|
{
|
||||||
|
assert(point_idx < polygon.size());
|
||||||
if (point != polygon.points[point_idx])
|
if (point != polygon.points[point_idx])
|
||||||
return polygon.points[point_idx];
|
return polygon.points[point_idx];
|
||||||
|
|
||||||
|
@ -137,8 +138,9 @@ static Vec2d three_points_inward_normal(const Point &left, const Point &middle,
|
||||||
normal_2.normalize();
|
normal_2.normalize();
|
||||||
|
|
||||||
return (normal_1 + normal_2).normalized();
|
return (normal_1 + normal_2).normalized();
|
||||||
};
|
}
|
||||||
|
|
||||||
|
// Compute normal of the polygon's vertex in an inward direction
|
||||||
static Vec2d get_polygon_vertex_inward_normal(const Polygon &polygon, const size_t point_idx)
|
static Vec2d get_polygon_vertex_inward_normal(const Polygon &polygon, const size_t point_idx)
|
||||||
{
|
{
|
||||||
const size_t left_idx = (point_idx <= 0) ? (polygon.size() - 1) : (point_idx - 1);
|
const size_t left_idx = (point_idx <= 0) ? (polygon.size() - 1) : (point_idx - 1);
|
||||||
|
@ -149,12 +151,13 @@ static Vec2d get_polygon_vertex_inward_normal(const Polygon &polygon, const size
|
||||||
return three_points_inward_normal(left, middle, right);
|
return three_points_inward_normal(left, middle, right);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute offset of polygon's in a direction inward normal
|
// Compute offset of point_idx of the polygon in a direction of inward normal
|
||||||
static Point get_polygon_vertex_offset(const Polygon &polygon, const size_t point_idx, const int offset)
|
static Point get_polygon_vertex_offset(const Polygon &polygon, const size_t point_idx, const int offset)
|
||||||
{
|
{
|
||||||
return polygon.points[point_idx] + (get_polygon_vertex_inward_normal(polygon, point_idx) * double(offset)).cast<coord_t>();
|
return polygon.points[point_idx] + (get_polygon_vertex_inward_normal(polygon, point_idx) * double(offset)).cast<coord_t>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compute offset (in the direction of inward normal) of the point(passed on "middle") based on the nearest points laying on the polygon (left_idx and right_idx).
|
||||||
static Point get_middle_point_offset(const Polygon &polygon, const size_t left_idx, const size_t right_idx, const Point &middle, const int offset)
|
static Point get_middle_point_offset(const Polygon &polygon, const size_t left_idx, const size_t right_idx, const Point &middle, const int offset)
|
||||||
{
|
{
|
||||||
const Point &left = find_first_different_vertex(polygon, left_idx, middle, false);
|
const Point &left = find_first_different_vertex(polygon, left_idx, middle, false);
|
||||||
|
@ -243,6 +246,15 @@ static coord_t get_perimeter_spacing_external(const Layer &layer)
|
||||||
return perimeter_spacing;
|
return perimeter_spacing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if anyone of ExPolygons contains whole travel.
|
||||||
|
template<class T> static bool any_expolygon_contains(const ExPolygons &ex_polygons, const T &travel)
|
||||||
|
{
|
||||||
|
for (const ExPolygon &ex_polygon : ex_polygons)
|
||||||
|
if (ex_polygon.contains(travel)) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ExPolygons AvoidCrossingPerimeters2::get_boundary(const Layer &layer)
|
ExPolygons AvoidCrossingPerimeters2::get_boundary(const Layer &layer)
|
||||||
{
|
{
|
||||||
const coord_t perimeter_spacing = get_perimeter_spacing(layer);
|
const coord_t perimeter_spacing = get_perimeter_spacing(layer);
|
||||||
|
@ -321,6 +333,7 @@ ExPolygons AvoidCrossingPerimeters2::get_boundary_external(const Layer &layer)
|
||||||
|
|
||||||
Polygons contours;
|
Polygons contours;
|
||||||
Polygons holes;
|
Polygons holes;
|
||||||
|
contours.reserve(boundary.size());
|
||||||
for (ExPolygon &poly : boundary) {
|
for (ExPolygon &poly : boundary) {
|
||||||
contours.emplace_back(poly.contour);
|
contours.emplace_back(poly.contour);
|
||||||
append(holes, poly.holes);
|
append(holes, poly.holes);
|
||||||
|
@ -429,10 +442,11 @@ Polyline AvoidCrossingPerimeters2::simplify_travel(const EdgeGrid::Grid &edge_gr
|
||||||
return optimized_comb_path;
|
return optimized_comb_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
Polyline AvoidCrossingPerimeters2::avoid_perimeters(const Polygons &boundaries,
|
size_t AvoidCrossingPerimeters2::avoid_perimeters(const Polygons &boundaries,
|
||||||
const EdgeGrid::Grid &edge_grid,
|
const EdgeGrid::Grid &edge_grid,
|
||||||
const Point &start,
|
const Point &start,
|
||||||
const Point &end)
|
const Point &end,
|
||||||
|
Polyline *result_out)
|
||||||
{
|
{
|
||||||
const Point direction = end - start;
|
const Point direction = end - start;
|
||||||
Matrix2d transform_to_x_axis = rotation_by_direction(direction);
|
Matrix2d transform_to_x_axis = rotation_by_direction(direction);
|
||||||
|
@ -496,12 +510,12 @@ Polyline AvoidCrossingPerimeters2::avoid_perimeters(const Polygons &bounda
|
||||||
// Append the nearest intersection into the path
|
// Append the nearest intersection into the path
|
||||||
size_t left_idx = intersection_first.line_idx;
|
size_t left_idx = intersection_first.line_idx;
|
||||||
size_t right_idx = (intersection_first.line_idx >= (boundaries[intersection_first.border_idx].points.size() - 1)) ? 0 : (intersection_first.line_idx + 1);
|
size_t right_idx = (intersection_first.line_idx >= (boundaries[intersection_first.border_idx].points.size() - 1)) ? 0 : (intersection_first.line_idx + 1);
|
||||||
|
// Offset of the polygon's point using get_middle_point_offset is used to simplify calculation of intersection between boundary
|
||||||
result.append(get_middle_point_offset(boundaries[intersection_first.border_idx], left_idx, right_idx, intersection_first.point, SCALED_EPSILON));
|
result.append(get_middle_point_offset(boundaries[intersection_first.border_idx], left_idx, right_idx, intersection_first.point, SCALED_EPSILON));
|
||||||
|
|
||||||
Direction shortest_direction = get_shortest_direction(border_lines, intersection_first.line_idx, intersection_second.line_idx,
|
Direction shortest_direction = get_shortest_direction(border_lines, intersection_first.line_idx, intersection_second.line_idx,
|
||||||
intersection_first.point, intersection_second.point);
|
intersection_first.point, intersection_second.point);
|
||||||
// Append the path around the border into the path
|
// Append the path around the border into the path
|
||||||
// Offset of the polygon's point is used to simplify calculation of intersection between boundary
|
|
||||||
if (shortest_direction == Direction::Forward)
|
if (shortest_direction == Direction::Forward)
|
||||||
for (int line_idx = intersection_first.line_idx; line_idx != int(intersection_second.line_idx);
|
for (int line_idx = intersection_first.line_idx; line_idx != int(intersection_second.line_idx);
|
||||||
line_idx = (((line_idx + 1) < int(border_lines.size())) ? (line_idx + 1) : 0))
|
line_idx = (((line_idx + 1) < int(border_lines.size())) ? (line_idx + 1) : 0))
|
||||||
|
@ -524,10 +538,48 @@ Polyline AvoidCrossingPerimeters2::avoid_perimeters(const Polygons &bounda
|
||||||
}
|
}
|
||||||
|
|
||||||
result.append(end);
|
result.append(end);
|
||||||
return simplify_travel(edge_grid, result);
|
if(!intersections.empty()) {
|
||||||
|
result = simplify_travel(edge_grid, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
append(result_out->points, result.points);
|
||||||
|
return intersections.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
Polyline AvoidCrossingPerimeters2::travel_to(const GCode &gcodegen, const Point &point)
|
bool AvoidCrossingPerimeters2::needs_wipe(const GCode & gcodegen,
|
||||||
|
const Line & original_travel,
|
||||||
|
const Polyline &result_travel,
|
||||||
|
const size_t intersection_count)
|
||||||
|
{
|
||||||
|
bool z_lift_enabled = gcodegen.config().retract_lift.get_at(gcodegen.writer().extruder()->id()) > 0.;
|
||||||
|
bool wipe_needed = false;
|
||||||
|
|
||||||
|
// If the original unmodified path doesn't have any intersection with boundary, then it is entirely inside the object otherwise is entirely
|
||||||
|
// outside the object.
|
||||||
|
if (intersection_count > 0) {
|
||||||
|
// The original layer is intersected with defined boundaries. Then it is necessary to make a detailed test.
|
||||||
|
// If the z-lift is enabled, then a wipe is needed when the original travel leads above the holes.
|
||||||
|
if (z_lift_enabled) {
|
||||||
|
if (any_expolygon_contains(m_slice, original_travel)) {
|
||||||
|
// Check if original_travel and are not same result_travel
|
||||||
|
if (result_travel.size() == 2 && result_travel.first_point() == original_travel.a && result_travel.last_point() == original_travel.b) {
|
||||||
|
wipe_needed = false;
|
||||||
|
} else {
|
||||||
|
wipe_needed = !any_expolygon_contains(m_slice, result_travel);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
wipe_needed = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
wipe_needed = !any_expolygon_contains(m_slice, result_travel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return wipe_needed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plan travel, which avoids perimeter crossings by following the boundaries of the layer.
|
||||||
|
Polyline AvoidCrossingPerimeters2::travel_to(const GCode &gcodegen, const Point &point, bool *could_be_wipe_disabled)
|
||||||
{
|
{
|
||||||
// If use_external, then perform the path planning in the world coordinate system (correcting for the gcodegen offset).
|
// If use_external, then perform the path planning in the world coordinate system (correcting for the gcodegen offset).
|
||||||
// Otherwise perform the path planning in the coordinate system of the active object.
|
// Otherwise perform the path planning in the coordinate system of the active object.
|
||||||
|
@ -536,14 +588,16 @@ Polyline AvoidCrossingPerimeters2::travel_to(const GCode &gcodegen, const Point
|
||||||
Point start = gcodegen.last_pos() + scaled_origin;
|
Point start = gcodegen.last_pos() + scaled_origin;
|
||||||
Point end = point + scaled_origin;
|
Point end = point + scaled_origin;
|
||||||
Polyline result;
|
Polyline result;
|
||||||
|
size_t travel_intersection_count = 0;
|
||||||
if (!check_if_could_cross_perimeters(use_external ? m_bbox_external : m_bbox, start, end)) {
|
if (!check_if_could_cross_perimeters(use_external ? m_bbox_external : m_bbox, start, end)) {
|
||||||
result = Polyline({start, end});
|
result = Polyline({start, end});
|
||||||
|
travel_intersection_count = 0;
|
||||||
} else {
|
} else {
|
||||||
auto [start_clamped, end_clamped] = clamp_endpoints_by_bounding_box(use_external ? m_bbox_external : m_bbox, start, end);
|
auto [start_clamped, end_clamped] = clamp_endpoints_by_bounding_box(use_external ? m_bbox_external : m_bbox, start, end);
|
||||||
if (use_external)
|
if (use_external)
|
||||||
result = this->avoid_perimeters(m_boundaries_external, m_grid_external, start_clamped, end_clamped);
|
travel_intersection_count = this->avoid_perimeters(m_boundaries_external, m_grid_external, start_clamped, end_clamped, &result);
|
||||||
else
|
else
|
||||||
result = this->avoid_perimeters(m_boundaries, m_grid, start_clamped, end_clamped);
|
travel_intersection_count = this->avoid_perimeters(m_boundaries, m_grid, start_clamped, end_clamped, &result);
|
||||||
}
|
}
|
||||||
|
|
||||||
result.points.front() = start;
|
result.points.front() = start;
|
||||||
|
@ -554,33 +608,32 @@ Polyline AvoidCrossingPerimeters2::travel_to(const GCode &gcodegen, const Point
|
||||||
if ((max_detour_length > 0) && ((result.length() - travel.length()) > max_detour_length)) {
|
if ((max_detour_length > 0) && ((result.length() - travel.length()) > max_detour_length)) {
|
||||||
result = Polyline({start, end});
|
result = Polyline({start, end});
|
||||||
}
|
}
|
||||||
if (use_external)
|
if (use_external) {
|
||||||
result.translate(-scaled_origin);
|
result.translate(-scaled_origin);
|
||||||
|
*could_be_wipe_disabled = false;
|
||||||
|
} else
|
||||||
|
*could_be_wipe_disabled = !needs_wipe(gcodegen, travel, result, travel_intersection_count);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvoidCrossingPerimeters2::init_layer(const Layer &layer)
|
void AvoidCrossingPerimeters2::init_layer(const Layer &layer)
|
||||||
{
|
{
|
||||||
|
m_slice.clear();
|
||||||
m_boundaries.clear();
|
m_boundaries.clear();
|
||||||
m_boundaries_external.clear();
|
m_boundaries_external.clear();
|
||||||
|
|
||||||
ExPolygons boundaries = get_boundary(layer);
|
for (const LayerRegion *layer_region : layer.regions())
|
||||||
ExPolygons boundaries_external = get_boundary_external(layer);
|
append(m_slice, (ExPolygons) layer_region->slices);
|
||||||
|
|
||||||
m_bbox = get_extents(boundaries);
|
m_boundaries = to_polygons(get_boundary(layer));
|
||||||
|
m_boundaries_external = to_polygons(get_boundary_external(layer));
|
||||||
|
|
||||||
|
m_bbox = get_extents(m_boundaries);
|
||||||
m_bbox.offset(SCALED_EPSILON);
|
m_bbox.offset(SCALED_EPSILON);
|
||||||
m_bbox_external = get_extents(boundaries_external);
|
m_bbox_external = get_extents(m_boundaries_external);
|
||||||
m_bbox_external.offset(SCALED_EPSILON);
|
m_bbox_external.offset(SCALED_EPSILON);
|
||||||
|
|
||||||
for (const ExPolygon &ex_poly : boundaries) {
|
|
||||||
m_boundaries.emplace_back(ex_poly.contour);
|
|
||||||
append(m_boundaries, ex_poly.holes);
|
|
||||||
}
|
|
||||||
for (const ExPolygon &ex_poly : boundaries_external) {
|
|
||||||
m_boundaries_external.emplace_back(ex_poly.contour);
|
|
||||||
append(m_boundaries_external, ex_poly.holes);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_grid.set_bbox(m_bbox);
|
m_grid.set_bbox(m_bbox);
|
||||||
m_grid.create(m_boundaries, scale_(1.));
|
m_grid.create(m_boundaries, scale_(1.));
|
||||||
m_grid_external.set_bbox(m_bbox_external);
|
m_grid_external.set_bbox(m_bbox_external);
|
||||||
|
|
|
@ -37,11 +37,17 @@ public:
|
||||||
m_external_mp.reset();
|
m_external_mp.reset();
|
||||||
m_layer_mp.reset();
|
m_layer_mp.reset();
|
||||||
}
|
}
|
||||||
void init_external_mp(const Print &print);
|
virtual void init_external_mp(const Print &print);
|
||||||
void init_layer_mp(const ExPolygons &islands) { m_layer_mp = Slic3r::make_unique<MotionPlanner>(islands); }
|
virtual void init_layer_mp(const ExPolygons &islands) { m_layer_mp = Slic3r::make_unique<MotionPlanner>(islands); }
|
||||||
|
|
||||||
virtual Polyline travel_to(const GCode &gcodegen, const Point &point);
|
virtual Polyline travel_to(const GCode &gcodegen, const Point &point);
|
||||||
|
|
||||||
|
virtual Polyline travel_to(const GCode &gcodegen, const Point &point, bool *could_be_wipe_disabled)
|
||||||
|
{
|
||||||
|
*could_be_wipe_disabled = true;
|
||||||
|
return this->travel_to(gcodegen, point);
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// For initializing the regions to avoid.
|
// For initializing the regions to avoid.
|
||||||
static Polygons collect_contours_all_layers(const PrintObjectPtrs &objects);
|
static Polygons collect_contours_all_layers(const PrintObjectPtrs &objects);
|
||||||
|
@ -55,9 +61,13 @@ class AvoidCrossingPerimeters2 : public AvoidCrossingPerimeters
|
||||||
protected:
|
protected:
|
||||||
struct Intersection
|
struct Intersection
|
||||||
{
|
{
|
||||||
|
// Index of the polygon containing this point of intersection.
|
||||||
size_t border_idx;
|
size_t border_idx;
|
||||||
|
// Index of the line on the polygon containing this point of intersection.
|
||||||
size_t line_idx;
|
size_t line_idx;
|
||||||
|
// Point of intersection projected on the travel path.
|
||||||
Point point_transformed;
|
Point point_transformed;
|
||||||
|
// Point of intersection.
|
||||||
Point point;
|
Point point;
|
||||||
|
|
||||||
Intersection(size_t border_idx, size_t line_idx, const Point &point_transformed, const Point &point)
|
Intersection(size_t border_idx, size_t line_idx, const Point &point_transformed, const Point &point)
|
||||||
|
@ -78,11 +88,19 @@ private:
|
||||||
|
|
||||||
static Polyline simplify_travel(const EdgeGrid::Grid &edge_grid, const Polyline &travel);
|
static Polyline simplify_travel(const EdgeGrid::Grid &edge_grid, const Polyline &travel);
|
||||||
|
|
||||||
static Polyline avoid_perimeters(const Polygons &boundaries, const EdgeGrid::Grid &grid, const Point &start, const Point &end);
|
static size_t avoid_perimeters(const Polygons &boundaries, const EdgeGrid::Grid &grid, const Point &start, const Point &end, Polyline *result_out);
|
||||||
|
|
||||||
|
bool needs_wipe(const GCode &gcodegen, const Line &original_travel, const Polyline &result_travel, const size_t intersection_count);
|
||||||
|
|
||||||
|
// Slice of layer with elephant foot compensation
|
||||||
|
ExPolygons m_slice;
|
||||||
|
// Collection of boundaries used for detection of crossing perimetrs for travels inside object
|
||||||
Polygons m_boundaries;
|
Polygons m_boundaries;
|
||||||
|
// Collection of boundaries used for detection of crossing perimetrs for travels outside object
|
||||||
Polygons m_boundaries_external;
|
Polygons m_boundaries_external;
|
||||||
|
// Bounding box of m_boundaries
|
||||||
BoundingBox m_bbox;
|
BoundingBox m_bbox;
|
||||||
|
// Bounding box of m_boundaries_external
|
||||||
BoundingBox m_bbox_external;
|
BoundingBox m_bbox_external;
|
||||||
EdgeGrid::Grid m_grid;
|
EdgeGrid::Grid m_grid;
|
||||||
EdgeGrid::Grid m_grid_external;
|
EdgeGrid::Grid m_grid_external;
|
||||||
|
@ -92,7 +110,17 @@ public:
|
||||||
|
|
||||||
virtual ~AvoidCrossingPerimeters2() = default;
|
virtual ~AvoidCrossingPerimeters2() = default;
|
||||||
|
|
||||||
virtual Polyline travel_to(const GCode &gcodegen, const Point &point) override;
|
// Used for disabling unnecessary calling collect_contours_all_layers
|
||||||
|
virtual void init_external_mp(const Print &print) override {};
|
||||||
|
virtual void init_layer_mp(const ExPolygons &islands) override {};
|
||||||
|
|
||||||
|
virtual Polyline travel_to(const GCode &gcodegen, const Point &point) override
|
||||||
|
{
|
||||||
|
bool could_be_wipe_disabled;
|
||||||
|
return this->travel_to(gcodegen, point, &could_be_wipe_disabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Polyline travel_to(const GCode &gcodegen, const Point &point, bool *needs_wipe) override;
|
||||||
|
|
||||||
void init_layer(const Layer &layer);
|
void init_layer(const Layer &layer);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue