diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 7979642d4b..14e5331c7c 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1586,6 +1586,11 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato #endif file.write_format("; EXECUTABLE_BLOCK_START\n"); + + // SoftFever: Orca's implementation for skipping object, for klipper firmware printer only + if (this->config().exclude_object && print.config().gcode_flavor.value == gcfKlipper) + 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()); @@ -2656,6 +2661,18 @@ namespace Skirt { } // namespace Skirt +inline std::string get_instance_name(const PrintObject* object, size_t inst_id) { + auto obj_name = object->model_object()->name; + // replace space in obj_name with '-' + std::replace(obj_name.begin(), obj_name.end(), ' ', '_'); + + return (boost::format("%1%_id_%2%_copy_%3%") % obj_name % object->get_klipper_object_id() % inst_id).str(); +} + +inline std::string get_instance_name(const PrintObject* object, const PrintInstance& inst) { + return get_instance_name(object, inst.id); +} + // 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. @@ -3156,6 +3173,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 auto& inst = instance_to_print.print_object.instances()[instance_to_print.instance_id]; const LayerToPrint &layer_to_print = layers[instance_to_print.layer_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 && @@ -3173,6 +3191,16 @@ GCode::LayerResult GCode::process_layer( } m_writer.set_object_start_str(start_str); } + //Orca's implementation for skipping object, for klipper firmware printer only + bool reset_e = false; + 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, inst.id) + "\n"; + reset_e = true; + } + if (reset_e && !RELATIVE_E_AXIS) + gcode += m_writer.reset_e(true); + // When starting a new object, use the external motion planner for the first travel move. const Point &offset = instance_to_print.print_object.instances()[instance_to_print.instance_id].shift; std::pair this_object_copy(&instance_to_print.print_object, offset); @@ -3267,7 +3295,14 @@ GCode::LayerResult GCode::process_layer( end_str += "M625\n"; m_writer.set_object_end_str(end_str); } - + //Orca's implementation for skipping object, for klipper firmware printer only + 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, inst.id) + "\n"; + reset_e = true; + } + if (reset_e && !RELATIVE_E_AXIS) + gcode += m_writer.reset_e(true); } } } @@ -4553,6 +4588,41 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z) return gcode; } +inline std::string polygon_to_string(const Polygon& polygon, Print* print) { + std::ostringstream gcode; + gcode << "["; + for (const Point& p : polygon.points) { + const auto v = print->translate_to_print_space(p); + gcode << "[" << v.x() << "," << v.y() << "],"; + } + const auto first_v = print->translate_to_print_space(polygon.points.front()); + gcode << "[" << first_v.x() << "," << first_v.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_klipper_object_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(); + auto center = print->translate_to_print_space(Vec2d(bbox.center().x(), bbox.center().y())); + gcode << "EXCLUDE_OBJECT_DEFINE NAME=" << get_instance_name(object, inst) << " CENTER=" << center.x() + << "," << center.y() << " POLYGON=" << polygon_to_string(inst.get_convex_hull_2d(), print) + << "\n"; + } + } + } + return gcode.str(); +} + // convert a model-space scaled point into G-code coordinates Vec2d GCode::point_to_gcode(const Point &point) const { diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index ab469f24ef..aee08ccf92 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -195,6 +195,9 @@ public: void set_layer_count(unsigned int value) { m_layer_count = value; } void apply_print_config(const PrintConfig &print_config); + // 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); diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 027d848260..6c51c0d10b 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1384,6 +1384,16 @@ BoundingBoxf3 ModelObject::instance_bounding_box(size_t instance_idx, bool dont_ return bb; } +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 { diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index a0a1a6582b..688f78991b 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -423,6 +423,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. diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 0fa6c49f74..eec56d3c40 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -785,7 +785,9 @@ static std::vector s_Preset_print_options { "default_jerk", "outer_wall_jerk", "inner_wall_jerk", "infill_jerk", "top_surface_jerk", "initial_layer_jerk", "travel_jerk", "filter_out_gap_fill", // calib - "print_flow_ratio" + "print_flow_ratio", + //Orca + "exclude_object" }; static std::vector s_Preset_filament_options { diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index deec3d9815..aff6c8ce0a 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -160,7 +160,8 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n "initial_layer_jerk", "travel_jerk", "inner_wall_acceleration", - "sparse_infill_acceleration" + "sparse_infill_acceleration", + "exclude_object", }; static std::unordered_set steps_ignore; @@ -2004,6 +2005,16 @@ std::vector Print::first_layer_wipe_tower_corners(bool check_wipe_tower_e return corners; } +//SoftFever +Vec2d Print::translate_to_print_space(const Vec2d& point) const { + //const BoundingBoxf bed_bbox(config().printable_area.values); + return Vec2d(point(0) - m_origin(0), point(1) - m_origin(1)); +} + +Vec2d Print::translate_to_print_space(const Point& point) const { + return Vec2d(unscaled(point.x()) - m_origin(0), unscaled(point.y()) - m_origin(1)); +} + void Print::finalize_first_layer_convex_hull() { append(m_first_layer_convex_hull.points, m_skirt_convex_hull); @@ -3495,4 +3506,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 diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 9a28718a3e..b3371541b4 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -194,6 +194,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 PrintInstances; @@ -295,6 +302,7 @@ public: Transform3d trafo_centered() const { Transform3d t = this->trafo(); t.pretranslate(Vec3d(- unscale(m_center_offset.x()), - unscale(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; } @@ -420,6 +428,11 @@ public: // BBS: Boundingbox of the first layer BoundingBox firstLayerObjectBrimBoundingBox; + + // SoftFever + size_t get_klipper_object_id() const { return m_klipper_object_id; } + void set_klipper_object_id(size_t id) { m_klipper_object_id = id; } + private: // to be called from Print only. friend class Print; @@ -504,6 +517,11 @@ private: PrintObject* m_shared_object{ nullptr }; + // SoftFever + // + // object id for klipper firmware only + size_t m_klipper_object_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). @@ -789,11 +807,14 @@ public: // Return 4 wipe tower corners in the world coordinates (shifted and rotated), including the wipe tower brim. std::vector first_layer_wipe_tower_corners(bool check_wipe_tower_existance=true) const; - + //SoftFever CalibMode & calib_mode() { return m_calib_params.mode; } const CalibMode& calib_mode() const { return m_calib_params.mode; } void set_calib_params(const Calib_Params ¶ms); const Calib_Params& calib_params() const { return m_calib_params; } + Vec2d translate_to_print_space(const Vec2d& point) const; + // scaled point + Vec2d translate_to_print_space(const Point& point) const; protected: // Invalidates the step, and its depending steps in Print. diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 54d424de5c..2a2b7808bc 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1704,6 +1704,13 @@ void PrintConfigDef::init_fff_params() def->readonly = false; def->set_default_value(new ConfigOptionEnum(gcfMarlinLegacy)); + //OrcaSlicer + 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 for klipper firmware printer"); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(1)); + //BBS def = this->add("infill_combination", coBool); def->label = L("Infill combination"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index ece226c4de..1539b38bf0 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -976,7 +976,8 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( ((ConfigOptionFloat, travel_jerk)) // BBS: move from PrintObjectConfig - ((ConfigOptionBool, independent_support_layer_height)) + ((ConfigOptionBool, independent_support_layer_height)) + ((ConfigOptionBool, exclude_object)) ) // This object is mapped to Perl as Slic3r::Config::Full. diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index e604797334..68a2d8e58c 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -703,6 +703,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co toggle_field("accel_to_decel_factor", config->opt_bool("accel_to_decel_enable")); } + toggle_line("exclude_object", gcflavor == gcfKlipper); } void ConfigManipulation::update_print_sla_config(DynamicPrintConfig* config, const bool is_global_config/* = false*/) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 1c809ada15..199a2fd235 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2050,6 +2050,7 @@ void TabPrint::build() optgroup = page->new_optgroup(L("G-code output"), L"param_gcode"); optgroup->append_single_option_line("reduce_infill_retraction"); optgroup->append_single_option_line("gcode_add_line_number"); + optgroup->append_single_option_line("exclude_object"); Option option = optgroup->get_option("filename_format"); option.opt.full_width = true; optgroup->append_single_option_line(option); @@ -3627,6 +3628,8 @@ void TabPrinter::toggle_options() //} if (m_active_page->title() == "Basic information") { toggle_option("single_extruder_multi_material", have_multiple_extruders); + //BBS: gcode_flavore of BBL printer can't be edited and changed + toggle_option("gcode_flavor", !is_BBL_printer); auto flavor = m_config->option>("gcode_flavor")->value; bool is_marlin_flavor = flavor == gcfMarlinLegacy || flavor == gcfMarlinFirmware;