diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index d33f44c35..01886e870 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -21,26 +21,40 @@ namespace Slic3r { unsigned int Model::s_auto_extruder_id = 1; -ModelID ModelBase::s_last_id = 0; +size_t ModelBase::s_last_id = 0; -Model::Model(const Model &rhs) +Model& Model::assign_copy(const Model &rhs) { - *this = rhs; -} - -Model& Model::operator=(const Model &rhs) -{ - m_id = rhs.m_id; + this->copy_id(rhs); // copy materials - for (const auto &m : rhs.materials) + for (const std::pair &m : rhs.materials) this->add_material(m.first, *m.second); // copy objects this->objects.reserve(rhs.objects.size()); for (const ModelObject *o : rhs.objects) - this->add_object(*o, true); + this->add_object(*o); return *this; } +Model& Model::assign_copy(Model &&rhs) +{ + this->copy_id(rhs); + this->materials = std::move(rhs.materials); + rhs.materials.clear(); + this->objects = std::move(rhs.objects); + rhs.objects.clear(); + return *this; +} + +void Model::assign_new_unique_ids_recursive() +{ + this->set_new_unique_id(); + for (std::pair &m : this->materials) + m.second->assign_new_unique_ids_recursive(); + for (ModelObject *model_object : this->objects) + model_object->assign_new_unique_ids_recursive(); +} + Model Model::read_from_file(const std::string &input_file, DynamicPrintConfig *config, bool add_default_instances) { Model model; @@ -150,9 +164,9 @@ ModelObject* Model::add_object(const char *name, const char *path, TriangleMesh return new_object; } -ModelObject* Model::add_object(const ModelObject &other, bool copy_volumes) +ModelObject* Model::add_object(const ModelObject &other) { - ModelObject* new_object = new ModelObject(this, other, copy_volumes); + ModelObject* new_object = new ModelObject(this, other); this->objects.push_back(new_object); return new_object; } @@ -483,10 +497,10 @@ void Model::reset_auto_extruder_id() s_auto_extruder_id = 1; } -ModelObject::ModelObject(Model *model, const ModelObject &rhs, bool copy_volumes) : +ModelObject::ModelObject(Model *model, const ModelObject &rhs) : m_model(model) { - this->assign(&rhs, copy_volumes); + this->assign_copy(rhs); } ModelObject::~ModelObject() @@ -495,41 +509,74 @@ ModelObject::~ModelObject() this->clear_instances(); } -// Clone this ModelObject including its volumes and instances, keep the IDs of the copies equal to the original. -// Called by Print::apply() to clone the Model / ModelObject hierarchy to the back end for background processing. -ModelObject* ModelObject::clone(Model *parent) +// maintains the m_model pointer +ModelObject& ModelObject::assign_copy(const ModelObject &rhs) { - return new ModelObject(parent, *this, true); -} + this->copy_id(rhs); -ModelObject& ModelObject::assign(const ModelObject *rhs, bool copy_volumes) -{ - m_id = rhs->m_id; - name = rhs->name; - input_file = rhs->input_file; - config = rhs->config; - sla_support_points = rhs->sla_support_points; - layer_height_ranges = rhs->layer_height_ranges; - layer_height_profile = rhs->layer_height_profile; - layer_height_profile_valid = rhs->layer_height_profile_valid; - origin_translation = rhs->origin_translation; - m_bounding_box = rhs->m_bounding_box; - m_bounding_box_valid = rhs->m_bounding_box_valid; + this->name = rhs.name; + this->input_file = rhs.input_file; + this->config = rhs.config; + this->sla_support_points = rhs.sla_support_points; + this->layer_height_ranges = rhs.layer_height_ranges; + this->layer_height_profile = rhs.layer_height_profile; + this->layer_height_profile_valid = rhs.layer_height_profile_valid; + this->origin_translation = rhs.origin_translation; + m_bounding_box = rhs.m_bounding_box; + m_bounding_box_valid = rhs.m_bounding_box_valid; - volumes.clear(); - instances.clear(); - if (copy_volumes) { - this->volumes.reserve(rhs->volumes.size()); - for (ModelVolume *model_volume : rhs->volumes) - this->add_volume(*model_volume); - this->instances.reserve(rhs->instances.size()); - for (const ModelInstance *model_instance : rhs->instances) - this->add_instance(*model_instance); - } + this->volumes.clear(); + this->volumes.reserve(rhs.volumes.size()); + for (ModelVolume *model_volume : rhs.volumes) + this->add_volume(*model_volume); + this->instances.clear(); + this->instances.reserve(rhs.instances.size()); + for (const ModelInstance *model_instance : rhs.instances) + this->add_instance(*model_instance); return *this; } +// maintains the m_model pointer +ModelObject& ModelObject::assign_copy(ModelObject &&rhs) +{ + this->copy_id(rhs); + + this->name = std::move(rhs.name); + this->input_file = std::move(rhs.input_file); + this->config = std::move(rhs.config); + this->sla_support_points = std::move(rhs.sla_support_points); + this->layer_height_ranges = std::move(rhs.layer_height_ranges); + this->layer_height_profile = std::move(rhs.layer_height_profile); + this->layer_height_profile_valid = std::move(rhs.layer_height_profile_valid); + this->origin_translation = std::move(rhs.origin_translation); + m_bounding_box = std::move(rhs.m_bounding_box); + m_bounding_box_valid = std::move(rhs.m_bounding_box_valid); + + this->volumes = std::move(rhs.volumes); + rhs.volumes.clear(); + this->instances = std::move(rhs.instances); + rhs.instances.clear(); + + return *this; +} + +void ModelObject::assign_new_unique_ids_recursive() +{ + this->set_new_unique_id(); + for (ModelVolume *model_volume : this->volumes) + model_volume->assign_new_unique_ids_recursive(); + for (ModelInstance *model_instance : this->instances) + model_instance->assign_new_unique_ids_recursive(); +} + +// Clone this ModelObject including its volumes and instances, keep the IDs of the copies equal to the original. +// Called by Print::apply() to clone the Model / ModelObject hierarchy to the back end for background processing. +//ModelObject* ModelObject::clone(Model *parent) +//{ +// return new ModelObject(parent, *this, true); +//} + ModelVolume* ModelObject::add_volume(const TriangleMesh &mesh) { ModelVolume* v = new ModelVolume(this, mesh); @@ -554,6 +601,14 @@ ModelVolume* ModelObject::add_volume(const ModelVolume &other) return v; } +ModelVolume* ModelObject::add_volume(const ModelVolume &other, TriangleMesh &&mesh) +{ + ModelVolume* v = new ModelVolume(this, other, std::move(mesh)); + this->volumes.push_back(v); + this->invalidate_bounding_box(); + return v; +} + void ModelObject::delete_volume(size_t idx) { ModelVolumePtrs::iterator i = this->volumes.begin() + idx; @@ -876,15 +931,13 @@ void ModelObject::split(ModelObjectPtrs* new_objects) mesh->repair(); - ModelObject* new_object = m_model->add_object(*this, false); - new_object->sla_support_points.clear(); - new_object->input_file = ""; - ModelVolume* new_volume = new_object->add_volume(*mesh); - new_volume->name = volume->name; - new_volume->config = volume->config; - new_volume->set_type(volume->type()); - new_volume->set_material_id(volume->material_id()); - + ModelObject* new_object = m_model->add_object(); + new_object->name = this->name; + new_object->config = this->config; + new_object->instances.reserve(this->instances.size()); + for (const ModelInstance *model_instance : this->instances) + new_object->add_instance(*model_instance); + new_object->add_volume(*volume, std::move(*mesh)); new_objects->push_back(new_object); delete mesh; } diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index b72f20501..90ee456ec 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -27,16 +27,31 @@ class Print; typedef std::string t_model_material_id; typedef std::string t_model_material_attribute; -typedef std::map t_model_material_attributes; +typedef std::map t_model_material_attributes; -typedef std::map ModelMaterialMap; +typedef std::map ModelMaterialMap; typedef std::vector ModelObjectPtrs; typedef std::vector ModelVolumePtrs; typedef std::vector ModelInstancePtrs; // Unique identifier of a Model, ModelObject, ModelVolume, ModelInstance or ModelMaterial. // Used to synchronize the front end (UI) with the back end (BackgroundSlicingProcess / Print / PrintObject) -typedef size_t ModelID; +// Valid IDs are strictly positive (non zero). +// It is declared as an object, as some compilers (notably msvcc) consider a typedef size_t equivalent to size_t +// for parameter overload. +struct ModelID +{ + ModelID(size_t id) : id(id) {} + + bool operator==(const ModelID &rhs) const { return this->id == rhs.id; } + bool operator!=(const ModelID &rhs) const { return this->id != rhs.id; } + bool operator< (const ModelID &rhs) const { return this->id < rhs.id; } + bool operator> (const ModelID &rhs) const { return this->id > rhs.id; } + bool operator<=(const ModelID &rhs) const { return this->id <= rhs.id; } + bool operator>=(const ModelID &rhs) const { return this->id >= rhs.id; } + + size_t id; +}; // Base for Model, ModelObject, ModelVolume, ModelInstance or ModelMaterial to provide a unique ID // to synchronize the front end (UI) with the back end (BackgroundSlicingProcess / Print / PrintObject). @@ -45,18 +60,71 @@ typedef size_t ModelID; class ModelBase { public: - ModelID id() const { return m_id; } + ModelID id() const { return m_id; } + // Use with caution! + void set_new_unique_id() { m_id = generate_new_id(); } + void set_invalid_id() { m_id = 0; } + // Use with caution! + void copy_id(const ModelBase &rhs) { m_id = rhs.id(); } protected: - // Constructor to be only called by derived classes. - ModelBase() {} - ModelID m_id = generate_new_id(); + // Constructors to be only called by derived classes. + // Default constructor to assign a unique ID. + ModelBase() : m_id(generate_new_id()) {} + // Constructor with ignored int parameter to assign an invalid ID, to be replaced + // by an existing ID copied from elsewhere. + ModelBase(int) : m_id(ModelID(0)) {} + + // Override this method if a ModelBase derived class owns other ModelBase derived instances. + void assign_new_unique_ids_recursive() { this->set_new_unique_id(); } private: - static inline ModelID generate_new_id() { return s_last_id ++; } - static ModelID s_last_id; + ModelID m_id; + + static inline ModelID generate_new_id() { return ModelID(++ s_last_id); } + static size_t s_last_id; }; +#define MODELBASE_DERIVED_COPY_MOVE_CLONE(TYPE) \ + /* To be able to return an object from own copy / clone methods. Hopefully the compiler will do the "Copy elision" */ \ + /* (Omits copy and move(since C++11) constructors, resulting in zero - copy pass - by - value semantics). */ \ + TYPE(const TYPE &rhs) : ModelBase(-1) { this->assign_copy(rhs); } \ + explicit TYPE(TYPE &&rhs) : ModelBase(-1) { this->assign_clone(std::move(rhs)); } \ + TYPE& operator=(const TYPE &rhs) { this->assign_copy(rhs); return *this; } \ + TYPE& operator=(TYPE &&rhs) { this->assign_copy(std::move(rhs)); return *this; } \ + /* Copy a model, copy the IDs. The Print::apply() will call the TYPE::copy() method */ \ + /* to make a private copy for background processing. */ \ + static TYPE* new_copy(const TYPE &rhs) { return new TYPE(rhs); } \ + static TYPE* new_copy(TYPE &&rhs) { return new TYPE(std::move(rhs)); } \ + static TYPE make_copy(const TYPE &rhs) { return TYPE(rhs); } \ + static TYPE make_copy(TYPE &&rhs) { return TYPE(std::move(rhs)); } \ + TYPE& assign_copy(const TYPE &rhs); \ + TYPE& assign_copy(TYPE &&rhs); \ + /* Copy a TYPE, generate new IDs. The front end will use this call. */ \ + TYPE* new_clone(const TYPE &rhs) { \ + /* Default constructor assigning an invalid ID. */ \ + auto obj = new TYPE(-1); \ + obj->assign_clone(rhs); \ + return obj; \ + } \ + TYPE make_clone(const TYPE &rhs) { \ + /* Default constructor assigning an invalid ID. */ \ + TYPE obj(-1); \ + obj.assign_clone(rhs); \ + return obj; \ + } \ + TYPE& assign_clone(const TYPE &rhs) { \ + this->assign_copy(rhs); \ + this->assign_new_unique_ids_recursive(); \ + return *this; \ + } + +#define MODELBASE_DERIVED_PRIVATE_COPY_MOVE(TYPE) \ +private: \ + /* Private constructor with an unused int parameter will create a TYPE instance with an invalid ID. */ \ + explicit TYPE(int) : ModelBase(-1) {}; \ + void assign_new_unique_ids_recursive(); + // Material, which may be shared across multiple ModelObjects of a single Model. class ModelMaterial : public ModelBase { @@ -119,15 +187,12 @@ public: when user expects that. */ Vec3d origin_translation; - // Assign a ModelObject to this object while keeping the original pointer to the parent Model. - // Make a deep copy. - ModelObject& assign(const ModelObject *rhs, bool copy_volumes = true); - Model* get_model() const { return m_model; }; ModelVolume* add_volume(const TriangleMesh &mesh); ModelVolume* add_volume(TriangleMesh &&mesh); ModelVolume* add_volume(const ModelVolume &volume); + ModelVolume* add_volume(const ModelVolume &volume, TriangleMesh &&mesh); void delete_volume(size_t idx); void clear_volumes(); bool is_multiparts() const { return volumes.size() > 1; } @@ -184,17 +249,16 @@ public: protected: friend class Print; - // Clone this ModelObject including its volumes and instances, keep the IDs of the copies equal to the original. - // Called by Print::apply() to clone the Model / ModelObject hierarchy to the back end for background processing. - ModelObject* clone(Model *parent); - void set_model(Model *model) { m_model = model; } + // Called by Print::apply() to set the model pointer after making a copy. + void set_model(Model *model) { m_model = model; } private: ModelObject(Model *model) : layer_height_profile_valid(false), m_model(model), origin_translation(Vec3d::Zero()), m_bounding_box_valid(false) {} - ModelObject(Model *model, const ModelObject &rhs, bool copy_volumes = true); - explicit ModelObject(ModelObject &rhs) = delete; + ModelObject(Model *model, const ModelObject &rhs); ~ModelObject(); - ModelObject& operator=(ModelObject &rhs) = default; + + MODELBASE_DERIVED_COPY_MOVE_CLONE(ModelObject) + MODELBASE_DERIVED_PRIVATE_COPY_MOVE(ModelObject) // Parent object, owning this ModelObject. Model *m_model; @@ -314,7 +378,7 @@ private: { this->set_material_id(other.material_id()); } - ModelVolume(ModelObject *object, const ModelVolume &other, const TriangleMesh &&mesh) : + ModelVolume(ModelObject *object, const ModelVolume &other, TriangleMesh &&mesh) : ModelBase(other), // copy the ID name(other.name), mesh(std::move(mesh)), config(other.config), m_type(other.m_type), object(object) { @@ -460,30 +524,32 @@ class Model : public ModelBase public: // Materials are owned by a model and referenced by objects through t_model_material_id. // Single material may be shared by multiple models. - ModelMaterialMap materials; + ModelMaterialMap materials; // Objects are owned by a model. Each model may have multiple instances, each instance having its own transformation (shift, scale, rotation). - ModelObjectPtrs objects; + ModelObjectPtrs objects; + // Default constructor assigns a new ID to the model. Model() {} - Model(const Model &rhs); - Model& operator=(const Model &rhs); ~Model() { this->clear_objects(); this->clear_materials(); } - // XXX: use fs::path ? + MODELBASE_DERIVED_COPY_MOVE_CLONE(Model) + static Model read_from_file(const std::string &input_file, DynamicPrintConfig *config = nullptr, bool add_default_instances = true); static Model read_from_archive(const std::string &input_file, DynamicPrintConfig *config, bool add_default_instances = true); /// Repair the ModelObjects of the current Model. /// This function calls repair function on each TriangleMesh of each model object volume - void repair(); + void repair(); + // Add a new ModelObject to this Model, generate a new ID for this ModelObject. ModelObject* add_object(); ModelObject* add_object(const char *name, const char *path, const TriangleMesh &mesh); ModelObject* add_object(const char *name, const char *path, TriangleMesh &&mesh); - ModelObject* add_object(const ModelObject &other, bool copy_volumes = true); - void delete_object(size_t idx); - void delete_object(ModelObject* object); - void clear_objects(); + ModelObject* add_object(const ModelObject &other); + void delete_object(size_t idx); + void delete_object(ModelID id); + void delete_object(ModelObject* object); + void clear_objects(); ModelMaterial* add_material(t_model_material_id material_id); ModelMaterial* add_material(t_model_material_id material_id, const ModelMaterial &other); @@ -520,8 +586,14 @@ public: static unsigned int get_auto_extruder_id(unsigned int max_extruders); static std::string get_auto_extruder_id_as_string(unsigned int max_extruders); static void reset_auto_extruder_id(); + +private: + MODELBASE_DERIVED_PRIVATE_COPY_MOVE(Model) }; +#undef MODELBASE_DERIVED_COPY_MOVE_CLONE +#undef MODELBASE_DERIVED_PRIVATE_COPY_MOVE + } #endif