diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 5afe6b34c4..1d72639f55 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -103,6 +103,41 @@ namespace Slic3r { } + // Accepts vector of PrintObjectPtrs and an object and instance ids. Returns starting tag for label object function. + static std::string label_object_start(LabelObjects label_object_style, const SpanOfConstPtrs& objects, int object_id, int instance_id) + { + int unique_id = 0; + for (size_t idx = 0; idx < size_t(object_id); ++idx) + unique_id += int(objects[idx]->model_object()->instances.size()); + unique_id += instance_id; + + std::string name = objects[object_id]->model_object()->name; + if (label_object_style == loMarlin && objects[object_id]->model_object()->instances.size() > 1u) + name += " (copy " + std::to_string(instance_id) + ")"; + + std::string out; + if (label_object_style == loOctoprint) + out += std::string("; printing object ") + name + " id:" + std::to_string(object_id) + " copy " + std::to_string(instance_id) + "\n"; + else if (label_object_style == loMarlin) { + out += std::string("M486 S") + std::to_string(unique_id) + "\n"; + out += std::string("M486 N") + name + "\n"; + } + return out; + } + + + static std::string label_object_stop(LabelObjects label_object_style, int object_id, int instance_id, const std::string& name) + { + std::string out; + if (label_object_style == loOctoprint) + out += std::string("; stop printing object ") + name + " id:" + std::to_string(object_id) + " copy " + std::to_string(instance_id) + "\n"; + else if (label_object_style == loMarlin) + out += std::string("M486 S-1\n"); + return out; + } + + + // Return true if tch_prefix is found in custom_gcode static bool custom_gcode_changes_tool(const std::string& custom_gcode, const std::string& tch_prefix, unsigned next_extruder) { @@ -1215,6 +1250,18 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail // Set other general things. file.write(this->preamble()); + // Label all objects so printer knows about them since the start. + if (config().gcode_label_objects != loDisabled) { + file.write("\n"); + for (size_t object_idx = 0; object_idx < print.objects().size(); ++object_idx) { + for (size_t inst_idx = 0; inst_idx < print.objects()[object_idx]->model_object()->instances.size(); ++inst_idx) { + file.write(label_object_start(config().gcode_label_objects, print.objects(), object_idx, inst_idx)); + file.write(label_object_stop(config().gcode_label_objects, object_idx, inst_idx, print.objects()[object_idx]->model_object()->name)); + } + } + file.write("\n"); + } + print.throw_if_canceled(); // Collect custom seam data from all objects. @@ -2354,13 +2401,13 @@ void GCodeGenerator::process_layer_single_object( m_avoid_crossing_perimeters.use_external_mp_once(); m_last_obj_copy = this_object_copy; this->set_origin(unscale(offset)); - if (this->config().gcode_label_objects) { - for (const PrintObject *po : print_object.print()->objects()) + if (this->config().gcode_label_objects != loDisabled) { + for (const PrintObject* po : print_object.print()->objects()) { if (po == &print_object) break; - else - ++ object_id; - 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"; + ++object_id; + } + gcode += label_object_start(config().gcode_label_objects, print_object.print()->objects(), object_id, print_instance.instance_id); } } }; @@ -2538,8 +2585,8 @@ void GCodeGenerator::process_layer_single_object( } } } - if (! first && this->config().gcode_label_objects) - 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"; + if (! first && config().gcode_label_objects != loDisabled) + gcode += label_object_stop(config().gcode_label_objects, object_id, print_instance.instance_id, print_object.model_object()->name); } void GCodeGenerator::apply_print_config(const PrintConfig &print_config) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 6d52484e9c..2c033c5d9c 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -229,6 +229,13 @@ static const t_config_enum_values s_keys_map_DraftShield = { }; CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(DraftShield) +static const t_config_enum_values s_keys_map_LabelObjects = { + { "disabled", loDisabled }, + { "octoprint", loOctoprint }, + { "marlin", loMarlin } +}; +CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(LabelObjects) + static const t_config_enum_values s_keys_map_GCodeThumbnailsFormat = { { "PNG", int(GCodeThumbnailsFormat::PNG) }, { "JPG", int(GCodeThumbnailsFormat::JPG) }, @@ -1493,13 +1500,18 @@ void PrintConfigDef::init_fff_params() def->mode = comExpert; def->set_default_value(new ConfigOptionEnum(gcfRepRapSprinter)); - def = this->add("gcode_label_objects", coBool); + def = this->add("gcode_label_objects", coEnum); def->label = L("Label objects"); def->tooltip = L("Enable this to add comments into the G-Code labeling print moves with what object they belong to," " which is useful for the Octoprint CancelObject plugin. This settings is NOT compatible with " "Single Extruder Multi Material setup and Wipe into Object / Wipe into Infill."); + def->set_enum({ + { "disabled", L("Disabled") }, + { "octoprint", L("OctoPrint comments") }, + { "marlin", L("Marlin (M486)") } + }); def->mode = comAdvanced; - def->set_default_value(new ConfigOptionBool(0)); + def->set_default_value(new ConfigOptionEnum(loDisabled)); def = this->add("gcode_substitutions", coStrings); def->label = L("G-code substitutions"); @@ -4335,6 +4347,10 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va } else if (opt_key == "draft_shield" && (value == "1" || value == "0")) { // draft_shield used to be a bool, it was turned into an enum in PrusaSlicer 2.4.0. value = value == "1" ? "enabled" : "disabled"; + } else if (opt_key == "gcode_label_objects" && (value == "1" || value == "0")) { + // gcode_label_objects used to be a bool (the behavior was nothing or "octoprint"), it is + // and enum since PrusaSlicer 2.6.2. + value = value == "1" ? "octoprint" : "disabled"; } else if (opt_key == "octoprint_host") { opt_key = "print_host"; } else if (opt_key == "octoprint_cafile") { diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 390f91daf6..5466ad1fd3 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -147,6 +147,10 @@ enum DraftShield { dsDisabled, dsLimited, dsEnabled }; +enum LabelObjects { + loDisabled, loOctoprint, loMarlin +}; + enum class PerimeterGeneratorType { // Classic perimeter generator using Clipper offsets with constant extrusion width. @@ -183,6 +187,7 @@ CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SLAPillarConnectionMode) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SLASupportTreeType) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(BrimType) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(DraftShield) +CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(LabelObjects) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(GCodeThumbnailsFormat) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(ForwardCompatibilitySubstitutionRule) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(PerimeterGeneratorType) @@ -729,7 +734,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionFloats, filament_multitool_ramming_flow)) ((ConfigOptionBool, gcode_comments)) ((ConfigOptionEnum, gcode_flavor)) - ((ConfigOptionBool, gcode_label_objects)) + ((ConfigOptionEnum, gcode_label_objects)) // Triples of strings: "search pattern", "replace with pattern", "attribs" // where "attribs" are one of: // r - regular expression