diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 431ad38304..0334720ff5 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -294,13 +294,18 @@ namespace Slic3r { // Toolchangeresult.gcode assumes the wipe tower corner is at the origin (except for priming lines) // We want to rotate and shift all extrusions (gcode postprocessing) and starting and ending position float alpha = m_wipe_tower_rotation / 180.f * float(M_PI); + + auto transform_wt_pt = [&alpha, this](const Vec2f& pt) -> Vec2f { + Vec2f out = Eigen::Rotation2Df(alpha) * pt; + out += m_wipe_tower_pos; + return out; + }; + Vec2f start_pos = tcr.start_pos; Vec2f end_pos = tcr.end_pos; if (!tcr.priming) { - start_pos = Eigen::Rotation2Df(alpha) * start_pos; - start_pos += m_wipe_tower_pos; - end_pos = Eigen::Rotation2Df(alpha) * end_pos; - end_pos += m_wipe_tower_pos; + start_pos = transform_wt_pt(start_pos); + end_pos = transform_wt_pt(end_pos); } Vec2f wipe_tower_offset = tcr.priming ? Vec2f::Zero() : m_wipe_tower_pos; @@ -403,7 +408,7 @@ namespace Slic3r { else { // Prepare a future wipe. - gcodegen.m_wipe.path.points.clear(); + /*gcodegen.m_wipe.path.points.clear(); if (new_extruder_id >= 0) { // Start the wipe at the current position. gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen, end_pos)); @@ -411,7 +416,10 @@ namespace Slic3r { gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen, Vec2f((std::abs(m_left - end_pos.x()) < std::abs(m_right - end_pos.x())) ? m_right : m_left, end_pos.y()))); - } + }*/ + gcodegen.m_wipe.reset_path(); + for (const Vec2f& wipe_pt : tcr.wipe_path) + gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen, transform_wt_pt(wipe_pt))); } // Let the planner know we are traveling between objects. diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index 0752b6dfcb..c5178eefa6 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -441,9 +441,26 @@ public: WipeTowerWriter& append(const std::string& text) { m_gcode += text; return *this; } + std::vector wipe_path() const + { + return m_wipe_path; + } + + WipeTowerWriter& add_wipe_point(const Vec2f& pt) + { + m_wipe_path.push_back(rotate(pt)); + return *this; + } + + WipeTowerWriter& add_wipe_point(float x, float y) + { + return add_wipe_point(Vec2f(x, y)); + } + private: Vec2f m_start_pos; Vec2f m_current_pos; + std::vector m_wipe_path; float m_current_z; float m_current_feedrate; size_t m_current_tool; @@ -790,7 +807,10 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool last_in_lay else { writer.rectangle(Vec2f::Zero(), m_wipe_tower_width, m_layer_info->depth + m_perimeter_width); if (layer_finished()) { // no finish_layer will be called, we must wipe the nozzle - writer.travel(writer.x()> m_wipe_tower_width / 2.f ? 0.f : m_wipe_tower_width, writer.y()); + //writer.travel(writer.x()> m_wipe_tower_width / 2.f ? 0.f : m_wipe_tower_width, writer.y()); + writer.add_wipe_point(writer.x(), writer.y()) + .add_wipe_point(writer.x()> m_wipe_tower_width / 2.f ? 0.f : m_wipe_tower_width, writer.y()); + } } } @@ -820,6 +840,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool last_in_lay result.extrusions = writer.extrusions(); result.start_pos = writer.start_pos_rotated(); result.end_pos = writer.pos_rotated(); + result.wipe_path = writer.wipe_path(); return result; } @@ -853,13 +874,20 @@ WipeTower::ToolChangeResult WipeTower::toolchange_Brim(bool sideOnly, float y_of for (size_t i = 0; i < 4; ++ i) { box.expand(spacing); writer.travel (box.ld, 7000) - .extrude(box.lu, 2100).extrude(box.ru) - .extrude(box.rd ).extrude(box.ld); + .extrude(box.lu, 2100).extrude(box.ru) + .extrude(box.rd ).extrude(box.ld); } - writer.travel(wipeTower_box.ld, 7000); // Move to the front left corner. - writer.travel(wipeTower_box.rd) // Always wipe the nozzle with a long wipe to reduce stringing when moving away from the wipe tower. - .travel(wipeTower_box.ld); + //writer.travel(wipeTower_box.ld, 7000); // Move to the front left corner. + //writer.travel(wipeTower_box.rd) // Always wipe the nozzle with a long wipe to reduce stringing when moving away from the wipe tower. + //.travel(wipeTower_box.ld); + + box.expand(-spacing); + writer.add_wipe_point(writer.x(), writer.y()) + .add_wipe_point(box.ld) + .add_wipe_point(box.rd); + + writer.append("; CP WIPE TOWER FIRST LAYER BRIM END\n" ";-----------------------------------\n"); @@ -884,6 +912,7 @@ WipeTower::ToolChangeResult WipeTower::toolchange_Brim(bool sideOnly, float y_of result.extrusions = writer.extrusions(); result.start_pos = writer.start_pos_rotated(); result.end_pos = writer.pos_rotated(); + result.wipe_path = writer.wipe_path(); return result; } @@ -1170,11 +1199,18 @@ void WipeTower::toolchange_Wipe( m_left_to_right = !m_left_to_right; } - // this is neither priming nor not the last toolchange on this layer - we are going back to the model - wipe the nozzle + // this is neither priming nor not the last toolchange on this layer - we are + // going back to the model - wipe the nozzle. if (m_layer_info != m_plan.end() && m_current_tool != m_layer_info->tool_changes.back().new_tool) { m_left_to_right = !m_left_to_right; - writer.travel(writer.x(), writer.y() - dy) - .travel(m_left_to_right ? m_wipe_tower_width : 0.f, writer.y()); + //writer.comment_with_value("starting wipe tower wipe ", 0) + // .travel(writer.x(), writer.y() - dy) + // .travel(m_left_to_right ? m_wipe_tower_width : 0.f, writer.y()) + // .comment_with_value("finished wipe tower wipe ", 0); + writer.add_wipe_point(writer.x(), writer.y()) + .add_wipe_point(writer.x(), writer.y() - dy) + .add_wipe_point(m_left_to_right ? m_wipe_tower_width : 0.f, writer.y() - dy); + } writer.set_extrusion_flow(m_extrusion_flow); // Reset the extrusion flow. @@ -1238,7 +1274,9 @@ WipeTower::ToolChangeResult WipeTower::finish_layer() writer.extrude(box.rd.x() - m_perimeter_width / 2.f, writer.y() + 0.5f * step); writer.extrude(box.ld.x() + m_perimeter_width / 2.f, writer.y()); } - writer.travel(box.rd.x()-m_perimeter_width/2.f,writer.y()); // wipe the nozzle + //writer.travel(box.rd.x()-m_perimeter_width/2.f,writer.y()); // wipe the nozzle + writer.add_wipe_point(writer.x(), writer.y()) + .add_wipe_point(box.rd.x()-m_perimeter_width/2.f,writer.y()); } else { // Extrude a sparse infill to support the material to be printed above. const float dy = (fill_box.lu.y() - fill_box.ld.y() - m_perimeter_width); @@ -1257,10 +1295,15 @@ WipeTower::ToolChangeResult WipeTower::finish_layer() writer.travel(x,writer.y()); writer.extrude(x,i%2 ? fill_box.rd.y() : fill_box.ru.y()); } - writer.travel(left,writer.y(),7200); // wipes the nozzle before moving away from the wipe tower + writer.add_wipe_point(Vec2f(writer.x(), writer.y())) + .add_wipe_point(Vec2f(left, writer.y())); + //writer.travel(left,writer.y(),7200); // wipes the nozzle before moving away from the wipe tower + } + else { + writer.add_wipe_point(Vec2f(writer.x(), writer.y())) + .add_wipe_point(Vec2f(right, writer.y())); + // writer.travel(right,writer.y(),7200); // wipes the nozzle before moving away from the wipe tower } - else - writer.travel(right,writer.y(),7200); // wipes the nozzle before moving away from the wipe tower } writer.append("; CP EMPTY GRID END\n" ";------------------\n\n\n\n\n\n\n"); @@ -1285,6 +1328,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer() result.extrusions = writer.extrusions(); result.start_pos = writer.start_pos_rotated(); result.end_pos = writer.pos_rotated(); + result.wipe_path = writer.wipe_path(); return result; } @@ -1432,6 +1476,7 @@ void WipeTower::generate(std::vector> & last_toolchange.gcode += finish_layer_toolchange.gcode; last_toolchange.extrusions.insert(last_toolchange.extrusions.end(), finish_layer_toolchange.extrusions.begin(), finish_layer_toolchange.extrusions.end()); last_toolchange.end_pos = finish_layer_toolchange.end_pos; + last_toolchange.wipe_path = finish_layer_toolchange.wipe_path; } else layer_result.emplace_back(std::move(finish_layer_toolchange)); diff --git a/src/libslic3r/GCode/WipeTower.hpp b/src/libslic3r/GCode/WipeTower.hpp index f353151575..e4b44e2bbd 100644 --- a/src/libslic3r/GCode/WipeTower.hpp +++ b/src/libslic3r/GCode/WipeTower.hpp @@ -57,6 +57,13 @@ public: // Is this a priming extrusion? (If so, the wipe tower rotation & translation will not be applied later) bool priming; + // Pass a polyline so that normal G-code generator can do a wipe for us. + // The wipe cannot be done by the wipe tower because it has to pass back + // a loaded extruder, so it would have to either do a wipe with no retraction + // (leading to https://github.com/prusa3d/PrusaSlicer/issues/2834) or do + // an extra retraction-unretraction pair. + std::vector wipe_path; + // Initial tool int initial_tool;