WIP: Reconstruction of background processing update timer,
added unique IDs to the Model / ModelObject / ModelVolume objects, added a copy of Model hierarchy at the Print, WIP: new Print::apply() method to update the Print's copy of Model, to update the Print's PrintObjects, to update status of the Print and PrintObjects, and to possibly stop the background processing.
This commit is contained in:
parent
404ef147b3
commit
7ed2752b2b
@ -21,6 +21,8 @@ namespace Slic3r {
|
|||||||
|
|
||||||
unsigned int Model::s_auto_extruder_id = 1;
|
unsigned int Model::s_auto_extruder_id = 1;
|
||||||
|
|
||||||
|
ModelID ModelBase::s_last_id = 0;
|
||||||
|
|
||||||
Model::Model(const Model &other)
|
Model::Model(const Model &other)
|
||||||
{
|
{
|
||||||
// copy materials
|
// copy materials
|
||||||
@ -503,6 +505,7 @@ void Model::reset_auto_extruder_id()
|
|||||||
}
|
}
|
||||||
|
|
||||||
ModelObject::ModelObject(Model *model, const ModelObject &other, bool copy_volumes) :
|
ModelObject::ModelObject(Model *model, const ModelObject &other, bool copy_volumes) :
|
||||||
|
ModelBase(other), // copy the id
|
||||||
name(other.name),
|
name(other.name),
|
||||||
input_file(other.input_file),
|
input_file(other.input_file),
|
||||||
instances(),
|
instances(),
|
||||||
@ -518,13 +521,13 @@ ModelObject::ModelObject(Model *model, const ModelObject &other, bool copy_volum
|
|||||||
{
|
{
|
||||||
if (copy_volumes) {
|
if (copy_volumes) {
|
||||||
this->volumes.reserve(other.volumes.size());
|
this->volumes.reserve(other.volumes.size());
|
||||||
for (ModelVolumePtrs::const_iterator i = other.volumes.begin(); i != other.volumes.end(); ++i)
|
for (ModelVolume *model_volume : other.volumes)
|
||||||
this->add_volume(**i);
|
this->add_volume(*model_volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->instances.reserve(other.instances.size());
|
this->instances.reserve(other.instances.size());
|
||||||
for (ModelInstancePtrs::const_iterator i = other.instances.begin(); i != other.instances.end(); ++i)
|
for (const ModelInstance *model_instance : other.instances)
|
||||||
this->add_instance(**i);
|
this->add_instance(*model_instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelObject& ModelObject::operator=(ModelObject other)
|
ModelObject& ModelObject::operator=(ModelObject other)
|
||||||
@ -535,6 +538,7 @@ ModelObject& ModelObject::operator=(ModelObject other)
|
|||||||
|
|
||||||
void ModelObject::swap(ModelObject &other)
|
void ModelObject::swap(ModelObject &other)
|
||||||
{
|
{
|
||||||
|
std::swap(this->m_id, other.m_id);
|
||||||
std::swap(this->input_file, other.input_file);
|
std::swap(this->input_file, other.input_file);
|
||||||
std::swap(this->instances, other.instances);
|
std::swap(this->instances, other.instances);
|
||||||
std::swap(this->volumes, other.volumes);
|
std::swap(this->volumes, other.volumes);
|
||||||
@ -553,6 +557,13 @@ ModelObject::~ModelObject()
|
|||||||
this->clear_instances();
|
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)
|
||||||
|
{
|
||||||
|
return new ModelObject(parent, *this, true);
|
||||||
|
}
|
||||||
|
|
||||||
ModelVolume* ModelObject::add_volume(const TriangleMesh &mesh)
|
ModelVolume* ModelObject::add_volume(const TriangleMesh &mesh)
|
||||||
{
|
{
|
||||||
ModelVolume* v = new ModelVolume(this, mesh);
|
ModelVolume* v = new ModelVolume(this, mesh);
|
||||||
@ -903,7 +914,7 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
|
|||||||
new_volume->name = volume->name;
|
new_volume->name = volume->name;
|
||||||
new_volume->config = volume->config;
|
new_volume->config = volume->config;
|
||||||
new_volume->set_type(volume->type());
|
new_volume->set_type(volume->type());
|
||||||
new_volume->material_id(volume->material_id());
|
new_volume->set_material_id(volume->material_id());
|
||||||
|
|
||||||
new_objects->push_back(new_object);
|
new_objects->push_back(new_object);
|
||||||
delete mesh;
|
delete mesh;
|
||||||
@ -982,22 +993,22 @@ void ModelObject::print_info() const
|
|||||||
cout << "volume = " << mesh.volume() << endl;
|
cout << "volume = " << mesh.volume() << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelVolume::material_id(t_model_material_id material_id)
|
void ModelVolume::set_material_id(t_model_material_id material_id)
|
||||||
{
|
{
|
||||||
this->_material_id = material_id;
|
m_material_id = material_id;
|
||||||
|
|
||||||
// ensure this->_material_id references an existing material
|
// ensure m_material_id references an existing material
|
||||||
(void)this->object->get_model()->add_material(material_id);
|
(void)this->object->get_model()->add_material(material_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelMaterial* ModelVolume::material() const
|
ModelMaterial* ModelVolume::material() const
|
||||||
{
|
{
|
||||||
return this->object->get_model()->get_material(this->_material_id);
|
return this->object->get_model()->get_material(m_material_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelVolume::set_material(t_model_material_id material_id, const ModelMaterial &material)
|
void ModelVolume::set_material(t_model_material_id material_id, const ModelMaterial &material)
|
||||||
{
|
{
|
||||||
this->_material_id = material_id;
|
m_material_id = material_id;
|
||||||
(void)this->object->get_model()->add_material(material_id, material);
|
(void)this->object->get_model()->add_material(material_id, material);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1006,8 +1017,8 @@ ModelMaterial* ModelVolume::assign_unique_material()
|
|||||||
Model* model = this->get_object()->get_model();
|
Model* model = this->get_object()->get_model();
|
||||||
|
|
||||||
// as material-id "0" is reserved by the AMF spec we start from 1
|
// as material-id "0" is reserved by the AMF spec we start from 1
|
||||||
this->_material_id = 1 + model->materials.size(); // watchout for implicit cast
|
m_material_id = 1 + model->materials.size(); // watchout for implicit cast
|
||||||
return model->add_material(this->_material_id);
|
return model->add_material(m_material_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelVolume::calculate_convex_hull()
|
void ModelVolume::calculate_convex_hull()
|
||||||
|
@ -20,6 +20,7 @@ class ModelMaterial;
|
|||||||
class ModelObject;
|
class ModelObject;
|
||||||
class ModelVolume;
|
class ModelVolume;
|
||||||
class PresetBundle;
|
class PresetBundle;
|
||||||
|
class Print;
|
||||||
|
|
||||||
typedef std::string t_model_material_id;
|
typedef std::string t_model_material_id;
|
||||||
typedef std::string t_model_material_attribute;
|
typedef std::string t_model_material_attribute;
|
||||||
@ -30,8 +31,27 @@ typedef std::vector<ModelObject*> ModelObjectPtrs;
|
|||||||
typedef std::vector<ModelVolume*> ModelVolumePtrs;
|
typedef std::vector<ModelVolume*> ModelVolumePtrs;
|
||||||
typedef std::vector<ModelInstance*> ModelInstancePtrs;
|
typedef std::vector<ModelInstance*> 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;
|
||||||
|
|
||||||
|
// 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).
|
||||||
|
class ModelBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ModelID id() const { return m_id; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ModelID m_id = generate_new_id();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static inline ModelID generate_new_id() { return s_last_id ++; }
|
||||||
|
static ModelID s_last_id;
|
||||||
|
};
|
||||||
|
|
||||||
// Material, which may be shared across multiple ModelObjects of a single Model.
|
// Material, which may be shared across multiple ModelObjects of a single Model.
|
||||||
class ModelMaterial
|
class ModelMaterial : public ModelBase
|
||||||
{
|
{
|
||||||
friend class Model;
|
friend class Model;
|
||||||
public:
|
public:
|
||||||
@ -56,7 +76,7 @@ private:
|
|||||||
// and possibly having multiple modifier volumes, each modifier volume with its set of parameters and materials.
|
// and possibly having multiple modifier volumes, each modifier volume with its set of parameters and materials.
|
||||||
// Each ModelObject may be instantiated mutliple times, each instance having different placement on the print bed,
|
// Each ModelObject may be instantiated mutliple times, each instance having different placement on the print bed,
|
||||||
// different rotation and different uniform scaling.
|
// different rotation and different uniform scaling.
|
||||||
class ModelObject
|
class ModelObject : public ModelBase
|
||||||
{
|
{
|
||||||
friend class Model;
|
friend class Model;
|
||||||
public:
|
public:
|
||||||
@ -86,20 +106,20 @@ public:
|
|||||||
when user expects that. */
|
when user expects that. */
|
||||||
Vec3d origin_translation;
|
Vec3d origin_translation;
|
||||||
|
|
||||||
Model* get_model() const { return m_model; };
|
Model* get_model() const { return m_model; };
|
||||||
|
|
||||||
ModelVolume* add_volume(const TriangleMesh &mesh);
|
ModelVolume* add_volume(const TriangleMesh &mesh);
|
||||||
ModelVolume* add_volume(TriangleMesh &&mesh);
|
ModelVolume* add_volume(TriangleMesh &&mesh);
|
||||||
ModelVolume* add_volume(const ModelVolume &volume);
|
ModelVolume* add_volume(const ModelVolume &volume);
|
||||||
void delete_volume(size_t idx);
|
void delete_volume(size_t idx);
|
||||||
void clear_volumes();
|
void clear_volumes();
|
||||||
|
|
||||||
ModelInstance* add_instance();
|
ModelInstance* add_instance();
|
||||||
ModelInstance* add_instance(const ModelInstance &instance);
|
ModelInstance* add_instance(const ModelInstance &instance);
|
||||||
ModelInstance* add_instance(const Vec3d &offset, const Vec3d &scaling_factor, const Vec3d &rotation);
|
ModelInstance* add_instance(const Vec3d &offset, const Vec3d &scaling_factor, const Vec3d &rotation);
|
||||||
void delete_instance(size_t idx);
|
void delete_instance(size_t idx);
|
||||||
void delete_last_instance();
|
void delete_last_instance();
|
||||||
void clear_instances();
|
void clear_instances();
|
||||||
|
|
||||||
// Returns the bounding box of the transformed instances.
|
// Returns the bounding box of the transformed instances.
|
||||||
// This bounding box is approximate and not snug.
|
// This bounding box is approximate and not snug.
|
||||||
@ -138,6 +158,13 @@ public:
|
|||||||
// Print object statistics to console.
|
// Print object statistics to console.
|
||||||
void print_info() const;
|
void print_info() const;
|
||||||
|
|
||||||
|
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; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ModelObject(Model *model) : layer_height_profile_valid(false), m_model(model), origin_translation(Vec3d::Zero()), m_bounding_box_valid(false) {}
|
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 &other, bool copy_volumes = true);
|
ModelObject(Model *model, const ModelObject &other, bool copy_volumes = true);
|
||||||
@ -146,7 +173,7 @@ private:
|
|||||||
~ModelObject();
|
~ModelObject();
|
||||||
|
|
||||||
// Parent object, owning this ModelObject.
|
// Parent object, owning this ModelObject.
|
||||||
Model *m_model;
|
Model *m_model;
|
||||||
// Bounding box, cached.
|
// Bounding box, cached.
|
||||||
|
|
||||||
mutable BoundingBoxf3 m_bounding_box;
|
mutable BoundingBoxf3 m_bounding_box;
|
||||||
@ -155,20 +182,20 @@ private:
|
|||||||
|
|
||||||
// An object STL, or a modifier volume, over which a different set of parameters shall be applied.
|
// An object STL, or a modifier volume, over which a different set of parameters shall be applied.
|
||||||
// ModelVolume instances are owned by a ModelObject.
|
// ModelVolume instances are owned by a ModelObject.
|
||||||
class ModelVolume
|
class ModelVolume : public ModelBase
|
||||||
{
|
{
|
||||||
friend class ModelObject;
|
friend class ModelObject;
|
||||||
|
|
||||||
// The convex hull of this model's mesh.
|
// The convex hull of this model's mesh.
|
||||||
TriangleMesh m_convex_hull;
|
TriangleMesh m_convex_hull;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::string name;
|
std::string name;
|
||||||
// The triangular model.
|
// The triangular model.
|
||||||
TriangleMesh mesh;
|
TriangleMesh mesh;
|
||||||
// Configuration parameters specific to an object model geometry or a modifier volume,
|
// Configuration parameters specific to an object model geometry or a modifier volume,
|
||||||
// overriding the global Slic3r settings and the ModelObject settings.
|
// overriding the global Slic3r settings and the ModelObject settings.
|
||||||
DynamicPrintConfig config;
|
DynamicPrintConfig config;
|
||||||
|
|
||||||
enum Type {
|
enum Type {
|
||||||
MODEL_TYPE_INVALID = -1,
|
MODEL_TYPE_INVALID = -1,
|
||||||
@ -178,6 +205,9 @@ public:
|
|||||||
SUPPORT_BLOCKER,
|
SUPPORT_BLOCKER,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Clone this ModelVolume, keep the ID identical, set the parent to the cloned volume.
|
||||||
|
ModelVolume* clone(ModelObject *parent) { return new ModelVolume(parent, *this); }
|
||||||
|
|
||||||
// A parent object owning this modifier volume.
|
// A parent object owning this modifier volume.
|
||||||
ModelObject* get_object() const { return this->object; };
|
ModelObject* get_object() const { return this->object; };
|
||||||
Type type() const { return m_type; }
|
Type type() const { return m_type; }
|
||||||
@ -186,8 +216,9 @@ public:
|
|||||||
bool is_modifier() const { return m_type == PARAMETER_MODIFIER; }
|
bool is_modifier() const { return m_type == PARAMETER_MODIFIER; }
|
||||||
bool is_support_enforcer() const { return m_type == SUPPORT_ENFORCER; }
|
bool is_support_enforcer() const { return m_type == SUPPORT_ENFORCER; }
|
||||||
bool is_support_blocker() const { return m_type == SUPPORT_BLOCKER; }
|
bool is_support_blocker() const { return m_type == SUPPORT_BLOCKER; }
|
||||||
t_model_material_id material_id() const { return this->_material_id; }
|
bool is_support_modifier() const { return m_type == SUPPORT_BLOCKER || m_type == SUPPORT_ENFORCER; }
|
||||||
void material_id(t_model_material_id material_id);
|
t_model_material_id material_id() const { return m_material_id; }
|
||||||
|
void set_material_id(t_model_material_id material_id);
|
||||||
ModelMaterial* material() const;
|
ModelMaterial* material() const;
|
||||||
void set_material(t_model_material_id material_id, const ModelMaterial &material);
|
void set_material(t_model_material_id material_id, const ModelMaterial &material);
|
||||||
// Split this volume, append the result to the object owning this volume.
|
// Split this volume, append the result to the object owning this volume.
|
||||||
@ -199,7 +230,7 @@ public:
|
|||||||
|
|
||||||
void calculate_convex_hull();
|
void calculate_convex_hull();
|
||||||
const TriangleMesh& get_convex_hull() const;
|
const TriangleMesh& get_convex_hull() const;
|
||||||
TriangleMesh& get_convex_hull();
|
TriangleMesh& get_convex_hull();
|
||||||
|
|
||||||
// Helpers for loading / storing into AMF / 3MF files.
|
// Helpers for loading / storing into AMF / 3MF files.
|
||||||
static Type type_from_string(const std::string &s);
|
static Type type_from_string(const std::string &s);
|
||||||
@ -210,23 +241,26 @@ private:
|
|||||||
ModelObject* object;
|
ModelObject* object;
|
||||||
// Is it an object to be printed, or a modifier volume?
|
// Is it an object to be printed, or a modifier volume?
|
||||||
Type m_type;
|
Type m_type;
|
||||||
t_model_material_id _material_id;
|
t_model_material_id m_material_id;
|
||||||
|
|
||||||
ModelVolume(ModelObject *object, const TriangleMesh &mesh) : mesh(mesh), m_type(MODEL_PART), object(object)
|
ModelVolume(ModelObject *object, const TriangleMesh &mesh) : mesh(mesh), m_type(MODEL_PART), object(object)
|
||||||
{
|
{
|
||||||
if (mesh.stl.stats.number_of_facets > 1)
|
if (mesh.stl.stats.number_of_facets > 1)
|
||||||
calculate_convex_hull();
|
calculate_convex_hull();
|
||||||
}
|
}
|
||||||
ModelVolume(ModelObject *object, TriangleMesh &&mesh, TriangleMesh &&convex_hull) : mesh(std::move(mesh)), m_convex_hull(std::move(convex_hull)), m_type(MODEL_PART), object(object) {}
|
ModelVolume(ModelObject *object, TriangleMesh &&mesh, TriangleMesh &&convex_hull) :
|
||||||
|
mesh(std::move(mesh)), m_convex_hull(std::move(convex_hull)), m_type(MODEL_PART), object(object) {}
|
||||||
ModelVolume(ModelObject *object, const ModelVolume &other) :
|
ModelVolume(ModelObject *object, const ModelVolume &other) :
|
||||||
|
ModelBase(other), // copy the ID
|
||||||
name(other.name), mesh(other.mesh), m_convex_hull(other.m_convex_hull), config(other.config), m_type(other.m_type), object(object)
|
name(other.name), mesh(other.mesh), m_convex_hull(other.m_convex_hull), config(other.config), m_type(other.m_type), object(object)
|
||||||
{
|
{
|
||||||
this->material_id(other.material_id());
|
this->set_material_id(other.material_id());
|
||||||
}
|
}
|
||||||
ModelVolume(ModelObject *object, const ModelVolume &other, const TriangleMesh &&mesh) :
|
ModelVolume(ModelObject *object, const ModelVolume &other, const TriangleMesh &&mesh) :
|
||||||
|
ModelBase(other), // copy the ID
|
||||||
name(other.name), mesh(std::move(mesh)), config(other.config), m_type(other.m_type), object(object)
|
name(other.name), mesh(std::move(mesh)), config(other.config), m_type(other.m_type), object(object)
|
||||||
{
|
{
|
||||||
this->material_id(other.material_id());
|
this->set_material_id(other.material_id());
|
||||||
if (mesh.stl.stats.number_of_facets > 1)
|
if (mesh.stl.stats.number_of_facets > 1)
|
||||||
calculate_convex_hull();
|
calculate_convex_hull();
|
||||||
}
|
}
|
||||||
@ -234,7 +268,7 @@ private:
|
|||||||
|
|
||||||
// A single instance of a ModelObject.
|
// A single instance of a ModelObject.
|
||||||
// Knows the affine transformation of an object.
|
// Knows the affine transformation of an object.
|
||||||
class ModelInstance
|
class ModelInstance : public ModelBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum EPrintVolumeState : unsigned char
|
enum EPrintVolumeState : unsigned char
|
||||||
@ -321,7 +355,7 @@ private:
|
|||||||
// and with multiple modifier meshes.
|
// and with multiple modifier meshes.
|
||||||
// A model groups multiple objects, each object having possibly multiple instances,
|
// A model groups multiple objects, each object having possibly multiple instances,
|
||||||
// all objects may share mutliple materials.
|
// all objects may share mutliple materials.
|
||||||
class Model
|
class Model : public ModelBase
|
||||||
{
|
{
|
||||||
static unsigned int s_auto_extruder_id;
|
static unsigned int s_auto_extruder_id;
|
||||||
|
|
||||||
|
@ -571,6 +571,415 @@ exit_for_rearrange_regions:
|
|||||||
return invalidated;
|
return invalidated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test whether the two models contain the same number of ModelObjects with the same set of IDs
|
||||||
|
// ordered in the same order. In that case it is not necessary to kill the background processing.
|
||||||
|
static inline bool model_object_list_equal(const Model &model_old, const Model &model_new)
|
||||||
|
{
|
||||||
|
if (model_old.objects.size() != model_new.objects.size())
|
||||||
|
return false;
|
||||||
|
for (size_t i = 0; i < model_old.objects.size(); ++ i)
|
||||||
|
if (model_old.objects[i]->id() != model_new.objects[i]->id())
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test whether the new model is just an extension of the old model (new objects were added
|
||||||
|
// to the end of the original list. In that case it is not necessary to kill the background processing.
|
||||||
|
static inline bool model_object_list_extended(const Model &model_old, const Model &model_new)
|
||||||
|
{
|
||||||
|
if (model_old.objects.size() >= model_new.objects.size())
|
||||||
|
return false;
|
||||||
|
for (size_t i = 0; i < model_old.objects.size(); ++ i)
|
||||||
|
if (model_old.objects[i]->id() != model_new.objects[i]->id())
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool model_volume_list_changed(const ModelObject &model_object_old, const ModelObject &model_object_new, const ModelVolume::Type type)
|
||||||
|
{
|
||||||
|
bool modifiers_differ = false;
|
||||||
|
size_t i_old, i_new;
|
||||||
|
for (i_old = 0, i_new = 0; i_old < model_object_old.volumes.size() && i_new < model_object_new.volumes.size();) {
|
||||||
|
const ModelVolume &mv_old = *model_object_old.volumes[i_old];
|
||||||
|
const ModelVolume &mv_new = *model_object_new.volumes[i_old];
|
||||||
|
if (mv_old.type() != type) {
|
||||||
|
++ i_old;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (mv_new.type() != type) {
|
||||||
|
++ i_new;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (mv_old.id() != mv_new.id())
|
||||||
|
return true;
|
||||||
|
//FIXME test for the content of the mesh!
|
||||||
|
//FIXME test for the transformation matrices!
|
||||||
|
++ i_old;
|
||||||
|
++ i_new;
|
||||||
|
}
|
||||||
|
for (; i_old < model_object_old.volumes.size(); ++ i_old) {
|
||||||
|
const ModelVolume &mv_old = *model_object_old.volumes[i_old];
|
||||||
|
if (mv_old.type() == type)
|
||||||
|
// ModelVolume was deleted.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (; i_new < model_object_new.volumes.size(); ++ i_new) {
|
||||||
|
const ModelVolume &mv_new = *model_object_new.volumes[i_new];
|
||||||
|
if (mv_new.type() == type)
|
||||||
|
// ModelVolume was added.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void model_volume_list_update_supports(ModelObject &model_object_dst, const ModelObject &model_object_src)
|
||||||
|
{
|
||||||
|
// 1) Delete the support volumes from model_object_dst.
|
||||||
|
{
|
||||||
|
std::vector<ModelVolume*> dst;
|
||||||
|
dst.reserve(model_object_dst.volumes.size());
|
||||||
|
for (ModelVolume *vol : model_object_dst.volumes) {
|
||||||
|
if (vol->is_support_modifier())
|
||||||
|
dst.emplace_back(vol);
|
||||||
|
else
|
||||||
|
delete vol;
|
||||||
|
}
|
||||||
|
model_object_dst.volumes = std::move(dst);
|
||||||
|
}
|
||||||
|
// 2) Copy the support volumes from model_object_src to the end of model_object_dst.
|
||||||
|
for (ModelVolume *vol : model_object_src.volumes) {
|
||||||
|
if (vol->is_support_modifier())
|
||||||
|
model_object_dst.volumes.emplace_back(vol->clone(&model_object_dst));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool transform3d_lower(const Transform3d &lhs, const Transform3d &rhs)
|
||||||
|
{
|
||||||
|
typedef Transform3d::Scalar T;
|
||||||
|
const T *lv = lhs.data();
|
||||||
|
const T *rv = rhs.data();
|
||||||
|
for (size_t i = 0; i < 16; ++ i, ++ lv, ++ rv) {
|
||||||
|
if (*lv < *rv)
|
||||||
|
return true;
|
||||||
|
else if (*lv > *rv)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool transform3d_equal(const Transform3d &lhs, const Transform3d &rhs)
|
||||||
|
{
|
||||||
|
typedef Transform3d::Scalar T;
|
||||||
|
const T *lv = lhs.data();
|
||||||
|
const T *rv = rhs.data();
|
||||||
|
for (size_t i = 0; i < 16; ++ i, ++ lv, ++ rv)
|
||||||
|
if (*lv != *rv)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PrintInstances
|
||||||
|
{
|
||||||
|
Transform3d trafo;
|
||||||
|
Points instances;
|
||||||
|
bool operator<(const PrintInstances &rhs) const { return transform3d_lower(this->trafo, rhs.trafo); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generate a list of trafos and XY offsets for instances of a ModelObject
|
||||||
|
static std::vector<PrintInstances> print_objects_from_model_object(const ModelObject &model_object)
|
||||||
|
{
|
||||||
|
std::set<PrintInstances> trafos;
|
||||||
|
PrintInstances trafo;
|
||||||
|
trafo.instances.assign(1, Point());
|
||||||
|
for (ModelInstance *model_instance : model_object.instances)
|
||||||
|
if (model_instance->is_printable()) {
|
||||||
|
const Vec3d &offst = model_instance->get_offset();
|
||||||
|
trafo.trafo = model_instance->world_matrix(true);
|
||||||
|
trafo.instances.front() = Point::new_scale(offst(0), offst(1));
|
||||||
|
auto it = trafos.find(trafo);
|
||||||
|
if (it == trafos.end())
|
||||||
|
trafos.emplace(trafo);
|
||||||
|
else
|
||||||
|
const_cast<PrintInstances&>(*it).instances.emplace_back(trafo.instances.front());
|
||||||
|
}
|
||||||
|
return std::vector<PrintInstances>(trafos.begin(), trafos.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Print::apply(const Model &model, const DynamicPrintConfig &config)
|
||||||
|
{
|
||||||
|
// Grab the lock for the Print / PrintObject milestones.
|
||||||
|
tbb::mutex::scoped_lock lock(m_mutex);
|
||||||
|
|
||||||
|
struct ModelObjectStatus {
|
||||||
|
enum Status {
|
||||||
|
Unknown,
|
||||||
|
Old,
|
||||||
|
New,
|
||||||
|
Moved,
|
||||||
|
Deleted,
|
||||||
|
};
|
||||||
|
ModelObjectStatus(ModelID id, Status status = Unknown) : id(id), status(status) {}
|
||||||
|
ModelID id;
|
||||||
|
Status status;
|
||||||
|
// Search by id.
|
||||||
|
bool operator<(const ModelObjectStatus &rhs) const { return id < rhs.id; }
|
||||||
|
};
|
||||||
|
std::set<ModelObjectStatus> model_object_status;
|
||||||
|
|
||||||
|
// 1) Synchronize model objects.
|
||||||
|
if (model.id() != m_model.id()) {
|
||||||
|
// Kill everything, initialize from scratch.
|
||||||
|
// The following call shall kill any computation if running.
|
||||||
|
this->invalidate_all_steps();
|
||||||
|
for (PrintObject *object : m_objects) {
|
||||||
|
model_object_status.emplace(object->model_object()->id(), ModelObjectStatus::Deleted);
|
||||||
|
delete object;
|
||||||
|
}
|
||||||
|
m_objects.clear();
|
||||||
|
for (PrintRegion *region : m_regions)
|
||||||
|
delete region;
|
||||||
|
m_regions.clear();
|
||||||
|
m_model = model;
|
||||||
|
} else {
|
||||||
|
if (model_object_list_equal(m_model, model)) {
|
||||||
|
// The object list did not change.
|
||||||
|
} else if (model_object_list_extended(m_model, model)) {
|
||||||
|
// Add new objects. Their volumes and configs will be synchronized later.
|
||||||
|
this->invalidate_step(psGCodeExport);
|
||||||
|
for (size_t i = m_model.objects.size(); i < model.objects.size(); ++ i) {
|
||||||
|
model_object_status.emplace(model.objects[i]->id(), ModelObjectStatus::New);
|
||||||
|
m_model.objects.emplace_back(model.objects[i]->clone(&m_model));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Reorder the objects, add new objects.
|
||||||
|
// First stop background processing before shuffling or deleting the PrintObjects in the object list.
|
||||||
|
m_cancel_callback();
|
||||||
|
this->invalidate_step(psGCodeExport);
|
||||||
|
// Second create a new list of objects.
|
||||||
|
std::vector<ModelObject*> old(std::move(m_model.objects));
|
||||||
|
m_model.objects.clear();
|
||||||
|
m_model.objects.reserve(model.objects.size());
|
||||||
|
auto by_id_lower = [](const ModelObject *lhs, const ModelObject *rhs){ return lhs->id() < rhs->id(); };
|
||||||
|
std::sort(old.begin(), old.end(), by_id_lower);
|
||||||
|
for (const ModelObject *mobj : model.objects) {
|
||||||
|
auto it = std::lower_bound(old.begin(), old.end(), mobj, by_id_lower);
|
||||||
|
if (it == old.end() || (*it)->id() != mobj->id()) {
|
||||||
|
// New ModelObject added.
|
||||||
|
m_model.objects.emplace_back((*it)->clone(&m_model));
|
||||||
|
model_object_status.emplace(mobj->id(), ModelObjectStatus::New);
|
||||||
|
} else {
|
||||||
|
// Existing ModelObject re-added (possibly moved in the list).
|
||||||
|
m_model.objects.emplace_back(*it);
|
||||||
|
model_object_status.emplace(mobj->id(), ModelObjectStatus::Old);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool deleted_any = false;
|
||||||
|
for (ModelObject *mobj : old)
|
||||||
|
if (model_object_status.find(ModelObjectStatus(mobj->id())) == model_object_status.end()) {
|
||||||
|
model_object_status.emplace(mobj->id(), ModelObjectStatus::Deleted);
|
||||||
|
delete mobj;
|
||||||
|
deleted_any = true;
|
||||||
|
}
|
||||||
|
if (deleted_any) {
|
||||||
|
// Delete PrintObjects of the deleted ModelObjects.
|
||||||
|
std::vector<PrintObject*> old = std::move(m_objects);
|
||||||
|
m_objects.clear();
|
||||||
|
m_objects.reserve(old.size());
|
||||||
|
for (PrintObject *print_object : old) {
|
||||||
|
auto it_status = model_object_status.find(ModelObjectStatus(print_object->model_object()->id()));
|
||||||
|
assert(it_status != model_object_status.end());
|
||||||
|
if (it_status->status == ModelObjectStatus::Deleted) {
|
||||||
|
print_object->invalidate_all_steps();
|
||||||
|
delete print_object;
|
||||||
|
} else
|
||||||
|
m_objects.emplace_back(print_object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) Map print objects including their transformation matrices.
|
||||||
|
struct PrintObjectStatus {
|
||||||
|
enum Status {
|
||||||
|
Unknown,
|
||||||
|
Deleted,
|
||||||
|
New
|
||||||
|
};
|
||||||
|
PrintObjectStatus(PrintObject *print_object, Status status = Unknown) :
|
||||||
|
id(print_object->model_object()->id()),
|
||||||
|
print_object(print_object),
|
||||||
|
trafo(print_object->trafo()),
|
||||||
|
status(status) {}
|
||||||
|
PrintObjectStatus(ModelID id) : id(id), print_object(nullptr), trafo(Transform3d::Identity()), status(Unknown) {}
|
||||||
|
// ID of the ModelObject & PrintObject
|
||||||
|
ModelID id;
|
||||||
|
// Pointer to the old PrintObject
|
||||||
|
PrintObject *print_object;
|
||||||
|
// Trafo generated with model_object->world_matrix(true)
|
||||||
|
Transform3d trafo;
|
||||||
|
Status status;
|
||||||
|
// Search by id.
|
||||||
|
bool operator<(const PrintObjectStatus &rhs) const { return id < rhs.id; }
|
||||||
|
};
|
||||||
|
std::multiset<PrintObjectStatus> print_object_status;
|
||||||
|
for (PrintObject *print_object : m_objects)
|
||||||
|
print_object_status.emplace(PrintObjectStatus(print_object));
|
||||||
|
|
||||||
|
// 3) Synchronize ModelObjects & PrintObjects.
|
||||||
|
for (size_t idx_model_object = 0; idx_model_object < model.objects.size(); ++ idx_model_object) {
|
||||||
|
ModelObject &model_object = *m_model.objects[idx_model_object];
|
||||||
|
auto it_status = model_object_status.find(ModelObjectStatus(model_object.id()));
|
||||||
|
assert(it_status != model_object_status.end());
|
||||||
|
assert(it_status->status != ModelObjectStatus::Deleted);
|
||||||
|
if (it_status->status == ModelObjectStatus::New)
|
||||||
|
// PrintObject instances will be added in the next loop.
|
||||||
|
continue;
|
||||||
|
// Update the ModelObject instance, possibly invalidate the linked PrintObjects.
|
||||||
|
assert(it_status->status == ModelObjectStatus::Moved);
|
||||||
|
const ModelObject &model_object_new = *model.objects[idx_model_object];
|
||||||
|
// Check whether a model part volume was added or removed, their transformations or order changed.
|
||||||
|
bool model_parts_differ = model_volume_list_changed(model_object, model_object_new, ModelVolume::MODEL_PART);
|
||||||
|
bool modifiers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolume::PARAMETER_MODIFIER);
|
||||||
|
bool support_blockers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolume::SUPPORT_BLOCKER);
|
||||||
|
bool support_enforcers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolume::SUPPORT_ENFORCER);
|
||||||
|
if (model_parts_differ || modifiers_differ) {
|
||||||
|
// The very first step (the slicing step) is invalidated. One may freely remove all associated PrintObjects.
|
||||||
|
auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id()));
|
||||||
|
for (auto it = range.first; it != range.second; ++ it) {
|
||||||
|
it->print_object->invalidate_all_steps();
|
||||||
|
const_cast<PrintObjectStatus&>(*it).status = PrintObjectStatus::Deleted;
|
||||||
|
}
|
||||||
|
// Copy content of the ModelObject including its ID, reset the parent.
|
||||||
|
model_object = model_object_new;
|
||||||
|
model_object.set_model(&m_model);
|
||||||
|
} else if (support_blockers_differ || support_enforcers_differ) {
|
||||||
|
// First stop background processing before shuffling or deleting the ModelVolumes in the ModelObject's list.
|
||||||
|
m_cancel_callback();
|
||||||
|
// Invalidate just the supports step.
|
||||||
|
auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id()));
|
||||||
|
for (auto it = range.first; it != range.second; ++ it)
|
||||||
|
it->print_object->invalidate_step(posSupportMaterial);
|
||||||
|
// Copy just the support volumes.
|
||||||
|
model_volume_list_update_supports(model_object, model_object_new);
|
||||||
|
}
|
||||||
|
if (! model_parts_differ && ! modifiers_differ) {
|
||||||
|
// Synchronize the remaining data of ModelVolumes (name, config, m_type, m_material_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4) Generate PrintObjects from ModelObjects and their instances.
|
||||||
|
std::vector<PrintObject*> print_objects_new;
|
||||||
|
print_objects_new.reserve(std::max(m_objects.size(), m_model.objects.size()));
|
||||||
|
// Walk over all new model objects and check, whether there are matching PrintObjects.
|
||||||
|
for (ModelObject *model_object : m_model.objects) {
|
||||||
|
auto range = print_object_status.equal_range(PrintObjectStatus(model_object->id()));
|
||||||
|
std::vector<const PrintObjectStatus*> old;
|
||||||
|
if (range.first != range.second) {
|
||||||
|
old.reserve(print_object_status.count(PrintObjectStatus(model_object->id())));
|
||||||
|
for (auto it = range.first; it != range.second; ++ it)
|
||||||
|
if (it->status != PrintObjectStatus::Deleted)
|
||||||
|
old.emplace_back(&(*it));
|
||||||
|
}
|
||||||
|
// Generate a list of trafos and XY offsets for instances of a ModelObject
|
||||||
|
std::vector<PrintInstances> new_print_instances = print_objects_from_model_object(*model_object);
|
||||||
|
if (old.empty()) {
|
||||||
|
// Simple case, just generate new instances.
|
||||||
|
for (const PrintInstances &print_instances : new_print_instances) {
|
||||||
|
PrintObject *print_object = new PrintObject(this, model_object, model_object->raw_bounding_box());
|
||||||
|
print_objects_new.emplace_back(print_object);
|
||||||
|
print_object_status.emplace(PrintObjectStatus(print_object, PrintObjectStatus::New));
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Complex case, try to merge the two lists.
|
||||||
|
// Sort the old lexicographically by their trafos.
|
||||||
|
std::sort(old.begin(), old.end(), [](const PrintObjectStatus *lhs, const PrintObjectStatus *rhs){ return transform3d_lower(lhs->trafo, rhs->trafo); });
|
||||||
|
// Merge the old / new lists.
|
||||||
|
|
||||||
|
}
|
||||||
|
if (m_objects != print_objects_new) {
|
||||||
|
m_cancel_callback();
|
||||||
|
m_objects = print_objects_new;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Synchronize materials.
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
{
|
||||||
|
m_model = model;
|
||||||
|
for (const ModelObject *model_object : m_model.objects) {
|
||||||
|
PrintObject *object = new PrintObject(this, model_object, model_object->raw_bounding_box());
|
||||||
|
m_objects.emplace_back(object);
|
||||||
|
size_t volume_id = 0;
|
||||||
|
for (const ModelVolume *volume : model_object->volumes) {
|
||||||
|
if (! volume->is_model_part() && ! volume->is_modifier())
|
||||||
|
continue;
|
||||||
|
// Get the config applied to this volume.
|
||||||
|
PrintRegionConfig config = this->_region_config_from_model_volume(*volume);
|
||||||
|
// Find an existing print region with the same config.
|
||||||
|
size_t region_id = size_t(-1);
|
||||||
|
for (size_t i = 0; i < m_regions.size(); ++ i)
|
||||||
|
if (config.equals(m_regions[i]->config())) {
|
||||||
|
region_id = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// If no region exists with the same config, create a new one.
|
||||||
|
if (region_id == size_t(-1)) {
|
||||||
|
region_id = m_regions.size();
|
||||||
|
this->add_region(config);
|
||||||
|
}
|
||||||
|
// Assign volume to a region.
|
||||||
|
object->add_region_volume(region_id, volume_id);
|
||||||
|
++ volume_id;
|
||||||
|
}
|
||||||
|
// Apply config to print object.
|
||||||
|
object->config_apply(this->default_object_config());
|
||||||
|
{
|
||||||
|
//normalize_and_apply_config(object->config(), model_object->config);
|
||||||
|
DynamicPrintConfig src_normalized(model_object->config);
|
||||||
|
src_normalized.normalize();
|
||||||
|
object->config_apply(src_normalized, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Synchronize m_model.objects with model.objects
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
this->update_object_placeholders();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update "scale", "input_filename", "input_filename_base" placeholders from the current m_objects.
|
||||||
|
void Print::update_object_placeholders()
|
||||||
|
{
|
||||||
|
// get the first input file name
|
||||||
|
std::string input_file;
|
||||||
|
std::vector<std::string> v_scale;
|
||||||
|
for (const PrintObject *object : m_objects) {
|
||||||
|
const ModelObject &mobj = *object->model_object();
|
||||||
|
#if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
|
||||||
|
// CHECK_ME -> Is the following correct ?
|
||||||
|
v_scale.push_back("x:" + boost::lexical_cast<std::string>(mobj.instances[0]->get_scaling_factor(X) * 100) +
|
||||||
|
"% y:" + boost::lexical_cast<std::string>(mobj.instances[0]->get_scaling_factor(Y) * 100) +
|
||||||
|
"% z:" + boost::lexical_cast<std::string>(mobj.instances[0]->get_scaling_factor(Z) * 100) + "%");
|
||||||
|
#else
|
||||||
|
v_scale.push_back(boost::lexical_cast<std::string>(mobj.instances[0]->scaling_factor * 100) + "%");
|
||||||
|
#endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
|
||||||
|
if (input_file.empty())
|
||||||
|
input_file = mobj.input_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlaceholderParser &pp = m_placeholder_parser;
|
||||||
|
pp.set("scale", v_scale);
|
||||||
|
if (! input_file.empty()) {
|
||||||
|
// get basename with and without suffix
|
||||||
|
const std::string input_basename = boost::filesystem::path(input_file).filename().string();
|
||||||
|
pp.set("input_filename", input_basename);
|
||||||
|
const std::string input_basename_base = input_basename.substr(0, input_basename.find_last_of("."));
|
||||||
|
pp.set("input_filename_base", input_basename_base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Print::has_infinite_skirt() const
|
bool Print::has_infinite_skirt() const
|
||||||
{
|
{
|
||||||
return (m_config.skirt_height == -1 && m_config.skirts > 0)
|
return (m_config.skirt_height == -1 && m_config.skirts > 0)
|
||||||
|
@ -194,6 +194,7 @@ public:
|
|||||||
void config_apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false) { this->m_config.apply_only(other, keys, ignore_nonexistent); }
|
void config_apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false) { this->m_config.apply_only(other, keys, ignore_nonexistent); }
|
||||||
const LayerPtrs& layers() const { return m_layers; }
|
const LayerPtrs& layers() const { return m_layers; }
|
||||||
const SupportLayerPtrs& support_layers() const { return m_support_layers; }
|
const SupportLayerPtrs& support_layers() const { return m_support_layers; }
|
||||||
|
const Transform3d& trafo() const { return m_trafo; }
|
||||||
|
|
||||||
const Points& copies() const { return m_copies; }
|
const Points& copies() const { return m_copies; }
|
||||||
bool add_copy(const Vec2d &point);
|
bool add_copy(const Vec2d &point);
|
||||||
@ -285,6 +286,8 @@ private:
|
|||||||
Print *m_print;
|
Print *m_print;
|
||||||
ModelObject *m_model_object;
|
ModelObject *m_model_object;
|
||||||
PrintObjectConfig m_config;
|
PrintObjectConfig m_config;
|
||||||
|
// Translation in Z + Rotation + Scaling / Mirroring.
|
||||||
|
Transform3d m_trafo = Transform3d::Identity();
|
||||||
// Slic3r::Point objects in scaled G-code coordinates
|
// Slic3r::Point objects in scaled G-code coordinates
|
||||||
Points m_copies;
|
Points m_copies;
|
||||||
// scaled coordinates to add to copies (to compensate for the alignment
|
// scaled coordinates to add to copies (to compensate for the alignment
|
||||||
@ -382,6 +385,8 @@ public:
|
|||||||
bool reload_model_instances();
|
bool reload_model_instances();
|
||||||
void add_model_object(ModelObject* model_object, int idx = -1);
|
void add_model_object(ModelObject* model_object, int idx = -1);
|
||||||
bool apply_config(DynamicPrintConfig config);
|
bool apply_config(DynamicPrintConfig config);
|
||||||
|
bool apply(const Model &model, const DynamicPrintConfig &config);
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
void export_gcode(const std::string &path_template, GCodePreviewData *preview_data);
|
void export_gcode(const std::string &path_template, GCodePreviewData *preview_data);
|
||||||
// SLA export, temporary.
|
// SLA export, temporary.
|
||||||
@ -477,6 +482,9 @@ protected:
|
|||||||
PrintRegion* add_region(const PrintRegionConfig &config);
|
PrintRegion* add_region(const PrintRegionConfig &config);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Update "scale", "input_filename", "input_filename_base" placeholders from the current m_objects.
|
||||||
|
void update_object_placeholders();
|
||||||
|
|
||||||
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
|
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
|
||||||
PrintRegionConfig _region_config_from_model_volume(const ModelVolume &volume);
|
PrintRegionConfig _region_config_from_model_volume(const ModelVolume &volume);
|
||||||
|
|
||||||
@ -503,6 +511,7 @@ private:
|
|||||||
// Callback to be evoked to stop the background processing before a state is updated.
|
// Callback to be evoked to stop the background processing before a state is updated.
|
||||||
cancel_callback_type m_cancel_callback = [](){};
|
cancel_callback_type m_cancel_callback = [](){};
|
||||||
|
|
||||||
|
Model m_model;
|
||||||
PrintConfig m_config;
|
PrintConfig m_config;
|
||||||
PrintObjectConfig m_default_object_config;
|
PrintObjectConfig m_default_object_config;
|
||||||
PrintRegionConfig m_default_region_config;
|
PrintRegionConfig m_default_region_config;
|
||||||
|
@ -159,7 +159,7 @@ void MainFrame::init_tabpanel()
|
|||||||
if (m_plater) {
|
if (m_plater) {
|
||||||
// load initial config
|
// load initial config
|
||||||
auto full_config = wxGetApp().preset_bundle->full_config();
|
auto full_config = wxGetApp().preset_bundle->full_config();
|
||||||
m_plater->on_config_change(&full_config);
|
m_plater->on_config_change(full_config);
|
||||||
|
|
||||||
// Show a correct number of filament fields.
|
// Show a correct number of filament fields.
|
||||||
// nozzle_diameter is undefined when SLA printer is selected
|
// nozzle_diameter is undefined when SLA printer is selected
|
||||||
@ -530,9 +530,10 @@ void MainFrame::quick_slice(const int qs){
|
|||||||
// Slic3r::GUI::catch_error(this, [](){ if (m_progress_dialog) m_progress_dialog->Destroy(); });
|
// Slic3r::GUI::catch_error(this, [](){ if (m_progress_dialog) m_progress_dialog->Destroy(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainFrame::reslice_now(){
|
void MainFrame::reslice_now()
|
||||||
// if (m_plater)
|
{
|
||||||
// m_plater->reslice();
|
if (m_plater)
|
||||||
|
m_plater->reslice();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainFrame::repair_stl()
|
void MainFrame::repair_stl()
|
||||||
@ -611,12 +612,13 @@ void MainFrame::load_config_file(wxString file/* = wxEmptyString*/)
|
|||||||
file = dlg->GetPath();
|
file = dlg->GetPath();
|
||||||
dlg->Destroy();
|
dlg->Destroy();
|
||||||
}
|
}
|
||||||
// eval{
|
try {
|
||||||
wxGetApp().preset_bundle->load_config_file(file.ToStdString());
|
wxGetApp().preset_bundle->load_config_file(file.ToStdString());
|
||||||
// };
|
} catch (std::exception & /* ex */) {
|
||||||
// Dont proceed further if the config file cannot be loaded.
|
// Dont proceed further if the config file cannot be loaded.
|
||||||
// if (Slic3r::GUI::catch_error(this))
|
// if (Slic3r::GUI::catch_error(this))
|
||||||
// return;
|
// return;
|
||||||
|
}
|
||||||
for (auto tab : m_options_tabs )
|
for (auto tab : m_options_tabs )
|
||||||
tab.second->load_current_preset();
|
tab.second->load_current_preset();
|
||||||
wxGetApp().app_config->update_config_dir(get_dir_name(file));
|
wxGetApp().app_config->update_config_dir(get_dir_name(file));
|
||||||
@ -644,18 +646,20 @@ void MainFrame::export_configbundle()
|
|||||||
dlg->Destroy();
|
dlg->Destroy();
|
||||||
if (!file.IsEmpty()) {
|
if (!file.IsEmpty()) {
|
||||||
// Export the config bundle.
|
// Export the config bundle.
|
||||||
wxGetApp().app_config->update_config_dir(get_dir_name(file));
|
wxGetApp().app_config->update_config_dir(get_dir_name(file));
|
||||||
// eval{
|
try {
|
||||||
wxGetApp().preset_bundle->export_configbundle(file.ToStdString());
|
wxGetApp().preset_bundle->export_configbundle(file.ToStdString());
|
||||||
// };
|
} catch (std::exception & /* ex */) {
|
||||||
// Slic3r::GUI::catch_error(this);
|
// Slic3r::GUI::catch_error(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loading a config bundle with an external file name used to be used
|
// Loading a config bundle with an external file name used to be used
|
||||||
// to auto - install a config bundle on a fresh user account,
|
// to auto - install a config bundle on a fresh user account,
|
||||||
// but that behavior was not documented and likely buggy.
|
// but that behavior was not documented and likely buggy.
|
||||||
void MainFrame::load_configbundle(wxString file/* = wxEmptyString, const bool reset_user_profile*/){
|
void MainFrame::load_configbundle(wxString file/* = wxEmptyString, const bool reset_user_profile*/)
|
||||||
|
{
|
||||||
if (!wxGetApp().check_unsaved_changes())
|
if (!wxGetApp().check_unsaved_changes())
|
||||||
return;
|
return;
|
||||||
if (file.IsEmpty()) {
|
if (file.IsEmpty()) {
|
||||||
@ -671,10 +675,11 @@ void MainFrame::load_configbundle(wxString file/* = wxEmptyString, const bool re
|
|||||||
wxGetApp().app_config->update_config_dir(get_dir_name(file));
|
wxGetApp().app_config->update_config_dir(get_dir_name(file));
|
||||||
|
|
||||||
auto presets_imported = 0;
|
auto presets_imported = 0;
|
||||||
// eval{
|
try {
|
||||||
presets_imported = wxGetApp().preset_bundle->load_configbundle(file.ToStdString());
|
presets_imported = wxGetApp().preset_bundle->load_configbundle(file.ToStdString());
|
||||||
// };
|
} catch (std::exception & /* ex */) {
|
||||||
// Slic3r::GUI::catch_error(this) and return;
|
// Slic3r::GUI::catch_error(this) and return;
|
||||||
|
}
|
||||||
|
|
||||||
// Load the currently selected preset into the GUI, update the preset selection box.
|
// Load the currently selected preset into the GUI, update the preset selection box.
|
||||||
for (auto tab : m_options_tabs)
|
for (auto tab : m_options_tabs)
|
||||||
@ -686,20 +691,24 @@ void MainFrame::load_configbundle(wxString file/* = wxEmptyString, const bool re
|
|||||||
|
|
||||||
// Load a provied DynamicConfig into the Print / Filament / Printer tabs, thus modifying the active preset.
|
// Load a provied DynamicConfig into the Print / Filament / Printer tabs, thus modifying the active preset.
|
||||||
// Also update the platter with the new presets.
|
// Also update the platter with the new presets.
|
||||||
void MainFrame::load_config(const DynamicPrintConfig& config){
|
void MainFrame::load_config(const DynamicPrintConfig& config)
|
||||||
|
{
|
||||||
for (auto tab : m_options_tabs)
|
for (auto tab : m_options_tabs)
|
||||||
tab.second->load_config(config);
|
tab.second->load_config(config);
|
||||||
// if (m_plater) m_plater->on_config_change(config);
|
if (m_plater)
|
||||||
|
m_plater->on_config_change(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainFrame::select_tab(size_t tab) const{
|
void MainFrame::select_tab(size_t tab) const
|
||||||
|
{
|
||||||
m_tabpanel->SetSelection(tab);
|
m_tabpanel->SetSelection(tab);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set a camera direction, zoom to all objects.
|
// Set a camera direction, zoom to all objects.
|
||||||
void MainFrame::select_view(const std::string& direction){
|
void MainFrame::select_view(const std::string& direction)
|
||||||
// if (m_plater)
|
{
|
||||||
// m_plater->select_view(direction);
|
// if (m_plater)
|
||||||
|
// m_plater->select_view(direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
wxMenuItem* MainFrame::append_menu_item(wxMenu* menu,
|
wxMenuItem* MainFrame::append_menu_item(wxMenu* menu,
|
||||||
@ -743,8 +752,7 @@ void MainFrame::on_presets_changed(SimpleEvent &event)
|
|||||||
if (preset_type == Slic3r::Preset::TYPE_PRINTER) {
|
if (preset_type == Slic3r::Preset::TYPE_PRINTER) {
|
||||||
// Printer selected at the Printer tab, update "compatible" marks at the print and filament selectors.
|
// Printer selected at the Printer tab, update "compatible" marks at the print and filament selectors.
|
||||||
// XXX: Do this in a more C++ way
|
// XXX: Do this in a more C++ way
|
||||||
std::vector<std::string> tab_names_other = { "print", "filament", "sla_material" };
|
for (const auto tab_name_other : { "print", "filament", "sla_material" }) {
|
||||||
for (const auto tab_name_other : tab_names_other) {
|
|
||||||
Tab* cur_tab = m_options_tabs[tab_name_other];
|
Tab* cur_tab = m_options_tabs[tab_name_other];
|
||||||
// If the printer tells us that the print or filament preset has been switched or invalidated,
|
// If the printer tells us that the print or filament preset has been switched or invalidated,
|
||||||
// refresh the print or filament tab page.Otherwise just refresh the combo box.
|
// refresh the print or filament tab page.Otherwise just refresh the combo box.
|
||||||
@ -756,8 +764,7 @@ void MainFrame::on_presets_changed(SimpleEvent &event)
|
|||||||
cur_tab->load_current_preset();
|
cur_tab->load_current_preset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// XXX: ?
|
m_plater->on_config_change(*tab->get_config());
|
||||||
// m_plater->on_config_change(tab->get_config());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -769,18 +776,19 @@ void MainFrame::on_value_changed(wxCommandEvent& event)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
auto opt_key = event.GetString();
|
auto opt_key = event.GetString();
|
||||||
auto config = tab->get_config();
|
|
||||||
if (m_plater) {
|
if (m_plater) {
|
||||||
m_plater->on_config_change(config); // propagate config change events to the plater
|
m_plater->on_config_change(*tab->get_config()); // propagate config change events to the plater
|
||||||
if (opt_key == "extruders_count"){
|
if (opt_key == "extruders_count"){
|
||||||
auto value = event.GetInt();
|
auto value = event.GetInt();
|
||||||
m_plater->on_extruders_change(value);
|
m_plater->on_extruders_change(value);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// Don't save while loading for the first time.
|
||||||
|
if (m_loaded) {
|
||||||
|
AppConfig &cfg = *wxGetApp().app_config;
|
||||||
|
if (cfg.get("autosave") == "1")
|
||||||
|
cfg.save();
|
||||||
}
|
}
|
||||||
// don't save while loading for the first time
|
|
||||||
// #ys_FIXME ?autosave?
|
|
||||||
// if (wxGetApp().autosave && m_loaded)
|
|
||||||
// m_config->save(wxGetApp().autosave);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called after the Preferences dialog is closed and the program settings are saved.
|
// Called after the Preferences dialog is closed and the program settings are saved.
|
||||||
|
@ -209,6 +209,7 @@ PresetComboBox::PresetComboBox(wxWindow *parent, Preset::Type preset_type) :
|
|||||||
if (dialog->ShowModal() == wxID_OK) {
|
if (dialog->ShowModal() == wxID_OK) {
|
||||||
DynamicPrintConfig cfg = *wxGetApp().get_tab(Preset::TYPE_PRINTER)->get_config();
|
DynamicPrintConfig cfg = *wxGetApp().get_tab(Preset::TYPE_PRINTER)->get_config();
|
||||||
|
|
||||||
|
//FIXME this is too expensive to call full_config to get just the extruder color!
|
||||||
auto colors = static_cast<ConfigOptionStrings*>(wxGetApp().preset_bundle->full_config().option("extruder_colour")->clone());
|
auto colors = static_cast<ConfigOptionStrings*>(wxGetApp().preset_bundle->full_config().option("extruder_colour")->clone());
|
||||||
colors->values[extruder_idx] = dialog->GetColourData().GetColour().GetAsString(wxC2S_HTML_SYNTAX);
|
colors->values[extruder_idx] = dialog->GetColourData().GetColour().GetAsString(wxC2S_HTML_SYNTAX);
|
||||||
|
|
||||||
@ -216,7 +217,7 @@ PresetComboBox::PresetComboBox(wxWindow *parent, Preset::Type preset_type) :
|
|||||||
|
|
||||||
wxGetApp().get_tab(Preset::TYPE_PRINTER)->load_config(cfg);
|
wxGetApp().get_tab(Preset::TYPE_PRINTER)->load_config(cfg);
|
||||||
wxGetApp().preset_bundle->update_platter_filament_ui(extruder_idx, this);
|
wxGetApp().preset_bundle->update_platter_filament_ui(extruder_idx, this);
|
||||||
wxGetApp().plater()->on_config_change(&cfg);
|
wxGetApp().plater()->on_config_change(cfg);
|
||||||
}
|
}
|
||||||
dialog->Destroy();
|
dialog->Destroy();
|
||||||
});
|
});
|
||||||
@ -741,7 +742,8 @@ struct Plater::priv
|
|||||||
Sidebar *sidebar;
|
Sidebar *sidebar;
|
||||||
wxGLCanvas *canvas3D; // TODO: Use GLCanvas3D when we can
|
wxGLCanvas *canvas3D; // TODO: Use GLCanvas3D when we can
|
||||||
Preview *preview;
|
Preview *preview;
|
||||||
BackgroundSlicingProcess background_process;
|
BackgroundSlicingProcess background_process;
|
||||||
|
wxTimer background_process_timer;
|
||||||
|
|
||||||
static const std::regex pattern_bundle;
|
static const std::regex pattern_bundle;
|
||||||
static const std::regex pattern_3mf;
|
static const std::regex pattern_3mf;
|
||||||
@ -855,15 +857,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) :
|
|||||||
_3DScene::enable_shader(canvas3D, true);
|
_3DScene::enable_shader(canvas3D, true);
|
||||||
_3DScene::enable_force_zoom_to_bed(canvas3D, true);
|
_3DScene::enable_force_zoom_to_bed(canvas3D, true);
|
||||||
|
|
||||||
// XXX: apply_config_timer
|
background_process_timer.Bind(wxEVT_TIMER, [this](wxTimerEvent &evt){ this->async_apply_config(); }, 0);
|
||||||
// {
|
|
||||||
// my $timer_id = Wx::NewId();
|
|
||||||
// $self->{apply_config_timer} = Wx::Timer->new($self, $timer_id);
|
|
||||||
// EVT_TIMER($self, $timer_id, sub {
|
|
||||||
// my ($self, $event) = @_;
|
|
||||||
// $self->async_apply_config;
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
auto *bed_shape = config->opt<ConfigOptionPoints>("bed_shape");
|
auto *bed_shape = config->opt<ConfigOptionPoints>("bed_shape");
|
||||||
_3DScene::set_bed_shape(canvas3D, bed_shape->values);
|
_3DScene::set_bed_shape(canvas3D, bed_shape->values);
|
||||||
@ -961,7 +955,7 @@ void Plater::priv::update(bool force_autocenter)
|
|||||||
preview->reset_gcode_preview_data();
|
preview->reset_gcode_preview_data();
|
||||||
preview->reload_print();
|
preview->reload_print();
|
||||||
|
|
||||||
// schedule_background_process(); // TODO
|
schedule_background_process();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::priv::update_ui_from_settings()
|
void Plater::priv::update_ui_from_settings()
|
||||||
@ -1172,7 +1166,7 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode
|
|||||||
_3DScene::zoom_to_volumes(canvas3D);
|
_3DScene::zoom_to_volumes(canvas3D);
|
||||||
object_list_changed();
|
object_list_changed();
|
||||||
|
|
||||||
// $self->schedule_background_process;
|
this->schedule_background_process();
|
||||||
|
|
||||||
return obj_idxs;
|
return obj_idxs;
|
||||||
}
|
}
|
||||||
@ -1449,12 +1443,40 @@ void Plater::priv::split_object()
|
|||||||
|
|
||||||
void Plater::priv::schedule_background_process()
|
void Plater::priv::schedule_background_process()
|
||||||
{
|
{
|
||||||
// TODO
|
// Trigger the timer event after 0.5s
|
||||||
|
this->background_process_timer.Start(500, wxTIMER_ONE_SHOT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::priv::async_apply_config()
|
void Plater::priv::async_apply_config()
|
||||||
{
|
{
|
||||||
// TODO
|
// Apply new config to the possibly running background task.
|
||||||
|
bool was_running = this->background_process.running();
|
||||||
|
bool invalidated = this->background_process.apply_config(wxGetApp().preset_bundle->full_config());
|
||||||
|
// Just redraw the 3D canvas without reloading the scene to consume the update of the layer height profile.
|
||||||
|
if (Slic3r::_3DScene::is_layers_editing_enabled(this->canvas3D))
|
||||||
|
this->canvas3D->Refresh();
|
||||||
|
// If the apply_config caused the calculation to stop, or it was not running yet:
|
||||||
|
if (invalidated) {
|
||||||
|
if (was_running) {
|
||||||
|
// Hide the slicing results if the current slicing status is no more valid.
|
||||||
|
this->sidebar->show_info_sizers(false);
|
||||||
|
}
|
||||||
|
if (this->get_config("background_processing") == "1")
|
||||||
|
this->background_process.start();
|
||||||
|
if (was_running) {
|
||||||
|
// Reset preview canvases. If the print has been invalidated, the preview canvases will be cleared.
|
||||||
|
// Otherwise they will be just refreshed.
|
||||||
|
this->gcode_preview_data.reset();
|
||||||
|
if (this->preview != nullptr)
|
||||||
|
this->preview->reload_print();
|
||||||
|
// We also need to reload 3D scene because of the wipe tower preview box
|
||||||
|
if (this->config->opt_bool("wipe_tower")) {
|
||||||
|
std::vector<int> selections = this->collect_selections();
|
||||||
|
Slic3r::_3DScene::set_objects_selections(this->canvas3D, selections);
|
||||||
|
Slic3r::_3DScene::reload_scene(this->canvas3D, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::priv::start_background_process()
|
void Plater::priv::start_background_process()
|
||||||
@ -1542,8 +1564,7 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt)
|
|||||||
// Synchronize config.ini with the current selections.
|
// Synchronize config.ini with the current selections.
|
||||||
wxGetApp().preset_bundle->export_selections(*wxGetApp().app_config);
|
wxGetApp().preset_bundle->export_selections(*wxGetApp().app_config);
|
||||||
// update plater with new config
|
// update plater with new config
|
||||||
auto config = wxGetApp().preset_bundle->full_config();
|
wxGetApp().plater()->on_config_change(wxGetApp().preset_bundle->full_config());
|
||||||
wxGetApp().plater()->on_config_change(&config);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::priv::on_progress_event()
|
void Plater::priv::on_progress_event()
|
||||||
@ -1677,7 +1698,8 @@ void Plater::priv::on_scale_uniformly(SimpleEvent&)
|
|||||||
|
|
||||||
// $self->selection_changed(1); # refresh info (size, volume etc.)
|
// $self->selection_changed(1); # refresh info (size, volume etc.)
|
||||||
// $self->update;
|
// $self->update;
|
||||||
// $self->schedule_background_process;
|
|
||||||
|
this->schedule_background_process();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::priv::on_wipetower_moved(Vec3dEvent &evt)
|
void Plater::priv::on_wipetower_moved(Vec3dEvent &evt)
|
||||||
@ -1756,7 +1778,7 @@ void Plater::increase(size_t num)
|
|||||||
|
|
||||||
p->selection_changed();
|
p->selection_changed();
|
||||||
|
|
||||||
// $self->schedule_background_process;
|
this->p->schedule_background_process();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::decrease(size_t num)
|
void Plater::decrease(size_t num)
|
||||||
@ -1933,11 +1955,11 @@ void Plater::on_extruders_change(int num_extruders)
|
|||||||
GetParent()->Layout();
|
GetParent()->Layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::on_config_change(DynamicPrintConfig* config)
|
void Plater::on_config_change(const DynamicPrintConfig &config)
|
||||||
{
|
{
|
||||||
bool update_scheduled = false;
|
bool update_scheduled = false;
|
||||||
for ( auto opt_key: p->config->diff(*config)) {
|
for (auto opt_key : p->config->diff(config)) {
|
||||||
p->config->set_key_value(opt_key, config->option(opt_key)->clone());
|
p->config->set_key_value(opt_key, config.option(opt_key)->clone());
|
||||||
if (opt_key == "bed_shape") {
|
if (opt_key == "bed_shape") {
|
||||||
if (p->canvas3D) _3DScene::set_bed_shape(p->canvas3D, p->config->option<ConfigOptionPoints>(opt_key)->values);
|
if (p->canvas3D) _3DScene::set_bed_shape(p->canvas3D, p->config->option<ConfigOptionPoints>(opt_key)->values);
|
||||||
if (p->preview) p->preview->set_bed_shape(p->config->option<ConfigOptionPoints>(opt_key)->values);
|
if (p->preview) p->preview->set_bed_shape(p->config->option<ConfigOptionPoints>(opt_key)->values);
|
||||||
@ -1948,7 +1970,7 @@ void Plater::on_config_change(DynamicPrintConfig* config)
|
|||||||
update_scheduled = true;
|
update_scheduled = true;
|
||||||
}
|
}
|
||||||
// else if(opt_key == "serial_port") {
|
// else if(opt_key == "serial_port") {
|
||||||
// sidebar()->p->btn_print->Show(config->get("serial_port")); // ???: btn_print is removed
|
// sidebar()->p->btn_print->Show(config.get("serial_port")); // ???: btn_print is removed
|
||||||
// Layout();
|
// Layout();
|
||||||
// }
|
// }
|
||||||
else if (opt_key == "print_host") {
|
else if (opt_key == "print_host") {
|
||||||
@ -1982,10 +2004,8 @@ void Plater::on_config_change(DynamicPrintConfig* config)
|
|||||||
if (update_scheduled)
|
if (update_scheduled)
|
||||||
update();
|
update();
|
||||||
|
|
||||||
if (!p->main_frame->is_loaded()) return ;
|
if (p->main_frame->is_loaded())
|
||||||
|
this->p->schedule_background_process();
|
||||||
// (re)start timer
|
|
||||||
// schedule_background_process();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wxGLCanvas* Plater::canvas3D()
|
wxGLCanvas* Plater::canvas3D()
|
||||||
@ -2012,7 +2032,7 @@ void Plater::changed_object_settings(int obj_idx)
|
|||||||
if (list->is_parts_changed() || list->is_part_settings_changed()) {
|
if (list->is_parts_changed() || list->is_part_settings_changed()) {
|
||||||
// stop_background_process();
|
// stop_background_process();
|
||||||
// $self->{print}->reload_object($obj_idx);
|
// $self->{print}->reload_object($obj_idx);
|
||||||
// schedule_background_process();
|
this->p->schedule_background_process();
|
||||||
#if !ENABLE_EXTENDED_SELECTION
|
#if !ENABLE_EXTENDED_SELECTION
|
||||||
if (p->canvas3D) _3DScene::reload_scene(p->canvas3D, true);
|
if (p->canvas3D) _3DScene::reload_scene(p->canvas3D, true);
|
||||||
auto selections = p->collect_selections();
|
auto selections = p->collect_selections();
|
||||||
@ -2021,7 +2041,7 @@ void Plater::changed_object_settings(int obj_idx)
|
|||||||
_3DScene::reload_scene(p->canvas3D, false);
|
_3DScene::reload_scene(p->canvas3D, false);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// schedule_background_process();
|
this->p->schedule_background_process();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -123,7 +123,7 @@ public:
|
|||||||
void send_gcode();
|
void send_gcode();
|
||||||
|
|
||||||
void on_extruders_change(int extruders_count);
|
void on_extruders_change(int extruders_count);
|
||||||
void on_config_change(DynamicPrintConfig* config);
|
void on_config_change(const DynamicPrintConfig &config);
|
||||||
|
|
||||||
wxGLCanvas* canvas3D();
|
wxGLCanvas* canvas3D();
|
||||||
private:
|
private:
|
||||||
|
@ -262,7 +262,7 @@ ModelMaterial::attributes()
|
|||||||
%code%{ THIS->name = value; %};
|
%code%{ THIS->name = value; %};
|
||||||
t_model_material_id material_id();
|
t_model_material_id material_id();
|
||||||
void set_material_id(t_model_material_id material_id)
|
void set_material_id(t_model_material_id material_id)
|
||||||
%code%{ THIS->material_id(material_id); %};
|
%code%{ THIS->set_material_id(material_id); %};
|
||||||
Ref<ModelMaterial> material();
|
Ref<ModelMaterial> material();
|
||||||
|
|
||||||
Ref<DynamicPrintConfig> config()
|
Ref<DynamicPrintConfig> config()
|
||||||
|
Loading…
Reference in New Issue
Block a user