From b610866d771dc602420b28c58ccd71f88f0ecb30 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 1 Sep 2017 17:30:18 +0200 Subject: [PATCH] Implemented priming of all the filaments of the Prusa Multi Material. --- slic3r.sublime-project | 2 +- xs/CMakeLists.txt | 13 +- xs/src/libslic3r/GCode.cpp | 53 ++++-- xs/src/libslic3r/GCode.hpp | 4 + xs/src/libslic3r/GCode/ToolOrdering.cpp | 58 ++++--- xs/src/libslic3r/GCode/ToolOrdering.hpp | 20 ++- xs/src/libslic3r/GCode/WipeTower.hpp | 18 ++- xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp | 168 ++++++++++++++++---- xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp | 7 +- xs/src/libslic3r/Print.cpp | 21 ++- xs/src/libslic3r/Print.hpp | 31 +++- xs/src/slic3r/GUI/3DScene.cpp | 21 ++- xs/src/xsinit.h | 1 + 13 files changed, 324 insertions(+), 93 deletions(-) diff --git a/slic3r.sublime-project b/slic3r.sublime-project index 096a4859b..3f2fc36dc 100644 --- a/slic3r.sublime-project +++ b/slic3r.sublime-project @@ -26,7 +26,7 @@ "file_regex": "^(..[^:]*)\\(([0-9]+)\\)(.*)$", // For GCC: // "file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$", - "shell_cmd": "chdir & ninja -j 6", + "shell_cmd": "chdir & ninja -j 6 -v", "env": { // "PATH": "C:\\Program Files (x86)\\MSBuild\\12.0\\bin\\amd64;C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\BIN\\amd64;C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\Common7\\IDE;C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\Common7\\Tools;%PATH%;c:\\wperl64d\\site\\bin;c:\\wperl64d\\bin", // "PERL_CPANM_HOME": "c:\\wperl64d\\cpanm", diff --git a/xs/CMakeLists.txt b/xs/CMakeLists.txt index 9d7c31100..617f79055 100644 --- a/xs/CMakeLists.txt +++ b/xs/CMakeLists.txt @@ -394,8 +394,15 @@ target_compile_options(XS PRIVATE ${PerlEmbed_CCFLAGS}) # If the Perl is compiled with optimization off, disable optimization over the whole project. if (WIN32 AND ";${PerlEmbed_CCFLAGS};" MATCHES ";[-/]Od;") message(STATUS "Perl compiled without optimization. Disabling optimization for the Slic3r build.") - set(CMAKE_CXX_FLAGS_RELEASE /Od /Zi) - set(CMAKE_C_FLAGS_RELEASE /Od /Zi) + message("Old CMAKE_CXX_FLAGS_RELEASE: ${CMAKE_CXX_FLAGS_RELEASE}") + message("Old CMAKE_CXX_FLAGS_RELWITHDEBINFO: ${CMAKE_CXX_FLAGS_RELEASE}") + message("Old CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS_RELEASE}") + set(CMAKE_CXX_FLAGS_RELEASE "/MD /Od /Zi /EHsc /DNDEBUG") + set(CMAKE_C_FLAGS_RELEASE "/MD /Od /Zi /DNDEBUG") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "/MD /Od /Zi /EHsc /DNDEBUG") + set(CMAKE_C_FLAGS_RELWITHDEBINFO "/MD /Od /Zi /DNDEBUG") + set(CMAKE_CXX_FLAGS "/MD /Od /Zi /EHsc /DNDEBUG") + set(CMAKE_C_FLAGS "/MD /Od /Zi /DNDEBUG") endif() # The following line will add -fPIC on Linux to make the XS.so rellocable. add_definitions(${PerlEmbed_CCCDLFLAGS}) @@ -437,6 +444,8 @@ if(MSVC) # Suppress implicit linking of the TBB libraries by the Visual Studio compiler. add_definitions(-D__TBB_NO_IMPLICIT_LINKAGE) endif() +# The Intel TBB library will use the std::exception_ptr feature of C++11. +add_definitions(-DTBB_USE_CAPTURED_EXCEPTION=0) target_link_libraries(XS ${TBB_LIBRARIES}) # Find and configure wxWidgets diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 699621974..3c7df750e 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -192,6 +192,33 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T return gcode; } +std::string WipeTowerIntegration::prime(GCode &gcodegen) +{ + assert(m_layer_idx == 0); + std::string gcode; + + if (&m_priming != nullptr && ! m_priming.extrusions.empty()) { + // Let the tool change be executed by the wipe tower class. + // Inform the G-code writer about the changes done behind its back. + gcode += m_priming.gcode; + // Let the m_writer know the current extruder_id, but ignore the generated G-code. + gcodegen.writer().toolchange(m_priming.extrusions.back().tool); + // A phony move to the end position at the wipe tower. + gcodegen.writer().travel_to_xy(Pointf(m_priming.end_pos.x, m_priming.end_pos.y)); + gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, m_priming.end_pos)); + + // Prepare a future wipe. + gcodegen.m_wipe.path.points.clear(); + // Start the wipe at the current position. + gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen, m_priming.end_pos)); + // Wipe end point: Wipe direction away from the closer tower edge to the further tower edge. + gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen, + WipeTower::xy((std::abs(m_left - m_priming.end_pos.x) < std::abs(m_right - m_priming.end_pos.x)) ? m_right : m_left, + m_priming.end_pos.y))); + } + return gcode; +} + std::string WipeTowerIntegration::tool_change(GCode &gcodegen, int extruder_id, bool finish_layer) { std::string gcode; @@ -522,7 +549,7 @@ bool GCode::_do_export(Print &print, FILE *file) writeln(file, m_placeholder_parser.process(print.config.start_gcode.value, initial_extruder_id)); // Process filament-specific gcode in extruder order. for (const std::string &start_gcode : print.config.start_filament_gcode.values) - writeln(file, m_placeholder_parser.process(start_gcode, &start_gcode - &print.config.start_filament_gcode.values.front())); + writeln(file, m_placeholder_parser.process(start_gcode, (unsigned int)(&start_gcode - &print.config.start_filament_gcode.values.front()))); this->_print_first_layer_extruder_temperatures(file, print, initial_extruder_id, true); // Set other general things. @@ -647,8 +674,10 @@ bool GCode::_do_export(Print &print, FILE *file) std::vector>> layers_to_print = collect_layers_to_print(print); // Prusa Multi-Material wipe tower. if (print.has_wipe_tower() && - ! tool_ordering.empty() && tool_ordering.front().wipe_tower_partitions > 0) - m_wipe_tower.reset(new WipeTowerIntegration(print.config, print.m_wipe_tower_tool_changes, *print.m_wipe_tower_final_purge.get())); + ! tool_ordering.empty() && tool_ordering.front().wipe_tower_partitions > 0) { + m_wipe_tower.reset(new WipeTowerIntegration(print.config, *print.m_wipe_tower_priming.get(), print.m_wipe_tower_tool_changes, *print.m_wipe_tower_final_purge.get())); + write(file, m_wipe_tower->prime(*this)); + } // Extrude the layers. for (auto &layer : layers_to_print) { const ToolOrdering::LayerTools &layer_tools = tool_ordering.tools_for_layer(layer.first); @@ -668,7 +697,7 @@ bool GCode::_do_export(Print &print, FILE *file) write(file, m_writer.set_fan(false)); // Process filament-specific gcode in extruder order. for (const std::string &end_gcode : print.config.end_filament_gcode.values) - writeln(file, m_placeholder_parser.process(end_gcode, &end_gcode - &print.config.end_filament_gcode.values.front())); + writeln(file, m_placeholder_parser.process(end_gcode, (unsigned int)(&end_gcode - &print.config.end_filament_gcode.values.front()))); writeln(file, m_placeholder_parser.process(print.config.end_gcode, m_writer.extruder()->id())); write(file, m_writer.update_progress(m_layer_count, m_layer_count, true)); // 100% write(file, m_writer.postamble()); @@ -1471,7 +1500,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou } else if (seam_position == spNearest || seam_position == spAligned || seam_position == spRear) { Polygon polygon = loop.polygon(); const coordf_t nozzle_dmr = EXTRUDER_CONFIG(nozzle_diameter); - const coord_t nozzle_r = scale_(0.5*nozzle_dmr); + const coord_t nozzle_r = coord_t(scale_(0.5 * nozzle_dmr) + 0.5); // Retrieve the last start position for this object. float last_pos_weight = 1.f; @@ -1524,11 +1553,11 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou penalty = penaltyConvexVertex; else if (ccwAngle < 0.f) { // Interpolate penalty between maximum and zero. - penalty = penaltyFlatSurface * bspline_kernel(ccwAngle * (PI * 2. / 3.)); + penalty = penaltyFlatSurface * bspline_kernel(ccwAngle * float(PI * 2. / 3.)); } else { assert(ccwAngle >= 0.f); // Interpolate penalty between maximum and the penalty for a convex vertex. - penalty = penaltyConvexVertex + (penaltyFlatSurface - penaltyConvexVertex) * bspline_kernel(ccwAngle * (PI * 2. / 3.)); + penalty = penaltyConvexVertex + (penaltyFlatSurface - penaltyConvexVertex) * bspline_kernel(ccwAngle * float(PI * 2. / 3.)); } // Give a negative penalty for points close to the last point or the prefered seam location. //float dist_to_last_pos_proj = last_pos_proj.distance_to(polygon.points[i]); @@ -1543,8 +1572,8 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou // Penalty for overhangs. if (lower_layer_edge_grid && (*lower_layer_edge_grid)) { // Use the edge grid distance field structure over the lower layer to calculate overhangs. - coord_t nozzle_r = scale_(0.5*nozzle_dmr); - coord_t search_r = scale_(0.8*nozzle_dmr); + coord_t nozzle_r = coord_t(floor(scale_(0.5 * nozzle_dmr) + 0.5)); + coord_t search_r = coord_t(floor(scale_(0.8 * nozzle_dmr) + 0.5)); for (size_t i = 0; i < polygon.points.size(); ++ i) { const Point &p = polygon.points[i]; coordf_t dist; @@ -1555,7 +1584,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou // If the approximate Signed Distance Field was initialized over lower_layer_edge_grid, // then the signed distnace shall always be known. assert(found); - penalties[i] += extrudate_overlap_penalty(nozzle_r, penaltyOverhangHalf, dist); + penalties[i] += extrudate_overlap_penalty(float(nozzle_r), penaltyOverhangHalf, float(dist)); } } @@ -1651,7 +1680,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou } // reset acceleration - gcode += m_writer.set_acceleration(m_config.default_acceleration.value); + gcode += m_writer.set_acceleration((unsigned int)(m_config.default_acceleration.value + 0.5)); if (m_wipe.enable) m_wipe.path = paths.front().polyline; // TODO: don't limit wipe to last path @@ -1708,7 +1737,7 @@ std::string GCode::extrude_multi_path(ExtrusionMultiPath multipath, std::string m_wipe.path.reverse(); } // reset acceleration - gcode += m_writer.set_acceleration(m_config.default_acceleration.value); + gcode += m_writer.set_acceleration((unsigned int)floor(m_config.default_acceleration.value + 0.5)); return gcode; } diff --git a/xs/src/libslic3r/GCode.hpp b/xs/src/libslic3r/GCode.hpp index ac0af3f2c..da97fd23a 100644 --- a/xs/src/libslic3r/GCode.hpp +++ b/xs/src/libslic3r/GCode.hpp @@ -77,16 +77,19 @@ class WipeTowerIntegration { public: WipeTowerIntegration( const PrintConfig &print_config, + const WipeTower::ToolChangeResult &priming, const std::vector> &tool_changes, const WipeTower::ToolChangeResult &final_purge) : m_left(float(print_config.wipe_tower_x.value)), m_right(float(print_config.wipe_tower_x.value + print_config.wipe_tower_width.value)), + m_priming(priming), m_tool_changes(tool_changes), m_final_purge(final_purge), m_layer_idx(-1), m_tool_change_idx(0), m_brim_done(false) {} + std::string prime(GCode &gcodegen); void next_layer() { ++ m_layer_idx; m_tool_change_idx = 0; } std::string tool_change(GCode &gcodegen, int extruder_id, bool finish_layer); std::string finalize(GCode &gcodegen); @@ -99,6 +102,7 @@ private: const float m_left; const float m_right; // Reference to cached values at the Printer class. + const WipeTower::ToolChangeResult &m_priming; const std::vector> &m_tool_changes; const WipeTower::ToolChangeResult &m_final_purge; // Current layer index. diff --git a/xs/src/libslic3r/GCode/ToolOrdering.cpp b/xs/src/libslic3r/GCode/ToolOrdering.cpp index 2bf659bb2..703e4262e 100644 --- a/xs/src/libslic3r/GCode/ToolOrdering.cpp +++ b/xs/src/libslic3r/GCode/ToolOrdering.cpp @@ -8,7 +8,7 @@ namespace Slic3r { // For the use case when each object is printed separately // (print.config.complete_objects is true). -ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extruder) +ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extruder, bool prime_multi_material) { if (object.layers.empty()) return; @@ -31,13 +31,15 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude this->reorder_extruders(first_extruder); this->fill_wipe_tower_partitions(object.print()->config, object.layers.front()->print_z - object.layers.front()->height); + + this->collect_extruder_statistics(prime_multi_material); } // For the use case when all objects are printed at once. // (print.config.complete_objects is false). -ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder) +ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool prime_multi_material) { - // Initialize the print layers for all objects and all layers. + // Initialize the print layers for all objects and all layers. coordf_t object_bottom_z = 0.; { std::vector zs; @@ -61,22 +63,8 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder) this->reorder_extruders(first_extruder); this->fill_wipe_tower_partitions(print.config, object_bottom_z); -} -unsigned int ToolOrdering::first_extruder() const -{ - for (const auto < : m_layer_tools) - if (! lt.extruders.empty()) - return lt.extruders.front(); - return (unsigned int)-1; -} - -unsigned int ToolOrdering::last_extruder() const -{ - for (auto lt_it = m_layer_tools.rbegin(); lt_it != m_layer_tools.rend(); ++ lt_it) - if (! lt_it->extruders.empty()) - return lt_it->extruders.back(); - return (unsigned int)-1; + this->collect_extruder_statistics(prime_multi_material); } ToolOrdering::LayerTools& ToolOrdering::tools_for_layer(coordf_t print_z) @@ -289,4 +277,38 @@ void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_ } } +void ToolOrdering::collect_extruder_statistics(bool prime_multi_material) +{ + m_first_printing_extruder = (unsigned int)-1; + for (const auto < : m_layer_tools) + if (! lt.extruders.empty()) { + m_first_printing_extruder = lt.extruders.front(); + break; + } + + m_last_printing_extruder = (unsigned int)-1; + for (auto lt_it = m_layer_tools.rbegin(); lt_it != m_layer_tools.rend(); ++ lt_it) + if (! lt_it->extruders.empty()) { + m_last_printing_extruder = lt_it->extruders.back(); + break; + } + + m_all_printing_extruders.clear(); + for (const auto < : m_layer_tools) { + append(m_all_printing_extruders, lt.extruders); + sort_remove_duplicates(m_all_printing_extruders); + } + + if (prime_multi_material && ! m_all_printing_extruders.empty()) { + // Reorder m_all_printing_extruders in the sequence they will be primed, the last one will be m_first_printing_extruder. + // Then set m_first_printing_extruder to the 1st extruder primed. + m_all_printing_extruders.erase( + std::remove_if(m_all_printing_extruders.begin(), m_all_printing_extruders.end(), + [ this ](const unsigned int eid) { return eid == m_first_printing_extruder; }), + m_all_printing_extruders.end()); + m_all_printing_extruders.emplace_back(m_first_printing_extruder); + m_first_printing_extruder = m_all_printing_extruders.front(); + } +} + } // namespace Slic3r diff --git a/xs/src/libslic3r/GCode/ToolOrdering.hpp b/xs/src/libslic3r/GCode/ToolOrdering.hpp index 77de726ba..ecf2d522f 100644 --- a/xs/src/libslic3r/GCode/ToolOrdering.hpp +++ b/xs/src/libslic3r/GCode/ToolOrdering.hpp @@ -45,19 +45,22 @@ public: // For the use case when each object is printed separately // (print.config.complete_objects is true). - ToolOrdering(const PrintObject &object, unsigned int first_extruder = (unsigned int)-1); + ToolOrdering(const PrintObject &object, unsigned int first_extruder = (unsigned int)-1, bool prime_multi_material = false); // For the use case when all objects are printed at once. // (print.config.complete_objects is false). - ToolOrdering(const Print &print, unsigned int first_extruder = (unsigned int)-1); + ToolOrdering(const Print &print, unsigned int first_extruder = (unsigned int)-1, bool prime_multi_material = false); void clear() { m_layer_tools.clear(); } // Get the first extruder printing the layer_tools, returns -1 if there is no layer printed. - unsigned int first_extruder() const; + unsigned int first_extruder() const { return m_first_printing_extruder; } // Get the first extruder printing the layer_tools, returns -1 if there is no layer printed. - unsigned int last_extruder() const; + unsigned int last_extruder() const { return m_last_printing_extruder; } + + // For a multi-material print, the printing extruders are ordered in the order they shall be primed. + std::vector all_extruders() const { return m_all_printing_extruders; } // Find LayerTools with the closest print_z. LayerTools& tools_for_layer(coordf_t print_z); @@ -74,8 +77,15 @@ private: void collect_extruders(const PrintObject &object); void reorder_extruders(unsigned int last_extruder_id); void fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z); + void collect_extruder_statistics(bool prime_multi_material); - std::vector m_layer_tools; + std::vector m_layer_tools; + // First printing extruder, including the multi-material priming sequence. + unsigned int m_first_printing_extruder; + // Final printing extruder. + unsigned int m_last_printing_extruder; + // All extruders, which extrude some material over m_layer_tools. + std::vector m_all_printing_extruders; }; } // namespace SLic3r diff --git a/xs/src/libslic3r/GCode/WipeTower.hpp b/xs/src/libslic3r/GCode/WipeTower.hpp index db3977246..cccbe23d8 100644 --- a/xs/src/libslic3r/GCode/WipeTower.hpp +++ b/xs/src/libslic3r/GCode/WipeTower.hpp @@ -89,11 +89,27 @@ public: // Time elapsed over this tool change. // This is useful not only for the print time estimation, but also for the control of layer cooling. float elapsed_time; + + // Sum the total length of the extrusion. + float total_extrusion_length_in_plane() { + float e_length = 0.f; + for (size_t i = 1; i < this->extrusions.size(); ++ i) { + const Extrusion &e = this->extrusions[i]; + if (e.width > 0) { + xy v = e.pos - (&e - 1)->pos; + e_length += sqrt(v.x*v.x+v.y*v.y); + } + } + return e_length; + } }; + // Returns gcode to prime the nozzles at the front edge of the print bed. + virtual ToolChangeResult prime(float first_layer_height, std::vector tools, Purpose purpose = PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE) = 0; + // Returns gcode for toolchange and the end position. // if new_tool == -1, just unload the current filament over the wipe tower. - virtual ToolChangeResult tool_change(int new_tool, bool last_in_layer, Purpose purpose = PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE) = 0; + virtual ToolChangeResult tool_change(unsigned int new_tool, bool last_in_layer, Purpose purpose = PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE) = 0; // Close the current wipe tower layer with a perimeter and possibly fill the unfilled space with a zig-zag. // Call this method only if layer_finished() is false. diff --git a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp index ec01e09dc..4e2921efd 100644 --- a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp +++ b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp @@ -315,6 +315,29 @@ private: Writer& operator=(const Writer &rhs); }; +/* +class Material +{ +public: + std::string name; + std::string type; + + struct RammingStep { +// float length; + float extrusion_multiplier; // sirka linky + float extrusion; + float speed; + }; + std::vector ramming_sequence; + + // Number and speed of the cooling moves. + std::vector cooling_moves; + + // Percentage of the speed overide, in pairs of + std::vector> speed_override; +}; +*/ + } // namespace PrusaMultiMaterial WipeTowerPrusaMM::material_type WipeTowerPrusaMM::parse_material(const char *name) @@ -340,7 +363,92 @@ WipeTowerPrusaMM::material_type WipeTowerPrusaMM::parse_material(const char *nam return INVALID; } -WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(int tool, bool last_in_layer, Purpose purpose) +// Returns gcode to prime the nozzles at the front edge of the print bed. +WipeTower::ToolChangeResult WipeTowerPrusaMM::prime(float first_layer_height, std::vector tools, Purpose purpose) +{ + this->set_layer(first_layer_height, first_layer_height, tools.size(), true, false); + + float wipe_area = m_wipe_area; + // Calculate the amount of wipe over the wipe tower brim following the prime, decrease wipe_area + // with the amount of material extruded over the brim. + { + // Simulate the brim extrusions, summ the length of the extrusion. + float e_length = this->tool_change(0, false, PURPOSE_EXTRUDE).total_extrusion_length_in_plane(); + // Shrink wipe_area by the amount of extrusion extruded by the finish_layer(). + // Y stepping of the wipe extrusions. + float dy = m_perimeter_width * 0.8f; + // Number of whole wipe lines, that would be extruded to wipe as much material as the finish_layer(). + // Minimum wipe area is 5mm wide. + //FIXME calculate the purge_lines_width precisely. + float purge_lines_width = 1.3f; + wipe_area = std::max(5.f, m_wipe_area - floor(e_length / m_wipe_tower_width) * dy - purge_lines_width); + } + + this->set_layer(first_layer_height, first_layer_height, tools.size(), true, false); + this->m_num_layer_changes = 0; + this->m_current_tool = tools.front(); + + box_coordinates cleaning_box(xy(0.f, - 4.0f), m_wipe_tower_width, wipe_area); + + PrusaMultiMaterial::Writer writer; + writer.set_extrusion_flow(m_extrusion_flow) + .set_z(m_z_pos) + .set_layer_height(m_layer_height) + .set_initial_tool(m_current_tool) + .append(";--------------------\n" + "; CP PRIMING START\n") + .append(";--------------------\n") + .speed_override(100); + + // Always move to the starting position. + writer.travel(cleaning_box.ld, 7200); + // Increase the extruder driver current to allow fast ramming. + writer.set_extruder_trimpot(750); + + if (purpose == PURPOSE_EXTRUDE || purpose == PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE) { + for (size_t idx_tool = 0; idx_tool < tools.size(); ++ idx_tool) { + unsigned int tool = tools[idx_tool]; + // Select the tool, set a speed override for soluble and flex materials. + toolchange_Change(writer, tool, m_material[tool]); + // Prime the tool. + toolchange_Load(writer, cleaning_box); + if (idx_tool + 1 == tools.size()) { + // Last tool should not be unloaded, but it should be wiped enough to become of a pure color. + toolchange_Wipe(writer, cleaning_box); + } else { + // 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, m_material[m_current_tool], m_first_layer_temperature[tool]); + cleaning_box.translate(m_wipe_tower_width, 0.f); + writer.travel(cleaning_box.ld, 7200); + } + ++ m_num_tool_changes; + } + } + + // Reset the extruder current to a normal value. + writer.set_extruder_trimpot(550) + .feedrate(6000) + .flush_planner_queue() + .reset_extruder() + .append("; CP PRIMING END\n" + ";------------------\n" + "\n\n"); + + // Force m_idx_tool_change_in_layer to -1, so that tool_change() will know to extrude the wipe tower brim. + m_idx_tool_change_in_layer = (unsigned int)(-1); + + ToolChangeResult result; + result.print_z = this->m_z_pos; + result.layer_height = this->m_layer_height; + result.gcode = writer.gcode(); + result.elapsed_time = writer.elapsed_time(); + result.extrusions = writer.extrusions(); + result.start_pos = writer.start_pos(); + result.end_pos = writer.pos(); + return result; +} + +WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(unsigned int tool, bool last_in_layer, Purpose purpose) { // Either it is the last tool unload, // or there must be a nonzero wipe tower partitions available. @@ -363,14 +471,7 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(int tool, bool last_in unsigned int old_idx_tool_change = m_idx_tool_change_in_layer; float old_wipe_start_y = m_current_wipe_start_y; m_current_wipe_start_y += wipe_area; - ToolChangeResult tcr = this->finish_layer(PURPOSE_EXTRUDE); - for (size_t i = 1; i < tcr.extrusions.size(); ++ i) { - const Extrusion &e = tcr.extrusions[i]; - if (e.width > 0) { - xy v = e.pos - (&e - 1)->pos; - e_length += sqrt(v.x*v.x+v.y*v.y); - } - } + e_length = this->finish_layer(PURPOSE_EXTRUDE).total_extrusion_length_in_plane(); m_idx_tool_change_in_layer = old_idx_tool_change; m_current_wipe_start_y = old_wipe_start_y; } @@ -431,10 +532,10 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(int tool, bool last_in // Increase the extruder driver current to allow fast ramming. writer.set_extruder_trimpot(750); // 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, m_material[m_current_tool], - m_is_first_layer ? m_first_layer_temperature[tool] : m_temperature[tool]); - if (tool >= 0) { + if (tool != (unsigned int)-1) { + toolchange_Unload(writer, cleaning_box, m_material[m_current_tool], + m_is_first_layer ? m_first_layer_temperature[tool] : m_temperature[tool]); // This is not the last change. // Change the tool, set a speed override for soluble and flex materials. toolchange_Change(writer, tool, m_material[tool]); @@ -455,7 +556,8 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(int tool, bool last_in if (purpose == PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE) writer.travel(box.ru, 7200) .travel(box.lu); - } + } else + toolchange_Unload(writer, cleaning_box, m_material[m_current_tool], m_temperature[m_current_tool]); // Reset the extruder current to a normal value. writer.set_extruder_trimpot(550) @@ -587,24 +689,27 @@ void WipeTowerPrusaMM::toolchange_Unload( { case ABS: // ramming start end y increment amount feedrate - writer.ram(xl + m_perimeter_width * 2, xr - m_perimeter_width, y_step * 0.2f, 0, 1.2f * e, 4000) - .ram(xr - m_perimeter_width, xl + m_perimeter_width, y_step * 1.2f, e0, 1.6f * e, 4600) - .ram(xl + m_perimeter_width * 2, xr - m_perimeter_width * 2, y_step * 1.2f, e0, 1.8f * e, 5000) - .ram(xr - m_perimeter_width * 2, xl + m_perimeter_width * 2, y_step * 1.2f, e0, 1.8f * e, 5000); + writer.ram(xl + m_perimeter_width * 2, xr - m_perimeter_width, y_step * 0.2f, 0, 1.2f * e, 4000) + .ram(xr - m_perimeter_width, xl + m_perimeter_width, y_step * 1.2f, e0, 1.6f * e, 4600) + .ram(xl + m_perimeter_width * 2, xr - m_perimeter_width * 2, y_step * 1.2f, e0, 1.8f * e, 5000) + .ram(xr - m_perimeter_width * 2, xl + m_perimeter_width * 2, y_step * 1.2f, e0, 1.8f * e, 5000); break; case PVA: - writer.ram(xl + m_perimeter_width * 2, xr - m_perimeter_width, y_step * 0.2f, 0, 3, 4000) - .ram(xr - m_perimeter_width, xl + m_perimeter_width, y_step * 1.5f, 0, 3, 4500) - .ram(xl + m_perimeter_width * 2, xr - m_perimeter_width * 2, y_step * 1.5f, 0, 3, 4800) - .ram(xr - m_perimeter_width, xl + m_perimeter_width, y_step * 1.5f, 0, 3, 5000); + // Used for the PrimaSelect PVA + writer.ram(xl + m_perimeter_width * 2, xr - m_perimeter_width, y_step * 0.2f, 0, 1.75f * e, 4000) + .ram(xr - m_perimeter_width, xl + m_perimeter_width, y_step * 1.5f, 0, 1.75f * e, 4500) + .ram(xl + m_perimeter_width * 2, xr - m_perimeter_width * 2, y_step * 1.5f, 0, 1.75f * e, 4800) + .ram(xr - m_perimeter_width, xl + m_perimeter_width, y_step * 1.5f, 0, 1.75f * e, 5000); break; case SCAFF: - writer.ram(xl + m_perimeter_width * 2, xr - m_perimeter_width, y_step * 2.f, 0, 3, 4000) - .ram(xr - m_perimeter_width, xl + m_perimeter_width, y_step * 3.f, 0, 4, 4600) - .ram(xl + m_perimeter_width * 2, xr - m_perimeter_width * 2, y_step * 3.f, 0, 4.5, 5200); + writer.ram(xl + m_perimeter_width * 2, xr - m_perimeter_width, y_step * 2.f, 0, 1.75f * e, 4000) + .ram(xr - m_perimeter_width, xl + m_perimeter_width, y_step * 3.f, 0, 2.34f * e, 4600) + .ram(xl + m_perimeter_width * 2, xr - m_perimeter_width * 2, y_step * 3.f, 0, 2.63f * e, 5200); break; default: - writer.ram(xl + m_perimeter_width * 2, xr - m_perimeter_width, y_step * 0.2f, 0, 1.6f * e, 4000) + // PLA, PLA/PHA and others + // Used for the Verbatim BVOH, PET, NGEN, co-polyesters + writer.ram(xl + m_perimeter_width * 2, xr - m_perimeter_width, y_step * 0.2f, 0, 1.60f * e, 4000) .ram(xr - m_perimeter_width, xl + m_perimeter_width, y_step * 1.2f, e0, 1.65f * e, 4600) .ram(xl + m_perimeter_width * 2, xr - m_perimeter_width * 2, y_step * 1.2f, e0, 1.74f * e, 5200); } @@ -624,12 +729,6 @@ void WipeTowerPrusaMM::toolchange_Unload( .suppress_preview(); switch (current_material) { - case ABS: - 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); - break; case PVA: writer.cool(xl, xr, 3, -5, 1600) .cool(xl, xr, 5, -5, 2000) @@ -659,8 +758,8 @@ void WipeTowerPrusaMM::toolchange_Unload( // Change the tool, set a speed override for solube and flex materials. void WipeTowerPrusaMM::toolchange_Change( PrusaMultiMaterial::Writer &writer, - const int new_tool, - material_type new_material) + const unsigned int new_tool, + material_type new_material) { // Speed override for the material. Go slow for flex and soluble materials. int speed_override; @@ -687,8 +786,11 @@ void WipeTowerPrusaMM::toolchange_Load( // Load the filament while moving left / right, // so the excess material will not create a blob at a single position. .suppress_preview() + // Accelerate the filament loading .load_move_x(xr, 20, 1400) + // Fast loading phase .load_move_x(xl, 40, 3000) + // Slowing down .load_move_x(xr, 20, 1600) .load_move_x(xl, 10, 1000) .resume_preview(); diff --git a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp index baf01f427..c21c62486 100644 --- a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp +++ b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp @@ -107,9 +107,12 @@ public: // The wipe tower is finished, there should be no more tool changes or wipe tower prints. virtual bool finished() const { return m_max_color_changes == 0; } + // Returns gcode to prime the nozzles at the front edge of the print bed. + virtual ToolChangeResult prime(float first_layer_height, std::vector tools, Purpose purpose = PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE); + // Returns gcode for a toolchange and a final print head position. // On the first layer, extrude a brim around the future wipe tower first. - virtual ToolChangeResult tool_change(int new_tool, bool last_in_layer, Purpose purpose); + virtual ToolChangeResult tool_change(unsigned int new_tool, bool last_in_layer, Purpose purpose); // Close the current wipe tower layer with a perimeter and possibly fill the unfilled space with a zig-zag. // Call this method only if layer_finished() is false. @@ -218,7 +221,7 @@ private: void toolchange_Change( PrusaMultiMaterial::Writer &writer, - int new_tool, + const unsigned int new_tool, material_type new_material); void toolchange_Load( diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 6ae36ec58..2069a7e55 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -54,6 +54,10 @@ void Print::reload_object(size_t /* idx */) this->add_model_object(mo); } +// Reloads the model instances into the print class. +// The slicing shall not be running as the modified model instances at the print +// are used for the brim & skirt calculation. +// Returns true if the brim or skirt have been invalidated. bool Print::reload_model_instances() { bool invalidated = false; @@ -461,7 +465,7 @@ bool Print::apply_config(DynamicPrintConfig config) if (region_id < object->region_volumes.size() && ! object->region_volumes[region_id].empty()) invalidated |= object->invalidate_state_by_config_options(diff); } - other_region_configs.emplace_back(this_region_config); + other_region_configs.emplace_back(std::move(this_region_config)); } } } @@ -953,6 +957,7 @@ bool Print::has_wipe_tower() const void Print::_clear_wipe_tower() { m_tool_ordering.clear(); + m_wipe_tower_priming.reset(nullptr); m_wipe_tower_tool_changes.clear(); m_wipe_tower_final_purge.reset(nullptr); } @@ -963,7 +968,8 @@ void Print::_make_wipe_tower() if (! this->has_wipe_tower()) return; - m_tool_ordering = ToolOrdering(*this, (unsigned int)-1); + // Let the ToolOrdering class know there will be initial priming extrusions at the start of the print. + m_tool_ordering = ToolOrdering(*this, (unsigned int)-1, true); unsigned int initial_extruder_id = m_tool_ordering.first_extruder(); if (initial_extruder_id == (unsigned int)-1 || m_tool_ordering.front().wipe_tower_partitions == 0) // Don't generate any wipe tower. @@ -977,7 +983,6 @@ void Print::_make_wipe_tower() //wipe_tower.set_retract(); //wipe_tower.set_zhop(); - //wipe_tower.set_zhop(); // Set the extruder & material properties at the wipe tower object. for (size_t i = 0; i < 4; ++ i) @@ -987,6 +992,9 @@ void Print::_make_wipe_tower() this->config.temperature.get_at(i), this->config.first_layer_temperature.get_at(i)); + m_wipe_tower_priming = Slic3r::make_unique( + wipe_tower.prime(this->skirt_first_layer_height(), m_tool_ordering.all_extruders(), WipeTower::PURPOSE_EXTRUDE)); + // Generate the wipe tower layers. m_wipe_tower_tool_changes.reserve(m_tool_ordering.layer_tools().size()); unsigned int current_extruder_id = initial_extruder_id; @@ -1048,7 +1056,7 @@ void Print::_make_wipe_tower() wipe_tower.set_layer(float(m_tool_ordering.back().print_z), float(layer_height), 0, false, true); } m_wipe_tower_final_purge = Slic3r::make_unique( - wipe_tower.tool_change(-1, false, WipeTower::PURPOSE_EXTRUDE)); + wipe_tower.tool_change((unsigned int)-1, false, WipeTower::PURPOSE_EXTRUDE)); } std::string Print::output_filename() @@ -1080,4 +1088,9 @@ std::string Print::output_filepath(const std::string &path) return path; } +void Print::set_status(int percent, const std::string &message) +{ + printf("Print::status %d => %s\n", percent, message.c_str()); +} + } diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp index 3b9b77982..bc8b17868 100644 --- a/xs/src/libslic3r/Print.hpp +++ b/xs/src/libslic3r/Print.hpp @@ -16,6 +16,8 @@ #include "GCode/ToolOrdering.hpp" #include "GCode/WipeTower.hpp" +#include "tbb/atomic.h" + namespace Slic3r { class Print; @@ -125,10 +127,10 @@ public: // Slic3r::Point objects in scaled G-code coordinates in our coordinates Points _shifted_copies; - LayerPtrs layers; - SupportLayerPtrs support_layers; - PrintState state; - + LayerPtrs layers; + SupportLayerPtrs support_layers; + PrintState state; + Print* print() { return this->_print; } const Print* print() const { return this->_print; } ModelObject* model_object() { return this->_model_object; } @@ -231,14 +233,14 @@ public: PrintRegionPtrs regions; PlaceholderParser placeholder_parser; // TODO: status_cb - double total_used_filament, total_extruded_volume, total_cost, total_weight; - std::map filament_stats; - PrintState state; + double total_used_filament, total_extruded_volume, total_cost, total_weight; + std::map filament_stats; + PrintState state; // ordered collections of extrusion paths to build skirt loops and brim ExtrusionEntityCollection skirt, brim; - Print() : total_used_filament(0), total_extruded_volume(0) {} + Print() : total_used_filament(0), total_extruded_volume(0) { restart(); } ~Print() { clear_objects(); } // methods for handling objects @@ -291,15 +293,28 @@ public: // Cache it here, so it does not need to be recalculated during the G-code generation. ToolOrdering m_tool_ordering; // Cache of tool changes per print layer. + std::unique_ptr m_wipe_tower_priming; std::vector> m_wipe_tower_tool_changes; std::unique_ptr m_wipe_tower_final_purge; std::string output_filename(); std::string output_filepath(const std::string &path); + + // Calls a registered callback to update the status. + void set_status(int percent, const std::string &message); + // Cancel the running computation. Stop execution of all the background threads. + void cancel() { m_canceled = true; } + // Cancel the running computation. Stop execution of all the background threads. + void restart() { m_canceled = false; } + // Has the calculation been canceled? + bool canceled() { return m_canceled; } private: bool invalidate_state_by_config_options(const std::vector &opt_keys); PrintRegionConfig _region_config_from_model_volume(const ModelVolume &volume); + + // Has the calculation been canceled? + tbb::atomic m_canceled; }; #define FOREACH_BASE(type, container, iterator) for (type::const_iterator iterator = (container).begin(); iterator != (container).end(); ++iterator) diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index 018d804de..6f9764b19 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -969,16 +969,23 @@ void _3DScene::_load_wipe_tower_toolpaths( const float* color_tool(size_t tool) const { return tool_colors->data() + tool * 4; } int volume_idx(int tool, int feature) const { return this->color_by_tool() ? std::min(this->number_tools() - 1, std::max(tool, 0)) : feature; } + + const std::vector& tool_change(size_t idx) + { return (idx == 0) ? priming : (idx == print->m_wipe_tower_tool_changes.size() + 1) ? final : print->m_wipe_tower_tool_changes[idx - 1]; } + std::vector priming; + std::vector final; } ctxt; ctxt.print = print; ctxt.tool_colors = tool_colors.empty() ? nullptr : &tool_colors; + ctxt.priming.emplace_back(*print->m_wipe_tower_priming.get()); + ctxt.final.emplace_back(*print->m_wipe_tower_final_purge.get()); BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - start"; //FIXME Improve the heuristics for a grain size. - size_t n_layers = print->m_wipe_tower_tool_changes.size(); - size_t grain_size = std::max(n_layers / 128, size_t(1)); + size_t n_items = print->m_wipe_tower_tool_changes.size() + 1; + size_t grain_size = std::max(n_items / 128, size_t(1)); tbb::spin_mutex new_volume_mutex; auto new_volume = [volumes, &new_volume_mutex](const float *color) -> GLVolume* { auto *volume = new GLVolume(color); @@ -988,21 +995,21 @@ void _3DScene::_load_wipe_tower_toolpaths( return volume; }; const size_t volumes_cnt_initial = volumes->volumes.size(); - std::vector volumes_per_thread(n_layers); + std::vector volumes_per_thread(n_items); tbb::parallel_for( - tbb::blocked_range(0, n_layers, grain_size), + tbb::blocked_range(0, n_items, grain_size), [&ctxt, &new_volume](const tbb::blocked_range& range) { // Bounding box of this slab of a wipe tower. BoundingBoxf3 bbox; bbox.min = Pointf3( ctxt.print->config.wipe_tower_x.value - 10., ctxt.print->config.wipe_tower_y.value - 10., - ctxt.print->m_wipe_tower_tool_changes[range.begin()].front().print_z - 3.); + ctxt.tool_change(range.begin()).front().print_z - 3.); bbox.max = Pointf3( ctxt.print->config.wipe_tower_x.value + ctxt.print->config.wipe_tower_width.value + 10., ctxt.print->config.wipe_tower_y.value + ctxt.print->config.wipe_tower_per_color_wipe.value * ctxt.print->m_tool_ordering.layer_tools()[range.begin()].wipe_tower_partitions + 10., - ctxt.print->m_wipe_tower_tool_changes[range.end() - 1].front().print_z + 0.1); + ctxt.tool_change(range.end() - 1).front().print_z + 0.1); std::vector vols; if (ctxt.color_by_tool()) { for (size_t i = 0; i < ctxt.number_tools(); ++ i) @@ -1015,7 +1022,7 @@ void _3DScene::_load_wipe_tower_toolpaths( volume.indexed_vertex_array.reserve(ctxt.alloc_size_reserve()); } for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) { - const std::vector &layer = ctxt.print->m_wipe_tower_tool_changes[idx_layer]; + const std::vector &layer = ctxt.tool_change(idx_layer); for (size_t i = 0; i < vols.size(); ++ i) { GLVolume &vol = *vols[i]; if (vol.print_zs.empty() || vol.print_zs.back() != layer.front().print_z) { diff --git a/xs/src/xsinit.h b/xs/src/xsinit.h index 987912433..c375c7e62 100644 --- a/xs/src/xsinit.h +++ b/xs/src/xsinit.h @@ -31,6 +31,7 @@ #undef socketpair #undef recvfrom #undef sendto +#undef pause // these need to be included early for Win32 (listing it in Build.PL is not enough) #include