1 //Copyright (c) 2018 Ultimaker B.V.
2 //CuraEngine is released under the terms of the AGPLv3 or higher.
3
4 #include <cmath> // sqrt
5 #include <fstream> // debug IO
6
7 #include "Application.h" //To get the communication channel.
8 #include "ExtruderTrain.h"
9 #include "pathOrderOptimizer.h" //For skirt/brim.
10 #include "PrintFeature.h"
11 #include "Slice.h"
12 #include "weaveDataStorage.h"
13 #include "Weaver.h"
14 #include "Wireframe2gcode.h"
15 #include "communication/Communication.h" //To write g-code output.
16 #include "progress/Progress.h"
17 #include "utils/math.h"
18 #include "utils/logoutput.h"
19
20 namespace cura
21 {
22
23
writeGCode()24 void Wireframe2gcode::writeGCode()
25 {
26 Settings& scene_settings = Application::getInstance().current_slice->scene.settings;
27 const size_t start_extruder_nr = scene_settings.get<ExtruderTrain&>("adhesion_extruder_nr").extruder_nr; // TODO: figure out how Wireframe works with dual extrusion
28 gcode.preSetup(start_extruder_nr);
29 gcode.setInitialAndBuildVolumeTemps(start_extruder_nr);
30
31 Application::getInstance().communication->beginGCode();
32
33 processStartingCode();
34
35 int maxObjectHeight;
36 if (wireFrame.layers.empty())
37 {
38 maxObjectHeight = 0;
39 }
40 else
41 {
42 maxObjectHeight = wireFrame.layers.back().z1;
43 }
44
45 gcode.setZ(initial_layer_thickness);
46
47 processSkirt();
48
49 unsigned int total_layers = wireFrame.layers.size();
50 gcode.writeLayerComment(0);
51 gcode.writeTypeComment(PrintFeatureType::SkirtBrim);
52
53 for (PolygonRef bottom_part : wireFrame.bottom_infill.roof_outlines)
54 {
55 if (bottom_part.size() == 0) continue;
56 writeMoveWithRetract(bottom_part[bottom_part.size()-1]);
57 for (Point& segment_to : bottom_part)
58 {
59 gcode.writeExtrusion(segment_to, speedBottom, extrusion_mm3_per_mm_flat, PrintFeatureType::Skin);
60 }
61 }
62
63
64
65 // bottom:
66 Polygons empty_outlines;
67 writeFill(wireFrame.bottom_infill.roof_insets, empty_outlines,
68 [this](Wireframe2gcode&, WeaveConnectionPart& part, unsigned int segment_idx) {
69 WeaveConnectionSegment& segment = part.connection.segments[segment_idx];
70 if (segment.segmentType == WeaveSegmentType::MOVE || segment.segmentType == WeaveSegmentType::DOWN_AND_FLAT) // this is the case when an inset overlaps with a hole
71 {
72 writeMoveWithRetract(segment.to);
73 } else
74 {
75 gcode.writeExtrusion(segment.to, speedBottom, extrusion_mm3_per_mm_connection, PrintFeatureType::Skin);
76 }
77 }
78 ,
79 [this](Wireframe2gcode&, WeaveConnectionSegment& segment) {
80 if (segment.segmentType == WeaveSegmentType::MOVE)
81 writeMoveWithRetract(segment.to);
82 else if (segment.segmentType == WeaveSegmentType::DOWN_AND_FLAT)
83 return; // do nothing
84 else
85 gcode.writeExtrusion(segment.to, speedBottom, extrusion_mm3_per_mm_flat, PrintFeatureType::Skin);
86 }
87 );
88 Progress::messageProgressStage(Progress::Stage::EXPORT, nullptr);
89 for (LayerIndex layer_nr = 0; layer_nr < static_cast<LayerIndex>(wireFrame.layers.size()); layer_nr++)
90 {
91 Progress::messageProgress(Progress::Stage::EXPORT, layer_nr+1, total_layers); // abuse the progress system of the normal mode of CuraEngine
92
93 WeaveLayer& layer = wireFrame.layers[layer_nr];
94
95 gcode.writeLayerComment(layer_nr+1);
96
97 double fanSpeed = scene_settings.get<Ratio>("cool_fan_speed_max") * 100.0;
98 if (layer_nr == 0)
99 {
100 fanSpeed = scene_settings.get<Ratio>("cool_fan_speed_min") * 100.0;
101 }
102 gcode.writeFanCommand(fanSpeed);
103
104 for (size_t part_nr = 0; part_nr < layer.connections.size(); part_nr++)
105 {
106 WeaveConnectionPart& part = layer.connections[part_nr];
107
108 if (part.connection.segments.size() == 0) continue;
109
110 gcode.writeTypeComment(PrintFeatureType::Support); // connection
111 {
112 if (vSize2(gcode.getPositionXY() - part.connection.from) > connectionHeight)
113 {
114 Point3 point_same_height(part.connection.from.x, part.connection.from.y, layer.z1+100);
115 writeMoveWithRetract(point_same_height);
116 }
117 writeMoveWithRetract(part.connection.from);
118 for (size_t segment_idx = 0; segment_idx < part.connection.segments.size(); segment_idx++)
119 {
120 handle_segment(part, segment_idx);
121 }
122 }
123
124
125
126 gcode.writeTypeComment(PrintFeatureType::OuterWall); // top
127 {
128 for (WeaveConnectionSegment& segment : part.connection.segments)
129 {
130 if (segment.segmentType == WeaveSegmentType::DOWN)
131 {
132 continue;
133 }
134 if (segment.segmentType == WeaveSegmentType::MOVE)
135 {
136 writeMoveWithRetract(segment.to);
137 }
138 else
139 {
140 gcode.writeExtrusion(segment.to, speedFlat, extrusion_mm3_per_mm_flat, PrintFeatureType::OuterWall);
141 gcode.writeDelay(flat_delay);
142 }
143 }
144 }
145 }
146
147 // roofs:
148 gcode.setZ(layer.z1);
149 std::function<void (Wireframe2gcode&, WeaveConnectionPart& part, unsigned int segment_idx)>
150 handle_roof = &Wireframe2gcode::handle_roof_segment;
151 writeFill(layer.roofs.roof_insets, layer.roofs.roof_outlines,
152 handle_roof,
153 [this](Wireframe2gcode&, WeaveConnectionSegment& segment) { // handle flat segments
154 if (segment.segmentType == WeaveSegmentType::MOVE)
155 {
156 writeMoveWithRetract(segment.to);
157 } else if (segment.segmentType == WeaveSegmentType::DOWN_AND_FLAT)
158 {
159 // do nothing
160 } else
161 {
162 gcode.writeExtrusion(segment.to, speedFlat, extrusion_mm3_per_mm_flat, PrintFeatureType::Skin);
163 gcode.writeDelay(flat_delay);
164 }
165 });
166
167
168
169 }
170
171 gcode.setZ(maxObjectHeight);
172
173 gcode.writeRetraction(standard_retraction_config);
174
175
176 gcode.updateTotalPrintTime();
177
178 gcode.writeDelay(0.3);
179
180 gcode.writeFanCommand(0);
181
182 finalize();
183 }
184
185
go_down(WeaveConnectionPart & part,unsigned int segment_idx)186 void Wireframe2gcode::go_down(WeaveConnectionPart& part, unsigned int segment_idx)
187 {
188 WeaveConnectionSegment& segment = part.connection.segments[segment_idx];
189 Point3 from = (segment_idx == 0)? part.connection.from : part.connection.segments[segment_idx - 1].to;
190 if (go_back_to_last_top)
191 gcode.writeTravel(from, speedDown);
192 if (straight_first_when_going_down <= 0)
193 {
194 gcode.writeExtrusion(segment.to, speedDown, extrusion_mm3_per_mm_connection, PrintFeatureType::OuterWall);
195 } else
196 {
197 Point3& to = segment.to;
198 Point3 from = gcode.getPosition();// segment.from;
199 Point3 vec = to - from;
200 Point3 in_between = from + vec * static_cast<double>(straight_first_when_going_down);
201
202 Point3 up(in_between.x, in_between.y, from.z);
203 int64_t new_length = (up - from).vSize() + (to - up).vSize() + 5;
204 int64_t orr_length = vec.vSize();
205 double enlargement = new_length / orr_length;
206 gcode.writeExtrusion(up, speedDown*enlargement, extrusion_mm3_per_mm_connection / enlargement, PrintFeatureType::OuterWall);
207 gcode.writeExtrusion(to, speedDown*enlargement, extrusion_mm3_per_mm_connection / enlargement, PrintFeatureType::OuterWall);
208 }
209 gcode.writeDelay(bottom_delay);
210 if (up_dist_half_speed > 0)
211 {
212
213 gcode.writeExtrusion(Point3(0,0,up_dist_half_speed) + gcode.getPosition(), speedUp / 2, extrusion_mm3_per_mm_connection * 2, PrintFeatureType::OuterWall);
214 }
215 }
216
217
218
strategy_knot(WeaveConnectionPart & part,unsigned int segment_idx)219 void Wireframe2gcode::strategy_knot(WeaveConnectionPart& part, unsigned int segment_idx)
220 {
221 WeaveConnectionSegment& segment = part.connection.segments[segment_idx];
222 gcode.writeExtrusion(segment.to, speedUp, extrusion_mm3_per_mm_connection, PrintFeatureType::OuterWall);
223 Point3 next_vector;
224 if (segment_idx + 1 < part.connection.segments.size())
225 {
226 WeaveConnectionSegment& next_segment = part.connection.segments[segment_idx+1];
227 next_vector = next_segment.to - segment.to;
228 } else
229 {
230 next_vector = part.connection.segments[0].to - segment.to;
231 }
232 Point next_dir_2D(next_vector.x, next_vector.y);
233 next_dir_2D = next_dir_2D * top_jump_dist / vSize(next_dir_2D);
234 Point3 next_dir (next_dir_2D.X / 2, next_dir_2D.Y / 2, -top_jump_dist);
235
236 Point3 current_pos = gcode.getPosition();
237
238 gcode.writeTravel(current_pos - next_dir, speedUp);
239 gcode.writeDelay(top_delay);
240 gcode.writeTravel(current_pos + next_dir_2D, speedUp);
241 }
242
strategy_retract(WeaveConnectionPart & part,unsigned int segment_idx)243 void Wireframe2gcode::strategy_retract(WeaveConnectionPart& part, unsigned int segment_idx)
244 {
245 WeaveConnectionSegment& segment = part.connection.segments[segment_idx];
246 Point3 from = (segment_idx == 0)? part.connection.from : part.connection.segments[segment_idx - 1].to;
247
248 Settings& scene_settings = Application::getInstance().current_slice->scene.settings;
249 RetractionConfig retraction_config;
250 // TODO: get these from the settings!
251 retraction_config.distance = 500; //INT2MM(getSettingInt("retraction_amount"))
252 retraction_config.prime_volume = 0;//INT2MM(getSettingInt("retractionPrime
253 retraction_config.speed = 20; // 40;
254 retraction_config.primeSpeed = 15; // 30;
255 retraction_config.zHop = 0; //getSettingInt("retraction_hop");
256 retraction_config.retraction_count_max = scene_settings.get<size_t>("retraction_count_max");
257 retraction_config.retraction_extrusion_window = scene_settings.get<double>("retraction_extrusion_window"); //Window in which to count retractions in mm of extruded filament.
258 retraction_config.retraction_min_travel_distance = scene_settings.get<coord_t>("retraction_min_travel");
259
260 double top_retract_pause = 2.0;
261 int retract_hop_dist = 1000;
262 bool after_retract_hop = false;
263 //bool go_horizontal_first = true;
264 bool lower_retract_start = true;
265
266 Point3& to = segment.to;
267 if (lower_retract_start)
268 {
269 Point3 vec = to - from;
270 Point3 lowering = vec * retract_hop_dist / 2 / vec.vSize();
271 Point3 lower = to - lowering;
272 gcode.writeExtrusion(lower, speedUp, extrusion_mm3_per_mm_connection, PrintFeatureType::OuterWall);
273 gcode.writeRetraction(retraction_config);
274 gcode.writeTravel(to + lowering, speedUp);
275 gcode.writeDelay(top_retract_pause);
276 if (after_retract_hop)
277 {
278 gcode.writeTravel(to + Point3(0, 0, retract_hop_dist), speedFlat);
279 }
280 }
281 else
282 {
283 gcode.writeExtrusion(to, speedUp, extrusion_mm3_per_mm_connection, PrintFeatureType::OuterWall);
284 gcode.writeRetraction(retraction_config);
285 gcode.writeTravel(to + Point3(0, 0, retract_hop_dist), speedFlat);
286 gcode.writeDelay(top_retract_pause);
287 if (after_retract_hop)
288 {
289 gcode.writeTravel(to + Point3(0, 0, retract_hop_dist*3), speedFlat);
290 }
291 }
292 }
293
strategy_compensate(WeaveConnectionPart & part,unsigned int segment_idx)294 void Wireframe2gcode::strategy_compensate(WeaveConnectionPart& part, unsigned int segment_idx)
295 {
296 WeaveConnectionSegment& segment = part.connection.segments[segment_idx];
297 Point3 from = (segment_idx == 0)? part.connection.from : part.connection.segments[segment_idx - 1].to;
298 Point3 to = segment.to + Point3(0, 0, fall_down*(segment.to - from).vSize() / connectionHeight);
299 Point3 vector = segment.to - from;
300 Point3 dir = vector * drag_along / vector.vSize();
301
302 Point3 next_point;
303 if (segment_idx + 1 < part.connection.segments.size())
304 {
305 WeaveConnectionSegment& next_segment = part.connection.segments[segment_idx+1];
306 next_point = next_segment.to;
307 } else
308 {
309 next_point = part.connection.segments[0].to;
310 }
311 Point3 next_vector = next_point - segment.to;
312 Point next_dir_2D(next_vector.x, next_vector.y);
313 int64_t next_dir_2D_size = vSize(next_dir_2D);
314 if (next_dir_2D_size > 0)
315 next_dir_2D = next_dir_2D * drag_along / next_dir_2D_size;
316 Point3 next_dir (next_dir_2D.X, next_dir_2D.Y, 0);
317
318 Point3 newTop = to - next_dir + dir;
319
320 int64_t orrLength = (segment.to - from).vSize() + next_vector.vSize() + 1; // + 1 in order to avoid division by zero
321 int64_t newLength = (newTop - from).vSize() + (next_point - newTop).vSize() + 1; // + 1 in order to avoid division by zero
322
323 gcode.writeExtrusion(newTop, speedUp * newLength / orrLength, extrusion_mm3_per_mm_connection * orrLength / newLength, PrintFeatureType::OuterWall);
324 }
handle_segment(WeaveConnectionPart & part,unsigned int segment_idx)325 void Wireframe2gcode::handle_segment(WeaveConnectionPart& part, unsigned int segment_idx)
326 {
327 WeaveConnectionSegment& segment = part.connection.segments[segment_idx];
328
329 switch(segment.segmentType)
330 {
331 case WeaveSegmentType::MOVE:
332 writeMoveWithRetract(segment.to);
333 break;
334 case WeaveSegmentType::DOWN:
335 go_down(part, segment_idx);
336 break;
337 case WeaveSegmentType::FLAT:
338 logWarning("Warning: flat piece in wire print connection.\n");
339 break;
340 case WeaveSegmentType::UP:
341 if (strategy == STRATEGY_KNOT)
342 {
343 strategy_knot(part, segment_idx);
344 } else if (strategy == STRATEGY_RETRACT)
345 {
346 strategy_retract(part, segment_idx);
347 } else if (strategy == STRATEGY_COMPENSATE)
348 {
349 strategy_compensate(part, segment_idx);
350 }
351 break;
352 case WeaveSegmentType::DOWN_AND_FLAT:
353 logError("Down and flat move in non-horizontal connection!");
354 break;
355 }
356 }
357
358
359
360
handle_roof_segment(WeaveConnectionPart & part,unsigned int segment_idx)361 void Wireframe2gcode::handle_roof_segment(WeaveConnectionPart& part, unsigned int segment_idx)
362 {
363 WeaveConnectionSegment& segment = part.connection.segments[segment_idx];
364 Point3 from = (segment_idx == 0)? part.connection.from : part.connection.segments[segment_idx - 1].to;
365 WeaveConnectionSegment* next_segment = nullptr;
366 if (segment_idx + 1 < part.connection.segments.size())
367 next_segment = &part.connection.segments[segment_idx+1];
368 switch(segment.segmentType)
369 {
370 case WeaveSegmentType::MOVE:
371 case WeaveSegmentType::DOWN_AND_FLAT:
372 if (next_segment && next_segment->segmentType != WeaveSegmentType::DOWN_AND_FLAT)
373 {
374 writeMoveWithRetract(segment.to);
375 }
376 break;
377 case WeaveSegmentType::UP:
378 {
379 Point3 to = segment.to + Point3(0, 0, roof_fall_down);
380
381 Point3 vector = segment.to - from;
382 if (vector.vSize2() == 0) return;
383 Point3 dir = vector * roof_drag_along / vector.vSize();
384
385 Point3 next_vector;
386 if (next_segment)
387 {
388 next_vector = next_segment->to - segment.to;
389 } else
390 {
391 next_vector = part.connection.segments[0].to - segment.to;
392 }
393 Point next_dir_2D(next_vector.x, next_vector.y);
394 Point3 detoured = to + dir;
395 if (vSize2(next_dir_2D) > 0)
396 {
397 next_dir_2D = next_dir_2D * roof_drag_along / vSize(next_dir_2D);
398 Point3 next_dir (next_dir_2D.X, next_dir_2D.Y, 0);
399 detoured -= next_dir;
400 }
401
402 gcode.writeExtrusion(detoured, speedUp, extrusion_mm3_per_mm_connection, PrintFeatureType::Skin);
403
404 }
405 break;
406 case WeaveSegmentType::DOWN:
407 gcode.writeExtrusion(segment.to, speedDown, extrusion_mm3_per_mm_connection, PrintFeatureType::Skin);
408 gcode.writeDelay(roof_outer_delay);
409 break;
410 case WeaveSegmentType::FLAT:
411 logError("Flat move in connection!");
412 break;
413 }
414
415 }
416
417
418
writeFill(std::vector<WeaveRoofPart> & infill_insets,Polygons & roof_outlines,std::function<void (Wireframe2gcode &,WeaveConnectionPart & part,unsigned int segment_idx)> connectionHandler,std::function<void (Wireframe2gcode &,WeaveConnectionSegment & p)> flatHandler)419 void Wireframe2gcode::writeFill(std::vector<WeaveRoofPart>& infill_insets, Polygons& roof_outlines
420 , std::function<void (Wireframe2gcode&, WeaveConnectionPart& part, unsigned int segment_idx)> connectionHandler
421 , std::function<void (Wireframe2gcode&, WeaveConnectionSegment& p)> flatHandler)
422 {
423
424 // bottom:
425 gcode.writeTypeComment(PrintFeatureType::Infill);
426 for (unsigned int inset_idx = 0; inset_idx < infill_insets.size(); inset_idx++)
427 {
428 WeaveRoofPart& inset = infill_insets[inset_idx];
429
430
431 for (unsigned int inset_part_nr = 0; inset_part_nr < inset.connections.size(); inset_part_nr++)
432 {
433 WeaveConnectionPart& inset_part = inset.connections[inset_part_nr];
434 std::vector<WeaveConnectionSegment>& segments = inset_part.connection.segments;
435
436 gcode.writeTypeComment(PrintFeatureType::Support); // connection
437 if (segments.size() == 0) continue;
438 Point3 first_extrusion_from = inset_part.connection.from;
439 unsigned int first_segment_idx;
440 for (first_segment_idx = 0; first_segment_idx < segments.size() && segments[first_segment_idx].segmentType == WeaveSegmentType::MOVE; first_segment_idx++)
441 { // finds the first segment which is not a move
442 first_extrusion_from = segments[first_segment_idx].to;
443 }
444 if (first_segment_idx == segments.size())
445 continue;
446 writeMoveWithRetract(first_extrusion_from);
447 for (unsigned int segment_idx = first_segment_idx; segment_idx < segments.size(); segment_idx++)
448 {
449 connectionHandler(*this, inset_part, segment_idx);
450 }
451
452 gcode.writeTypeComment(PrintFeatureType::InnerWall); // top
453 for (unsigned int segment_idx = 0; segment_idx < segments.size(); segment_idx++)
454 {
455 WeaveConnectionSegment& segment = segments[segment_idx];
456
457 if (segment.segmentType == WeaveSegmentType::DOWN) continue;
458
459 flatHandler(*this, segment);
460 }
461 }
462
463
464 }
465
466 gcode.writeTypeComment(PrintFeatureType::OuterWall); // outer perimeter of the flat parts
467 for (PolygonRef poly : roof_outlines)
468 {
469 writeMoveWithRetract(poly[poly.size() - 1]);
470 for (Point& p : poly)
471 {
472 Point3 to(p.X, p.Y, gcode.getPositionZ());
473 WeaveConnectionSegment segment(to, WeaveSegmentType::FLAT);
474 flatHandler(*this, segment);
475 }
476 }
477 }
478
479
480
481
writeMoveWithRetract(Point3 to)482 void Wireframe2gcode::writeMoveWithRetract(Point3 to)
483 {
484 if ((gcode.getPosition() - to).vSize2() >= nozzle_top_diameter * nozzle_top_diameter * 2 * 2)
485 gcode.writeRetraction(standard_retraction_config);
486 gcode.writeTravel(to, moveSpeed);
487 }
488
writeMoveWithRetract(Point to)489 void Wireframe2gcode::writeMoveWithRetract(Point to)
490 {
491 if (vSize2(gcode.getPositionXY() - to) >= nozzle_top_diameter * nozzle_top_diameter * 2 * 2)
492 gcode.writeRetraction(standard_retraction_config);
493 gcode.writeTravel(to, moveSpeed);
494 }
495
Wireframe2gcode(Weaver & weaver,GCodeExport & gcode)496 Wireframe2gcode::Wireframe2gcode(Weaver& weaver, GCodeExport& gcode)
497 : gcode(gcode)
498 , wireFrame(weaver.wireFrame)
499 {
500 const Settings& scene_settings = Application::getInstance().current_slice->scene.settings;
501 initial_layer_thickness = scene_settings.get<coord_t>("layer_height_0");
502 connectionHeight = scene_settings.get<coord_t>("wireframe_height");
503 roof_inset = scene_settings.get<coord_t>("wireframe_roof_inset");
504
505 filament_diameter = scene_settings.get<coord_t>("material_diameter");
506 line_width = scene_settings.get<coord_t>("wall_line_width_x");
507
508 flowConnection = scene_settings.get<Ratio>("wireframe_flow_connection");
509 flowFlat = scene_settings.get<Ratio>("wireframe_flow_flat");
510
511 const double line_area = M_PI * square(INT2MM(line_width) / 2.0);
512 extrusion_mm3_per_mm_connection = line_area * flowConnection;
513 extrusion_mm3_per_mm_flat = line_area * flowFlat;
514
515 update_extrusion_offset = false;
516
517 nozzle_outer_diameter = scene_settings.get<coord_t>("machine_nozzle_tip_outer_diameter"); // ___ ___ .
518 // \ / .
519 nozzle_expansion_angle = scene_settings.get<AngleRadians>("machine_nozzle_expansion_angle"); // \_U_/ .
520 nozzle_clearance = scene_settings.get<coord_t>("wireframe_nozzle_clearance"); // at least line width
521 nozzle_top_diameter = tan(nozzle_expansion_angle) * connectionHeight + nozzle_outer_diameter + nozzle_clearance;
522
523 moveSpeed = 40;
524 speedBottom = scene_settings.get<Velocity>("wireframe_printspeed_bottom");
525 speedUp = scene_settings.get<Velocity>("wireframe_printspeed_up");
526 speedDown = scene_settings.get<Velocity>("wireframe_printspeed_down");
527 speedFlat = scene_settings.get<Velocity>("wireframe_printspeed_flat");
528
529 flat_delay = scene_settings.get<Duration>("wireframe_flat_delay");
530 bottom_delay = scene_settings.get<Duration>("wireframe_bottom_delay");
531 top_delay = scene_settings.get<Duration>("wireframe_top_delay");
532
533 up_dist_half_speed = scene_settings.get<coord_t>("wireframe_up_half_speed");
534
535 top_jump_dist = scene_settings.get<coord_t>("wireframe_top_jump");
536
537 fall_down = scene_settings.get<coord_t>("wireframe_fall_down");
538 drag_along = scene_settings.get<coord_t>("wireframe_drag_along");
539
540 strategy = STRATEGY_COMPENSATE;
541 if (scene_settings.get<std::string>("wireframe_strategy") == "compensate")
542 strategy = STRATEGY_COMPENSATE;
543 if (scene_settings.get<std::string>("wireframe_strategy") == "knot")
544 strategy = STRATEGY_KNOT;
545 if (scene_settings.get<std::string>("wireframe_strategy") == "retract")
546 strategy = STRATEGY_RETRACT;
547
548 go_back_to_last_top = false;
549 straight_first_when_going_down = scene_settings.get<Ratio>("wireframe_straight_before_down");
550
551 roof_fall_down = scene_settings.get<coord_t>("wireframe_roof_fall_down");
552 roof_drag_along = scene_settings.get<coord_t>("wireframe_roof_drag_along");
553 roof_outer_delay = scene_settings.get<Duration>("wireframe_roof_outer_delay");
554
555
556 standard_retraction_config.distance = scene_settings.get<double>("retraction_amount"); //Retraction distance in mm.
557 standard_retraction_config.prime_volume = std::max(0.0, scene_settings.get<double>("retraction_extra_prime_amount"));
558 standard_retraction_config.speed = scene_settings.get<Velocity>("retraction_retract_speed");
559 standard_retraction_config.primeSpeed = scene_settings.get<Velocity>("retraction_prime_speed");
560 standard_retraction_config.zHop = scene_settings.get<coord_t>("retraction_hop");
561 standard_retraction_config.retraction_count_max = scene_settings.get<size_t>("retraction_count_max");
562 standard_retraction_config.retraction_extrusion_window = scene_settings.get<double>("retraction_extrusion_window"); //Window in which to count retractions in mm of extruded filament.
563 standard_retraction_config.retraction_min_travel_distance = scene_settings.get<coord_t>("retraction_min_travel");
564 }
565
processStartingCode()566 void Wireframe2gcode::processStartingCode()
567 {
568 const Settings& scene_settings = Application::getInstance().current_slice->scene.settings;
569 const size_t extruder_count = Application::getInstance().current_slice->scene.extruders.size();
570 size_t start_extruder_nr = scene_settings.get<ExtruderTrain&>("adhesion_extruder_nr").extruder_nr;
571
572 if (Application::getInstance().communication->isSequential())
573 {
574 std::vector<bool> extruder_is_used;
575 extruder_is_used.resize(extruder_count, false);
576 extruder_is_used[start_extruder_nr] = true;
577 std::string prefix = gcode.getFileHeader(extruder_is_used);
578 gcode.writeCode(prefix.c_str());
579 }
580
581 gcode.writeComment("Generated with Cura_SteamEngine " VERSION);
582
583 if (gcode.getFlavor() != EGCodeFlavor::ULTIGCODE && gcode.getFlavor() != EGCodeFlavor::GRIFFIN)
584 {
585 if (scene_settings.get<bool>("material_bed_temp_prepend"))
586 {
587 if (scene_settings.get<bool>("machine_heated_bed") && scene_settings.get<Temperature>("material_bed_temperature") != 0)
588 {
589 gcode.writeBedTemperatureCommand(scene_settings.get<Temperature>("material_bed_temperature"), scene_settings.get<bool>("material_bed_temp_wait"));
590 }
591 }
592
593 if (scene_settings.get<bool>("material_print_temp_prepend"))
594 {
595 for (size_t extruder_nr = 0; extruder_nr < extruder_count; extruder_nr++)
596 {
597 Temperature print_temp = scene_settings.get<Temperature>("material_print_temperature");
598 gcode.writeTemperatureCommand(extruder_nr, print_temp);
599 }
600 if (scene_settings.get<bool>("material_print_temp_wait"))
601 {
602 for (size_t extruder_nr = 0; extruder_nr < extruder_count; extruder_nr++)
603 {
604 const Temperature print_temp = scene_settings.get<Temperature>("material_print_temperature");
605 gcode.writeTemperatureCommand(extruder_nr, print_temp, true);
606 }
607 }
608 }
609 }
610
611 gcode.writeCode(scene_settings.get<std::string>("machine_start_gcode").c_str());
612
613 if (gcode.getFlavor() == EGCodeFlavor::BFB)
614 {
615 gcode.writeComment("enable auto-retraction");
616 std::ostringstream tmp;
617 tmp << "M227 S" << (scene_settings.get<coord_t>("retraction_amount") * 2560 / 1000) << " P" << (scene_settings.get<coord_t>("retraction_amount") * 2560 / 1000);
618 gcode.writeLine(tmp.str().c_str());
619 }
620 else if (gcode.getFlavor() == EGCodeFlavor::GRIFFIN)
621 { // initialize extruder trains
622 gcode.writeCode("T0"); // Toolhead already assumed to be at T0, but writing it just to be safe...
623 Application::getInstance().communication->sendCurrentPosition(gcode.getPositionXY());
624 gcode.startExtruder(start_extruder_nr);
625 constexpr bool wait = true;
626 gcode.writeTemperatureCommand(start_extruder_nr, scene_settings.get<Temperature>("material_print_temperature"), wait);
627 gcode.writePrimeTrain(scene_settings.get<Velocity>("speed_travel"));
628 gcode.writeRetraction(standard_retraction_config);
629 }
630 }
631
632
processSkirt()633 void Wireframe2gcode::processSkirt()
634 {
635 if (wireFrame.bottom_outline.size() == 0) //If we have no layers, don't create a skirt either.
636 {
637 return;
638 }
639 Polygons skirt = wireFrame.bottom_outline.offset(100000+5000).offset(-100000);
640 PathOrderOptimizer order(Point(INT32_MIN, INT32_MIN));
641 order.addPolygons(skirt);
642 order.optimize();
643
644 const Settings& scene_settings = Application::getInstance().current_slice->scene.settings;
645 for (size_t poly_order_idx = 0; poly_order_idx < skirt.size(); poly_order_idx++)
646 {
647 const size_t poly_idx = order.polyOrder[poly_order_idx];
648 PolygonRef poly = skirt[poly_idx];
649 gcode.writeTravel(poly[order.polyStart[poly_idx]], scene_settings.get<Velocity>("speed_travel"));
650 for (unsigned int point_idx = 0; point_idx < poly.size(); point_idx++)
651 {
652 Point& p = poly[(point_idx + order.polyStart[poly_idx] + 1) % poly.size()];
653 gcode.writeExtrusion(p, scene_settings.get<Velocity>("skirt_brim_speed"), scene_settings.get<double>("skirt_brim_line_width") * scene_settings.get<Ratio>("initial_layer_line_width_factor") * INT2MM(initial_layer_thickness), PrintFeatureType::SkirtBrim);
654 }
655 }
656 }
657
658
finalize()659 void Wireframe2gcode::finalize()
660 {
661 gcode.finalize(Application::getInstance().current_slice->scene.settings.get<std::string>("machine_end_gcode").c_str());
662 for (size_t e = 0; e < Application::getInstance().current_slice->scene.extruders.size(); e++)
663 {
664 gcode.writeTemperatureCommand(e, 0, false);
665 }
666 }
667 }//namespace cura
668