diff --git a/xs/src/libslic3r/WipeTower.cpp b/xs/src/libslic3r/WipeTower.cpp index 5ff94496c..c8bfabdaf 100644 --- a/xs/src/libslic3r/WipeTower.cpp +++ b/xs/src/libslic3r/WipeTower.cpp @@ -15,137 +15,224 @@ namespace PrusaSingleExtruderMM { -static inline std::string line_XY(float x, float y) +class Writer { - char buf[128]; - sprintf(buf, "G1 X%.3f Y%.3f\n", x, y); - return buf; -} +public: + Writer() : + m_current_pos(std::numeric_limits::max(), std::numeric_limits::max()), + m_current_z(0.f), + m_current_feedrate(0.f), + m_extrusion_flow(0.f) {} -static inline std::string line_XYE(float x, float y, float e) -{ - char buf[128]; - sprintf(buf, "G1 X%.3f Y%.3f E%.4f\n", x, y, e); - return buf; -} + Writer& set_z(float z) + { m_current_z = z; return *this; } -static inline std::string line_XYF(float x, float y, float f) -{ - char buf[128]; - sprintf(buf, "G1 X%.3f Y%.3f F%.0f\n", x, y, f); - return buf; -} + Writer& set_extrusion_flow(float flow) + { m_extrusion_flow = flow; return *this; } -static inline std::string line_ZF(float z, float f) -{ - char buf[128]; - sprintf(buf, "G1 Z%.3f F%.0f\n", z, f); - return buf; -} - -static inline std::string line_F(float f) -{ - char buf[128]; - sprintf(buf, "G1 F%.0f\n", f); - return buf; -} - -static inline std::string line_XEF(float x, float e, float f) -{ - char buf[128]; - sprintf(buf, "G1 X%.3f E%.4f F%.0f\n", x, e, f); - return buf; -} - -static inline std::string line_EF(float e, float f) -{ - char buf[128]; - sprintf(buf, "G1 E%.4f F%.0f\n", e, f); - return buf; -} - -// Set extruder temperature, don't wait. -static inline std::string line_M104(int temperature) -{ - char buf[128]; - sprintf(buf, "M104 S%d\n", temperature); - return buf; -}; - -// Set extruder temperature and wait. -static inline std::string line_M109(int temperature) -{ - char buf[128]; - sprintf(buf, "M109 S%d\n", temperature); - buf; -}; - -// Set maximum feedrate -static inline std::string line_M203(int feedrate) -{ - char buf[128]; - sprintf(buf, "M203 E%d\n", feedrate); - return buf; -}; - -// Set speed factor override percentage -static inline std::string line_M220(int speed) -{ - char buf[128]; - sprintf(buf, "M220 S%d\n", speed); - return buf; -}; - -// Set digital trimpot motor -static inline std::string line_M907(int current) -{ - char buf[128]; - sprintf(buf, "M907 E%d\n", current); - return buf; -}; - -// Dwell for seconds. If delay == 0, this just flushes planner queue. -static inline std::string line_G4(int delay) -{ - char buf[128]; - sprintf(buf, "G4 S%d\n", delay); - return buf; -}; - -// Reset internal extruder counter. -static inline std::string line_ResetE() -{ - return "G92 E0.0\n"; -}; - -static inline std::string line_CommentValue(const char *comment, int value) -{ - char strvalue[15]; - sprintf(strvalue, "%d", value); - return std::string(";") + comment + strvalue + "\n"; -}; - -static inline std::string line_CommentMaterial(WipeTower::material_type material) -{ - std::string ret("; material : "); - - switch (material) + Writer& feedrate(float f) { - case WipeTower::PVA: - ret += "#8 (PVA)"; - break; - case WipeTower::SCAFF: - ret += "#5 (Scaffold)"; - break; - case WipeTower::FLEX: - ret += "#4 (Flex)"; - break; - default: - ret += "DEFAULT (PLA)"; - break; + if (f != m_current_feedrate) + m_gcode += "G1" + set_format_F(f) + "\n"; + return *this; + } + + const std::string& gcode() const { return m_gcode; } + float x() const { return m_current_pos.x; } + float y() const { return m_current_pos.y; } + const WipeTower::xy& pos() const { return m_current_pos; } + + Writer& extrude_explicit(float x, float y, float e, float f = 0.f) + { + if (x == m_current_pos.x && y == m_current_pos.y && e == 0.f && (f == 0.f || f == m_current_feedrate)) + return *this; + m_gcode += "G1 "; + if (x != m_current_pos.x) + m_gcode += set_format_X(x); + if (y != m_current_pos.y) + m_gcode += set_format_Y(y); + if (e != 0) + m_gcode += set_format_E(e); + if (f != 0 && f != m_current_feedrate) + m_gcode += set_format_F(f); + m_gcode += "\n"; + return *this; + } + + Writer& extrude_explicit(const WipeTower::xy &dest, float e, float f = 0.f) + { return extrude_explicit(dest.x, dest.y, e, f); } + + // Travel to a new XY position. f=0 means use the current value. + Writer& travel(float x, float y, float f = 0.f) + { return extrude_explicit(x, y, 0, f); } + + Writer& travel(const WipeTower::xy &dest, float f = 0.f) + { return extrude_explicit(dest.x, dest.y, 0.f, f); } + + Writer& extrude(float x, float y, float f = 0.f) { + float dx = x - m_current_pos.x; + float dy = y - m_current_pos.y; + return extrude_explicit(x, y, sqrt(dx*dx+dy*dy) * m_extrusion_flow, f); + } + + Writer& extrude(const WipeTower::xy &dest, const float f = 0.f) + { return extrude(dest.x, dest.y, f); } + + Writer& deretract(float e, float f = 0.f) + { + if (e == 0 && (f == 0 || f == m_current_feedrate)) + return *this; + m_gcode += "G1 "; + if (e != 0) + m_gcode += set_format_E(e); + if (f != 0 && f != m_current_feedrate) + m_gcode += set_format_F(f); + m_gcode += "\n"; + return *this; + } + + Writer& deretract_move_x(float x, float e, float f = 0.f) + { return extrude_explicit(x, m_current_pos.y, e, f); } + + Writer& retract(float e, float f = 0.f) + { return retract(-e, f); } + + Writer& z_hop(float hop, float f = 0.f) { + m_gcode += std::string("G1") + set_format_Z(m_current_z + hop); + if (f != 0 && f != m_current_feedrate) + m_gcode += set_format_F(f); + m_gcode += "\n"; + return *this; + } + + // Move to x1, +y_increment, + // extrude quickly amount e to x2 with feed f. + Writer& ram(float x1, float x2, float dy, float e, float f) { + return travel(x1, m_current_pos.y + dy, f) + .extrude_explicit(x2, m_current_pos.y, e); + } + + Writer& cool(float x1, float x2, float e1, float e2, float f) { + return extrude_explicit(x1, m_current_pos.y, e1, f) + .extrude_explicit(x2, m_current_pos.y, e2); + } + + Writer& set_tool(int tool) + { + char buf[64]; + sprintf(buf, "T%d\n", tool); + m_gcode += buf; + return *this; + } + + // Set extruder temperature, don't wait. + Writer& set_extruder_temp(int temperature, bool wait = false) + { + char buf[128]; + sprintf(buf, "M%d S%d\n", wait ? 109 : 104, temperature); + m_gcode += buf; + return *this; + }; + + // Set speed factor override percentage + Writer& speed_override(int speed) { + char buf[128]; + sprintf(buf, "M220 S%d\n", speed); + m_gcode += buf; + return *this; + }; + + // Set digital trimpot motor + Writer& set_extruder_trimpot(int current) + { + char buf[128]; + sprintf(buf, "M907 E%d\n", current); + m_gcode += buf; + return *this; + }; + + Writer& flush_planner_queue() { + m_gcode += "G4 S0\n"; + return *this; + } + + // Reset internal extruder counter. + Writer& reset_extruder() { + m_gcode += "G92 E0.0\n"; + return *this; + } + + Writer& comment_with_value(const char *comment, int value) + { + char strvalue[15]; + sprintf(strvalue, "%d", value); + m_gcode += std::string(";") + comment + strvalue + "\n"; + return *this; + }; + + Writer& comment_material(WipeTower::material_type material) + { + m_gcode += "; material : "; + switch (material) + { + case WipeTower::PVA: + m_gcode += "#8 (PVA)"; + break; + case WipeTower::SCAFF: + m_gcode += "#5 (Scaffold)"; + break; + case WipeTower::FLEX: + m_gcode += "#4 (Flex)"; + break; + default: + m_gcode += "DEFAULT (PLA)"; + break; + } + m_gcode += "\n"; + return *this; + }; + + Writer& append(const char *text) { m_gcode += text; return *this; } + +private: + WipeTower::xy m_current_pos; + float m_current_z; + float m_current_feedrate; + float m_extrusion_flow; + std::string m_gcode; + + std::string set_format_X(float x) { + char buf[64]; + sprintf(buf, " X%.3f", x); + m_current_pos.x = x; + return buf; + } + + std::string set_format_Y(float y) { + char buf[64]; + sprintf(buf, " Y%.3f", y); + m_current_pos.y = y; + return buf; + } + + std::string set_format_Z(float y) { + char buf[64]; + sprintf(buf, " Z%.3f", y); + return buf; + } + + std::string set_format_E(float e) { + char buf[64]; + sprintf(buf, " E%.4f", e); + return buf; + } + + std::string set_format_F(float f) { + char buf[64]; + sprintf(buf, " F%.0f", f); + m_current_feedrate = f; + return buf; } - - return ret + "\n"; }; static inline int randi(int lo, int hi) @@ -179,630 +266,382 @@ WipeTower::material_type WipeTower::parse_material(const char *name) return INVALID; } -std::string WipeTower::FirstLayer(bool sideOnly, float offset) +std::string WipeTower::FirstLayer(bool sideOnly, float y_offset) { - float _ext = extrusion_flow + ((extrusion_flow / 100) * 10); - - box_coordinates wipeTower_box(m_wipe_tower_pos, m_wipe_tower_width, m_wipe_area * float(m_color_changes) - perimeterWidth / 2); - - std::string gcode = + const box_coordinates wipeTower_box( + m_wipe_tower_pos, + m_wipe_tower_width, + m_wipe_area * float(m_color_changes) - perimeterWidth / 2); + + Writer writer; + writer.set_extrusion_flow(extrusion_flow * 1.1f) + // Let the writer know the current Z position as a base for Z-hop. + .set_z(m_z_pos) + .append( ";-------------------------------------\n" - "; CP WIPE TOWER FIRST LAYER BRIM START\n"; - - gcode += line_ZF(m_z_pos + zHop, 7200); - - gcode += line_F(6000); - gcode += line_XY( wipeTower_box.lu.x - (perimeterWidth * 10), wipeTower_box.lu.y ); - gcode += line_ZF(m_z_pos, 7200); - - gcode += line_F(2400); - gcode += line_XYE(wipeTower_box.ld.x - (perimeterWidth * 10), wipeTower_box.ld.y, retract); - - float _offset = 0; - gcode += line_F(2100); - int _per = 0; - - if (sideOnly) - { - do - { - _offset = _offset + perimeterWidth; - gcode += line_XY(wipeTower_box.ld.x - _offset, wipeTower_box.ld.y + offset); - gcode += line_XYE(wipeTower_box.lu.x - _offset, wipeTower_box.lu.y - offset, (wipeTower_box.lu.y - wipeTower_box.ld.y) * _ext); - _per++; - } while (_per < 4); - gcode += line_F(7000); - gcode += line_XY(wipeTower_box.rd.x + _offset, wipeTower_box.ld.y + offset); - gcode += line_F(2100); - _per = 0; - _offset = 0; - do - { - _offset = _offset + perimeterWidth; - gcode += line_XY(wipeTower_box.rd.x + _offset, wipeTower_box.ld.y + offset); - gcode += line_XYE(wipeTower_box.ru.x + _offset, wipeTower_box.lu.y - offset, (wipeTower_box.lu.y - wipeTower_box.ld.y) * _ext); - _per++; - } while (_per < 4); - - } - else - { - do - { - _offset = _offset + perimeterWidth; - float _ext_X = ((wipeTower_box.rd.x + _offset) - (wipeTower_box.ld.x - _offset))* _ext; - float _ext_Y = ((wipeTower_box.lu.y + _offset) - (wipeTower_box.ld.y - _offset))* _ext; - - float __x0 = wipeTower_box.ld.x - _offset + (perimeterWidth / 2); - float __y0 = wipeTower_box.ld.y - _offset + perimeterWidth; - gcode += line_XY(__x0, __y0); - - float __x1 = wipeTower_box.lu.x - _offset + (perimeterWidth / 2); - float __y1 = wipeTower_box.lu.y + _offset; - gcode += line_XYE(__x1, __y1, _ext_Y); - - float __x2 = wipeTower_box.ru.x + _offset - (perimeterWidth / 2); - float __y2 = wipeTower_box.ru.y + _offset; - gcode += line_XYE(__x2, __y2, _ext_X); - - float __x3 = wipeTower_box.rd.x + _offset - (perimeterWidth / 2); - float __y3 = wipeTower_box.rd.y - _offset + perimeterWidth; - gcode += line_XYE(__x3, __y3, _ext_Y); - - float __x4 = wipeTower_box.ld.x - _offset + (perimeterWidth / 2); - float __y4 = wipeTower_box.ld.y - _offset + perimeterWidth; - gcode += line_XYE(__x4, __y4, _ext_X); - _per++; - - } while (_per < 4); + "; CP WIPE TOWER FIRST LAYER BRIM START\n"); + // Move with Z hop and prime the extruder 10*perimeterWidth left along the vertical edge of the wipe tower. + writer.z_hop(zHop, 7200) + .travel(wipeTower_box.lu - xy(perimeterWidth * 10.f, 0), 6000) + .z_hop(0, 7200) + .extrude_explicit(wipeTower_box.ld - xy(perimeterWidth * 10.f, 0), retract, 2400) + .feedrate(2100); + if (sideOnly) { + float x_offset = 0.f; + for (size_t i = 0; i < 4; ++ i, x_offset += perimeterWidth) + writer.travel (wipeTower_box.ld + xy(- x_offset, y_offset)) + .extrude(wipeTower_box.lu + xy(- x_offset, - y_offset)); + writer.travel(wipeTower_box.rd + xy(x_offset, y_offset), 7000) + .feedrate(2100); + x_offset = 0.f; + for (size_t i = 0; i < 4; ++ i, x_offset += perimeterWidth) + writer.travel (wipeTower_box.rd + xy(x_offset, y_offset)) + .extrude(wipeTower_box.ru + xy(x_offset, - y_offset)); + } else { + // Extrude 4 rounds of a brim around the future wipe tower. + box_coordinates box(wipeTower_box); + box.ld += xy(- perimeterWidth / 2, 0); + box.lu += xy(- perimeterWidth / 2, perimeterWidth); + box.rd += xy( perimeterWidth / 2, 0); + box.ru += xy( perimeterWidth / 2, perimeterWidth); + for (size_t i = 0; i < 4; ++ i) { + writer.travel(box.ld) + .extrude(box.lu) .extrude(box.ru) + .extrude(box.rd) .extrude(box.ld); + box.expand(perimeterWidth); + } } - gcode += line_F(7000); - gcode += line_XY(wipeTower_box.ld.x, wipeTower_box.ld.y); - gcode += line_XY(wipeTower_box.rd.x, wipeTower_box.ld.y); - gcode += line_XY(wipeTower_box.ld.x, wipeTower_box.ld.y); + // Move to the front left corner and wipe along the front edge. + writer.travel(wipeTower_box.ld, 7000) + .travel(wipeTower_box.rd) + .travel(wipeTower_box.ld) + .append("; CP WIPE TOWER FIRST LAYER BRIM END\n" + ";-----------------------------------\n"); - gcode += "; CP WIPE TOWER FIRST LAYER BRIM END\n"; - gcode += ";-----------------------------------\n"; - return gcode; + return writer.gcode(); } -std::pair WipeTower::Toolchange(int tool, material_type current_material, material_type new_material, int temperature, wipe_shape shape, int count, float spaceAvailable, float wipeStartY, bool lastInFile, bool colorInit) +std::pair WipeTower::Toolchange( + const int tool, + const material_type current_material, + const material_type new_material, + const int temperature, + const wipe_shape shape, + const int count, + const float spaceAvailable, + const float wipeStartY, + const bool lastInFile, + const bool colorInit) { box_coordinates cleaning_box( m_wipe_tower_pos.x, - m_wipe_tower_pos.y + wipeStartY, //(order * _wipe_area); //wipeStartY; + m_wipe_tower_pos.y + wipeStartY, m_wipe_tower_width, - spaceAvailable - perimeterWidth / 2); //space_available //wipe_area + spaceAvailable - perimeterWidth / 2); - std::string gcode; - gcode += ";--------------------\n"; - gcode += "; CP TOOLCHANGE START\n"; - gcode += line_CommentValue(" toolchange #", count); - gcode += line_CommentMaterial(current_material); - gcode += ";--------------------\n"; + Writer writer; + writer.set_extrusion_flow(extrusion_flow) + .set_z(m_z_pos) + .append(";--------------------\n" + "; CP TOOLCHANGE START\n") + .comment_with_value(" toolchange #", count) + .comment_material(current_material) + .append(";--------------------\n") + .speed_override(100) + // Lift for a Z hop. + .z_hop(zHop, 7200) + // additional retract on move to tower + .retract(retract/2, 3600) + .travel(((shape == SHAPE_NORMAL) ? cleaning_box.ld : cleaning_box.rd) + xy(perimeterWidth, shape * perimeterWidth), 7200) + // Unlift for a Z hop. + .z_hop(0, 7200) + // Additional retract on move to tower. + .deretract(retract/2, 3600) + .deretract(retract, 1500) + // Increase extruder current for ramming. + .set_extruder_trimpot(750) + .flush_planner_queue(); - gcode += line_M220(100); - gcode += line_ZF(m_z_pos + zHop, 7200); + // Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool. + toolchange_Unload(writer, cleaning_box, current_material, shape, temperature); - gcode += line_EF((retract/2)*-1, 3600); // additional retract on move to tower - gcode += line_XYF(cleaning_box.ld.x + perimeterWidth, cleaning_box.ld.y + shape * perimeterWidth, 7200); - gcode += line_ZF(m_z_pos, 7200); - gcode += line_EF((retract / 2), 3600); // additional retract on move to tower - gcode += line_EF((retract), 1500); - - m_y_position = (shape == NORMAL) ? cleaning_box.ld.y : cleaning_box.lu.y; - - gcode += line_M907(750); - gcode += line_G4(0); - - gcode += toolchange_Unload(cleaning_box, current_material, shape, temperature); - - if (!lastInFile) - { - gcode += toolchange_Change(tool, current_material, new_material); - gcode += toolchange_Load(cleaning_box, current_material, shape, colorInit); - gcode += toolchange_Wipe(cleaning_box, current_material, shape); - gcode += toolchange_Done(cleaning_box, current_material, shape); + if (! lastInFile) { + // Change the tool, set a speed override for solube and flex materials. + toolchange_Change(writer, tool, current_material, new_material); + toolchange_Load(writer, cleaning_box, current_material, shape, colorInit); + // Wipe the newly loaded filament until the end of the assigned wipe area. + toolchange_Wipe(writer, cleaning_box, current_material, shape); + // Draw a perimeter around cleaning_box and wipe. + toolchange_Done(writer, cleaning_box, current_material, shape); } - gcode += line_M907(550); - gcode += line_G4(0); - gcode += line_ResetE(); - - gcode += "; CP TOOLCHANGE END\n" - ";------------------\n" - "\n\n"; - return std::pair(gcode, (shape == NORMAL) ? cleaning_box.lu : cleaning_box.ld); + // Reset the extruder current to a normal value. + writer.set_extruder_trimpot(550) + .flush_planner_queue() + .reset_extruder() + .append("; CP TOOLCHANGE END\n" + ";------------------\n" + "\n\n"); + + return std::pair(writer.gcode(), writer.pos()); } -std::string WipeTower::toolchange_Unload(const box_coordinates &cleaning_box, material_type material, wipe_shape shape, int temperature) +// Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool. +void WipeTower::toolchange_Unload( + Writer &writer, + const box_coordinates &cleaning_box, + const material_type material, + const wipe_shape shape, + const int temperature) { - float __xl = 0; - float __xr = 0; - __xl = cleaning_box.ld.x + (perimeterWidth / 2); - __xr = cleaning_box.rd.x - (perimeterWidth / 2); + float xl = cleaning_box.ld.x + (perimeterWidth / 2); + float xr = cleaning_box.rd.x - (perimeterWidth / 2); + float y_step = shape * perimeterWidth; - std::string gcode = "; CP TOOLCHANGE UNLOAD"; + writer.append("; CP TOOLCHANGE UNLOAD"); + // Ram the hot material out of the extruder melt zone. switch (material) { case PVA: - - gcode += line_F(4000); - m_y_position += shape * perimeterWidth * 1.2f; - gcode += line_XYE(__xl + (perimeterWidth * 2), m_y_position, 0); - gcode += line_XYE(__xr - perimeterWidth, m_y_position, 3); - - gcode += line_F(4500); - m_y_position += shape * perimeterWidth * 1.5f; - gcode += line_XYE(__xr - perimeterWidth, m_y_position, 0); - gcode += line_XYE(__xl + perimeterWidth, m_y_position, 3); - - gcode += line_F(4800); - m_y_position += shape * perimeterWidth * 1.5f; - gcode += line_XYE(__xl + (perimeterWidth * 2), m_y_position, 0); - gcode += line_XYE(__xr - (perimeterWidth * 2), m_y_position, 3); - - gcode += line_F(5000); - m_y_position += shape * perimeterWidth * 1.5f; - gcode += line_XYE(__xr - perimeterWidth, m_y_position, 0); - gcode += line_XYE(__xl + perimeterWidth, m_y_position, 3); - - gcode += line_EF(-15, 5000); - gcode += line_EF(-50, 5400); - gcode += line_EF(-15, 3000); - gcode += line_EF(-12, 2000); - - - if (temperature != 0) - { - gcode += line_M104(temperature); - } - - // cooling moves - m_y_position += shape * perimeterWidth * 0.8f; - - gcode += line_F(1600); - gcode += line_XYE(__xl, m_y_position, 3); - gcode += line_XYE(__xr, m_y_position, -5); - - gcode += line_F(2000); - gcode += line_XYE(__xl, m_y_position, 5); - gcode += line_XYE(__xr, m_y_position, -5); - - gcode += line_F(2200); - gcode += line_XYE(__xl, m_y_position, 5); - gcode += line_XYE(__xr, m_y_position, -5); - - gcode += line_F(2400); - gcode += line_XYE(__xl, m_y_position, 5); - gcode += line_XYE(__xr, m_y_position, -5); - - gcode += line_F(2400); - gcode += line_XYE(__xl, m_y_position, 5); - gcode += line_XYE(__xr, m_y_position, -5); - - gcode += line_F(2400); - gcode += line_XYE(__xl, m_y_position, 5); - gcode += line_XYE(__xr, m_y_position, -3); - - gcode += line_G4(0); - - break; // end of SCAFF - - + // ramming start end y increment amount feedrate + writer.ram(xl + perimeterWidth * 2, xr - perimeterWidth, y_step * 1.2f, 3, 4000) + .ram(xr - perimeterWidth, xl + perimeterWidth, y_step * 1.5f, 3, 4500) + .ram(xl + perimeterWidth * 2, xr - perimeterWidth * 2, y_step * 1.5f, 3, 4800) + .ram(xr - perimeterWidth, xl + perimeterWidth, y_step * 1.5f, 3, 5000); + break; case SCAFF: - - gcode += line_F(4000); - m_y_position += shape * perimeterWidth * 3.f; - gcode += line_XYE(__xl + (perimeterWidth * 2), m_y_position, 0); - gcode += line_XYE(__xr - perimeterWidth, m_y_position, 3); - - gcode += line_F(4600); - m_y_position += shape * perimeterWidth * 3.f; - gcode += line_XYE(__xr - perimeterWidth, m_y_position, 0); - gcode += line_XYE(__xl + perimeterWidth, m_y_position, 4); - - gcode += line_F(5200); - m_y_position += shape * perimeterWidth * 3.f; - gcode += line_XYE(__xl + (perimeterWidth * 2), m_y_position, 0); - gcode += line_XYE(__xr - (perimeterWidth * 2), m_y_position, 4.5); - - gcode += line_EF(-15, 5000); - gcode += line_EF(-50, 5400); - gcode += line_EF(-15, 3000); - gcode += line_EF(-12, 2000); - - - if (temperature != 0) - { - gcode += line_M104(temperature); - } - - // cooling moves - m_y_position += shape * perimeterWidth * 0.8f; - - gcode += line_F(1600); - gcode += line_XYE(__xl, m_y_position, 3); - gcode += line_XYE(__xr, m_y_position, -5); - - gcode += line_F(2000); - gcode += line_XYE(__xl, m_y_position, 5); - gcode += line_XYE(__xr, m_y_position, -5); - - gcode += line_F(2200); - gcode += line_XYE(__xl, m_y_position, 5); - gcode += line_XYE(__xr, m_y_position, -5); - - gcode += line_F(2200); - gcode += line_XYE(__xl, m_y_position, 5); - gcode += line_XYE(__xr, m_y_position, -5); - - gcode += line_F(2400); - gcode += line_XYE(__xl, m_y_position, 5); - gcode += line_XYE(__xr, m_y_position, -3); - - gcode += line_G4(0); - - break; // end of SCAFF - - + writer.ram(xl + perimeterWidth * 2, xr - perimeterWidth, y_step * 3.f, 3, 4000) + .ram(xr - perimeterWidth, xl + perimeterWidth, y_step * 3.f, 4, 4600) + .ram(xl + perimeterWidth * 2, xr - perimeterWidth * 2, y_step * 3.f, 4.5, 5200); + break; default: - - gcode += line_F(4000); - m_y_position += shape * perimeterWidth * 1.2f; - gcode += line_XYE(__xl + (perimeterWidth * 2), m_y_position, 0); - gcode += line_XYE(__xr - perimeterWidth, m_y_position, (__xr - __xl) * (extrusion_flow*(float)1.6)); - - gcode += line_F(4600); - m_y_position += shape * perimeterWidth * 1.2f; - gcode += line_XYE(__xr - perimeterWidth, m_y_position, perimeterWidth*extrusion_flow); - gcode += line_XYE(__xl + perimeterWidth, m_y_position, (__xr - __xl) * (extrusion_flow*(float)1.65)); - - gcode += line_F(5200); - m_y_position += shape * perimeterWidth * 1.2f; //1.4f - gcode += line_XYE(__xl + (perimeterWidth * 2), m_y_position, perimeterWidth*extrusion_flow); - gcode += line_XYE(__xr - (perimeterWidth * 2), m_y_position, (__xr - __xl) * (extrusion_flow*(float)1.74)); - - gcode += line_EF(-15, 5000); - gcode += line_EF(-50, 5400); - gcode += line_EF(-15, 3000); - gcode += line_EF(-12, 2000); - - - if (temperature != 0) - { - gcode += line_M104(temperature); - } - - // cooling moves - m_y_position += shape * perimeterWidth * 0.8f; - - gcode += line_F(1600); - gcode += line_XYE(__xl, m_y_position, 3); - gcode += line_XYE(__xr, m_y_position, -5); - - gcode += line_F(2000); - gcode += line_XYE(__xl, m_y_position, 5); - gcode += line_XYE(__xr, m_y_position, -5); - - gcode += line_F(2400); - gcode += line_XYE(__xl, m_y_position, 5); - gcode += line_XYE(__xr, m_y_position, -5); - - gcode += line_F(2400); - gcode += line_XYE(__xl, m_y_position, 5); - gcode += line_XYE(__xr, m_y_position, -3); - - gcode += line_G4(0); - - break; // end of default material + writer.ram(xl + perimeterWidth * 2, xr - perimeterWidth, y_step * 1.2f, 1.6f, 4000) + .ram(xr - perimeterWidth, xl + perimeterWidth, y_step * 1.2f, 1.65f, 4600) + .ram(xl + perimeterWidth * 2, xr - perimeterWidth * 2, y_step * 1.2f, 1.74f, 5200); } - return gcode; -} + // Pull the filament end into a cooling tube. + writer.retract(15, 5000).retract(50, 5400).retract(15, 3000).deretract(12, 2000); -std::string WipeTower::toolchange_Load(const box_coordinates &cleaning_box, material_type material, wipe_shape shape, bool colorInit) -{ - float __xl = 0; - float __xr = 0; - - std::string gcode = "; CP TOOLCHANGE LOAD\n"; + if (temperature != 0) + // Set the extruder temperature, but don't wait. + writer.set_extruder_temp(temperature, false); + // Horizontal cooling moves at the following y coordinate: + writer.travel(writer.x(), writer.y() + y_step * 0.8f, 1600); switch (material) { - default: - - __xl = cleaning_box.ld.x + (perimeterWidth * 1); - __xr = cleaning_box.rd.x - (perimeterWidth * 1); - float _extrusion = (__xr - __xl) * extrusion_flow; - - gcode += line_XEF(__xr, 20, 1400); - gcode += line_XEF(__xl, 40, 3000); - gcode += line_XEF(__xr, 20, 1600); - gcode += line_XEF(__xl, 10, 1000); - - gcode += line_F(1600); - gcode += line_XYE(__xr, m_y_position, _extrusion); - - gcode += line_F(2200); - - int _pass = 2; - if (colorInit) _pass = 1; - - for (int _i = 0; _i < _pass; _i++) - { - m_y_position += shape * perimeterWidth * 0.85f; - gcode += line_XY(__xr, m_y_position); - gcode += line_XYE(__xl, m_y_position, _extrusion); - - m_y_position += shape * perimeterWidth * 0.85f; - gcode += line_XY(__xl, m_y_position); - gcode += line_XYE(__xr, m_y_position, _extrusion); - } - - break; - } - - gcode += line_M907(550); - return gcode; -} - -std::string WipeTower::toolchange_Wipe(const box_coordinates &cleaning_box, material_type material, wipe_shape shape) -{ - // wipe new filament until end of wipe area - float __xl = 0; - float __xr = 0; - int __p = 0; - float _wipespeed = 4200; - float _extr = extrusion_flow; - float _wipekoef = 1; - - std::string gcode = "; CP TOOLCHANGE WIPE\n"; - - // increase flow on first layer, slow down print - if (int(m_z_pos * 100) < 21) - { - _extr = extrusion_flow + ((extrusion_flow / 100) * 18); - _wipekoef = (float)0.5; - } - else - { - _extr = extrusion_flow; - _wipekoef = (float)1; - } - - switch (material) - { - - default: - - __xl = cleaning_box.ld.x + (perimeterWidth*2); - __xr = cleaning_box.rd.x - (perimeterWidth*2); - - switch (shape) - { - case NORMAL: - do - { - __p++; - _wipespeed = _wipespeed + 50; - if (_wipespeed > 4800) { _wipespeed = 4800; } - gcode += line_F(_wipespeed * _wipekoef); - m_y_position += shape * perimeterWidth * 0.7f; - if (__p < 2) - { - gcode += line_XYE(__xl - (perimeterWidth/2), m_y_position, perimeterWidth * _extr); - gcode += line_XYE(__xr + (perimeterWidth), m_y_position, (__xr - __xl) * _extr); - } - else - { - gcode += line_XYE(__xl-(perimeterWidth), m_y_position, perimeterWidth * _extr); - gcode += line_XYE(__xr+(perimeterWidth*2), m_y_position, (__xr - __xl) * _extr); - __p = 0; - } - _wipespeed = _wipespeed + 50; - if (_wipespeed > 4800) { _wipespeed = 4800; } - gcode += line_F(_wipespeed * _wipekoef); - m_y_position += shape * perimeterWidth * 0.7f; - gcode += line_XYE(__xr + (perimeterWidth), m_y_position, perimeterWidth * _extr); - gcode += line_XYE(__xl - (perimeterWidth), m_y_position, (__xr - __xl) * _extr); - - } while (m_y_position <= cleaning_box.lu.y - (perimeterWidth*1)); - break; - - case REVERSED: - do - { - __p++; - _wipespeed = _wipespeed + 50; - if (_wipespeed > 4900) { _wipespeed = 4900; } - gcode += line_F(_wipespeed * _wipekoef); - m_y_position += shape * perimeterWidth * 0.7f; - if (__p < 2) - { - gcode += line_XYE(__xl - (perimeterWidth/2), m_y_position, perimeterWidth * _extr); - gcode += line_XYE(__xr + (perimeterWidth), m_y_position, (__xr - __xl) * _extr); - } - else - { - gcode += line_XYE(__xl - (perimeterWidth), m_y_position, perimeterWidth * _extr); - gcode += line_XYE(__xr + (perimeterWidth *2), m_y_position, (__xr - __xl) * _extr); - __p = 0; - - } - _wipespeed = _wipespeed + 50; - if (_wipespeed > 4900) { _wipespeed = 4900; } - gcode += line_F(_wipespeed * _wipekoef); - m_y_position += shape * perimeterWidth * 0.7f; - gcode += line_XYE(__xr + (perimeterWidth), m_y_position, perimeterWidth * _extr); - gcode += line_XYE(__xl - (perimeterWidth), m_y_position, (__xr - __xl) * _extr); - - } while (m_y_position >= cleaning_box.ld.y + (perimeterWidth*1 )); - break; - } - - break; - } - - return gcode; -} - -std::string WipeTower::toolchange_Done(const box_coordinates &cleaning_box, material_type /* material */, wipe_shape shape) -{ - std::string gcode; - - switch (shape) - { - case NORMAL: - gcode += line_F(7000); - gcode += line_XY(cleaning_box.lu.x, cleaning_box.lu.y); - gcode += line_F(3200); - gcode += line_XYE(cleaning_box.ld.x, cleaning_box.ld.y, (cleaning_box.lu.y - cleaning_box.ld.y)*(extrusion_flow )); - gcode += line_XYE(cleaning_box.rd.x, cleaning_box.rd.y, (cleaning_box.rd.x - cleaning_box.ld.x)*(extrusion_flow )); - gcode += line_XYE(cleaning_box.ru.x, cleaning_box.lu.y, (cleaning_box.lu.y - cleaning_box.ld.y)*(extrusion_flow )); - gcode += line_XYE(cleaning_box.lu.x, cleaning_box.lu.y, (cleaning_box.rd.x - cleaning_box.ld.x)*(extrusion_flow )); - - gcode += line_F(7200); - gcode += line_XY(cleaning_box.ru.x, cleaning_box.lu.y); - gcode += line_XY(cleaning_box.lu.x, cleaning_box.lu.y); - - - gcode += line_F(6000); - break; - - case REVERSED: - gcode += line_F(7000); - gcode += line_XY(cleaning_box.ld.x , cleaning_box.ld.y ); - gcode += line_F(3200); - gcode += line_XYE(cleaning_box.rd.x , cleaning_box.rd.y, (cleaning_box.rd.x - cleaning_box.ld.x)*(extrusion_flow )); - gcode += line_XYE(cleaning_box.ru.x , cleaning_box.ru.y, (cleaning_box.ru.y - cleaning_box.rd.y)*(extrusion_flow )); - gcode += line_XYE(cleaning_box.lu.x , cleaning_box.lu.y, (cleaning_box.ru.x - cleaning_box.lu.x)*(extrusion_flow )); - gcode += line_XYE(cleaning_box.ld.x, cleaning_box.ld.y, (cleaning_box.lu.y - cleaning_box.ld.y)*(extrusion_flow )); - - gcode += line_F(7200); - gcode += line_XY(cleaning_box.rd.x, cleaning_box.ld.y); - gcode += line_XY(cleaning_box.ld.x, cleaning_box.ld.y); - - gcode += line_F(6000); - break; - } - - return gcode; -} - -std::string WipeTower::toolchange_Change(int tool, material_type /* current_material */, material_type new_material) -{ - assert(tool >= 0 && tool < 4); - std::string gcode("T0\n"); - gcode[1] += char(tool); - - switch (new_material) - { case PVA: - gcode += line_M220(80); - gcode += line_G4(0); + writer.cool(xl, xr, 3, -5, 1600) + .cool(xl, xr, 5, -5, 2000) + .cool(xl, xr, 5, -5, 2200) + .cool(xl, xr, 5, -5, 2400) + .cool(xl, xr, 5, -5, 2400) + .cool(xl, xr, 5, -5, 2400); break; case SCAFF: - gcode += line_M220(35); - gcode += line_G4(0); - break; - case FLEX: - gcode += line_M220(35); - gcode += line_G4(0); + writer.cool(xl, xr, 3, -5, 1600) + .cool(xl, xr, 5, -5, 2000) + .cool(xl, xr, 5, -5, 2200) + .cool(xl, xr, 5, -5, 2200) + .cool(xl, xr, 5, -5, 2400); break; default: - gcode += line_M220(100); - gcode += line_G4(0); - break; + writer.cool(xl, xr, 3, -5, 1600) + .cool(xl, xr, 5, -5, 2000) + .cool(xl, xr, 5, -5, 2400) + .cool(xl, xr, 5, -3, 2400); } - return gcode; + writer.flush_planner_queue(); +} + +// Change the tool, set a speed override for solube and flex materials. +void WipeTower::toolchange_Change( + Writer &writer, + const int tool, + material_type /* current_material */, + material_type new_material) +{ + // Speed override for the material. Go slow for flex and soluble materials. + int speed_override; + switch (new_material) { + case PVA: speed_override = 80; break; + case SCAFF: speed_override = 35; break; + case FLEX: speed_override = 35; break; + default: speed_override = 100; + } + writer.set_tool(tool) + .speed_override(speed_override) + .flush_planner_queue(); +} + +void WipeTower::toolchange_Load( + Writer &writer, + const box_coordinates &cleaning_box, + const material_type /* material */, + const wipe_shape shape, + const bool colorInit) +{ + float xl = cleaning_box.ld.x + perimeterWidth; + float xr = cleaning_box.rd.x - perimeterWidth; + + writer.append("; CP TOOLCHANGE LOAD\n") + // Load the filament while moving left / right, + // so the excess material will not create a blob at a single position. + .deretract_move_x(xr, 20, 1400) + .deretract_move_x(xl, 40, 3000) + .deretract_move_x(xr, 20, 1600) + .deretract_move_x(xl, 10, 1000); + + // Extrude first five lines (just three lines if colorInit is set). + writer.extrude(xr, writer.y(), 1600); + size_t pass = colorInit ? 1 : 2; + for (int i = 0; i < pass; ++ i) + writer.travel (xr, writer.y() + shape * perimeterWidth * 0.85f, 2200) + .extrude(xl, writer.y()) + .travel (xl, writer.y() + shape * perimeterWidth * 0.85f) + .extrude(xr, writer.y()); + + // Reset the extruder current to the normal value. + writer.set_extruder_trimpot(550); +} + +// Wipe the newly loaded filament until the end of the assigned wipe area. +void WipeTower::toolchange_Wipe( + Writer &writer, + const box_coordinates &cleaning_box, + const material_type material, + const wipe_shape shape) +{ + // Increase flow on first layer, slow down print. + writer.set_extrusion_flow(extrusion_flow * (is_first_layer() ? 1.18f : 1.f)) + .append("; CP TOOLCHANGE WIPE\n"); + float wipe_coeff = is_first_layer() ? 0.5f : 1.f; + float xl = cleaning_box.ld.x + 2.f * perimeterWidth; + float xr = cleaning_box.rd.x - 2.f * perimeterWidth; + // Wipe speed will increase up to 4800. + float wipe_speed = 4200; + // Y increment per wipe line. + float dy = shape * perimeterWidth * 0.7f; + for (bool p = true; ; p = ! p) { + writer.feedrate((wipe_speed = std::min(4800.f, wipe_speed + 50.f)) * wipe_coeff); + if (p) + writer.extrude(xl - perimeterWidth/2, writer.y() + dy) + .extrude(xr + perimeterWidth, writer.y()); + else + writer.extrude(xl - perimeterWidth, writer.y() + dy) + .extrude(xr + perimeterWidth*2, writer.y()); + writer.feedrate((wipe_speed = std::min(4800.f, wipe_speed + 50.f)) * wipe_coeff) + .extrude(xr + perimeterWidth, writer.y() + dy) + .extrude(xl - perimeterWidth, writer.y()); + if ((shape == SHAPE_NORMAL) ? + (writer.y() > cleaning_box.lu.y - perimeterWidth) : + (writer.y() < cleaning_box.ld.y + perimeterWidth)) + // Next wipe line does not fit the cleaning box. + break; + } + // Reset the extrusion flow. + writer.set_extrusion_flow(extrusion_flow); +} + +// Draw a perimeter around cleaning_box and wipe. +void WipeTower::toolchange_Done( + Writer &writer, + const box_coordinates &cleaning_box, + const material_type /* material */, + const wipe_shape shape) +{ + box_coordinates box = cleaning_box; + if (shape == SHAPE_REVERSED) { + std::swap(box.lu, box.ld); + std::swap(box.ru, box.rd); + } + // Draw a perimeter around cleaning_box. + writer.travel(box.lu, 7000) + .extrude(box.ld, 3200).extrude(box.rd) + .extrude(box.ru).extrude(box.lu) + // Wipe the nozzle. + .travel(box.ru, 7200) + .travel(box.lu) + .feedrate(6000); } std::string WipeTower::Perimeter(int order, int total, int Layer, bool afterToolchange, int firstLayerOffset) { - float _speed = 1.f; + Writer writer; + writer.set_extrusion_flow(extrusion_flow) + .set_z(m_z_pos) + .append(";--------------------\n" + "; CP EMPTY GRID START\n") + .comment_with_value(" layer #", Layer); - std::string gcode = - ";--------------------\n" - "; CP EMPTY GRID START\n"; - gcode += line_CommentValue(" layer #", Layer); - - if (Layer == 20) - _speed = 2.f; + // Slow down on the 1st layer. + float speed_factor = is_first_layer() ? 0.5f : 1.f; - box_coordinates _p = _boxForColor(order); - box_coordinates _to = _boxForColor(total); - _p.ld.y += firstLayerOffset; - _p.rd.y += firstLayerOffset; - - _p.lu = _to.lu; _p.ru = _to.ru; - - - if (!afterToolchange) + box_coordinates _p = _boxForColor(order); { - gcode += line_EF(retract*(float)-1.5, 3600); - gcode += line_ZF(m_z_pos + zHop, 7200); - gcode += line_XYF(_p.ld.x + randi(5, 20), _p.ld.y, 7000); - gcode += line_ZF(m_z_pos, 7200); - gcode += line_XEF(_p.ld.x, retract*(float)1.5, 3600); + box_coordinates _to = _boxForColor(total); + _p.ld.y += firstLayerOffset; + _p.rd.y += firstLayerOffset; + _p.lu = _to.lu; _p.ru = _to.ru; } - - gcode += line_F(2400 / _speed); - gcode += line_XYE(_p.lu.x, _p.ru.y, (_p.ru.y - _p.ld.y) * extrusion_flow); - gcode += line_XYE(_p.ru.x, _p.ru.y, (_p.ru.x - _p.lu.x) * extrusion_flow); - gcode += line_XYE(_p.rd.x, _p.rd.y, (_p.ru.y - _p.ld.y) * extrusion_flow); - gcode += line_XYE(_p.ld.x + (perimeterWidth / 2), _p.ld.y, (_p.ru.x - _p.lu.x) * extrusion_flow); - - gcode += line_F(3200 / _speed); - gcode += line_XYE(_p.lu.x + (perimeterWidth / 2), _p.lu.y - (perimeterWidth / 2), (_p.ru.y - _p.ld.y) * extrusion_flow); - gcode += line_XYE(_p.ru.x - (perimeterWidth / 2), _p.ru.y - (perimeterWidth / 2), (_p.ru.x - _p.lu.x) * extrusion_flow); - gcode += line_XYE(_p.rd.x - (perimeterWidth / 2), _p.rd.y + (perimeterWidth / 2), (_p.ru.y - _p.ld.y) * extrusion_flow); - gcode += line_XYE(_p.ld.x + perimeterWidth, _p.ld.y + (perimeterWidth / 2), (_p.ru.x - _p.lu.x) * extrusion_flow); - gcode += line_XYE(_p.ld.x + perimeterWidth, _p.ld.y + perimeterWidth, perimeterWidth * extrusion_flow); - - gcode += line_F(2900 / _speed); - gcode += line_XYE(_p.ld.x + (perimeterWidth * 3), _p.ld.y + perimeterWidth, (perimeterWidth * 3) * extrusion_flow); - gcode += line_XYE(_p.lu.x + (perimeterWidth * 3), _p.lu.y - perimeterWidth, (_p.ru.y - _p.ld.y) * extrusion_flow); - gcode += line_XYE(_p.lu.x + (perimeterWidth * 6), _p.lu.y - perimeterWidth, (perimeterWidth * 3) * extrusion_flow); - gcode += line_XYE(_p.ld.x + (perimeterWidth * 6), _p.ld.y + perimeterWidth, (_p.ru.y - _p.ld.y) * extrusion_flow); - if (_p.lu.y - _p.ld.y > 4) - { - gcode += line_F(3200 / _speed); - float _step = (m_wipe_tower_width - (perimeterWidth * 12)) / 3; - float _sx = 0; - for (int _s = 0; _s < 3; _s++) - { - float _ext = ((_p.ru.y - _p.ld.y) / 3)*(extrusion_flow*(float)1.5); - _sx = _sx + (_step / 2); - gcode += line_XYE(_p.ld.x + (perimeterWidth * 6) + (_step / 4) + (_step * _s), _p.ld.y + (perimeterWidth * 8), _ext); - gcode += line_XYE(_p.ld.x + (perimeterWidth * 6) + (_step / 4) + (_step * _s), _p.lu.y - (perimeterWidth * 8), _ext); - gcode += line_XYE(_p.ld.x + (perimeterWidth * 6) + ((_step / 4) * 2) + (_step * _s), _p.lu.y - perimeterWidth, _ext); - gcode += line_XYE(_p.ld.x + (perimeterWidth * 6) + ((_step / 4) * 3) + (_step * _s), _p.lu.y - (perimeterWidth * 8), _ext); - gcode += line_XYE(_p.ld.x + (perimeterWidth * 6) + ((_step / 4) * 3) + (_step * _s), _p.ld.y + (perimeterWidth * 8), _ext); - gcode += line_XYE(_p.ld.x + (perimeterWidth * 6) + (_step)+(_step * _s), _p.ld.y + perimeterWidth, _ext); + if (! afterToolchange) + // Jump with retract to _p.ld + a random shift in +x. + writer.retract(retract * 1.5f, 3600) + .z_hop(zHop, 7200) + .travel(_p.ld.x + randi(5, 20), _p.ld.y, 7000) + .z_hop(0, 7200) + .extrude_explicit(_p.ld, retract * 1.5f, 3600); + + box_coordinates box = _p; + writer.extrude(box.lu, 2400 * speed_factor) + .extrude(box.ru) + .extrude(box.rd) + .extrude(box.ld + xy(perimeterWidth / 2, 0)); + + box.expand(- perimeterWidth / 2); + writer.extrude(box.lu, 3200 * speed_factor) + .extrude(box.ru) + .extrude(box.rd) + .extrude(box.ld + xy(perimeterWidth / 2, 0)) + .extrude(box.ld + xy(perimeterWidth / 2, perimeterWidth / 2)); + + writer.extrude(_p.ld + xy(perimeterWidth * 3, perimeterWidth), 2900 * speed_factor) + .extrude(_p.lu + xy(perimeterWidth * 3, - perimeterWidth)) + .extrude(_p.lu + xy(perimeterWidth * 6, - perimeterWidth)) + .extrude(_p.ld + xy(perimeterWidth * 6, perimeterWidth)); + + if (_p.lu.y - _p.ld.y > 4) { + // Extrude three zig-zags. + writer.feedrate(3200 * speed_factor); + float step = (m_wipe_tower_width - perimeterWidth * 12.f) / 12.f; + for (size_t i = 0; i < 3; ++ i) { + writer.extrude(writer.x() + step, _p.ld.y + perimeterWidth * 8); + writer.extrude(writer.x() , _p.lu.y - perimeterWidth * 8); + writer.extrude(writer.x() + step, _p.lu.y - perimeterWidth ); + writer.extrude(writer.x() + step, _p.lu.y - perimeterWidth * 8); + writer.extrude(writer.x() , _p.ld.y + perimeterWidth * 8); + writer.extrude(writer.x() + step, _p.ld.y + perimeterWidth ); } } - gcode += line_F(2900 / _speed); - gcode += line_XYE(_p.ru.x - (perimeterWidth * 6), _p.ru.y - perimeterWidth, (_p.ru.y - _p.ld.y) * extrusion_flow); - gcode += line_XYE(_p.ru.x - (perimeterWidth * 3), _p.ru.y - perimeterWidth, (perimeterWidth * 3) * extrusion_flow); - gcode += line_XYE(_p.rd.x - (perimeterWidth * 3), _p.rd.y + perimeterWidth, (_p.ru.y - _p.ld.y) * extrusion_flow); - gcode += line_XYE(_p.rd.x - perimeterWidth, _p.rd.y + perimeterWidth, perimeterWidth * extrusion_flow); + writer.extrude(_p.ru + xy(- perimeterWidth * 6, - perimeterWidth), 2900 * speed_factor) + .extrude(_p.ru + xy(- perimeterWidth * 3, - perimeterWidth)) + .extrude(_p.rd + xy(- perimeterWidth * 3, perimeterWidth)) + .extrude(_p.rd + xy(- perimeterWidth, perimeterWidth)) + // Wipe along the front side of the current wiping box. + .travel(_p.ld + xy( perimeterWidth, perimeterWidth / 2), 7200) + .travel(_p.rd + xy(- perimeterWidth, perimeterWidth / 2)) + .append("; CP EMPTY GRID END\n" + ";------------------\n\n\n\n\n\n\n"); - gcode += line_F(7200); - gcode += line_XY(_p.ld.x + perimeterWidth, _p.rd.y + (perimeterWidth / 2)); - gcode += line_XY(_p.rd.x - perimeterWidth, _p.ld.y + (perimeterWidth / 2)); - - gcode += "; CP EMPTY GRID END\n" - ";------------------\n\n\n\n\n\n\n"; - - return gcode; + return writer.gcode(); } WipeTower::box_coordinates WipeTower::_boxForColor(int order) const diff --git a/xs/src/libslic3r/WipeTower.hpp b/xs/src/libslic3r/WipeTower.hpp index a694ea4a3..38d8203c9 100644 --- a/xs/src/libslic3r/WipeTower.hpp +++ b/xs/src/libslic3r/WipeTower.hpp @@ -8,6 +8,8 @@ namespace PrusaSingleExtruderMM { +class Writer; + class WipeTower { public: @@ -27,13 +29,17 @@ public: enum wipe_shape { - NORMAL = 1, - REVERSED = -1 + SHAPE_NORMAL = 1, + SHAPE_REVERSED = -1 }; struct xy { xy(float x = 0.f, float y = 0.f) : x(x), y(y) {} + xy operator+(const xy &rhs) const { xy out(*this); out.x += rhs.x; out.y += rhs.y; return out; } + xy operator-(const xy &rhs) const { xy out(*this); out.x -= rhs.x; out.y -= rhs.y; return out; } + xy& operator+=(const xy &rhs) { x += rhs.x; y += rhs.y; return *this; } + xy& operator-=(const xy &rhs) { x -= rhs.x; y -= rhs.y; return *this; } float x; float y; }; @@ -58,6 +64,7 @@ public: // Z height -- mm void setZ(float z) { m_z_pos = z; } + bool is_first_layer() const { return m_z_pos < 0.205f; } // _retract - retract value in mm void setRetract(float _retract) { retract = _retract; } @@ -89,36 +96,40 @@ public: sideOnly -- set to false -- experimental, draw brim on sides of wipe tower offset -- set to 0 -- experimental, offset to replace brim in front / rear of wipe tower */ - std::string FirstLayer(bool sideOnly, float offset); + std::string FirstLayer(bool sideOnly = false, float y_offset = 0.f); - /* - Returns gcode for toolchange - - tool -- extruder # 0 - 3 - current_material -- filament type currently used to print and loaded in nozzle -- see enum material_type - new_material -- filament type that will be loaded in to the nozzle -- see enum material_type - temperature -- temperature in Celsius for new filament that will be loaded into the nozzle - shape -- orientation of purge / wipe shape -- 0 = normal, 1 = reversed -- enum wipe_shape - count -- total toolchanges done counter ( comment in header of toolchange only ) - spaceAvailable -- space available for toolchange ( purge / load / wipe ) - in mm - wipeStartY -- experimental, don't use, set to 0 - lastInFile -- for last toolchange in object set to true to unload filament into cooling tube, for all other set to false - colorInit -- experimental, set to 0 - */ + // Returns gcode for toolchange std::pair Toolchange( - int tool, material_type current_material, material_type new_material, int temperature, wipe_shape shape, - int count, float spaceAvailable, float wipeStartY, bool lastInFile, bool colorInit); + // extruder # 0 - 3 + const int tool, + // filament type currently used to print and loaded in nozzle -- see enum material_type + const material_type current_material, + // filament type that will be loaded in to the nozzle -- see enum material_type + const material_type new_material, + // temperature in Celsius for new filament that will be loaded into the nozzle + const int temperature, + // orientation of purge / wipe shape (NORMAL / REVERSED) + const wipe_shape shape, + // total toolchanges done counter ( comment in header of toolchange only ) + const int count, + // space available for toolchange ( purge / load / wipe ) - in mm + const float spaceAvailable, + // experimental, don't use, set to 0 + const float wipeStartY, + // for last toolchange in object set to true to unload filament into cooling tube, for all other set to false + const bool lastInFile, + // experimental, set to false + const bool colorInit = false); /* Returns gcode to draw empty pattern in place of a toolchange -> in case there are less toolchanges atm then what is required later order -- total toolchanges done for current layer total -- total colors in current z layer including empty ones - layer -- Z height in mm * 100 ( slows down print for first layer ) afterToolchange -- true - ignore some not neccesary moves | false - do whole move from object to wipe tower firstLayerOffset -- experimental , set to 0 */ - std::string Perimeter(int order, int total, int layer, bool afterToolchange, int firstLayerOffset); + std::string Perimeter(int order, int total, int Layer, bool afterToolchange, int firstLayerOffset = 0); private: WipeTower(); @@ -133,8 +144,6 @@ private: float m_z_pos; // Maximum number of color changes per layer. int m_color_changes; - // Current y position at the wipe tower. - float m_y_position; float zHop = 0.5f; float retract = 4.f; @@ -149,17 +158,49 @@ private: rd(left + width, bottom ), ru(left + width, bottom + height) {} box_coordinates(const xy &pos, float width, float height) : box_coordinates(pos.x, pos.y, width, height) {} + void expand(const float offset) { + ld += xy(- offset, - offset); + lu += xy(- offset, offset); + rd += xy( offset, - offset); + ru += xy( offset, offset); + } xy ld; // left down xy lu; // left upper xy ru; // right upper xy rd; // right lower }; - std::string toolchange_Unload(const box_coordinates &cleaning_box, material_type material, wipe_shape shape, int temperature); - std::string toolchange_Change(int tool, material_type current_material, material_type new_material); - std::string toolchange_Load(const box_coordinates &cleaning_box, material_type material, wipe_shape shape, bool colorInit); - std::string toolchange_Wipe(const box_coordinates &cleaning_box, material_type material, wipe_shape shape); - std::string toolchange_Done(const box_coordinates &cleaning_box, material_type material, wipe_shape shape); + void toolchange_Unload( + Writer &writer, + const box_coordinates &cleaning_box, + const material_type material, + const wipe_shape shape, + const int temperature); + + void toolchange_Change( + Writer &writer, + int tool, + material_type current_material, + material_type new_material); + + void toolchange_Load( + Writer &writer, + const box_coordinates &cleaning_box, + const material_type material, + const wipe_shape shape, + const bool colorInit); + + void toolchange_Wipe( + Writer &writer, + const box_coordinates &cleaning_box, + const material_type material, + const wipe_shape shape); + + void toolchange_Done( + Writer &writer, + const box_coordinates &cleaning_box, + const material_type material, + const wipe_shape shape); box_coordinates _boxForColor(int order) const; };