mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-11-02 20:51:23 -07:00 
			
		
		
		
	ENH: support exclude objects for klipper printer
Thanks OrcaSlicer. This is just function for klipper printer. NEVER used for BBL printer. Signed-off-by: salt.wei <salt.wei@bambulab.com> Change-Id: I910abceb67f4dcb4260f74f5dd1b4fb614812670
This commit is contained in:
		
							parent
							
								
									0daca9d329
								
							
						
					
					
						commit
						e567afdcb5
					
				
					 11 changed files with 146 additions and 5 deletions
				
			
		| 
						 | 
				
			
			@ -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<const PrintObject*, Point> 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
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -785,7 +785,9 @@ static std::vector<std::string> 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<std::string> s_Preset_filament_options {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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<std::string> steps_ignore;
 | 
			
		||||
| 
						 | 
				
			
			@ -2004,6 +2005,16 @@ std::vector<Point> 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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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<PrintInstance> PrintInstances;
 | 
			
		||||
| 
						 | 
				
			
			@ -295,6 +302,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; }
 | 
			
		||||
| 
						 | 
				
			
			@ -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<Point>  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.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1704,6 +1704,13 @@ void PrintConfigDef::init_fff_params()
 | 
			
		|||
    def->readonly = false;
 | 
			
		||||
    def->set_default_value(new ConfigOptionEnum<GCodeFlavor>(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");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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*/)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor")->value;
 | 
			
		||||
        bool is_marlin_flavor = flavor == gcfMarlinLegacy || flavor == gcfMarlinFirmware;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue