Fix layer change handling

This commit is contained in:
Martin Šach 2024-06-21 15:44:21 +02:00 committed by Lukas Matena
parent 796eddd971
commit 61e015fc38
6 changed files with 76 additions and 177 deletions

View File

@ -2174,25 +2174,11 @@ bool GCodeGenerator::line_distancer_is_required(const std::vector<unsigned int>&
} }
Polyline GCodeGenerator::get_layer_change_xy_path(const Vec3d &from, const Vec3d &to) { Polyline GCodeGenerator::get_layer_change_xy_path(const Vec3d &from, const Vec3d &to) {
bool could_be_wipe_disabled{false}; bool could_be_wipe_disabled{false};
const bool needs_retraction{true}; const bool needs_retraction{true};
const Point saved_last_position{*this->last_position};
const bool saved_use_external_mp{this->m_avoid_crossing_perimeters.use_external_mp_once};
const Vec2d saved_origin{this->origin()};
const Layer* saved_layer{this->layer()};
this->m_avoid_crossing_perimeters.use_external_mp_once = m_layer_change_used_external_mp;
if (this->m_layer_change_origin) {
this->m_origin = *this->m_layer_change_origin;
}
this->m_layer = m_layer_change_layer;
this->m_avoid_crossing_perimeters.init_layer(*this->m_layer);
const Point start_point{this->gcode_to_point(from.head<2>())}; const Point start_point{this->gcode_to_point(from.head<2>())};
const Point end_point{this->gcode_to_point(to.head<2>())}; const Point end_point{this->gcode_to_point(to.head<2>())};
this->last_position = start_point;
Polyline xy_path{ Polyline xy_path{
this->generate_travel_xy_path(start_point, end_point, needs_retraction, could_be_wipe_disabled)}; this->generate_travel_xy_path(start_point, end_point, needs_retraction, could_be_wipe_disabled)};
@ -2202,11 +2188,6 @@ Polyline GCodeGenerator::get_layer_change_xy_path(const Vec3d &from, const Vec3d
gcode_xy_path.push_back(this->point_to_gcode(point)); gcode_xy_path.push_back(this->point_to_gcode(point));
} }
this->last_position = saved_last_position;
this->m_avoid_crossing_perimeters.use_external_mp_once = saved_use_external_mp;
this->m_origin = saved_origin;
this->m_layer = saved_layer;
Polyline result; Polyline result;
for (const Vec2d& point : gcode_xy_path) { for (const Vec2d& point : gcode_xy_path) {
result.points.push_back(gcode_to_point(point)); result.points.push_back(gcode_to_point(point));
@ -2457,7 +2438,10 @@ LayerResult GCodeGenerator::process_layer(
const std::vector<ExtruderExtrusions> extrusions{ const std::vector<ExtruderExtrusions> extrusions{
this->get_sorted_extrusions(print, layers, layer_tools, instances_to_print, smooth_path_caches, first_layer)}; this->get_sorted_extrusions(print, layers, layer_tools, instances_to_print, smooth_path_caches, first_layer)};
const std::optional<Point> first_point{GCode::ExtrusionOrder::get_first_point(extrusions)}; if (extrusions.empty()) {
return result;
}
const Point first_point{*GCode::ExtrusionOrder::get_first_point(extrusions)};
std::string gcode; std::string gcode;
assert(is_decimal_separator_point()); // for the sprintfs assert(is_decimal_separator_point()); // for the sprintfs
@ -2477,8 +2461,7 @@ LayerResult GCodeGenerator::process_layer(
m_last_layer_z = static_cast<float>(print_z); m_last_layer_z = static_cast<float>(print_z);
m_max_layer_z = std::max(m_max_layer_z, m_last_layer_z); m_max_layer_z = std::max(m_max_layer_z, m_last_layer_z);
m_last_height = height; m_last_height = height;
m_current_layer_first_position = std::nullopt; m_already_extruded = false;
m_already_unretracted = false;
// Set new layer - this will change Z and force a retraction if retract_layer_change is enabled. // Set new layer - this will change Z and force a retraction if retract_layer_change is enabled.
if (!first_layer && ! print.config().before_layer_gcode.value.empty()) { if (!first_layer && ! print.config().before_layer_gcode.value.empty()) {
@ -2490,7 +2473,7 @@ LayerResult GCodeGenerator::process_layer(
print.config().before_layer_gcode.value, m_writer.extruder()->id(), &config) print.config().before_layer_gcode.value, m_writer.extruder()->id(), &config)
+ "\n"; + "\n";
} }
gcode += this->change_layer(previous_layer_z, print_z, result.spiral_vase_enable); // this will increase m_layer_index gcode += this->change_layer(previous_layer_z, print_z, result.spiral_vase_enable, first_point, first_layer); // this will increase m_layer_index
m_layer = &layer; m_layer = &layer;
if (this->line_distancer_is_required(layer_tools.extruders) && this->m_layer != nullptr && this->m_layer->lower_layer != nullptr) if (this->line_distancer_is_required(layer_tools.extruders) && this->m_layer != nullptr && this->m_layer->lower_layer != nullptr)
m_travel_obstacle_tracker.init_layer(layer, layers); m_travel_obstacle_tracker.init_layer(layer, layers);
@ -2554,6 +2537,10 @@ LayerResult GCodeGenerator::process_layer(
} }
} }
const Vec3crd point{to_3d(first_point, scaled(print_z))};
gcode += this->travel_to_first_position(point, print_z, ExtrusionRole::Mixed, [&](){
return m_writer.multiple_extruders ? "" : m_label_objects.maybe_change_instance(m_writer);
});
// Extrude the skirt, brim, support, perimeters, infill ordered by the extruders. // Extrude the skirt, brim, support, perimeters, infill ordered by the extruders.
for (const ExtruderExtrusions &extruder_extrusions : extrusions) for (const ExtruderExtrusions &extruder_extrusions : extrusions)
@ -2662,73 +2649,6 @@ LayerResult GCodeGenerator::process_layer(
this->set_origin(0.0, 0.0); this->set_origin(0.0, 0.0);
} }
// During layer change the starting position of next layer is now known.
// The solution is thus to emplace a temporary tag to the gcode, cache the postion and
// replace the tag later. The tag is Layer_Change_Travel, the cached position is
// m_current_layer_first_position and it is replaced here.
const std::string tag = GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Layer_Change_Travel);
std::string layer_change_gcode;
const bool do_ramping_layer_change = (
m_previous_layer_last_position
&& m_current_layer_first_position
&& m_layer_change_extruder_id
&& !result.spiral_vase_enable
&& print_z > previous_layer_z
&& this->m_config.travel_ramping_lift.get_at(*m_layer_change_extruder_id)
&& this->m_config.travel_slope.get_at(*m_layer_change_extruder_id) > 0
&& this->m_config.travel_slope.get_at(*m_layer_change_extruder_id) < 90
);
if (first_layer) {
layer_change_gcode = ""; // Explicit for readability.
} else if (do_ramping_layer_change) {
const Vec3d &from{*m_previous_layer_last_position};
const Vec3d &to{*m_current_layer_first_position};
layer_change_gcode = this->get_ramping_layer_change_gcode(from, to, *m_layer_change_extruder_id);
} else {
layer_change_gcode = this->writer().get_travel_to_z_gcode(print_z, "simple layer change");
}
const auto keep_retraciton{[&](){
if (!do_ramping_layer_change) {
return true;
}
const double travel_length{(*m_current_layer_first_position - *m_previous_layer_last_position_before_wipe).norm()};
if (this->m_config.retract_before_travel.get_at(*m_layer_change_extruder_id) < travel_length) {
// Travel is long, keep retraction.
return true;
}
return false;
}};
bool removed_retraction{false};
if (this->m_config.travel_ramping_lift.get_at(*m_layer_change_extruder_id) && !result.spiral_vase_enable) {
const std::string retraction_start_tag = GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Layer_Change_Retraction_Start);
const std::string retraction_end_tag = GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Layer_Change_Retraction_End);
if (keep_retraciton()) {
boost::algorithm::replace_first(gcode, retraction_start_tag, "");
boost::algorithm::replace_first(gcode, retraction_end_tag, "");
} else {
const std::size_t start{gcode.find(retraction_start_tag)};
const std::size_t end_tag_start{gcode.find(retraction_end_tag)};
const std::size_t end{end_tag_start + retraction_end_tag.size()};
gcode.replace(start, end - start, "");
layer_change_gcode = this->get_ramping_layer_change_gcode(*m_previous_layer_last_position_before_wipe, *m_current_layer_first_position, *m_layer_change_extruder_id);
removed_retraction = true;
}
}
if (removed_retraction) {
const std::size_t start{gcode.find("FIRST_UNRETRACT")};
const std::size_t end{gcode.find("\n", start)};
gcode.replace(start, end - start, "");
} else {
boost::algorithm::replace_first(gcode,"FIRST_UNRETRACT", "");
}
boost::algorithm::replace_first(gcode, tag, layer_change_gcode);
BOOST_LOG_TRIVIAL(trace) << "Exported layer " << layer.id() << " print_z " << print_z << BOOST_LOG_TRIVIAL(trace) << "Exported layer " << layer.id() << " print_z " << print_z <<
log_memory_info(); log_memory_info();
@ -2866,7 +2786,9 @@ std::string GCodeGenerator::preamble()
std::string GCodeGenerator::change_layer( std::string GCodeGenerator::change_layer(
coordf_t previous_layer_z, coordf_t previous_layer_z,
coordf_t print_z, coordf_t print_z,
bool vase_mode bool vase_mode,
const Point &first_point,
const bool first_layer
) { ) {
std::string gcode; std::string gcode;
if (m_layer_count > 0) if (m_layer_count > 0)
@ -2877,29 +2799,40 @@ std::string GCodeGenerator::change_layer(
gcode += m_label_objects.maybe_change_instance(m_writer); gcode += m_label_objects.maybe_change_instance(m_writer);
} }
if (!EXTRUDER_CONFIG(travel_ramping_lift) && EXTRUDER_CONFIG(retract_layer_change)) { const unsigned extruder_id{m_writer.extruder()->id()};
gcode += this->retract_and_wipe(); const bool do_ramping_layer_change = (
} else if (EXTRUDER_CONFIG(travel_ramping_lift) && !vase_mode){ this->last_position
m_previous_layer_last_position_before_wipe = this->last_position ? && !vase_mode
std::optional{to_3d(this->point_to_gcode(*this->last_position), previous_layer_z)} : && print_z > previous_layer_z
std::nullopt; && this->m_config.travel_ramping_lift.get_at(extruder_id)
gcode += GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Layer_Change_Retraction_Start); && this->m_config.travel_slope.get_at(extruder_id) > 0
gcode += this->retract_and_wipe(false, false); && this->m_config.travel_slope.get_at(extruder_id) < 90
gcode += GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Layer_Change_Retraction_End); );
gcode += m_writer.reset_e(); if (do_ramping_layer_change) {
Vec3d from{to_3d(this->point_to_gcode(*this->last_position), previous_layer_z)};
const Vec3d to{to_3d(unscaled(first_point), print_z)};
const double travel_length{(to - from).norm()};
if (this->m_config.retract_before_travel.get_at(extruder_id) < travel_length) {
gcode += this->retract_and_wipe();
}
// Update from after wipe.
from = to_3d(this->point_to_gcode(*this->last_position), previous_layer_z);
gcode += this->get_ramping_layer_change_gcode(from, to, extruder_id);
this->writer().update_position(to);
this->last_position = this->gcode_to_point(unscaled(first_point));
} else {
if (EXTRUDER_CONFIG(retract_layer_change)) {
gcode += this->retract_and_wipe();
}
if (!first_layer) {
gcode += this->writer().get_travel_to_z_gcode(print_z, "simple layer change");
}
} }
Vec3d new_position = this->writer().get_position();
new_position.z() = print_z;
this->writer().update_position(new_position);
m_previous_layer_last_position = this->last_position ?
std::optional{to_3d(this->point_to_gcode(*this->last_position), previous_layer_z)} :
std::nullopt;
gcode += GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Layer_Change_Travel);
this->m_layer_change_extruder_id = m_writer.extruder()->id();
// forget last wiping path as wiping after raising Z is pointless // forget last wiping path as wiping after raising Z is pointless
m_wipe.reset_path(); m_wipe.reset_path();
@ -3103,10 +3036,6 @@ std::string GCodeGenerator::travel_to_first_position(const Vec3crd& point, const
*this->last_position, point.head<2>(), role, "travel to first layer point", insert_gcode *this->last_position, point.head<2>(), role, "travel to first layer point", insert_gcode
); );
} else { } else {
this->m_layer_change_used_external_mp = this->m_avoid_crossing_perimeters.use_external_mp_once;
this->m_layer_change_layer = this->layer();
this->m_layer_change_origin = this->origin();
double lift{ double lift{
EXTRUDER_CONFIG(travel_ramping_lift) ? EXTRUDER_CONFIG(travel_max_lift) : EXTRUDER_CONFIG(travel_ramping_lift) ? EXTRUDER_CONFIG(travel_max_lift) :
EXTRUDER_CONFIG(retract_lift)}; EXTRUDER_CONFIG(retract_lift)};
@ -3135,7 +3064,7 @@ std::string GCodeGenerator::travel_to_first_position(const Vec3crd& point, const
this->writer().update_position(gcode_point); this->writer().update_position(gcode_point);
} }
m_current_layer_first_position = gcode_point; m_already_extruded = true;
return gcode; return gcode;
} }
@ -3178,42 +3107,26 @@ std::string GCodeGenerator::_extrude(
gcode += m_label_objects.maybe_change_instance(m_writer); gcode += m_label_objects.maybe_change_instance(m_writer);
} }
if (!m_current_layer_first_position) { if (!this->last_position) {
const Vec3crd point = to_3d(path.front().point, scaled(this->m_last_layer_z)); const double z = this->m_last_layer_z;
gcode += this->travel_to_first_position(point, unscaled(point.z()), path_attr.role, [&](){ const std::string comment{"move to print after unknown position"};
gcode += this->retract_and_wipe();
gcode += m_writer.multiple_extruders ? "" : m_label_objects.maybe_change_instance(m_writer);
gcode += this->m_writer.travel_to_xy(this->point_to_gcode(path.front().point), comment);
gcode += this->m_writer.get_travel_to_z_gcode(z, comment);
} else if ( this->last_position != path.front().point) {
std::string comment = "move to first ";
comment += description;
comment += description_bridge;
comment += " point";
const std::string travel_gcode{this->travel_to(*this->last_position, path.front().point, path_attr.role, comment, [&](){
return m_writer.multiple_extruders ? "" : m_label_objects.maybe_change_instance(m_writer); return m_writer.multiple_extruders ? "" : m_label_objects.maybe_change_instance(m_writer);
}); })};
} else { gcode += travel_gcode;
// go to first point of extrusion path
if (!this->last_position) {
const double z = this->m_last_layer_z;
const std::string comment{"move to print after unknown position"};
gcode += this->retract_and_wipe();
gcode += m_writer.multiple_extruders ? "" : m_label_objects.maybe_change_instance(m_writer);
gcode += this->m_writer.travel_to_xy(this->point_to_gcode(path.front().point), comment);
gcode += this->m_writer.get_travel_to_z_gcode(z, comment);
} else if ( this->last_position != path.front().point) {
std::string comment = "move to first ";
comment += description;
comment += description_bridge;
comment += " point";
const std::string travel_gcode{this->travel_to(*this->last_position, path.front().point, path_attr.role, comment, [&](){
return m_writer.multiple_extruders ? "" : m_label_objects.maybe_change_instance(m_writer);
})};
gcode += travel_gcode;
}
} }
// compensate retraction // compensate retraction
if (this->m_already_unretracted) { gcode += this->unretract();
gcode += this->unretract();
} else {
this->m_already_unretracted = true;
gcode += "FIRST_UNRETRACT" + this->unretract();
//First unretract may or may not be removed thus we must start from E0.
gcode += this->writer().reset_e();
}
if (m_writer.multiple_extruders && !has_active_instance) { if (m_writer.multiple_extruders && !has_active_instance) {
gcode += m_label_objects.maybe_change_instance(m_writer); gcode += m_label_objects.maybe_change_instance(m_writer);

View File

@ -279,7 +279,9 @@ private:
std::string change_layer( std::string change_layer(
coordf_t previous_layer_z, coordf_t previous_layer_z,
coordf_t print_z, coordf_t print_z,
bool vase_mode bool vase_mode,
const Point &first_point,
const bool first_layer
); );
std::string extrude_smooth_path( std::string extrude_smooth_path(
const GCode::SmoothPath &smooth_path, const bool is_loop, const std::string_view description, const double speed const GCode::SmoothPath &smooth_path, const bool is_loop, const std::string_view description, const double speed
@ -429,12 +431,7 @@ private:
std::optional<Vec3d> m_previous_layer_last_position; std::optional<Vec3d> m_previous_layer_last_position;
std::optional<Vec3d> m_previous_layer_last_position_before_wipe; std::optional<Vec3d> m_previous_layer_last_position_before_wipe;
// This needs to be populated during the layer processing! // This needs to be populated during the layer processing!
std::optional<Vec3d> m_current_layer_first_position; bool m_already_extruded{false};
std::optional<unsigned> m_layer_change_extruder_id;
bool m_layer_change_used_external_mp{false};
const Layer* m_layer_change_layer{nullptr};
std::optional<Vec2d> m_layer_change_origin;
bool m_already_unretracted{false};
std::unique_ptr<CoolingBuffer> m_cooling_buffer; std::unique_ptr<CoolingBuffer> m_cooling_buffer;
std::unique_ptr<SpiralVase> m_spiral_vase; std::unique_ptr<SpiralVase> m_spiral_vase;
std::unique_ptr<GCodeFindReplace> m_find_replace; std::unique_ptr<GCodeFindReplace> m_find_replace;

View File

@ -198,13 +198,13 @@ inline std::optional<InstancePoint> get_first_point(const std::vector<SliceExtru
} }
inline std::optional<Point> get_first_point(const ExtruderExtrusions &extrusions) { inline std::optional<Point> get_first_point(const ExtruderExtrusions &extrusions) {
for (const BrimPath &brim_path : extrusions.brim) { for (const auto&[_, path] : extrusions.skirt) {
if (auto result = get_first_point(brim_path.path)) { if (auto result = get_first_point(path)) {
return result->local_point; return result->local_point;
}; };
} }
for (const auto&[_, path] : extrusions.skirt) { for (const BrimPath &brim_path : extrusions.brim) {
if (auto result = get_first_point(path)) { if (auto result = get_first_point(brim_path.path)) {
return result->local_point; return result->local_point;
}; };
} }

View File

@ -57,9 +57,6 @@ const std::vector<std::string> GCodeProcessor::Reserved_Tags = {
"HEIGHT:", "HEIGHT:",
"WIDTH:", "WIDTH:",
"LAYER_CHANGE", "LAYER_CHANGE",
"LAYER_CHANGE_TRAVEL",
"LAYER_CHANGE_RETRACTION_START",
"LAYER_CHANGE_RETRACTION_END",
"COLOR_CHANGE", "COLOR_CHANGE",
"PAUSE_PRINT", "PAUSE_PRINT",
"CUSTOM_GCODE", "CUSTOM_GCODE",

View File

@ -181,9 +181,6 @@ namespace Slic3r {
Height, Height,
Width, Width,
Layer_Change, Layer_Change,
Layer_Change_Travel,
Layer_Change_Retraction_Start,
Layer_Change_Retraction_End,
Color_Change, Color_Change,
Pause_Print, Pause_Print,
Custom_Code, Custom_Code,

View File

@ -68,18 +68,13 @@ std::string WipeTowerIntegration::append_tcr(GCodeGenerator &gcodegen, const Wip
gcode += gcodegen.retract_and_wipe(); gcode += gcodegen.retract_and_wipe();
gcodegen.m_avoid_crossing_perimeters.use_external_mp_once = true; gcodegen.m_avoid_crossing_perimeters.use_external_mp_once = true;
const std::string comment{"Travel to a Wipe Tower"}; const std::string comment{"Travel to a Wipe Tower"};
if (gcodegen.m_current_layer_first_position) { if (gcodegen.last_position) {
if (gcodegen.last_position) { gcode += gcodegen.travel_to(
gcode += gcodegen.travel_to( *gcodegen.last_position, xy_point, ExtrusionRole::Mixed, comment, [](){return "";}
*gcodegen.last_position, xy_point, ExtrusionRole::Mixed, comment, [](){return "";} );
);
} else {
gcode += gcodegen.writer().travel_to_xy(gcodegen.point_to_gcode(xy_point), comment);
gcode += gcodegen.writer().get_travel_to_z_gcode(z, comment);
}
} else { } else {
const Vec3crd point = to_3d(xy_point, scaled(z)); gcode += gcodegen.writer().travel_to_xy(gcodegen.point_to_gcode(xy_point), comment);
gcode += gcodegen.travel_to_first_position(point, current_z, ExtrusionRole::Mixed, [](){return "";}); gcode += gcodegen.writer().get_travel_to_z_gcode(z, comment);
} }
gcode += gcodegen.unretract(); gcode += gcodegen.unretract();
} else { } else {