Label objects: refactoring + fix of object/instance indexing when instances are rotated/out-of-bed

This commit is contained in:
Lukas Matena 2023-09-12 17:23:27 +02:00
parent 387376fb25
commit fe3cf27394
7 changed files with 192 additions and 78 deletions

View File

@ -158,6 +158,8 @@ set(SLIC3R_SOURCES
GCode/ExtrusionProcessor.hpp
GCode/FindReplace.cpp
GCode/FindReplace.hpp
GCode/LabelObjects.cpp
GCode/LabelObjects.hpp
GCode/GCodeWriter.cpp
GCode/GCodeWriter.hpp
GCode/PostProcessor.cpp

View File

@ -28,6 +28,7 @@
#include "Exception.hpp"
#include "ExtrusionEntity.hpp"
#include "Geometry/ConvexHull.hpp"
#include "GCode/LabelObjects.hpp"
#include "GCode/PrintExtents.hpp"
#include "GCode/Thumbnails.hpp"
#include "GCode/WipeTower.hpp"
@ -102,69 +103,6 @@ namespace Slic3r {
gcode += '\n';
}
// 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, GCodeFlavor flavor, const SpanOfConstPtrs<PrintObject>& 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 == LabelObjects::Firmware && objects[object_id]->model_object()->instances.size() > 1u)
name += " (copy " + std::to_string(instance_id) + ")";
std::string out;
if (label_object_style == LabelObjects::Octoprint)
out += std::string("; printing object ") + name + " id:" + std::to_string(object_id) + " copy " + std::to_string(instance_id) + "\n";
else if (label_object_style == LabelObjects::Firmware) {
if (flavor == GCodeFlavor::gcfMarlinFirmware || flavor == GCodeFlavor::gcfMarlinLegacy || flavor == GCodeFlavor::gcfRepRapFirmware) {
out += std::string("M486 S") + std::to_string(unique_id) + "\n";
out += std::string("M486 A");
out += (flavor == GCodeFlavor::gcfRepRapFirmware ? (std::string("\"") + name + "\"") : name) + "\n";
} else {
// Not supported by / implemented for the other firmware flavors.
}
}
return out;
}
static std::string label_object_stop(LabelObjects label_object_style, GCodeFlavor flavor, int object_id, int instance_id, const std::string& name)
{
std::string out;
if (label_object_style == LabelObjects::Octoprint)
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 == LabelObjects::Firmware)
if (flavor == GCodeFlavor::gcfMarlinFirmware || flavor == GCodeFlavor::gcfMarlinLegacy || flavor == GCodeFlavor::gcfRepRapFirmware)
out += std::string("M486 S-1\n");
else {
// Not supported by / implemented for the other firmware flavors.
}
return out;
}
static std::string label_all_objects(LabelObjects label_objects_style, GCodeFlavor flavor, const Print& print)
{
std::string out;
if (label_objects_style != LabelObjects::Disabled) {
out += "\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) {
out += label_object_start(label_objects_style, flavor, print.objects(), object_idx, inst_idx);
out += label_object_stop(label_objects_style, flavor, object_idx, inst_idx, print.objects()[object_idx]->model_object()->name);
}
}
out += "\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)
{
@ -1207,7 +1145,8 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
this->print_machine_envelope(file, print);
// Label all objects so printer knows about them since the start.
file.write(label_all_objects(config().gcode_label_objects, config().gcode_flavor, print));
m_label_objects.init(print);
file.write(m_label_objects.all_objects_header());
// Update output variables after the extruders were initialized.
m_placeholder_parser_integration.init(m_writer);
@ -2419,13 +2358,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 != LabelObjects::Disabled) {
if (this->config().gcode_label_objects != LabelObjectsStyle::Disabled) {
for (const PrintObject* po : print_object.print()->objects()) {
if (po == &print_object)
break;
++object_id;
}
gcode += label_object_start(config().gcode_label_objects, config().gcode_flavor, print_object.print()->objects(), object_id, print_instance.instance_id);
gcode += m_label_objects.start_object(print_instance.print_object.instances()[print_instance.instance_id], GCode::LabelObjects::IncludeName::No);
}
}
};
@ -2603,8 +2542,8 @@ void GCodeGenerator::process_layer_single_object(
}
}
}
if (! first && config().gcode_label_objects != LabelObjects::Disabled)
gcode += label_object_stop(config().gcode_label_objects, config().gcode_flavor, object_id, print_instance.instance_id, print_object.model_object()->name);
if (! first)
gcode += m_label_objects.stop_object(print_instance.print_object.instances()[print_instance.instance_id]);
}
void GCodeGenerator::apply_print_config(const PrintConfig &print_config)

View File

@ -28,6 +28,7 @@
#include "GCode/CoolingBuffer.hpp"
#include "GCode/FindReplace.hpp"
#include "GCode/GCodeWriter.hpp"
#include "GCode/LabelObjects.hpp"
#include "GCode/PressureEqualizer.hpp"
#include "GCode/RetractWhenCrossingPerimeters.hpp"
#include "GCode/SmoothPath.hpp"
@ -353,6 +354,7 @@ private:
OozePrevention m_ooze_prevention;
GCode::Wipe m_wipe;
GCode::LabelObjects m_label_objects;
AvoidCrossingPerimeters m_avoid_crossing_perimeters;
JPSPathFinder m_avoid_crossing_curled_overhangs;
RetractWhenCrossingPerimeters m_retract_when_crossing_perimeters;

View File

@ -0,0 +1,122 @@
#include "LabelObjects.hpp"
namespace Slic3r::GCode {
void LabelObjects::init(const Print& print)
{
m_label_objects_style = print.config().gcode_label_objects;
m_flavor = print.config().gcode_flavor;
if (m_label_objects_style == LabelObjectsStyle::Disabled)
return;
std::map<const ModelObject*, std::vector<const PrintInstance*>> model_object_to_print_instances;
// Iterate over all PrintObjects and their PrintInstances, collect PrintInstances which
// belong to the same ModelObject.
for (const PrintObject* po : print.objects())
for (const PrintInstance& pi : po->instances())
model_object_to_print_instances[pi.model_instance->get_object()].emplace_back(&pi);
// Now go through the map, assign a unique_id to each of the PrintInstances and get the indices of the
// respective ModelObject and ModelInstance so we can use them in the tags. This will maintain
// indices even in case that some instances are rotated (those end up in different PrintObjects)
// or when some are out of bed (these ModelInstances have no corresponding PrintInstances).
int unique_id = 0;
for (const auto& [model_object, print_instances] : model_object_to_print_instances) {
const ModelObjectPtrs& model_objects = model_object->get_model()->objects;
int object_id = int(std::find(model_objects.begin(), model_objects.end(), model_object) - model_objects.begin());
for (const PrintInstance* const pi : print_instances) {
int instance_id = int(std::find(model_object->instances.begin(), model_object->instances.end(), pi->model_instance) - model_object->instances.begin());
if (m_label_objects_style != LabelObjectsStyle::Octoprint) {
// OctoPrint comments have always indexed instances from 0, let's keep it that way.
// In the other cases, we will use one-based indexing so the indices match with the one in PrusaSlicer.
++instance_id;
}
m_label_data.emplace(pi, LabelData{model_object->name, unique_id, object_id, instance_id, print_instances.size() > 1});
++unique_id;
}
}
}
std::string LabelObjects::all_objects_header() const
{
if (m_label_objects_style == LabelObjectsStyle::Disabled)
return std::string();
std::string out;
// Let's sort the values according to unique_id so they are in the same order in which they were added.
std::vector<std::pair<const PrintInstance*, LabelData>> label_data_sorted;
for (const auto& pi_and_label : m_label_data)
label_data_sorted.emplace_back(pi_and_label);
std::sort(label_data_sorted.begin(), label_data_sorted.end(), [](const auto& ld1, const auto& ld2) { return ld1.second.unique_id < ld2.second.unique_id; });
out += "\n";
for (const auto& [print_instance, label] : label_data_sorted) {
out += start_object(*print_instance, IncludeName::Yes);
out += stop_object(*print_instance);
}
out += "\n";
return out;
}
std::string LabelObjects::start_object(const PrintInstance& print_instance, IncludeName include_name) const
{
if (m_label_objects_style == LabelObjectsStyle::Disabled)
return std::string();
const LabelData& label = m_label_data.at(&print_instance);
std::string name = label.name;
if (m_label_objects_style == LabelObjectsStyle::Firmware && label.object_has_more_instances)
name += " (copy " + std::to_string(label.instance_id) + ")";
std::string out;
if (m_label_objects_style == LabelObjectsStyle::Octoprint)
out += std::string("; printing object ") + name + " id:" + std::to_string(label.object_id) + " copy " + std::to_string(label.instance_id) + "\n";
else if (m_label_objects_style == LabelObjectsStyle::Firmware) {
if (m_flavor == GCodeFlavor::gcfMarlinFirmware || m_flavor == GCodeFlavor::gcfMarlinLegacy || m_flavor == GCodeFlavor::gcfRepRapFirmware) {
out += std::string("M486 S") + std::to_string(label.unique_id) + "\n";
if (include_name == IncludeName::Yes) {
out += std::string("M486 A");
out += (m_flavor == GCodeFlavor::gcfRepRapFirmware ? (std::string("\"") + name + "\"") : name) + "\n";
}
} else {
// Not supported by / implemented for the other firmware flavors.
}
}
return out;
}
std::string LabelObjects::stop_object(const PrintInstance& print_instance) const
{
if (m_label_objects_style == LabelObjectsStyle::Disabled)
return std::string();
const LabelData& label = m_label_data.at(&print_instance);
std::string out;
if (m_label_objects_style == LabelObjectsStyle::Octoprint)
out += std::string("; stop printing object ") + label.name + " id:" + std::to_string(label.object_id) + " copy " + std::to_string(label.instance_id) + "\n";
else if (m_label_objects_style == LabelObjectsStyle::Firmware)
if (m_flavor == GCodeFlavor::gcfMarlinFirmware || m_flavor == GCodeFlavor::gcfMarlinLegacy || m_flavor == GCodeFlavor::gcfRepRapFirmware)
out += std::string("M486 S-1\n");
else {
// Not supported by / implemented for the other firmware flavors.
}
return out;
}
} // namespace Slic3r::GCode

View File

@ -0,0 +1,49 @@
#ifndef slic3r_GCode_LabelObjects_hpp_
#define slic3r_GCode_LabelObjects_hpp_
#include "Print.hpp"
namespace Slic3r {
enum GCodeFlavor : unsigned char;
enum class LabelObjectsStyle;
namespace GCode {
//std::string label_object_start(LabelObjectsStyle label_object_style, GCodeFlavor flavor, const SpanOfConstPtrs<PrintObject>& objects, int object_id, int instance_id);
//std::string label_object_stop(LabelObjectsStyle label_object_style, GCodeFlavor flavor, int object_id, int instance_id, const std::string& name);
//std::string label_all_objects(LabelObjectsStyle label_objects_style, GCodeFlavor flavor, const Print& print);
class LabelObjects {
public:
enum class IncludeName {
No,
Yes
};
void init(const Print& print);
std::string all_objects_header() const;
std::string start_object(const PrintInstance& print_instance, IncludeName include_name) const;
std::string stop_object(const PrintInstance& print_instance) const;
private:
struct LabelData {
std::string name;
int unique_id;
int object_id;
int instance_id;
bool object_has_more_instances;
};
LabelObjectsStyle m_label_objects_style;
GCodeFlavor m_flavor;
std::unordered_map<const PrintInstance*, LabelData> m_label_data;
};
} // namespace GCode
} // namespace Slic3r
#endif // slic3r_GCode_LabelObjects_hpp_

View File

@ -229,12 +229,12 @@ 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", int(LabelObjects::Disabled) },
{ "octoprint", int(LabelObjects::Octoprint) },
{ "firmware", int(LabelObjects::Firmware) }
static const t_config_enum_values s_keys_map_LabelObjectsStyle = {
{ "disabled", int(LabelObjectsStyle::Disabled) },
{ "octoprint", int(LabelObjectsStyle::Octoprint) },
{ "firmware", int(LabelObjectsStyle::Firmware) }
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(LabelObjects)
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(LabelObjectsStyle)
static const t_config_enum_values s_keys_map_GCodeThumbnailsFormat = {
{ "PNG", int(GCodeThumbnailsFormat::PNG) },
@ -1507,13 +1507,13 @@ void PrintConfigDef::init_fff_params()
" Firmware = firmware specific G-code (it will be chosen based on firmware flavor and it can end up to be empty).\n\n"
"This settings is NOT compatible with Single Extruder Multi Material setup and Wipe into Object / Wipe into Infill.");
def->set_enum<LabelObjects>({
def->set_enum<LabelObjectsStyle>({
{ "disabled", L("Disabled") },
{ "octoprint", L("OctoPrint comments") },
{ "firmware", L("Firmware-specific") }
});
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionEnum<LabelObjects>(LabelObjects::Disabled));
def->set_default_value(new ConfigOptionEnum<LabelObjectsStyle>(LabelObjectsStyle::Disabled));
def = this->add("gcode_substitutions", coStrings);
def->label = L("G-code substitutions");

View File

@ -147,7 +147,7 @@ enum DraftShield {
dsDisabled, dsLimited, dsEnabled
};
enum class LabelObjects {
enum class LabelObjectsStyle {
Disabled, Octoprint, Firmware
};
@ -187,7 +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(LabelObjectsStyle)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(GCodeThumbnailsFormat)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(ForwardCompatibilitySubstitutionRule)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(PerimeterGeneratorType)
@ -734,7 +734,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloats, filament_multitool_ramming_flow))
((ConfigOptionBool, gcode_comments))
((ConfigOptionEnum<GCodeFlavor>, gcode_flavor))
((ConfigOptionEnum<LabelObjects>, gcode_label_objects))
((ConfigOptionEnum<LabelObjectsStyle>, gcode_label_objects))
// Triples of strings: "search pattern", "replace with pattern", "attribs"
// where "attribs" are one of:
// r - regular expression