support Klipper Exclude objects natively.

Also remove fake slicer info
This commit is contained in:
SoftFever 2023-04-01 13:25:55 +08:00
parent 32d952587d
commit 22a24168e6
11 changed files with 141 additions and 34 deletions

View file

@ -1530,12 +1530,6 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
print.config().nozzle_temperature_initial_layer.get_at(0));
file.write("; CONFIG_BLOCK_END\n\n");
} else {
file.write_format("; hack-fix: write fake slicer info here so that "
"preprocess_cancellation can process.\n");
file.write_format("; %s\n\n", std::string(std::string("generated by SuperSlicer " SoftFever_VERSION " on ") +
Slic3r::Utils::local_timestamp())
.c_str());
DoExport::export_thumbnails_to_file(
thumbnail_cb, print.get_plate_index(), print.full_print_config().option<ConfigOptionPoints>("thumbnails")->values,
[&file](const char *sz) { file.write(sz); },
@ -1563,6 +1557,10 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
}
file.write_format("; EXECUTABLE_BLOCK_START\n");
// SoftFever
file.write(set_object_info(&print));
// adds tags for time estimators
file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::First_Line_M73_Placeholder).c_str());
@ -2474,7 +2472,7 @@ std::vector<GCode::InstanceToPrint> GCode::sort_print_object_instances(
const PrintObject *print_object = layers[layer_id].original_object;
//const PrintObject *print_object = layers[layer_id].object();
if (print_object)
out.emplace_back(object_by_extruder, layer_id, *print_object, single_object_instance_idx);
out.emplace_back(object_by_extruder, *print_object, single_object_instance_idx);
}
} else {
// Create mapping from PrintObject* to ObjectByExtruder*.
@ -2502,7 +2500,7 @@ std::vector<GCode::InstanceToPrint> GCode::sort_print_object_instances(
auto it = std::lower_bound(sorted.begin(), sorted.end(), key);
if (it != sorted.end() && it->first == &print_object)
// ObjectByExtruder for this PrintObject was found.
out.emplace_back(*it->second, it->second - objects_by_extruder.data(), print_object, instance - print_object.instances().data());
out.emplace_back(*it->second, print_object, instance->id);
}
}
}
@ -2670,6 +2668,14 @@ namespace Skirt {
} // namespace Skirt
inline std::string get_instance_name(const PrintObject *object, const PrintInstance &inst) {
return (boost::format("%1%_id_%2%_copy_%3%") % object->model_object()->name % object->get_id() % inst.id).str();
}
inline std::string get_instance_name(const PrintObject *object, size_t inst_id) {
return (boost::format("%1%_id_%2%_copy_%3%") % object->model_object()->name % object->get_id() % inst_id).str();
}
// In sequential mode, process_layer is called once per each object and its copy,
// therefore layers will contain a single entry and single_object_instance_idx will point to the copy of the object.
// In non-sequential mode, process_layer is called per each print_z height with all object and support layers accumulated.
@ -3172,7 +3178,7 @@ GCode::LayerResult GCode::process_layer(
if (is_anything_overridden && print_wipe_extrusions == 0)
gcode+="; PURGING FINISHED\n";
for (InstanceToPrint &instance_to_print : instances_to_print) {
const LayerToPrint &layer_to_print = layers[instance_to_print.layer_id];
const LayerToPrint &layer_to_print = layers[instance_to_print.get_object_id()];
// To control print speed of the 1st object layer printed over raft interface.
bool object_layer_over_raft = layer_to_print.object_layer && layer_to_print.object_layer->id() > 0 &&
instance_to_print.print_object.slicing_parameters().raft_layers() == layer_to_print.object_layer->id();
@ -3181,11 +3187,19 @@ GCode::LayerResult GCode::process_layer(
m_object_layer_over_raft = object_layer_over_raft;
if (m_config.reduce_crossing_wall)
m_avoid_crossing_perimeters.init_layer(*m_layer);
bool reset_e = false;
if (this->config().gcode_label_objects) {
gcode += std::string("; printing object ") + instance_to_print.print_object.model_object()->name + " id:" + std::to_string(instance_to_print.layer_id) + " copy " + std::to_string(instance_to_print.instance_id) + "\n";
if (!m_config.use_relative_e_distances)
gcode += m_writer.reset_e(true);
gcode += std::string("; printing object ") + instance_to_print.print_object.model_object()->name + " id:" + std::to_string(instance_to_print.print_object.get_id()) + " copy " + std::to_string(instance_to_print.instance_id) + "\n";
reset_e = true;
}
if (this->config().exclude_object && print.config().gcode_flavor.value == gcfKlipper) {
gcode += std::string("EXCLUDE_OBJECT_START NAME=") +
get_instance_name(&instance_to_print.print_object, instance_to_print.instance_id) + "\n";
reset_e = true;
}
// ref to: https://github.com/SoftFever/OrcaSlicer/pull/205/commits/7f1fe0bd544077626080aa1a9a0576aa735da1a4#r1083470162
if (reset_e && !m_config.use_relative_e_distances)
gcode += m_writer.reset_e(true);
m_extrusion_quality_estimator.set_current_object(&instance_to_print.print_object);
// When starting a new object, use the external motion planner for the first travel move.
@ -3196,7 +3210,7 @@ GCode::LayerResult GCode::process_layer(
m_last_obj_copy = this_object_copy;
this->set_origin(unscale(offset));
if (instance_to_print.object_by_extruder.support != nullptr) {
m_layer = layers[instance_to_print.layer_id].support_layer;
m_layer = layers[instance_to_print.get_object_id()].support_layer;
m_object_layer_over_raft = false;
//BBS: print supports' brims first
@ -3274,10 +3288,16 @@ GCode::LayerResult GCode::process_layer(
gcode += this->extrude_infill(print,by_region_specific, true);
}
if (this->config().gcode_label_objects) {
gcode += std::string("; stop printing object ") + instance_to_print.print_object.model_object()->name + " id:" + std::to_string(instance_to_print.layer_id) + " copy " + std::to_string(instance_to_print.instance_id) + "\n";
if (!m_config.use_relative_e_distances)
gcode += m_writer.reset_e(true);
gcode += std::string("; stop printing object ") + instance_to_print.print_object.model_object()->name + " id:" + std::to_string(instance_to_print.print_object.get_id()) + " copy " + std::to_string(instance_to_print.instance_id) + "\n";
reset_e = true;
}
if (this->config().exclude_object && print.config().gcode_flavor.value == gcfKlipper) {
gcode += std::string("EXCLUDE_OBJECT_END NAME=") +
get_instance_name(&instance_to_print.print_object, instance_to_print.instance_id) + "\n";
reset_e = true;
}
if (reset_e && !m_config.use_relative_e_distances)
gcode += m_writer.reset_e(true);
}
}
}
@ -4591,6 +4611,37 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
return gcode;
}
inline std::string polygon_to_string(const Polygon &polygon) {
std::ostringstream gcode;
gcode << "[";
for (const Point &p : polygon.points) {
gcode << "[" << unscaled(p.x()) << "," << unscaled(p.y()) << "],";
}
gcode << "[" << unscaled(polygon.points.front().x()) << "," << unscaled(polygon.points.front().y()) << "]";
gcode << "]";
return gcode.str();
}
// this function iterator PrintObject and assign a seqential id to each object.
// this id is used to generate unique object id for each object.
std::string GCode::set_object_info(Print* print) {
std::ostringstream gcode;
size_t object_id = 0;
for (PrintObject* object : print->objects()) {
object->set_id(object_id++);
size_t inst_id = 0;
for (PrintInstance &inst : object->instances()) {
inst.id = inst_id;
if (this->config().exclude_object && print->config().gcode_flavor.value == gcfKlipper) {
auto bbox = inst.get_bounding_box();
gcode << "EXCLUDE_OBJECT_DEFINE NAME=" << get_instance_name(object, inst)
<< " CENTER=" << bbox.center().x() << "," << bbox.center().y()
<< " POLYGON=" << polygon_to_string(inst.get_convex_hull_2d()) << "\n";
}
}
}
return gcode.str();
}
// convert a model-space scaled point into G-code coordinates
Vec2d GCode::point_to_gcode(const Point &point) const
{
@ -4714,4 +4765,10 @@ void GCode::ObjectByExtruder::Island::Region::append(const Type type, const Extr
}
}
// Index into std::vector<LayerToPrint>, which contains Object and Support layers for the current print_z, collected for
// a single object, or for possibly multiple objects with multiple instances.
inline size_t GCode::InstanceToPrint::get_object_id() const { return print_object.get_id(); }
} // namespace Slic3r

View file

@ -202,6 +202,9 @@ public:
std::string unretract() { return m_writer.unlift() + m_writer.unretract(); }
std::string set_extruder(unsigned int extruder_id, double print_z);
// SoftFever
std::string set_object_info(Print* print);
// append full config to the given string
static void append_full_config(const Print& print, std::string& str);
@ -377,13 +380,13 @@ private:
struct InstanceToPrint
{
InstanceToPrint(ObjectByExtruder &object_by_extruder, size_t layer_id, const PrintObject &print_object, size_t instance_id) :
object_by_extruder(object_by_extruder), layer_id(layer_id), print_object(print_object), instance_id(instance_id) {}
InstanceToPrint(ObjectByExtruder &object_by_extruder, const PrintObject &print_object, size_t instance_id) :
object_by_extruder(object_by_extruder), print_object(print_object), instance_id(instance_id) {}
// Repository
ObjectByExtruder &object_by_extruder;
// Index into std::vector<LayerToPrint>, which contains Object and Support layers for the current print_z, collected for a single object, or for possibly multiple objects with multiple instances.
const size_t layer_id;
size_t get_object_id() const;
const PrintObject &print_object;
// Instance idx of the copy of a print object.
const size_t instance_id;

View file

@ -1286,18 +1286,21 @@ const BoundingBoxf3& ModelObject::raw_bounding_box() const
}
// This returns an accurate snug bounding box of the transformed object instance, without the translation applied.
BoundingBoxf3 ModelObject::instance_bounding_box(size_t instance_idx, bool dont_translate) const
{
BoundingBoxf3 bb;
const Transform3d& inst_matrix = this->instances[instance_idx]->get_transformation().get_matrix(dont_translate);
for (ModelVolume *v : this->volumes)
{
if (v->is_model_part())
bb.merge(v->mesh().transformed_bounding_box(inst_matrix * v->get_matrix()));
}
return bb;
BoundingBoxf3 ModelObject::instance_bounding_box(size_t instance_idx, bool dont_translate) const {
return instance_bounding_box(*this->instances[instance_idx], dont_translate);
}
BoundingBoxf3 ModelObject::instance_bounding_box(const ModelInstance &instance, bool dont_translate) const {
BoundingBoxf3 bbox;
const auto& inst_mat = instance.get_transformation().get_matrix(dont_translate);
for (auto vol : this->volumes) {
if (vol->is_model_part())
bbox.merge(vol->mesh().transformed_bounding_box(inst_mat * vol->get_matrix()));
}
return bbox;
}
//BBS: add convex bounding box
BoundingBoxf3 ModelObject::instance_convex_hull_bounding_box(size_t instance_idx, bool dont_translate) const
{

View file

@ -345,6 +345,8 @@ public:
const BoundingBoxf3& raw_bounding_box() const;
// A snug bounding box around the transformed non-modifier object volumes.
BoundingBoxf3 instance_bounding_box(size_t instance_idx, bool dont_translate = false) const;
BoundingBoxf3 instance_bounding_box(const ModelInstance& instance, bool dont_translate = false) const;
// A snug bounding box of non-transformed (non-rotated, non-scaled, non-translated) sum of non-modifier object volumes.
const BoundingBoxf3& raw_mesh_bounding_box() const;
// A snug bounding box of non-transformed (non-rotated, non-scaled, non-translated) sum of all object volumes.

View file

@ -755,7 +755,8 @@ static std::vector<std::string> s_Preset_print_options {
"role_based_wipe_speed", "wipe_speed", "accel_to_decel_enable", "accel_to_decel_factor", "wipe_on_loops",
"bridge_density", "precise_outer_wall", "overhang_speed_classic", "bridge_acceleration",
"sparse_infill_acceleration", "internal_solid_infill_acceleration", "tree_support_adaptive_layer_height", "tree_support_auto_brim",
"tree_support_brim_width", "gcode_comments", "gcode_label_objects", "initial_layer_travel_speed"
"tree_support_brim_width", "gcode_comments", "gcode_label_objects",
"initial_layer_travel_speed", "exclude_object"
};

View file

@ -159,7 +159,8 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
"accel_to_decel_factor",
"wipe_on_loops",
"gcode_comments",
"gcode_label_objects"
"gcode_label_objects",
"exclude_object"
};
static std::unordered_set<std::string> steps_ignore;
@ -3329,4 +3330,14 @@ int Print::load_cached_data(const std::string& directory)
return ret;
}
BoundingBoxf3 PrintInstance::get_bounding_box() {
return print_object->model_object()->instance_bounding_box(*model_instance, false);
}
Polygon PrintInstance::get_convex_hull_2d() {
Polygon poly = print_object->model_object()->convex_hull_2d(model_instance->get_matrix());
poly.douglas_peucker(0.1);
return poly;
}
} // namespace Slic3r

View file

@ -191,6 +191,13 @@ struct PrintInstance
const ModelInstance *model_instance;
// Shift of this instance's center into the world coordinates.
Point shift;
BoundingBoxf3 get_bounding_box();
Polygon get_convex_hull_2d();
// SoftFever
//
// instance id
size_t id;
};
typedef std::vector<PrintInstance> PrintInstances;
@ -292,6 +299,7 @@ public:
Transform3d trafo_centered() const
{ Transform3d t = this->trafo(); t.pretranslate(Vec3d(- unscale<double>(m_center_offset.x()), - unscale<double>(m_center_offset.y()), 0)); return t; }
const PrintInstances& instances() const { return m_instances; }
PrintInstances &instances() { return m_instances; }
// Whoever will get a non-const pointer to PrintObject will be able to modify its layers.
LayerPtrs& layers() { return m_layers; }
@ -417,7 +425,12 @@ public:
// BBS: Boundingbox of the first layer
BoundingBox firstLayerObjectBrimBoundingBox;
private:
// SoftFever
size_t get_id() const { return m_id; }
void set_id(size_t id) { m_id = id; }
private:
// to be called from Print only.
friend class Print;
@ -501,6 +514,12 @@ private:
PrintObject* m_shared_object{ nullptr };
// SoftFever
//
// object id
size_t m_id;
public:
//BBS: When printing multi-material objects, this settings will make slicer to clip the overlapping object parts one by the other.
//(2nd part will be clipped by the 1st, 3rd part will be clipped by the 1st and 2nd etc).

View file

@ -1814,6 +1814,12 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(1));
def = this->add("exclude_object", coBool);
def->label = L("Exclude objects");
def->tooltip = L("Enable this option to add EXCLUDE OBJECT command in g-code");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(1));
def = this->add("gcode_comments", coBool);
def->label = L("Verbose G-code");
def->tooltip = L("Enable this to get a commented G-code file, with each line explained by a descriptive text. "

View file

@ -1003,6 +1003,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
// SoftFever
((ConfigOptionPercents, filament_shrink))
((ConfigOptionBool, gcode_label_objects))
((ConfigOptionBool, exclude_object))
((ConfigOptionBool, gcode_comments))
)

View file

@ -697,6 +697,9 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
toggle_line(el, gcflavor == gcfKlipper);
if(gcflavor == gcfKlipper)
toggle_field("accel_to_decel_factor", config->opt_bool("accel_to_decel_enable"));
toggle_field("exclude_object", gcflavor == gcfKlipper);
}
void ConfigManipulation::update_print_sla_config(DynamicPrintConfig* config, const bool is_global_config/* = false*/)

View file

@ -2058,6 +2058,7 @@ void TabPrint::build()
optgroup->append_single_option_line("gcode_add_line_number");
optgroup->append_single_option_line("gcode_comments");
optgroup->append_single_option_line("gcode_label_objects");
optgroup->append_single_option_line("exclude_object");
Option option = optgroup->get_option("filename_format");
// option.opt.full_width = true;
option.opt.is_code = true;