From 28d2227c7bfe1d9c3da1959bfb8d05bd8c520a54 Mon Sep 17 00:00:00 2001 From: "salt.wei" Date: Fri, 19 May 2023 21:21:47 +0800 Subject: [PATCH] ENH: support skiping object when export gcode Enable label object when does not print with multi filament and object number is smaller than 65 Signed-off-by: salt.wei Change-Id: Id670c6a5258f266076bc0a52c50ab5a28386f242 (cherry picked from commit 40248347908788ce6303ed255826011127d8eaa3) --- src/libslic3r/GCode.cpp | 118 +++++++++++++++++++++++++++++----- src/libslic3r/GCode.hpp | 14 ++-- src/libslic3r/GCodeWriter.cpp | 52 +++++++++++---- src/libslic3r/GCodeWriter.hpp | 13 +++- 4 files changed, 163 insertions(+), 34 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 5c4aaa69c..426eeee34 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -78,8 +78,7 @@ namespace Slic3r { static const float g_min_purge_volume = 100.f; static const float g_purge_volume_one_time = 135.f; static const int g_max_flush_count = 4; - -bool GCode::gcode_label_objects = false; +static const size_t g_max_label_object = 64; Vec2d travel_point_1; Vec2d travel_point_2; @@ -411,6 +410,9 @@ static std::vector get_path_of_change_filament(const Print& print) gcode += gcodegen.unretract(); } + //BBS: if needed, write the gcode_label_objects_end then priming tower, if the retract, didn't did it. + gcodegen.m_writer.add_object_end_labels(gcode); + double current_z = gcodegen.writer().get_position().z(); if (z == -1.) // in case no specific z was provided, print at current_z pos z = current_z; @@ -1505,6 +1507,27 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Estimated_Printing_Time_Placeholder).c_str()); //BBS: total layer number file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Total_Layer_Number_Placeholder).c_str()); + //BBS: judge whether support skipping, if yes, list all label_object_id with sorted order here + if (print.extruders(true).size() == 1 && //Don't support multi-color + print.num_object_instances() <= g_max_label_object) { //Don't support too many objects on one plate + m_enable_label_object = true; + m_label_objects_ids.clear(); + m_label_objects_ids.reserve(print.num_object_instances()); + for (const PrintObject* print_object : print.objects()) + for (const PrintInstance& print_instance : print_object->instances()) + m_label_objects_ids.push_back(print_instance.model_instance->id().id); + std::sort(m_label_objects_ids.begin(), m_label_objects_ids.end()); + + std::string objects_id_list = "; model label id: "; + for (size_t id : m_label_objects_ids) + objects_id_list += (std::to_string(id) + (id != m_label_objects_ids.back() ? "," : "\n")); + file.writeln(objects_id_list); + } + else { + m_enable_label_object = false; + m_label_objects_ids.clear(); + } + file.write_format("; HEADER_BLOCK_END\n\n"); //BBS: write global config at the beginning of gcode file because printer need these config information @@ -1981,6 +2004,14 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato //BBS: the last retraction // Write end commands to file. file.write(this->retract(false, true)); + + // if needed, write the gcode_label_objects_end + { + std::string gcode; + m_writer.add_object_change_labels(gcode); + file.write(gcode); + } + file.write(m_writer.set_fan(0)); //BBS: make sure the additional fan is closed when end file.write(m_writer.set_additional_fan(0)); @@ -2388,7 +2419,7 @@ std::vector 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, layer_id, *print_object, single_object_instance_idx, print_object->instances()[single_object_instance_idx].model_instance->id().id); } } else { // Create mapping from PrintObject* to ObjectByExtruder*. @@ -2416,7 +2447,7 @@ std::vector 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, it->second - objects_by_extruder.data(), print_object, instance - print_object.instances().data(), instance->model_instance->id().id); } } } @@ -2692,7 +2723,7 @@ GCode::LayerResult GCode::process_layer( } // BBS: don't use lazy_raise when enable spiral vase - gcode += this->change_layer(print_z, !m_spiral_vase); // this will increase m_layer_index + gcode += this->change_layer(print_z); // this will increase m_layer_index m_layer = &layer; m_object_layer_over_raft = false; if (! print.config().layer_change_gcode.value.empty()) { @@ -3077,8 +3108,14 @@ 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); - if (GCode::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_enable_label_object) { + std::string start_str = std::string("; start printing object, unique label id: ") + std::to_string(instance_to_print.label_object_id) + "\n"; + if (print.is_BBL_Printer()) { + start_str += ("M624 " + _encode_label_ids_to_base64({ instance_to_print.label_object_id })); + start_str += "\n"; + } + m_writer.set_object_start_str(start_str); + } // 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); @@ -3164,8 +3201,16 @@ GCode::LayerResult GCode::process_layer( // ironing gcode += this->extrude_infill(print,by_region_specific, true); } - if (GCode::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"; + // Don't set m_gcode_label_objects_end if you don't had to write the m_gcode_label_objects_start. + if (!m_writer.empty_object_start_str()) { + m_writer.set_object_start_str(""); + } else if (m_enable_label_object) { + std::string end_str = std::string("; stop printing object, unique label id: ") + std::to_string(instance_to_print.label_object_id) + "\n"; + if (print.is_BBL_Printer()) + end_str += "M625\n"; + m_writer.set_object_end_str(end_str); + } + } } } @@ -3268,7 +3313,7 @@ std::string GCode::preamble() } // called by GCode::process_layer() -std::string GCode::change_layer(coordf_t print_z, bool lazy_raise) +std::string GCode::change_layer(coordf_t print_z) { std::string gcode; if (m_layer_count > 0) @@ -3283,16 +3328,19 @@ std::string GCode::change_layer(coordf_t print_z, bool lazy_raise) gcode += this->retract(false, false, ZHopType(EXTRUDER_CONFIG(z_hop_types)) == ZHopType::zhtAuto ? LiftType::SpiralLift : lift_type); } - if (!lazy_raise) { + m_writer.add_object_change_labels(gcode); + + if (m_spiral_vase) { + //BBS: force to normal lift immediately in spiral vase mode std::ostringstream comment; comment << "move to next layer (" << m_layer_index << ")"; gcode += m_writer.travel_to_z(z, comment.str()); - } else { + } + else { //BBS: set m_need_change_layer_lift_z to be true so that z lift can be done in travel_to() function m_need_change_layer_lift_z = true; } - // BBS m_nominal_z = print_z; // forget last wiping path as wiping after raising Z is pointless @@ -3667,6 +3715,10 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, m_need_change_layer_lift_z = false; } + // if needed, write the gcode_label_objects_end then gcode_label_objects_start + // should be already done by travel_to, but just in case + m_writer.add_object_change_labels(gcode); + // compensate retraction gcode += this->unretract(); m_config.apply(m_calib_config); @@ -3921,6 +3973,37 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, return gcode; } +std::string encodeBase64(uint64_t value) +{ + //Always use big endian mode + uint8_t src[8]; + for (size_t i = 0; i < 8; i++) + src[i] = (value >> (8 * i)) & 0xff; + + std::string dest; + dest.resize(boost::beast::detail::base64::encoded_size(sizeof(src))); + dest.resize(boost::beast::detail::base64::encode(&dest[0], src, sizeof(src))); + return dest; +} + +std::string GCode::_encode_label_ids_to_base64(std::vector ids) +{ + assert(m_label_objects_ids.size() < 64); + + uint64_t bitset = 0; + for (size_t id : ids) { + auto index = std::lower_bound(m_label_objects_ids.begin(), m_label_objects_ids.end(), id); + if (index != m_label_objects_ids.end() && *index == id) + bitset |= (1ull << (index - m_label_objects_ids.begin())); + else + throw Slic3r::LogicError("Unknown label object id!"); + } + if (bitset == 0) + throw Slic3r::LogicError("Label object id error!"); + + return encodeBase64(bitset); +} + // This method accepts &point in print coordinates. std::string GCode::travel_to(const Point &point, ExtrusionRole role, std::string comment) { @@ -3977,6 +4060,9 @@ std::string GCode::travel_to(const Point &point, ExtrusionRole role, std::string // Reset the wipe path when traveling, so one would not wipe along an old path. m_wipe.reset_path(); + // if needed, write the gcode_label_objects_end then gcode_label_objects_start + m_writer.add_object_change_labels(gcode); + // use G1 because we rely on paths being straight (G0 may make round paths) if (travel.size() >= 2) { for (size_t i = 1; i < travel.size(); ++ i) { @@ -3992,6 +4078,7 @@ std::string GCode::travel_to(const Point &point, ExtrusionRole role, std::string } this->set_last_pos(travel.points.back()); } + return gcode; } @@ -4147,9 +4234,8 @@ std::string GCode::retract(bool toolchange, bool is_last_retraction, LiftType li gcode += m_writer.reset_e(); //BBS if (m_writer.extruder()->retraction_length() > 0) { - // BBS: don't do lazy_lift when enable spiral vase - size_t extruder_id = m_writer.extruder()->id(); - gcode += m_writer.lift(!m_spiral_vase ? lift_type : LiftType::NormalLift); + // BBS: force to use normal lift for spiral vase mode + gcode += m_writer.lift(lift_type, m_spiral_vase != nullptr); } return gcode; diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index b93ba5e62..10beff9dc 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -322,7 +322,7 @@ private: void set_extruders(const std::vector &extruder_ids); std::string preamble(); // BBS - std::string change_layer(coordf_t print_z, bool lazy_raise = false); + std::string change_layer(coordf_t print_z); std::string extrude_entity(const ExtrusionEntity &entity, std::string description = "", double speed = -1.); std::string extrude_loop(ExtrusionLoop loop, std::string description, double speed = -1.); std::string extrude_multi_path(ExtrusionMultiPath multipath, std::string description = "", double speed = -1.); @@ -370,8 +370,8 @@ 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, size_t layer_id, const PrintObject &print_object, size_t instance_id, size_t label_object_id) : + object_by_extruder(object_by_extruder), layer_id(layer_id), print_object(print_object), instance_id(instance_id), label_object_id(label_object_id) {} // Repository ObjectByExtruder &object_by_extruder; @@ -380,6 +380,8 @@ private: const PrintObject &print_object; // Instance idx of the copy of a print object. const size_t instance_id; + //BBS: Unique id to label object to support skiping during printing + const size_t label_object_id; }; std::vector sort_print_object_instances( @@ -476,6 +478,10 @@ private: bool m_second_layer_things_done; // Index of a last object copy extruded. std::pair m_last_obj_copy; + //BBS + bool m_enable_label_object; + std::vector m_label_objects_ids; + std::string _encode_label_ids_to_base64(std::vector ids); bool m_silent_time_estimator_enabled; @@ -489,8 +495,6 @@ private: bool m_need_change_layer_lift_z = false; int m_start_gcode_filament = -1; - static bool gcode_label_objects; - // BBS int get_bed_temperature(const int extruder_id, const bool is_first_layer, const BedType bed_type) const; diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index 04af9f01f..a4b574265 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -314,17 +314,19 @@ std::string GCodeWriter::travel_to_xyz(const Vec3d &point, const std::string &co Vec2d delta_no_z = { delta(0), delta(1) }; //BBS: don'need slope travel because we don't know where is the source position the first time //BBS: Also don't need to do slope move or spiral lift if x-y distance is absolute zero - if (this->is_current_position_clear() && delta(2) > 0 && delta_no_z.norm() != 0.0f) { - double radius = delta(2) / (2 * PI * atan(GCodeWriter::slope_threshold)); - Vec2d ij_offset = radius * delta_no_z.normalized(); - ij_offset = { -ij_offset(1), ij_offset(0) }; + if (delta(2) > 0 && delta_no_z.norm() != 0.0f) { //BBS: SpiralLift - if (m_to_lift_type == LiftType::SpiralLift) { + if (m_to_lift_type == LiftType::SpiralLift && this->is_current_position_clear()) { //BBS: todo: check the arc move all in bed area, if not, then use lazy lift + double radius = delta(2) / (2 * PI * atan(GCodeWriter::slope_threshold)); + Vec2d ij_offset = radius * delta_no_z.normalized(); + ij_offset = { -ij_offset(1), ij_offset(0) }; slop_move = this->_spiral_travel_to_z(target(2), ij_offset, "spiral lift Z"); } //BBS: LazyLift - else if (atan2(delta(2), delta_no_z.norm()) < GCodeWriter::slope_threshold) { + else if (m_to_lift_type == LiftType::LazyLift && + this->is_current_position_clear() && + atan2(delta(2), delta_no_z.norm()) < GCodeWriter::slope_threshold) { //BBS: check whether we can make a travel like // _____ // / to make the z list early to avoid to hit some warping place when travel is long. @@ -334,9 +336,12 @@ std::string GCodeWriter::travel_to_xyz(const Vec3d &point, const std::string &co w0.emit_xyz(slope_top_point); w0.emit_f(this->config.travel_speed.value * 60.0); //BBS - w0.emit_comment(GCodeWriter::full_gcode_comment, comment); + w0.emit_comment(GCodeWriter::full_gcode_comment, "slope lift Z"); slop_move = w0.string(); } + else if (m_to_lift_type == LiftType::NormalLift) { + slop_move = _travel_to_z(target.z(), "normal lift Z"); + } } std::string xy_z_move; @@ -595,7 +600,7 @@ std::string GCodeWriter::unretract() /* If this method is called more than once before calling unlift(), it will not perform subsequent lifts, even if Z was raised manually (i.e. with travel_to_z()) and thus _lifted was reduced. */ -std::string GCodeWriter::lift(LiftType lift_type) +std::string GCodeWriter::lift(LiftType lift_type, bool spiral_vase) { // check whether the above/below conditions are met double target_lift = 0; @@ -605,13 +610,14 @@ std::string GCodeWriter::lift(LiftType lift_type) } // BBS if (m_lifted == 0 && m_to_lift == 0 && target_lift > 0) { - if (lift_type == LiftType::LazyLift || lift_type == LiftType::SpiralLift) { - m_to_lift = target_lift; - m_to_lift_type = lift_type; - } else { + if (spiral_vase) { m_lifted = target_lift; return this->_travel_to_z(m_pos(2) + target_lift, "lift Z"); } + else { + m_to_lift = target_lift; + m_to_lift_type = lift_type; + } } return ""; } @@ -683,6 +689,28 @@ std::string GCodeWriter::set_additional_fan(unsigned int speed) return gcode.str(); } +void GCodeWriter::add_object_start_labels(std::string& gcode) +{ + if (!m_gcode_label_objects_start.empty()) { + gcode += m_gcode_label_objects_start; + m_gcode_label_objects_start = ""; + } +} + +void GCodeWriter::add_object_end_labels(std::string& gcode) +{ + if (!m_gcode_label_objects_end.empty()) { + gcode += m_gcode_label_objects_end; + m_gcode_label_objects_end = ""; + } +} + +void GCodeWriter::add_object_change_labels(std::string& gcode) +{ + add_object_end_labels(gcode); + add_object_start_labels(gcode); +} + void GCodeFormatter::emit_axis(const char axis, const double v, size_t digits) { assert(digits <= 9); static constexpr const std::array pow_10{1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp index e12ae705a..0a0cd2ecf 100644 --- a/src/libslic3r/GCodeWriter.hpp +++ b/src/libslic3r/GCodeWriter.hpp @@ -73,7 +73,7 @@ public: std::string retract(bool before_wipe = false); std::string retract_for_toolchange(bool before_wipe = false); std::string unretract(); - std::string lift(LiftType lift_type = LiftType::NormalLift); + std::string lift(LiftType lift_type = LiftType::NormalLift, bool spiral_vase = false); std::string unlift(); Vec3d get_position() const { return m_pos; } void set_position(Vec3d& in) { m_pos = in; } @@ -88,6 +88,14 @@ public: std::string set_fan(unsigned int speed) const; //BBS: set additional fan speed for BBS machine only static std::string set_additional_fan(unsigned int speed); + //BBS + void set_object_start_str(std::string start_string) { m_gcode_label_objects_start = start_string; } + bool empty_object_start_str() { return m_gcode_label_objects_start.empty(); } + void set_object_end_str(std::string end_string) { m_gcode_label_objects_end = end_string; } + bool empty_object_end_str() { return m_gcode_label_objects_end.empty(); } + void add_object_start_labels(std::string& gcode); + void add_object_end_labels(std::string& gcode); + void add_object_change_labels(std::string& gcode); //BBS: void set_current_position_clear(bool clear) { m_is_current_pos_clear = clear; }; @@ -124,6 +132,9 @@ private: double m_x_offset{ 0 }; double m_y_offset{ 0 }; + std::string m_gcode_label_objects_start; + std::string m_gcode_label_objects_end; + std::string _travel_to_z(double z, const std::string &comment); std::string _spiral_travel_to_z(double z, const Vec2d &ij_offset, const std::string &comment); std::string _retract(double length, double restart_extra, const std::string &comment);