From 8b2a94ed5f8b757ccc4919b9182f3d8edaf767fd Mon Sep 17 00:00:00 2001 From: "zhimin.zeng" Date: Tue, 30 Jul 2024 19:25:45 +0800 Subject: [PATCH] ENH: wipe tower support nozzle change jira: none Change-Id: I398a508cbc8d02644b60e504405392254329ef10 --- src/libslic3r/GCode.cpp | 64 ++++++++++ src/libslic3r/GCode/WipeTower.cpp | 204 ++++++++++++++++++++++++++++-- src/libslic3r/GCode/WipeTower.hpp | 39 ++++-- src/libslic3r/Preset.cpp | 2 +- src/libslic3r/Print.cpp | 1 + src/libslic3r/PrintConfig.cpp | 8 ++ src/libslic3r/PrintConfig.hpp | 1 + src/slic3r/GUI/Plater.cpp | 2 +- src/slic3r/GUI/Tab.cpp | 2 + 9 files changed, 300 insertions(+), 23 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 0971efb57..fb9bcae24 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -288,6 +288,57 @@ static std::vector get_path_of_change_filament(const Print& print) : gcodegen.config().nozzle_temperature.get_at(gcodegen.writer().filament()->id()); } + std::string transform_gcode(const std::string &gcode, Vec2f pos, const Vec2f &translation, float angle) + { + Vec2f extruder_offset(0, 0); + std::istringstream gcode_str(gcode); + std::string gcode_out; + std::string line; + Vec2f transformed_pos = pos; + Vec2f old_pos(-1000.1f, -1000.1f); + + while (gcode_str) { + std::getline(gcode_str, line); // we read the gcode line by line + + if (line.find("G1 ") == 0) { + bool never_skip = false; + auto it = line.find(WipeTower::never_skip_tag()); + if (it != std::string::npos) { + // remove the tag and remember we saw it + never_skip = true; + line.erase(it, it + WipeTower::never_skip_tag().size()); + } + std::ostringstream line_out; + std::istringstream line_str(line); + line_str >> std::noskipws; // don't skip whitespace + char ch = 0; + while (line_str >> ch) { + if (ch == 'X' || ch == 'Y') + line_str >> (ch == 'X' ? pos.x() : pos.y()); + else + line_out << ch; + } + + transformed_pos = Eigen::Rotation2Df(angle) * pos + translation; + + if (transformed_pos != old_pos || never_skip) { + line = line_out.str(); + std::ostringstream oss; + oss << std::fixed << std::setprecision(3) << "G1 "; + if (transformed_pos.x() != old_pos.x() || never_skip) oss << " X" << transformed_pos.x() - extruder_offset.x(); + if (transformed_pos.y() != old_pos.y() || never_skip) oss << " Y" << transformed_pos.y() - extruder_offset.y(); + oss << " "; + line.replace(line.find("G1 "), 3, oss.str()); + old_pos = transformed_pos; + } + } + + gcode_out += line + "\n"; + } + return gcode_out; + } + + std::string Wipe::wipe(GCode& gcodegen, bool toolchange, bool is_last) { std::string gcode; @@ -441,6 +492,12 @@ static std::vector get_path_of_change_filament(const Print& print) check_add_eol(end_filament_gcode_str); } } + + std::string nozzle_change_gcode_trans; + if (!tcr.nozzle_change_result.gcode.empty()) { + nozzle_change_gcode_trans = transform_gcode(tcr.nozzle_change_result.gcode, tcr.start_pos, wipe_tower_offset, wipe_tower_rotation); + } + //BBS: increase toolchange count gcodegen.m_toolchange_count++; @@ -532,6 +589,13 @@ static std::vector get_path_of_change_filament(const Print& print) } } toolchange_gcode_str = gcodegen.placeholder_parser_process("change_filament_gcode", change_filament_gcode, new_filament_id, &config); + + std::string target_str = ";nozzle_change_gcode"; + size_t pos = toolchange_gcode_str.find(target_str); + if (pos != std::string::npos) { + toolchange_gcode_str.replace(pos, target_str.length(), nozzle_change_gcode_trans); + } + check_add_eol(toolchange_gcode_str); // retract before toolchange diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index 8099c844b..dab429bb9 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -586,6 +586,7 @@ WipeTower::ToolChangeResult WipeTower::construct_tcr(WipeTowerWriter& writer, result.extrusions = std::move(writer.extrusions()); result.wipe_path = std::move(writer.wipe_path()); result.is_finish_first = is_finish; + result.nozzle_change_result = m_nozzle_change_result; // BBS result.purge_volume = purge_volume; return result; @@ -614,7 +615,8 @@ WipeTower::WipeTower(const PrintConfig& config, int plate_idx, Vec3d plate_origi m_current_tool(initial_tool), //wipe_volumes(flush_matrix) m_wipe_volume(prime_volume), - m_enable_timelapse_print(config.timelapse_type.value == TimelapseType::tlSmooth) + m_enable_timelapse_print(config.timelapse_type.value == TimelapseType::tlSmooth), + m_nozzle_change_length(config.extruder_change_length.get_at(0)) { // Read absolute value of first layer speed, if given as percentage, // it is taken over following default. Speeds from config are not @@ -729,14 +731,49 @@ std::vector WipeTower::prime( return std::vector(); } +Vec2f WipeTower::get_next_pos(const WipeTower::box_coordinates &cleaning_box, float wipe_length) +{ + const float &xl = cleaning_box.ld.x(); + const float &xr = cleaning_box.rd.x(); + int line_count = wipe_length / (xr - xl); + + float dy = m_layer_info->extra_spacing * m_perimeter_width; + float y_offset = float(line_count) * dy; + const Vec2f pos_offset = Vec2f(0.f, m_depth_traversed); + + Vec2f res; + int index = m_cur_layer_id % 4; + switch (index % 4) { + case 0: + res = cleaning_box.ld + pos_offset; + break; + case 1: + res = cleaning_box.rd + pos_offset + Vec2f(0, y_offset); + break; + case 2: + res = cleaning_box.rd + pos_offset; + break; + case 3: + res = cleaning_box.ld + pos_offset + Vec2f(0, y_offset); + break; + default: break; + } + return res; +} + WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_perimeter, bool first_toolchange_to_nonsoluble) { + m_nozzle_change_result.gcode.clear(); + if (!m_filament_map.empty() && tool < m_filament_map.size() && m_filament_map[m_current_tool] != m_filament_map[tool]) { + m_nozzle_change_result = nozzle_change(m_current_tool, tool); + } + size_t old_tool = m_current_tool; float wipe_depth = 0.f; float wipe_length = 0.f; float purge_volume = 0.f; - + float nozzle_change_depth = 0.f; // Finds this toolchange info if (tool != (unsigned int)(-1)) { @@ -745,6 +782,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_per wipe_length = b.wipe_length; wipe_depth = b.required_depth; purge_volume = b.purge_volume; + nozzle_change_depth = b.nozzle_change_depth; break; } } @@ -775,7 +813,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_per writer.speed_override_backup(); writer.speed_override(100); - Vec2f initial_position = cleaning_box.ld + Vec2f(0.f, m_depth_traversed); + Vec2f initial_position = get_next_pos(cleaning_box, wipe_length); writer.set_initial_position(initial_position, m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation); // Increase the extruder driver current to allow fast ramming. @@ -792,9 +830,17 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_per toolchange_Load(writer, cleaning_box); // BBS //writer.travel(writer.x(), writer.y()-m_perimeter_width); // cooling and loading were done a bit down the road + + // ensure travel to initial_positoin + { + writer.travel(initial_position - Vec2f(0.5, 0.5)); + writer.travel(initial_position); + } + toolchange_Wipe(writer, cleaning_box, wipe_length); // Wipe the newly loaded filament until the end of the assigned wipe area. + if (extrude_perimeter) { - box_coordinates wt_box(Vec2f(0.f, (m_current_shape == SHAPE_REVERSED) ? m_layer_info->toolchanges_depth() - m_layer_info->depth : 0.f), - m_wipe_tower_width, m_layer_info->depth + m_perimeter_width); + box_coordinates wt_box(Vec2f(0.f, (m_current_shape == SHAPE_REVERSED) ? m_layer_info->toolchanges_depth() - m_layer_info->depth : 0.f), m_wipe_tower_width, + m_layer_info->depth + m_perimeter_width); // align the perimeter Vec2f pos = initial_position; @@ -829,7 +875,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_per } else toolchange_Unload(writer, cleaning_box, m_filpar[m_current_tool].material, m_filpar[m_current_tool].nozzle_temperature); - m_depth_traversed += wipe_depth; + m_depth_traversed += (wipe_depth - nozzle_change_depth); //BBS //if (m_set_extruder_trimpot) @@ -849,6 +895,114 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_per return construct_tcr(writer, false, old_tool, false, purge_volume); } +WipeTower::NozzleChangeResult WipeTower::nozzle_change(int old_filament_id, int new_filament_id) +{ + float wipe_depth = 0.f; + float wipe_length = 0.f; + float purge_volume = 0.f; + int nozzle_change_line_count = 0; + + // Finds this toolchange info + if (new_filament_id != (unsigned int) (-1)) { + for (const auto &b : m_layer_info->tool_changes) + if (b.new_tool == new_filament_id) { + wipe_length = b.wipe_length; + wipe_depth = b.required_depth; + purge_volume = b.purge_volume; + nozzle_change_line_count = (b.nozzle_change_depth + WT_EPSILON) / m_perimeter_width; + break; + } + } else { + // Otherwise we are going to Unload only. And m_layer_info would be invalid. + } + + float nozzle_change_speed = 60.0f * m_filpar[m_current_tool].max_e_speed / m_extrusion_flow; + + WipeTowerWriter writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar); + writer.set_extrusion_flow(m_extrusion_flow) + .set_z(m_z_pos) + .set_initial_tool(m_current_tool) + .set_extrusion_flow(m_extrusion_flow) + .set_y_shift(m_y_shift + (new_filament_id != (unsigned int) (-1) && (m_current_shape == SHAPE_REVERSED) ? m_layer_info->depth - m_layer_info->toolchanges_depth() : 0.f)) + .append("; Nozzle change start\n"); + + writer.speed_override_backup(); + writer.speed_override(100); + + box_coordinates cleaning_box(Vec2f(m_perimeter_width, m_perimeter_width), + m_wipe_tower_width - 2 * m_perimeter_width, + (new_filament_id != (unsigned int) (-1) ? wipe_depth + m_depth_traversed - m_perimeter_width : m_wipe_tower_depth - m_perimeter_width)); + + Vec2f initial_position = cleaning_box.ld + Vec2f(0.f, m_depth_traversed); + writer.travel(initial_position, 30000); + writer.append("G1 Z" + std::to_string(m_z_pos) + "\n"); + writer.append("G1 E2 F1800\n"); + writer.set_initial_position(initial_position, m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation); + + const float &xl = cleaning_box.ld.x(); + const float &xr = cleaning_box.rd.x(); + + float dy = m_layer_info->extra_spacing * m_perimeter_width; + + const float target_speed = 4800.f; + float wipe_speed = std::max(target_speed, nozzle_change_speed); + + float start_y = writer.y(); + + m_left_to_right = true; + + bool need_change_flow = false; + // now the wiping itself: + for (int i = 0; true; ++i) { + if (m_left_to_right) + writer.extrude(xr + 0.25f * m_perimeter_width, writer.y(), wipe_speed); + else + writer.extrude(xl - 0.25f * m_perimeter_width, writer.y(), wipe_speed); + + if (writer.y() - float(EPSILON) > cleaning_box.lu.y()) + break; // in case next line would not fit + + if (i == nozzle_change_line_count - 1) + break; + + // stepping to the next line: + writer.extrude(writer.x(), writer.y() + dy); + m_left_to_right = !m_left_to_right; + } + + writer.set_extrusion_flow(m_extrusion_flow); // Reset the extrusion flow. + + m_depth_traversed += (nozzle_change_line_count) * dy; + + auto float_to_string_with_precision = [](float value, int precision) { + std::ostringstream out; + out << std::fixed << std::setprecision(precision) << value; + return out.str(); + }; + + float wipe_distance = 2; + Vec2f wipe_pos = writer.pos(); + if (m_left_to_right) { + wipe_pos.x() -= wipe_distance; + } + else { + wipe_pos.x() += wipe_distance; + } + writer.append("; WIPE_START\n"); + writer.extrude_explicit(wipe_pos, -2); + writer.append("; WIPE_END\n"); + + std::string lift_gcode = "G2 Z" + float_to_string_with_precision(m_z_pos + 0.4, 3) + " I0.86 J0.86 P1 F10000\n"; + writer.append(lift_gcode); + + writer.append("; Nozzle change end\n"); + + NozzleChangeResult result; + result.start_pos = writer.start_pos_rotated(); + result.end_pos = writer.pos(); + result.gcode = std::move(writer.gcode()); + return result; +} // Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool. void WipeTower::toolchange_Unload( @@ -1094,7 +1248,8 @@ void WipeTower::toolchange_Wipe( } #endif - m_left_to_right = true; + m_left_to_right = ((m_cur_layer_id + 3) % 4 >= 2); + bool is_from_up = (m_cur_layer_id % 2 == 1); // BBS: do not need to move dy #if 0 @@ -1130,9 +1285,12 @@ void WipeTower::toolchange_Wipe( writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height) + std::to_string(m_layer_height) + "\n"); } - if (writer.y() - float(EPSILON) > cleaning_box.lu.y()) + if (!is_from_up && (writer.y() - float(EPSILON) > cleaning_box.lu.y())) break; // in case next line would not fit + if (is_from_up && (writer.y() + float(EPSILON) < cleaning_box.ld.y())) + break; + x_to_wipe -= (xr - xl); if (x_to_wipe < WT_EPSILON) { // BBS: Delete some unnecessary travel @@ -1140,7 +1298,11 @@ void WipeTower::toolchange_Wipe( break; } // stepping to the next line: - writer.extrude(writer.x(), writer.y() + dy); + if (is_from_up) + writer.extrude(writer.x(), writer.y() - dy); + else + writer.extrude(writer.x(), writer.y() + dy); + m_left_to_right = !m_left_to_right; } @@ -1208,7 +1370,6 @@ WipeTower::ToolChangeResult WipeTower::finish_layer(bool extrude_perimeter, bool bool first_layer = is_first_layer(); // BBS: speed up perimeter speed to 90mm/s for non-first layer float feedrate = first_layer ? std::min(m_first_layer_speed * 60.f, 5400.f) : std::min(60.0f * m_filpar[m_current_tool].max_e_speed / m_extrusion_flow, 5400.f); - writer.feedrate(feedrate); float fill_box_y = m_layer_info->toolchanges_depth() + m_perimeter_width; box_coordinates fill_box(Vec2f(m_perimeter_width, fill_box_y), m_wipe_tower_width - 2 * m_perimeter_width, m_layer_info->depth - fill_box_y); @@ -1319,7 +1480,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer(bool extrude_perimeter, bool box_coordinates box = wt_box; for (size_t i = 0; i < loops_num; ++i) { box.expand(spacing); - writer.rectangle(box); + writer.rectangle(box, feedrate); } if (first_layer) { @@ -1399,7 +1560,17 @@ void WipeTower::plan_toolchange(float z_par, float layer_height_par, unsigned in depth += std::ceil(length_to_extrude / width) * m_perimeter_width; //depth *= m_extra_spacing; - m_plan.back().tool_changes.push_back(WipeTowerInfo::ToolChange(old_tool, new_tool, depth, 0.f, 0.f, wipe_volume, length_to_extrude, purge_volume)); + float nozzle_change_depth = 0; + if (!m_filament_map.empty() && m_filament_map[old_tool] != m_filament_map[new_tool]) { + double e_flow = extrusion_flow(0.2); + double length = m_nozzle_change_length / e_flow; + int nozzle_change_line_count = length / (m_wipe_tower_width - m_perimeter_width) + 1; + nozzle_change_depth = nozzle_change_line_count * m_perimeter_width; + depth += nozzle_change_depth; + } + WipeTowerInfo::ToolChange tool_change = WipeTowerInfo::ToolChange(old_tool, new_tool, depth, 0.f, 0.f, wipe_volume, length_to_extrude, purge_volume); + tool_change.nozzle_change_depth = nozzle_change_depth; + m_plan.back().tool_changes.push_back(tool_change); #endif } @@ -1467,6 +1638,12 @@ void WipeTower::plan_tower() x_to_wipe_new = std::max(x_to_wipe_new, x_to_wipe); int line_count = std::ceil((x_to_wipe_new - WT_EPSILON) / line_len); + + { // nozzle change length + int nozzle_change_line_count = (toolchange.nozzle_change_depth + WT_EPSILON) / m_perimeter_width; + line_count += nozzle_change_line_count; + } + toolchange.required_depth = line_count * m_perimeter_width; toolchange.wipe_volume = x_to_wipe_new / x_to_wipe * toolchange.wipe_volume; toolchange.wipe_length = x_to_wipe_new; @@ -1490,7 +1667,7 @@ void WipeTower::plan_tower() float max_depth_for_all = 0; for (int layer_index = int(m_plan.size()) - 1; layer_index >= 0; --layer_index) { - float this_layer_depth = std::max(m_plan[layer_index].depth, m_plan[layer_index].toolchanges_depth()); + float this_layer_depth = std::max(m_plan[layer_index].depth, m_plan[layer_index].toolchanges_depth()); if (m_enable_timelapse_print && this_layer_depth < EPSILON) this_layer_depth = min_wipe_tower_depth; @@ -1615,6 +1792,7 @@ void WipeTower::generate(std::vector> & m_old_temperature = -1; // reset last temperature written in the gcode int index = 0; std::vector layer_result; + int index = 0; for (auto layer : m_plan) { m_cur_layer_id = index++; diff --git a/src/libslic3r/GCode/WipeTower.hpp b/src/libslic3r/GCode/WipeTower.hpp index f43479842..07ce844fe 100644 --- a/src/libslic3r/GCode/WipeTower.hpp +++ b/src/libslic3r/GCode/WipeTower.hpp @@ -17,7 +17,6 @@ class PrintConfig; enum GCodeFlavor : unsigned char; - class WipeTower { public: @@ -38,6 +37,16 @@ public: unsigned int tool; }; + struct NozzleChangeResult + { + std::string gcode; + + Vec2f start_pos; + Vec2f end_pos; + + std::vector wipe_path; + }; + struct ToolChangeResult { // Print heigh of this tool change. @@ -81,6 +90,8 @@ public: // executing the gcode finish_layer_tcr. bool is_finish_first = false; + NozzleChangeResult nozzle_change_result; + // Sum the total length of the extrusion. float total_extrusion_length_in_plane() { float e_length = 0.f; @@ -190,7 +201,7 @@ public: m_num_tool_changes = 0; } else ++ m_num_layer_changes; - + // Calculate extrusion flow from desired line width, nozzle diameter, filament diameter and layer_height: m_extrusion_flow = extrusion_flow(layer_height); @@ -209,7 +220,7 @@ public: // Returns gcode to prime the nozzles at the front edge of the print bed. std::vector prime( // print_z of the first layer. - float initial_layer_print_height, + float initial_layer_print_height, // Extruder indices, in the order to be primed. The last extruder will later print the wipe tower brim, print brim and the object. const std::vector &tools, // If true, the last priming are will be the same as the other priming areas, and the rest of the wipe will be performed inside the wipe tower. @@ -221,6 +232,8 @@ public: // BBS ToolChangeResult tool_change(size_t new_tool, bool extrude_perimeter = false, bool first_toolchange_to_nonsoluble = false); + NozzleChangeResult nozzle_change(int old_filament_id, int new_filament_id); + // Fill the unfilled space with a sparse infill. // Call this method only if layer_finished() is false. ToolChangeResult finish_layer(bool extruder_perimeter = true, bool extruder_fill = true); @@ -244,6 +257,8 @@ public: std::vector get_used_filament() const { return m_used_filament_length; } int get_number_of_toolchanges() const { return m_num_tool_changes; } + void set_filament_map(const std::vector &filament_map) { m_filament_map = filament_map; } + struct FilamentParameters { std::string material = "PLA"; bool is_soluble = false; @@ -300,7 +315,12 @@ private: float m_travel_speed = 0.f; float m_first_layer_speed = 0.f; size_t m_first_layer_idx = size_t(-1); - size_t m_cur_layer_id; + + double m_nozzle_change_length = 10; + size_t m_cur_layer_id; + NozzleChangeResult m_nozzle_change_result; + std::vector m_filament_map; + // G-code generator parameters. // BBS: remove useless config //float m_cooling_tube_retraction = 0.f; @@ -360,6 +380,8 @@ private: // Goes through m_plan and recalculates depths and width of the WT to make it exactly square - experimental void make_wipe_tower_square(); + Vec2f get_next_pos(const WipeTower::box_coordinates &cleaning_box, float wipe_length); + // Goes through m_plan, calculates border and finish_layer extrusions and subtracts them from last wipe void save_on_last_wipe(); @@ -377,6 +399,7 @@ private: float first_wipe_line; float wipe_volume; float wipe_length; + float nozzle_change_depth{0}; // BBS float purge_volume; ToolChange(size_t old, size_t newtool, float depth=0.f, float ramming_depth=0.f, float fwl=0.f, float wv=0.f, float wl = 0, float pv = 0) @@ -409,7 +432,7 @@ private: void toolchange_Unload( WipeTowerWriter &writer, - const box_coordinates &cleaning_box, + const box_coordinates &cleaning_box, const std::string& current_material, const int new_temperature); @@ -417,11 +440,11 @@ private: WipeTowerWriter &writer, const size_t new_tool, const std::string& new_material); - + void toolchange_Load( WipeTowerWriter &writer, const box_coordinates &cleaning_box); - + void toolchange_Wipe( WipeTowerWriter &writer, const box_coordinates &cleaning_box, @@ -433,4 +456,4 @@ private: } // namespace Slic3r -#endif // WipeTowerPrusaMM_hpp_ +#endif // WipeTowerPrusaMM_hpp_ diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index b2e928b02..ecc850929 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -952,7 +952,7 @@ static std::vector s_Preset_printer_options { // BBS "scan_first_layer", "machine_load_filament_time", "machine_unload_filament_time", "machine_pause_gcode", "template_custom_gcode", "nozzle_type","auxiliary_fan", "nozzle_volume","upward_compatible_machine", "z_hop_types","support_chamber_temp_control","support_air_filtration","printer_structure","thumbnail_size", - "best_object_pos","head_wrap_detect_zone","printer_notes", + "best_object_pos","extruder_change_length","head_wrap_detect_zone","printer_notes", "enable_long_retraction_when_cut","long_retractions_when_cut","retraction_distances_when_cut", //OrcaSlicer "host_type", "print_host", "printhost_apikey", diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index f81ef5c44..993f015bb 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -2456,6 +2456,7 @@ void Print::_make_wipe_tower() WipeTower wipe_tower(m_config, m_plate_index, m_origin, m_config.prime_volume, m_wipe_tower_data.tool_ordering.first_extruder(), m_wipe_tower_data.tool_ordering.empty() ? 0.f : m_wipe_tower_data.tool_ordering.back().print_z); + wipe_tower.set_filament_map(this->get_filament_maps()); // Set the extruder & material properties at the wipe tower object. for (size_t i = 0; i < number_of_extruders; ++ i) wipe_tower.set_extruder(i, m_config); diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 53861a144..aed1ed066 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -3087,6 +3087,14 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionStrings { "Direct Drive Normal" }); def->cli = ConfigOptionDef::nocli; + def = this->add("extruder_change_length", coFloats); + def->label = L("Extruder change length"); + def->tooltip = L("Extruder change length"); + def->sidetext = L("mm"); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloats{10}); + def = this->add("extruder_ams_count", coStrings); def->label = "Extruder ams count"; def->tooltip = "Ams counts of per extruder"; diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 61a069d09..620fdfb49 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1054,6 +1054,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( ((ConfigOptionBool, reduce_crossing_wall)) ((ConfigOptionFloatOrPercent, max_travel_detour_distance)) ((ConfigOptionPoints, printable_area)) + ((ConfigOptionFloats, extruder_change_length)) //BBS: add bed_exclude_area ((ConfigOptionPoints, bed_exclude_area)) ((ConfigOptionPoints, head_wrap_detect_zone)) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index dc6edb834..59bbe66ad 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3052,7 +3052,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) "brim_width", "wall_loops", "wall_filament", "sparse_infill_density", "sparse_infill_filament", "top_shell_layers", "enable_support", "support_filament", "support_interface_filament", "support_top_z_distance", "support_bottom_z_distance", "raft_layers", - "best_object_pos" + "best_object_pos", "extruder_change_length" })) , sidebar(new Sidebar(q)) , notification_manager(std::make_unique(q)) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 0d7d19bf5..79b80ea2c 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -3546,6 +3546,8 @@ void TabPrinter::build_fff() optgroup->append_single_option_line("printable_height"); optgroup->append_single_option_line("nozzle_volume"); optgroup->append_single_option_line("best_object_pos"); + // todo: for multi_extruder test + optgroup->append_single_option_line("extruder_change_length"); // BBS #if 0 //optgroup->append_single_option_line("z_offset");