diff --git a/xs/MANIFEST b/xs/MANIFEST index 8983907a72..a14d989ce5 100644 --- a/xs/MANIFEST +++ b/xs/MANIFEST @@ -430,6 +430,8 @@ src/libslic3r/TriangleMesh.cpp src/libslic3r/TriangleMesh.hpp src/libslic3r/utils.cpp src/libslic3r/Utils.hpp +src/libslic3r/WipeTower.cpp +src/libslic3r/WipeTower.hpp src/perlglue.cpp src/poly2tri/common/shapes.cc src/poly2tri/common/shapes.h diff --git a/xs/src/libslic3r/WipeTower.cpp b/xs/src/libslic3r/WipeTower.cpp new file mode 100644 index 0000000000..a9bea7eb1e --- /dev/null +++ b/xs/src/libslic3r/WipeTower.cpp @@ -0,0 +1,809 @@ +#include "WipeTower.hpp" + +#include +#include +#include + +#ifdef _MSC_VER +#define strcasecmp _stricmp +#endif + +namespace PrusaSingleExtruderMM +{ + +static inline std::string line_XY(float x, float y) +{ + char buf[128]; + sprintf(buf, "G1 X%.3f Y%.3f\n", x, y); + return buf; +} + +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; +} + +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; +} + +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) + { + 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; + } + + return ret + "\n"; +}; + +static inline int randi(int lo, int hi) +{ + int n = hi - lo + 1; + int i = rand() % n; + if (i < 0) i = -i; + return lo + i; +} + +WipeTower::material_type WipeTower::parse_material(const char *name) +{ + if (strcasecmp(name, "PLA") == 0) + return PLA; + if (strcasecmp(name, "ABS") == 0) + return ABS; + if (strcasecmp(name, "PET") == 0) + return PET; + if (strcasecmp(name, "HIPS") == 0) + return HIPS; + if (strcasecmp(name, "FLEX") == 0) + return FLEX; + if (strcasecmp(name, "SCAFF") == 0) + return SCAFF; + if (strcasecmp(name, "EDGE") == 0) + return EDGE; + if (strcasecmp(name, "NGEN") == 0) + return NGEN; + if (strcasecmp(name, "PVA") == 0) + return PVA; + return INVALID; +} + +std::string WipeTower::FirstLayer(bool sideOnly, float 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 = + ";-------------------------------------\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); + + + } + + 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); + + gcode += "; CP WIPE TOWER FIRST LAYER BRIM END\n"; + gcode += ";-----------------------------------\n"; + return 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) +{ + box_coordinates cleaning_box( + m_wipe_tower_pos.x, + m_wipe_tower_pos.y + wipeStartY, //(order * _wipe_area); //wipeStartY; + m_wipe_tower_width, + spaceAvailable - perimeterWidth / 2); //space_available //wipe_area + + std::string gcode; + gcode += ";--------------------\n"; + gcode += "; CP TOOLCHANGE START\n"; + gcode += line_CommentValue(" toolchange #", count); + gcode += line_CommentMaterial(current_material); + gcode += ";--------------------\n"; + + gcode += line_M220(100); + gcode += line_ZF(m_z_pos + zHop, 7200); + + 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); + } + + 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); +} + +std::string WipeTower::toolchange_Unload(const box_coordinates &cleaning_box, material_type material, wipe_shape shape, int temperature) +{ + float __xl = 0; + float __xr = 0; + __xl = cleaning_box.ld.x + (perimeterWidth / 2); + __xr = cleaning_box.rd.x - (perimeterWidth / 2); + + std::string gcode = "; CP TOOLCHANGE UNLOAD"; + + 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 + + + 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 + + + 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 + } + + return gcode; +} + +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"; + + 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); + break; + case SCAFF: + gcode += line_M220(35); + gcode += line_G4(0); + break; + case FLEX: + gcode += line_M220(35); + gcode += line_G4(0); + break; + default: + gcode += line_M220(100); + gcode += line_G4(0); + break; + } + + return gcode; +} + +std::string WipeTower::Perimeter(int order, int total, int Layer, bool afterToolchange, int firstLayerOffset) +{ + float _speed = 1.f; + + std::string gcode = + ";--------------------\n" + "; CP EMPTY GRID START\n"; + gcode += line_CommentValue(" layer #", Layer); + + if (Layer == 20) + _speed = 2.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) + { + 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); + } + + 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); + } + } + + 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); + + 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; +} + +WipeTower::box_coordinates WipeTower::_boxForColor(int order) const +{ + return box_coordinates(m_wipe_tower_pos.x, m_wipe_tower_pos.y + m_wipe_area * order - perimeterWidth / 2, m_wipe_tower_width, perimeterWidth); +} + +}; // namespace PrusaSingleExtruderMM diff --git a/xs/src/libslic3r/WipeTower.hpp b/xs/src/libslic3r/WipeTower.hpp new file mode 100644 index 0000000000..a694ea4a3c --- /dev/null +++ b/xs/src/libslic3r/WipeTower.hpp @@ -0,0 +1,169 @@ +#ifndef PrusaSingleExtruderMM_WipeTower_hpp_ +#define PrusaSingleExtruderMM_WipeTower_hpp_ + +#include +#include +#include + +namespace PrusaSingleExtruderMM +{ + +class WipeTower +{ +public: + enum material_type + { + INVALID = -1, + PLA = 0, // E:210C B:55C + ABS = 1, // E:255C B:100C + PET = 2, // E:240C B:90C + HIPS = 3, // E:220C B:100C + FLEX = 4, // E:245C B:80C + SCAFF = 5, // E:215C B:55C + EDGE = 6, // E:240C B:80C + NGEN = 7, // E:230C B:80C + PVA = 8 // E:210C B:80C + }; + + enum wipe_shape + { + NORMAL = 1, + REVERSED = -1 + }; + + struct xy + { + xy(float x = 0.f, float y = 0.f) : x(x), y(y) {} + float x; + float y; + }; + + // Parse material name into material_type. + static material_type parse_material(const char *name); + + // x -- x coordinates of wipe tower in mm ( left bottom corner ) + // y -- y coordinates of wipe tower in mm ( left bottom corner ) + // width -- width of wipe tower in mm ( default 60 mm - leave as it is ) + // wipe_area -- space available for one toolchange in mm + // colors -- maximum colors for object + WipeTower(float x, float y, float width, float wipe_area, int color_changes) : + m_wipe_tower_pos(x, y), + m_wipe_tower_width(width), + m_wipe_area(wipe_area), + m_color_changes(color_changes), + m_z_pos(0.f) {} + + // colors -- maximum color changes for layer + void setColors(int colors) { m_color_changes = colors; } + + // Z height -- mm + void setZ(float z) { m_z_pos = z; } + + // _retract - retract value in mm + void setRetract(float _retract) { retract = _retract; } + + // _zHop - z hop value in mm + void setZHop(float _zhop) { zHop = _zhop; } + + void setExtrusion(int layerHeight) + { + // set extrusion coefficient for layer height + // layerHeight -- mm * 100 + + switch (layerHeight) + { + case 15: + extrusion_flow = (float)0.024; + break; + case 20: + extrusion_flow = (float)0.029; + break; + default: + break; + } + } + + /* + Returns gcode for wipe tower brim + + 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); + + /* + 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 + */ + 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); + + /* + 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); + +private: + WipeTower(); + + // Left front corner of the wipe tower in mm. + xy m_wipe_tower_pos; + // Width of the wipe tower. + float m_wipe_tower_width; + // Per color Y span. + float m_wipe_area; + // Current Z position. + 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; + float perimeterWidth = 0.5f; + float extrusion_flow = 0.029f; + + struct box_coordinates + { + box_coordinates(float left, float bottom, float width, float height) : + ld(left , bottom ), + lu(left , bottom + height), + 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) {} + 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); + + box_coordinates _boxForColor(int order) const; +}; + +}; // namespace PrusaSingleExtruderMM + +#endif /* PrusaSingleExtruderMM_WipeTower_hpp_ */