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