diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index 2db6de209a..ac3d8da7cc 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -28,6 +28,39 @@ bool GCodeWriter::supports_separate_travel_acceleration(GCodeFlavor flavor) void GCodeWriter::apply_print_config(const PrintConfig &print_config) { this->config.apply(print_config, true); + + // Some machine limits are stride-2 (normal, silent) pairs, here we extract the value that will be used, + // which is always normal mode at the moment + // TODO: support silent? Any printer actually have that? + auto get_machine_limits = [](const std::string key, const ConfigOptionFloats& opt) -> std::vector { + unsigned int stride = 1; + unsigned int offset = 0; + if (printer_options_with_variant_2.count(key) > 0) { + stride = 2; + // offset = ; + } + + std::vector results; + results.reserve(opt.values.size() / stride); + + for (unsigned int i = offset; i < opt.values.size(); i += stride) { + results.emplace_back(opt.values[i]); + } + + return results; + }; + auto rounded = [](std::vector&& vec) -> std::vector&&{ + std::transform(vec.cbegin(), vec.cend(), vec.begin(), [](const double v) { return std::round(v); }); + return std::move(vec); + }; + auto to_uint = [](const std::vector& vec) { + std::vector r; + std::transform(vec.begin(), vec.end(), std::back_inserter(r), [](const double v) { return static_cast(v); }); + return r; + }; +#define LIMITS(OPT) get_machine_limits(#OPT, print_config.OPT) +#define LIMITS_UINT(OPT) to_uint(rounded(LIMITS(OPT))) + m_single_extruder_multi_material = print_config.single_extruder_multi_material.value; bool use_mach_limits = print_config.gcode_flavor.value == gcfMarlinLegacy || print_config.gcode_flavor.value == gcfMarlinFirmware || print_config.gcode_flavor.value == gcfKlipper || print_config.gcode_flavor.value == gcfRepRapFirmware; @@ -35,29 +68,40 @@ void GCodeWriter::apply_print_config(const PrintConfig &print_config) // For Klipper, SET_VELOCITY_LIMIT ACCEL= applies to all moves, so the effective cap // is the minimum of the extruding limit and the per-axis X/Y limits. // This ensures user-configured Motion Ability limits are honoured (#12244). - unsigned int extruding_limit = std::lrint(print_config.machine_max_acceleration_extruding.values.front()); + auto extruding_limit = LIMITS_UINT(machine_max_acceleration_extruding); if (print_config.gcode_flavor.value == gcfKlipper) { - unsigned int x_limit = std::lrint(print_config.machine_max_acceleration_x.values.front()); - unsigned int y_limit = std::lrint(print_config.machine_max_acceleration_y.values.front()); - if (x_limit > 0) extruding_limit = std::min(extruding_limit, x_limit); - if (y_limit > 0) extruding_limit = std::min(extruding_limit, y_limit); + auto x_limit = LIMITS_UINT(machine_max_acceleration_x); + auto y_limit = LIMITS_UINT(machine_max_acceleration_y); + + for (size_t i = 0; i < extruding_limit.size(); i++) { + if (x_limit[i] > 0) extruding_limit[i] = std::min(extruding_limit[i], x_limit[i]); + if (y_limit[i] > 0) extruding_limit[i] = std::min(extruding_limit[i], y_limit[i]); + } } - m_max_acceleration = extruding_limit; + m_max_acceleration = std::move(extruding_limit); } else { - m_max_acceleration = 0; + m_max_acceleration.clear(); + } + if (use_mach_limits && supports_separate_travel_acceleration(print_config.gcode_flavor.value)) { + m_max_travel_acceleration = LIMITS_UINT(machine_max_acceleration_travel); + } else { + m_max_travel_acceleration.clear(); } - m_max_travel_acceleration = static_cast( - std::round((use_mach_limits && supports_separate_travel_acceleration(print_config.gcode_flavor.value)) ? - print_config.machine_max_acceleration_travel.values.front() : - 0)); if (use_mach_limits) { - m_max_jerk_x = std::lrint(print_config.machine_max_jerk_x.values.front()); - m_max_jerk_y = std::lrint(print_config.machine_max_jerk_y.values.front()); - m_max_junction_deviation = (print_config.machine_max_junction_deviation.values.front()); - }; - m_max_jerk_z = print_config.machine_max_jerk_z.values.front(); - m_max_jerk_e = print_config.machine_max_jerk_e.values.front(); + m_max_jerk_x = rounded(LIMITS(machine_max_jerk_x)); + m_max_jerk_y = rounded(LIMITS(machine_max_jerk_y)); + m_max_junction_deviation = LIMITS(machine_max_junction_deviation); + } else { + m_max_jerk_x.clear(); + m_max_jerk_y.clear(); + m_max_junction_deviation.clear(); + } + m_max_jerk_z = LIMITS(machine_max_jerk_z); + m_max_jerk_e = LIMITS(machine_max_jerk_e); m_resolution = print_config.resolution.value; + +#undef LIMITS +#undef LIMITS_UINT } void GCodeWriter::set_extruders(std::vector extruder_ids) @@ -212,14 +256,16 @@ std::string GCodeWriter::set_chamber_temperature(int temperature, bool wait) return gcode.str(); } +#define EXTRUDER_LIMIT(OPT) (OPT.size() <= filament()->extruder_id() ? 0 : OPT[filament()->extruder_id()]) + // copied from PrusaSlicer std::string GCodeWriter::set_acceleration_internal(Acceleration type, unsigned int acceleration) { // Clamp the acceleration to the allowed maximum. - if (type == Acceleration::Print && m_max_acceleration > 0 && acceleration > m_max_acceleration) - acceleration = m_max_acceleration; - if (type == Acceleration::Travel && m_max_travel_acceleration > 0 && acceleration > m_max_travel_acceleration) - acceleration = m_max_travel_acceleration; + if (type == Acceleration::Print && EXTRUDER_LIMIT(m_max_acceleration) > 0 && acceleration > EXTRUDER_LIMIT(m_max_acceleration)) + acceleration = EXTRUDER_LIMIT(m_max_acceleration); + if (type == Acceleration::Travel && EXTRUDER_LIMIT(m_max_travel_acceleration) > 0 && acceleration > EXTRUDER_LIMIT(m_max_travel_acceleration)) + acceleration = EXTRUDER_LIMIT(m_max_travel_acceleration); // Are we setting travel acceleration for a flavour that supports separate travel and print acc? bool separate_travel = (type == Acceleration::Travel && supports_separate_travel_acceleration(this->config.gcode_flavor)); @@ -262,10 +308,10 @@ std::string GCodeWriter::set_jerk_xy(double jerk) std::ostringstream gcode; if (FLAVOR_IS(gcfKlipper)) { // Clamp the jerk to the allowed maximum. - if (m_max_jerk_x > 0 && jerk > m_max_jerk_x) - jerk = m_max_jerk_x; - if (m_max_jerk_y > 0 && jerk > m_max_jerk_y) - jerk = m_max_jerk_y; + if (EXTRUDER_LIMIT(m_max_jerk_x) > 0 && jerk > EXTRUDER_LIMIT(m_max_jerk_x)) + jerk = EXTRUDER_LIMIT(m_max_jerk_x); + if (EXTRUDER_LIMIT(m_max_jerk_y) > 0 && jerk > EXTRUDER_LIMIT(m_max_jerk_y)) + jerk = EXTRUDER_LIMIT(m_max_jerk_y); gcode << "SET_VELOCITY_LIMIT SQUARE_CORNER_VELOCITY=" << jerk; @@ -274,12 +320,12 @@ std::string GCodeWriter::set_jerk_xy(double jerk) double jerk_xy = jerk; // Clamp against the X machine limit - if (m_max_jerk_x > 0 && jerk_xy > m_max_jerk_x) - jerk_xy = m_max_jerk_x; + if (EXTRUDER_LIMIT(m_max_jerk_x) > 0 && jerk_xy > EXTRUDER_LIMIT(m_max_jerk_x)) + jerk_xy = EXTRUDER_LIMIT(m_max_jerk_x); // Clamp against the Y machine limit as well to be safe - if (m_max_jerk_y > 0 && jerk_xy > m_max_jerk_y) - jerk_xy = m_max_jerk_y; + if (EXTRUDER_LIMIT(m_max_jerk_y) > 0 && jerk_xy > EXTRUDER_LIMIT(m_max_jerk_y)) + jerk_xy = EXTRUDER_LIMIT(m_max_jerk_y); // Output the lowest safe limit using ONLY the X parameter gcode << "M207 X" << jerk_xy; @@ -287,16 +333,16 @@ std::string GCodeWriter::set_jerk_xy(double jerk) double jerk_x = jerk; double jerk_y = jerk; // Clamp the axis jerk to the allowed maximum. - if (m_max_jerk_x > 0 && jerk > m_max_jerk_x) - jerk_x = m_max_jerk_x; - if (m_max_jerk_y > 0 && jerk > m_max_jerk_y) - jerk_y = m_max_jerk_y; + if (EXTRUDER_LIMIT(m_max_jerk_x) > 0 && jerk > EXTRUDER_LIMIT(m_max_jerk_x)) + jerk_x = EXTRUDER_LIMIT(m_max_jerk_x); + if (EXTRUDER_LIMIT(m_max_jerk_y) > 0 && jerk > EXTRUDER_LIMIT(m_max_jerk_y)) + jerk_y = EXTRUDER_LIMIT(m_max_jerk_y); gcode << "M205 X" << jerk_x << " Y" << jerk_y; } //the is_bbl check should be in the else statement above so that it doesn't inadverently added Z & E to klipper if (m_is_bbl_printers) - gcode << std::setprecision(2) << " Z" << m_max_jerk_z << " E" << m_max_jerk_e; + gcode << std::setprecision(2) << " Z" << EXTRUDER_LIMIT(m_max_jerk_z) << " E" << EXTRUDER_LIMIT(m_max_jerk_e); if (GCodeWriter::full_gcode_comment) gcode << " ; adjust jerk"; gcode << "\n"; @@ -312,8 +358,8 @@ std::string GCodeWriter::set_accel_and_jerk(unsigned int acceleration, double je throw std::runtime_error(_u8L("set_accel_and_jerk() is only supported by Klipper")); // Clamp the acceleration to the allowed maximum. - if (m_max_acceleration > 0 && acceleration > m_max_acceleration) - acceleration = m_max_acceleration; + if (EXTRUDER_LIMIT(m_max_acceleration) > 0 && acceleration > EXTRUDER_LIMIT(m_max_acceleration)) + acceleration = EXTRUDER_LIMIT(m_max_acceleration); bool is_empty = true; std::ostringstream gcode; @@ -327,10 +373,10 @@ std::string GCodeWriter::set_accel_and_jerk(unsigned int acceleration, double je is_empty = false; } // Clamp the jerk to the allowed maximum. - if (m_max_jerk_x > 0 && jerk > m_max_jerk_x) - jerk = m_max_jerk_x; - if (m_max_jerk_y > 0 && jerk > m_max_jerk_y) - jerk = m_max_jerk_y; + if (EXTRUDER_LIMIT(m_max_jerk_x) > 0 && jerk > EXTRUDER_LIMIT(m_max_jerk_x)) + jerk = EXTRUDER_LIMIT(m_max_jerk_x); + if (EXTRUDER_LIMIT(m_max_jerk_y) > 0 && jerk > EXTRUDER_LIMIT(m_max_jerk_y)) + jerk = EXTRUDER_LIMIT(m_max_jerk_y); if (jerk > 0.01 && !is_approx(jerk, m_last_jerk)) { gcode << " SQUARE_CORNER_VELOCITY=" << jerk; @@ -351,13 +397,13 @@ std::string GCodeWriter::set_accel_and_jerk(unsigned int acceleration, double je std::string GCodeWriter::set_junction_deviation(double junction_deviation){ std::ostringstream gcode; - if (FLAVOR_IS(gcfMarlinFirmware) && m_max_junction_deviation > 0 && junction_deviation > 0) { + if (FLAVOR_IS(gcfMarlinFirmware) && EXTRUDER_LIMIT(m_max_junction_deviation) > 0 && junction_deviation > 0) { // Clamp the junction deviation to the allowed maximum. gcode << "M205 J"; - if (junction_deviation <= m_max_junction_deviation) { + if (junction_deviation <= EXTRUDER_LIMIT(m_max_junction_deviation)) { gcode << std::fixed << std::setprecision(3) << junction_deviation; } else { - gcode << std::fixed << std::setprecision(3) << m_max_junction_deviation; + gcode << std::fixed << std::setprecision(3) << EXTRUDER_LIMIT(m_max_junction_deviation); } if (GCodeWriter::full_gcode_comment) { gcode << " ; Junction Deviation"; diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp index 10e52a1c8e..d3f419df7c 100644 --- a/src/libslic3r/GCodeWriter.hpp +++ b/src/libslic3r/GCodeWriter.hpp @@ -135,22 +135,22 @@ public: bool m_single_extruder_multi_material; std::vector m_curr_filament_extruder; int m_curr_extruder_id; - unsigned int m_last_acceleration; - unsigned int m_last_travel_acceleration; - unsigned int m_max_travel_acceleration; + unsigned int m_last_acceleration; + unsigned int m_last_travel_acceleration; + std::vector m_max_travel_acceleration; // Limit for setting the acceleration, to respect the machine limits set for the Marlin firmware. - // If set to zero, the limit is not in action. - unsigned int m_max_acceleration; - double m_max_jerk_x; - double m_max_jerk_y; - double m_last_jerk; - double m_max_jerk_z; - double m_max_jerk_e; - double m_max_junction_deviation; + // If set to zero, the limit is not in action. Indexed by 0-based physical nozzle id. + std::vector m_max_acceleration; + std::vector m_max_jerk_x; + std::vector m_max_jerk_y; + double m_last_jerk; + std::vector m_max_jerk_z; + std::vector m_max_jerk_e; + std::vector m_max_junction_deviation; - unsigned int m_travel_acceleration; - unsigned int m_travel_jerk; + // unsigned int m_travel_acceleration; + // unsigned int m_travel_jerk; //BBS