Prusa Slicer 2.6.0
Loading...
Searching...
No Matches
Slic3r::WipeTowerIntegration Class Reference

#include <src/libslic3r/GCode.hpp>

+ Collaboration diagram for Slic3r::WipeTowerIntegration:

Public Member Functions

 WipeTowerIntegration (const PrintConfig &print_config, const std::vector< WipeTower::ToolChangeResult > &priming, const std::vector< std::vector< WipeTower::ToolChangeResult > > &tool_changes, const WipeTower::ToolChangeResult &final_purge)
 
std::string prime (GCode &gcodegen)
 
void next_layer ()
 
std::string tool_change (GCode &gcodegen, int extruder_id, bool finish_layer)
 
std::string finalize (GCode &gcodegen)
 
std::vector< float > used_filament_length () const
 

Private Member Functions

WipeTowerIntegrationoperator= (const WipeTowerIntegration &)
 
std::string append_tcr (GCode &gcodegen, const WipeTower::ToolChangeResult &tcr, int new_extruder_id, double z=-1.) const
 
std::string post_process_wipe_tower_moves (const WipeTower::ToolChangeResult &tcr, const Vec2f &translation, float angle) const
 

Private Attributes

const float m_left
 
const float m_right
 
const Vec2f m_wipe_tower_pos
 
const float m_wipe_tower_rotation
 
const std::vector< Vec2dm_extruder_offsets
 
const std::vector< WipeTower::ToolChangeResult > & m_priming
 
const std::vector< std::vector< WipeTower::ToolChangeResult > > & m_tool_changes
 
const WipeTower::ToolChangeResultm_final_purge
 
int m_layer_idx
 
int m_tool_change_idx
 
double m_last_wipe_tower_print_z = 0.f
 

Detailed Description

Constructor & Destructor Documentation

◆ WipeTowerIntegration()

Slic3r::WipeTowerIntegration::WipeTowerIntegration ( const PrintConfig &  print_config,
const std::vector< WipeTower::ToolChangeResult > &  priming,
const std::vector< std::vector< WipeTower::ToolChangeResult > > &  tool_changes,
const WipeTower::ToolChangeResult final_purge 
)
inline
68 :
69 m_left(/*float(print_config.wipe_tower_x.value)*/ 0.f),
70 m_right(float(/*print_config.wipe_tower_x.value +*/ print_config.wipe_tower_width.value)),
71 m_wipe_tower_pos(float(print_config.wipe_tower_x.value), float(print_config.wipe_tower_y.value)),
72 m_wipe_tower_rotation(float(print_config.wipe_tower_rotation_angle)),
73 m_extruder_offsets(print_config.extruder_offset.values),
74 m_priming(priming),
75 m_tool_changes(tool_changes),
76 m_final_purge(final_purge),
77 m_layer_idx(-1),
79 {}
const float m_right
Definition GCode.hpp:96
int m_layer_idx
Definition GCode.hpp:106
const float m_left
Definition GCode.hpp:95
const std::vector< Vec2d > m_extruder_offsets
Definition GCode.hpp:99
const float m_wipe_tower_rotation
Definition GCode.hpp:98
int m_tool_change_idx
Definition GCode.hpp:107
const Vec2f m_wipe_tower_pos
Definition GCode.hpp:97
const WipeTower::ToolChangeResult & m_final_purge
Definition GCode.hpp:104
const std::vector< WipeTower::ToolChangeResult > & m_priming
Definition GCode.hpp:102
const std::vector< std::vector< WipeTower::ToolChangeResult > > & m_tool_changes
Definition GCode.hpp:103

Member Function Documentation

◆ append_tcr()

std::string Slic3r::WipeTowerIntegration::append_tcr ( GCode gcodegen,
const WipeTower::ToolChangeResult tcr,
int  new_extruder_id,
double  z = -1. 
) const
private
206 {
207 if (new_extruder_id != -1 && new_extruder_id != tcr.new_tool)
208 throw Slic3r::InvalidArgument("Error: WipeTowerIntegration::append_tcr was asked to do a toolchange it didn't expect.");
209
210 std::string gcode;
211
212 // Toolchangeresult.gcode assumes the wipe tower corner is at the origin (except for priming lines)
213 // We want to rotate and shift all extrusions (gcode postprocessing) and starting and ending position
214 float alpha = m_wipe_tower_rotation / 180.f * float(M_PI);
215
216 auto transform_wt_pt = [&alpha, this](const Vec2f& pt) -> Vec2f {
217 Vec2f out = Eigen::Rotation2Df(alpha) * pt;
218 out += m_wipe_tower_pos;
219 return out;
220 };
221
222 Vec2f start_pos = tcr.start_pos;
223 Vec2f end_pos = tcr.end_pos;
224 if (! tcr.priming) {
225 start_pos = transform_wt_pt(start_pos);
226 end_pos = transform_wt_pt(end_pos);
227 }
228
229 Vec2f wipe_tower_offset = tcr.priming ? Vec2f::Zero() : m_wipe_tower_pos;
230 float wipe_tower_rotation = tcr.priming ? 0.f : alpha;
231
232 std::string tcr_rotated_gcode = post_process_wipe_tower_moves(tcr, wipe_tower_offset, wipe_tower_rotation);
233
234 gcode += gcodegen.writer().unlift(); // Make sure there is no z-hop (in most cases, there isn't).
235
236 double current_z = gcodegen.writer().get_position().z();
237 if (z == -1.) // in case no specific z was provided, print at current_z pos
238 z = current_z;
239
240 const bool needs_toolchange = gcodegen.writer().need_toolchange(new_extruder_id);
241 const bool will_go_down = ! is_approx(z, current_z);
242 if (tcr.force_travel || ! needs_toolchange || (gcodegen.config().single_extruder_multi_material && ! tcr.priming)) {
243 // Move over the wipe tower. If this is not single-extruder MM, the first wipe tower move following the
244 // toolchange will travel there anyway (if there is a toolchange).
245 // FIXME: It would be better if the wipe tower set the force_travel flag for all toolchanges,
246 // then we could simplify the condition and make it more readable.
247 gcode += gcodegen.retract();
248 gcodegen.m_avoid_crossing_perimeters.use_external_mp_once();
249 gcode += gcodegen.travel_to(
250 wipe_tower_point_to_object_point(gcodegen, start_pos),
252 "Travel to a Wipe Tower");
253 gcode += gcodegen.unretract();
254 }
255
256 if (will_go_down) {
257 gcode += gcodegen.writer().retract();
258 gcode += gcodegen.writer().travel_to_z(z, "Travel down to the last wipe tower layer.");
259 gcode += gcodegen.writer().unretract();
260 }
261
262 std::string toolchange_gcode_str;
263 std::string deretraction_str;
264 if (tcr.priming || (new_extruder_id >= 0 && needs_toolchange)) {
265 if (gcodegen.config().single_extruder_multi_material)
266 gcodegen.m_wipe.reset_path(); // We don't want wiping on the ramming lines.
267 toolchange_gcode_str = gcodegen.set_extruder(new_extruder_id, tcr.print_z); // TODO: toolchange_z vs print_z
268 if (gcodegen.config().wipe_tower)
269 deretraction_str = gcodegen.unretract();
270 }
271
272
273
274
275 // Insert the toolchange and deretraction gcode into the generated gcode.
276 DynamicConfig config;
277 config.set_key_value("toolchange_gcode", new ConfigOptionString(toolchange_gcode_str));
278 config.set_key_value("deretraction_from_wipe_tower_generator", new ConfigOptionString(deretraction_str));
279 std::string tcr_gcode, tcr_escaped_gcode = gcodegen.placeholder_parser_process("tcr_rotated_gcode", tcr_rotated_gcode, new_extruder_id, &config);
280 unescape_string_cstyle(tcr_escaped_gcode, tcr_gcode);
281 gcode += tcr_gcode;
282 check_add_eol(toolchange_gcode_str);
283
284 // A phony move to the end position at the wipe tower.
285 gcodegen.writer().travel_to_xy(end_pos.cast<double>());
286 gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, end_pos));
287 if (!is_approx(z, current_z)) {
288 gcode += gcodegen.writer().retract();
289 gcode += gcodegen.writer().travel_to_z(current_z, "Travel back up to the topmost object layer.");
290 gcode += gcodegen.writer().unretract();
291 }
292
293 else {
294 // Prepare a future wipe.
295 gcodegen.m_wipe.reset_path();
296 for (const Vec2f& wipe_pt : tcr.wipe_path)
297 gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen, transform_wt_pt(wipe_pt)));
298 }
299
300 // Let the planner know we are traveling between objects.
301 gcodegen.m_avoid_crossing_perimeters.use_external_mp_once();
302 return gcode;
303 }
#define M_PI
Definition ExtrusionSimulator.cpp:20
std::string post_process_wipe_tower_moves(const WipeTower::ToolChangeResult &tcr, const Vec2f &translation, float angle) const
Definition GCode.cpp:307
Rotation2D< float > Rotation2Df
Definition Rotation2D.h:165
static Point wipe_tower_point_to_object_point(GCode &gcodegen, const Vec2f &wipe_tower_pt)
Definition GCode.cpp:200
constexpr bool is_approx(Number value, Number test_value, Number precision=EPSILON)
Definition libslic3r.h:271
Eigen::Matrix< float, 2, 1, Eigen::DontAlign > Vec2f
Definition Point.hpp:48
bool unescape_string_cstyle(const std::string &str, std::string &str_out)
Definition Config.cpp:107
static void check_add_eol(std::string &gcode)
Definition GCode.cpp:75
static constexpr const ExtrusionRoleModifiers Mixed
Definition ExtrusionRole.hpp:79

References Slic3r::check_add_eol(), Slic3r::GCode::config(), Slic3r::WipeTower::ToolChangeResult::end_pos, Slic3r::WipeTower::ToolChangeResult::force_travel, Slic3r::GCodeWriter::get_position(), Slic3r::is_approx(), Slic3r::GCode::m_avoid_crossing_perimeters, M_PI, Slic3r::GCode::m_wipe, m_wipe_tower_pos, m_wipe_tower_rotation, Slic3r::ExtrusionRole::Mixed, Slic3r::GCodeWriter::need_toolchange(), Slic3r::WipeTower::ToolChangeResult::new_tool, Slic3r::Wipe::path, Slic3r::GCode::placeholder_parser_process(), Slic3r::MultiPoint::points, post_process_wipe_tower_moves(), Slic3r::WipeTower::ToolChangeResult::priming, Slic3r::WipeTower::ToolChangeResult::print_z, Slic3r::Wipe::reset_path(), Slic3r::GCodeWriter::retract(), Slic3r::GCode::retract(), Slic3r::GCode::set_extruder(), Slic3r::DynamicConfig::set_key_value(), Slic3r::GCode::set_last_pos(), Slic3r::WipeTower::ToolChangeResult::start_pos, Slic3r::GCode::travel_to(), Slic3r::GCodeWriter::travel_to_xy(), Slic3r::GCodeWriter::travel_to_z(), Slic3r::unescape_string_cstyle(), Slic3r::GCodeWriter::unlift(), Slic3r::GCode::unretract(), Slic3r::GCodeWriter::unretract(), Slic3r::AvoidCrossingPerimeters::use_external_mp_once(), Slic3r::WipeTower::ToolChangeResult::wipe_path, Slic3r::wipe_tower_point_to_object_point(), and Slic3r::GCode::writer().

Referenced by finalize(), prime(), and tool_change().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ finalize()

std::string Slic3r::WipeTowerIntegration::finalize ( GCode gcodegen)
424 {
425 std::string gcode;
426 if (std::abs(gcodegen.writer().get_position().z() - m_final_purge.print_z) > EPSILON)
427 gcode += gcodegen.change_layer(m_final_purge.print_z);
428 gcode += append_tcr(gcodegen, m_final_purge, -1);
429 return gcode;
430 }
std::string append_tcr(GCode &gcodegen, const WipeTower::ToolChangeResult &tcr, int new_extruder_id, double z=-1.) const
Definition GCode.cpp:205
static constexpr double EPSILON
Definition libslic3r.h:51
float print_z
Definition WipeTower.hpp:43

References append_tcr(), Slic3r::GCode::change_layer(), EPSILON, Slic3r::GCodeWriter::get_position(), m_final_purge, Slic3r::WipeTower::ToolChangeResult::print_z, and Slic3r::GCode::writer().

+ Here is the call graph for this function:

◆ next_layer()

void Slic3r::WipeTowerIntegration::next_layer ( )
inline

◆ operator=()

WipeTowerIntegration & Slic3r::WipeTowerIntegration::operator= ( const WipeTowerIntegration )
private

◆ post_process_wipe_tower_moves()

std::string Slic3r::WipeTowerIntegration::post_process_wipe_tower_moves ( const WipeTower::ToolChangeResult tcr,
const Vec2f translation,
float  angle 
) const
private
308 {
309 Vec2f extruder_offset = m_extruder_offsets[tcr.initial_tool].cast<float>();
310
311 std::istringstream gcode_str(tcr.gcode);
312 std::string gcode_out;
313 std::string line;
314 Vec2f pos = tcr.start_pos;
315 Vec2f transformed_pos = Eigen::Rotation2Df(angle) * pos + translation;
316 Vec2f old_pos(-1000.1f, -1000.1f);
317
318 while (gcode_str) {
319 std::getline(gcode_str, line); // we read the gcode line by line
320
321 // All G1 commands should be translated and rotated. X and Y coords are
322 // only pushed to the output when they differ from last time.
323 // WT generator can override this by appending the never_skip_tag
324 if (boost::starts_with(line, "G1 ")) {
325 bool never_skip = false;
326 auto it = line.find(WipeTower::never_skip_tag());
327 if (it != std::string::npos) {
328 // remove the tag and remember we saw it
329 never_skip = true;
330 line.erase(it, it + WipeTower::never_skip_tag().size());
331 }
332 std::ostringstream line_out;
333 std::istringstream line_str(line);
334 line_str >> std::noskipws; // don't skip whitespace
335 char ch = 0;
336 line_str >> ch >> ch; // read the "G1"
337 while (line_str >> ch) {
338 if (ch == 'X' || ch == 'Y')
339 line_str >> (ch == 'X' ? pos.x() : pos.y());
340 else
341 line_out << ch;
342 }
343
344 transformed_pos = Eigen::Rotation2Df(angle) * pos + translation;
345
346 if (transformed_pos != old_pos || never_skip) {
347 line = line_out.str();
348 boost::trim_left(line); // Remove leading spaces
349 std::ostringstream oss;
350 oss << std::fixed << std::setprecision(3) << "G1";
351 if (transformed_pos.x() != old_pos.x() || never_skip)
352 oss << " X" << transformed_pos.x() - extruder_offset.x();
353 if (transformed_pos.y() != old_pos.y() || never_skip)
354 oss << " Y" << transformed_pos.y() - extruder_offset.y();
355 if (! line.empty())
356 oss << " ";
357 line = oss.str() + line;
358 old_pos = transformed_pos;
359 }
360 }
361
362 gcode_out += line + "\n";
363
364 // If this was a toolchange command, we should change current extruder offset
365 if (line == "[toolchange_gcode]") {
366 extruder_offset = m_extruder_offsets[tcr.new_tool].cast<float>();
367
368 // If the extruder offset changed, add an extra move so everything is continuous
369 if (extruder_offset != m_extruder_offsets[tcr.initial_tool].cast<float>()) {
370 std::ostringstream oss;
371 oss << std::fixed << std::setprecision(3)
372 << "G1 X" << transformed_pos.x() - extruder_offset.x()
373 << " Y" << transformed_pos.y() - extruder_offset.y()
374 << "\n";
375 gcode_out += oss.str();
376 }
377 }
378 }
379 return gcode_out;
380 }
static const std::string never_skip_tag()
Definition WipeTower.hpp:24
Vec3d pos(const Pt &p)
Definition ReprojectPointsOnMesh.hpp:14
double angle(const Eigen::MatrixBase< Derived > &v1, const Eigen::MatrixBase< Derived2 > &v2)
Definition Point.hpp:112
constexpr auto size(const C &c) -> decltype(c.size())
Definition span.hpp:183

References Slic3r::angle(), Slic3r::WipeTower::ToolChangeResult::gcode, Slic3r::WipeTower::ToolChangeResult::initial_tool, m_extruder_offsets, Slic3r::WipeTower::never_skip_tag(), Slic3r::WipeTower::ToolChangeResult::new_tool, and Slic3r::WipeTower::ToolChangeResult::start_pos.

Referenced by append_tcr().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ prime()

std::string Slic3r::WipeTowerIntegration::prime ( GCode gcodegen)
384 {
385 std::string gcode;
386 for (const WipeTower::ToolChangeResult& tcr : m_priming) {
387 if (! tcr.extrusions.empty())
388 gcode += append_tcr(gcodegen, tcr, tcr.new_tool);
389 }
390 return gcode;
391 }

References append_tcr(), and m_priming.

+ Here is the call graph for this function:

◆ tool_change()

std::string Slic3r::WipeTowerIntegration::tool_change ( GCode gcodegen,
int  extruder_id,
bool  finish_layer 
)
394 {
395 std::string gcode;
396 assert(m_layer_idx >= 0);
397 if (gcodegen.writer().need_toolchange(extruder_id) || finish_layer) {
398 if (m_layer_idx < (int)m_tool_changes.size()) {
400 throw Slic3r::RuntimeError("Wipe tower generation failed, possibly due to empty first layer.");
401
402 // Calculate where the wipe tower layer will be printed. -1 means that print z will not change,
403 // resulting in a wipe tower with sparse layers.
404 double wipe_tower_z = -1;
405 bool ignore_sparse = false;
406 if (gcodegen.config().wipe_tower_no_sparse_layers.value) {
407 wipe_tower_z = m_last_wipe_tower_print_z;
408 ignore_sparse = (m_tool_changes[m_layer_idx].size() == 1 && m_tool_changes[m_layer_idx].front().initial_tool == m_tool_changes[m_layer_idx].front().new_tool && m_layer_idx != 0);
409 if (m_tool_change_idx == 0 && !ignore_sparse)
410 wipe_tower_z = m_last_wipe_tower_print_z + m_tool_changes[m_layer_idx].front().layer_height;
411 }
412
413 if (!ignore_sparse) {
414 gcode += append_tcr(gcodegen, m_tool_changes[m_layer_idx][m_tool_change_idx++], extruder_id, wipe_tower_z);
415 m_last_wipe_tower_print_z = wipe_tower_z;
416 }
417 }
418 }
419 return gcode;
420 }
double m_last_wipe_tower_print_z
Definition GCode.hpp:108

References append_tcr(), Slic3r::GCode::config(), m_last_wipe_tower_print_z, m_layer_idx, m_tool_change_idx, m_tool_changes, Slic3r::GCodeWriter::need_toolchange(), and Slic3r::GCode::writer().

+ Here is the call graph for this function:

◆ used_filament_length()

std::vector< float > Slic3r::WipeTowerIntegration::used_filament_length ( ) const

Member Data Documentation

◆ m_extruder_offsets

const std::vector<Vec2d> Slic3r::WipeTowerIntegration::m_extruder_offsets
private

◆ m_final_purge

const WipeTower::ToolChangeResult& Slic3r::WipeTowerIntegration::m_final_purge
private

Referenced by finalize().

◆ m_last_wipe_tower_print_z

double Slic3r::WipeTowerIntegration::m_last_wipe_tower_print_z = 0.f
private

Referenced by tool_change().

◆ m_layer_idx

int Slic3r::WipeTowerIntegration::m_layer_idx
private

Referenced by next_layer(), and tool_change().

◆ m_left

const float Slic3r::WipeTowerIntegration::m_left
private

◆ m_priming

const std::vector<WipeTower::ToolChangeResult>& Slic3r::WipeTowerIntegration::m_priming
private

Referenced by prime().

◆ m_right

const float Slic3r::WipeTowerIntegration::m_right
private

◆ m_tool_change_idx

int Slic3r::WipeTowerIntegration::m_tool_change_idx
private

Referenced by next_layer(), and tool_change().

◆ m_tool_changes

const std::vector<std::vector<WipeTower::ToolChangeResult> >& Slic3r::WipeTowerIntegration::m_tool_changes
private

Referenced by tool_change().

◆ m_wipe_tower_pos

const Vec2f Slic3r::WipeTowerIntegration::m_wipe_tower_pos
private

Referenced by append_tcr().

◆ m_wipe_tower_rotation

const float Slic3r::WipeTowerIntegration::m_wipe_tower_rotation
private

Referenced by append_tcr().


The documentation for this class was generated from the following files: