1 //Copyright (c) 2018 Ultimaker B.V.
2 //CuraEngine is released under the terms of the AGPLv3 or higher.
3 
4 #ifndef GCODE_WRITER_H
5 #define GCODE_WRITER_H
6 
7 #include <fstream>
8 #include "FanSpeedLayerTime.h"
9 #include "gcodeExport.h"
10 #include "LayerPlanBuffer.h"
11 #include "settings/PathConfigStorage.h" //For the MeshPathConfigs subclass.
12 #include "utils/NoCopy.h"
13 
14 namespace std
15 {
16 template<typename T> class optional;
17 }
18 
19 namespace cura
20 {
21 
22 class AngleDegrees;
23 class Polygons;
24 class SkinPart;
25 class SliceDataStorage;
26 class SliceMeshStorage;
27 class SliceLayer;
28 class SliceLayerPart;
29 class TimeKeeper;
30 
31 /*!
32  * Secondary stage in Fused Filament Fabrication processing: The generated polygons are used in the gcode generation.
33  * Some polygons in the SliceDataStorage signify areas which are to be filled with parallel lines,
34  * while other polygons signify the contours which should be printed.
35  *
36  * The main function of this class is FffGcodeWriter::writeGCode().
37  */
38 class FffGcodeWriter : public NoCopy
39 {
40     friend class Scene; // cause WireFrame2Gcode uses the member [gcode] (TODO)
41     friend class FffProcessor; //Because FffProcessor exposes finalize (TODO)
42 private:
43     coord_t max_object_height; //!< The maximal height of all previously sliced meshgroups, used to avoid collision when moving to the next meshgroup to print.
44 
45     /*
46      * Buffer for all layer plans (of type LayerPlan)
47      *
48      * The layer plans are buffered so that we can start heating up a nozzle several layers before it needs to be used.
49      * Another reason is to perform Auto Temperature.
50      */
51     LayerPlanBuffer layer_plan_buffer;
52 
53     /*!
54      * The class holding the current state of the gcode being written.
55      *
56      * It holds information such as the last written position etc.
57      */
58     GCodeExport gcode;
59 
60     /*!
61      * The gcode file to write to when using CuraEngine as command line tool.
62      */
63     std::ofstream output_file;
64 
65     /*!
66      * For each raft/filler layer, the extruders to be used in that layer in the order in which they are going to be used.
67      * The first number is the first raft layer. Indexing is shifted compared to normal negative layer numbers for raft/filler layers.
68      */
69     std::vector<std::vector<size_t>> extruder_order_per_layer_negative_layers;
70 
71     std::vector<std::vector<size_t>> extruder_order_per_layer; //!< For each layer, the extruders to be used in that layer in the order in which they are going to be used
72 
73     std::vector<std::vector<size_t>> mesh_order_per_extruder; //!< For each extruder, the order of the meshes (first element is first mesh to be printed)
74 
75     /*!
76      * For each extruder on which layer the prime will be planned,
77      * or a large negative number if it's already planned outside of \ref FffGcodeWriter::processLayer
78      *
79      * Depending on whether we need to prime on the first layer, or anywhere in the print,
80      * the layer numbers are all zero (or less in case of raft)
81      * or they are the first layer at which the extruder is needed
82      */
83     LayerIndex extruder_prime_layer_nr[MAX_EXTRUDERS];
84 
85     std::vector<FanSpeedLayerTimeSettings> fan_speed_layer_time_settings_per_extruder; //!< The settings used relating to minimal layer time and fan speeds. Configured for each extruder.
86 
87 public:
88     /*
89      * \brief Construct a g-code writer.
90      *
91      * This sets the initial state of the printer correctly in itself, so that
92      * it's ready for writing.
93      */
94     FffGcodeWriter();
95 
96     /*!
97      * Set the target to write gcode to: to a file.
98      *
99      * Used when CuraEngine is used as command line tool.
100      *
101      * \param filename The filename of the file to which to write the gcode.
102      */
setTargetFile(const char * filename)103     bool setTargetFile(const char* filename)
104     {
105         output_file.open(filename);
106         if (output_file.is_open())
107         {
108             gcode.setOutputStream(&output_file);
109             return true;
110         }
111         return false;
112     }
113 
114     /*!
115      * Set the target to write gcode to: an output stream.
116      *
117      * Used when CuraEngine is NOT used as command line tool.
118      *
119      * \param stream The stream to write gcode to.
120      */
setTargetStream(std::ostream * stream)121     void setTargetStream(std::ostream* stream)
122     {
123         gcode.setOutputStream(stream);
124     }
125 
126     /*!
127      * Get the total extruded volume for a specific extruder in mm^3
128      *
129      * Retractions and unretractions don't contribute to this.
130      *
131      * \param extruder_nr The extruder number for which to get the total netto extruded volume
132      * \return total filament printed in mm^3
133      */
getTotalFilamentUsed(int extruder_nr)134     double getTotalFilamentUsed(int extruder_nr)
135     {
136         return gcode.getTotalFilamentUsed(extruder_nr);
137     }
138 
139     /*!
140      * Get the total estimated print time in seconds for each feature
141      *
142      * \return total print time in seconds for each feature
143      */
getTotalPrintTimePerFeature()144     std::vector<Duration> getTotalPrintTimePerFeature()
145     {
146         return gcode.getTotalPrintTimePerFeature();
147     }
148 
149     /*!
150      * Write all the gcode for the current meshgroup.
151      * This is the primary function of this class.
152      *
153      * \param[in] storage The data storage from which to get the polygons to print and the areas to fill.
154      * \param timeKeeper The stop watch to see how long it takes for each of the stages in the slicing process.
155      */
156     void writeGCode(SliceDataStorage& storage, TimeKeeper& timeKeeper);
157 
158 private:
159     /*!
160      * \brief Set the FffGcodeWriter::fan_speed_layer_time_settings by
161      * retrieving all settings from the global/per-meshgroup settings.
162      */
163     void setConfigFanSpeedLayerTime();
164 
165     /*!
166      * Create and set the SliceDataStorage::coasting_config for each extruder.
167      *
168      * \param[out] storage The data storage to which to save the configuration
169      */
170     void setConfigCoasting(SliceDataStorage& storage);
171 
172     /*!
173      * Set the retraction config globally, per extruder and per mesh.
174      *
175      * \param[out] storage The data storage to which to save the configurations
176      */
177     void setConfigRetraction(SliceDataStorage& storage);
178 
179     /*!
180      * Set the wipe config globally, per extruder.
181      *
182      * \param[out] storage The data storage to which to save the configurations
183      */
184     void setConfigWipe(SliceDataStorage& storage);
185 
186     /*!
187      * Get the extruder with which to start the print.
188      *
189      * Generally this is the adhesion_extruder_nr, but in case the platform adhesion type is none,
190      * the extruder with lowest number which is used on the first layer is used as initial extruder.
191      *
192      * \param[in] storage where to get settings from.
193      */
194     unsigned int getStartExtruder(const SliceDataStorage& storage);
195 
196     /*!
197      * Set the infill angles and skin angles in the SliceDataStorage.
198      *
199      * These lists of angles are cycled through to get the infill angle of a specific layer.
200      *
201      * \param mesh The mesh for which to determine the infill and skin angles.
202      */
203     void setInfillAndSkinAngles(SliceMeshStorage& mesh);
204 
205     /*!
206      * Set the support and interface infill angles in the SliceDataStorage.
207      *
208      * Default angles depend on which pattern it's using and in certain patterns it
209      * alternates between layers.
210      *
211      * These lists of angles are cycled through to get the support infill angle of a specific layer.
212      *
213      * \param storage The storage for which to determine the support infill angles.
214      */
215     void setSupportAngles(SliceDataStorage& storage);
216 
217     /*!
218     * Set temperatures for the initial layer. Called by 'processStartingCode' and whenever a new object is started at layer 0.
219     *
220     * \param[in] storage where the slice data is stored.
221     * \param[in] start_extruder_nr The extruder with which to start the print.
222     */
223     void processInitialLayerTemperature(const SliceDataStorage& storage, const size_t start_extruder_nr);
224 
225     /*!
226      * Set temperatures and perform initial priming.
227      *
228      * Write a stub header if CuraEngine is in command line tool mode. (Cause writing the header afterwards would entail moving all gcode down.)
229      *
230      * \param[in] storage where the slice data is stored.
231      * \param[in] start_extruder_nr The extruder with which to start the print.
232      */
233     void processStartingCode(const SliceDataStorage& storage, const size_t start_extruder_nr);
234 
235     /*!
236      * Move up and over the already printed meshgroups to print the next meshgroup.
237      *
238      * \param[in] storage where the slice data is stored.
239      */
240     void processNextMeshGroupCode(const SliceDataStorage& storage);
241 
242     /*!
243      * Add raft layer plans onto the FffGcodeWriter::layer_plan_buffer
244      *
245      * \param[in,out] storage where the slice data is stored.
246      */
247     void processRaft(const SliceDataStorage& storage);
248 
249     /*!
250      * Convert the polygon data of a layer into a layer plan on the FffGcodeWriter::layer_plan_buffer
251      *
252      * In case of negative layer numbers, create layers only containing the data from
253      * the helper parts (support etc) to fill up the gap between the raft and the model.
254      *
255      * \param[in] storage where the slice data is stored.
256      * \param layer_nr The index of the layer to write the gcode of.
257      * \param total_layers The total number of layers.
258      * \return The layer plans
259      */
260     LayerPlan& processLayer(const SliceDataStorage& storage, LayerIndex layer_nr, const size_t total_layers) const;
261 
262     /*!
263      * This function checks whether prime blob should happen for any extruder on the first layer.
264      * Priming will always happen, but the actual priming may or may not include a prime blob.
265      *
266      * Technically, this function checks whether any extruder needs to be primed (with a prime blob)
267      * separately just before they are used.
268      *
269      * \return whether any extruder need to be primed separately just before they are used
270      */
271     bool getExtruderNeedPrimeBlobDuringFirstLayer(const SliceDataStorage& storage, const size_t extruder_nr) const;
272 
273     /*!
274      * Plan priming of all used extruders which haven't been primed yet
275      * \param[in] storage where the slice data is stored.
276      * \param layer_plan The initial planning of the g-code of the layer.
277      */
278     void ensureAllExtrudersArePrimed(const SliceDataStorage& storage, LayerPlan& layer_plan) const;
279 
280     /*!
281      * Add the skirt or the brim to the layer plan \p gcodeLayer if it hasn't already been added yet.
282      *
283      * This function should be called for only one layer;
284      * calling it for multiple layers results in the skirt/brim being printed on multiple layers.
285      *
286      * \param storage where the slice data is stored.
287      * \param gcodeLayer The initial planning of the g-code of the layer.
288      * \param extruder_nr The extruder train for which to process the skirt or
289      * brim.
290      */
291     void processSkirtBrim(const SliceDataStorage& storage, LayerPlan& gcodeLayer, unsigned int extruder_nr) const;
292 
293     /*!
294      * Adds the ooze shield to the layer plan \p gcodeLayer.
295      *
296      * \param[in] storage where the slice data is stored.
297      * \param gcodeLayer The initial planning of the gcode of the layer.
298      */
299     void processOozeShield(const SliceDataStorage& storage, LayerPlan& gcodeLayer) const;
300 
301     /*!
302      * Adds the draft protection screen to the layer plan \p gcodeLayer.
303      *
304      * \param[in] storage where the slice data is stored.
305      * \param gcodeLayer The initial planning of the gcode of the layer.
306      */
307     void processDraftShield(const SliceDataStorage& storage, LayerPlan& gcodeLayer) const;
308 
309     /*!
310      * Calculate in which order to plan the extruders for each layer
311      * Store the order of extruders for each layer in extruder_order_per_layer for normal layers
312      * and the order of extruders for raft/filler layers in extruder_order_per_layer_negative_layers.
313      *
314      * Only extruders which are (most probably) going to be used are planned
315      *
316      * \note At the planning stage we only have information on areas, not how those are filled.
317      * If an area is too small to be filled with anything it will still get specified as being used with the extruder for that area.
318      *
319      * Computes \ref FffGcodeWriter::extruder_prime_layer_nr, \ref FffGcodeWriter::extruder_order_per_layer and \ref FffGcodeWriter::extruder_order_per_layer_negative_layers
320      *
321      * \param[in] storage where the slice data is stored.
322      */
323     void calculateExtruderOrderPerLayer(const SliceDataStorage& storage);
324 
325     /*!
326      * Gets a list of extruders that are used on the given layer, but excluding the given starting extruder.
327      * When it's on the first layer, the prime blob will also be taken into account.
328      *
329      * \note At the planning stage we only have information on areas, not how those are filled.
330      * If an area is too small to be filled with anything it will still get specified as being used with the extruder for that area.
331      *
332      * \param[in] storage where the slice data is stored.
333      * \param current_extruder The current extruder with which we last printed
334      * \return The order of extruders for a layer beginning with \p current_extruder
335      */
336     std::vector<size_t> getUsedExtrudersOnLayerExcludingStartingExtruder(const SliceDataStorage& storage, const size_t start_extruder, const LayerIndex& layer_nr) const;
337 
338     /*!
339      * Calculate in which order to plan the meshes of a specific extruder
340      * Each mesh which has some feature printed with the extruder is included in this order.
341      * One mesh can occur in the mesh order of multiple extruders.
342      *
343      * \param[in] storage where the slice data is stored.
344      * \param extruder_nr The extruder for which to determine the order
345      * \return A vector of mesh indices ordered on print order for that extruder.
346      */
347     std::vector<size_t> calculateMeshOrder(const SliceDataStorage& storage, const size_t extruder_nr) const;
348 
349     /*!
350      * Add a single layer from a single mesh-volume to the layer plan \p gcodeLayer in mesh surface mode.
351      *
352      * \param[in] storage where the slice data is stored.
353      * \param mesh The mesh to add to the layer plan \p gcodeLayer.
354      * \param mesh_config the line config with which to print a print feature
355      * \param gcodeLayer The initial planning of the gcode of the layer.
356      */
357     void addMeshLayerToGCode_meshSurfaceMode(const SliceDataStorage& storage, const SliceMeshStorage& mesh, const PathConfigStorage::MeshPathConfigs& mesh_config, LayerPlan& gcodeLayer) const;
358 
359     /*!
360      * Add the open polylines from a single layer from a single mesh-volume to the layer plan \p gcodeLayer for mesh the surface modes.
361      *
362      * \param[in] storage where the slice data is stored.
363      * \param mesh The mesh for which to add to the layer plan \p gcodeLayer.
364      * \param mesh_config the line config with which to print a print feature
365      * \param gcodeLayer The initial planning of the gcode of the layer.
366      */
367     void addMeshOpenPolyLinesToGCode(const SliceMeshStorage& mesh, const PathConfigStorage::MeshPathConfigs& mesh_config, LayerPlan& gcode_layer) const;
368 
369     /*!
370      * Add all features of a given extruder from a single layer from a single mesh-volume to the layer plan \p gcode_layer.
371      *
372      * This adds all features (e.g. walls, skin etc.) of this \p mesh to the gcode which are printed using \p extruder_nr
373      *
374      * \param[in] storage where the slice data is stored.
375      * \param mesh The mesh to add to the layer plan \p gcode_layer.
376      * \param extruder_nr The extruder for which to print all features of the mesh which should be printed with this extruder
377      * \param mesh_config the line config with which to print a print feature
378      * \param gcode_layer The initial planning of the gcode of the layer.
379      */
380     void addMeshLayerToGCode(const SliceDataStorage& storage, const SliceMeshStorage& mesh, const size_t extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, LayerPlan& gcode_layer) const;
381 
382     /*!
383      * Add all features of the given extruder from a single part from a given layer of a mesh-volume to the layer plan \p gcode_layer.
384      * This only adds the features which are printed with \p extruder_nr.
385      *
386      * \param[in] storage where the slice data is stored.
387      * \param storage Storage to get global settings from.
388      * \param mesh The mesh to add to the layer plan \p gcode_layer.
389      * \param extruder_nr The extruder for which to print all features of the mesh which should be printed with this extruder
390      * \param mesh_config the line config with which to print a print feature
391      * \param part The part to add
392      * \param gcode_layer The initial planning of the gcode of the layer.
393      */
394     void addMeshPartToGCode(const SliceDataStorage& storage, const SliceMeshStorage& mesh, const size_t extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const SliceLayerPart& part, LayerPlan& gcode_layer) const;
395 
396     /*!
397      * \brief Add infill for a given part in a layer plan.
398      *
399      * \param gcodeLayer The initial planning of the gcode of the layer.
400      * \param mesh The mesh for which to add to the layer plan \p gcodeLayer.
401      * \param extruder_nr The extruder for which to print all features of the
402      * mesh which should be printed with this extruder.
403      * \param mesh_config the line config with which to print a print feature.
404      * \param part The part for which to create gcode.
405      * \return Whether this function added anything to the layer plan.
406      */
407     bool processInfill(const SliceDataStorage& storage, LayerPlan& gcodeLayer, const SliceMeshStorage& mesh, const size_t extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const SliceLayerPart& part) const;
408 
409     /*!
410      * \brief Add thicker (multiple layers) sparse infill for a given part in a
411      * layer plan.
412      *
413      * \param gcodeLayer The initial planning of the gcode of the layer.
414      * \param mesh The mesh for which to add to the layer plan \p gcodeLayer.
415      * \param extruder_nr The extruder for which to print all features of the
416      * mesh which should be printed with this extruder.
417      * \param mesh_config The line config with which to print a print feature.
418      * \param part The part for which to create gcode.
419      * \return Whether this function added anything to the layer plan.
420      */
421     bool processMultiLayerInfill(const SliceDataStorage& storage, LayerPlan& gcodeLayer, const SliceMeshStorage& mesh, const size_t extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const SliceLayerPart& part) const;
422 
423     /*!
424      * \brief Add normal sparse infill for a given part in a layer.
425      * \param gcodeLayer The initial planning of the gcode of the layer.
426      * \param mesh The mesh for which to add to the layer plan \p gcodeLayer.
427      * \param extruder_nr The extruder for which to print all features of the
428      * mesh which should be printed with this extruder
429      * \param mesh_config The line config with which to print a print feature.
430      * \param part The part for which to create gcode.
431      * \return Whether this function added anything to the layer plan.
432      */
433     bool processSingleLayerInfill(const SliceDataStorage& storage, LayerPlan& gcodeLayer, const SliceMeshStorage& mesh, const size_t extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const SliceLayerPart& part) const;
434 
435     /*!
436      * Generate the insets for the walls of a given layer part.
437      * \param[in] storage where the slice data is stored.
438      * \param gcodeLayer The initial planning of the gcode of the layer.
439      * \param mesh The mesh for which to add to the layer plan \p gcodeLayer.
440      * \param extruder_nr The extruder for which to print all features of the mesh which should be printed with this extruder
441      * \param mesh_config the line config with which to print a print feature
442      * \param part The part for which to create gcode
443      * \return Whether this function added anything to the layer plan
444      */
445     bool processInsets(const SliceDataStorage& storage, LayerPlan& gcodeLayer, const SliceMeshStorage& mesh, const size_t extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const SliceLayerPart& part) const;
446 
447     /*!
448      * Generate the a spiralized wall for a given layer part.
449      * \param[in] storage where the slice data is stored.
450      * \param[out] gcodeLayer The initial planning of the gcode of the layer.
451      * \param mesh_config the line config with which to print a print feature
452      * \param part The part for which to create gcode
453      * \param mesh The mesh for which to add to the layer plan \p gcodeLayer.
454      */
455     void processSpiralizedWall(const SliceDataStorage& storage, LayerPlan& gcode_layer, const PathConfigStorage::MeshPathConfigs& mesh_config, const SliceLayerPart& part, const SliceMeshStorage& mesh) const;
456 
457     /*!
458      * Add the gcode of the outline gaps: the areas for thin parts in which a single perimter doesnt fit.
459      *
460      * \param gcode_layer The initial planning of the gcode of the layer.
461      * \param mesh The mesh for which to add to the layer plan \p gcode_layer.
462      * \param extruder_nr The extruder for which to print all features of the mesh which should be printed with this extruder
463      * \param mesh_config the line config with which to print a print feature
464      * \param part The part for which to create gcode
465      * \param[out] added_something Whether this function added anything to the layer plan
466      */
467     void processOutlineGaps(const SliceDataStorage& storage, LayerPlan& gcode_layer, const SliceMeshStorage& mesh, const size_t extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const SliceLayerPart& part, bool& added_something) const;
468 
469     /*!
470      * Add the gcode of the top/bottom skin of the given part and of the perimeter gaps.
471      *
472      * Perimeter gaps are handled for skin outlines and printed after the skin fill of the skin part is printed by calling \ref processSkinPart.
473      * Perimeter gaps between the walls are added to the gcode afterwards.
474      *
475      * \param[in] storage where the slice data is stored.
476      * \param gcode_layer The initial planning of the gcode of the layer.
477      * \param mesh The mesh for which to add to the layer plan \p gcode_layer.
478      * \param extruder_nr The extruder for which to print all features of the mesh which should be printed with this extruder
479      * \param mesh_config the line config with which to print a print feature
480      * \param part The part for which to create gcode
481      * \return Whether this function added anything to the layer plan
482      */
483     bool processSkinAndPerimeterGaps(const SliceDataStorage& storage, LayerPlan& gcode_layer, const SliceMeshStorage& mesh, const size_t extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const SliceLayerPart& part) const;
484 
485     /*!
486      * Add the gcode of the top/bottom skin of the given skin part and of the perimeter gaps.
487      *
488      * Perimeter gaps are handled for the current extruder for the following features if they are printed with this extruder.
489      * - skin outlines
490      * - roofing (if concentric)
491      * - top/bottom (if concentric)
492      * They are all printed at the end of printing the skin part features which are printed with this extruder.
493      *
494      * Note that the normal perimeter gaps are printed with the outer wall extruder,
495      * while newly generated perimeter gaps
496      * are printed with the extruder with which the feature was printed which generated the gaps.
497      *
498      * \param[in] storage where the slice data is stored.
499      * \param gcode_layer The initial planning of the gcode of the layer.
500      * \param mesh The mesh for which to add to the layer plan \p gcode_layer.
501      * \param extruder_nr The extruder for which to print all features of the mesh which should be printed with this extruder
502      * \param mesh_config the line config with which to print a print feature
503      * \param skin_part The skin part for which to create gcode
504      * \return Whether this function added anything to the layer plan
505      */
506     bool processSkinPart(const SliceDataStorage& storage, LayerPlan& gcode_layer, const SliceMeshStorage& mesh, const size_t extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const SkinPart& skin_part) const;
507 
508     /*!
509      * Add the extra skin walls
510      *
511      * \param[in] storage where the slice data is stored.
512      * \param gcode_layer The initial planning of the gcode of the layer.
513      * \param mesh The mesh for which to add to the layer plan \p gcode_layer.
514      * \param extruder_nr The extruder for which to print all features of the mesh which should be printed with this extruder
515      * \param mesh_config the line config with which to print a print feature
516      * \param skin_part The skin part for which to create gcode
517      * \param[out] added_something Whether this function added anything to the layer plan
518      */
519     void processSkinInsets(const SliceDataStorage& storage, LayerPlan& gcode_layer, const SliceMeshStorage& mesh, const size_t extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const SkinPart& skin_part, bool& added_something) const;
520 
521     /*!
522      * Add the roofing which is the area inside the innermost skin inset which has air 'directly' above
523      *
524      * Perimeter gaps are generated when the pattern is concentric
525      * These gaps are generated here, but not printed here because printing all perimeter gaps at the same time is more efficient.
526      * There are already some perimeter gaps from the skin outline walls.
527      * This function adds more perimeter gaps for the roofing concentric pattern.
528      * The gaps will be filled in \ref concentric_perimeter_gaps
529      * That way we can choose the fastest route between all perimeter gaps of this skin part.
530      *
531      * \param[in] storage where the slice data is stored.
532      * \param gcode_layer The initial planning of the gcode of the layer.
533      * \param mesh The mesh for which to add to the layer plan \p gcode_layer.
534      * \param extruder_nr The extruder for which to print all features of the mesh which should be printed with this extruder
535      * \param mesh_config the line config with which to print a print feature
536      * \param skin_part The skin part for which to create gcode
537      * \param[out] concentric_perimeter_gaps The perimeter gaps output which are generated when the pattern is concentric
538      * \param[out] added_something Whether this function added anything to the layer plan
539      */
540     void processRoofing(const SliceDataStorage& storage, LayerPlan& gcode_layer, const SliceMeshStorage& mesh, const size_t extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const SkinPart& skin_part, Polygons& concentric_perimeter_gaps, bool& added_something) const;
541 
542     /*!
543      * Add the normal skinfill which is the area inside the innermost skin inset
544      * which doesn't have air directly above it if we're printing roofing
545      *
546      * Perimeter gaps are generated when the pattern is concentric.
547      * These gaps are generated here, but not printed here because printing all perimeter gaps at the same time is more efficient.
548      * There are already some perimeter gaps from the skin outline walls.
549      * This function adds more perimeter gaps for the skin concentric pattern.
550      * The gaps will be filled in \ref concentric_perimeter_gaps
551      * That way we can choose the fastest route between all perimeter gaps of this skin part.
552      *
553      * \param[in] storage where the slice data is stored.
554      * \param gcode_layer The initial planning of the gcode of the layer.
555      * \param mesh The mesh for which to add to the layer plan \p gcode_layer.
556      * \param extruder_nr The extruder for which to print all features of the mesh which should be printed with this extruder
557      * \param mesh_config the line config with which to print a print feature
558      * \param skin_part The skin part for which to create gcode
559      * \param[out] concentric_perimeter_gaps The perimeter gaps output which are generated when the pattern is concentric
560      * \param[out] added_something Whether this function added anything to the layer plan
561      */
562     void processTopBottom(const SliceDataStorage& storage, LayerPlan& gcode_layer, const SliceMeshStorage& mesh, const size_t extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const SkinPart& skin_part, Polygons& concentric_perimeter_gaps, bool& added_something) const;
563 
564     /*!
565      * Process a dense skin feature like roofing or top/bottom
566      *
567      * \param[in] storage where the slice data is stored.
568      * \param gcode_layer The initial planning of the gcode of the layer.
569      * \param mesh The mesh for which to add to the layer plan \p gcode_layer.
570      * \param extruder_nr The extruder for which to print all features of the mesh which should be printed with this extruder
571      * \param area The area to fill
572      * \param config the line config with which to print the print feature
573      * \param pattern the pattern with which to fill the print feature
574      * \param skin_angle the angle to use for linear infill types
575      * \param skin_overlap The amount by which to expand the \p area
576      * \param skin density Sets the density of the the skin lines by adjusting the distance between them (normal skin is 1.0)
577      * \param[out] perimeter_gaps_output Optional output to store the gaps which occur if the pattern is concentric
578      * \param[out] added_something Whether this function added anything to the layer plan
579      * \param fan_speed fan speed override for this skin area
580      */
581     void processSkinPrintFeature(const SliceDataStorage& storage, LayerPlan& gcode_layer, const SliceMeshStorage& mesh, const size_t extruder_nr, const Polygons& area, const GCodePathConfig& config, EFillMethod pattern, const AngleDegrees skin_angle, const coord_t skin_overlap, const Ratio skin_density, Polygons* perimeter_gaps_output, bool& added_something, double fan_speed = GCodePathConfig::FAN_SPEED_DEFAULT) const;
582 
583     /*!
584      * Add perimeter gaps of a mesh with the given extruder.
585      *
586      * \param[in] storage where the slice data is stored.
587      * \param gcode_layer The initial planning of the gcode of the layer.
588      * \param mesh The mesh for which to add to the layer plan \p gcode_layer.
589      * \param extruder_nr The extruder for which to print all features of the mesh which should be printed with this extruder
590      * \param perimeter_gaps The generated perimeter gaps to fill
591      * \param perimeter_gap_config the line config with which to print the perimeter gaps print feature
592      * \param[out] added_something Whether this function added anything to the layer plan
593      */
594     void processPerimeterGaps(const SliceDataStorage& storage, LayerPlan& gcode_layer, const SliceMeshStorage& mesh, const size_t extruder_nr, const Polygons& perimeter_gaps, const GCodePathConfig& perimeter_gap_config, bool& added_something) const;
595 
596     /*!
597      *  see if we can avoid printing a lines or zig zag style skin part in multiple segments by moving to
598      *  a start point that would increase the chance that the skin will be printed in a single segment.
599      *  Obviously, if the skin part contains holes then it will have to be printed in multiple segments anyway but
600      *  doing this may still produce fewer skin seams or move a seam that would be across the middle of the part
601      *  to a less noticeable position
602      *
603      * So, instead of this \/         We get this \/
604      *                +------+               +------+
605      *                |2///#1|               |1/////|
606      *                |///#//|               |//////|
607      *                |//#///|               |//////|
608      *                |/#////|               |//////|
609      *                |#/////|               |//////|
610      *                +------+               +------+
611      *     1, 2 = start locations of skin segments
612      *     # = seam
613      *
614      * \param filling_part The part which we are going to fill with a linear filling type
615      * \param filling_angle The angle of the filling lines
616      * \param last_position The position the print head is in before going to fill the part
617      * \return The location near where to start filling the part
618      */
619     std::optional<Point> getSeamAvoidingLocation(const Polygons& filling_part, int filling_angle, Point last_position) const;
620 
621     /*!
622      * Add the g-code for ironing the top surface.
623      *
624      * This produces additional low-extrusion moves that cover the top surface,
625      * in order to smooth the surface more.
626      *
627      * \param mesh The settings storage to get the ironing settings and skin
628      * angles from.
629      * \param layer The layer to process the ironing for.
630      * \param line_config The configuration of the lines to draw the ironing
631      * with.
632      * \param[out] gcode_layer The output layer to put the resulting paths in.
633      * \return Whether this function added anything to the layer plan.
634      */
635     bool processIroning(const SliceMeshStorage& mesh, const SliceLayer& part, const GCodePathConfig& line_config, LayerPlan& gcode_layer) const;
636 
637     /*!
638      * Add the support to the layer plan \p gcodeLayer of the current layer for all support parts with the given \p extruder_nr.
639      * \param[in] storage where the slice data is stored.
640      * \param gcodeLayer The initial planning of the gcode of the layer.
641      * \return whether any support was added to the layer plan
642      */
643     bool addSupportToGCode(const SliceDataStorage& storage, LayerPlan& gcodeLayer, const size_t extruder_nr) const;
644 
645     /*!
646      * Add the support lines/walls to the layer plan \p gcodeLayer of the current layer.
647      * \param[in] storage where the slice data is stored.
648      * \param gcode_layer The initial planning of the gcode of the layer.
649      * \return whether any support infill was added to the layer plan
650      */
651     bool processSupportInfill(const SliceDataStorage& storage, LayerPlan& gcode_layer) const;
652 
653     /*!
654      * Add the support roofs to the layer plan \p gcodeLayer of the current
655      * layer.
656      *
657      * \param[in] storage Where the slice data is stored.
658      * \param gcodeLayer The initial planning of the g-code of the layer.
659      * \return Whether any support skin was added to the layer plan.
660      */
661     bool addSupportRoofsToGCode(const SliceDataStorage& storage, LayerPlan& gcodeLayer) const;
662 
663     /*!
664      * Add the support bottoms to the layer plan \p gcodeLayer of the current
665      * layer.
666      *
667      * \param[in] storage Where the slice data is stored.
668      * \param gcodeLayer The initial planning of the g-code of the layer.
669      * \return Whether any support skin was added to the layer plan.
670      */
671     bool addSupportBottomsToGCode(const SliceDataStorage& storage, LayerPlan& gcodeLayer) const;
672 
673 public:
674     /*!
675      * Change to a new extruder, and add the prime tower instructions if the new extruder is different from the last.
676      *
677      * On layer 0 this function adds the skirt for the nozzle it switches to, instead of the prime tower.
678      *
679      * \param[in] storage where the slice data is stored.
680      * \param gcode_layer The initial planning of the gcode of the layer.
681      * \param extruder_nr The extruder to switch to.
682      */
683     void setExtruder_addPrime(const SliceDataStorage& storage, LayerPlan& gcode_layer, const size_t extruder_nr) const;
684 
685 private:
686     /*!
687      * Add the prime tower gcode for the current layer.
688      * \param[in] storage where the slice data is stored.
689      * \param gcodeLayer The initial planning of the gcode of the layer.
690      * \param prev_extruder The current extruder with which we last printed.
691      */
692     void addPrimeTower(const SliceDataStorage& storage, LayerPlan& gcodeLayer, int prev_extruder) const;
693 
694     /*!
695      * Add the end gcode and set all temperatures to zero.
696      */
697     void finalize();
698 
699     /*!
700      * Calculate for each layer the index of the vertex that is considered to be the seam
701      * \param storage where the slice data is stored.
702      * \param total_layers The total number of layers
703      */
704     void findLayerSeamsForSpiralize(SliceDataStorage& storage, size_t total_layers);
705 
706     /*!
707      * Calculate the index of the vertex that is considered to be the seam for the given layer
708      * \param storage where the slice data is stored.
709      * \param mesh the mesh containing the layer of interest
710      * \param layer_nr layer number of the layer whose seam verted index is required
711      * \param last_layer_nr layer number of the previous layer
712      * \return layer seam vertex index
713      */
714     unsigned int findSpiralizedLayerSeamVertexIndex(const SliceDataStorage& storage, const SliceMeshStorage& mesh, const int layer_nr, const int last_layer_nr);
715 };
716 
717 }//namespace cura
718 
719 #endif // GCODE_WRITER_H
720