878 lines
34 KiB
C++
878 lines
34 KiB
C++
|
#ifndef __part_plate_hpp_
|
||
|
#define __part_plate_hpp_
|
||
|
|
||
|
#include <vector>
|
||
|
#include <set>
|
||
|
#include <array>
|
||
|
#include <thread>
|
||
|
#include <mutex>
|
||
|
|
||
|
#include "libslic3r/ObjectID.hpp"
|
||
|
#include "libslic3r/GCode/GCodeProcessor.hpp"
|
||
|
#include "libslic3r/Format/bbs_3mf.hpp"
|
||
|
#include "libslic3r/Slicing.hpp"
|
||
|
#include "libslic3r/Arrange.hpp"
|
||
|
#include "Plater.hpp"
|
||
|
#include "libslic3r/Model.hpp"
|
||
|
#include "libslic3r/Print.hpp"
|
||
|
#include "libslic3r/PrintConfig.hpp"
|
||
|
#include "GLCanvas3D.hpp"
|
||
|
#include "GLTexture.hpp"
|
||
|
#include "3DScene.hpp"
|
||
|
#include "GLModel.hpp"
|
||
|
#include "3DBed.hpp"
|
||
|
#include "libslic3r/ParameterUtils.hpp"
|
||
|
|
||
|
class GLUquadric;
|
||
|
typedef class GLUquadric GLUquadricObject;
|
||
|
|
||
|
|
||
|
// use PLATE_CURRENT_IDX stands for using current plate
|
||
|
// and use PLATE_ALL_IDX
|
||
|
#define PLATE_CURRENT_IDX -1
|
||
|
#define PLATE_ALL_IDX -2
|
||
|
|
||
|
#define MAX_PLATE_COUNT 36
|
||
|
|
||
|
inline int compute_colum_count(int count)
|
||
|
{
|
||
|
float value = sqrt((float)count);
|
||
|
float round_value = round(value);
|
||
|
int cols;
|
||
|
|
||
|
if (value > round_value)
|
||
|
cols = round_value +1;
|
||
|
else
|
||
|
cols = round_value;
|
||
|
|
||
|
return cols;
|
||
|
}
|
||
|
|
||
|
|
||
|
extern const float WIPE_TOWER_DEFAULT_X_POS;
|
||
|
extern const float WIPE_TOWER_DEFAULT_Y_POS; // Max y
|
||
|
|
||
|
extern const float I3_WIPE_TOWER_DEFAULT_X_POS;
|
||
|
extern const float I3_WIPE_TOWER_DEFAULT_Y_POS; // Max y
|
||
|
|
||
|
|
||
|
|
||
|
namespace Slic3r {
|
||
|
|
||
|
class Model;
|
||
|
class ModelObject;
|
||
|
class ModelInstance;
|
||
|
class Print;
|
||
|
class SLAPrint;
|
||
|
|
||
|
namespace GUI {
|
||
|
class Plater;
|
||
|
class GLCanvas3D;
|
||
|
struct Camera;
|
||
|
class PartPlateList;
|
||
|
|
||
|
using GCodeResult = GCodeProcessorResult;
|
||
|
|
||
|
class PartPlate : public ObjectBase
|
||
|
{
|
||
|
public:
|
||
|
enum HeightLimitMode{
|
||
|
HEIGHT_LIMIT_NONE,
|
||
|
HEIGHT_LIMIT_BOTTOM,
|
||
|
HEIGHT_LIMIT_TOP,
|
||
|
HEIGHT_LIMIT_BOTH
|
||
|
};
|
||
|
|
||
|
private:
|
||
|
PartPlateList* m_partplate_list {nullptr };
|
||
|
Plater* m_plater; //Plater reference, not own it
|
||
|
Model* m_model; //Model reference, not own it
|
||
|
PrinterTechnology printer_technology;
|
||
|
|
||
|
std::set<std::pair<int, int>> obj_to_instance_set;
|
||
|
std::set<std::pair<int, int>> instance_outside_set;
|
||
|
int m_plate_index;
|
||
|
Vec3d m_origin;
|
||
|
int m_width;
|
||
|
int m_depth;
|
||
|
int m_height;
|
||
|
float m_height_to_lid;
|
||
|
float m_height_to_rod;
|
||
|
bool m_printable;
|
||
|
bool m_locked;
|
||
|
bool m_ready_for_slice;
|
||
|
bool m_slice_result_valid;
|
||
|
bool m_apply_invalid {false};
|
||
|
float m_slice_percent;
|
||
|
|
||
|
Print *m_print; //Print reference, not own it, no need to serialize
|
||
|
GCodeProcessorResult *m_gcode_result;
|
||
|
std::vector<FilamentInfo> slice_filaments_info;
|
||
|
int m_print_index;
|
||
|
|
||
|
std::string m_tmp_gcode_path; //use a temp path to store the gcode
|
||
|
std::string m_temp_config_3mf_path; //use a temp path to store the config 3mf
|
||
|
std::string m_gcode_path_from_3mf; //use a path to store the gcode loaded from 3mf
|
||
|
|
||
|
friend class PartPlateList;
|
||
|
|
||
|
Pointfs m_raw_shape;
|
||
|
Pointfs m_shape;
|
||
|
Pointfs m_exclude_area;
|
||
|
BoundingBoxf3 m_bounding_box;
|
||
|
BoundingBoxf3 m_extended_bounding_box;
|
||
|
mutable std::vector<BoundingBoxf3> m_exclude_bounding_box;
|
||
|
mutable BoundingBoxf3 m_grabber_box;
|
||
|
Transform3d m_grabber_trans_matrix;
|
||
|
Slic3r::Geometry::Transformation position;
|
||
|
std::vector<Vec3f> positions;
|
||
|
unsigned int m_vbo_id{ 0 };
|
||
|
GeometryBuffer m_triangles;
|
||
|
GeometryBuffer m_exclude_triangles;
|
||
|
GeometryBuffer m_logo_triangles;
|
||
|
GeometryBuffer m_gridlines;
|
||
|
GeometryBuffer m_gridlines_bolder;
|
||
|
GeometryBuffer m_height_limit_common;
|
||
|
GeometryBuffer m_height_limit_bottom;
|
||
|
GeometryBuffer m_height_limit_top;
|
||
|
GeometryBuffer m_del_icon;
|
||
|
GeometryBuffer m_plate_name_edit_icon;
|
||
|
//GeometryBuffer m_del_and_background_icon;
|
||
|
mutable unsigned int m_del_vbo_id{ 0 };
|
||
|
GeometryBuffer m_arrange_icon;
|
||
|
mutable unsigned int m_arrange_vbo_id{ 0 };
|
||
|
GeometryBuffer m_orient_icon;
|
||
|
mutable unsigned int m_orient_vbo_id{ 0 };
|
||
|
GeometryBuffer m_lock_icon;
|
||
|
mutable unsigned int m_lock_vbo_id{ 0 };
|
||
|
GeometryBuffer m_plate_settings_icon;
|
||
|
mutable unsigned int m_plate_settings_vbo_id{ 0 };
|
||
|
GeometryBuffer m_plate_idx_icon;
|
||
|
mutable unsigned int m_plate_idx_vbo_id{ 0 };
|
||
|
mutable unsigned int m_plate_name_edit_vbo_id{0};
|
||
|
GLTexture m_texture;
|
||
|
|
||
|
mutable float m_grabber_color[4];
|
||
|
float m_scale_factor{ 1.0f };
|
||
|
GLUquadricObject* m_quadric;
|
||
|
int m_hover_id;
|
||
|
bool m_selected;
|
||
|
int m_timelapse_warning_code = 0;
|
||
|
|
||
|
// BBS
|
||
|
DynamicPrintConfig m_config;
|
||
|
|
||
|
// part plate name
|
||
|
std::string m_name; // utf8 string
|
||
|
bool m_name_change = false;
|
||
|
GeometryBuffer m_plate_name_icon;
|
||
|
mutable unsigned int m_plate_name_vbo_id{0};
|
||
|
GLTexture m_name_texture;
|
||
|
|
||
|
void init();
|
||
|
bool valid_instance(int obj_id, int instance_id);
|
||
|
void generate_print_polygon(ExPolygon &print_polygon);
|
||
|
void generate_exclude_polygon(ExPolygon &exclude_polygon);
|
||
|
void generate_logo_polygon(ExPolygon &logo_polygon);
|
||
|
void calc_bounding_boxes() const;
|
||
|
void calc_triangles(const ExPolygon& poly);
|
||
|
void calc_exclude_triangles(const ExPolygon& poly);
|
||
|
void calc_gridlines(const ExPolygon& poly, const BoundingBox& pp_bbox);
|
||
|
void calc_height_limit();
|
||
|
void calc_vertex_for_number(int index, bool one_number, GeometryBuffer &buffer);
|
||
|
void calc_vertex_for_plate_name(GLTexture& texture, GeometryBuffer &buffer);
|
||
|
void calc_vertex_for_plate_name_edit_icon(GLTexture *texture, int index, GeometryBuffer &buffer);
|
||
|
void calc_vertex_for_icons(int index, GeometryBuffer &buffer);
|
||
|
void calc_vertex_for_icons_background(int icon_count, GeometryBuffer &buffer);
|
||
|
void render_background(bool force_default_color = false) const;
|
||
|
void render_logo(bool bottom, bool render_cali = true) const;
|
||
|
void render_logo_texture(GLTexture& logo_texture, const GeometryBuffer& logo_buffer, bool bottom, unsigned int vbo_id) const;
|
||
|
void render_exclude_area(bool force_default_color) const;
|
||
|
//void render_background_for_picking(const float* render_color) const;
|
||
|
void render_grid(bool bottom) const;
|
||
|
void render_height_limit(PartPlate::HeightLimitMode mode = HEIGHT_LIMIT_BOTH) const;
|
||
|
void render_label(GLCanvas3D& canvas) const;
|
||
|
void render_grabber(const float* render_color, bool use_lighting) const;
|
||
|
void render_face(float x_size, float y_size) const;
|
||
|
void render_arrows(const float* render_color, bool use_lighting) const;
|
||
|
void render_left_arrow(const float* render_color, bool use_lighting) const;
|
||
|
void render_right_arrow(const float* render_color, bool use_lighting) const;
|
||
|
void render_icon_texture(int position_id, int tex_coords_id, const GeometryBuffer &buffer, GLTexture &texture, unsigned int &vbo_id) const;
|
||
|
void render_plate_name_texture(int position_id, int tex_coords_id);
|
||
|
void render_icons(bool bottom, bool only_body = false, int hover_id = -1);
|
||
|
void render_only_numbers(bool bottom) const;
|
||
|
void render_rectangle_for_picking(const GeometryBuffer &buffer, const float* render_color) const;
|
||
|
void on_render_for_picking() const;
|
||
|
std::array<float, 4> picking_color_component(int idx) const;
|
||
|
void release_opengl_resource();
|
||
|
|
||
|
public:
|
||
|
static const unsigned int PLATE_BASE_ID = 255 * 255 * 253;
|
||
|
static const unsigned int PLATE_NAME_HOVER_ID = 6;
|
||
|
static const unsigned int GRABBER_COUNT = 7;
|
||
|
|
||
|
static std::array<float, 4> SELECT_COLOR;
|
||
|
static std::array<float, 4> UNSELECT_COLOR;
|
||
|
static std::array<float, 4> UNSELECT_DARK_COLOR;
|
||
|
static std::array<float, 4> DEFAULT_COLOR;
|
||
|
static std::array<float, 4> LINE_BOTTOM_COLOR;
|
||
|
static std::array<float, 4> LINE_TOP_COLOR;
|
||
|
static std::array<float, 4> LINE_TOP_DARK_COLOR;
|
||
|
static std::array<float, 4> LINE_TOP_SEL_COLOR;
|
||
|
static std::array<float, 4> LINE_TOP_SEL_DARK_COLOR;
|
||
|
static std::array<float, 4> HEIGHT_LIMIT_BOTTOM_COLOR;
|
||
|
static std::array<float, 4> HEIGHT_LIMIT_TOP_COLOR;
|
||
|
|
||
|
static void update_render_colors();
|
||
|
static void load_render_colors();
|
||
|
|
||
|
PartPlate();
|
||
|
PartPlate(PartPlateList *partplate_list, Vec3d origin, int width, int depth, int height, Plater* platerObj, Model* modelObj, bool printable=true, PrinterTechnology tech = ptFFF);
|
||
|
~PartPlate();
|
||
|
|
||
|
bool operator<(PartPlate&) const;
|
||
|
|
||
|
//clear alll the instances in plate
|
||
|
void clear(bool clear_sliced_result = true);
|
||
|
|
||
|
BedType get_bed_type(bool load_from_project = false) const;
|
||
|
void set_bed_type(BedType bed_type);
|
||
|
void reset_bed_type();
|
||
|
DynamicPrintConfig* config() { return &m_config; }
|
||
|
|
||
|
// set print sequence per plate
|
||
|
//bool print_seq_same_global = true;
|
||
|
void set_print_seq(PrintSequence print_seq = PrintSequence::ByDefault);
|
||
|
PrintSequence get_print_seq() const;
|
||
|
// Get the real effective print sequence of current plate.
|
||
|
// If curr_plate's print_seq is ByDefault, use the global sequence
|
||
|
// @return PrintSequence::{ByLayer,ByObject}
|
||
|
PrintSequence get_real_print_seq(bool* plate_same_as_global=nullptr) const;
|
||
|
|
||
|
bool has_spiral_mode_config() const;
|
||
|
bool get_spiral_vase_mode() const;
|
||
|
void set_spiral_vase_mode(bool spiral_mode, bool as_global);
|
||
|
|
||
|
//static const int plate_x_offset = 20; //mm
|
||
|
//static const double plate_x_gap = 0.2;
|
||
|
ThumbnailData thumbnail_data;
|
||
|
ThumbnailData no_light_thumbnail_data;
|
||
|
static const int plate_thumbnail_width = 512;
|
||
|
static const int plate_thumbnail_height = 512;
|
||
|
|
||
|
ThumbnailData top_thumbnail_data;
|
||
|
ThumbnailData pick_thumbnail_data;
|
||
|
|
||
|
//ThumbnailData cali_thumbnail_data;
|
||
|
PlateBBoxData cali_bboxes_data;
|
||
|
//static const int cali_thumbnail_width = 2560;
|
||
|
//static const int cali_thumbnail_height = 2560;
|
||
|
|
||
|
//set the plate's index
|
||
|
void set_index(int index);
|
||
|
// get the plate's index
|
||
|
int get_index() { return m_plate_index; }
|
||
|
|
||
|
// get the plate's name
|
||
|
std::string get_plate_name() const { return m_name; }
|
||
|
bool generate_plate_name_texture();
|
||
|
// set the plate's name
|
||
|
void set_plate_name(const std::string &name);
|
||
|
|
||
|
void set_timelapse_warning_code(int code) { m_timelapse_warning_code = code; }
|
||
|
int timelapse_warning_code() { return m_timelapse_warning_code; }
|
||
|
|
||
|
//get the print's object, result and index
|
||
|
void get_print(PrintBase **print, GCodeResult **result, int *index);
|
||
|
|
||
|
//set the print object, result and it's index
|
||
|
void set_print(PrintBase *print, GCodeResult* result = nullptr, int index = -1);
|
||
|
|
||
|
//get gcode filename
|
||
|
std::string get_gcode_filename();
|
||
|
|
||
|
bool is_valid_gcode_file();
|
||
|
|
||
|
//get the plate's center point origin
|
||
|
Vec3d get_center_origin();
|
||
|
/* size and position related functions*/
|
||
|
//set position and size
|
||
|
void set_pos_and_size(Vec3d& origin, int width, int depth, int height, bool with_instance_move, bool do_clear = true);
|
||
|
|
||
|
// BBS
|
||
|
Vec2d get_size() const { return Vec2d(m_width, m_depth); }
|
||
|
ModelObjectPtrs get_objects() { return m_model->objects; }
|
||
|
ModelObjectPtrs get_objects_on_this_plate();
|
||
|
ModelInstance* get_instance(int obj_id, int instance_id);
|
||
|
BoundingBoxf3 get_objects_bounding_box();
|
||
|
|
||
|
Vec3d get_origin() { return m_origin; }
|
||
|
Vec3d estimate_wipe_tower_size(const DynamicPrintConfig & config, const double w, const double wipe_volume, int plate_extruder_size = 0, bool use_global_objects = false) const;
|
||
|
arrangement::ArrangePolygon estimate_wipe_tower_polygon(const DynamicPrintConfig & config, int plate_index, int plate_extruder_size = 0, bool use_global_objects = false) const;
|
||
|
std::vector<int> get_extruders(bool conside_custom_gcode = false) const;
|
||
|
std::vector<int> get_extruders_under_cli(bool conside_custom_gcode, DynamicPrintConfig& full_config) const;
|
||
|
std::vector<int> get_extruders_without_support(bool conside_custom_gcode = false) const;
|
||
|
std::vector<int> get_used_extruders();
|
||
|
|
||
|
/* instance related operations*/
|
||
|
//judge whether instance is bound in plate or not
|
||
|
bool contain_instance(int obj_id, int instance_id);
|
||
|
bool contain_instance_totally(ModelObject* object, int instance_id) const;
|
||
|
//judge whether instance is totally included in plate or not
|
||
|
bool contain_instance_totally(int obj_id, int instance_id) const;
|
||
|
|
||
|
//judge whether the plate's origin is at the left of instance or not
|
||
|
bool is_left_top_of(int obj_id, int instance_id);
|
||
|
|
||
|
//check whether instance is outside the plate or not
|
||
|
bool check_outside(int obj_id, int instance_id, BoundingBoxf3* bounding_box = nullptr);
|
||
|
|
||
|
//judge whether instance is intesected with plate or not
|
||
|
bool intersect_instance(int obj_id, int instance_id, BoundingBoxf3* bounding_box = nullptr);
|
||
|
|
||
|
//add an instance into plate
|
||
|
int add_instance(int obj_id, int instance_id, bool move_position, BoundingBoxf3* bounding_box = nullptr);
|
||
|
|
||
|
//remove instance from plate
|
||
|
int remove_instance(int obj_id, int instance_id);
|
||
|
|
||
|
//translate instance on the plate
|
||
|
void translate_all_instance(Vec3d position);
|
||
|
|
||
|
//duplicate all instance for count
|
||
|
void duplicate_all_instance(unsigned int dup_count, bool need_skip, std::map<int, bool>& skip_objects);
|
||
|
|
||
|
//update instance exclude state
|
||
|
void update_instance_exclude_status(int obj_id, int instance_id, BoundingBoxf3* bounding_box = nullptr);
|
||
|
|
||
|
//update object's index caused by original object deleted
|
||
|
void update_object_index(int obj_idx_removed, int obj_idx_max);
|
||
|
|
||
|
// set objects configs when enabling spiral vase mode.
|
||
|
void set_vase_mode_related_object_config(int obj_id = -1);
|
||
|
|
||
|
//whether it is empty
|
||
|
bool empty() { return obj_to_instance_set.empty(); }
|
||
|
|
||
|
int printable_instance_size();
|
||
|
|
||
|
//whether it is has printable instances
|
||
|
bool has_printable_instances();
|
||
|
bool is_all_instances_unprintable();
|
||
|
|
||
|
//move instances to left or right PartPlate
|
||
|
void move_instances_to(PartPlate& left_plate, PartPlate& right_plate, BoundingBoxf3* bounding_box = nullptr);
|
||
|
|
||
|
/*rendering related functions*/
|
||
|
const Pointfs& get_shape() const { return m_shape; }
|
||
|
bool set_shape(const Pointfs& shape, const Pointfs& exclude_areas, Vec2d position, float height_to_lid, float height_to_rod);
|
||
|
bool contains(const Vec3d& point) const;
|
||
|
bool contains(const GLVolume& v) const;
|
||
|
bool contains(const BoundingBoxf3& bb) const;
|
||
|
bool intersects(const BoundingBoxf3& bb) const;
|
||
|
|
||
|
void render(bool bottom, bool only_body = false, bool force_background_color = false, HeightLimitMode mode = HEIGHT_LIMIT_NONE, int hover_id = -1, bool render_cali = false);
|
||
|
void render_for_picking() const { on_render_for_picking(); }
|
||
|
void set_selected();
|
||
|
void set_unselected();
|
||
|
void set_hover_id(int id) { m_hover_id = id; }
|
||
|
const BoundingBoxf3& get_bounding_box(bool extended = false) { return extended ? m_extended_bounding_box : m_bounding_box; }
|
||
|
const BoundingBox get_bounding_box_crd();
|
||
|
BoundingBoxf3 get_plate_box() {return get_build_volume();}
|
||
|
BoundingBoxf3 get_build_volume()
|
||
|
{
|
||
|
auto eps=Slic3r::BuildVolume::SceneEpsilon;
|
||
|
Vec3d up_point = Vec3d(m_origin.x() + m_width + eps, m_origin.y() + m_depth + eps, m_origin.z() + m_height + eps);
|
||
|
Vec3d low_point = Vec3d(m_origin.x() - eps, m_origin.y() - eps, m_origin.z() - eps);
|
||
|
if (m_raw_shape.size() > 0) {
|
||
|
up_point.x() += m_raw_shape[0].x();
|
||
|
up_point.y() += m_raw_shape[0].y();
|
||
|
low_point.x() += m_raw_shape[0].x();
|
||
|
low_point.y() += m_raw_shape[0].y();
|
||
|
}
|
||
|
BoundingBoxf3 plate_box(low_point, up_point);
|
||
|
return plate_box;
|
||
|
}
|
||
|
|
||
|
const std::vector<BoundingBoxf3>& get_exclude_areas() { return m_exclude_bounding_box; }
|
||
|
|
||
|
|
||
|
/*status related functions*/
|
||
|
//update status
|
||
|
void update_states();
|
||
|
|
||
|
//is locked or not
|
||
|
bool is_locked() const { return m_locked; }
|
||
|
void lock(bool state) { m_locked = state; }
|
||
|
|
||
|
//is a printable plate or not
|
||
|
bool is_printable() const { return m_printable; }
|
||
|
|
||
|
//can be sliced or not
|
||
|
bool can_slice() const
|
||
|
{
|
||
|
return m_ready_for_slice && !m_apply_invalid;
|
||
|
}
|
||
|
void update_slice_ready_status(bool ready_slice)
|
||
|
{
|
||
|
m_ready_for_slice = ready_slice;
|
||
|
}
|
||
|
|
||
|
//bedtype mismatch or not
|
||
|
bool is_apply_result_invalid() const
|
||
|
{
|
||
|
return m_apply_invalid;
|
||
|
}
|
||
|
void update_apply_result_invalid(bool invalid)
|
||
|
{
|
||
|
m_apply_invalid = invalid;
|
||
|
}
|
||
|
|
||
|
//is slice result valid or not
|
||
|
bool is_slice_result_valid() const
|
||
|
{
|
||
|
return m_slice_result_valid;
|
||
|
}
|
||
|
|
||
|
//is slice result ready for print
|
||
|
bool is_slice_result_ready_for_print() const
|
||
|
{
|
||
|
bool result = m_slice_result_valid;
|
||
|
if (result)
|
||
|
result = m_gcode_result ? (!m_gcode_result->toolpath_outside) : false;// && !m_gcode_result->conflict_result.has_value() gcode conflict can also print
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
// check whether plate's slice result valid for export to file
|
||
|
bool is_slice_result_ready_for_export()
|
||
|
{
|
||
|
return is_slice_result_ready_for_print() && has_printable_instances();
|
||
|
}
|
||
|
|
||
|
//invalid sliced result
|
||
|
void update_slice_result_valid_state(bool valid = false);
|
||
|
|
||
|
void update_slicing_percent(float percent)
|
||
|
{
|
||
|
m_slice_percent = percent;
|
||
|
}
|
||
|
|
||
|
float get_slicing_percent() { return m_slice_percent; }
|
||
|
|
||
|
/*slice related functions*/
|
||
|
//update current slice context into backgroud slicing process
|
||
|
void update_slice_context(BackgroundSlicingProcess& process);
|
||
|
//return the fff print object
|
||
|
Print* fff_print() { return m_print; }
|
||
|
//return the slice result
|
||
|
GCodeProcessorResult* get_slice_result() { return m_gcode_result; }
|
||
|
|
||
|
std::string get_tmp_gcode_path();
|
||
|
std::string get_temp_config_3mf_path();
|
||
|
//this API should only be used for command line usage
|
||
|
void set_tmp_gcode_path(std::string new_path)
|
||
|
{
|
||
|
m_tmp_gcode_path = new_path;
|
||
|
}
|
||
|
//load gcode from file
|
||
|
int load_gcode_from_file(const std::string& filename);
|
||
|
//load thumbnail data from file
|
||
|
int load_thumbnail_data(std::string filename, ThumbnailData& thumb_data);
|
||
|
//load pattern thumbnail data from file
|
||
|
int load_pattern_thumbnail_data(std::string filename);
|
||
|
//load pattern box data from file
|
||
|
int load_pattern_box_data(std::string filename);
|
||
|
|
||
|
std::vector<int> get_first_layer_print_sequence() const;
|
||
|
std::vector<LayerPrintSequence> get_other_layers_print_sequence() const;
|
||
|
void set_first_layer_print_sequence(const std::vector<int> &sorted_filaments);
|
||
|
void set_other_layers_print_sequence(const std::vector<LayerPrintSequence>& layer_seq_list);
|
||
|
void update_first_layer_print_sequence(size_t filament_nums);
|
||
|
|
||
|
void print() const;
|
||
|
|
||
|
std::map<std::string, std::string> get_diff_object_setting();
|
||
|
std::map<std::string, std::string> get_diff_plate_setting();
|
||
|
|
||
|
friend class cereal::access;
|
||
|
friend class UndoRedo::StackImpl;
|
||
|
|
||
|
template<class Archive> void load(Archive& ar) {
|
||
|
std::vector<std::pair<int, int>> objects_and_instances;
|
||
|
std::vector<std::pair<int, int>> instances_outside;
|
||
|
|
||
|
ar(m_plate_index, m_print_index, m_locked, m_selected, m_ready_for_slice, m_slice_result_valid, m_apply_invalid, m_printable, m_tmp_gcode_path, objects_and_instances, instances_outside, m_config, m_name);
|
||
|
|
||
|
for (std::vector<std::pair<int, int>>::iterator it = objects_and_instances.begin(); it != objects_and_instances.end(); ++it)
|
||
|
obj_to_instance_set.insert(std::pair(it->first, it->second));
|
||
|
|
||
|
for (std::vector<std::pair<int, int>>::iterator it = instances_outside.begin(); it != instances_outside.end(); ++it)
|
||
|
instance_outside_set.insert(std::pair(it->first, it->second));
|
||
|
}
|
||
|
template<class Archive> void save(Archive& ar) const {
|
||
|
std::vector<std::pair<int, int>> objects_and_instances;
|
||
|
std::vector<std::pair<int, int>> instances_outside;
|
||
|
|
||
|
for (std::set<std::pair<int, int>>::iterator it = instance_outside_set.begin(); it != instance_outside_set.end(); ++it)
|
||
|
instances_outside.emplace_back(it->first, it->second);
|
||
|
|
||
|
for (std::set<std::pair<int, int>>::iterator it = obj_to_instance_set.begin(); it != obj_to_instance_set.end(); ++it)
|
||
|
objects_and_instances.emplace_back(it->first, it->second);
|
||
|
|
||
|
ar(m_plate_index, m_print_index, m_locked, m_selected, m_ready_for_slice, m_slice_result_valid, m_apply_invalid, m_printable,m_tmp_gcode_path, objects_and_instances, instances_outside, m_config, m_name);
|
||
|
}
|
||
|
/*template<class Archive> void serialize(Archive& ar)
|
||
|
{
|
||
|
std::vector<std::pair<int, int>> objects_and_instances;
|
||
|
for (std::set<std::pair<int, int>>::iterator it = obj_to_instance_set.begin(); it != obj_to_instance_set.end(); ++it)
|
||
|
objects_and_instances.emplace_back(it->first, it->second);
|
||
|
ar(m_plate_index, m_origin, m_width, m_depth, m_height, m_locked, m_ready_for_slice, m_printable, objects_and_instances);
|
||
|
}*/
|
||
|
};
|
||
|
|
||
|
class PartPlateList : public ObjectBase
|
||
|
{
|
||
|
Plater* m_plater; //Plater reference, not own it
|
||
|
Model* m_model; //Model reference, not own it
|
||
|
PrinterTechnology printer_technology;
|
||
|
|
||
|
std::vector<PartPlate*> m_plate_list;
|
||
|
std::map<int, PrintBase*> m_print_list;
|
||
|
std::map<int, GCodeResult*> m_gcode_result_list;
|
||
|
std::mutex m_plates_mutex;
|
||
|
int m_plate_count;
|
||
|
int m_plate_cols;
|
||
|
int m_current_plate;
|
||
|
int m_print_index;
|
||
|
|
||
|
int m_plate_width;
|
||
|
int m_plate_depth;
|
||
|
int m_plate_height;
|
||
|
|
||
|
float m_height_to_lid;
|
||
|
float m_height_to_rod;
|
||
|
PartPlate::HeightLimitMode m_height_limit_mode{PartPlate::HEIGHT_LIMIT_BOTH};
|
||
|
|
||
|
PartPlate unprintable_plate;
|
||
|
Pointfs m_shape;
|
||
|
Pointfs m_exclude_areas;
|
||
|
BoundingBoxf3 m_bounding_box;
|
||
|
bool m_intialized;
|
||
|
std::string m_logo_texture_filename;
|
||
|
GLTexture m_logo_texture;
|
||
|
GLTexture m_del_texture;
|
||
|
GLTexture m_del_hovered_texture;
|
||
|
GLTexture m_arrange_texture;
|
||
|
GLTexture m_arrange_hovered_texture;
|
||
|
GLTexture m_orient_texture;
|
||
|
GLTexture m_orient_hovered_texture;
|
||
|
GLTexture m_locked_texture;
|
||
|
GLTexture m_locked_hovered_texture;
|
||
|
GLTexture m_lockopen_texture;
|
||
|
GLTexture m_lockopen_hovered_texture;
|
||
|
GLTexture m_plate_settings_texture;
|
||
|
GLTexture m_plate_settings_changed_texture;
|
||
|
GLTexture m_plate_settings_hovered_texture;
|
||
|
GLTexture m_plate_settings_changed_hovered_texture;
|
||
|
GLTexture m_plate_name_edit_texture;
|
||
|
GLTexture m_plate_name_edit_hovered_texture;
|
||
|
GLTexture m_idx_textures[MAX_PLATE_COUNT];
|
||
|
// set render option
|
||
|
bool render_bedtype_logo = true;
|
||
|
bool render_plate_settings = true;
|
||
|
bool render_cali_logo = true;
|
||
|
|
||
|
bool m_is_dark = false;
|
||
|
|
||
|
void init();
|
||
|
//compute the origin for printable plate with index i
|
||
|
Vec3d compute_origin(int index, int column_count);
|
||
|
//compute the origin for unprintable plate
|
||
|
Vec3d compute_origin_for_unprintable();
|
||
|
//compute shape position
|
||
|
Vec2d compute_shape_position(int index, int cols);
|
||
|
//generate icon textures
|
||
|
void generate_icon_textures();
|
||
|
void release_icon_textures();
|
||
|
|
||
|
void set_default_wipe_tower_pos_for_plate(int plate_idx);
|
||
|
|
||
|
friend class cereal::access;
|
||
|
friend class UndoRedo::StackImpl;
|
||
|
friend class PartPlate;
|
||
|
|
||
|
public:
|
||
|
class BedTextureInfo {
|
||
|
public:
|
||
|
class TexturePart {
|
||
|
public:
|
||
|
// position
|
||
|
float x;
|
||
|
float y;
|
||
|
float w;
|
||
|
float h;
|
||
|
unsigned int vbo_id;
|
||
|
std::string filename;
|
||
|
GLTexture* texture { nullptr };
|
||
|
Vec2d offset;
|
||
|
GeometryBuffer* buffer { nullptr };
|
||
|
TexturePart(float xx, float yy, float ww, float hh, std::string file){
|
||
|
x = xx; y = yy;
|
||
|
w = ww; h = hh;
|
||
|
filename = file;
|
||
|
texture = nullptr;
|
||
|
buffer = nullptr;
|
||
|
vbo_id = 0;
|
||
|
offset = Vec2d(0, 0);
|
||
|
}
|
||
|
|
||
|
TexturePart(const TexturePart& part) {
|
||
|
this->x = part.x;
|
||
|
this->y = part.y;
|
||
|
this->w = part.w;
|
||
|
this->h = part.h;
|
||
|
this->offset = part.offset;
|
||
|
this->buffer = part.buffer;
|
||
|
this->filename = part.filename;
|
||
|
this->texture = part.texture;
|
||
|
this->vbo_id = part.vbo_id;
|
||
|
}
|
||
|
|
||
|
void update_buffer();
|
||
|
void reset();
|
||
|
private:
|
||
|
void release_vbo();
|
||
|
};
|
||
|
std::vector<TexturePart> parts;
|
||
|
void reset();
|
||
|
};
|
||
|
|
||
|
static const unsigned int MAX_PLATES_COUNT = MAX_PLATE_COUNT;
|
||
|
static GLTexture bed_textures[(unsigned int)btCount];
|
||
|
static bool is_load_bedtype_textures;
|
||
|
static bool is_load_cali_texture;
|
||
|
|
||
|
PartPlateList(int width, int depth, int height, Plater* platerObj, Model* modelObj, PrinterTechnology tech = ptFFF);
|
||
|
PartPlateList(Plater* platerObj, Model* modelObj, PrinterTechnology tech = ptFFF);
|
||
|
~PartPlateList();
|
||
|
|
||
|
//this may be happened after machine changed
|
||
|
void reset_size(int width, int depth, int height, bool reload_objects = true, bool update_shapes = false);
|
||
|
//clear all the instances in the plate, but keep the plates
|
||
|
void clear(bool delete_plates = false, bool release_print_list = false, bool except_locked = false, int plate_index = -1);
|
||
|
//clear all the instances in the plate, and delete the plates, only keep the first default plate
|
||
|
void reset(bool do_init);
|
||
|
//compute the origin for printable plate with index i using new width
|
||
|
Vec3d compute_origin_using_new_size(int i, int new_width, int new_depth);
|
||
|
|
||
|
//reset partplate to init states
|
||
|
void reinit();
|
||
|
|
||
|
//get the plate stride
|
||
|
double plate_stride_x();
|
||
|
double plate_stride_y();
|
||
|
void get_plate_size(int& width, int& depth, int& height) {
|
||
|
width = m_plate_width;
|
||
|
depth = m_plate_depth;
|
||
|
height = m_plate_height;
|
||
|
}
|
||
|
|
||
|
/*basic plate operations*/
|
||
|
//create an empty plate and return its index
|
||
|
int create_plate(bool adjust_position = true);
|
||
|
|
||
|
//destroy print which has the index of print_index
|
||
|
int destroy_print(int print_index);
|
||
|
|
||
|
//delete a plate by index
|
||
|
int delete_plate(int index);
|
||
|
|
||
|
//delete a plate by pointer
|
||
|
//int delete_plate(PartPlate* plate);
|
||
|
void delete_selected_plate();
|
||
|
|
||
|
//get a plate pointer by index
|
||
|
PartPlate* get_plate(int index);
|
||
|
|
||
|
void get_height_limits(float& height_to_lid, float& height_to_rod)
|
||
|
{
|
||
|
height_to_lid = m_height_to_lid;
|
||
|
height_to_rod = m_height_to_rod;
|
||
|
}
|
||
|
|
||
|
void set_height_limits_mode(PartPlate::HeightLimitMode mode)
|
||
|
{
|
||
|
m_height_limit_mode = mode;
|
||
|
}
|
||
|
|
||
|
int get_curr_plate_index() const { return m_current_plate; }
|
||
|
PartPlate* get_curr_plate() { return m_plate_list[m_current_plate]; }
|
||
|
const PartPlate *get_curr_plate() const { return m_plate_list[m_current_plate]; }
|
||
|
|
||
|
std::vector<PartPlate*>& get_plate_list() { return m_plate_list; };
|
||
|
|
||
|
PartPlate* get_selected_plate();
|
||
|
|
||
|
std::vector<PartPlate*> get_nonempty_plate_list();
|
||
|
|
||
|
std::vector<const GCodeProcessorResult*> get_nonempty_plates_slice_results();
|
||
|
|
||
|
//compute the origin for printable plate with index i
|
||
|
Vec3d get_current_plate_origin() { return compute_origin(m_current_plate, m_plate_cols); }
|
||
|
Vec2d get_current_shape_position() { return compute_shape_position(m_current_plate, m_plate_cols); }
|
||
|
Pointfs get_exclude_area() { return m_exclude_areas; }
|
||
|
|
||
|
std::set<int> get_extruders(bool conside_custom_gcode = false) const;
|
||
|
|
||
|
//select plate
|
||
|
int select_plate(int index);
|
||
|
|
||
|
//get the plate counts, not including the invalid plate
|
||
|
int get_plate_count() const;
|
||
|
|
||
|
//update the plate cols due to plate count change
|
||
|
void update_plate_cols();
|
||
|
|
||
|
void update_all_plates_pos_and_size(bool adjust_position = true, bool with_unprintable_move = true, bool switch_plate_type = false, bool do_clear = true);
|
||
|
|
||
|
//get the plate cols
|
||
|
int get_plate_cols() { return m_plate_cols; }
|
||
|
|
||
|
//move the plate to position index
|
||
|
int move_plate_to_index(int old_index, int new_index);
|
||
|
|
||
|
//lock plate
|
||
|
int lock_plate(int index, bool state);
|
||
|
|
||
|
//is locked
|
||
|
bool is_locked(int index) { return m_plate_list[index]->is_locked();}
|
||
|
|
||
|
//find plate by print index, return -1 if not found
|
||
|
int find_plate_by_print_index(int index);
|
||
|
|
||
|
/*instance related operations*/
|
||
|
//find instance in which plate, return -1 when not found
|
||
|
//this function only judges whether it is intersect with plate
|
||
|
int find_instance(int obj_id, int instance_id);
|
||
|
int find_instance(BoundingBoxf3& bounding_box);
|
||
|
|
||
|
//find instance belongs to which plate
|
||
|
//this function not only judges whether it is intersect with plate, but also judges whether it is fully included in plate
|
||
|
//returns -1 when can not find any plate
|
||
|
int find_instance_belongs(int obj_id, int instance_id);
|
||
|
|
||
|
//notify instance's update, need to refresh the instance in plates
|
||
|
int notify_instance_update(int obj_id, int instance_id, bool is_new = false);
|
||
|
|
||
|
//notify instance is removed
|
||
|
int notify_instance_removed(int obj_id, int instance_id);
|
||
|
|
||
|
//add instance to special plate, need to remove from the original plate
|
||
|
int add_to_plate(int obj_id, int instance_id, int plate_id);
|
||
|
|
||
|
//reload all objects
|
||
|
int reload_all_objects(bool except_locked = false, int plate_index = -1);
|
||
|
|
||
|
//reload objects for newly created plate
|
||
|
int construct_objects_list_for_new_plate(int plate_index);
|
||
|
|
||
|
/* arrangement related functions */
|
||
|
//compute the plate index
|
||
|
int compute_plate_index(arrangement::ArrangePolygon& arrange_polygon);
|
||
|
//preprocess an arrangement::ArrangePolygon, return true if it is in a locked plate
|
||
|
bool preprocess_arrange_polygon(int obj_index, int instance_index, arrangement::ArrangePolygon& arrange_polygon, bool selected);
|
||
|
bool preprocess_arrange_polygon_other_locked(int obj_index, int instance_index, arrangement::ArrangePolygon& arrange_polygon, bool selected);
|
||
|
bool preprocess_exclude_areas(arrangement::ArrangePolygons& unselected, int num_plates = 16, float inflation = 0);
|
||
|
bool preprocess_nonprefered_areas(arrangement::ArrangePolygons& regions, int num_plates = 1, float inflation=0);
|
||
|
|
||
|
void postprocess_bed_index_for_selected(arrangement::ArrangePolygon& arrange_polygon);
|
||
|
void postprocess_bed_index_for_unselected(arrangement::ArrangePolygon& arrange_polygon);
|
||
|
void postprocess_bed_index_for_current_plate(arrangement::ArrangePolygon& arrange_polygon);
|
||
|
|
||
|
//postprocess an arrangement:;ArrangePolygon
|
||
|
void postprocess_arrange_polygon(arrangement::ArrangePolygon& arrange_polygon, bool selected);
|
||
|
|
||
|
/*rendering related functions*/
|
||
|
void on_change_color_mode(bool is_dark) { m_is_dark = is_dark; }
|
||
|
void render(bool bottom, bool only_current = false, bool only_body = false, int hover_id = -1, bool render_cali = false);
|
||
|
void render_for_picking_pass();
|
||
|
void set_render_option(bool bedtype_texture, bool plate_settings);
|
||
|
void set_render_cali(bool value = true) { render_cali_logo = value; }
|
||
|
BoundingBoxf3& get_bounding_box() { return m_bounding_box; }
|
||
|
//int select_plate_by_hover_id(int hover_id);
|
||
|
int select_plate_by_obj(int obj_index, int instance_index);
|
||
|
void calc_bounding_boxes();
|
||
|
void select_plate_view();
|
||
|
bool set_shapes(const Pointfs& shape, const Pointfs& exclude_areas, const std::string& custom_texture, float height_to_lid, float height_to_rod);
|
||
|
void set_hover_id(int id);
|
||
|
void reset_hover_id();
|
||
|
bool intersects(const BoundingBoxf3 &bb);
|
||
|
bool contains(const BoundingBoxf3 &bb);
|
||
|
|
||
|
const std::string &get_logo_texture_filename() { return m_logo_texture_filename; }
|
||
|
void update_logo_texture_filename(const std::string &texture_filename);
|
||
|
/*slice related functions*/
|
||
|
//update current slice context into backgroud slicing process
|
||
|
void update_slice_context_to_current_plate(BackgroundSlicingProcess& process);
|
||
|
//return the current fff print object
|
||
|
Print& get_current_fff_print() const;
|
||
|
//return the slice result
|
||
|
GCodeProcessorResult* get_current_slice_result() const;
|
||
|
//will create a plate and load gcode, return the plate index
|
||
|
int create_plate_from_gcode_file(const std::string& filename);
|
||
|
|
||
|
//invalid all the plater's slice result
|
||
|
void invalid_all_slice_result();
|
||
|
//set current plater's slice result to valid
|
||
|
void update_current_slice_result_state(bool valid) { m_plate_list[m_current_plate]->update_slice_result_valid_state(valid); }
|
||
|
//is slice result valid or not
|
||
|
bool is_all_slice_results_valid() const;
|
||
|
bool is_all_slice_results_ready_for_print() const;
|
||
|
bool is_all_plates_ready_for_slice() const;
|
||
|
bool is_all_slice_result_ready_for_export() const;
|
||
|
void print() const;
|
||
|
|
||
|
//get the all the sliced result
|
||
|
void get_sliced_result(std::vector<bool>& sliced_result, std::vector<std::string>& gcode_paths);
|
||
|
//retruct plates structures after de-serialize
|
||
|
int rebuild_plates_after_deserialize(std::vector<bool>& previous_sliced_result, std::vector<std::string>& previous_gcode_paths);
|
||
|
|
||
|
//retruct plates structures after auto-arrangement
|
||
|
int rebuild_plates_after_arrangement(bool recycle_plates = true, bool except_locked = false, int plate_index = -1);
|
||
|
|
||
|
/* load/store releted functions, with_gcode = true and plate_idx = -1, export all gcode
|
||
|
* if with_gcode = true and specify plate_idx, export plate_idx gcode only
|
||
|
*/
|
||
|
int store_to_3mf_structure(PlateDataPtrs& plate_data_list, bool with_slice_info = true, int plate_idx = -1);
|
||
|
int load_from_3mf_structure(PlateDataPtrs& plate_data_list);
|
||
|
//load gcode files
|
||
|
int load_gcode_files();
|
||
|
|
||
|
template<class Archive> void serialize(Archive& ar)
|
||
|
{
|
||
|
//ar(cereal::base_class<ObjectBase>(this));
|
||
|
//Cancel undo/redo for m_shape ,m_plate_width, m_plate_depth, m_plate_height,Because the printing area of different models is different, currently if the grid changes, it cannot correspond to the model on the left ui
|
||
|
ar(m_height_to_lid, m_height_to_rod, m_height_limit_mode, m_plate_count, m_current_plate, m_plate_list, unprintable_plate);
|
||
|
//ar(m_plate_width, m_plate_depth, m_plate_height, m_plate_count, m_current_plate);
|
||
|
}
|
||
|
|
||
|
void init_bed_type_info();
|
||
|
void load_bedtype_textures();
|
||
|
|
||
|
void show_cali_texture(bool show = true);
|
||
|
void init_cali_texture_info();
|
||
|
void load_cali_textures();
|
||
|
|
||
|
BedTextureInfo bed_texture_info[btCount];
|
||
|
BedTextureInfo cali_texture_info;
|
||
|
};
|
||
|
|
||
|
} // namespace GUI
|
||
|
} // namespace Slic3r
|
||
|
|
||
|
namespace cereal
|
||
|
{
|
||
|
template <class Archive> struct specialize<Archive, Slic3r::GUI::PartPlate, cereal::specialization::member_load_save> {};
|
||
|
}
|
||
|
#endif //__part_plate_hpp_
|