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

#include <src/libslic3r/GCode.hpp>

+ Collaboration diagram for Slic3r::GCode:

Classes

class  GCodeOutputStream
 
struct  InstanceToPrint
 
struct  ObjectLayerToPrint
 
struct  PlaceholderParserIntegration
 

Public Types

using ObjectsLayerToPrint = std::vector< ObjectLayerToPrint >
 

Public Member Functions

 GCode ()
 
 ~GCode ()=default
 
void do_export (Print *print, const char *path, GCodeProcessorResult *result=nullptr, ThumbnailsGeneratorCallback thumbnail_cb=nullptr)
 
const Vec2dorigin () const
 
void set_origin (const Vec2d &pointf)
 
void set_origin (const coordf_t x, const coordf_t y)
 
const Pointlast_pos () const
 
Vec2d point_to_gcode (const Point &point) const
 
Vec2d point_to_gcode_quantized (const Point &point) const
 
Point gcode_to_point (const Vec2d &point) const
 
const FullPrintConfig & config () const
 
const Layerlayer () const
 
GCodeWriterwriter ()
 
const GCodeWriterwriter () const
 
PlaceholderParserplaceholder_parser ()
 
const PlaceholderParserplaceholder_parser () const
 
std::string placeholder_parser_process (const std::string &name, const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override=nullptr)
 
bool enable_cooling_markers () const
 
unsigned int layer_count () const
 
void set_layer_count (unsigned int value)
 
void apply_print_config (const PrintConfig &print_config)
 

Static Public Member Functions

static void append_full_config (const Print &print, std::string &str)
 

Private Member Functions

void _do_export (Print &print, GCodeOutputStream &file, ThumbnailsGeneratorCallback thumbnail_cb)
 
LayerResult process_layer (const Print &print, const ObjectsLayerToPrint &layers, const LayerTools &layer_tools, const bool last_layer, const std::vector< const PrintInstance * > *ordering, const size_t single_object_idx=size_t(-1))
 
void process_layers (const Print &print, const ToolOrdering &tool_ordering, const std::vector< const PrintInstance * > &print_object_instances_ordering, const std::vector< std::pair< coordf_t, ObjectsLayerToPrint > > &layers_to_print, GCodeOutputStream &output_stream)
 
void process_layers (const Print &print, const ToolOrdering &tool_ordering, ObjectsLayerToPrint layers_to_print, const size_t single_object_idx, GCodeOutputStream &output_stream)
 
void set_last_pos (const Point &pos)
 
bool last_pos_defined () const
 
void set_extruders (const std::vector< unsigned int > &extruder_ids)
 
std::string preamble ()
 
std::string change_layer (coordf_t print_z)
 
std::string extrude_entity (const ExtrusionEntity &entity, const std::string_view description, double speed=-1.)
 
std::string extrude_loop (ExtrusionLoop loop, const std::string_view description, double speed=-1.)
 
std::string extrude_multi_path (ExtrusionMultiPath multipath, const std::string_view description, double speed=-1.)
 
std::string extrude_path (ExtrusionPath path, const std::string_view description, double speed=-1.)
 
std::vector< InstanceToPrintsort_print_object_instances (const std::vector< ObjectLayerToPrint > &layers, const std::vector< const PrintInstance * > *ordering, const size_t single_object_instance_idx)
 
void process_layer_single_object (std::string &gcode, const unsigned int extruder_id, const InstanceToPrint &print_instance, const ObjectLayerToPrint &layer_to_print, const LayerTools &layer_tools, const bool is_anything_overridden, const bool print_wipe_extrusions)
 
std::string extrude_support (const ExtrusionEntityCollection &support_fills)
 
std::string travel_to (const Point &point, ExtrusionRole role, std::string comment)
 
bool needs_retraction (const Polyline &travel, ExtrusionRole role=ExtrusionRole::None)
 
std::string retract (bool toolchange=false)
 
std::string unretract ()
 
std::string set_extruder (unsigned int extruder_id, double print_z)
 
std::string _extrude (const ExtrusionPath &path, const std::string_view description, double speed=-1)
 
void print_machine_envelope (GCodeOutputStream &file, Print &print)
 
void _print_first_layer_bed_temperature (GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait)
 
void _print_first_layer_extruder_temperatures (GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait)
 
bool on_first_layer () const
 
bool object_layer_over_raft () const
 

Static Private Member Functions

static ObjectsLayerToPrint collect_layers_to_print (const PrintObject &object)
 
static std::vector< std::pair< coordf_t, ObjectsLayerToPrint > > collect_layers_to_print (const Print &print)
 

Private Attributes

SeamPlacer m_seam_placer
 
ExtrusionQualityEstimator m_extrusion_quality_estimator
 
Vec2d m_origin
 
FullPrintConfig m_config
 
double m_scaled_resolution
 
GCodeWriter m_writer
 
struct Slic3r::GCode::PlaceholderParserIntegration m_placeholder_parser_integration
 
OozePrevention m_ooze_prevention
 
Wipe m_wipe
 
AvoidCrossingPerimeters m_avoid_crossing_perimeters
 
JPSPathFinder m_avoid_crossing_curled_overhangs
 
RetractWhenCrossingPerimeters m_retract_when_crossing_perimeters
 
bool m_enable_loop_clipping
 
bool m_enable_cooling_markers
 
bool m_enable_extrusion_role_markers
 
GCodeExtrusionRole m_last_processor_extrusion_role
 
unsigned int m_layer_count
 
int m_layer_index
 
const Layerm_layer
 
bool m_object_layer_over_raft
 
double m_volumetric_speed
 
GCodeExtrusionRole m_last_extrusion_role
 
float m_last_height { 0.0f }
 
float m_last_layer_z { 0.0f }
 
float m_max_layer_z { 0.0f }
 
float m_last_width { 0.0f }
 
Point m_last_pos
 
bool m_last_pos_defined
 
std::unique_ptr< CoolingBufferm_cooling_buffer
 
std::unique_ptr< SpiralVasem_spiral_vase
 
std::unique_ptr< GCodeFindReplacem_find_replace
 
std::unique_ptr< PressureEqualizerm_pressure_equalizer
 
std::unique_ptr< WipeTowerIntegrationm_wipe_tower
 
std::vector< coordf_tm_skirt_done
 
bool m_brim_done
 
bool m_second_layer_things_done
 
std::pair< const PrintObject *, Pointm_last_obj_copy
 
bool m_silent_time_estimator_enabled
 
GCodeProcessor m_processor
 

Friends

class Wipe
 
class WipeTowerIntegration
 
class PressureEqualizer
 

Detailed Description

Member Typedef Documentation

◆ ObjectsLayerToPrint

Constructor & Destructor Documentation

◆ GCode()

Slic3r::GCode::GCode ( )
inline
134 :
135 m_origin(Vec2d::Zero()),
140 m_layer_count(0),
141 m_layer_index(-1),
142 m_layer(nullptr),
145 m_last_pos_defined(false),
147 m_last_width(0.0f),
148#if ENABLE_GCODE_VIEWER_DATA_CHECKING
149 m_last_mm3_per_mm(0.0),
150#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
151 m_brim_done(false),
154 m_last_obj_copy(nullptr, Point(std::numeric_limits<coord_t>::max(), std::numeric_limits<coord_t>::max()))
155 {}
bool m_enable_cooling_markers
Definition GCode.hpp:386
double m_volumetric_speed
Definition GCode.hpp:402
bool m_brim_done
Definition GCode.hpp:426
bool m_object_layer_over_raft
Definition GCode.hpp:401
bool m_silent_time_estimator_enabled
Definition GCode.hpp:432
int m_layer_index
Definition GCode.hpp:396
bool m_second_layer_things_done
Definition GCode.hpp:428
bool m_enable_extrusion_role_markers
Definition GCode.hpp:389
Vec2d m_origin
Definition GCode.hpp:341
bool m_enable_loop_clipping
Definition GCode.hpp:382
const Layer * m_layer
Definition GCode.hpp:399
float m_last_width
Definition GCode.hpp:409
std::pair< const PrintObject *, Point > m_last_obj_copy
Definition GCode.hpp:430
GCodeExtrusionRole m_last_extrusion_role
Definition GCode.hpp:404
bool m_last_pos_defined
Definition GCode.hpp:415
GCodeExtrusionRole m_last_processor_extrusion_role
Definition GCode.hpp:391
unsigned int m_layer_count
Definition GCode.hpp:394
Kernel::Point_2 Point
Definition point_areas.cpp:20

◆ ~GCode()

Slic3r::GCode::~GCode ( )
default

Member Function Documentation

◆ _do_export()

void Slic3r::GCode::_do_export ( Print print,
GCodeOutputStream file,
ThumbnailsGeneratorCallback  thumbnail_cb 
)
private
1084{
1085 // modifies m_silent_time_estimator_enabled
1087
1088 if (! print.config().gcode_substitutions.values.empty()) {
1089 m_find_replace = make_unique<GCodeFindReplace>(print.config());
1090 file.set_find_replace(m_find_replace.get(), false);
1091 }
1092
1093 // resets analyzer's tracking data
1094 m_last_height = 0.f;
1095 m_last_layer_z = 0.f;
1096 m_max_layer_z = 0.f;
1097 m_last_width = 0.f;
1098#if ENABLE_GCODE_VIEWER_DATA_CHECKING
1099 m_last_mm3_per_mm = 0.;
1100#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
1101
1102 // How many times will be change_layer() called?
1103 // change_layer() in turn increments the progress bar status.
1104 m_layer_count = 0;
1105 if (print.config().complete_objects.value) {
1106 // Add each of the object's layers separately.
1107 for (auto object : print.objects()) {
1108 std::vector<coordf_t> zs;
1109 zs.reserve(object->layers().size() + object->support_layers().size());
1110 for (auto layer : object->layers())
1111 zs.push_back(layer->print_z);
1112 for (auto layer : object->support_layers())
1113 zs.push_back(layer->print_z);
1114 std::sort(zs.begin(), zs.end());
1115 m_layer_count += (unsigned int)(object->instances().size() * (std::unique(zs.begin(), zs.end()) - zs.begin()));
1116 }
1117 }
1118 print.throw_if_canceled();
1119
1121 this->apply_print_config(print.config());
1122
1124 print.throw_if_canceled();
1125
1126 if (print.config().spiral_vase.value)
1127 m_spiral_vase = make_unique<SpiralVase>(print.config());
1128
1129 if (print.config().max_volumetric_extrusion_rate_slope_positive.value > 0 ||
1130 print.config().max_volumetric_extrusion_rate_slope_negative.value > 0)
1131 m_pressure_equalizer = make_unique<PressureEqualizer>(print.config());
1133
1134 if (print.config().avoid_crossing_curled_overhangs){
1136 }
1137
1138 // Write information on the generator.
1139 file.write_format("; %s\n\n", Slic3r::header_slic3r_generated().c_str());
1140
1141 // Unit tests or command line slicing may not define "thumbnails" or "thumbnails_format".
1142 // If "thumbnails_format" is not defined, export to PNG.
1143 if (const auto [thumbnails, thumbnails_format] = std::make_pair(
1144 print.full_print_config().option<ConfigOptionPoints>("thumbnails"),
1145 print.full_print_config().option<ConfigOptionEnum<GCodeThumbnailsFormat>>("thumbnails_format"));
1146 thumbnails)
1148 thumbnail_cb, thumbnails->values, thumbnails_format ? thumbnails_format->value : GCodeThumbnailsFormat::PNG,
1149 [&file](const char* sz) { file.write(sz); },
1150 [&print]() { print.throw_if_canceled(); });
1151
1152 // Write notes (content of the Print Settings tab -> Notes)
1153 {
1154 std::list<std::string> lines;
1155 boost::split(lines, print.config().notes.value, boost::is_any_of("\n"), boost::token_compress_off);
1156 for (auto line : lines) {
1157 // Remove the trailing '\r' from the '\r\n' sequence.
1158 if (! line.empty() && line.back() == '\r')
1159 line.pop_back();
1160 file.write_format("; %s\n", line.c_str());
1161 }
1162 if (! lines.empty())
1163 file.write("\n");
1164 }
1165 print.throw_if_canceled();
1166
1167 // Write some terse information on the slicing parameters.
1168 const PrintObject *first_object = print.objects().front();
1169 const double layer_height = first_object->config().layer_height.value;
1170 assert(! print.config().first_layer_height.percent);
1171 const double first_layer_height = print.config().first_layer_height.value;
1172 for (size_t region_id = 0; region_id < print.num_print_regions(); ++ region_id) {
1173 const PrintRegion &region = print.get_print_region(region_id);
1174 file.write_format("; external perimeters extrusion width = %.2fmm\n", region.flow(*first_object, frExternalPerimeter, layer_height).width());
1175 file.write_format("; perimeters extrusion width = %.2fmm\n", region.flow(*first_object, frPerimeter, layer_height).width());
1176 file.write_format("; infill extrusion width = %.2fmm\n", region.flow(*first_object, frInfill, layer_height).width());
1177 file.write_format("; solid infill extrusion width = %.2fmm\n", region.flow(*first_object, frSolidInfill, layer_height).width());
1178 file.write_format("; top infill extrusion width = %.2fmm\n", region.flow(*first_object, frTopSolidInfill, layer_height).width());
1179 if (print.has_support_material())
1180 file.write_format("; support material extrusion width = %.2fmm\n", support_material_flow(first_object).width());
1181 if (print.config().first_layer_extrusion_width.value > 0)
1182 file.write_format("; first layer extrusion width = %.2fmm\n", region.flow(*first_object, frPerimeter, first_layer_height, true).width());
1183 file.write_format("\n");
1184 }
1185 print.throw_if_canceled();
1186
1187 // adds tags for time estimators
1188 if (print.config().remaining_times.value)
1190
1191 // Starting now, the G-code find / replace post-processor will be enabled.
1192 file.find_replace_enable();
1193
1194 // Prepare the helper object for replacing placeholders in custom G-code and output filename.
1195 m_placeholder_parser_integration.parser = print.placeholder_parser();
1197 m_placeholder_parser_integration.context.rng = std::mt19937(std::chrono::high_resolution_clock::now().time_since_epoch().count());
1198 // Enable passing global variables between PlaceholderParser invocations.
1199 m_placeholder_parser_integration.context.global_config = std::make_unique<DynamicConfig>();
1200 print.update_object_placeholders(m_placeholder_parser_integration.parser.config_writable(), ".gcode");
1201
1202 // Get optimal tool ordering to minimize tool switches of a multi-exruder print.
1203 // For a print by objects, find the 1st printing object.
1204 ToolOrdering tool_ordering;
1205 unsigned int initial_extruder_id = (unsigned int)-1;
1206 unsigned int final_extruder_id = (unsigned int)-1;
1207 bool has_wipe_tower = false;
1208 std::vector<const PrintInstance*> print_object_instances_ordering;
1209 std::vector<const PrintInstance*>::const_iterator print_object_instance_sequential_active;
1210 if (print.config().complete_objects.value) {
1211 // Order object instances for sequential print.
1212 print_object_instances_ordering = sort_object_instances_by_model_order(print);
1213// print_object_instances_ordering = sort_object_instances_by_max_z(print);
1214 // Find the 1st printing object, find its tool ordering and the initial extruder ID.
1215 print_object_instance_sequential_active = print_object_instances_ordering.begin();
1216 for (; print_object_instance_sequential_active != print_object_instances_ordering.end(); ++ print_object_instance_sequential_active) {
1217 tool_ordering = ToolOrdering(*(*print_object_instance_sequential_active)->print_object, initial_extruder_id);
1218 if ((initial_extruder_id = tool_ordering.first_extruder()) != static_cast<unsigned int>(-1))
1219 break;
1220 }
1221 if (initial_extruder_id == static_cast<unsigned int>(-1))
1222 // No object to print was found, cancel the G-code export.
1223 throw Slic3r::SlicingError(_u8L("No extrusions were generated for objects."));
1224 // We don't allow switching of extruders per layer by Model::custom_gcode_per_print_z in sequential mode.
1225 // Use the extruder IDs collected from Regions.
1226 this->set_extruders(print.extruders());
1227 } else {
1228 // Find tool ordering for all the objects at once, and the initial extruder ID.
1229 // If the tool ordering has been pre-calculated by Print class for wipe tower already, reuse it.
1230 tool_ordering = print.tool_ordering();
1231 tool_ordering.assign_custom_gcodes(print);
1232 if (tool_ordering.all_extruders().empty())
1233 // No object to print was found, cancel the G-code export.
1234 throw Slic3r::SlicingError(_u8L("No extrusions were generated for objects."));
1235 has_wipe_tower = print.has_wipe_tower() && tool_ordering.has_wipe_tower();
1236 initial_extruder_id = (has_wipe_tower && ! print.config().single_extruder_multi_material_priming) ?
1237 // The priming towers will be skipped.
1238 tool_ordering.all_extruders().back() :
1239 // Don't skip the priming towers.
1240 tool_ordering.first_extruder();
1241 // In non-sequential print, the printing extruders may have been modified by the extruder switches stored in Model::custom_gcode_per_print_z.
1242 // Therefore initialize the printing extruders from there.
1243 this->set_extruders(tool_ordering.all_extruders());
1244 // Order object instances using a nearest neighbor search.
1245 print_object_instances_ordering = chain_print_object_instances(print);
1246 m_layer_count = tool_ordering.layer_tools().size();
1247 }
1248 if (initial_extruder_id == (unsigned int)-1) {
1249 // Nothing to print!
1250 initial_extruder_id = 0;
1251 final_extruder_id = 0;
1252 } else {
1253 final_extruder_id = tool_ordering.last_extruder();
1254 assert(final_extruder_id != (unsigned int)-1);
1255 }
1256 print.throw_if_canceled();
1257
1258 m_cooling_buffer = make_unique<CoolingBuffer>(*this);
1259 m_cooling_buffer->set_current_extruder(initial_extruder_id);
1260
1261 // Emit machine envelope limits for the Marlin firmware.
1262 this->print_machine_envelope(file, print);
1263
1264 // Update output variables after the extruders were initialized.
1266 // Let the start-up script prime the 1st printing tool.
1267 this->placeholder_parser().set("initial_tool", initial_extruder_id);
1268 this->placeholder_parser().set("initial_extruder", initial_extruder_id);
1269 this->placeholder_parser().set("current_extruder", initial_extruder_id);
1270 //Set variable for total layer count so it can be used in custom gcode.
1271 this->placeholder_parser().set("total_layer_count", m_layer_count);
1272 // Useful for sequential prints.
1273 this->placeholder_parser().set("current_object_idx", 0);
1274 // For the start / end G-code to do the priming and final filament pull in case there is no wipe tower provided.
1275 this->placeholder_parser().set("has_wipe_tower", has_wipe_tower);
1276 this->placeholder_parser().set("has_single_extruder_multi_material_priming", has_wipe_tower && print.config().single_extruder_multi_material_priming);
1277 this->placeholder_parser().set("total_toolchanges", std::max(0, print.wipe_tower_data().number_of_toolchanges)); // Check for negative toolchanges (single extruder mode) and set to 0 (no tool change).
1278 {
1279 BoundingBoxf bbox(print.config().bed_shape.values);
1280 this->placeholder_parser().set("print_bed_min", new ConfigOptionFloats({ bbox.min.x(), bbox.min.y() }));
1281 this->placeholder_parser().set("print_bed_max", new ConfigOptionFloats({ bbox.max.x(), bbox.max.y() }));
1282 this->placeholder_parser().set("print_bed_size", new ConfigOptionFloats({ bbox.size().x(), bbox.size().y() }));
1283 }
1284 {
1285 // Convex hull of the 1st layer extrusions, for bed leveling and placing the initial purge line.
1286 // It encompasses the object extrusions, support extrusions, skirt, brim, wipe tower.
1287 // It does NOT encompass user extrusions generated by custom G-code,
1288 // therefore it does NOT encompass the initial purge line.
1289 // It does NOT encompass MMU/MMU2 starting (wipe) areas.
1290 auto pts = std::make_unique<ConfigOptionPoints>();
1291 pts->values.reserve(print.first_layer_convex_hull().size());
1292 for (const Point &pt : print.first_layer_convex_hull().points)
1293 pts->values.emplace_back(unscale(pt));
1294 BoundingBoxf bbox(pts->values);
1295 this->placeholder_parser().set("first_layer_print_convex_hull", pts.release());
1296 this->placeholder_parser().set("first_layer_print_min", new ConfigOptionFloats({ bbox.min.x(), bbox.min.y() }));
1297 this->placeholder_parser().set("first_layer_print_max", new ConfigOptionFloats({ bbox.max.x(), bbox.max.y() }));
1298 this->placeholder_parser().set("first_layer_print_size", new ConfigOptionFloats({ bbox.size().x(), bbox.size().y() }));
1299 this->placeholder_parser().set("num_extruders", int(print.config().nozzle_diameter.values.size()));
1300 // PlaceholderParser currently substitues non-existent vector values with the zero'th value, which is harmful in the case of "is_extruder_used[]"
1301 // as Slicer may lie about availability of such non-existent extruder.
1302 // We rather sacrifice 256B of memory before we change the behavior of the PlaceholderParser, which should really only fill in the non-existent
1303 // vector elements for filament parameters.
1304 std::vector<unsigned char> is_extruder_used(std::max(size_t(255), print.config().nozzle_diameter.size()), 0);
1305 for (unsigned int extruder_id : tool_ordering.all_extruders())
1306 is_extruder_used[extruder_id] = true;
1307 this->placeholder_parser().set("is_extruder_used", new ConfigOptionBools(is_extruder_used));
1308 }
1309
1310 // Enable ooze prevention if configured so.
1312
1313 std::string start_gcode = this->placeholder_parser_process("start_gcode", print.config().start_gcode.value, initial_extruder_id);
1314 // Set bed temperature if the start G-code does not contain any bed temp control G-codes.
1315 this->_print_first_layer_bed_temperature(file, print, start_gcode, initial_extruder_id, true);
1316 // Set extruder(s) temperature before and after start G-code.
1317 this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, false);
1318
1319 // adds tag for processor
1321
1322 // Write the custom start G-code
1323 file.writeln(start_gcode);
1324
1325 this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, true);
1326 print.throw_if_canceled();
1327
1328 // Set other general things.
1329 file.write(this->preamble());
1330
1331 print.throw_if_canceled();
1332
1333 // Collect custom seam data from all objects.
1334 std::function<void(void)> throw_if_canceled_func = [&print]() { print.throw_if_canceled();};
1335 m_seam_placer.init(print, throw_if_canceled_func);
1336
1337 if (! (has_wipe_tower && print.config().single_extruder_multi_material_priming)) {
1338 // Set initial extruder only after custom start G-code.
1339 // Ugly hack: Do not set the initial extruder if the extruder is primed using the MMU priming towers at the edge of the print bed.
1340 file.write(this->set_extruder(initial_extruder_id, 0.));
1341 }
1342
1343 // Do all objects for each layer.
1344 if (print.config().complete_objects.value) {
1345 size_t finished_objects = 0;
1346 const PrintObject *prev_object = (*print_object_instance_sequential_active)->print_object;
1347 for (; print_object_instance_sequential_active != print_object_instances_ordering.end(); ++ print_object_instance_sequential_active) {
1348 const PrintObject &object = *(*print_object_instance_sequential_active)->print_object;
1349 if (&object != prev_object || tool_ordering.first_extruder() != final_extruder_id) {
1350 tool_ordering = ToolOrdering(object, final_extruder_id);
1351 unsigned int new_extruder_id = tool_ordering.first_extruder();
1352 if (new_extruder_id == (unsigned int)-1)
1353 // Skip this object.
1354 continue;
1355 initial_extruder_id = new_extruder_id;
1356 final_extruder_id = tool_ordering.last_extruder();
1357 assert(final_extruder_id != (unsigned int)-1);
1358 }
1359 print.throw_if_canceled();
1360 this->set_origin(unscale((*print_object_instance_sequential_active)->shift));
1361 if (finished_objects > 0) {
1362 // Move to the origin position for the copy we're going to print.
1363 // This happens before Z goes down to layer 0 again, so that no collision happens hopefully.
1364 m_enable_cooling_markers = false; // we're not filtering these moves through CoolingBuffer
1366 file.write(this->retract());
1367 file.write(this->travel_to(Point(0, 0), ExtrusionRole::None, "move to origin position for next object"));
1369 // Disable motion planner when traveling to first object point.
1371 // Ff we are printing the bottom layer of an object, and we have already finished
1372 // another one, set first layer temperatures. This happens before the Z move
1373 // is triggered, so machine has more time to reach such temperatures.
1374 this->placeholder_parser().set("current_object_idx", int(finished_objects));
1375 std::string between_objects_gcode = this->placeholder_parser_process("between_objects_gcode", print.config().between_objects_gcode.value, initial_extruder_id);
1376 // Set first layer bed and extruder temperatures, don't wait for it to reach the temperature.
1377 this->_print_first_layer_bed_temperature(file, print, between_objects_gcode, initial_extruder_id, false);
1378 this->_print_first_layer_extruder_temperatures(file, print, between_objects_gcode, initial_extruder_id, false);
1379 file.writeln(between_objects_gcode);
1380 }
1381 // Reset the cooling buffer internal state (the current position, feed rate, accelerations).
1382 m_cooling_buffer->reset(this->writer().get_position());
1383 m_cooling_buffer->set_current_extruder(initial_extruder_id);
1384 // Process all layers of a single object instance (sequential mode) with a parallel pipeline:
1385 // Generate G-code, run the filters (vase mode, cooling buffer), run the G-code analyser
1386 // and export G-code into file.
1387 this->process_layers(print, tool_ordering, collect_layers_to_print(object), *print_object_instance_sequential_active - object.instances().data(), file);
1388 ++ finished_objects;
1389 // Flag indicating whether the nozzle temperature changes from 1st to 2nd layer were performed.
1390 // Reset it when starting another object from 1st layer.
1392 prev_object = &object;
1393 }
1394 } else {
1395 // Sort layers by Z.
1396 // All extrusion moves with the same top layer height are extruded uninterrupted.
1397 std::vector<std::pair<coordf_t, ObjectsLayerToPrint>> layers_to_print = collect_layers_to_print(print);
1398 // Prusa Multi-Material wipe tower.
1399 if (has_wipe_tower && ! layers_to_print.empty()) {
1400 m_wipe_tower.reset(new WipeTowerIntegration(print.config(), *print.wipe_tower_data().priming.get(), print.wipe_tower_data().tool_changes, *print.wipe_tower_data().final_purge.get()));
1401 file.write(m_writer.travel_to_z(first_layer_height + m_config.z_offset.value, "Move to the first layer height"));
1402 if (print.config().single_extruder_multi_material_priming) {
1403 file.write(m_wipe_tower->prime(*this));
1404 // Verify, whether the print overaps the priming extrusions.
1405 BoundingBoxf bbox_print(get_print_extrusions_extents(print));
1406 coordf_t twolayers_printz = ((layers_to_print.size() == 1) ? layers_to_print.front() : layers_to_print[1]).first + EPSILON;
1407 for (const PrintObject *print_object : print.objects())
1408 bbox_print.merge(get_print_object_extrusions_extents(*print_object, twolayers_printz));
1409 bbox_print.merge(get_wipe_tower_extrusions_extents(print, twolayers_printz));
1410 BoundingBoxf bbox_prime(get_wipe_tower_priming_extrusions_extents(print));
1411 bbox_prime.offset(0.5f);
1412 bool overlap = bbox_prime.overlap(bbox_print);
1413
1414 if (print.config().gcode_flavor == gcfMarlinLegacy || print.config().gcode_flavor == gcfMarlinFirmware) {
1415 file.write(this->retract());
1416 file.write("M300 S800 P500\n"); // Beep for 500ms, tone 800Hz.
1417 if (overlap) {
1418 // Wait for the user to remove the priming extrusions.
1419 file.write("M1 Remove priming towers and click button.\n");
1420 } else {
1421 // Just wait for a bit to let the user check, that the priming succeeded.
1422 //TODO Add a message explaining what the printer is waiting for. This needs a firmware fix.
1423 file.write("M1 S10\n");
1424 }
1425 } else {
1426 // This is not Marlin, M1 command is probably not supported.
1427 // (See https://github.com/prusa3d/PrusaSlicer/issues/5441.)
1428 if (overlap) {
1429 print.active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL,
1430 _u8L("Your print is very close to the priming regions. "
1431 "Make sure there is no collision."));
1432 } else {
1433 // Just continue printing, no action necessary.
1434 }
1435
1436 }
1437 }
1438 print.throw_if_canceled();
1439 }
1440 // Process all layers of all objects (non-sequential mode) with a parallel pipeline:
1441 // Generate G-code, run the filters (vase mode, cooling buffer), run the G-code analyser
1442 // and export G-code into file.
1443 this->process_layers(print, tool_ordering, print_object_instances_ordering, layers_to_print, file);
1444 if (m_wipe_tower)
1445 // Purge the extruder, pull out the active filament.
1446 file.write(m_wipe_tower->finalize(*this));
1447 }
1448
1449 // Write end commands to file.
1450 file.write(this->retract());
1451 file.write(m_writer.set_fan(0));
1452
1453 // adds tag for processor
1455
1456 // Process filament-specific gcode in extruder order.
1457 {
1458 DynamicConfig config;
1459 config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
1460 config.set_key_value("layer_z", new ConfigOptionFloat(m_writer.get_position().z() - m_config.z_offset.value));
1461 config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
1462 if (print.config().single_extruder_multi_material) {
1463 // Process the end_filament_gcode for the active filament only.
1464 int extruder_id = m_writer.extruder()->id();
1465 config.set_key_value("filament_extruder_id", new ConfigOptionInt(extruder_id));
1466 file.writeln(this->placeholder_parser_process("end_filament_gcode", print.config().end_filament_gcode.get_at(extruder_id), extruder_id, &config));
1467 } else {
1468 for (const std::string &end_gcode : print.config().end_filament_gcode.values) {
1469 int extruder_id = (unsigned int)(&end_gcode - &print.config().end_filament_gcode.values.front());
1470 config.set_key_value("filament_extruder_id", new ConfigOptionInt(extruder_id));
1471 file.writeln(this->placeholder_parser_process("end_filament_gcode", end_gcode, extruder_id, &config));
1472 }
1473 }
1474 file.writeln(this->placeholder_parser_process("end_gcode", print.config().end_gcode, m_writer.extruder()->id(), &config));
1475 }
1476 file.write(m_writer.update_progress(m_layer_count, m_layer_count, true)); // 100%
1477 file.write(m_writer.postamble());
1478
1479 // From now to the end of G-code, the G-code find / replace post-processor will be disabled.
1480 // Thus the PrusaSlicer generated config will NOT be processed by the G-code post-processor, see GH issue #7952.
1481 file.find_replace_supress();
1482
1483 // adds tags for time estimators
1484 if (print.config().remaining_times.value)
1486
1487 print.throw_if_canceled();
1488
1489 // Get filament stats.
1491 // Const inputs
1492 has_wipe_tower, print.wipe_tower_data(),
1493 this->config(),
1495 initial_extruder_id,
1496 // Modifies
1497 print.m_print_statistics));
1498 file.write("\n");
1499 file.write_format("; total filament used [g] = %.2lf\n", print.m_print_statistics.total_weight);
1500 file.write_format("; total filament cost = %.2lf\n", print.m_print_statistics.total_cost);
1501 if (print.m_print_statistics.total_toolchanges > 0)
1502 file.write_format("; total toolchanges = %i\n", print.m_print_statistics.total_toolchanges);
1504
1505 // Append full config, delimited by two 'phony' configuration keys prusaslicer_config = begin and prusaslicer_config = end.
1506 // The delimiters are structured as configuration key / value pairs to be parsable by older versions of PrusaSlicer G-code viewer.
1507 {
1508 file.write("\n; prusaslicer_config = begin\n");
1509 std::string full_config;
1510 append_full_config(print, full_config);
1511 if (!full_config.empty())
1512 file.write(full_config);
1513 file.write("; prusaslicer_config = end\n");
1514 }
1515 print.throw_if_canceled();
1516}
#define _u8L(s)
macro used to mark string used at localization, return same string
Definition SLAPrint.cpp:29
void use_external_mp_once()
Definition AvoidCrossingPerimeters.hpp:20
void disable_once()
Definition AvoidCrossingPerimeters.hpp:22
unsigned int id() const
Definition Extruder.hpp:17
std::unique_ptr< WipeTowerIntegration > m_wipe_tower
Definition GCode.hpp:421
void print_machine_envelope(GCodeOutputStream &file, Print &print)
Definition GCode.cpp:1797
GCodeProcessor m_processor
Definition GCode.hpp:435
std::string set_extruder(unsigned int extruder_id, double print_z)
Definition GCode.cpp:3316
std::string preamble()
Definition GCode.cpp:2618
friend class WipeTowerIntegration
Definition GCode.hpp:447
float m_max_layer_z
Definition GCode.hpp:408
GCodeWriter m_writer
Definition GCode.hpp:345
std::unique_ptr< GCodeFindReplace > m_find_replace
Definition GCode.hpp:419
void set_origin(const Vec2d &pointf)
Definition GCode.cpp:2606
std::string travel_to(const Point &point, ExtrusionRole role, std::string comment)
Definition GCode.cpp:3169
static void append_full_config(const Print &print, std::string &str)
Definition GCode.cpp:2572
std::string placeholder_parser_process(const std::string &name, const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override=nullptr)
Definition GCode.cpp:1683
float m_last_height
Definition GCode.hpp:406
void apply_print_config(const PrintConfig &print_config)
Definition GCode.cpp:2565
std::unique_ptr< SpiralVase > m_spiral_vase
Definition GCode.hpp:418
PlaceholderParser & placeholder_parser()
Definition GCode.hpp:176
std::string retract(bool toolchange=false)
Definition GCode.cpp:3290
void set_extruders(const std::vector< unsigned int > &extruder_ids)
Definition GCode.cpp:2593
float m_last_layer_z
Definition GCode.hpp:407
FullPrintConfig m_config
Definition GCode.hpp:342
void _print_first_layer_extruder_temperatures(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait)
Definition GCode.cpp:1880
struct Slic3r::GCode::PlaceholderParserIntegration m_placeholder_parser_integration
AvoidCrossingPerimeters m_avoid_crossing_perimeters
Definition GCode.hpp:379
GCodeWriter & writer()
Definition GCode.hpp:174
SeamPlacer m_seam_placer
Definition GCode.hpp:334
const FullPrintConfig & config() const
Definition GCode.hpp:172
static ObjectsLayerToPrint collect_layers_to_print(const PrintObject &object)
Definition GCode.cpp:547
OozePrevention m_ooze_prevention
Definition GCode.hpp:377
std::unique_ptr< CoolingBuffer > m_cooling_buffer
Definition GCode.hpp:417
std::unique_ptr< PressureEqualizer > m_pressure_equalizer
Definition GCode.hpp:420
void process_layers(const Print &print, const ToolOrdering &tool_ordering, const std::vector< const PrintInstance * > &print_object_instances_ordering, const std::vector< std::pair< coordf_t, ObjectsLayerToPrint > > &layers_to_print, GCodeOutputStream &output_stream)
Definition GCode.cpp:1521
const Layer * layer() const
Definition GCode.hpp:173
void _print_first_layer_bed_temperature(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait)
Definition GCode.cpp:1858
JPSPathFinder m_avoid_crossing_curled_overhangs
Definition GCode.hpp:380
static const std::string & reserved_tag(ETags tag)
Definition GCodeProcessor.hpp:186
const std::vector< Extruder > & extruders() const
Definition GCodeWriter.hpp:34
Extruder * extruder()
Definition GCodeWriter.hpp:26
std::string postamble() const
Definition GCodeWriter.cpp:80
static std::string set_fan(const GCodeFlavor gcode_flavor, bool gcode_comments, unsigned int speed)
Definition GCodeWriter.cpp:503
std::string update_progress(unsigned int num, unsigned int tot, bool allow_100=false) const
Definition GCodeWriter.cpp:207
std::string travel_to_z(double z, const std::string &comment=std::string())
Definition GCodeWriter.cpp:305
Vec3d get_position() const
Definition GCodeWriter.hpp:75
void init_bed_shape(const Points &bed_shape)
Definition JumpPointSearch.hpp:29
std::mt19937 rng
Definition PlaceholderParser.hpp:23
void set(const std::string &key, const std::string &value)
Definition PlaceholderParser.hpp:44
DynamicConfig & config_writable()
Definition PlaceholderParser.hpp:53
std::unique_ptr< DynamicConfig > global_config
Definition PlaceholderParser.hpp:26
static void update_timestamp(DynamicConfig &config)
Definition PlaceholderParser.cpp:76
void init(const Print &print, std::function< void(void)> throw_if_canceled_func)
Definition SeamPlacer.cpp:1414
#define const
Definition getopt.c:38
typedef void(GLAPIENTRYP _GLUfuncptr)(void)
static constexpr double EPSILON
Definition libslic3r.h:51
double coordf_t
Definition libslic3r.h:45
static void init_ooze_prevention(const Print &print, OozePrevention &ooze_prevention)
Definition GCode.cpp:966
static std::string update_print_stats_and_format_filament_stats(const bool has_wipe_tower, const WipeTowerData &wipe_tower_data, const FullPrintConfig &config, const std::vector< Extruder > &extruders, unsigned int initial_extruder_id, PrintStatistics &print_statistics)
Definition GCode.cpp:972
static void init_gcode_processor(const PrintConfig &config, GCodeProcessor &processor, bool &silent_time_estimator_enabled)
Definition GCode.cpp:899
static double autospeed_volumetric_limit(const Print &print)
Definition GCode.cpp:909
void export_thumbnails_to_file(ThumbnailsGeneratorCallback &thumbnail_cb, const std::vector< Vec2d > &sizes, GCodeThumbnailsFormat format, WriteToOutput output, ThrowIfCanceledCallback throw_if_canceled)
Definition Thumbnails.hpp:27
coord_t width(const BoundingBox &box)
Definition Arrange.cpp:539
@ gcfMarlinFirmware
Definition PrintConfig.hpp:35
@ gcfMarlinLegacy
Definition PrintConfig.hpp:35
ConfigOptionFloat
Definition PrintConfig.hpp:570
layer_height((ConfigOptionInt, faded_layers))((ConfigOptionFloat
@ frTopSolidInfill
Definition Flow.hpp:21
@ frExternalPerimeter
Definition Flow.hpp:17
@ frPerimeter
Definition Flow.hpp:18
@ frSolidInfill
Definition Flow.hpp:20
@ frInfill
Definition Flow.hpp:19
between_objects_gcode((ConfigOptionFloats, deretract_speed))((ConfigOptionString
BoundingBoxf get_wipe_tower_extrusions_extents(const Print &print, const coordf_t max_print_z)
Definition PrintExtents.cpp:136
BoundingBoxf get_print_object_extrusions_extents(const PrintObject &print_object, const coordf_t max_print_z)
Definition PrintExtents.cpp:108
std::string header_slic3r_generated()
Definition utils.cpp:914
Flow support_material_flow(const PrintObject *object, float layer_height)
Definition Flow.cpp:218
std::vector< const PrintInstance * > chain_print_object_instances(const Print &print)
Definition ShortestPath.cpp:1984
Points get_bed_shape(const DynamicPrintConfig &config)
Definition PrintConfig.cpp:4936
BoundingBoxf get_print_extrusions_extents(const Print &print)
Definition PrintExtents.cpp:101
std::vector< const PrintInstance * > sort_object_instances_by_model_order(const Print &print)
Definition GCode.cpp:1062
ConfigOptionBoolsTempl< false > ConfigOptionBools
Definition Config.hpp:1491
GCodeThumbnailsFormat
Definition PrintConfig.hpp:137
T unscale(Q v)
Definition libslic3r.h:95
ConfigOptionFloatsTempl< false > ConfigOptionFloats
Definition Config.hpp:716
end_gcode((ConfigOptionStrings, end_filament_gcode))((ConfigOptionString
BoundingBoxf get_wipe_tower_priming_extrusions_extents(const Print &print)
Definition PrintExtents.cpp:165
std::string gcode_extrusion_role_to_string(GCodeExtrusionRole role)
Definition ExtrusionRole.cpp:34
constexpr auto data(C &c) -> decltype(c.data())
Definition span.hpp:195
IGL_INLINE void count(const Eigen::SparseMatrix< XType > &X, const int dim, Eigen::SparseVector< SType > &S)
Definition count.cpp:12
TMultiShape< PolygonImpl > merge(const TMultiShape< PolygonImpl > &shapes)
Definition geometries.hpp:259
TCoord< P > x(const P &p)
Definition geometry_traits.hpp:297
static constexpr const ExtrusionRoleModifiers None
Definition ExtrusionRole.hpp:47
PlaceholderParser parser
Definition GCode.hpp:353
PlaceholderParser::ContextData context
Definition GCode.hpp:355
void init(const GCodeWriter &config)
Definition GCode.cpp:456

References _print_first_layer_bed_temperature(), _print_first_layer_extruder_temperatures(), _u8L, Slic3r::PrintBaseWithState< PrintStepEnumType, COUNT >::active_step_add_warning(), Slic3r::ToolOrdering::all_extruders(), append_full_config(), apply_print_config(), Slic3r::ToolOrdering::assign_custom_gcodes(), Slic3r::DoExport::autospeed_volumetric_limit(), Slic3r::between_objects_gcode(), Slic3r::chain_print_object_instances(), collect_layers_to_print(), config(), Slic3r::PrintObject::config(), Slic3r::Print::config(), Slic3r::PlaceholderParser::config_writable(), Slic3r::GCode::PlaceholderParserIntegration::context, Slic3r::PrintStateBase::CRITICAL, Slic3r::Custom, Slic3r::AvoidCrossingPerimeters::disable_once(), Slic3r::end_gcode(), EPSILON, Slic3r::GCodeProcessor::Estimated_Printing_Time_Placeholder, Slic3r::GCodeThumbnails::export_thumbnails_to_file(), Slic3r::GCodeWriter::extruder(), Slic3r::GCodeWriter::extruders(), Slic3r::Print::extruders(), Slic3r::WipeTowerData::final_purge, Slic3r::GCode::GCodeOutputStream::find_replace_enable(), Slic3r::GCode::GCodeOutputStream::find_replace_supress(), Slic3r::ToolOrdering::first_extruder(), Slic3r::Print::first_layer_convex_hull(), Slic3r::GCodeProcessor::First_Line_M73_Placeholder, Slic3r::PrintRegion::flow(), Slic3r::frExternalPerimeter, Slic3r::frInfill, Slic3r::frPerimeter, Slic3r::frSolidInfill, Slic3r::frTopSolidInfill, Slic3r::PrintBase::full_print_config(), Slic3r::gcfMarlinFirmware, Slic3r::gcfMarlinLegacy, Slic3r::gcode_extrusion_role_to_string(), Slic3r::get_bed_shape(), Slic3r::GCodeWriter::get_position(), Slic3r::get_print_extrusions_extents(), Slic3r::get_print_object_extrusions_extents(), Slic3r::Print::get_print_region(), Slic3r::get_wipe_tower_extrusions_extents(), Slic3r::get_wipe_tower_priming_extrusions_extents(), Slic3r::PlaceholderParser::ContextData::global_config, Slic3r::Print::has_support_material(), Slic3r::ToolOrdering::has_wipe_tower(), Slic3r::Print::has_wipe_tower(), Slic3r::header_slic3r_generated(), Slic3r::Extruder::id(), Slic3r::GCode::PlaceholderParserIntegration::init(), Slic3r::SeamPlacer::init(), Slic3r::JPSPathFinder::init_bed_shape(), Slic3r::DoExport::init_gcode_processor(), Slic3r::DoExport::init_ooze_prevention(), Slic3r::ToolOrdering::last_extruder(), Slic3r::GCodeProcessor::Last_Line_M73_Placeholder, layer(), Slic3r::layer_height(), Slic3r::ToolOrdering::layer_tools(), m_avoid_crossing_curled_overhangs, m_avoid_crossing_perimeters, m_config, m_cooling_buffer, m_enable_cooling_markers, m_enable_extrusion_role_markers, m_find_replace, m_last_height, m_last_layer_z, m_last_width, m_layer_count, m_layer_index, m_max_layer_z, m_ooze_prevention, m_placeholder_parser_integration, m_pressure_equalizer, Slic3r::Print::m_print_statistics, m_processor, m_seam_placer, m_second_layer_things_done, m_silent_time_estimator_enabled, m_spiral_vase, m_volumetric_speed, m_wipe_tower, m_writer, Slic3r::BoundingBoxBase< PointType, APointsType >::max, Slic3r::BoundingBoxBase< PointType, APointsType >::merge(), Slic3r::BoundingBoxBase< PointType, APointsType >::min, Slic3r::ExtrusionRole::None, Slic3r::Print::num_print_regions(), Slic3r::WipeTowerData::number_of_toolchanges, Slic3r::Print::objects(), Slic3r::BoundingBoxBase< PointType, APointsType >::offset(), Slic3r::ConfigBase::option(), Slic3r::BoundingBoxBase< PointType, APointsType >::overlap(), Slic3r::GCode::PlaceholderParserIntegration::parser, placeholder_parser(), Slic3r::PrintBase::placeholder_parser(), placeholder_parser_process(), Slic3r::PNG, Slic3r::MultiPoint::points, Slic3r::GCodeWriter::postamble(), preamble(), Slic3r::WipeTowerData::priming, print_machine_envelope(), Slic3r::Layer::print_z, process_layers(), Slic3r::GCodeProcessor::reserved_tag(), retract(), Slic3r::PlaceholderParser::ContextData::rng, Slic3r::GCodeProcessor::Role, Slic3r::PlaceholderParser::set(), set_extruder(), set_extruders(), Slic3r::GCodeWriter::set_fan(), Slic3r::GCode::GCodeOutputStream::set_find_replace(), set_origin(), Slic3r::BoundingBoxBase< PointType, APointsType >::size(), Slic3r::MultiPoint::size(), Slic3r::sort_object_instances_by_model_order(), Slic3r::support_material_flow(), Slic3r::PrintBase::throw_if_canceled(), Slic3r::WipeTowerData::tool_changes, Slic3r::Print::tool_ordering(), Slic3r::PrintStatistics::total_cost, Slic3r::PrintStatistics::total_toolchanges, Slic3r::PrintStatistics::total_weight, travel_to(), Slic3r::GCodeWriter::travel_to_z(), Slic3r::unscale(), Slic3r::PrintBase::update_object_placeholders(), Slic3r::DoExport::update_print_stats_and_format_filament_stats(), Slic3r::GCodeWriter::update_progress(), Slic3r::PlaceholderParser::update_timestamp(), Slic3r::AvoidCrossingPerimeters::use_external_mp_once(), void(), Slic3r::Flow::width(), Slic3r::Print::wipe_tower_data(), WipeTowerIntegration, Slic3r::GCode::GCodeOutputStream::write(), Slic3r::GCode::GCodeOutputStream::write_format(), Slic3r::GCode::GCodeOutputStream::writeln(), and writer().

Referenced by do_export().

+ Here is the caller graph for this function:

◆ _extrude()

std::string Slic3r::GCode::_extrude ( const ExtrusionPath path,
const std::string_view  description,
double  speed = -1 
)
private
2921{
2922 std::string gcode;
2923 const std::string_view description_bridge = path.role().is_bridge() ? " (bridge)"sv : ""sv;
2924
2925 // go to first point of extrusion path
2926 if (!m_last_pos_defined || m_last_pos != path.first_point()) {
2927 std::string comment = "move to first ";
2928 comment += description;
2929 comment += description_bridge;
2930 comment += " point";
2931 gcode += this->travel_to(path.first_point(), path.role(), comment);
2932 }
2933
2934 // compensate retraction
2935 gcode += this->unretract();
2936
2937 // adjust acceleration
2938 if (m_config.default_acceleration.value > 0) {
2939 double acceleration;
2940 if (this->on_first_layer() && m_config.first_layer_acceleration.value > 0) {
2941 acceleration = m_config.first_layer_acceleration.value;
2942 } else if (this->object_layer_over_raft() && m_config.first_layer_acceleration_over_raft.value > 0) {
2943 acceleration = m_config.first_layer_acceleration_over_raft.value;
2944 } else if (m_config.bridge_acceleration.value > 0 && path.role().is_bridge()) {
2945 acceleration = m_config.bridge_acceleration.value;
2946 } else if (m_config.top_solid_infill_acceleration > 0 && path.role() == ExtrusionRole::TopSolidInfill) {
2947 acceleration = m_config.top_solid_infill_acceleration.value;
2948 } else if (m_config.solid_infill_acceleration > 0 && path.role().is_solid_infill()) {
2949 acceleration = m_config.solid_infill_acceleration.value;
2950 } else if (m_config.infill_acceleration.value > 0 && path.role().is_infill()) {
2951 acceleration = m_config.infill_acceleration.value;
2952 } else if (m_config.external_perimeter_acceleration > 0 && path.role().is_external_perimeter()) {
2953 acceleration = m_config.external_perimeter_acceleration.value;
2954 } else if (m_config.perimeter_acceleration.value > 0 && path.role().is_perimeter()) {
2955 acceleration = m_config.perimeter_acceleration.value;
2956 } else {
2957 acceleration = m_config.default_acceleration.value;
2958 }
2959 gcode += m_writer.set_print_acceleration((unsigned int)floor(acceleration + 0.5));
2960 }
2961
2962 // calculate extrusion length per distance unit
2963 double e_per_mm = m_writer.extruder()->e_per_mm3() * path.mm3_per_mm;
2964 if (m_writer.extrusion_axis().empty())
2965 // gcfNoExtrusion
2966 e_per_mm = 0;
2967
2968 // set speed
2969 if (speed == -1) {
2970 if (path.role() == ExtrusionRole::Perimeter) {
2971 speed = m_config.get_abs_value("perimeter_speed");
2972 } else if (path.role() == ExtrusionRole::ExternalPerimeter) {
2973 speed = m_config.get_abs_value("external_perimeter_speed");
2974 } else if (path.role().is_bridge()) {
2975 assert(path.role().is_perimeter() || path.role() == ExtrusionRole::BridgeInfill);
2976 speed = m_config.get_abs_value("bridge_speed");
2977 } else if (path.role() == ExtrusionRole::InternalInfill) {
2978 speed = m_config.get_abs_value("infill_speed");
2979 } else if (path.role() == ExtrusionRole::SolidInfill) {
2980 speed = m_config.get_abs_value("solid_infill_speed");
2981 } else if (path.role() == ExtrusionRole::TopSolidInfill) {
2982 speed = m_config.get_abs_value("top_solid_infill_speed");
2983 } else if (path.role() == ExtrusionRole::Ironing) {
2984 speed = m_config.get_abs_value("ironing_speed");
2985 } else if (path.role() == ExtrusionRole::GapFill) {
2986 speed = m_config.get_abs_value("gap_fill_speed");
2987 } else {
2988 throw Slic3r::InvalidArgument("Invalid speed");
2989 }
2990 }
2991 if (m_volumetric_speed != 0. && speed == 0)
2992 speed = m_volumetric_speed / path.mm3_per_mm;
2993 if (this->on_first_layer())
2994 speed = m_config.get_abs_value("first_layer_speed", speed);
2995 else if (this->object_layer_over_raft())
2996 speed = m_config.get_abs_value("first_layer_speed_over_raft", speed);
2997 if (m_config.max_volumetric_speed.value > 0) {
2998 // cap speed with max_volumetric_speed anyway (even if user is not using autospeed)
2999 speed = std::min(
3000 speed,
3001 m_config.max_volumetric_speed.value / path.mm3_per_mm
3002 );
3003 }
3005 // cap speed with max_volumetric_speed anyway (even if user is not using autospeed)
3006 speed = std::min(
3007 speed,
3009 );
3010 }
3011
3012 bool variable_speed_or_fan_speed = false;
3013 std::vector<ProcessedPoint> new_points{};
3014 if ((this->m_config.enable_dynamic_overhang_speeds || this->config().enable_dynamic_fan_speeds.get_at(m_writer.extruder()->id())) &&
3015 !this->on_first_layer() && path.role().is_perimeter()) {
3016 std::vector<std::pair<int, ConfigOptionFloatOrPercent>> overhangs_with_speeds = {{100, ConfigOptionFloatOrPercent{speed, false}}};
3017 if (this->m_config.enable_dynamic_overhang_speeds) {
3018 overhangs_with_speeds = {{0, m_config.overhang_speed_0},
3019 {25, m_config.overhang_speed_1},
3020 {50, m_config.overhang_speed_2},
3021 {75, m_config.overhang_speed_3},
3022 {100, ConfigOptionFloatOrPercent{speed, false}}};
3023 }
3024
3025 std::vector<std::pair<int, ConfigOptionInts>> overhang_w_fan_speeds = {{100, ConfigOptionInts{0}}};
3026 if (this->m_config.enable_dynamic_fan_speeds.get_at(m_writer.extruder()->id())) {
3027 overhang_w_fan_speeds = {{0, m_config.overhang_fan_speed_0},
3028 {25, m_config.overhang_fan_speed_1},
3029 {50, m_config.overhang_fan_speed_2},
3030 {75, m_config.overhang_fan_speed_3},
3031 {100, ConfigOptionInts{0}}};
3032 }
3033
3034 double external_perim_reference_speed = m_config.get_abs_value("external_perimeter_speed");
3035 if (external_perim_reference_speed == 0)
3036 external_perim_reference_speed = m_volumetric_speed / path.mm3_per_mm;
3037 if (m_config.max_volumetric_speed.value > 0)
3038 external_perim_reference_speed = std::min(external_perim_reference_speed, m_config.max_volumetric_speed.value / path.mm3_per_mm);
3040 external_perim_reference_speed = std::min(external_perim_reference_speed,
3042 }
3043
3044 new_points = m_extrusion_quality_estimator.estimate_speed_from_extrusion_quality(path, overhangs_with_speeds, overhang_w_fan_speeds,
3045 m_writer.extruder()->id(), external_perim_reference_speed,
3046 speed);
3047 variable_speed_or_fan_speed = std::any_of(new_points.begin(), new_points.end(),
3048 [speed](const ProcessedPoint &p) { return p.speed != speed || p.fan_speed != 0; });
3049 }
3050
3051 double F = speed * 60; // convert mm/sec to mm/min
3052
3053 // extrude arc or line
3055 {
3057 {
3058 m_last_extrusion_role = role;
3060 {
3061 char buf[32];
3062 sprintf(buf, ";_EXTRUSION_ROLE:%d\n", int(m_last_extrusion_role));
3063 gcode += buf;
3064 }
3065 }
3066 }
3067
3068 // adds processor tags and updates processor tracking data
3069 // PrusaMultiMaterial::Writer may generate GCodeProcessor::Height_Tag lines without updating m_last_height
3070 // so, if the last role was GCodeExtrusionRole::WipeTower we force export of GCodeProcessor::Height_Tag lines
3071 bool last_was_wipe_tower = (m_last_processor_extrusion_role == GCodeExtrusionRole::WipeTower);
3073
3076 char buf[64];
3078 gcode += buf;
3079 }
3080
3081 if (last_was_wipe_tower || m_last_width != path.width) {
3082 m_last_width = path.width;
3085 }
3086
3087#if ENABLE_GCODE_VIEWER_DATA_CHECKING
3088 if (last_was_wipe_tower || (m_last_mm3_per_mm != path.mm3_per_mm)) {
3089 m_last_mm3_per_mm = path.mm3_per_mm;
3090 gcode += std::string(";") + GCodeProcessor::Mm3_Per_Mm_Tag
3091 + float_to_string_decimal_point(m_last_mm3_per_mm) + "\n";
3092 }
3093#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
3094
3095 if (last_was_wipe_tower || std::abs(m_last_height - path.height) > EPSILON) {
3096 m_last_height = path.height;
3097
3100 }
3101
3102 std::string cooling_marker_setspeed_comments;
3104 if (path.role().is_bridge())
3105 gcode += ";_BRIDGE_FAN_START\n";
3106 else
3107 cooling_marker_setspeed_comments = ";_EXTRUDE_SET_SPEED";
3108 if (path.role() == ExtrusionRole::ExternalPerimeter)
3109 cooling_marker_setspeed_comments += ";_EXTERNAL_PERIMETER";
3110 }
3111
3112 if (!variable_speed_or_fan_speed) {
3113 // F is mm per minute.
3114 gcode += m_writer.set_speed(F, "", cooling_marker_setspeed_comments);
3115 double path_length = 0.;
3116 std::string comment;
3117 if (m_config.gcode_comments) {
3118 comment = description;
3119 comment += description_bridge;
3120 }
3121 Vec2d prev = this->point_to_gcode_quantized(path.polyline.points.front());
3122 auto it = path.polyline.points.begin();
3123 auto end = path.polyline.points.end();
3124 for (++ it; it != end; ++ it) {
3125 Vec2d p = this->point_to_gcode_quantized(*it);
3126 const double line_length = (p - prev).norm();
3127 path_length += line_length;
3128 gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment);
3129 prev = p;
3130 }
3131 } else {
3132 std::string marked_comment;
3133 if (m_config.gcode_comments) {
3134 marked_comment = description;
3135 marked_comment += description_bridge;
3136 }
3137 double last_set_speed = new_points[0].speed * 60.0;
3138 double last_set_fan_speed = new_points[0].fan_speed;
3139 gcode += m_writer.set_speed(last_set_speed, "", cooling_marker_setspeed_comments);
3140 gcode += "\n;_SET_FAN_SPEED" + std::to_string(int(last_set_fan_speed)) + "\n";
3141 Vec2d prev = this->point_to_gcode_quantized(new_points[0].p);
3142 for (size_t i = 1; i < new_points.size(); i++) {
3143 const ProcessedPoint &processed_point = new_points[i];
3144 Vec2d p = this->point_to_gcode_quantized(processed_point.p);
3145 const double line_length = (p - prev).norm();
3146 gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, marked_comment);
3147 prev = p;
3148 double new_speed = processed_point.speed * 60.0;
3149 if (last_set_speed != new_speed) {
3150 gcode += m_writer.set_speed(new_speed, "", cooling_marker_setspeed_comments);
3151 last_set_speed = new_speed;
3152 }
3153 if (last_set_fan_speed != processed_point.fan_speed) {
3154 last_set_fan_speed = processed_point.fan_speed;
3155 gcode += "\n;_SET_FAN_SPEED" + std::to_string(int(last_set_fan_speed)) + "\n";
3156 }
3157 }
3158 gcode += "\n;_RESET_FAN_SPEED\n";
3159 }
3160
3162 gcode += path.role().is_bridge() ? ";_BRIDGE_FAN_END\n" : ";_EXTRUDE_END\n";
3163
3164 this->set_last_pos(path.last_point());
3165 return gcode;
3166}
EIGEN_DEVICE_FUNC const FloorReturnType floor() const
Definition ArrayCwiseUnaryOps.h:388
#define EXTRUDER_CONFIG(OPT)
Definition GCode.cpp:434
double e_per_mm3() const
Definition Extruder.hpp:34
std::vector< ProcessedPoint > estimate_speed_from_extrusion_quality(const ExtrusionPath &path, const std::vector< std::pair< int, ConfigOptionFloatOrPercent > > overhangs_w_speeds, const std::vector< std::pair< int, ConfigOptionInts > > overhangs_w_fan_speeds, size_t extruder_id, float ext_perimeter_speed, float original_speed)
Definition ExtrusionProcessor.hpp:243
bool object_layer_over_raft() const
Definition GCode.hpp:444
void set_last_pos(const Point &pos)
Definition GCode.hpp:278
Point m_last_pos
Definition GCode.hpp:414
ExtrusionQualityEstimator m_extrusion_quality_estimator
Definition GCode.hpp:336
Vec2d point_to_gcode_quantized(const Point &point) const
Definition GCode.cpp:3424
bool on_first_layer() const
Definition GCode.hpp:442
std::string unretract()
Definition GCode.hpp:330
std::string set_speed(double F, const std::string &comment=std::string(), const std::string &cooling_marker=std::string()) const
Definition GCodeWriter.cpp:248
std::string extrude_to_xy(const Vec2d &point, double dE, const std::string &comment=std::string())
Definition GCodeWriter.cpp:351
std::string extrusion_axis() const
Definition GCodeWriter.hpp:30
std::string set_print_acceleration(unsigned int acceleration)
Definition GCodeWriter.hpp:46
#define comment
Definition lexer.c:1004
filament_max_volumetric_speed((ConfigOptionFloats, filament_loading_speed))((ConfigOptionFloats
Eigen::Matrix< double, 2, 1, Eigen::DontAlign > Vec2d
Definition Point.hpp:51
GCodeExtrusionRole extrusion_role_to_gcode_extrusion_role(ExtrusionRole role)
Definition ExtrusionRole.cpp:13
bool is_decimal_separator_point()
Definition LocalesUtils.cpp:47
std::string float_to_string_decimal_point(double value, int precision)
Definition LocalesUtils.cpp:74
ConfigOptionIntsTempl< false > ConfigOptionInts
Definition Config.hpp:844
GCodeExtrusionRole
Definition ExtrusionRole.hpp:104
@ F
Definition libslic3r.h:102
S::iterator end(S &sh, const PathTag &)
Definition geometry_traits.hpp:620
static constexpr const ExtrusionRoleModifiers BridgeInfill
Definition ExtrusionRole.hpp:64
static constexpr const ExtrusionRoleModifiers TopSolidInfill
Definition ExtrusionRole.hpp:60
static constexpr const ExtrusionRoleModifiers Perimeter
Definition ExtrusionRole.hpp:49
static constexpr const ExtrusionRoleModifiers GapFill
Definition ExtrusionRole.hpp:69
static constexpr const ExtrusionRoleModifiers InternalInfill
Definition ExtrusionRole.hpp:55
static constexpr const ExtrusionRoleModifiers Ironing
Definition ExtrusionRole.hpp:62
static constexpr const ExtrusionRoleModifiers SolidInfill
Definition ExtrusionRole.hpp:57
static constexpr const ExtrusionRoleModifiers ExternalPerimeter
Definition ExtrusionRole.hpp:51

References Slic3r::ExtrusionRole::BridgeInfill, comment, Slic3r::Extruder::e_per_mm3(), EPSILON, Slic3r::ExtrusionQualityEstimator::estimate_speed_from_extrusion_quality(), Slic3r::ExtrusionRole::ExternalPerimeter, Slic3r::GCodeWriter::extrude_to_xy(), Slic3r::GCodeWriter::extruder(), EXTRUDER_CONFIG, Slic3r::GCodeWriter::extrusion_axis(), Slic3r::extrusion_role_to_gcode_extrusion_role(), Slic3r::F, Slic3r::ProcessedPoint::fan_speed, Slic3r::filament_max_volumetric_speed(), Slic3r::ExtrusionPath::first_point(), Slic3r::float_to_string_decimal_point(), floor(), Slic3r::ExtrusionRole::GapFill, Slic3r::gcode_extrusion_role_to_string(), Slic3r::ExtrusionPath::height, Slic3r::GCodeProcessor::Height, Slic3r::Extruder::id(), Slic3r::ExtrusionRole::InternalInfill, Slic3r::ExtrusionRole::Ironing, Slic3r::ExtrusionRole::is_bridge(), Slic3r::is_decimal_separator_point(), Slic3r::ExtrusionRole::is_external_perimeter(), Slic3r::ExtrusionRole::is_infill(), Slic3r::ExtrusionRole::is_perimeter(), Slic3r::ExtrusionRole::is_solid_infill(), Slic3r::ExtrusionPath::last_point(), m_config, m_enable_cooling_markers, m_enable_extrusion_role_markers, m_extrusion_quality_estimator, m_last_extrusion_role, m_last_height, m_last_pos, m_last_pos_defined, m_last_processor_extrusion_role, m_last_width, m_volumetric_speed, m_writer, Slic3r::ExtrusionPath::mm3_per_mm, object_layer_over_raft(), on_first_layer(), Slic3r::ProcessedPoint::p, Slic3r::ExtrusionRole::Perimeter, point_to_gcode_quantized(), Slic3r::MultiPoint::points, Slic3r::ExtrusionPath::polyline, Slic3r::GCodeProcessor::reserved_tag(), Slic3r::ExtrusionPath::role(), Slic3r::GCodeProcessor::Role, set_last_pos(), Slic3r::GCodeWriter::set_print_acceleration(), Slic3r::GCodeWriter::set_speed(), Slic3r::ExtrusionRole::SolidInfill, Slic3r::ProcessedPoint::speed, Slic3r::ExtrusionRole::TopSolidInfill, travel_to(), unretract(), Slic3r::ExtrusionPath::width, Slic3r::GCodeProcessor::Width, and Slic3r::WipeTower.

Referenced by extrude_loop(), extrude_multi_path(), and extrude_path().

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

◆ _print_first_layer_bed_temperature()

void Slic3r::GCode::_print_first_layer_bed_temperature ( GCodeOutputStream file,
Print print,
const std::string &  gcode,
unsigned int  first_printing_extruder_id,
bool  wait 
)
private
1859{
1860 bool autoemit = print.config().autoemit_temperature_commands;
1861 // Initial bed temperature based on the first extruder.
1862 int temp = print.config().first_layer_bed_temperature.get_at(first_printing_extruder_id);
1863 // Is the bed temperature set by the provided custom G-code?
1864 int temp_by_gcode = -1;
1865 bool temp_set_by_gcode = custom_gcode_sets_temperature(gcode, 140, 190, false, temp_by_gcode);
1866 if (autoemit && temp_set_by_gcode && temp_by_gcode >= 0 && temp_by_gcode < 1000)
1867 temp = temp_by_gcode;
1868 // Always call m_writer.set_bed_temperature() so it will set the internal "current" state of the bed temp as if
1869 // the custom start G-code emited these.
1870 std::string set_temp_gcode = m_writer.set_bed_temperature(temp, wait);
1871 if (autoemit && ! temp_set_by_gcode)
1872 file.write(set_temp_gcode);
1873}
std::string set_bed_temperature(unsigned int temperature, bool wait=false)
Definition GCodeWriter.cpp:130
static bool custom_gcode_sets_temperature(const std::string &gcode, const int mcode_set_temp_dont_wait, const int mcode_set_temp_and_wait, const bool include_g10, int &temp_out)
Definition GCode.cpp:1733

References Slic3r::Print::config(), Slic3r::custom_gcode_sets_temperature(), m_writer, Slic3r::GCodeWriter::set_bed_temperature(), and Slic3r::GCode::GCodeOutputStream::write().

Referenced by _do_export().

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

◆ _print_first_layer_extruder_temperatures()

void Slic3r::GCode::_print_first_layer_extruder_temperatures ( GCodeOutputStream file,
Print print,
const std::string &  gcode,
unsigned int  first_printing_extruder_id,
bool  wait 
)
private
1881{
1882 bool autoemit = print.config().autoemit_temperature_commands;
1883 // Is the bed temperature set by the provided custom G-code?
1884 int temp_by_gcode = -1;
1885 bool include_g10 = print.config().gcode_flavor == gcfRepRapFirmware;
1886 if (! autoemit || custom_gcode_sets_temperature(gcode, 104, 109, include_g10, temp_by_gcode)) {
1887 // Set the extruder temperature at m_writer, but throw away the generated G-code as it will be written with the custom G-code.
1888 int temp = print.config().first_layer_temperature.get_at(first_printing_extruder_id);
1889 if (autoemit && temp_by_gcode >= 0 && temp_by_gcode < 1000)
1890 temp = temp_by_gcode;
1891 m_writer.set_temperature(temp, wait, first_printing_extruder_id);
1892 } else {
1893 // Custom G-code does not set the extruder temperature. Do it now.
1894 if (print.config().single_extruder_multi_material.value) {
1895 // Set temperature of the first printing extruder only.
1896 int temp = print.config().first_layer_temperature.get_at(first_printing_extruder_id);
1897 if (temp > 0)
1898 file.write(m_writer.set_temperature(temp, wait, first_printing_extruder_id));
1899 } else {
1900 // Set temperatures of all the printing extruders.
1901 for (unsigned int tool_id : print.extruders()) {
1902 int temp = print.config().first_layer_temperature.get_at(tool_id);
1903
1904 if (print.config().ooze_prevention.value && tool_id != first_printing_extruder_id) {
1905 if (print.config().idle_temperature.is_nil(tool_id))
1906 temp += print.config().standby_temperature_delta.value;
1907 else
1908 temp = print.config().idle_temperature.get_at(tool_id);
1909 }
1910
1911 if (temp > 0)
1912 file.write(m_writer.set_temperature(temp, wait, tool_id));
1913 }
1914 }
1915 }
1916}
std::string set_temperature(unsigned int temperature, bool wait=false, int tool=-1) const
Definition GCodeWriter.cpp:88
@ gcfRepRapFirmware
Definition PrintConfig.hpp:35

References Slic3r::Print::config(), Slic3r::custom_gcode_sets_temperature(), Slic3r::Print::extruders(), Slic3r::gcfRepRapFirmware, m_writer, Slic3r::GCodeWriter::set_temperature(), and Slic3r::GCode::GCodeOutputStream::write().

Referenced by _do_export().

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

◆ append_full_config()

void Slic3r::GCode::append_full_config ( const Print print,
std::string &  str 
)
static
2573{
2574 const DynamicPrintConfig &cfg = print.full_print_config();
2575 // Sorted list of config keys, which shall not be stored into the G-code. Initializer list.
2576 static constexpr auto banned_keys = {
2577 "compatible_printers"sv,
2578 "compatible_prints"sv,
2579 //FIXME The print host keys should not be exported to full_print_config anymore. The following keys may likely be removed.
2580 "print_host"sv,
2581 "printhost_apikey"sv,
2582 "printhost_cafile"sv
2583 };
2584 assert(std::is_sorted(banned_keys.begin(), banned_keys.end()));
2585 auto is_banned = [](const std::string &key) {
2586 return std::binary_search(banned_keys.begin(), banned_keys.end(), key);
2587 };
2588 for (const std::string &key : cfg.keys())
2589 if (! is_banned(key) && ! cfg.option(key)->is_nil())
2590 str += "; " + key + " = " + cfg.opt_serialize(key) + "\n";
2591}
Definition getopt.h:102
if(!(yy_init))
Definition lexer.c:1190

References Slic3r::PrintBase::full_print_config(), Slic3r::ConfigOption::is_nil(), Slic3r::DynamicConfig::keys(), Slic3r::ConfigBase::opt_serialize(), and Slic3r::ConfigBase::option().

Referenced by _do_export().

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

◆ apply_print_config()

void Slic3r::GCode::apply_print_config ( const PrintConfig &  print_config)
2566{
2567 m_writer.apply_print_config(print_config);
2568 m_config.apply(print_config);
2569 m_scaled_resolution = scaled<double>(print_config.gcode_resolution.value);
2570}
double m_scaled_resolution
Definition GCode.hpp:344
void apply_print_config(const PrintConfig &print_config)
Definition GCodeWriter.cpp:24

References Slic3r::GCodeWriter::apply_print_config(), m_config, m_scaled_resolution, and m_writer.

Referenced by _do_export().

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

◆ change_layer()

std::string Slic3r::GCode::change_layer ( coordf_t  print_z)
private
2633{
2634 std::string gcode;
2635 if (m_layer_count > 0)
2636 // Increment a progress bar indicator.
2638 coordf_t z = print_z + m_config.z_offset.value; // in unscaled coordinates
2639 if (EXTRUDER_CONFIG(retract_layer_change) && m_writer.will_move_z(z))
2640 gcode += this->retract();
2641
2642 {
2643 std::ostringstream comment;
2644 comment << "move to next layer (" << m_layer_index << ")";
2645 gcode += m_writer.travel_to_z(z, comment.str());
2646 }
2647
2648 // forget last wiping path as wiping after raising Z is pointless
2650
2651 return gcode;
2652}
Wipe m_wipe
Definition GCode.hpp:378
bool will_move_z(double z) const
Definition GCodeWriter.cpp:339
void reset_path()
Definition GCode.hpp:58

References comment, EXTRUDER_CONFIG, m_config, m_layer_count, m_layer_index, m_wipe, m_writer, Slic3r::Wipe::reset_path(), retract(), Slic3r::GCodeWriter::travel_to_z(), Slic3r::GCodeWriter::update_progress(), and Slic3r::GCodeWriter::will_move_z().

Referenced by Slic3r::WipeTowerIntegration::finalize(), and process_layer().

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

◆ collect_layers_to_print() [1/2]

std::vector< std::pair< coordf_t, GCode::ObjectsLayerToPrint > > Slic3r::GCode::collect_layers_to_print ( const Print print)
staticprivate
649{
650 struct OrderingItem {
651 coordf_t print_z;
652 size_t object_idx;
653 size_t layer_idx;
654 };
655
656 std::vector<ObjectsLayerToPrint> per_object(print.objects().size(), ObjectsLayerToPrint());
657 std::vector<OrderingItem> ordering;
658 for (size_t i = 0; i < print.objects().size(); ++i) {
659 per_object[i] = collect_layers_to_print(*print.objects()[i]);
660 OrderingItem ordering_item;
661 ordering_item.object_idx = i;
662 ordering.reserve(ordering.size() + per_object[i].size());
663 const ObjectLayerToPrint &front = per_object[i].front();
664 for (const ObjectLayerToPrint &ltp : per_object[i]) {
665 ordering_item.print_z = ltp.print_z();
666 ordering_item.layer_idx = &ltp - &front;
667 ordering.emplace_back(ordering_item);
668 }
669 }
670
671 std::sort(ordering.begin(), ordering.end(), [](const OrderingItem& oi1, const OrderingItem& oi2) { return oi1.print_z < oi2.print_z; });
672
673 std::vector<std::pair<coordf_t, ObjectsLayerToPrint>> layers_to_print;
674
675 // Merge numerically very close Z values.
676 for (size_t i = 0; i < ordering.size();) {
677 // Find the last layer with roughly the same print_z.
678 size_t j = i + 1;
679 coordf_t zmax = ordering[i].print_z + EPSILON;
680 for (; j < ordering.size() && ordering[j].print_z <= zmax; ++j);
681 // Merge into layers_to_print.
682 std::pair<coordf_t, ObjectsLayerToPrint> merged;
683 // Assign an average print_z to the set of layers with nearly equal print_z.
684 merged.first = 0.5 * (ordering[i].print_z + ordering[j - 1].print_z);
685 merged.second.assign(print.objects().size(), ObjectLayerToPrint());
686 for (; i < j; ++i) {
687 const OrderingItem& oi = ordering[i];
688 assert(merged.second[oi.object_idx].layer() == nullptr);
689 merged.second[oi.object_idx] = std::move(per_object[oi.object_idx][oi.layer_idx]);
690 }
691 layers_to_print.emplace_back(std::move(merged));
692 }
693
694 return layers_to_print;
695}
std::vector< ObjectLayerToPrint > ObjectsLayerToPrint
Definition GCode.hpp:202
static enum @17 ordering
constexpr auto size(const C &c) -> decltype(c.size())
Definition span.hpp:183
TPoint< P > front(const P &p)
Definition geometry_traits.hpp:872

References collect_layers_to_print(), EPSILON, Slic3r::Print::objects(), and ordering.

+ Here is the call graph for this function:

◆ collect_layers_to_print() [2/2]

GCode::ObjectsLayerToPrint Slic3r::GCode::collect_layers_to_print ( const PrintObject object)
staticprivate
548{
549 GCode::ObjectsLayerToPrint layers_to_print;
550 layers_to_print.reserve(object.layers().size() + object.support_layers().size());
551
552 /*
553 // Calculate a minimum support layer height as a minimum over all extruders, but not smaller than 10um.
554 // This is the same logic as in support generator.
555 //FIXME should we use the printing extruders instead?
556 double gap_over_supports = object.config().support_material_contact_distance;
557 // FIXME should we test object.config().support_material_synchronize_layers ? Currently the support layers are synchronized with object layers iff soluble supports.
558 assert(!object.has_support() || gap_over_supports != 0. || object.config().support_material_synchronize_layers);
559 if (gap_over_supports != 0.) {
560 gap_over_supports = std::max(0., gap_over_supports);
561 // Not a soluble support,
562 double support_layer_height_min = 1000000.;
563 for (auto lh : object.print()->config().min_layer_height.values)
564 support_layer_height_min = std::min(support_layer_height_min, std::max(0.01, lh));
565 gap_over_supports += support_layer_height_min;
566 }*/
567
568 std::vector<std::pair<double, double>> warning_ranges;
569
570 // Pair the object layers with the support layers by z.
571 size_t idx_object_layer = 0;
572 size_t idx_support_layer = 0;
573 const ObjectLayerToPrint* last_extrusion_layer = nullptr;
574 while (idx_object_layer < object.layers().size() || idx_support_layer < object.support_layers().size()) {
575 ObjectLayerToPrint layer_to_print;
576 layer_to_print.object_layer = (idx_object_layer < object.layers().size()) ? object.layers()[idx_object_layer++] : nullptr;
577 layer_to_print.support_layer = (idx_support_layer < object.support_layers().size()) ? object.support_layers()[idx_support_layer++] : nullptr;
578 if (layer_to_print.object_layer && layer_to_print.support_layer) {
579 if (layer_to_print.object_layer->print_z < layer_to_print.support_layer->print_z - EPSILON) {
580 layer_to_print.support_layer = nullptr;
581 --idx_support_layer;
582 }
583 else if (layer_to_print.support_layer->print_z < layer_to_print.object_layer->print_z - EPSILON) {
584 layer_to_print.object_layer = nullptr;
585 --idx_object_layer;
586 }
587 }
588
589 layers_to_print.emplace_back(layer_to_print);
590
591 bool has_extrusions = (layer_to_print.object_layer && layer_to_print.object_layer->has_extrusions())
592 || (layer_to_print.support_layer && layer_to_print.support_layer->has_extrusions());
593
594 // Check that there are extrusions on the very first layer. The case with empty
595 // first layer may result in skirt/brim in the air and maybe other issues.
596 if (layers_to_print.size() == 1u) {
597 if (!has_extrusions)
598 throw Slic3r::SlicingError(_u8L("There is an object with no extrusions in the first layer.") + "\n" +
599 _u8L("Object name") + ": " + object.model_object()->name);
600 }
601
602 // In case there are extrusions on this layer, check there is a layer to lay it on.
603 if ((layer_to_print.object_layer && layer_to_print.object_layer->has_extrusions())
604 // Allow empty support layers, as the support generator may produce no extrusions for non-empty support regions.
605 || (layer_to_print.support_layer /* && layer_to_print.support_layer->has_extrusions() */)) {
606 double top_cd = object.config().support_material_contact_distance;
607 double bottom_cd = object.config().support_material_bottom_contact_distance == 0. ? top_cd : object.config().support_material_bottom_contact_distance;
608
609 double extra_gap = (layer_to_print.support_layer ? bottom_cd : top_cd);
610
611 double maximal_print_z = (last_extrusion_layer ? last_extrusion_layer->print_z() : 0.)
612 + layer_to_print.layer()->height
613 + std::max(0., extra_gap);
614 // Negative support_contact_z is not taken into account, it can result in false positives in cases
615 // where previous layer has object extrusions too (https://github.com/prusa3d/PrusaSlicer/issues/2752)
616
617 if (has_extrusions && layer_to_print.print_z() > maximal_print_z + 2. * EPSILON)
618 warning_ranges.emplace_back(std::make_pair((last_extrusion_layer ? last_extrusion_layer->print_z() : 0.), layers_to_print.back().print_z()));
619 }
620 // Remember last layer with extrusions.
621 if (has_extrusions)
622 last_extrusion_layer = &layers_to_print.back();
623 }
624
625 if (! warning_ranges.empty()) {
626 std::string warning;
627 size_t i = 0;
628 for (i = 0; i < std::min(warning_ranges.size(), size_t(3)); ++i)
629 warning += Slic3r::format(_u8L("Empty layer between %1% and %2%."),
630 warning_ranges[i].first, warning_ranges[i].second) + "\n";
631 if (i < warning_ranges.size())
632 warning += _u8L("(Some lines not shown)") + "\n";
633 warning += "\n";
634 warning += Slic3r::format(_u8L("Object name: %1%"), object.model_object()->name) + "\n\n"
635 + _u8L("Make sure the object is printable. This is usually caused by negligibly small extrusions or by a faulty model. "
636 "Try to repair the model or change its orientation on the bed.");
637
638 const_cast<Print*>(object.print())->active_step_add_warning(
640 }
641
642 return layers_to_print;
643}
std::string format(const char *fmt, TArgs &&... args)
Definition format.hpp:44
TPoint< P > back(const P &p)
Definition geometry_traits.hpp:873

References _u8L, Slic3r::PrintStateBase::CRITICAL, EPSILON, Slic3r::format(), Slic3r::Layer::has_extrusions(), Slic3r::SupportLayer::has_extrusions(), Slic3r::Layer::height, Slic3r::GCode::ObjectLayerToPrint::layer(), Slic3r::GCode::ObjectLayerToPrint::object_layer, Slic3r::GCode::ObjectLayerToPrint::print_z(), Slic3r::Layer::print_z, and Slic3r::GCode::ObjectLayerToPrint::support_layer.

Referenced by _do_export(), and collect_layers_to_print().

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

◆ config()

const FullPrintConfig & Slic3r::GCode::config ( ) const
inline

◆ do_export()

void Slic3r::GCode::do_export ( Print print,
const char *  path,
GCodeProcessorResult result = nullptr,
ThumbnailsGeneratorCallback  thumbnail_cb = nullptr 
)
803{
804 CNumericLocalesSetter locales_setter;
805
806 // Does the file exist? If so, we hope that it is still valid.
807 {
808 PrintStateBase::StateWithTimeStamp state = print->step_state_with_timestamp(psGCodeExport);
809 if (! state.enabled || (state.is_done() && boost::filesystem::exists(boost::filesystem::path(path))))
810 return;
811 }
812
813 // Enabled and either not done, or marked as done while the output file is missing.
814 print->set_started(psGCodeExport);
815
816 // check if any custom gcode contains keywords used by the gcode processor to
817 // produce time estimation and gcode toolpaths
818 std::vector<std::pair<std::string, std::string>> validation_res = DoExport::validate_custom_gcode(*print);
819 if (!validation_res.empty()) {
820 std::string reports;
821 for (const auto& [source, keyword] : validation_res) {
822 reports += source + ": \"" + keyword + "\"\n";
823 }
824 print->active_step_add_warning(PrintStateBase::WarningLevel::NON_CRITICAL,
825 _u8L("In the custom G-code were found reserved keywords:") + "\n" +
826 reports +
827 _u8L("This may cause problems in g-code visualization and printing time estimation."));
828 }
829
830 BOOST_LOG_TRIVIAL(info) << "Exporting G-code..." << log_memory_info();
831
832 // Remove the old g-code if it exists.
833 boost::nowide::remove(path);
834
835 std::string path_tmp(path);
836 path_tmp += ".tmp";
837
838 m_processor.initialize(path_tmp);
839 m_processor.set_print(print);
840 GCodeOutputStream file(boost::nowide::fopen(path_tmp.c_str(), "wb"), m_processor);
841 if (! file.is_open())
842 throw Slic3r::RuntimeError(std::string("G-code export to ") + path + " failed.\nCannot open the file for writing.\n");
843
844 try {
845 this->_do_export(*print, file, thumbnail_cb);
846 file.flush();
847 if (file.is_error()) {
848 file.close();
849 boost::nowide::remove(path_tmp.c_str());
850 throw Slic3r::RuntimeError(std::string("G-code export to ") + path + " failed\nIs the disk full?\n");
851 }
852 } catch (std::exception & /* ex */) {
853 // Rethrow on any exception. std::runtime_exception and CanceledException are expected to be thrown.
854 // Close and remove the file.
855 file.close();
856 boost::nowide::remove(path_tmp.c_str());
857 throw;
858 }
859 file.close();
860
862 // G-code export proceeded, but some of the PlaceholderParser substitutions failed.
863 //FIXME localize!
864 std::string msg = std::string("G-code export to ") + path + " failed due to invalid custom G-code sections:\n\n";
865 for (const auto &name_and_error : m_placeholder_parser_integration.failed_templates)
866 msg += name_and_error.first + "\n" + name_and_error.second + "\n";
867 msg += "\nPlease inspect the file ";
868 msg += path_tmp + " for error messages enclosed between\n";
869 msg += " !!!!! Failed to process the custom G-code template ...\n";
870 msg += "and\n";
871 msg += " !!!!! End of an error report for the custom G-code template ...\n";
872 msg += "for all macro processing errors.";
873 throw Slic3r::PlaceholderParserError(msg);
874 }
875
876 BOOST_LOG_TRIVIAL(debug) << "Start processing gcode, " << log_memory_info();
877 // Post-process the G-code to update time stamps.
878 m_processor.finalize(true);
879// DoExport::update_print_estimated_times_stats(m_processor, print->m_print_statistics);
881 if (result != nullptr) {
882 *result = std::move(m_processor.extract_result());
883 // set the filename to the correct value
884 result->filename = path;
885 }
886 BOOST_LOG_TRIVIAL(debug) << "Finished processing gcode, " << log_memory_info();
887
888 if (rename_file(path_tmp, path))
889 throw Slic3r::RuntimeError(
890 std::string("Failed to rename the output G-code file from ") + path_tmp + " to " + path + '\n' +
891 "Is " + path_tmp + " locked?" + '\n');
892
893 BOOST_LOG_TRIVIAL(info) << "Exporting G-code finished" << log_memory_info();
894 print->set_done(psGCodeExport);
895}
void _do_export(Print &print, GCodeOutputStream &file, ThumbnailsGeneratorCallback thumbnail_cb)
Definition GCode.cpp:1083
void set_print(Print *print)
Definition GCodeProcessor.hpp:624
void finalize(bool post_process)
Definition GCodeProcessor.cpp:1114
GCodeProcessorResult && extract_result()
Definition GCodeProcessor.hpp:634
void initialize(const std::string &filename)
Definition GCodeProcessor.cpp:1093
TOKEN * keyword(int primary)
Definition config.c:261
static std::vector< std::pair< std::string, std::string > > validate_custom_gcode(const Print &print)
Definition GCode.cpp:748
static void update_print_estimated_stats(const GCodeProcessor &processor, const std::vector< Extruder > &extruders, PrintStatistics &print_statistics)
Definition GCode.cpp:707
@ psGCodeExport
Definition Print.hpp:64
std::string log_memory_info(bool ignore_loglevel)
Definition utils.cpp:1073
std::error_code rename_file(const std::string &from, const std::string &to)
Definition utils.cpp:468
std::map< std::string, std::string > failed_templates
Definition GCode.hpp:357

References _do_export(), _u8L, Slic3r::PrintBaseWithState< PrintStepEnumType, COUNT >::active_step_add_warning(), Slic3r::GCode::GCodeOutputStream::close(), Slic3r::PrintStateBase::StateWithTimeStamp::enabled, Slic3r::GCodeProcessor::extract_result(), Slic3r::GCodeWriter::extruders(), Slic3r::GCode::PlaceholderParserIntegration::failed_templates, Slic3r::GCodeProcessorResult::filename, Slic3r::GCodeProcessor::finalize(), Slic3r::GCode::GCodeOutputStream::flush(), Slic3r::GCodeProcessor::initialize(), Slic3r::PrintStateBase::StateWithTimeStamp::is_done(), Slic3r::GCode::GCodeOutputStream::is_error(), Slic3r::GCode::GCodeOutputStream::is_open(), keyword(), Slic3r::log_memory_info(), m_placeholder_parser_integration, Slic3r::Print::m_print_statistics, m_processor, m_writer, Slic3r::PrintStateBase::NON_CRITICAL, Slic3r::psGCodeExport, Slic3r::rename_file(), Slic3r::PrintBaseWithState< PrintStepEnumType, COUNT >::set_done(), Slic3r::GCodeProcessor::set_print(), Slic3r::PrintBaseWithState< PrintStepEnumType, COUNT >::set_started(), Slic3r::PrintBaseWithState< PrintStepEnumType, COUNT >::step_state_with_timestamp(), Slic3r::DoExport::update_print_estimated_stats(), and Slic3r::DoExport::validate_custom_gcode().

+ Here is the call graph for this function:

◆ enable_cooling_markers()

bool Slic3r::GCode::enable_cooling_markers ( ) const
inline
181{ return m_enable_cooling_markers; }

References m_enable_cooling_markers.

Referenced by Slic3r::Wipe::wipe().

+ Here is the caller graph for this function:

◆ extrude_entity()

std::string Slic3r::GCode::extrude_entity ( const ExtrusionEntity entity,
const std::string_view  description,
double  speed = -1. 
)
private
2795{
2796 if (const ExtrusionPath* path = dynamic_cast<const ExtrusionPath*>(&entity))
2797 return this->extrude_path(*path, description, speed);
2798 else if (const ExtrusionMultiPath* multipath = dynamic_cast<const ExtrusionMultiPath*>(&entity))
2799 return this->extrude_multi_path(*multipath, description, speed);
2800 else if (const ExtrusionLoop* loop = dynamic_cast<const ExtrusionLoop*>(&entity))
2801 return this->extrude_loop(*loop, description, speed);
2802 else
2803 throw Slic3r::InvalidArgument("Invalid argument supplied to extrude()");
2804 return "";
2805}
std::string extrude_path(ExtrusionPath path, const std::string_view description, double speed=-1.)
Definition GCode.cpp:2807
std::string extrude_loop(ExtrusionLoop loop, const std::string_view description, double speed=-1.)
Definition GCode.cpp:2654
std::string extrude_multi_path(ExtrusionMultiPath multipath, const std::string_view description, double speed=-1.)
Definition GCode.cpp:2761

References extrude_loop(), extrude_multi_path(), and extrude_path().

Referenced by process_layer(), and process_layer_single_object().

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

◆ extrude_loop()

std::string Slic3r::GCode::extrude_loop ( ExtrusionLoop  loop,
const std::string_view  description,
double  speed = -1. 
)
private
2655{
2656 // get a copy; don't modify the orientation of the original loop object otherwise
2657 // next copies (if any) would not detect the correct orientation
2658
2659 // extrude all loops ccw
2660 bool was_clockwise = loop.make_counter_clockwise();
2661
2662 // find the point of the loop that is closest to the current extruder position
2663 // or randomize if requested
2664 Point last_pos = this->last_pos();
2665
2666 if (! m_config.spiral_vase && comment_is_perimeter(description)) {
2667 assert(m_layer != nullptr);
2668 m_seam_placer.place_seam(m_layer, loop, m_config.external_perimeters_first, this->last_pos());
2669 } else
2670 // Because the G-code export has 1um resolution, don't generate segments shorter than 1.5 microns,
2671 // thus empty path segments will not be produced by G-code export.
2672 loop.split_at(last_pos, false, scaled<double>(0.0015));
2673
2674 for (auto it = std::next(loop.paths.begin()); it != loop.paths.end(); ++it) {
2675 assert(it->polyline.points.size() >= 2);
2676 assert(std::prev(it)->polyline.last_point() == it->polyline.first_point());
2677 }
2678 assert(loop.paths.front().first_point() == loop.paths.back().last_point());
2679
2680 // clip the path to avoid the extruder to get exactly on the first point of the loop;
2681 // if polyline was shorter than the clipping distance we'd get a null polyline, so
2682 // we discard it in that case
2683 double clip_length = m_enable_loop_clipping ?
2685 0;
2686
2687 // get paths
2688 ExtrusionPaths paths;
2689 loop.clip_end(clip_length, &paths);
2690 if (paths.empty()) return "";
2691
2692 // apply the small perimeter speed
2693 if (paths.front().role().is_perimeter() && loop.length() <= SMALL_PERIMETER_LENGTH && speed == -1)
2694 speed = m_config.small_perimeter_speed.get_abs_value(m_config.perimeter_speed);
2695
2696 // extrude along the path
2697 std::string gcode;
2698 for (ExtrusionPath &path : paths) {
2699 path.simplify(m_scaled_resolution);
2700 gcode += this->_extrude(path, description, speed);
2701 }
2702
2703 // reset acceleration
2704 gcode += m_writer.set_print_acceleration((unsigned int)(m_config.default_acceleration.value + 0.5));
2705
2706 if (m_wipe.enable) {
2707 m_wipe.path = paths.front().polyline;
2708
2709 for (auto it = std::next(paths.begin()); it != paths.end(); ++it) {
2710 if (it->role().is_bridge())
2711 break; // Don't perform a wipe on bridges.
2712
2713 assert(it->polyline.points.size() >= 2);
2714 assert(m_wipe.path.points.back() == it->polyline.first_point());
2715 if (m_wipe.path.points.back() != it->polyline.first_point())
2716 break; // ExtrusionLoop is interrupted in some place.
2717
2718 m_wipe.path.points.insert(m_wipe.path.points.end(), it->polyline.points.begin() + 1, it->polyline.points.end());
2719 }
2720 }
2721
2722 // make a little move inwards before leaving loop
2723 if (paths.back().role().is_external_perimeter() && m_layer != NULL && m_config.perimeters.value > 1 && paths.front().size() >= 2 && paths.back().polyline.points.size() >= 3) {
2724 // detect angle between last and first segment
2725 // the side depends on the original winding order of the polygon (left for contours, right for holes)
2726 //FIXME improve the algorithm in case the loop is tiny.
2727 //FIXME improve the algorithm in case the loop is split into segments with a low number of points (see the Point b query).
2728 // Angle from the 2nd point to the last point.
2729 double angle_inside = angle(paths.front().polyline.points[1] - paths.front().first_point(),
2730 *(paths.back().polyline.points.end()-3) - paths.front().first_point());
2731 assert(angle_inside >= -M_PI && angle_inside <= M_PI);
2732 // 3rd of this angle will be taken, thus make the angle monotonic before interpolation.
2733 if (was_clockwise) {
2734 if (angle_inside > 0)
2735 angle_inside -= 2.0 * M_PI;
2736 } else {
2737 if (angle_inside < 0)
2738 angle_inside += 2.0 * M_PI;
2739 }
2740
2741 // create the destination point along the first segment and rotate it
2742 // we make sure we don't exceed the segment length because we don't know
2743 // the rotation of the second segment so we might cross the object boundary
2744 Vec2d p1 = paths.front().polyline.points.front().cast<double>();
2745 Vec2d p2 = paths.front().polyline.points[1].cast<double>();
2746 Vec2d v = p2 - p1;
2747 double nd = scale_(EXTRUDER_CONFIG(nozzle_diameter));
2748 double l2 = v.squaredNorm();
2749 // Shift by no more than a nozzle diameter.
2750 //FIXME Hiding the seams will not work nicely for very densely discretized contours!
2751 Point pt = ((nd * nd >= l2) ? p2 : (p1 + v * (nd / sqrt(l2)))).cast<coord_t>();
2752 // Rotate pt inside around the seam point.
2753 pt.rotate(angle_inside / 3., paths.front().polyline.points.front());
2754 // generate the travel move
2755 gcode += m_writer.travel_to_xy(this->point_to_gcode(pt), "move inwards before travel");
2756 }
2757
2758 return gcode;
2759}
EIGEN_DEVICE_FUNC const SqrtReturnType sqrt() const
Definition ArrayCwiseUnaryOps.h:152
EIGEN_DEVICE_FUNC CastXpr< NewType >::Type cast() const
Definition CommonCwiseUnaryOps.h:62
#define M_PI
Definition ExtrusionSimulator.cpp:20
std::string _extrude(const ExtrusionPath &path, const std::string_view description, double speed=-1)
Definition GCode.cpp:2920
const Point & last_pos() const
Definition GCode.hpp:166
Vec2d point_to_gcode(const Point &point) const
Definition GCode.cpp:3418
std::string travel_to_xy(const Vec2d &point, const std::string &comment=std::string())
Definition GCodeWriter.cpp:260
Points points
Definition MultiPoint.hpp:18
const Point & front() const
Definition MultiPoint.hpp:36
void place_seam(const Layer *layer, ExtrusionLoop &loop, bool external_first, const Point &last_pos) const
Definition SeamPlacer.cpp:1487
bool enable
Definition GCode.hpp:53
Polyline path
Definition GCode.hpp:54
static constexpr double LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER
Definition libslic3r.h:60
#define scale_(val)
Definition libslic3r.h:69
int32_t coord_t
Definition libslic3r.h:39
#define SMALL_PERIMETER_LENGTH
Definition libslic3r.h:62
T l2(const boost::geometry::model::d2::point_xy< T > &v)
Definition ExtrusionSimulator.cpp:166
std::vector< ExtrusionPath > ExtrusionPaths
Definition ExtrusionEntity.hpp:135
double angle(const Eigen::MatrixBase< Derived > &v1, const Eigen::MatrixBase< Derived2 > &v2)
Definition Point.hpp:112
static bool comment_is_perimeter(const std::string_view comment)
Definition GCode.cpp:2343
IGL_INLINE void loop(const int n_verts, const Eigen::PlainObjectBase< DerivedF > &F, Eigen::SparseMatrix< SType > &S, Eigen::PlainObjectBase< DerivedNF > &NF)
Definition loop.cpp:21

References _extrude(), Slic3r::angle(), Slic3r::comment_is_perimeter(), Slic3r::Wipe::enable, EXTRUDER_CONFIG, Slic3r::MultiPoint::front(), Slic3r::l2(), last_pos(), LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER, m_config, m_enable_loop_clipping, m_layer, M_PI, m_scaled_resolution, m_seam_placer, m_wipe, m_writer, Slic3r::Wipe::path, Slic3r::SeamPlacer::place_seam(), point_to_gcode(), Slic3r::MultiPoint::points, Slic3r::Point::rotate(), scale_, Slic3r::GCodeWriter::set_print_acceleration(), SMALL_PERIMETER_LENGTH, sqrt(), and Slic3r::GCodeWriter::travel_to_xy().

Referenced by extrude_entity(), and process_layer().

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

◆ extrude_multi_path()

std::string Slic3r::GCode::extrude_multi_path ( ExtrusionMultiPath  multipath,
const std::string_view  description,
double  speed = -1. 
)
private
2762{
2763 for (auto it = std::next(multipath.paths.begin()); it != multipath.paths.end(); ++it) {
2764 assert(it->polyline.points.size() >= 2);
2765 assert(std::prev(it)->polyline.last_point() == it->polyline.first_point());
2766 }
2767 // extrude along the path
2768 std::string gcode;
2769 for (ExtrusionPath path : multipath.paths) {
2770 path.simplify(m_scaled_resolution);
2771 gcode += this->_extrude(path, description, speed);
2772 }
2773 if (m_wipe.enable) {
2774 m_wipe.path = std::move(multipath.paths.back().polyline);
2776
2777 for (auto it = std::next(multipath.paths.rbegin()); it != multipath.paths.rend(); ++it) {
2778 if (it->role().is_bridge())
2779 break; // Do not perform a wipe on bridges.
2780
2781 assert(it->polyline.points.size() >= 2);
2782 assert(m_wipe.path.points.back() == it->polyline.last_point());
2783 if (m_wipe.path.points.back() != it->polyline.last_point())
2784 break; // ExtrusionMultiPath is interrupted in some place.
2785
2786 m_wipe.path.points.insert(m_wipe.path.points.end(), it->polyline.points.rbegin() + 1, it->polyline.points.rend());
2787 }
2788 }
2789 // reset acceleration
2790 gcode += m_writer.set_print_acceleration((unsigned int)floor(m_config.default_acceleration.value + 0.5));
2791 return gcode;
2792}
void reverse()
Definition MultiPoint.hpp:34

References _extrude(), Slic3r::Wipe::enable, floor(), m_config, m_scaled_resolution, m_wipe, m_writer, Slic3r::Wipe::path, Slic3r::ExtrusionMultiPath::paths, Slic3r::MultiPoint::points, Slic3r::MultiPoint::reverse(), and Slic3r::GCodeWriter::set_print_acceleration().

Referenced by extrude_entity(), and extrude_support().

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

◆ extrude_path()

std::string Slic3r::GCode::extrude_path ( ExtrusionPath  path,
const std::string_view  description,
double  speed = -1. 
)
private
2808{
2809 path.simplify(m_scaled_resolution);
2810 std::string gcode = this->_extrude(path, description, speed);
2811 if (m_wipe.enable) {
2812 m_wipe.path = std::move(path.polyline);
2814 }
2815 // reset acceleration
2816 gcode += m_writer.set_print_acceleration((unsigned int)floor(m_config.default_acceleration.value + 0.5));
2817 return gcode;
2818}

References _extrude(), Slic3r::Wipe::enable, floor(), m_config, m_scaled_resolution, m_wipe, m_writer, Slic3r::Wipe::path, Slic3r::ExtrusionPath::polyline, Slic3r::MultiPoint::reverse(), Slic3r::GCodeWriter::set_print_acceleration(), and Slic3r::ExtrusionPath::simplify().

Referenced by extrude_entity(), and extrude_support().

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

◆ extrude_support()

std::string Slic3r::GCode::extrude_support ( const ExtrusionEntityCollection support_fills)
private
2821{
2822 static constexpr const auto support_label = "support material"sv;
2823 static constexpr const auto support_interface_label = "support material interface"sv;
2824
2825 std::string gcode;
2826 if (! support_fills.entities.empty()) {
2827 const double support_speed = m_config.support_material_speed.value;
2828 const double support_interface_speed = m_config.support_material_interface_speed.get_abs_value(support_speed);
2829 for (const ExtrusionEntity *ee : support_fills.entities) {
2830 ExtrusionRole role = ee->role();
2832 const auto label = (role == ExtrusionRole::SupportMaterial) ? support_label : support_interface_label;
2833 const double speed = (role == ExtrusionRole::SupportMaterial) ? support_speed : support_interface_speed;
2834 const ExtrusionPath *path = dynamic_cast<const ExtrusionPath*>(ee);
2835 if (path)
2836 gcode += this->extrude_path(*path, label, speed);
2837 else {
2838 const ExtrusionMultiPath *multipath = dynamic_cast<const ExtrusionMultiPath*>(ee);
2839 if (multipath)
2840 gcode += this->extrude_multi_path(*multipath, label, speed);
2841 else {
2842 const ExtrusionEntityCollection *eec = dynamic_cast<const ExtrusionEntityCollection*>(ee);
2843 assert(eec);
2844 if (eec)
2845 gcode += this->extrude_support(*eec);
2846 }
2847 }
2848 }
2849 }
2850 return gcode;
2851}
std::string extrude_support(const ExtrusionEntityCollection &support_fills)
Definition GCode.cpp:2820
static constexpr const ExtrusionRoleModifiers SupportMaterial
Definition ExtrusionRole.hpp:73
static constexpr const ExtrusionRoleModifiers SupportMaterialInterface
Definition ExtrusionRole.hpp:75

References Slic3r::ExtrusionEntityCollection::entities, extrude_multi_path(), extrude_path(), extrude_support(), m_config, Slic3r::ExtrusionRole::SupportMaterial, and Slic3r::ExtrusionRole::SupportMaterialInterface.

Referenced by extrude_support(), and process_layer_single_object().

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

◆ gcode_to_point()

Point Slic3r::GCode::gcode_to_point ( const Vec2d point) const
3432{
3433 Vec2d pt = point - m_origin;
3434 if (const Extruder *extruder = m_writer.extruder(); extruder)
3435 // This function may be called at the very start from toolchange G-code when the extruder is not assigned yet.
3436 pt += m_config.extruder_offset.get_at(extruder->id());
3437 return scaled<coord_t>(pt);
3438
3439}

References Slic3r::GCodeWriter::extruder(), m_config, m_origin, and m_writer.

Referenced by placeholder_parser_process(), and Slic3r::Wipe::wipe().

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

◆ last_pos()

const Point & Slic3r::GCode::last_pos ( ) const
inline
166{ return m_last_pos; }

References m_last_pos.

Referenced by extrude_loop(), Slic3r::AvoidCrossingPerimeters::travel_to(), travel_to(), and Slic3r::Wipe::wipe().

+ Here is the caller graph for this function:

◆ last_pos_defined()

bool Slic3r::GCode::last_pos_defined ( ) const
inlineprivate
279{ return m_last_pos_defined; }

References m_last_pos_defined.

◆ layer()

const Layer * Slic3r::GCode::layer ( ) const
inline
173{ return m_layer; }

References m_layer.

Referenced by _do_export(), Slic3r::OozePrevention::_get_temp(), process_layer(), process_layer_single_object(), process_layers(), process_layers(), and Slic3r::AvoidCrossingPerimeters::travel_to().

+ Here is the caller graph for this function:

◆ layer_count()

unsigned int Slic3r::GCode::layer_count ( ) const
inline
184{ return m_layer_count; }

References m_layer_count.

◆ needs_retraction()

bool Slic3r::GCode::needs_retraction ( const Polyline travel,
ExtrusionRole  role = ExtrusionRole::None 
)
private
3252{
3253 if (travel.length() < scale_(EXTRUDER_CONFIG(retract_before_travel))) {
3254 // skip retraction if the move is shorter than the configured threshold
3255 return false;
3256 }
3257
3259 if (const SupportLayer *support_layer = dynamic_cast<const SupportLayer*>(m_layer);
3260 support_layer != nullptr && ! support_layer->support_islands_bboxes.empty()) {
3261 BoundingBox bbox_travel = get_extents(travel);
3262 Polylines trimmed;
3263 bool trimmed_initialized = false;
3264 for (const BoundingBox &bbox : support_layer->support_islands_bboxes)
3265 if (bbox.overlap(bbox_travel)) {
3266 const auto &island = support_layer->support_islands[&bbox - support_layer->support_islands_bboxes.data()];
3267 trimmed = trimmed_initialized ? diff_pl(trimmed, island) : diff_pl(travel, island);
3268 trimmed_initialized = true;
3269 if (trimmed.empty())
3270 // skip retraction if this is a travel move inside a support material island
3271 //FIXME not retracting over a long path may cause oozing, which in turn may result in missing material
3272 // at the end of the extrusion path!
3273 return false;
3274 // Not sure whether updating the boudning box isn't too expensive.
3275 //bbox_travel = get_extents(trimmed);
3276 }
3277 }
3278
3279 if (m_config.only_retract_when_crossing_perimeters && m_layer != nullptr &&
3281 // Skip retraction if travel is contained in an internal slice *and*
3282 // internal infill is enabled (so that stringing is entirely not visible).
3283 //FIXME any_internal_region_slice_contains() is potentionally very slow, it shall test for the bounding boxes first.
3284 return false;
3285
3286 // retract if only_retract_when_crossing_perimeters is disabled or doesn't apply
3287 return true;
3288}
RetractWhenCrossingPerimeters m_retract_when_crossing_perimeters
Definition GCode.hpp:381
bool travel_inside_internal_regions(const Layer &layer, const Polyline &travel)
Definition RetractWhenCrossingPerimeters.cpp:9
Slic3r::Polylines diff_pl(const Slic3r::Polyline &subject, const Slic3r::Polygons &clip)
Definition ClipperUtils.cpp:852
std::vector< Polyline > Polylines
Definition Polyline.hpp:14
BoundingBox get_extents(const ExPolygon &expolygon)
Definition ExPolygon.cpp:352

References Slic3r::diff_pl(), EXTRUDER_CONFIG, Slic3r::get_extents(), Slic3r::Polyline::length(), m_config, m_layer, m_retract_when_crossing_perimeters, scale_, Slic3r::SupportLayer::support_islands_bboxes, Slic3r::ExtrusionRole::SupportMaterial, and Slic3r::RetractWhenCrossingPerimeters::travel_inside_internal_regions().

Referenced by travel_to().

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

◆ object_layer_over_raft()

bool Slic3r::GCode::object_layer_over_raft ( ) const
inlineprivate
444{ return m_object_layer_over_raft; }

References m_object_layer_over_raft.

Referenced by _extrude().

+ Here is the caller graph for this function:

◆ on_first_layer()

bool Slic3r::GCode::on_first_layer ( ) const
inlineprivate
442{ return m_layer != nullptr && m_layer->id() == 0; }
size_t id() const
Definition Layer.hpp:315

References Slic3r::Layer::id(), and m_layer.

Referenced by _extrude().

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

◆ origin()

const Vec2d & Slic3r::GCode::origin ( ) const
inline
163{ return m_origin; }

References m_origin.

Referenced by Slic3r::AvoidCrossingPerimeters::travel_to(), travel_to(), and Slic3r::wipe_tower_point_to_object_point().

+ Here is the caller graph for this function:

◆ placeholder_parser() [1/2]

PlaceholderParser & Slic3r::GCode::placeholder_parser ( )
inline

References m_placeholder_parser_integration, and Slic3r::GCode::PlaceholderParserIntegration::parser.

Referenced by _do_export(), and set_extruder().

+ Here is the caller graph for this function:

◆ placeholder_parser() [2/2]

◆ placeholder_parser_process()

std::string Slic3r::GCode::placeholder_parser_process ( const std::string &  name,
const std::string &  templ,
unsigned int  current_extruder_id,
const DynamicConfig config_override = nullptr 
)
1688{
1689 PlaceholderParserIntegration &ppi = m_placeholder_parser_integration;
1690 try {
1692 std::string output = ppi.parser.process(templ, current_extruder_id, config_override, &ppi.output_config, &ppi.context);
1693 ppi.validate_output_vector_variables();
1694
1695 if (const std::vector<double> &pos = ppi.opt_position->values; ppi.position != pos) {
1696 // Update G-code writer.
1697 m_writer.update_position({ pos[0], pos[1], pos[2] });
1698 this->set_last_pos(this->gcode_to_point({ pos[0], pos[1] }));
1699 }
1700
1701 for (const Extruder &e : m_writer.extruders()) {
1702 unsigned int eid = e.id();
1703 assert(eid < ppi.num_extruders);
1704 if ( eid < ppi.num_extruders) {
1705 if (! m_writer.config.use_relative_e_distances && ! is_approx(ppi.e_position[eid], ppi.opt_e_position->values[eid]))
1706 const_cast<Extruder&>(e).set_position(ppi.opt_e_position->values[eid]);
1707 if (! is_approx(ppi.e_retracted[eid], ppi.opt_e_retracted->values[eid]) ||
1708 ! is_approx(ppi.e_restart_extra[eid], ppi.opt_e_restart_extra->values[eid]))
1709 const_cast<Extruder&>(e).set_retracted(ppi.opt_e_retracted->values[eid], ppi.opt_e_restart_extra->values[eid]);
1710 }
1711 }
1712
1713 return output;
1714 }
1715 catch (std::runtime_error &err)
1716 {
1717 // Collect the names of failed template substitutions for error reporting.
1718 auto it = ppi.failed_templates.find(name);
1719 if (it == ppi.failed_templates.end())
1720 // Only if there was no error reported for this template, store the first error message into the map to be reported.
1721 // We don't want to collect error message for each and every occurence of a single custom G-code section.
1722 ppi.failed_templates.insert(it, std::make_pair(name, std::string(err.what())));
1723 // Insert the macro error message into the G-code.
1724 return
1725 std::string("\n!!!!! Failed to process the custom G-code template ") + name + "\n" +
1726 err.what() +
1727 "!!!!! End of an error report for the custom G-code template " + name + "\n\n";
1728 }
1729}
Point gcode_to_point(const Vec2d &point) const
Definition GCode.cpp:3431
GCodeConfig config
Definition GCodeWriter.hpp:16
void update_position(const Vec3d &new_pos)
Definition GCodeWriter.cpp:489
Vec3d pos(const Pt &p)
Definition ReprojectPointsOnMesh.hpp:14
constexpr bool is_approx(Number value, Number test_value, Number precision=EPSILON)
Definition libslic3r.h:271
void update_from_gcodewriter(const GCodeWriter &writer)
Definition GCode.cpp:492

References Slic3r::GCodeWriter::config, Slic3r::GCode::PlaceholderParserIntegration::context, Slic3r::GCode::PlaceholderParserIntegration::e_position, Slic3r::GCode::PlaceholderParserIntegration::e_restart_extra, Slic3r::GCode::PlaceholderParserIntegration::e_retracted, Slic3r::GCodeWriter::extruders(), Slic3r::GCode::PlaceholderParserIntegration::failed_templates, gcode_to_point(), Slic3r::is_approx(), m_placeholder_parser_integration, m_writer, Slic3r::GCode::PlaceholderParserIntegration::num_extruders, Slic3r::GCode::PlaceholderParserIntegration::opt_e_position, Slic3r::GCode::PlaceholderParserIntegration::opt_e_restart_extra, Slic3r::GCode::PlaceholderParserIntegration::opt_e_retracted, Slic3r::GCode::PlaceholderParserIntegration::opt_position, Slic3r::GCode::PlaceholderParserIntegration::output_config, Slic3r::GCode::PlaceholderParserIntegration::parser, Slic3r::GCode::PlaceholderParserIntegration::position, Slic3r::PlaceholderParser::process(), set_last_pos(), Slic3r::Extruder::set_retracted(), Slic3r::GCode::PlaceholderParserIntegration::update_from_gcodewriter(), Slic3r::GCodeWriter::update_position(), Slic3r::GCode::PlaceholderParserIntegration::validate_output_vector_variables(), and Slic3r::ConfigOptionVector< T >::values.

Referenced by _do_export(), Slic3r::WipeTowerIntegration::append_tcr(), Slic3r::ProcessLayer::emit_custom_gcode_per_print_z(), process_layer(), and set_extruder().

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

◆ point_to_gcode()

Vec2d Slic3r::GCode::point_to_gcode ( const Point point) const
3419{
3420 Vec2d extruder_offset = EXTRUDER_CONFIG(extruder_offset);
3421 return unscaled<double>(point) + m_origin - extruder_offset;
3422}

References EXTRUDER_CONFIG, and m_origin.

Referenced by extrude_loop(), and point_to_gcode_quantized().

+ Here is the caller graph for this function:

◆ point_to_gcode_quantized()

Vec2d Slic3r::GCode::point_to_gcode_quantized ( const Point point) const
3425{
3426 Vec2d p = this->point_to_gcode(point);
3428}
static double quantize_xyzf(double v)
Definition GCodeWriter.hpp:153

References point_to_gcode(), and Slic3r::GCodeFormatter::quantize_xyzf().

Referenced by _extrude(), and Slic3r::Wipe::wipe().

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

◆ preamble()

std::string Slic3r::GCode::preamble ( )
private
2619{
2620 std::string gcode = m_writer.preamble();
2621
2622 /* Perform a *silent* move to z_offset: we need this to initialize the Z
2623 position of our writer object so that any initial lift taking place
2624 before the first layer change will raise the extruder from the correct
2625 initial Z instead of 0. */
2626 m_writer.travel_to_z(m_config.z_offset.value);
2627
2628 return gcode;
2629}
std::string preamble()
Definition GCodeWriter.cpp:52

References m_config, m_writer, Slic3r::GCodeWriter::preamble(), and Slic3r::GCodeWriter::travel_to_z().

Referenced by _do_export().

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

◆ print_machine_envelope()

void Slic3r::GCode::print_machine_envelope ( GCodeOutputStream file,
Print print 
)
private
1798{
1799 const GCodeFlavor flavor = print.config().gcode_flavor.value;
1800 if ( (flavor == gcfMarlinLegacy || flavor == gcfMarlinFirmware || flavor == gcfRepRapFirmware)
1801 && print.config().machine_limits_usage.value == MachineLimitsUsage::EmitToGCode) {
1802 int factor = flavor == gcfRepRapFirmware ? 60 : 1; // RRF M203 and M566 are in mm/min
1803 file.write_format("M201 X%d Y%d Z%d E%d ; sets maximum accelerations, mm/sec^2\n",
1804 int(print.config().machine_max_acceleration_x.values.front() + 0.5),
1805 int(print.config().machine_max_acceleration_y.values.front() + 0.5),
1806 int(print.config().machine_max_acceleration_z.values.front() + 0.5),
1807 int(print.config().machine_max_acceleration_e.values.front() + 0.5));
1808 file.write_format("M203 X%d Y%d Z%d E%d ; sets maximum feedrates, %s\n",
1809 int(print.config().machine_max_feedrate_x.values.front() * factor + 0.5),
1810 int(print.config().machine_max_feedrate_y.values.front() * factor + 0.5),
1811 int(print.config().machine_max_feedrate_z.values.front() * factor + 0.5),
1812 int(print.config().machine_max_feedrate_e.values.front() * factor + 0.5),
1813 factor == 60 ? "mm / min" : "mm / sec");
1814
1815 // Now M204 - acceleration. This one is quite hairy...
1816 if (flavor == gcfRepRapFirmware)
1817 // Uses M204 P[print] T[travel]
1818 file.write_format("M204 P%d T%d ; sets acceleration (P, T), mm/sec^2\n",
1819 int(print.config().machine_max_acceleration_extruding.values.front() + 0.5),
1820 int(print.config().machine_max_acceleration_travel.values.front() + 0.5));
1821 else if (flavor == gcfMarlinLegacy)
1822 // Legacy Marlin uses M204 S[print] T[retract]
1823 file.write_format("M204 S%d T%d ; sets acceleration (S) and retract acceleration (R), mm/sec^2\n",
1824 int(print.config().machine_max_acceleration_extruding.values.front() + 0.5),
1825 int(print.config().machine_max_acceleration_retracting.values.front() + 0.5));
1826 else if (flavor == gcfMarlinFirmware)
1827 // New Marlin uses M204 P[print] R[retract] T[travel]
1828 file.write_format("M204 P%d R%d T%d ; sets acceleration (P, T) and retract acceleration (R), mm/sec^2\n",
1829 int(print.config().machine_max_acceleration_extruding.values.front() + 0.5),
1830 int(print.config().machine_max_acceleration_retracting.values.front() + 0.5),
1831 int(print.config().machine_max_acceleration_travel.values.front() + 0.5));
1832 else
1833 assert(false);
1834
1836 file.write_format(flavor == gcfRepRapFirmware
1837 ? "M566 X%.2lf Y%.2lf Z%.2lf E%.2lf ; sets the jerk limits, mm/min\n"
1838 : "M205 X%.2lf Y%.2lf Z%.2lf E%.2lf ; sets the jerk limits, mm/sec\n",
1839 print.config().machine_max_jerk_x.values.front() * factor,
1840 print.config().machine_max_jerk_y.values.front() * factor,
1841 print.config().machine_max_jerk_z.values.front() * factor,
1842 print.config().machine_max_jerk_e.values.front() * factor);
1843 if (flavor != gcfRepRapFirmware)
1844 file.write_format("M205 S%d T%d ; sets the minimum extruding and travel feed rate, mm/sec\n",
1845 int(print.config().machine_min_extruding_rate.values.front() + 0.5),
1846 int(print.config().machine_min_travel_rate.values.front() + 0.5));
1847 else {
1848 // M205 Sn Tn not supported in RRF. They use M203 Inn to set minimum feedrate for
1849 // all moves. This is currently not implemented.
1850 }
1851 }
1852}
GCodeFlavor
Definition PrintConfig.hpp:34
machine_max_jerk_x((ConfigOptionFloats, machine_max_jerk_y))((ConfigOptionFloats
machine_max_jerk_z((ConfigOptionFloats, machine_max_jerk_e))((ConfigOptionFloats

References Slic3r::Print::config(), Slic3r::EmitToGCode, Slic3r::gcfMarlinFirmware, Slic3r::gcfMarlinLegacy, Slic3r::gcfRepRapFirmware, Slic3r::is_decimal_separator_point(), and Slic3r::GCode::GCodeOutputStream::write_format().

Referenced by _do_export().

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

◆ process_layer()

LayerResult Slic3r::GCode::process_layer ( const Print print,
const ObjectsLayerToPrint layers,
const LayerTools layer_tools,
const bool  last_layer,
const std::vector< const PrintInstance * > *  ordering,
const size_t  single_object_idx = size_t(-1) 
)
private
2123{
2124 assert(! layers.empty());
2125 // Either printing all copies of all objects, or just a single copy of a single object.
2126 assert(single_object_instance_idx == size_t(-1) || layers.size() == 1);
2127
2128 // First object, support and raft layer, if available.
2129 const Layer *object_layer = nullptr;
2130 const SupportLayer *support_layer = nullptr;
2131 const SupportLayer *raft_layer = nullptr;
2132 for (const ObjectLayerToPrint &l : layers) {
2133 if (l.object_layer && ! object_layer)
2134 object_layer = l.object_layer;
2135 if (l.support_layer) {
2136 if (! support_layer)
2137 support_layer = l.support_layer;
2138 if (! raft_layer && support_layer->id() < support_layer->object()->slicing_parameters().raft_layers())
2139 raft_layer = support_layer;
2140 }
2141 }
2142 const Layer &layer = (object_layer != nullptr) ? *object_layer : *support_layer;
2143 LayerResult result { {}, layer.id(), false, last_layer, false};
2144 if (layer_tools.extruders.empty())
2145 // Nothing to extrude.
2146 return result;
2147
2148 // Extract 1st object_layer and support_layer of this set of layers with an equal print_z.
2149 coordf_t print_z = layer.print_z;
2150 bool first_layer = layer.id() == 0;
2151 unsigned int first_extruder_id = layer_tools.extruders.front();
2152
2153 // Initialize config with the 1st object to be printed at this layer.
2154 m_config.apply(layer.object()->config(), true);
2155
2156 // Check whether it is possible to apply the spiral vase logic for this layer.
2157 // Just a reminder: A spiral vase mode is allowed for a single object, single material print only.
2159 if (m_spiral_vase && layers.size() == 1 && support_layer == nullptr) {
2160 bool enable = (layer.id() > 0 || !print.has_brim()) && (layer.id() >= (size_t)print.config().skirt_height.value && ! print.has_infinite_skirt());
2161 if (enable) {
2162 for (const LayerRegion *layer_region : layer.regions())
2163 if (size_t(layer_region->region().config().bottom_solid_layers.value) > layer.id() ||
2164 layer_region->perimeters().items_count() > 1u ||
2165 layer_region->fills().items_count() > 0) {
2166 enable = false;
2167 break;
2168 }
2169 }
2170 result.spiral_vase_enable = enable;
2171 // If we're going to apply spiralvase to this layer, disable loop clipping.
2172 m_enable_loop_clipping = !enable;
2173 }
2174
2175 std::string gcode;
2176 assert(is_decimal_separator_point()); // for the sprintfs
2177
2178 // add tag for processor
2180 // export layer z
2181 gcode += std::string(";Z:") + float_to_string_decimal_point(print_z) + "\n";
2182
2183 // export layer height
2184 float height = first_layer ? static_cast<float>(print_z) : static_cast<float>(print_z) - m_last_layer_z;
2186 + float_to_string_decimal_point(height) + "\n";
2187
2188 // update caches
2189 m_last_layer_z = static_cast<float>(print_z);
2192
2193 // Set new layer - this will change Z and force a retraction if retract_layer_change is enabled.
2194 if (! print.config().before_layer_gcode.value.empty()) {
2195 DynamicConfig config;
2196 config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index + 1));
2197 config.set_key_value("layer_z", new ConfigOptionFloat(print_z));
2198 config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
2199 gcode += this->placeholder_parser_process("before_layer_gcode",
2200 print.config().before_layer_gcode.value, m_writer.extruder()->id(), &config)
2201 + "\n";
2202 }
2203 gcode += this->change_layer(print_z); // this will increase m_layer_index
2204 m_layer = &layer;
2206 if (! print.config().layer_gcode.value.empty()) {
2207 DynamicConfig config;
2208 config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
2209 config.set_key_value("layer_z", new ConfigOptionFloat(print_z));
2210 config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
2211 gcode += this->placeholder_parser_process("layer_gcode",
2212 print.config().layer_gcode.value, m_writer.extruder()->id(), &config)
2213 + "\n";
2214 }
2215
2216 if (! first_layer && ! m_second_layer_things_done) {
2217 // Transition from 1st to 2nd layer. Adjust nozzle temperatures as prescribed by the nozzle dependent
2218 // first_layer_temperature vs. temperature settings.
2219 for (const Extruder &extruder : m_writer.extruders()) {
2220 if (print.config().single_extruder_multi_material.value || m_ooze_prevention.enable) {
2221 // In single extruder multi material mode, set the temperature for the current extruder only.
2222 // The same applies when ooze prevention is enabled.
2223 if (extruder.id() != m_writer.extruder()->id())
2224 continue;
2225 }
2226 int temperature = print.config().temperature.get_at(extruder.id());
2227 if (temperature > 0 && (temperature != print.config().first_layer_temperature.get_at(extruder.id())))
2228 gcode += m_writer.set_temperature(temperature, false, extruder.id());
2229 }
2230 gcode += m_writer.set_bed_temperature(print.config().bed_temperature.get_at(first_extruder_id));
2231 // Mark the temperature transition from 1st to 2nd layer to be finished.
2233 }
2234
2235 // Map from extruder ID to <begin, end> index of skirt loops to be extruded with that extruder.
2236 std::map<unsigned int, std::pair<size_t, size_t>> skirt_loops_per_extruder;
2237
2238 if (single_object_instance_idx == size_t(-1)) {
2239 // Normal (non-sequential) print.
2240 gcode += ProcessLayer::emit_custom_gcode_per_print_z(*this, layer_tools.custom_gcode, m_writer.extruder()->id(), first_extruder_id, print.config());
2241 }
2242 // Extrude skirt at the print_z of the raft layers and normal object layers
2243 // not at the print_z of the interlaced support material layers.
2244 skirt_loops_per_extruder = first_layer ?
2247
2248 if (this->config().avoid_crossing_curled_overhangs) {
2250 for (const ObjectLayerToPrint &layer_to_print : layers) {
2251 if (layer_to_print.object() == nullptr)
2252 continue;
2253 for (const auto &instance : layer_to_print.object()->instances()) {
2254 m_avoid_crossing_curled_overhangs.add_obstacles(layer_to_print.object_layer, instance.shift);
2255 m_avoid_crossing_curled_overhangs.add_obstacles(layer_to_print.support_layer, instance.shift);
2256 }
2257 }
2258 }
2259
2260 for (const ObjectLayerToPrint &layer_to_print : layers) {
2261 m_extrusion_quality_estimator.prepare_for_new_layer(layer_to_print.object_layer);
2262 }
2263
2264 // Extrude the skirt, brim, support, perimeters, infill ordered by the extruders.
2265 for (unsigned int extruder_id : layer_tools.extruders)
2266 {
2267 gcode += (layer_tools.has_wipe_tower && m_wipe_tower) ?
2268 m_wipe_tower->tool_change(*this, extruder_id, extruder_id == layer_tools.extruders.back()) :
2269 this->set_extruder(extruder_id, print_z);
2270
2271 // let analyzer tag generator aware of a role type change
2272 if (layer_tools.has_wipe_tower && m_wipe_tower)
2274
2275 if (auto loops_it = skirt_loops_per_extruder.find(extruder_id); loops_it != skirt_loops_per_extruder.end()) {
2276 const std::pair<size_t, size_t> loops = loops_it->second;
2277 this->set_origin(0., 0.);
2279 Flow layer_skirt_flow = print.skirt_flow().with_height(float(m_skirt_done.back() - (m_skirt_done.size() == 1 ? 0. : m_skirt_done[m_skirt_done.size() - 2])));
2280 double mm3_per_mm = layer_skirt_flow.mm3_per_mm();
2281 for (size_t i = loops.first; i < loops.second; ++i) {
2282 // Adjust flow according to this layer's layer height.
2283 ExtrusionLoop loop = *dynamic_cast<const ExtrusionLoop*>(print.skirt().entities[i]);
2284 for (ExtrusionPath &path : loop.paths) {
2285 path.height = layer_skirt_flow.height();
2286 path.mm3_per_mm = mm3_per_mm;
2287 }
2288 //FIXME using the support_material_speed of the 1st object printed.
2289 gcode += this->extrude_loop(loop, "skirt"sv, m_config.support_material_speed.value);
2290 }
2292 // Allow a straight travel move to the first object point if this is the first layer (but don't in next layers).
2293 if (first_layer && loops.first == 0)
2295 }
2296
2297 // Extrude brim with the extruder of the 1st region.
2298 if (! m_brim_done) {
2299 this->set_origin(0., 0.);
2301 for (const ExtrusionEntity *ee : print.brim().entities) {
2302 gcode += this->extrude_entity(*ee, "brim"sv, m_config.support_material_speed.value);
2303 }
2304 m_brim_done = true;
2306 // Allow a straight travel move to the first object point.
2308 }
2309
2310 std::vector<InstanceToPrint> instances_to_print = sort_print_object_instances(layers, ordering, single_object_instance_idx);
2311
2312 // We are almost ready to print. However, we must go through all the objects twice to print the the overridden extrusions first (infill/perimeter wiping feature):
2313 bool is_anything_overridden = layer_tools.wiping_extrusions().is_anything_overridden();
2314 if (is_anything_overridden) {
2315 // Extrude wipes.
2316 size_t gcode_size_old = gcode.size();
2317 for (const InstanceToPrint &instance : instances_to_print)
2319 gcode, extruder_id, instance,
2320 layers[instance.object_layer_to_print_id], layer_tools,
2321 is_anything_overridden, true /* print_wipe_extrusions */);
2322 if (gcode_size_old < gcode.size())
2323 gcode+="; PURGING FINISHED\n";
2324 }
2325 // Extrude normal extrusions.
2326 for (const InstanceToPrint &instance : instances_to_print)
2328 gcode, extruder_id, instance,
2329 layers[instance.object_layer_to_print_id], layer_tools,
2330 is_anything_overridden, false /* print_wipe_extrusions */);
2331 }
2332
2333 BOOST_LOG_TRIVIAL(trace) << "Exported layer " << layer.id() << " print_z " << print_z <<
2335
2336 result.gcode = std::move(gcode);
2337 result.cooling_buffer_flush = object_layer || raft_layer || last_layer;
2338 return result;
2339}
void use_external_mp(bool use=true)
Definition AvoidCrossingPerimeters.hpp:19
void prepare_for_new_layer(const Layer *layer)
Definition ExtrusionProcessor.hpp:232
void process_layer_single_object(std::string &gcode, const unsigned int extruder_id, const InstanceToPrint &print_instance, const ObjectLayerToPrint &layer_to_print, const LayerTools &layer_tools, const bool is_anything_overridden, const bool print_wipe_extrusions)
Definition GCode.cpp:2347
std::vector< coordf_t > m_skirt_done
Definition GCode.hpp:424
std::vector< InstanceToPrint > sort_print_object_instances(const std::vector< ObjectLayerToPrint > &layers, const std::vector< const PrintInstance * > *ordering, const size_t single_object_instance_idx)
Definition GCode.cpp:1918
std::string extrude_entity(const ExtrusionEntity &entity, const std::string_view description, double speed=-1.)
Definition GCode.cpp:2794
std::string change_layer(coordf_t print_z)
Definition GCode.cpp:2632
void clear()
Definition JumpPointSearch.cpp:184
void add_obstacles(const Lines &obstacles)
Definition JumpPointSearch.cpp:192
coordf_t print_z
Definition Layer.hpp:324
PrintObject * object()
Definition Layer.hpp:317
bool enable
Definition GCode.hpp:41
const PrintObjectConfig & config() const
Definition Print.hpp:246
static std::string emit_custom_gcode_per_print_z(GCode &gcodegen, const CustomGCode::Item *custom_gcode, unsigned int current_extruder_id, unsigned int first_extruder_id, const PrintConfig &config)
Definition GCode.cpp:1958
static std::map< unsigned int, std::pair< size_t, size_t > > make_skirt_loops_per_extruder_other_layers(const Print &print, const LayerTools &layer_tools, std::vector< coordf_t > &skirt_done)
Definition GCode.cpp:2071
static std::map< unsigned int, std::pair< size_t, size_t > > make_skirt_loops_per_extruder_1st_layer(const Print &print, const LayerTools &layer_tools, std::vector< coordf_t > &skirt_done)
Definition GCode.cpp:2053
coord_t height(const BoundingBox &box)
Definition Arrange.cpp:540

References Slic3r::JPSPathFinder::add_obstacles(), Slic3r::Print::brim(), change_layer(), Slic3r::JPSPathFinder::clear(), config(), Slic3r::PrintObject::config(), Slic3r::Print::config(), Slic3r::LayerTools::custom_gcode, Slic3r::AvoidCrossingPerimeters::disable_once(), Slic3r::ProcessLayer::emit_custom_gcode_per_print_z(), Slic3r::OozePrevention::enable, Slic3r::ExtrusionEntityCollection::entities, extrude_entity(), extrude_loop(), Slic3r::GCodeWriter::extruder(), Slic3r::LayerTools::extruders, Slic3r::GCodeWriter::extruders(), Slic3r::float_to_string_decimal_point(), Slic3r::Print::has_brim(), Slic3r::Print::has_infinite_skirt(), Slic3r::LayerTools::has_wipe_tower, Slic3r::Flow::height(), Slic3r::GCodeProcessor::Height, Slic3r::Extruder::id(), Slic3r::Layer::id(), Slic3r::WipingExtrusions::is_anything_overridden(), Slic3r::is_decimal_separator_point(), layer(), Slic3r::GCodeProcessor::Layer_Change, Slic3r::log_memory_info(), m_avoid_crossing_curled_overhangs, m_avoid_crossing_perimeters, m_brim_done, m_config, m_enable_loop_clipping, m_extrusion_quality_estimator, m_last_height, m_last_layer_z, m_last_processor_extrusion_role, m_layer, m_layer_index, m_max_layer_z, m_object_layer_over_raft, m_ooze_prevention, m_second_layer_things_done, m_skirt_done, m_spiral_vase, m_wipe_tower, m_writer, Slic3r::Skirt::make_skirt_loops_per_extruder_1st_layer(), Slic3r::Skirt::make_skirt_loops_per_extruder_other_layers(), Slic3r::Flow::mm3_per_mm(), Slic3r::Layer::object(), ordering, placeholder_parser_process(), Slic3r::ExtrusionQualityEstimator::prepare_for_new_layer(), Slic3r::Layer::print_z, process_layer_single_object(), Slic3r::SlicingParameters::raft_layers(), Slic3r::Layer::regions(), Slic3r::GCodeProcessor::reserved_tag(), Slic3r::GCodeWriter::set_bed_temperature(), set_extruder(), set_origin(), Slic3r::GCodeWriter::set_temperature(), Slic3r::Print::skirt(), Slic3r::Print::skirt_flow(), Slic3r::PrintObject::slicing_parameters(), sort_print_object_instances(), Slic3r::AvoidCrossingPerimeters::use_external_mp(), Slic3r::WipeTower, Slic3r::LayerTools::wiping_extrusions(), and Slic3r::Flow::with_height().

Referenced by process_layers(), and process_layers().

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

◆ process_layer_single_object()

void Slic3r::GCode::process_layer_single_object ( std::string &  gcode,
const unsigned int  extruder_id,
const InstanceToPrint print_instance,
const ObjectLayerToPrint layer_to_print,
const LayerTools layer_tools,
const bool  is_anything_overridden,
const bool  print_wipe_extrusions 
)
private
2362{
2363 bool first = true;
2364 int object_id = 0;
2365 // Delay layer initialization as many layers may not print with all extruders.
2366 auto init_layer_delayed = [this, &print_instance, &layer_to_print, &first, &object_id, &gcode]() {
2367 if (first) {
2368 first = false;
2369 const PrintObject &print_object = print_instance.print_object;
2370 const Print &print = *print_object.print();
2371 m_config.apply(print_object.config(), true);
2372 m_layer = layer_to_print.layer();
2373 if (print.config().avoid_crossing_perimeters)
2375 // When starting a new object, use the external motion planner for the first travel move.
2376 const Point &offset = print_object.instances()[print_instance.instance_id].shift;
2377 std::pair<const PrintObject*, Point> this_object_copy(&print_object, offset);
2378 if (m_last_obj_copy != this_object_copy)
2380 m_last_obj_copy = this_object_copy;
2381 this->set_origin(unscale(offset));
2382 if (this->config().gcode_label_objects) {
2383 for (const PrintObject *po : print_object.print()->objects())
2384 if (po == &print_object)
2385 break;
2386 else
2387 ++ object_id;
2388 gcode += std::string("; printing object ") + print_object.model_object()->name + " id:" + std::to_string(object_id) + " copy " + std::to_string(print_instance.instance_id) + "\n";
2389 }
2390 }
2391 };
2392
2393 const PrintObject &print_object = print_instance.print_object;
2394 const Print &print = *print_object.print();
2395
2397
2398 if (! print_wipe_extrusions && layer_to_print.support_layer != nullptr)
2399 if (const SupportLayer &support_layer = *layer_to_print.support_layer; ! support_layer.support_fills.entities.empty()) {
2400 ExtrusionRole role = support_layer.support_fills.role();
2401 bool has_support = role.is_mixed() || role.is_support_base();
2402 bool has_interface = role.is_mixed() || role.is_support_interface();
2403 // Extruder ID of the support base. -1 if "don't care".
2404 unsigned int support_extruder = print_object.config().support_material_extruder.value - 1;
2405 // Shall the support be printed with the active extruder, preferably with non-soluble, to avoid tool changes?
2406 bool support_dontcare = support_extruder == std::numeric_limits<unsigned int>::max();
2407 // Extruder ID of the support interface. -1 if "don't care".
2408 unsigned int interface_extruder = print_object.config().support_material_interface_extruder.value - 1;
2409 // Shall the support interface be printed with the active extruder, preferably with non-soluble, to avoid tool changes?
2410 bool interface_dontcare = interface_extruder == std::numeric_limits<unsigned int>::max();
2411 if (support_dontcare || interface_dontcare) {
2412 // Some support will be printed with "don't care" material, preferably non-soluble.
2413 // Is the current extruder assigned a soluble filament?
2414 auto it_nonsoluble = std::find_if(layer_tools.extruders.begin(), layer_tools.extruders.end(),
2415 [&soluble = std::as_const(print.config().filament_soluble)](unsigned int extruder_id) { return ! soluble.get_at(extruder_id); });
2416 // There should be a non-soluble extruder available.
2417 assert(it_nonsoluble != layer_tools.extruders.end());
2418 unsigned int dontcare_extruder = it_nonsoluble == layer_tools.extruders.end() ? layer_tools.extruders.front() : *it_nonsoluble;
2419 if (support_dontcare)
2420 support_extruder = dontcare_extruder;
2421 if (interface_dontcare)
2422 interface_extruder = dontcare_extruder;
2423 }
2424 bool extrude_support = has_support && support_extruder == extruder_id;
2425 bool extrude_interface = has_interface && interface_extruder == extruder_id;
2426 if (extrude_support || extrude_interface) {
2427 init_layer_delayed();
2428 m_layer = layer_to_print.support_layer;
2430 gcode += this->extrude_support(
2431 // support_extrusion_role is ExtrusionRole::SupportMaterial, ExtrusionRole::SupportMaterialInterface or ExtrusionRole::Mixed for all extrusion paths.
2432 support_layer.support_fills.chained_path_from(m_last_pos, extrude_support ? (extrude_interface ? ExtrusionRole::Mixed : ExtrusionRole::SupportMaterial) : ExtrusionRole::SupportMaterialInterface));
2433 }
2434 }
2435
2436 m_layer = layer_to_print.layer();
2437 // To control print speed of the 1st object layer printed over raft interface.
2438 m_object_layer_over_raft = layer_to_print.object_layer && layer_to_print.object_layer->id() > 0 &&
2439 print_object.slicing_parameters().raft_layers() == layer_to_print.object_layer->id();
2440
2441 // Check whether this ExtrusionEntityCollection should be printed now with extruder_id, given print_wipe_extrusions
2442 // (wipe extrusions are printed before regular extrusions).
2443 auto shall_print_this_extrusion_collection = [extruder_id, instance_id = print_instance.instance_id, &layer_tools, is_anything_overridden, print_wipe_extrusions](const ExtrusionEntityCollection *eec, const PrintRegion &region) -> bool {
2444 assert(eec != nullptr);
2445 if (eec->entities.empty())
2446 // This shouldn't happen. FIXME why? but first_point() would fail.
2447 return false;
2448 // This extrusion is part of certain Region, which tells us which extruder should be used for it:
2449 int correct_extruder_id = layer_tools.extruder(*eec, region);
2450 if (! layer_tools.has_extruder(correct_extruder_id)) {
2451 // this entity is not overridden, but its extruder is not in layer_tools - we'll print it
2452 // by last extruder on this layer (could happen e.g. when a wiping object is taller than others - dontcare extruders are eradicated from layer_tools)
2453 correct_extruder_id = layer_tools.extruders.back();
2454 }
2455 int extruder_override_id = is_anything_overridden ? layer_tools.wiping_extrusions().get_extruder_override(eec, instance_id) : -1;
2456 return print_wipe_extrusions ?
2457 extruder_override_id == int(extruder_id) :
2458 extruder_override_id < 0 && int(extruder_id) == correct_extruder_id;
2459 };
2460
2461 ExtrusionEntitiesPtr temp_fill_extrusions;
2462 if (const Layer *layer = layer_to_print.object_layer; layer)
2463 for (size_t idx : layer->lslice_indices_sorted_by_print_order) {
2464 const LayerSlice &lslice = layer->lslices_ex[idx];
2465 auto extrude_infill_range = [&](
2466 const LayerRegion &layerm, const ExtrusionEntityCollection &fills,
2467 LayerExtrusionRanges::const_iterator it_fill_ranges_begin, LayerExtrusionRanges::const_iterator it_fill_ranges_end, bool ironing) {
2468 // PrintObjects own the PrintRegions, thus the pointer to PrintRegion would be unique to a PrintObject, they would not
2469 // identify the content of PrintRegion accross the whole print uniquely. Translate to a Print specific PrintRegion.
2470 const PrintRegion &region = print.get_print_region(layerm.region().print_region_id());
2471 temp_fill_extrusions.clear();
2472 for (auto it_fill_range = it_fill_ranges_begin; it_fill_range != it_fill_ranges_end; ++ it_fill_range) {
2473 assert(it_fill_range->region() == it_fill_ranges_begin->region());
2474 for (uint32_t fill_id : *it_fill_range) {
2475 assert(dynamic_cast<ExtrusionEntityCollection*>(fills.entities[fill_id]));
2476 if (auto *eec = static_cast<ExtrusionEntityCollection*>(fills.entities[fill_id]);
2477 (eec->role() == ExtrusionRole::Ironing) == ironing && shall_print_this_extrusion_collection(eec, region)) {
2478 if (eec->can_reverse())
2479 // Flatten the infill collection for better path planning.
2480 for (auto *ee : eec->entities)
2481 temp_fill_extrusions.emplace_back(ee);
2482 else
2483 temp_fill_extrusions.emplace_back(eec);
2484 }
2485 }
2486 }
2487 if (! temp_fill_extrusions.empty()) {
2488 init_layer_delayed();
2489 m_config.apply(region.config());
2490 //FIXME The source extrusions may be reversed, thus modifying the extrusions! Is it a problem? How about the initial G-code preview?
2491 // Will parallel access of initial G-code preview to these extrusions while reordering them at backend cause issues?
2492 chain_and_reorder_extrusion_entities(temp_fill_extrusions, &m_last_pos);
2493 const auto extrusion_name = ironing ? "ironing"sv : "infill"sv;
2494 for (const ExtrusionEntity *fill : temp_fill_extrusions)
2495 if (auto *eec = dynamic_cast<const ExtrusionEntityCollection*>(fill); eec) {
2496 for (const ExtrusionEntity *ee : eec->chained_path_from(m_last_pos).entities)
2497 gcode += this->extrude_entity(*ee, extrusion_name);
2498 } else
2499 gcode += this->extrude_entity(*fill, extrusion_name);
2500 }
2501 };
2502
2503 //FIXME order islands?
2504 // Sequential tool path ordering of multiple parts within the same object, aka. perimeter tracking (#5511)
2505 for (const LayerIsland &island : lslice.islands) {
2506 auto process_perimeters = [&]() {
2507 const LayerRegion &layerm = *layer->get_region(island.perimeters.region());
2508 // PrintObjects own the PrintRegions, thus the pointer to PrintRegion would be unique to a PrintObject, they would not
2509 // identify the content of PrintRegion accross the whole print uniquely. Translate to a Print specific PrintRegion.
2510 const PrintRegion &region = print.get_print_region(layerm.region().print_region_id());
2511 bool first = true;
2512 for (uint32_t perimeter_id : island.perimeters) {
2513 assert(dynamic_cast<const ExtrusionEntityCollection*>(layerm.perimeters().entities[perimeter_id]));
2514 if (const auto *eec = static_cast<const ExtrusionEntityCollection*>(layerm.perimeters().entities[perimeter_id]);
2515 shall_print_this_extrusion_collection(eec, region)) {
2516 // This may not apply to Arachne, but maybe the Arachne gap fill should disable reverse as well?
2517 // assert(! eec->can_reverse());
2518 if (first) {
2519 first = false;
2520 init_layer_delayed();
2521 m_config.apply(region.config());
2522 }
2523 for (const ExtrusionEntity *ee : *eec)
2524 gcode += this->extrude_entity(*ee, comment_perimeter, -1.);
2525 }
2526 }
2527 };
2528 auto process_infill = [&]() {
2529 for (auto it = island.fills.begin(); it != island.fills.end();) {
2530 // Gather range of fill ranges with the same region.
2531 auto it_end = it;
2532 for (++ it_end; it_end != island.fills.end() && it->region() == it_end->region(); ++ it_end) ;
2533 const LayerRegion &layerm = *layer->get_region(it->region());
2534 extrude_infill_range(layerm, layerm.fills(), it, it_end, false /* normal extrusions, not ironing */);
2535 it = it_end;
2536 }
2537 };
2538 if (print.config().infill_first) {
2539 process_infill();
2540 process_perimeters();
2541 } else {
2542 process_perimeters();
2543 process_infill();
2544 }
2545 }
2546 // ironing
2547 //FIXME move ironing into the loop above over LayerIslands?
2548 // First Ironing changes extrusion rate quickly, second single ironing may be done over multiple perimeter regions.
2549 // Ironing in a second phase is safer, but it may be less efficient.
2550 for (const LayerIsland &island : lslice.islands) {
2551 for (auto it = island.fills.begin(); it != island.fills.end();) {
2552 // Gather range of fill ranges with the same region.
2553 auto it_end = it;
2554 for (++ it_end; it_end != island.fills.end() && it->region() == it_end->region(); ++ it_end) ;
2555 const LayerRegion &layerm = *layer->get_region(it->region());
2556 extrude_infill_range(layerm, layerm.fills(), it, it_end, true /* ironing, not normal extrusions */);
2557 it = it_end;
2558 }
2559 }
2560 }
2561 if (! first && this->config().gcode_label_objects)
2562 gcode += std::string("; stop printing object ") + print_object.model_object()->name + " id:" + std::to_string(object_id) + " copy " + std::to_string(print_instance.instance_id) + "\n";
2563}
void init_layer(const Layer &layer)
Definition AvoidCrossingPerimeters.cpp:1243
void set_current_object(const PrintObject *object)
Definition ExtrusionProcessor.hpp:230
LayerSlices lslices_ex
Definition Layer.hpp:341
const LayerRegion * get_region(int idx) const
Definition Layer.hpp:344
void chain_and_reorder_extrusion_entities(std::vector< ExtrusionEntity * > &entities, const Point *start_near)
Definition ShortestPath.cpp:1039
ironing((ConfigOptionEnum< IroningType >, ironing_type))((ConfigOptionPercent
Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, ClipperLib::JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:416
static const auto comment_perimeter
Definition GCode.cpp:2341
std::vector< ExtrusionEntity * > ExtrusionEntitiesPtr
Definition ExtrusionEntity.hpp:58
static constexpr const ExtrusionRoleModifiers Mixed
Definition ExtrusionRole.hpp:79
unsigned __int32 uint32_t
Definition unistd.h:79

References Slic3r::chain_and_reorder_extrusion_entities(), Slic3r::comment_perimeter, config(), Slic3r::PrintRegion::config(), Slic3r::PrintObject::config(), Slic3r::Print::config(), Slic3r::ExtrusionEntityCollection::entities, extrude_entity(), extrude_support(), Slic3r::LayerTools::extruder(), Slic3r::LayerTools::extruders, Slic3r::LayerRegion::fills(), Slic3r::WipingExtrusions::get_extruder_override(), Slic3r::Print::get_print_region(), Slic3r::Layer::get_region(), Slic3r::LayerTools::has_extruder(), Slic3r::Layer::id(), Slic3r::AvoidCrossingPerimeters::init_layer(), Slic3r::GCode::InstanceToPrint::instance_id, Slic3r::PrintObject::instances(), Slic3r::ExtrusionRole::Ironing, Slic3r::ironing(), Slic3r::ExtrusionRole::is_mixed(), Slic3r::ExtrusionRole::is_support_base(), Slic3r::ExtrusionRole::is_support_interface(), Slic3r::LayerSlice::islands, layer(), Slic3r::GCode::ObjectLayerToPrint::layer(), Slic3r::Layer::lslice_indices_sorted_by_print_order, Slic3r::Layer::lslices_ex, m_avoid_crossing_perimeters, m_config, m_extrusion_quality_estimator, m_last_obj_copy, m_last_pos, m_layer, m_object_layer_over_raft, Slic3r::ExtrusionRole::Mixed, Slic3r::PrintObjectBase::model_object(), Slic3r::ModelObject::name, Slic3r::GCode::ObjectLayerToPrint::object_layer, Slic3r::Print::objects(), Slic3r::offset(), Slic3r::LayerRegion::perimeters(), Slic3r::PrintObjectBaseWithState< PrintType, PrintObjectStepEnumType, COUNT >::print(), Slic3r::GCode::InstanceToPrint::print_object, Slic3r::PrintRegion::print_region_id(), Slic3r::SlicingParameters::raft_layers(), Slic3r::LayerRegion::region(), Slic3r::ExtrusionQualityEstimator::set_current_object(), set_origin(), Slic3r::PrintObject::slicing_parameters(), Slic3r::GCode::ObjectLayerToPrint::support_layer, Slic3r::ExtrusionRole::SupportMaterial, Slic3r::ExtrusionRole::SupportMaterialInterface, Slic3r::unscale(), Slic3r::AvoidCrossingPerimeters::use_external_mp_once(), and Slic3r::LayerTools::wiping_extrusions().

Referenced by process_layer().

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

◆ process_layers() [1/2]

void Slic3r::GCode::process_layers ( const Print print,
const ToolOrdering tool_ordering,
const std::vector< const PrintInstance * > &  print_object_instances_ordering,
const std::vector< std::pair< coordf_t, ObjectsLayerToPrint > > &  layers_to_print,
GCodeOutputStream output_stream 
)
private
1527{
1528 // The pipeline is variable: The vase mode filter is optional.
1529 size_t layer_to_print_idx = 0;
1530 const auto generator = tbb::make_filter<void, LayerResult>(slic3r_tbb_filtermode::serial_in_order,
1531 [this, &print, &tool_ordering, &print_object_instances_ordering, &layers_to_print, &layer_to_print_idx](tbb::flow_control& fc) -> LayerResult {
1532 if (layer_to_print_idx >= layers_to_print.size()) {
1533 if ((!m_pressure_equalizer && layer_to_print_idx == layers_to_print.size()) || (m_pressure_equalizer && layer_to_print_idx == (layers_to_print.size() + 1))) {
1534 fc.stop();
1535 return {};
1536 } else {
1537 // Pressure equalizer need insert empty input. Because it returns one layer back.
1538 // Insert NOP (no operation) layer;
1539 ++layer_to_print_idx;
1540 return LayerResult::make_nop_layer_result();
1541 }
1542 } else {
1543 const std::pair<coordf_t, ObjectsLayerToPrint> &layer = layers_to_print[layer_to_print_idx++];
1544 const LayerTools& layer_tools = tool_ordering.tools_for_layer(layer.first);
1545 if (m_wipe_tower && layer_tools.has_wipe_tower)
1546 m_wipe_tower->next_layer();
1547 print.throw_if_canceled();
1548 return this->process_layer(print, layer.second, layer_tools, &layer == &layers_to_print.back(), &print_object_instances_ordering, size_t(-1));
1549 }
1550 });
1551 const auto spiral_vase = tbb::make_filter<LayerResult, LayerResult>(slic3r_tbb_filtermode::serial_in_order,
1552 [spiral_vase = this->m_spiral_vase.get()](LayerResult in) -> LayerResult {
1553 if (in.nop_layer_result)
1554 return in;
1555
1556 spiral_vase->enable(in.spiral_vase_enable);
1557 return { spiral_vase->process_layer(std::move(in.gcode)), in.layer_id, in.spiral_vase_enable, in.cooling_buffer_flush};
1558 });
1559 const auto pressure_equalizer = tbb::make_filter<LayerResult, LayerResult>(slic3r_tbb_filtermode::serial_in_order,
1560 [pressure_equalizer = this->m_pressure_equalizer.get()](LayerResult in) -> LayerResult {
1561 return pressure_equalizer->process_layer(std::move(in));
1562 });
1563 const auto cooling = tbb::make_filter<LayerResult, std::string>(slic3r_tbb_filtermode::serial_in_order,
1564 [cooling_buffer = this->m_cooling_buffer.get()](LayerResult in) -> std::string {
1565 if (in.nop_layer_result)
1566 return in.gcode;
1567
1568 return cooling_buffer->process_layer(std::move(in.gcode), in.layer_id, in.cooling_buffer_flush);
1569 });
1570 const auto find_replace = tbb::make_filter<std::string, std::string>(slic3r_tbb_filtermode::serial_in_order,
1571 [find_replace = this->m_find_replace.get()](std::string s) -> std::string {
1572 return find_replace->process_layer(std::move(s));
1573 });
1574 const auto output = tbb::make_filter<std::string, void>(slic3r_tbb_filtermode::serial_in_order,
1575 [&output_stream](std::string s) { output_stream.write(s); }
1576 );
1577
1578 // It registers a handler that sets locales to "C" before any TBB thread starts participating in tbb::parallel_pipeline.
1579 // Handler is unregistered when the destructor is called.
1580 TBBLocalesSetter locales_setter;
1581
1582 // The pipeline elements are joined using const references, thus no copying is performed.
1583 output_stream.find_replace_supress();
1585 tbb::parallel_pipeline(12, generator & spiral_vase & pressure_equalizer & cooling & find_replace & output);
1586 else if (m_spiral_vase && m_find_replace)
1587 tbb::parallel_pipeline(12, generator & spiral_vase & cooling & find_replace & output);
1589 tbb::parallel_pipeline(12, generator & spiral_vase & pressure_equalizer & cooling & output);
1591 tbb::parallel_pipeline(12, generator & pressure_equalizer & cooling & find_replace & output);
1592 else if (m_spiral_vase)
1593 tbb::parallel_pipeline(12, generator & spiral_vase & cooling & output);
1594 else if (m_find_replace)
1595 tbb::parallel_pipeline(12, generator & cooling & find_replace & output);
1596 else if (m_pressure_equalizer)
1597 tbb::parallel_pipeline(12, generator & pressure_equalizer & cooling & output);
1598 else
1599 tbb::parallel_pipeline(12, generator & cooling & output);
1600 output_stream.find_replace_enable();
1601}
LayerResult process_layer(const Print &print, const ObjectsLayerToPrint &layers, const LayerTools &layer_tools, const bool last_layer, const std::vector< const PrintInstance * > *ordering, const size_t single_object_idx=size_t(-1))
Definition GCode.cpp:2112

References Slic3r::LayerTools::has_wipe_tower, layer(), m_wipe_tower, process_layer(), Slic3r::PrintBase::throw_if_canceled(), and Slic3r::ToolOrdering::tools_for_layer().

Referenced by _do_export().

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

◆ process_layers() [2/2]

void Slic3r::GCode::process_layers ( const Print print,
const ToolOrdering tool_ordering,
ObjectsLayerToPrint  layers_to_print,
const size_t  single_object_idx,
GCodeOutputStream output_stream 
)
private
1612{
1613 // The pipeline is variable: The vase mode filter is optional.
1614 size_t layer_to_print_idx = 0;
1615 const auto generator = tbb::make_filter<void, LayerResult>(slic3r_tbb_filtermode::serial_in_order,
1616 [this, &print, &tool_ordering, &layers_to_print, &layer_to_print_idx, single_object_idx](tbb::flow_control& fc) -> LayerResult {
1617 if (layer_to_print_idx >= layers_to_print.size()) {
1618 if ((!m_pressure_equalizer && layer_to_print_idx == layers_to_print.size()) || (m_pressure_equalizer && layer_to_print_idx == (layers_to_print.size() + 1))) {
1619 fc.stop();
1620 return {};
1621 } else {
1622 // Pressure equalizer need insert empty input. Because it returns one layer back.
1623 // Insert NOP (no operation) layer;
1624 ++layer_to_print_idx;
1625 return LayerResult::make_nop_layer_result();
1626 }
1627 } else {
1628 ObjectLayerToPrint &layer = layers_to_print[layer_to_print_idx ++];
1629 print.throw_if_canceled();
1630 return this->process_layer(print, { std::move(layer) }, tool_ordering.tools_for_layer(layer.print_z()), &layer == &layers_to_print.back(), nullptr, single_object_idx);
1631 }
1632 });
1633 const auto spiral_vase = tbb::make_filter<LayerResult, LayerResult>(slic3r_tbb_filtermode::serial_in_order,
1634 [spiral_vase = this->m_spiral_vase.get()](LayerResult in)->LayerResult {
1635 if (in.nop_layer_result)
1636 return in;
1637 spiral_vase->enable(in.spiral_vase_enable);
1638 return { spiral_vase->process_layer(std::move(in.gcode)), in.layer_id, in.spiral_vase_enable, in.cooling_buffer_flush };
1639 });
1640 const auto pressure_equalizer = tbb::make_filter<LayerResult, LayerResult>(slic3r_tbb_filtermode::serial_in_order,
1641 [pressure_equalizer = this->m_pressure_equalizer.get()](LayerResult in) -> LayerResult {
1642 return pressure_equalizer->process_layer(std::move(in));
1643 });
1644 const auto cooling = tbb::make_filter<LayerResult, std::string>(slic3r_tbb_filtermode::serial_in_order,
1645 [cooling_buffer = this->m_cooling_buffer.get()](LayerResult in)->std::string {
1646 if (in.nop_layer_result)
1647 return in.gcode;
1648 return cooling_buffer->process_layer(std::move(in.gcode), in.layer_id, in.cooling_buffer_flush);
1649 });
1650 const auto find_replace = tbb::make_filter<std::string, std::string>(slic3r_tbb_filtermode::serial_in_order,
1651 [find_replace = this->m_find_replace.get()](std::string s) -> std::string {
1652 return find_replace->process_layer(std::move(s));
1653 });
1654 const auto output = tbb::make_filter<std::string, void>(slic3r_tbb_filtermode::serial_in_order,
1655 [&output_stream](std::string s) { output_stream.write(s); }
1656 );
1657
1658 // It registers a handler that sets locales to "C" before any TBB thread starts participating in tbb::parallel_pipeline.
1659 // Handler is unregistered when the destructor is called.
1660 TBBLocalesSetter locales_setter;
1661
1662 // The pipeline elements are joined using const references, thus no copying is performed.
1663 output_stream.find_replace_supress();
1665 tbb::parallel_pipeline(12, generator & spiral_vase & pressure_equalizer & cooling & find_replace & output);
1666 else if (m_spiral_vase && m_find_replace)
1667 tbb::parallel_pipeline(12, generator & spiral_vase & cooling & find_replace & output);
1669 tbb::parallel_pipeline(12, generator & spiral_vase & pressure_equalizer & cooling & output);
1671 tbb::parallel_pipeline(12, generator & pressure_equalizer & cooling & find_replace & output);
1672 else if (m_spiral_vase)
1673 tbb::parallel_pipeline(12, generator & spiral_vase & cooling & output);
1674 else if (m_find_replace)
1675 tbb::parallel_pipeline(12, generator & cooling & find_replace & output);
1676 else if (m_pressure_equalizer)
1677 tbb::parallel_pipeline(12, generator & pressure_equalizer & cooling & output);
1678 else
1679 tbb::parallel_pipeline(12, generator & cooling & output);
1680 output_stream.find_replace_enable();
1681}

References layer(), Slic3r::Layer::print_z, process_layer(), Slic3r::PrintBase::throw_if_canceled(), and Slic3r::ToolOrdering::tools_for_layer().

+ Here is the call graph for this function:

◆ retract()

std::string Slic3r::GCode::retract ( bool  toolchange = false)
private
3291{
3292 std::string gcode;
3293
3294 if (m_writer.extruder() == nullptr)
3295 return gcode;
3296
3297 // wipe (if it's enabled for this extruder and we have a stored wipe path)
3298 if (EXTRUDER_CONFIG(wipe) && m_wipe.has_path()) {
3299 gcode += toolchange ? m_writer.retract_for_toolchange(true) : m_writer.retract(true);
3300 gcode += m_wipe.wipe(*this, toolchange);
3301 }
3302
3303 /* The parent class will decide whether we need to perform an actual retraction
3304 (the extruder might be already retracted fully or partially). We call these
3305 methods even if we performed wipe, since this will ensure the entire retraction
3306 length is honored in case wipe path was too short. */
3308
3309 gcode += m_writer.reset_e();
3310 if (m_writer.extruder()->retract_length() > 0 || m_config.use_firmware_retraction)
3311 gcode += m_writer.lift();
3312
3313 return gcode;
3314}
double retract_length() const
Definition Extruder.cpp:128
std::string lift()
Definition GCodeWriter.cpp:462
std::string retract_for_toolchange(bool before_wipe=false)
Definition GCodeWriter.cpp:389
std::string retract(bool before_wipe=false)
Definition GCodeWriter.cpp:378
std::string reset_e(bool force=false)
Definition GCodeWriter.cpp:197
std::string wipe(GCode &gcodegen, bool toolchange)
Definition GCode.cpp:149
bool has_path() const
Definition GCode.hpp:57

References Slic3r::GCodeWriter::extruder(), EXTRUDER_CONFIG, Slic3r::Wipe::has_path(), Slic3r::GCodeWriter::lift(), m_config, m_wipe, m_writer, Slic3r::GCodeWriter::reset_e(), Slic3r::GCodeWriter::retract(), Slic3r::GCodeWriter::retract_for_toolchange(), Slic3r::Extruder::retract_length(), and Slic3r::Wipe::wipe().

Referenced by _do_export(), Slic3r::WipeTowerIntegration::append_tcr(), change_layer(), set_extruder(), and travel_to().

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

◆ set_extruder()

std::string Slic3r::GCode::set_extruder ( unsigned int  extruder_id,
double  print_z 
)
private
3317{
3318 if (!m_writer.need_toolchange(extruder_id))
3319 return "";
3320
3321 // if we are running a single-extruder setup, just set the extruder and return nothing
3323 this->placeholder_parser().set("current_extruder", extruder_id);
3324
3325 std::string gcode;
3326 // Append the filament start G-code.
3327 const std::string &start_filament_gcode = m_config.start_filament_gcode.get_at(extruder_id);
3328 if (! start_filament_gcode.empty()) {
3329 // Process the start_filament_gcode for the filament.
3330 DynamicConfig config;
3331 config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
3332 config.set_key_value("layer_z", new ConfigOptionFloat(this->writer().get_position().z() - m_config.z_offset.value));
3333 config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
3334 config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(extruder_id)));
3335 gcode += this->placeholder_parser_process("start_filament_gcode", start_filament_gcode, extruder_id, &config);
3336 check_add_eol(gcode);
3337 }
3338 gcode += m_writer.toolchange(extruder_id);
3339 return gcode;
3340 }
3341
3342 // prepend retraction on the current extruder
3343 std::string gcode = this->retract(true);
3344
3345 // Always reset the extrusion path, even if the tool change retract is set to zero.
3347
3348 if (m_writer.extruder() != nullptr) {
3349 // Process the custom end_filament_gcode.
3350 unsigned int old_extruder_id = m_writer.extruder()->id();
3351 const std::string &end_filament_gcode = m_config.end_filament_gcode.get_at(old_extruder_id);
3352 if (! end_filament_gcode.empty()) {
3353 gcode += placeholder_parser_process("end_filament_gcode", end_filament_gcode, old_extruder_id);
3354 check_add_eol(gcode);
3355 }
3356 }
3357
3358
3359 // If ooze prevention is enabled, set current extruder to the standby temperature.
3360 if (m_ooze_prevention.enable && m_writer.extruder() != nullptr)
3362
3363 const std::string& toolchange_gcode = m_config.toolchange_gcode.value;
3364 std::string toolchange_gcode_parsed;
3365
3366 // Process the custom toolchange_gcode. If it is empty, insert just a Tn command.
3367 if (!toolchange_gcode.empty()) {
3368 DynamicConfig config;
3369 config.set_key_value("previous_extruder", new ConfigOptionInt((int)(m_writer.extruder() != nullptr ? m_writer.extruder()->id() : -1 )));
3370 config.set_key_value("next_extruder", new ConfigOptionInt((int)extruder_id));
3371 config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
3372 config.set_key_value("layer_z", new ConfigOptionFloat(print_z));
3373 config.set_key_value("toolchange_z", new ConfigOptionFloat(print_z));
3374 config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
3375 toolchange_gcode_parsed = placeholder_parser_process("toolchange_gcode", toolchange_gcode, extruder_id, &config);
3376 gcode += toolchange_gcode_parsed;
3377 check_add_eol(gcode);
3378 }
3379
3380 // We inform the writer about what is happening, but we may not use the resulting gcode.
3381 std::string toolchange_command = m_writer.toolchange(extruder_id);
3382 if (! custom_gcode_changes_tool(toolchange_gcode_parsed, m_writer.toolchange_prefix(), extruder_id))
3383 gcode += toolchange_command;
3384 else {
3385 // user provided his own toolchange gcode, no need to do anything
3386 }
3387
3388 // Set the temperature if the wipe tower didn't (not needed for non-single extruder MM)
3389 if (m_config.single_extruder_multi_material && !m_config.wipe_tower) {
3390 int temp = (m_layer_index <= 0 ? m_config.first_layer_temperature.get_at(extruder_id) :
3391 m_config.temperature.get_at(extruder_id));
3392
3393 gcode += m_writer.set_temperature(temp, false);
3394 }
3395
3396 this->placeholder_parser().set("current_extruder", extruder_id);
3397
3398 // Append the filament start G-code.
3399 const std::string &start_filament_gcode = m_config.start_filament_gcode.get_at(extruder_id);
3400 if (! start_filament_gcode.empty()) {
3401 // Process the start_filament_gcode for the new filament.
3402 DynamicConfig config;
3403 config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
3404 config.set_key_value("layer_z", new ConfigOptionFloat(this->writer().get_position().z() - m_config.z_offset.value));
3405 config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
3406 config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(extruder_id)));
3407 gcode += this->placeholder_parser_process("start_filament_gcode", start_filament_gcode, extruder_id, &config);
3408 check_add_eol(gcode);
3409 }
3410 // Set the new extruder to the operating temperature.
3413
3414 return gcode;
3415}
std::string toolchange(unsigned int extruder_id)
Definition GCodeWriter.cpp:228
bool multiple_extruders
Definition GCodeWriter.hpp:17
std::string toolchange_prefix() const
Definition GCodeWriter.cpp:222
bool need_toolchange(unsigned int extruder_id) const
Definition GCodeWriter.hpp:51
std::string post_toolchange(GCode &gcodegen)
Definition GCode.cpp:135
std::string pre_toolchange(GCode &gcodegen)
Definition GCode.cpp:109
start_filament_gcode((ConfigOptionBool, single_extruder_multi_material))((ConfigOptionBool
toolchange_gcode((ConfigOptionFloat, travel_speed))((ConfigOptionFloat
static void check_add_eol(std::string &gcode)
Definition GCode.cpp:75
static bool custom_gcode_changes_tool(const std::string &custom_gcode, const std::string &tch_prefix, unsigned next_extruder)
Definition GCode.cpp:83

References Slic3r::check_add_eol(), config(), Slic3r::custom_gcode_changes_tool(), Slic3r::OozePrevention::enable, Slic3r::GCodeWriter::extruder(), Slic3r::Extruder::id(), m_config, m_layer_index, m_max_layer_z, m_ooze_prevention, m_wipe, m_writer, Slic3r::GCodeWriter::multiple_extruders, Slic3r::GCodeWriter::need_toolchange(), placeholder_parser(), placeholder_parser_process(), Slic3r::OozePrevention::post_toolchange(), Slic3r::OozePrevention::pre_toolchange(), Slic3r::Wipe::reset_path(), retract(), Slic3r::PlaceholderParser::set(), Slic3r::GCodeWriter::set_temperature(), Slic3r::start_filament_gcode(), Slic3r::GCodeWriter::toolchange(), Slic3r::toolchange_gcode(), Slic3r::GCodeWriter::toolchange_prefix(), and writer().

Referenced by _do_export(), Slic3r::WipeTowerIntegration::append_tcr(), and process_layer().

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

◆ set_extruders()

void Slic3r::GCode::set_extruders ( const std::vector< unsigned int > &  extruder_ids)
private
2594{
2595 m_writer.set_extruders(extruder_ids);
2596
2597 // enable wipe path generation if any extruder has wipe enabled
2598 m_wipe.enable = false;
2599 for (auto id : extruder_ids)
2600 if (m_config.wipe.get_at(id)) {
2601 m_wipe.enable = true;
2602 break;
2603 }
2604}
void set_extruders(std::vector< unsigned int > extruder_ids)
Definition GCodeWriter.cpp:38

References Slic3r::Wipe::enable, m_config, m_wipe, m_writer, and Slic3r::GCodeWriter::set_extruders().

Referenced by _do_export().

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

◆ set_last_pos()

void Slic3r::GCode::set_last_pos ( const Point pos)
inlineprivate
278{ m_last_pos = pos; m_last_pos_defined = true; }

References m_last_pos, and m_last_pos_defined.

Referenced by _extrude(), Slic3r::WipeTowerIntegration::append_tcr(), placeholder_parser_process(), travel_to(), and Slic3r::Wipe::wipe().

+ Here is the caller graph for this function:

◆ set_layer_count()

void Slic3r::GCode::set_layer_count ( unsigned int  value)
inline
185{ m_layer_count = value; }

References m_layer_count.

◆ set_origin() [1/2]

void Slic3r::GCode::set_origin ( const coordf_t  x,
const coordf_t  y 
)
inline
165{ this->set_origin(Vec2d(x, y)); }

References set_origin().

Referenced by set_origin().

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

◆ set_origin() [2/2]

void Slic3r::GCode::set_origin ( const Vec2d pointf)
2607{
2608 // if origin increases (goes towards right), last_pos decreases because it goes towards left
2609 const Point translate(
2610 scale_(m_origin(0) - pointf(0)),
2611 scale_(m_origin(1) - pointf(1))
2612 );
2614 m_wipe.path.translate(translate);
2615 m_origin = pointf;
2616}
void translate(double x, double y)
Definition MultiPoint.hpp:29
void translate(Slic3r::ExPolygon &sh, const Slic3r::Point &offs)
Definition geometries.hpp:241

References m_last_pos, m_origin, m_wipe, Slic3r::Wipe::path, scale_, and Slic3r::MultiPoint::translate().

Referenced by _do_export(), process_layer(), and process_layer_single_object().

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

◆ sort_print_object_instances()

std::vector< GCode::InstanceToPrint > Slic3r::GCode::sort_print_object_instances ( const std::vector< ObjectLayerToPrint > &  layers,
const std::vector< const PrintInstance * > *  ordering,
const size_t  single_object_instance_idx 
)
private
1924{
1925 std::vector<InstanceToPrint> out;
1926
1927 if (ordering == nullptr) {
1928 // Sequential print, single object is being printed.
1929 assert(object_layers.size() == 1);
1930 out.emplace_back(0, *object_layers.front().object(), single_object_instance_idx);
1931 } else {
1932 // Create mapping from PrintObject* to ObjectLayerToPrint ID.
1933 std::vector<std::pair<const PrintObject*, size_t>> sorted;
1934 sorted.reserve(object_layers.size());
1935 for (const ObjectLayerToPrint &object : object_layers)
1936 if (const PrintObject* print_object = object.object(); print_object)
1937 sorted.emplace_back(print_object, &object - object_layers.data());
1938 std::sort(sorted.begin(), sorted.end());
1939
1940 if (! sorted.empty()) {
1941 out.reserve(sorted.size());
1942 for (const PrintInstance *instance : *ordering) {
1943 const PrintObject &print_object = *instance->print_object;
1944 std::pair<const PrintObject*, size_t> key(&print_object, 0);
1945 auto it = std::lower_bound(sorted.begin(), sorted.end(), key);
1946 if (it != sorted.end() && it->first == &print_object)
1947 // ObjectLayerToPrint for this PrintObject was found.
1948 out.emplace_back(it->second, print_object, instance - print_object.instances().data());
1949 }
1950 }
1951 }
1952 return out;
1953}

References Slic3r::PrintObject::instances(), and ordering.

Referenced by process_layer().

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

◆ travel_to()

std::string Slic3r::GCode::travel_to ( const Point point,
ExtrusionRole  role,
std::string  comment 
)
private
3170{
3171 /* Define the travel move as a line between current position and the taget point.
3172 This is expressed in print coordinates, so it will need to be translated by
3173 this->origin in order to get G-code coordinates. */
3174 Polyline travel { this->last_pos(), point };
3175
3176 if (this->config().avoid_crossing_curled_overhangs) {
3177 if (m_config.avoid_crossing_perimeters) {
3178 BOOST_LOG_TRIVIAL(warning)
3179 << "Option >avoid crossing curled overhangs< is not compatible with avoid crossing perimeters and it will be ignored!";
3180 } else {
3181 Point scaled_origin = Point(scaled(this->origin()));
3182 travel = m_avoid_crossing_curled_overhangs.find_path(this->last_pos() + scaled_origin, point + scaled_origin);
3183 travel.translate(-scaled_origin);
3184 }
3185 }
3186
3187 // check whether a straight travel move would need retraction
3188 bool needs_retraction = this->needs_retraction(travel, role);
3189 // check whether wipe could be disabled without causing visible stringing
3190 bool could_be_wipe_disabled = false;
3191 // Save state of use_external_mp_once for the case that will be needed to call twice m_avoid_crossing_perimeters.travel_to.
3192 const bool used_external_mp_once = m_avoid_crossing_perimeters.used_external_mp_once();
3193
3194 // if a retraction would be needed, try to use avoid_crossing_perimeters to plan a
3195 // multi-hop travel path inside the configuration space
3197 && m_config.avoid_crossing_perimeters
3199 travel = m_avoid_crossing_perimeters.travel_to(*this, point, &could_be_wipe_disabled);
3200 // check again whether the new travel path still needs a retraction
3201 needs_retraction = this->needs_retraction(travel, role);
3202 //if (needs_retraction && m_layer_index > 1) exit(0);
3203 }
3204
3205 // Re-allow avoid_crossing_perimeters for the next travel moves
3207
3208 // generate G-code for the travel move
3209 std::string gcode;
3210 if (needs_retraction) {
3211 if (m_config.avoid_crossing_perimeters && could_be_wipe_disabled)
3213
3214 Point last_post_before_retract = this->last_pos();
3215 gcode += this->retract();
3216 // When "Wipe while retracting" is enabled, then extruder moves to another position, and travel from this position can cross perimeters.
3217 // Because of it, it is necessary to call avoid crossing perimeters again with new starting point after calling retraction()
3218 // FIXME Lukas H.: Try to predict if this second calling of avoid crossing perimeters will be needed or not. It could save computations.
3219 if (last_post_before_retract != this->last_pos() && m_config.avoid_crossing_perimeters) {
3220 // If in the previous call of m_avoid_crossing_perimeters.travel_to was use_external_mp_once set to true restore this value for next call.
3221 if (used_external_mp_once)
3223 travel = m_avoid_crossing_perimeters.travel_to(*this, point);
3224 // If state of use_external_mp_once was changed reset it to right value.
3225 if (used_external_mp_once)
3227 }
3228 } else
3229 // Reset the wipe path when traveling, so one would not wipe along an old path.
3231
3232 // use G1 because we rely on paths being straight (G0 may make round paths)
3233 if (travel.size() >= 2) {
3234
3235 gcode += m_writer.set_travel_acceleration((unsigned int)(m_config.travel_acceleration.value + 0.5));
3236
3237 for (size_t i = 1; i < travel.size(); ++ i)
3238 gcode += m_writer.travel_to_xy(this->point_to_gcode(travel.points[i]), comment);
3239
3241 // In case that this flavor does not support separate print and travel acceleration,
3242 // reset acceleration to default.
3243 gcode += m_writer.set_travel_acceleration((unsigned int)(m_config.travel_acceleration.value + 0.5));
3244 }
3245
3246 this->set_last_pos(travel.points.back());
3247 }
3248 return gcode;
3249}
Polyline travel_to(const GCode &gcodegen, const Point &point)
Definition AvoidCrossingPerimeters.hpp:28
void reset_once_modifiers()
Definition AvoidCrossingPerimeters.hpp:24
bool used_external_mp_once()
Definition AvoidCrossingPerimeters.hpp:21
bool disabled_once() const
Definition AvoidCrossingPerimeters.hpp:23
bool needs_retraction(const Polyline &travel, ExtrusionRole role=ExtrusionRole::None)
Definition GCode.cpp:3251
const Vec2d & origin() const
Definition GCode.hpp:163
static bool supports_separate_travel_acceleration(GCodeFlavor flavor)
Definition GCodeWriter.cpp:19
std::string set_travel_acceleration(unsigned int acceleration)
Definition GCodeWriter.hpp:47
Polyline find_path(const Point &start, const Point &end)
Definition JumpPointSearch.cpp:221
BoundingBox scaled(const BoundingBoxf &bb)
Definition BoundingBox.hpp:240
gcode_flavor((ConfigOptionBool, gcode_label_objects))((ConfigOptionStrings

References comment, config(), Slic3r::AvoidCrossingPerimeters::disabled_once(), Slic3r::JPSPathFinder::find_path(), Slic3r::gcode_flavor(), last_pos(), m_avoid_crossing_curled_overhangs, m_avoid_crossing_perimeters, m_config, m_wipe, m_writer, needs_retraction(), origin(), Slic3r::AvoidCrossingPerimeters::reset_once_modifiers(), Slic3r::Wipe::reset_path(), retract(), Slic3r::scaled(), set_last_pos(), Slic3r::GCodeWriter::set_travel_acceleration(), Slic3r::GCodeWriter::supports_separate_travel_acceleration(), Slic3r::MultiPoint::translate(), Slic3r::AvoidCrossingPerimeters::travel_to(), Slic3r::GCodeWriter::travel_to_xy(), Slic3r::AvoidCrossingPerimeters::use_external_mp_once(), and Slic3r::AvoidCrossingPerimeters::used_external_mp_once().

Referenced by _do_export(), _extrude(), and Slic3r::WipeTowerIntegration::append_tcr().

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

◆ unretract()

std::string Slic3r::GCode::unretract ( )
inlineprivate
330{ return m_writer.unlift() + m_writer.unretract(); }
std::string unlift()
Definition GCodeWriter.cpp:479
std::string unretract()
Definition GCodeWriter.cpp:435

References m_writer, Slic3r::GCodeWriter::unlift(), and Slic3r::GCodeWriter::unretract().

Referenced by _extrude(), and Slic3r::WipeTowerIntegration::append_tcr().

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

◆ writer() [1/2]

◆ writer() [2/2]

const GCodeWriter & Slic3r::GCode::writer ( ) const
inline
175{ return m_writer; }

References m_writer.

Friends And Related Symbol Documentation

◆ PressureEqualizer

friend class PressureEqualizer
friend

◆ Wipe

friend class Wipe
friend

◆ WipeTowerIntegration

friend class WipeTowerIntegration
friend

Referenced by _do_export().

Member Data Documentation

◆ m_avoid_crossing_curled_overhangs

JPSPathFinder Slic3r::GCode::m_avoid_crossing_curled_overhangs
private

◆ m_avoid_crossing_perimeters

◆ m_brim_done

bool Slic3r::GCode::m_brim_done
private

Referenced by process_layer().

◆ m_config

◆ m_cooling_buffer

std::unique_ptr<CoolingBuffer> Slic3r::GCode::m_cooling_buffer
private

Referenced by _do_export().

◆ m_enable_cooling_markers

bool Slic3r::GCode::m_enable_cooling_markers
private

◆ m_enable_extrusion_role_markers

bool Slic3r::GCode::m_enable_extrusion_role_markers
private

Referenced by _do_export(), and _extrude().

◆ m_enable_loop_clipping

bool Slic3r::GCode::m_enable_loop_clipping
private

Referenced by extrude_loop(), and process_layer().

◆ m_extrusion_quality_estimator

ExtrusionQualityEstimator Slic3r::GCode::m_extrusion_quality_estimator
private

◆ m_find_replace

std::unique_ptr<GCodeFindReplace> Slic3r::GCode::m_find_replace
private

◆ m_last_extrusion_role

GCodeExtrusionRole Slic3r::GCode::m_last_extrusion_role
private

Referenced by _extrude().

◆ m_last_height

float Slic3r::GCode::m_last_height { 0.0f }
private

Referenced by _do_export(), _extrude(), and process_layer().

◆ m_last_layer_z

float Slic3r::GCode::m_last_layer_z { 0.0f }
private

Referenced by _do_export(), and process_layer().

◆ m_last_obj_copy

std::pair<const PrintObject*, Point> Slic3r::GCode::m_last_obj_copy
private

◆ m_last_pos

Point Slic3r::GCode::m_last_pos
private

◆ m_last_pos_defined

bool Slic3r::GCode::m_last_pos_defined
private

◆ m_last_processor_extrusion_role

GCodeExtrusionRole Slic3r::GCode::m_last_processor_extrusion_role
private

Referenced by _extrude(), and process_layer().

◆ m_last_width

float Slic3r::GCode::m_last_width { 0.0f }
private

Referenced by _do_export(), and _extrude().

◆ m_layer

◆ m_layer_count

unsigned int Slic3r::GCode::m_layer_count
private

◆ m_layer_index

int Slic3r::GCode::m_layer_index
private

◆ m_max_layer_z

float Slic3r::GCode::m_max_layer_z { 0.0f }
private

◆ m_object_layer_over_raft

bool Slic3r::GCode::m_object_layer_over_raft
private

◆ m_ooze_prevention

OozePrevention Slic3r::GCode::m_ooze_prevention
private

◆ m_origin

Vec2d Slic3r::GCode::m_origin
private

◆ m_placeholder_parser_integration

struct Slic3r::GCode::PlaceholderParserIntegration Slic3r::GCode::m_placeholder_parser_integration
private

◆ m_pressure_equalizer

std::unique_ptr<PressureEqualizer> Slic3r::GCode::m_pressure_equalizer
private

Referenced by _do_export().

◆ m_processor

GCodeProcessor Slic3r::GCode::m_processor
private

◆ m_retract_when_crossing_perimeters

RetractWhenCrossingPerimeters Slic3r::GCode::m_retract_when_crossing_perimeters
private

Referenced by needs_retraction().

◆ m_scaled_resolution

double Slic3r::GCode::m_scaled_resolution
private

◆ m_seam_placer

SeamPlacer Slic3r::GCode::m_seam_placer
private

Referenced by _do_export(), and extrude_loop().

◆ m_second_layer_things_done

bool Slic3r::GCode::m_second_layer_things_done
private

Referenced by _do_export(), and process_layer().

◆ m_silent_time_estimator_enabled

bool Slic3r::GCode::m_silent_time_estimator_enabled
private

Referenced by _do_export().

◆ m_skirt_done

std::vector<coordf_t> Slic3r::GCode::m_skirt_done
private

Referenced by process_layer().

◆ m_spiral_vase

std::unique_ptr<SpiralVase> Slic3r::GCode::m_spiral_vase
private

Referenced by _do_export(), and process_layer().

◆ m_volumetric_speed

double Slic3r::GCode::m_volumetric_speed
private

Referenced by _do_export(), and _extrude().

◆ m_wipe

◆ m_wipe_tower

std::unique_ptr<WipeTowerIntegration> Slic3r::GCode::m_wipe_tower
private

◆ m_writer


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