mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-13 23:35:59 +08:00
Use path generation even on layer change
This commit is contained in:
parent
ed8c373dc7
commit
ea9dfa9a8d
@ -1245,7 +1245,7 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
|
||||
// Move to the origin position for the copy we're going to print.
|
||||
// This happens before Z goes down to layer 0 again, so that no collision happens hopefully.
|
||||
m_enable_cooling_markers = false; // we're not filtering these moves through CoolingBuffer
|
||||
m_avoid_crossing_perimeters.use_external_mp_once();
|
||||
m_avoid_crossing_perimeters.use_external_mp_once = true;
|
||||
file.write(this->retract_and_wipe());
|
||||
file.write(m_label_objects.maybe_stop_instance());
|
||||
const double last_z{this->writer().get_position().z()};
|
||||
@ -2120,18 +2120,61 @@ bool GCodeGenerator::line_distancer_is_required(const std::vector<unsigned int>&
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string GCodeGenerator::get_layer_change_gcode(const Vec3d& from, const Vec3d& to, const unsigned extruder_id) {
|
||||
const Polyline xy_path{
|
||||
this->gcode_to_point(from.head<2>()),
|
||||
this->gcode_to_point(to.head<2>())
|
||||
};
|
||||
Polyline GCodeGenerator::get_layer_change_xy_path(const Vec3d &from, const Vec3d &to) {
|
||||
|
||||
bool could_be_wipe_disabled{false};
|
||||
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 end_point{this->gcode_to_point(to.head<2>())};
|
||||
this->last_position = start_point;
|
||||
|
||||
Polyline xy_path{
|
||||
this->generate_travel_xy_path(start_point, end_point, needs_retraction, could_be_wipe_disabled)};
|
||||
std::vector<Vec2d> gcode_xy_path;
|
||||
gcode_xy_path.reserve(xy_path.size());
|
||||
for (const Point &point : xy_path.points) {
|
||||
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;
|
||||
for (const Vec2d& point : gcode_xy_path) {
|
||||
result.points.push_back(gcode_to_point(point));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
GCode::Impl::Travels::ElevatedTravelParams get_ramping_layer_change_params(
|
||||
const Vec3d &from,
|
||||
const Vec3d &to,
|
||||
const Polyline &xy_path,
|
||||
const FullPrintConfig &config,
|
||||
const unsigned extruder_id,
|
||||
const GCode::TravelObstacleTracker &obstacle_tracker
|
||||
) {
|
||||
using namespace GCode::Impl::Travels;
|
||||
|
||||
ElevatedTravelParams elevation_params{
|
||||
get_elevated_traval_params(xy_path, this->m_config, extruder_id, this->m_travel_obstacle_tracker)};
|
||||
get_elevated_traval_params(xy_path, config, extruder_id, obstacle_tracker)};
|
||||
|
||||
const double initial_elevation = from.z();
|
||||
const double z_change = to.z() - from.z();
|
||||
elevation_params.lift_height = std::max(z_change, elevation_params.lift_height);
|
||||
|
||||
@ -2145,6 +2188,26 @@ std::string GCodeGenerator::get_layer_change_gcode(const Vec3d& from, const Vec3
|
||||
elevation_params.slope_end = path_length;
|
||||
}
|
||||
|
||||
return elevation_params;
|
||||
}
|
||||
|
||||
std::string GCodeGenerator::get_ramping_layer_change_gcode(const Vec3d &from, const Vec3d &to, const unsigned extruder_id) {
|
||||
const Polyline xy_path{this->get_layer_change_xy_path(from, to)};
|
||||
|
||||
const GCode::Impl::Travels::ElevatedTravelParams elevation_params{
|
||||
get_ramping_layer_change_params(
|
||||
from, to, xy_path, m_config, extruder_id, m_travel_obstacle_tracker
|
||||
)};
|
||||
return this->generate_ramping_layer_change_gcode(xy_path, from.z(), elevation_params);
|
||||
}
|
||||
|
||||
std::string GCodeGenerator::generate_ramping_layer_change_gcode(
|
||||
const Polyline &xy_path,
|
||||
const double initial_elevation,
|
||||
const GCode::Impl::Travels::ElevatedTravelParams &elevation_params
|
||||
) const {
|
||||
using namespace GCode::Impl::Travels;
|
||||
|
||||
const std::vector<double> ensure_points_at_distances = linspace(
|
||||
elevation_params.slope_end - elevation_params.blend_width / 2.0,
|
||||
elevation_params.slope_end + elevation_params.blend_width / 2.0,
|
||||
@ -2158,9 +2221,10 @@ std::string GCodeGenerator::get_layer_change_gcode(const Vec3d& from, const Vec3
|
||||
|
||||
std::string travel_gcode;
|
||||
Vec3d previous_point{this->point_to_gcode(travel.front())};
|
||||
for (const Vec3crd& point : travel) {
|
||||
for (const Vec3crd &point : travel) {
|
||||
const Vec3d gcode_point{this->point_to_gcode(point)};
|
||||
travel_gcode += this->m_writer.get_travel_to_xyz_gcode(previous_point, gcode_point, "layer change");
|
||||
travel_gcode += this->m_writer
|
||||
.get_travel_to_xyz_gcode(previous_point, gcode_point, "layer change");
|
||||
previous_point = gcode_point;
|
||||
}
|
||||
return travel_gcode;
|
||||
@ -2448,7 +2512,9 @@ LayerResult GCodeGenerator::process_layer(
|
||||
if (first_layer) {
|
||||
layer_change_gcode = ""; // Explicit for readability.
|
||||
} else if (do_ramping_layer_change) {
|
||||
layer_change_gcode = this->get_layer_change_gcode(*m_previous_layer_last_position, *m_current_layer_first_position, *m_layer_change_extruder_id);
|
||||
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");
|
||||
}
|
||||
@ -2479,7 +2545,7 @@ LayerResult GCodeGenerator::process_layer(
|
||||
const std::size_t end{end_tag_start + retraction_end_tag.size()};
|
||||
gcode.replace(start, end - start, "");
|
||||
|
||||
layer_change_gcode = this->get_layer_change_gcode(*m_previous_layer_last_position_before_wipe, *m_current_layer_first_position, *m_layer_change_extruder_id);
|
||||
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;
|
||||
}
|
||||
@ -2540,11 +2606,13 @@ void GCodeGenerator::process_layer_single_object(
|
||||
m_avoid_crossing_perimeters.init_layer(*m_layer);
|
||||
// When starting a new object, use the external motion planner for the first travel move.
|
||||
const Point &offset = print_object.instances()[print_instance.instance_id].shift;
|
||||
|
||||
const bool updated{m_label_objects.update(&print_instance.print_object.instances()[print_instance.instance_id])};
|
||||
if (updated)
|
||||
m_avoid_crossing_perimeters.use_external_mp_once();
|
||||
GCode::PrintObjectInstance next_instance = {&print_object, int(print_instance.instance_id)};
|
||||
if (m_current_instance != next_instance) {
|
||||
m_avoid_crossing_perimeters.use_external_mp_once = true;
|
||||
}
|
||||
m_current_instance = next_instance;
|
||||
this->set_origin(unscale(offset));
|
||||
m_label_objects.update(&print_instance.print_object.instances()[print_instance.instance_id]);
|
||||
}
|
||||
};
|
||||
|
||||
@ -3096,37 +3164,53 @@ void GCodeGenerator::GCodeOutputStream::write_format(const char* format, ...)
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
std::string GCodeGenerator::travel_to_first_position(const Vec3crd& point, const double from_z, const std::function<std::string()>& insert_gcode) {
|
||||
std::string GCodeGenerator::travel_to_first_position(const Vec3crd& point, const double from_z, const ExtrusionRole role, const std::function<std::string()>& insert_gcode) {
|
||||
std::string gcode;
|
||||
|
||||
const Vec3d gcode_point = to_3d(this->point_to_gcode(point.head<2>()), unscaled(point.z()));
|
||||
|
||||
double lift{
|
||||
EXTRUDER_CONFIG(travel_ramping_lift) ? EXTRUDER_CONFIG(travel_max_lift) :
|
||||
EXTRUDER_CONFIG(retract_lift)};
|
||||
const double upper_limit = EXTRUDER_CONFIG(retract_lift_below);
|
||||
const double lower_limit = EXTRUDER_CONFIG(retract_lift_above);
|
||||
if ((lower_limit > 0 && gcode_point.z() < lower_limit) ||
|
||||
(upper_limit > 0 && gcode_point.z() > upper_limit)) {
|
||||
lift = 0.0;
|
||||
}
|
||||
if (!EXTRUDER_CONFIG(travel_ramping_lift) && this->last_position) {
|
||||
Vec3d writer_position{this->writer().get_position()};
|
||||
writer_position.z() = 0.0; // Endofrce z generation!
|
||||
this->writer().update_position(writer_position);
|
||||
gcode = this->travel_to(
|
||||
*this->last_position, point.head<2>(), role, "travel to first layer point", insert_gcode
|
||||
);
|
||||
} 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();
|
||||
|
||||
if (EXTRUDER_CONFIG(retract_length) > 0 && (!this->last_position || (!EXTRUDER_CONFIG(travel_ramping_lift)))) {
|
||||
if (!this->last_position || EXTRUDER_CONFIG(retract_before_travel) < (this->point_to_gcode(*this->last_position) - gcode_point.head<2>()).norm()) {
|
||||
gcode += this->writer().retract();
|
||||
gcode += this->writer().get_travel_to_z_gcode(from_z + lift, "lift");
|
||||
double lift{
|
||||
EXTRUDER_CONFIG(travel_ramping_lift) ? EXTRUDER_CONFIG(travel_max_lift) :
|
||||
EXTRUDER_CONFIG(retract_lift)};
|
||||
const double upper_limit = EXTRUDER_CONFIG(retract_lift_below);
|
||||
const double lower_limit = EXTRUDER_CONFIG(retract_lift_above);
|
||||
if ((lower_limit > 0 && gcode_point.z() < lower_limit) ||
|
||||
(upper_limit > 0 && gcode_point.z() > upper_limit)) {
|
||||
lift = 0.0;
|
||||
}
|
||||
|
||||
if (EXTRUDER_CONFIG(retract_length) > 0 && !this->last_position) {
|
||||
if (!this->last_position || EXTRUDER_CONFIG(retract_before_travel) < (this->point_to_gcode(*this->last_position) - gcode_point.head<2>()).norm()) {
|
||||
gcode += this->writer().retract();
|
||||
gcode += this->writer().get_travel_to_z_gcode(from_z + lift, "lift");
|
||||
}
|
||||
}
|
||||
|
||||
const std::string comment{"move to first layer point"};
|
||||
|
||||
gcode += insert_gcode();
|
||||
gcode += this->writer().get_travel_to_xy_gcode(gcode_point.head<2>(), comment);
|
||||
gcode += this->writer().get_travel_to_z_gcode(gcode_point.z(), comment);
|
||||
|
||||
this->m_avoid_crossing_perimeters.reset_once_modifiers();
|
||||
this->last_position = point.head<2>();
|
||||
this->writer().update_position(gcode_point);
|
||||
}
|
||||
this->last_position = point.head<2>();
|
||||
this->writer().update_position(gcode_point);
|
||||
|
||||
gcode += insert_gcode();
|
||||
|
||||
std::string comment{"move to first layer point"};
|
||||
gcode += this->writer().get_travel_to_xy_gcode(gcode_point.head<2>(), comment);
|
||||
gcode += this->writer().get_travel_to_z_gcode(gcode_point.z(), comment);
|
||||
|
||||
m_current_layer_first_position = gcode_point;
|
||||
|
||||
return gcode;
|
||||
}
|
||||
|
||||
@ -3160,7 +3244,7 @@ std::string GCodeGenerator::_extrude(
|
||||
|
||||
if (!m_current_layer_first_position) {
|
||||
const Vec3crd point = to_3d(path.front().point, scaled(this->m_last_layer_z));
|
||||
gcode += this->travel_to_first_position(point, unscaled(point.z()), [&](){
|
||||
gcode += this->travel_to_first_position(point, unscaled(point.z()), path_attr.role, [&](){
|
||||
return m_writer.multiple_extruders ? "" : m_label_objects.maybe_change_instance(m_writer);
|
||||
});
|
||||
} else {
|
||||
|
@ -110,7 +110,7 @@ struct PrintObjectInstance
|
||||
int instance_idx = -1;
|
||||
|
||||
bool operator==(const PrintObjectInstance &other) const {return print_object == other.print_object && instance_idx == other.instance_idx; }
|
||||
bool operator!=(const PrintObjectInstance &other) const { return *this == other; }
|
||||
bool operator!=(const PrintObjectInstance &other) const { return !(*this == other); }
|
||||
};
|
||||
|
||||
} // namespace GCode
|
||||
@ -226,8 +226,16 @@ private:
|
||||
static ObjectsLayerToPrint collect_layers_to_print(const PrintObject &object);
|
||||
static std::vector<std::pair<coordf_t, ObjectsLayerToPrint>> collect_layers_to_print(const Print &print);
|
||||
|
||||
Polyline get_layer_change_xy_path(const Vec3d &from, const Vec3d &to);
|
||||
|
||||
std::string get_ramping_layer_change_gcode(const Vec3d &from, const Vec3d &to, const unsigned extruder_id);
|
||||
|
||||
/** @brief Generates ramping travel gcode for layer change. */
|
||||
std::string get_layer_change_gcode(const Vec3d& from, const Vec3d& to, const unsigned extruder_id);
|
||||
std::string generate_ramping_layer_change_gcode(
|
||||
const Polyline &xy_path,
|
||||
const double initial_elevation,
|
||||
const GCode::Impl::Travels::ElevatedTravelParams &elevation_params
|
||||
) const;
|
||||
|
||||
LayerResult process_layer(
|
||||
const Print &print,
|
||||
@ -336,7 +344,7 @@ private:
|
||||
const std::function<std::string()>& insert_gcode
|
||||
);
|
||||
|
||||
std::string travel_to_first_position(const Vec3crd& point, const double from_z, const std::function<std::string()>& insert_gcode);
|
||||
std::string travel_to_first_position(const Vec3crd& point, const double from_z, const ExtrusionRole role, const std::function<std::string()>& insert_gcode);
|
||||
|
||||
bool needs_retraction(const Polyline &travel, ExtrusionRole role = ExtrusionRole::None);
|
||||
|
||||
@ -431,6 +439,9 @@ private:
|
||||
// This needs to be populated during the layer processing!
|
||||
std::optional<Vec3d> m_current_layer_first_position;
|
||||
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<SpiralVase> m_spiral_vase;
|
||||
@ -446,6 +457,9 @@ private:
|
||||
bool m_second_layer_things_done;
|
||||
// G-code that is due to be written before the next extrusion
|
||||
std::string m_pending_pre_extrusion_gcode;
|
||||
// Pointer to currently exporting PrintObject and instance index.
|
||||
GCode::PrintObjectInstance m_current_instance;
|
||||
|
||||
bool m_silent_time_estimator_enabled;
|
||||
|
||||
// Processor
|
||||
|
@ -1175,7 +1175,7 @@ Polyline AvoidCrossingPerimeters::travel_to(const GCodeGenerator &gcodegen, cons
|
||||
{
|
||||
// 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.
|
||||
bool use_external = m_use_external_mp || m_use_external_mp_once;
|
||||
bool use_external = m_use_external_mp || use_external_mp_once;
|
||||
Point scaled_origin = use_external ? Point::new_scale(gcodegen.origin()(0), gcodegen.origin()(1)) : Point(0, 0);
|
||||
const Point start = *gcodegen.last_position + scaled_origin;
|
||||
const Point end = point + scaled_origin;
|
||||
|
@ -21,11 +21,10 @@ class AvoidCrossingPerimeters
|
||||
public:
|
||||
// Routing around the objects vs. inside a single object.
|
||||
void use_external_mp(bool use = true) { m_use_external_mp = use; };
|
||||
void use_external_mp_once() { m_use_external_mp_once = true; }
|
||||
bool used_external_mp_once() { return m_use_external_mp_once; }
|
||||
bool used_external_mp_once() { return use_external_mp_once; }
|
||||
void disable_once() { m_disabled_once = true; }
|
||||
bool disabled_once() const { return m_disabled_once; }
|
||||
void reset_once_modifiers() { m_use_external_mp_once = false; m_disabled_once = false; }
|
||||
void reset_once_modifiers() { use_external_mp_once = false; m_disabled_once = false; }
|
||||
|
||||
void init_layer(const Layer &layer);
|
||||
|
||||
@ -54,10 +53,10 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// just for the next travel move
|
||||
bool use_external_mp_once { false };
|
||||
private:
|
||||
bool m_use_external_mp { false };
|
||||
// just for the next travel move
|
||||
bool m_use_external_mp_once { false };
|
||||
// this flag disables avoid_crossing_perimeters just for the next travel move
|
||||
// we enable it by default for the first travel move in print
|
||||
bool m_disabled_once { true };
|
||||
|
@ -60,7 +60,7 @@ std::string WipeTowerIntegration::append_tcr(GCodeGenerator &gcodegen, const Wip
|
||||
const Point xy_point = wipe_tower_point_to_object_point(gcodegen, start_pos);
|
||||
gcode += gcodegen.m_label_objects.maybe_stop_instance();
|
||||
gcode += gcodegen.retract_and_wipe();
|
||||
gcodegen.m_avoid_crossing_perimeters.use_external_mp_once();
|
||||
gcodegen.m_avoid_crossing_perimeters.use_external_mp_once = true;
|
||||
const std::string comment{"Travel to a Wipe Tower"};
|
||||
if (gcodegen.m_current_layer_first_position) {
|
||||
if (gcodegen.last_position) {
|
||||
@ -73,7 +73,7 @@ std::string WipeTowerIntegration::append_tcr(GCodeGenerator &gcodegen, const Wip
|
||||
}
|
||||
} else {
|
||||
const Vec3crd point = to_3d(xy_point, scaled(z));
|
||||
gcode += gcodegen.travel_to_first_position(point, current_z, [](){return "";});
|
||||
gcode += gcodegen.travel_to_first_position(point, current_z, ExtrusionRole::Mixed, [](){return "";});
|
||||
}
|
||||
gcode += gcodegen.unretract();
|
||||
} else {
|
||||
@ -140,7 +140,7 @@ std::string WipeTowerIntegration::append_tcr(GCodeGenerator &gcodegen, const Wip
|
||||
}
|
||||
|
||||
// Let the planner know we are traveling between objects.
|
||||
gcodegen.m_avoid_crossing_perimeters.use_external_mp_once();
|
||||
gcodegen.m_avoid_crossing_perimeters.use_external_mp_once = true;
|
||||
return gcode;
|
||||
}
|
||||
|
||||
|
@ -145,6 +145,12 @@ TEST_CASE("Extrusion, travels, temeperatures", "[GCode]") {
|
||||
Model model;
|
||||
Test::init_print({TestMesh::cube_20x20x20}, print, model, config, false, 2);
|
||||
std::string gcode = Test::gcode(print);
|
||||
|
||||
if constexpr (debug_files) {
|
||||
std::ofstream gcode_file{"sequential_print.gcode"};
|
||||
gcode_file << gcode;
|
||||
}
|
||||
|
||||
parser.parse_buffer(gcode, [&] (Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) {
|
||||
INFO("Unexpected E argument");
|
||||
CHECK(!line.has_e());
|
||||
|
Loading…
x
Reference in New Issue
Block a user