mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-11 16:57:53 -06:00
Merge remote-tracking branch 'origin/master' into tm_sla_supports_backend and add get_current_elevation
This commit is contained in:
commit
c39698878d
22 changed files with 756 additions and 179 deletions
|
@ -1232,6 +1232,19 @@ void ModelVolume::set_material(t_model_material_id material_id, const ModelMater
|
||||||
this->object->get_model()->add_material(material_id, material);
|
this->object->get_model()->add_material(material_id, material);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extract the current extruder ID based on this ModelVolume's config and the parent ModelObject's config.
|
||||||
|
int ModelVolume::extruder_id() const
|
||||||
|
{
|
||||||
|
int extruder_id = -1;
|
||||||
|
if (this->is_model_part()) {
|
||||||
|
const ConfigOption *opt = this->config.option("extruder");
|
||||||
|
if (opt == nullptr)
|
||||||
|
opt = this->object->config.option("extruder");
|
||||||
|
extruder_id = (opt == nullptr) ? 0 : opt->getInt();
|
||||||
|
}
|
||||||
|
return extruder_id;
|
||||||
|
}
|
||||||
|
|
||||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||||
void ModelVolume::center_geometry()
|
void ModelVolume::center_geometry()
|
||||||
{
|
{
|
||||||
|
@ -1525,6 +1538,71 @@ Transform3d ModelInstance::get_matrix(bool dont_translate, bool dont_rotate, boo
|
||||||
}
|
}
|
||||||
#endif // !ENABLE_MODELVOLUME_TRANSFORM
|
#endif // !ENABLE_MODELVOLUME_TRANSFORM
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
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.
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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_new];
|
||||||
|
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!
|
||||||
|
|
||||||
|
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||||
|
if (!mv_old.get_matrix().isApprox(mv_new.get_matrix()))
|
||||||
|
return true;
|
||||||
|
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
||||||
|
++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;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
// Verify whether the IDs of Model / ModelObject / ModelVolume / ModelInstance / ModelMaterial are valid and unique.
|
// Verify whether the IDs of Model / ModelObject / ModelVolume / ModelInstance / ModelMaterial are valid and unique.
|
||||||
void check_model_ids_validity(const Model &model)
|
void check_model_ids_validity(const Model &model)
|
||||||
|
|
|
@ -23,6 +23,7 @@ class ModelMaterial;
|
||||||
class ModelObject;
|
class ModelObject;
|
||||||
class ModelVolume;
|
class ModelVolume;
|
||||||
class Print;
|
class Print;
|
||||||
|
class SLAPrint;
|
||||||
|
|
||||||
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;
|
||||||
|
@ -252,6 +253,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class Print;
|
friend class Print;
|
||||||
|
friend class SLAPrint;
|
||||||
// Called by Print::apply() to set the model pointer after making a copy.
|
// Called by Print::apply() to set the model pointer after making a copy.
|
||||||
void set_model(Model *model) { m_model = model; }
|
void set_model(Model *model) { m_model = model; }
|
||||||
|
|
||||||
|
@ -310,6 +312,10 @@ public:
|
||||||
void set_material_id(t_model_material_id 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);
|
||||||
|
// Extract the current extruder ID based on this ModelVolume's config and the parent ModelObject's config.
|
||||||
|
// Extruder ID is only valid for FFF. Returns -1 for SLA or if the extruder ID is not applicable (support volumes).
|
||||||
|
int extruder_id() const;
|
||||||
|
|
||||||
// Split this volume, append the result to the object owning this volume.
|
// Split this volume, append the result to the object owning this volume.
|
||||||
// Return the number of volumes created from this one.
|
// Return the number of volumes created from this one.
|
||||||
// This is useful to assign different materials to different volumes of an object.
|
// This is useful to assign different materials to different volumes of an object.
|
||||||
|
@ -368,6 +374,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class Print;
|
friend class Print;
|
||||||
|
friend class SLAPrint;
|
||||||
friend class ModelObject;
|
friend class ModelObject;
|
||||||
|
|
||||||
explicit ModelVolume(const ModelVolume &rhs) = default;
|
explicit ModelVolume(const ModelVolume &rhs) = default;
|
||||||
|
@ -535,6 +542,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class Print;
|
friend class Print;
|
||||||
|
friend class SLAPrint;
|
||||||
friend class ModelObject;
|
friend class ModelObject;
|
||||||
|
|
||||||
explicit ModelInstance(const ModelInstance &rhs) = default;
|
explicit ModelInstance(const ModelInstance &rhs) = default;
|
||||||
|
@ -652,6 +660,18 @@ private:
|
||||||
#undef MODELBASE_DERIVED_COPY_MOVE_CLONE
|
#undef MODELBASE_DERIVED_COPY_MOVE_CLONE
|
||||||
#undef MODELBASE_DERIVED_PRIVATE_COPY_MOVE
|
#undef MODELBASE_DERIVED_PRIVATE_COPY_MOVE
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
extern bool model_object_list_equal(const Model &model_old, const Model &model_new);
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
extern bool model_object_list_extended(const Model &model_old, const Model &model_new);
|
||||||
|
|
||||||
|
// Test whether the new ModelObject contains a different set of volumes (or sorted in a different order)
|
||||||
|
// than the old ModelObject.
|
||||||
|
extern bool model_volume_list_changed(const ModelObject &model_object_old, const ModelObject &model_object_new, const ModelVolume::Type type);
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
// Verify whether the IDs of Model / ModelObject / ModelVolume / ModelInstance / ModelMaterial are valid and unique.
|
// Verify whether the IDs of Model / ModelObject / ModelVolume / ModelInstance / ModelMaterial are valid and unique.
|
||||||
void check_model_ids_validity(const Model &model);
|
void check_model_ids_validity(const Model &model);
|
||||||
|
|
|
@ -550,71 +550,6 @@ 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_new];
|
|
||||||
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!
|
|
||||||
|
|
||||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
|
||||||
if (!mv_old.get_matrix().isApprox(mv_new.get_matrix()))
|
|
||||||
return true;
|
|
||||||
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
|
||||||
++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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add or remove support modifier ModelVolumes from model_object_dst to match the ModelVolumes of model_object_new
|
// Add or remove support modifier ModelVolumes from model_object_dst to match the ModelVolumes of model_object_new
|
||||||
// in the exact order and with the same IDs.
|
// in the exact order and with the same IDs.
|
||||||
// It is expected, that the model_object_dst already contains the non-support volumes of model_object_new in the correct order.
|
// It is expected, that the model_object_dst already contains the non-support volumes of model_object_new in the correct order.
|
||||||
|
|
|
@ -131,9 +131,6 @@ public:
|
||||||
SupportLayerPtrs::const_iterator insert_support_layer(SupportLayerPtrs::const_iterator pos, int id, coordf_t height, coordf_t print_z, coordf_t slice_z);
|
SupportLayerPtrs::const_iterator insert_support_layer(SupportLayerPtrs::const_iterator pos, int id, coordf_t height, coordf_t print_z, coordf_t slice_z);
|
||||||
void delete_support_layer(int idx);
|
void delete_support_layer(int idx);
|
||||||
|
|
||||||
// methods for handling state
|
|
||||||
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
|
|
||||||
|
|
||||||
// To be used over the layer_height_profile of both the PrintObject and ModelObject
|
// To be used over the layer_height_profile of both the PrintObject and ModelObject
|
||||||
// to initialize the height profile with the height ranges.
|
// to initialize the height profile with the height ranges.
|
||||||
bool update_layer_height_profile(std::vector<coordf_t> &layer_height_profile) const;
|
bool update_layer_height_profile(std::vector<coordf_t> &layer_height_profile) const;
|
||||||
|
@ -174,6 +171,8 @@ protected:
|
||||||
bool invalidate_step(PrintObjectStep step);
|
bool invalidate_step(PrintObjectStep step);
|
||||||
// Invalidates all PrintObject and Print steps.
|
// Invalidates all PrintObject and Print steps.
|
||||||
bool invalidate_all_steps();
|
bool invalidate_all_steps();
|
||||||
|
// Invalidate steps based on a set of parameters changed.
|
||||||
|
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void make_perimeters();
|
void make_perimeters();
|
||||||
|
|
|
@ -2447,6 +2447,7 @@ void PrintConfigDef::init_sla_params()
|
||||||
|
|
||||||
def = this->add("support_head_front_radius", coFloat);
|
def = this->add("support_head_front_radius", coFloat);
|
||||||
def->label = L("Support head front radius");
|
def->label = L("Support head front radius");
|
||||||
|
def->category = L("Supports");
|
||||||
def->tooltip = L("Radius of the pointing side of the head");
|
def->tooltip = L("Radius of the pointing side of the head");
|
||||||
def->sidetext = L("mm");
|
def->sidetext = L("mm");
|
||||||
def->cli = "";
|
def->cli = "";
|
||||||
|
@ -2455,6 +2456,7 @@ void PrintConfigDef::init_sla_params()
|
||||||
|
|
||||||
def = this->add("support_head_penetration", coFloat);
|
def = this->add("support_head_penetration", coFloat);
|
||||||
def->label = L("Support head penetration");
|
def->label = L("Support head penetration");
|
||||||
|
def->category = L("Supports");
|
||||||
def->tooltip = L("How much the pinhead has to penetrate the model surface");
|
def->tooltip = L("How much the pinhead has to penetrate the model surface");
|
||||||
def->sidetext = L("mm");
|
def->sidetext = L("mm");
|
||||||
def->cli = "";
|
def->cli = "";
|
||||||
|
@ -2463,6 +2465,7 @@ void PrintConfigDef::init_sla_params()
|
||||||
|
|
||||||
def = this->add("support_head_back_radius", coFloat);
|
def = this->add("support_head_back_radius", coFloat);
|
||||||
def->label = L("Support head back radius");
|
def->label = L("Support head back radius");
|
||||||
|
def->category = L("Supports");
|
||||||
def->tooltip = L("Radius of the back side of the 3d arrow");
|
def->tooltip = L("Radius of the back side of the 3d arrow");
|
||||||
def->sidetext = L("mm");
|
def->sidetext = L("mm");
|
||||||
def->cli = "";
|
def->cli = "";
|
||||||
|
@ -2471,6 +2474,7 @@ void PrintConfigDef::init_sla_params()
|
||||||
|
|
||||||
def = this->add("support_head_width", coFloat);
|
def = this->add("support_head_width", coFloat);
|
||||||
def->label = L("Support head width");
|
def->label = L("Support head width");
|
||||||
|
def->category = L("Supports");
|
||||||
def->tooltip = L("Width from the back sphere center to the front sphere center");
|
def->tooltip = L("Width from the back sphere center to the front sphere center");
|
||||||
def->sidetext = L("mm");
|
def->sidetext = L("mm");
|
||||||
def->cli = "";
|
def->cli = "";
|
||||||
|
@ -2479,6 +2483,7 @@ void PrintConfigDef::init_sla_params()
|
||||||
|
|
||||||
def = this->add("support_pillar_radius", coFloat);
|
def = this->add("support_pillar_radius", coFloat);
|
||||||
def->label = L("Support pillar radius");
|
def->label = L("Support pillar radius");
|
||||||
|
def->category = L("Supports");
|
||||||
def->tooltip = L("Radius in mm of the support pillars");
|
def->tooltip = L("Radius in mm of the support pillars");
|
||||||
def->sidetext = L("mm");
|
def->sidetext = L("mm");
|
||||||
def->cli = "";
|
def->cli = "";
|
||||||
|
@ -2487,6 +2492,7 @@ void PrintConfigDef::init_sla_params()
|
||||||
|
|
||||||
def = this->add("support_base_radius", coFloat);
|
def = this->add("support_base_radius", coFloat);
|
||||||
def->label = L("Support base radius");
|
def->label = L("Support base radius");
|
||||||
|
def->category = L("Supports");
|
||||||
def->tooltip = L("Radius in mm of the pillar base");
|
def->tooltip = L("Radius in mm of the pillar base");
|
||||||
def->sidetext = L("mm");
|
def->sidetext = L("mm");
|
||||||
def->cli = "";
|
def->cli = "";
|
||||||
|
@ -2495,6 +2501,7 @@ void PrintConfigDef::init_sla_params()
|
||||||
|
|
||||||
def = this->add("support_base_height", coFloat);
|
def = this->add("support_base_height", coFloat);
|
||||||
def->label = L("Support base height");
|
def->label = L("Support base height");
|
||||||
|
def->category = L("Supports");
|
||||||
def->tooltip = L("The height of the pillar base cone");
|
def->tooltip = L("The height of the pillar base cone");
|
||||||
def->sidetext = L("mm");
|
def->sidetext = L("mm");
|
||||||
def->cli = "";
|
def->cli = "";
|
||||||
|
@ -2503,6 +2510,7 @@ void PrintConfigDef::init_sla_params()
|
||||||
|
|
||||||
def = this->add("support_critical_angle", coFloat);
|
def = this->add("support_critical_angle", coFloat);
|
||||||
def->label = L("Critical angle");
|
def->label = L("Critical angle");
|
||||||
|
def->category = L("Supports");
|
||||||
def->tooltip = L("The default angle for connecting support sticks and junctions.");
|
def->tooltip = L("The default angle for connecting support sticks and junctions.");
|
||||||
def->sidetext = L("°");
|
def->sidetext = L("°");
|
||||||
def->cli = "";
|
def->cli = "";
|
||||||
|
@ -2511,6 +2519,7 @@ void PrintConfigDef::init_sla_params()
|
||||||
|
|
||||||
def = this->add("support_max_bridge_length", coFloat);
|
def = this->add("support_max_bridge_length", coFloat);
|
||||||
def->label = L("Max bridge length");
|
def->label = L("Max bridge length");
|
||||||
|
def->category = L("Supports");
|
||||||
def->tooltip = L("The max length of a bridge");
|
def->tooltip = L("The max length of a bridge");
|
||||||
def->sidetext = L("mm");
|
def->sidetext = L("mm");
|
||||||
def->cli = "";
|
def->cli = "";
|
||||||
|
@ -2519,6 +2528,7 @@ void PrintConfigDef::init_sla_params()
|
||||||
|
|
||||||
def = this->add("support_object_elevation", coFloat);
|
def = this->add("support_object_elevation", coFloat);
|
||||||
def->label = L("Object elevation");
|
def->label = L("Object elevation");
|
||||||
|
def->category = L("Supports");
|
||||||
def->tooltip = L("How much the supports should lift up the supported object.");
|
def->tooltip = L("How much the supports should lift up the supported object.");
|
||||||
def->sidetext = L("mm");
|
def->sidetext = L("mm");
|
||||||
def->cli = "";
|
def->cli = "";
|
||||||
|
@ -2527,6 +2537,7 @@ void PrintConfigDef::init_sla_params()
|
||||||
|
|
||||||
def = this->add("pad_enable", coBool);
|
def = this->add("pad_enable", coBool);
|
||||||
def->label = L("Use pad");
|
def->label = L("Use pad");
|
||||||
|
def->category = L("Pad");
|
||||||
def->tooltip = L("Add a pad underneath the supported model");
|
def->tooltip = L("Add a pad underneath the supported model");
|
||||||
def->sidetext = L("");
|
def->sidetext = L("");
|
||||||
def->cli = "";
|
def->cli = "";
|
||||||
|
@ -2534,6 +2545,7 @@ void PrintConfigDef::init_sla_params()
|
||||||
|
|
||||||
def = this->add("pad_wall_thickness", coFloat);
|
def = this->add("pad_wall_thickness", coFloat);
|
||||||
def->label = L("Pad wall thickness");
|
def->label = L("Pad wall thickness");
|
||||||
|
def->category = L("Pad");
|
||||||
def->tooltip = L("");
|
def->tooltip = L("");
|
||||||
def->sidetext = L("mm");
|
def->sidetext = L("mm");
|
||||||
def->cli = "";
|
def->cli = "";
|
||||||
|
@ -2542,6 +2554,7 @@ void PrintConfigDef::init_sla_params()
|
||||||
|
|
||||||
def = this->add("pad_wall_height", coFloat);
|
def = this->add("pad_wall_height", coFloat);
|
||||||
def->label = L("Pad wall height");
|
def->label = L("Pad wall height");
|
||||||
|
def->category = L("Pad");
|
||||||
def->tooltip = L("");
|
def->tooltip = L("");
|
||||||
def->sidetext = L("mm");
|
def->sidetext = L("mm");
|
||||||
def->cli = "";
|
def->cli = "";
|
||||||
|
@ -2550,6 +2563,7 @@ void PrintConfigDef::init_sla_params()
|
||||||
|
|
||||||
def = this->add("pad_max_merge_distance", coFloat);
|
def = this->add("pad_max_merge_distance", coFloat);
|
||||||
def->label = L("Max merge distance");
|
def->label = L("Max merge distance");
|
||||||
|
def->category = L("Pad");
|
||||||
def->tooltip = L("");
|
def->tooltip = L("");
|
||||||
def->sidetext = L("mm");
|
def->sidetext = L("mm");
|
||||||
def->cli = "";
|
def->cli = "";
|
||||||
|
@ -2558,6 +2572,7 @@ void PrintConfigDef::init_sla_params()
|
||||||
|
|
||||||
def = this->add("pad_edge_radius", coFloat);
|
def = this->add("pad_edge_radius", coFloat);
|
||||||
def->label = L("Pad edge radius");
|
def->label = L("Pad edge radius");
|
||||||
|
def->category = L("Pad");
|
||||||
def->tooltip = L("");
|
def->tooltip = L("");
|
||||||
def->sidetext = L("mm");
|
def->sidetext = L("mm");
|
||||||
def->cli = "";
|
def->cli = "";
|
||||||
|
|
|
@ -902,7 +902,7 @@ class SLAPrintObjectConfig : public StaticPrintConfig
|
||||||
{
|
{
|
||||||
STATIC_PRINT_CONFIG_CACHE(SLAPrintObjectConfig)
|
STATIC_PRINT_CONFIG_CACHE(SLAPrintObjectConfig)
|
||||||
public:
|
public:
|
||||||
ConfigOptionFloat layer_height;
|
ConfigOptionFloat layer_height;
|
||||||
|
|
||||||
// Radius in mm of the pointing side of the head.
|
// Radius in mm of the pointing side of the head.
|
||||||
ConfigOptionFloat support_head_front_radius /*= 0.2*/;
|
ConfigOptionFloat support_head_front_radius /*= 0.2*/;
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#include "SLA/SLABasePool.hpp"
|
#include "SLA/SLABasePool.hpp"
|
||||||
#include "MTUtils.hpp"
|
#include "MTUtils.hpp"
|
||||||
|
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
#include <tbb/parallel_for.h>
|
#include <tbb/parallel_for.h>
|
||||||
#include <boost/log/trivial.hpp>
|
#include <boost/log/trivial.hpp>
|
||||||
|
|
||||||
|
@ -75,53 +77,296 @@ void SLAPrint::clear()
|
||||||
m_objects.clear();
|
m_objects.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Transformation without rotation around Z and without a shift by X and Y.
|
||||||
|
static Transform3d sla_trafo(const ModelObject &model_object)
|
||||||
|
{
|
||||||
|
ModelInstance &model_instance = *model_object.instances.front();
|
||||||
|
Vec3d offset = model_instance.get_offset();
|
||||||
|
Vec3d rotation = model_instance.get_rotation();
|
||||||
|
offset(0) = 0.;
|
||||||
|
offset(1) = 0.;
|
||||||
|
rotation(2) = 0.;
|
||||||
|
return Geometry::assemble_transform(offset, rotation, model_instance.get_scaling_factor(), model_instance.get_mirror());
|
||||||
|
}
|
||||||
|
|
||||||
|
// List of instances, where the ModelInstance transformation is a composite of sla_trafo and the transformation defined by SLAPrintObject::Instance.
|
||||||
|
static std::vector<SLAPrintObject::Instance> sla_instances(const ModelObject &model_object)
|
||||||
|
{
|
||||||
|
std::vector<SLAPrintObject::Instance> instances;
|
||||||
|
for (ModelInstance *model_instance : model_object.instances)
|
||||||
|
if (model_instance->is_printable()) {
|
||||||
|
instances.emplace_back(SLAPrintObject::Instance(
|
||||||
|
model_instance->id(),
|
||||||
|
Point::new_scale(model_instance->get_offset(X), model_instance->get_offset(Y)),
|
||||||
|
float(model_instance->get_rotation(Z))));
|
||||||
|
}
|
||||||
|
return instances;
|
||||||
|
}
|
||||||
|
|
||||||
SLAPrint::ApplyStatus SLAPrint::apply(const Model &model,
|
SLAPrint::ApplyStatus SLAPrint::apply(const Model &model,
|
||||||
const DynamicPrintConfig &config_in)
|
const DynamicPrintConfig &config_in)
|
||||||
{
|
{
|
||||||
// if (m_objects.empty())
|
#ifdef _DEBUG
|
||||||
// return APPLY_STATUS_UNCHANGED;
|
check_model_ids_validity(model);
|
||||||
|
#endif /* _DEBUG */
|
||||||
|
|
||||||
|
// Make a copy of the config, normalize it.
|
||||||
|
DynamicPrintConfig config(config_in);
|
||||||
|
config.normalize();
|
||||||
|
// Collect changes to print config.
|
||||||
|
t_config_option_keys printer_diff = m_printer_config.diff(config);
|
||||||
|
t_config_option_keys material_diff = m_material_config.diff(config);
|
||||||
|
t_config_option_keys object_diff = m_default_object_config.diff(config);
|
||||||
|
|
||||||
|
// Do not use the ApplyStatus as we will use the max function when updating apply_status.
|
||||||
|
unsigned int apply_status = APPLY_STATUS_UNCHANGED;
|
||||||
|
auto update_apply_status = [&apply_status](bool invalidated)
|
||||||
|
{ apply_status = std::max<unsigned int>(apply_status, invalidated ? APPLY_STATUS_INVALIDATED : APPLY_STATUS_CHANGED); };
|
||||||
|
if (! (printer_diff.empty() && material_diff.empty() && object_diff.empty()))
|
||||||
|
update_apply_status(false);
|
||||||
|
|
||||||
// Grab the lock for the Print / PrintObject milestones.
|
// Grab the lock for the Print / PrintObject milestones.
|
||||||
tbb::mutex::scoped_lock lock(this->state_mutex());
|
tbb::mutex::scoped_lock lock(this->state_mutex());
|
||||||
if (m_objects.empty() && model.objects.empty() && m_model.objects.empty())
|
|
||||||
return APPLY_STATUS_UNCHANGED;
|
|
||||||
|
|
||||||
// Temporary: just to have to correct layer height for the rasterization
|
// The following call may stop the background processing.
|
||||||
DynamicPrintConfig config(config_in);
|
update_apply_status(this->invalidate_state_by_config_options(printer_diff));
|
||||||
config.normalize();
|
update_apply_status(this->invalidate_state_by_config_options(material_diff));
|
||||||
m_material_config.initial_layer_height.set(
|
|
||||||
config.opt<ConfigOptionFloat>("initial_layer_height"));
|
|
||||||
|
|
||||||
// Temporary quick fix, just invalidate everything.
|
// It is also safe to change m_config now after this->invalidate_state_by_config_options() call.
|
||||||
{
|
m_printer_config.apply_only(config, printer_diff, true);
|
||||||
for (SLAPrintObject *print_object : m_objects) {
|
// Handle changes to material config.
|
||||||
print_object->invalidate_all_steps();
|
m_material_config.apply_only(config, material_diff, true);
|
||||||
delete print_object;
|
// Handle changes to object config defaults
|
||||||
}
|
m_default_object_config.apply_only(config, object_diff, true);
|
||||||
m_objects.clear();
|
|
||||||
this->invalidate_all_steps();
|
|
||||||
|
|
||||||
// Copy the model by value (deep copy),
|
struct ModelObjectStatus {
|
||||||
// keep the Model / ModelObject / ModelInstance / ModelVolume IDs.
|
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.
|
||||||
|
// Stop background processing.
|
||||||
|
this->call_cancell_callback();
|
||||||
|
update_apply_status(this->invalidate_all_steps());
|
||||||
|
for (SLAPrintObject *object : m_objects) {
|
||||||
|
model_object_status.emplace(object->model_object()->id(), ModelObjectStatus::Deleted);
|
||||||
|
delete object;
|
||||||
|
}
|
||||||
|
m_objects.clear();
|
||||||
m_model.assign_copy(model);
|
m_model.assign_copy(model);
|
||||||
// Generate new SLAPrintObjects.
|
for (const ModelObject *model_object : m_model.objects)
|
||||||
for (ModelObject *model_object : m_model.objects) {
|
model_object_status.emplace(model_object->id(), ModelObjectStatus::New);
|
||||||
auto po = new SLAPrintObject(this, model_object);
|
} else {
|
||||||
|
if (model_object_list_equal(m_model, model)) {
|
||||||
// po->m_config.layer_height.set(lh);
|
// The object list did not change.
|
||||||
po->m_config.apply(config, true);
|
for (const ModelObject *model_object : m_model.objects)
|
||||||
|
model_object_status.emplace(model_object->id(), ModelObjectStatus::Old);
|
||||||
m_objects.emplace_back(po);
|
} else if (model_object_list_extended(m_model, model)) {
|
||||||
for (ModelInstance *oinst : model_object->instances) {
|
// Add new objects. Their volumes and configs will be synchronized later.
|
||||||
Point tr = Point::new_scale(oinst->get_offset()(X),
|
update_apply_status(this->invalidate_step(slapsRasterize));
|
||||||
oinst->get_offset()(Y));
|
for (const ModelObject *model_object : m_model.objects)
|
||||||
auto rotZ = float(oinst->get_rotation()(Z));
|
model_object_status.emplace(model_object->id(), ModelObjectStatus::Old);
|
||||||
po->m_instances.emplace_back(oinst->id(), tr, rotZ);
|
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(ModelObject::new_copy(*model.objects[i]));
|
||||||
|
m_model.objects.back()->set_model(&m_model);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Reorder the objects, add new objects.
|
||||||
|
// First stop background processing before shuffling or deleting the PrintObjects in the object list.
|
||||||
|
this->call_cancell_callback();
|
||||||
|
update_apply_status(this->invalidate_step(slapsRasterize));
|
||||||
|
// Second create a new list of objects.
|
||||||
|
std::vector<ModelObject*> model_objects_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(model_objects_old.begin(), model_objects_old.end(), by_id_lower);
|
||||||
|
for (const ModelObject *mobj : model.objects) {
|
||||||
|
auto it = std::lower_bound(model_objects_old.begin(), model_objects_old.end(), mobj, by_id_lower);
|
||||||
|
if (it == model_objects_old.end() || (*it)->id() != mobj->id()) {
|
||||||
|
// New ModelObject added.
|
||||||
|
m_model.objects.emplace_back(ModelObject::new_copy(*mobj));
|
||||||
|
m_model.objects.back()->set_model(&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::Moved);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool deleted_any = false;
|
||||||
|
for (ModelObject *&model_object : model_objects_old) {
|
||||||
|
if (model_object_status.find(ModelObjectStatus(model_object->id())) == model_object_status.end()) {
|
||||||
|
model_object_status.emplace(model_object->id(), ModelObjectStatus::Deleted);
|
||||||
|
deleted_any = true;
|
||||||
|
} else
|
||||||
|
// Do not delete this ModelObject instance.
|
||||||
|
model_object = nullptr;
|
||||||
|
}
|
||||||
|
if (deleted_any) {
|
||||||
|
// Delete PrintObjects of the deleted ModelObjects.
|
||||||
|
std::vector<SLAPrintObject*> print_objects_old = std::move(m_objects);
|
||||||
|
m_objects.clear();
|
||||||
|
m_objects.reserve(print_objects_old.size());
|
||||||
|
for (SLAPrintObject *print_object : print_objects_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) {
|
||||||
|
update_apply_status(print_object->invalidate_all_steps());
|
||||||
|
delete print_object;
|
||||||
|
} else
|
||||||
|
m_objects.emplace_back(print_object);
|
||||||
|
}
|
||||||
|
for (ModelObject *model_object : model_objects_old)
|
||||||
|
delete model_object;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return APPLY_STATUS_INVALIDATED;
|
// 2) Map print objects including their transformation matrices.
|
||||||
|
struct PrintObjectStatus {
|
||||||
|
enum Status {
|
||||||
|
Unknown,
|
||||||
|
Deleted,
|
||||||
|
Reused,
|
||||||
|
New
|
||||||
|
};
|
||||||
|
PrintObjectStatus(SLAPrintObject *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
|
||||||
|
SLAPrintObject *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 (SLAPrintObject *print_object : m_objects)
|
||||||
|
print_object_status.emplace(PrintObjectStatus(print_object));
|
||||||
|
|
||||||
|
// 3) Synchronize ModelObjects & PrintObjects.
|
||||||
|
std::vector<SLAPrintObject*> print_objects_new;
|
||||||
|
print_objects_new.reserve(std::max(m_objects.size(), m_model.objects.size()));
|
||||||
|
bool new_objects = false;
|
||||||
|
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::Old || it_status->status == ModelObjectStatus::Moved);
|
||||||
|
const ModelObject &model_object_new = *model.objects[idx_model_object];
|
||||||
|
auto it_print_object_status = print_object_status.lower_bound(PrintObjectStatus(model_object.id()));
|
||||||
|
if (it_print_object_status != print_object_status.end() && it_print_object_status->id != model_object.id())
|
||||||
|
it_print_object_status = print_object_status.end();
|
||||||
|
// 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 sla_trafo_differs = model_object.instances.empty() != model_object_new.instances.empty() ||
|
||||||
|
(! model_object.instances.empty() && ! sla_trafo(model_object).isApprox(sla_trafo(model_object_new)));
|
||||||
|
if (model_parts_differ || sla_trafo_differs) {
|
||||||
|
// The very first step (the slicing step) is invalidated. One may freely remove all associated PrintObjects.
|
||||||
|
if (it_print_object_status != print_object_status.end()) {
|
||||||
|
update_apply_status(it_print_object_status->print_object->invalidate_all_steps());
|
||||||
|
const_cast<PrintObjectStatus&>(*it_print_object_status).status = PrintObjectStatus::Deleted;
|
||||||
|
}
|
||||||
|
// Copy content of the ModelObject including its ID, do not change the parent.
|
||||||
|
model_object.assign_copy(model_object_new);
|
||||||
|
} else {
|
||||||
|
// Synchronize Object's config.
|
||||||
|
bool object_config_changed = model_object.config != model_object_new.config;
|
||||||
|
if (object_config_changed)
|
||||||
|
model_object.config = model_object_new.config;
|
||||||
|
if (! object_diff.empty() || object_config_changed) {
|
||||||
|
SLAPrintObjectConfig new_config = m_default_object_config;
|
||||||
|
normalize_and_apply_config(new_config, model_object.config);
|
||||||
|
if (it_print_object_status != print_object_status.end()) {
|
||||||
|
t_config_option_keys diff = it_print_object_status->print_object->config().diff(new_config);
|
||||||
|
if (! diff.empty()) {
|
||||||
|
update_apply_status(it_print_object_status->print_object->invalidate_state_by_config_options(diff));
|
||||||
|
it_print_object_status->print_object->config_apply_only(new_config, diff, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (model_object.sla_support_points != model_object_new.sla_support_points) {
|
||||||
|
model_object.sla_support_points = model_object_new.sla_support_points;
|
||||||
|
if (it_print_object_status != print_object_status.end())
|
||||||
|
update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints));
|
||||||
|
}
|
||||||
|
// Copy the ModelObject name, input_file and instances. The instances will compared against PrintObject instances in the next step.
|
||||||
|
model_object.name = model_object_new.name;
|
||||||
|
model_object.input_file = model_object_new.input_file;
|
||||||
|
model_object.clear_instances();
|
||||||
|
model_object.instances.reserve(model_object_new.instances.size());
|
||||||
|
for (const ModelInstance *model_instance : model_object_new.instances) {
|
||||||
|
model_object.instances.emplace_back(new ModelInstance(*model_instance));
|
||||||
|
model_object.instances.back()->set_model_object(&model_object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<SLAPrintObject::Instance> new_instances = sla_instances(model_object);
|
||||||
|
if (it_print_object_status != print_object_status.end() && it_print_object_status->status != PrintObjectStatus::Deleted) {
|
||||||
|
// The SLAPrintObject is already there.
|
||||||
|
if (new_instances != it_print_object_status->print_object->instances()) {
|
||||||
|
// Instances changed.
|
||||||
|
it_print_object_status->print_object->set_instances(new_instances);
|
||||||
|
update_apply_status(this->invalidate_step(slapsRasterize));
|
||||||
|
}
|
||||||
|
print_objects_new.emplace_back(it_print_object_status->print_object);
|
||||||
|
const_cast<PrintObjectStatus&>(*it_print_object_status).status = PrintObjectStatus::Reused;
|
||||||
|
} else {
|
||||||
|
auto print_object = new SLAPrintObject(this, &model_object);
|
||||||
|
print_object->set_trafo(sla_trafo(model_object));
|
||||||
|
print_object->set_instances(new_instances);
|
||||||
|
print_object->config_apply(config, true);
|
||||||
|
print_objects_new.emplace_back(print_object);
|
||||||
|
new_objects = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_objects != print_objects_new) {
|
||||||
|
this->call_cancell_callback();
|
||||||
|
update_apply_status(this->invalidate_all_steps());
|
||||||
|
m_objects = print_objects_new;
|
||||||
|
// Delete the PrintObjects marked as Unknown or Deleted.
|
||||||
|
bool deleted_objects = false;
|
||||||
|
for (auto &pos : print_object_status)
|
||||||
|
if (pos.status == PrintObjectStatus::Unknown || pos.status == PrintObjectStatus::Deleted) {
|
||||||
|
// update_apply_status(pos.print_object->invalidate_all_steps());
|
||||||
|
delete pos.print_object;
|
||||||
|
deleted_objects = true;
|
||||||
|
}
|
||||||
|
update_apply_status(new_objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
check_model_ids_equal(m_model, model);
|
||||||
|
#endif /* _DEBUG */
|
||||||
|
|
||||||
|
return static_cast<ApplyStatus>(apply_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SLAPrint::process()
|
void SLAPrint::process()
|
||||||
|
@ -418,12 +663,12 @@ void SLAPrint::process()
|
||||||
|
|
||||||
// Status indication
|
// Status indication
|
||||||
auto st = ist + unsigned(sd*level_id*slot/levels.size());
|
auto st = ist + unsigned(sd*level_id*slot/levels.size());
|
||||||
slck.lock();
|
{ std::lock_guard<SpinMutex> lck(slck);
|
||||||
if( st > pst) {
|
if( st > pst) {
|
||||||
set_status(st, PRINT_STEP_LABELS[slapsRasterize]);
|
set_status(st, PRINT_STEP_LABELS[slapsRasterize]);
|
||||||
pst = st;
|
pst = st;
|
||||||
}
|
}
|
||||||
slck.unlock();
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// last minute escape
|
// last minute escape
|
||||||
|
@ -534,6 +779,61 @@ void SLAPrint::process()
|
||||||
set_status(100, L("Slicing done"));
|
set_status(100, L("Slicing done"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SLAPrint::invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys)
|
||||||
|
{
|
||||||
|
if (opt_keys.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Cache the plenty of parameters, which influence the final rasterization only,
|
||||||
|
// or they are only notes not influencing the rasterization step.
|
||||||
|
static std::unordered_set<std::string> steps_rasterize = {
|
||||||
|
"exposure_time",
|
||||||
|
"initial_exposure_time",
|
||||||
|
"material_correction_printing",
|
||||||
|
"material_correction_curing",
|
||||||
|
"display_width",
|
||||||
|
"display_height",
|
||||||
|
"display_pixels_x",
|
||||||
|
"display_pixels_y",
|
||||||
|
"printer_correction"
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::unordered_set<std::string> steps_ignore = {
|
||||||
|
"bed_shape",
|
||||||
|
"max_print_height",
|
||||||
|
"printer_technology",
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<SLAPrintStep> steps;
|
||||||
|
std::vector<SLAPrintObjectStep> osteps;
|
||||||
|
bool invalidated = false;
|
||||||
|
|
||||||
|
for (const t_config_option_key &opt_key : opt_keys) {
|
||||||
|
if (steps_rasterize.find(opt_key) != steps_rasterize.end()) {
|
||||||
|
// These options only affect the final rasterization, or they are just notes without influence on the output,
|
||||||
|
// so there is nothing to invalidate.
|
||||||
|
steps.emplace_back(slapsRasterize);
|
||||||
|
} else if (steps_ignore.find(opt_key) != steps_ignore.end()) {
|
||||||
|
// These steps have no influence on the output. Just ignore them.
|
||||||
|
} else if (opt_key == "initial_layer_height") {
|
||||||
|
steps.emplace_back(slapsRasterize);
|
||||||
|
osteps.emplace_back(slaposObjectSlice);
|
||||||
|
} else {
|
||||||
|
// All values should be covered.
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort_remove_duplicates(steps);
|
||||||
|
for (SLAPrintStep step : steps)
|
||||||
|
invalidated |= this->invalidate_step(step);
|
||||||
|
sort_remove_duplicates(osteps);
|
||||||
|
for (SLAPrintObjectStep ostep : osteps)
|
||||||
|
for (SLAPrintObject *object : m_objects)
|
||||||
|
invalidated |= object->invalidate_step(ostep);
|
||||||
|
return invalidated;
|
||||||
|
}
|
||||||
|
|
||||||
SLAPrintObject::SLAPrintObject(SLAPrint *print, ModelObject *model_object):
|
SLAPrintObject::SLAPrintObject(SLAPrint *print, ModelObject *model_object):
|
||||||
Inherited(print, model_object),
|
Inherited(print, model_object),
|
||||||
m_stepmask(slaposCount, true),
|
m_stepmask(slaposCount, true),
|
||||||
|
@ -545,6 +845,75 @@ SLAPrintObject::SLAPrintObject(SLAPrint *print, ModelObject *model_object):
|
||||||
|
|
||||||
SLAPrintObject::~SLAPrintObject() {}
|
SLAPrintObject::~SLAPrintObject() {}
|
||||||
|
|
||||||
|
// Called by SLAPrint::apply_config().
|
||||||
|
// This method only accepts SLAPrintObjectConfig option keys.
|
||||||
|
bool SLAPrintObject::invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys)
|
||||||
|
{
|
||||||
|
if (opt_keys.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::vector<SLAPrintObjectStep> steps;
|
||||||
|
bool invalidated = false;
|
||||||
|
for (const t_config_option_key &opt_key : opt_keys) {
|
||||||
|
if ( opt_key == "support_head_front_radius"
|
||||||
|
|| opt_key == "support_head_penetration"
|
||||||
|
|| opt_key == "support_head_back_radius"
|
||||||
|
|| opt_key == "support_head_width"
|
||||||
|
|| opt_key == "support_pillar_radius"
|
||||||
|
|| opt_key == "support_base_radius"
|
||||||
|
|| opt_key == "support_base_height"
|
||||||
|
|| opt_key == "support_critical_angle"
|
||||||
|
|| opt_key == "support_max_bridge_length"
|
||||||
|
|| opt_key == "support_object_elevation") {
|
||||||
|
steps.emplace_back(slaposSupportTree);
|
||||||
|
} else if (
|
||||||
|
opt_key == "pad_enable"
|
||||||
|
|| opt_key == "pad_wall_thickness"
|
||||||
|
|| opt_key == "pad_wall_height"
|
||||||
|
|| opt_key == "pad_max_merge_distance"
|
||||||
|
|| opt_key == "pad_edge_radius") {
|
||||||
|
steps.emplace_back(slaposBasePool);
|
||||||
|
} else {
|
||||||
|
// All keys should be covered.
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort_remove_duplicates(steps);
|
||||||
|
for (SLAPrintObjectStep step : steps)
|
||||||
|
invalidated |= this->invalidate_step(step);
|
||||||
|
return invalidated;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SLAPrintObject::invalidate_step(SLAPrintObjectStep step)
|
||||||
|
{
|
||||||
|
bool invalidated = Inherited::invalidate_step(step);
|
||||||
|
// propagate to dependent steps
|
||||||
|
if (step == slaposObjectSlice) {
|
||||||
|
invalidated |= this->invalidate_all_steps();
|
||||||
|
} else if (step == slaposSupportIslands) {
|
||||||
|
invalidated |= this->invalidate_steps({ slaposSupportPoints, slaposSupportTree, slaposBasePool, slaposSliceSupports });
|
||||||
|
invalidated |= m_print->invalidate_step(slapsRasterize);
|
||||||
|
} else if (step == slaposSupportPoints) {
|
||||||
|
invalidated |= this->invalidate_steps({ slaposSupportTree, slaposBasePool, slaposSliceSupports });
|
||||||
|
invalidated |= m_print->invalidate_step(slapsRasterize);
|
||||||
|
} else if (step == slaposSupportTree) {
|
||||||
|
invalidated |= this->invalidate_steps({ slaposBasePool, slaposSliceSupports });
|
||||||
|
invalidated |= m_print->invalidate_step(slapsRasterize);
|
||||||
|
} else if (step == slaposBasePool) {
|
||||||
|
invalidated |= this->invalidate_step(slaposSliceSupports);
|
||||||
|
invalidated |= m_print->invalidate_step(slapsRasterize);
|
||||||
|
} else if (step == slaposSliceSupports) {
|
||||||
|
invalidated |= m_print->invalidate_step(slapsRasterize);
|
||||||
|
}
|
||||||
|
return invalidated;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SLAPrintObject::invalidate_all_steps()
|
||||||
|
{
|
||||||
|
return Inherited::invalidate_all_steps() | m_print->invalidate_all_steps();
|
||||||
|
}
|
||||||
|
|
||||||
double SLAPrintObject::get_elevation() const {
|
double SLAPrintObject::get_elevation() const {
|
||||||
double ret = m_config.support_object_elevation.getFloat();
|
double ret = m_config.support_object_elevation.getFloat();
|
||||||
|
|
||||||
|
@ -565,6 +934,18 @@ double SLAPrintObject::get_elevation() const {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double SLAPrintObject::get_current_elevation() const
|
||||||
|
{
|
||||||
|
bool has_supports = is_step_done(slaposSupportTree);
|
||||||
|
bool has_pad = is_step_done(slaposBasePool);
|
||||||
|
if(!has_supports && !has_pad) return 0;
|
||||||
|
else if(has_supports && !has_pad)
|
||||||
|
return m_config.support_object_elevation.getFloat();
|
||||||
|
else return get_elevation();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
namespace { // dummy empty static containers for return values in some methods
|
namespace { // dummy empty static containers for return values in some methods
|
||||||
const std::vector<ExPolygons> EMPTY_SLICES;
|
const std::vector<ExPolygons> EMPTY_SLICES;
|
||||||
const TriangleMesh EMPTY_MESH;
|
const TriangleMesh EMPTY_MESH;
|
||||||
|
|
|
@ -38,16 +38,18 @@ private: // Prevents erroneous use by other classes.
|
||||||
using Inherited = _SLAPrintObjectBase;
|
using Inherited = _SLAPrintObjectBase;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const Transform3d& trafo() const { return m_trafo; }
|
const SLAPrintObjectConfig& config() const { return m_config; }
|
||||||
|
const Transform3d& trafo() const { return m_trafo; }
|
||||||
|
|
||||||
struct Instance {
|
struct Instance {
|
||||||
Instance(ModelID instance_id, const Point &shift, float rotation) : instance_id(instance_id), shift(shift), rotation(rotation) {}
|
Instance(ModelID instance_id, const Point &shift, float rotation) : instance_id(instance_id), shift(shift), rotation(rotation) {}
|
||||||
|
bool operator==(const Instance &rhs) const { return this->instance_id == rhs.instance_id && this->shift == rhs.shift && this->rotation == rhs.rotation; }
|
||||||
// ID of the corresponding ModelInstance.
|
// ID of the corresponding ModelInstance.
|
||||||
ModelID instance_id;
|
ModelID instance_id;
|
||||||
// Slic3r::Point objects in scaled G-code coordinates
|
// Slic3r::Point objects in scaled G-code coordinates
|
||||||
Point shift;
|
Point shift;
|
||||||
// Rotation along the Z axis, in radians.
|
// Rotation along the Z axis, in radians.
|
||||||
float rotation;
|
float rotation;
|
||||||
};
|
};
|
||||||
const std::vector<Instance>& instances() const { return m_instances; }
|
const std::vector<Instance>& instances() const { return m_instances; }
|
||||||
|
|
||||||
|
@ -72,6 +74,11 @@ public:
|
||||||
// as the pad height also needs to be considered.
|
// as the pad height also needs to be considered.
|
||||||
double get_elevation() const;
|
double get_elevation() const;
|
||||||
|
|
||||||
|
// This method returns the needed elevation according to the processing
|
||||||
|
// status. If the supports are not ready, it is zero, if they are and the
|
||||||
|
// pad is not, then without the pad, otherwise the full value is returned.
|
||||||
|
double get_current_elevation() const;
|
||||||
|
|
||||||
// Should be obvious
|
// Should be obvious
|
||||||
const std::vector<ExPolygons>& get_support_slices() const;
|
const std::vector<ExPolygons>& get_support_slices() const;
|
||||||
const std::vector<ExPolygons>& get_model_slices() const;
|
const std::vector<ExPolygons>& get_model_slices() const;
|
||||||
|
@ -95,12 +102,14 @@ protected:
|
||||||
m_transformed_rmesh.invalidate([this, &trafo](){ m_trafo = trafo; });
|
m_transformed_rmesh.invalidate([this, &trafo](){ m_trafo = trafo; });
|
||||||
}
|
}
|
||||||
|
|
||||||
bool set_instances(const std::vector<Instance> &instances);
|
void set_instances(const std::vector<Instance> &instances) { m_instances = instances; }
|
||||||
// Invalidates the step, and its depending steps in SLAPrintObject and SLAPrint.
|
// Invalidates the step, and its depending steps in SLAPrintObject and SLAPrint.
|
||||||
bool invalidate_step(SLAPrintObjectStep step);
|
bool invalidate_step(SLAPrintObjectStep step);
|
||||||
|
bool invalidate_all_steps();
|
||||||
|
// Invalidate steps based on a set of parameters changed.
|
||||||
|
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// Object specific configuration, pulled from the configuration layer.
|
// Object specific configuration, pulled from the configuration layer.
|
||||||
SLAPrintObjectConfig m_config;
|
SLAPrintObjectConfig m_config;
|
||||||
// Translation in Z + Rotation by Y and Z + Scaling / Mirroring.
|
// Translation in Z + Rotation by Y and Z + Scaling / Mirroring.
|
||||||
|
@ -143,7 +152,7 @@ public:
|
||||||
PrinterTechnology technology() const noexcept { return ptSLA; }
|
PrinterTechnology technology() const noexcept { return ptSLA; }
|
||||||
|
|
||||||
void clear() override;
|
void clear() override;
|
||||||
bool empty() const override { return false; }
|
bool empty() const override { return m_objects.empty(); }
|
||||||
ApplyStatus apply(const Model &model, const DynamicPrintConfig &config) override;
|
ApplyStatus apply(const Model &model, const DynamicPrintConfig &config) override;
|
||||||
void process() override;
|
void process() override;
|
||||||
|
|
||||||
|
@ -156,8 +165,13 @@ private:
|
||||||
using SLAPrinter = FilePrinter<FilePrinterFormat::SLA_PNGZIP>;
|
using SLAPrinter = FilePrinter<FilePrinterFormat::SLA_PNGZIP>;
|
||||||
using SLAPrinterPtr = std::unique_ptr<SLAPrinter>;
|
using SLAPrinterPtr = std::unique_ptr<SLAPrinter>;
|
||||||
|
|
||||||
|
// Invalidate steps based on a set of parameters changed.
|
||||||
|
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
|
||||||
|
|
||||||
SLAPrinterConfig m_printer_config;
|
SLAPrinterConfig m_printer_config;
|
||||||
SLAMaterialConfig m_material_config;
|
SLAMaterialConfig m_material_config;
|
||||||
|
SLAPrintObjectConfig m_default_object_config;
|
||||||
|
|
||||||
PrintObjects m_objects;
|
PrintObjects m_objects;
|
||||||
std::vector<bool> m_stepmask;
|
std::vector<bool> m_stepmask;
|
||||||
SLAPrinterPtr m_printer;
|
SLAPrinterPtr m_printer;
|
||||||
|
|
|
@ -31,6 +31,8 @@
|
||||||
#define ENABLE_NEW_MENU_LAYOUT (1 && ENABLE_1_42_0)
|
#define ENABLE_NEW_MENU_LAYOUT (1 && ENABLE_1_42_0)
|
||||||
// All rotations made using the rotate gizmo are done with respect to the world reference system
|
// All rotations made using the rotate gizmo are done with respect to the world reference system
|
||||||
#define ENABLE_WORLD_ROTATIONS (1 && ENABLE_1_42_0)
|
#define ENABLE_WORLD_ROTATIONS (1 && ENABLE_1_42_0)
|
||||||
|
// Enables shortcut keys for gizmos
|
||||||
|
#define ENABLE_GIZMOS_SHORTCUT (1 && ENABLE_1_42_0)
|
||||||
|
|
||||||
#endif // _technologies_h_
|
#endif // _technologies_h_
|
||||||
|
|
||||||
|
|
|
@ -201,6 +201,8 @@ const float GLVolume::HOVER_COLOR[4] = { 0.4f, 0.9f, 0.1f, 1.0f };
|
||||||
const float GLVolume::OUTSIDE_COLOR[4] = { 0.0f, 0.38f, 0.8f, 1.0f };
|
const float GLVolume::OUTSIDE_COLOR[4] = { 0.0f, 0.38f, 0.8f, 1.0f };
|
||||||
const float GLVolume::SELECTED_OUTSIDE_COLOR[4] = { 0.19f, 0.58f, 1.0f, 1.0f };
|
const float GLVolume::SELECTED_OUTSIDE_COLOR[4] = { 0.19f, 0.58f, 1.0f, 1.0f };
|
||||||
const float GLVolume::DISABLED_COLOR[4] = { 0.25f, 0.25f, 0.25f, 1.0f };
|
const float GLVolume::DISABLED_COLOR[4] = { 0.25f, 0.25f, 0.25f, 1.0f };
|
||||||
|
const float GLVolume::SLA_SUPPORT_COLOR[4] = { 0.75f, 0.75f, 0.75f, 1.0f };
|
||||||
|
const float GLVolume::SLA_PAD_COLOR[4] = { 0.0f, 0.2f, 0.0f, 1.0f };
|
||||||
|
|
||||||
GLVolume::GLVolume(float r, float g, float b, float a)
|
GLVolume::GLVolume(float r, float g, float b, float a)
|
||||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||||
|
@ -214,6 +216,7 @@ GLVolume::GLVolume(float r, float g, float b, float a)
|
||||||
, m_world_matrix_dirty(true)
|
, m_world_matrix_dirty(true)
|
||||||
, m_transformed_bounding_box_dirty(true)
|
, m_transformed_bounding_box_dirty(true)
|
||||||
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
||||||
|
, m_sla_shift_z(0.0)
|
||||||
, m_transformed_convex_hull_bounding_box_dirty(true)
|
, m_transformed_convex_hull_bounding_box_dirty(true)
|
||||||
, m_convex_hull(nullptr)
|
, m_convex_hull(nullptr)
|
||||||
, m_convex_hull_owned(false)
|
, m_convex_hull_owned(false)
|
||||||
|
@ -378,7 +381,14 @@ void GLVolume::set_convex_hull(const TriangleMesh *convex_hull, bool owned)
|
||||||
m_convex_hull_owned = owned;
|
m_convex_hull_owned = owned;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !ENABLE_MODELVOLUME_TRANSFORM
|
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||||
|
Transform3d GLVolume::world_matrix() const
|
||||||
|
{
|
||||||
|
Transform3d m = m_instance_transformation.get_matrix() * m_volume_transformation.get_matrix();
|
||||||
|
m.translation()(2) += m_sla_shift_z;
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
#else
|
||||||
const Transform3f& GLVolume::world_matrix() const
|
const Transform3f& GLVolume::world_matrix() const
|
||||||
{
|
{
|
||||||
if (m_world_matrix_dirty)
|
if (m_world_matrix_dirty)
|
||||||
|
@ -388,7 +398,7 @@ const Transform3f& GLVolume::world_matrix() const
|
||||||
}
|
}
|
||||||
return m_world_matrix;
|
return m_world_matrix;
|
||||||
}
|
}
|
||||||
#endif // !ENABLE_MODELVOLUME_TRANSFORM
|
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
||||||
|
|
||||||
const BoundingBoxf3& GLVolume::transformed_bounding_box() const
|
const BoundingBoxf3& GLVolume::transformed_bounding_box() const
|
||||||
{
|
{
|
||||||
|
@ -745,18 +755,9 @@ int GLVolumeCollection::load_object_volume(
|
||||||
{ 0.5f, 0.5f, 1.0f, 1.f }
|
{ 0.5f, 0.5f, 1.0f, 1.f }
|
||||||
};
|
};
|
||||||
|
|
||||||
const ModelVolume *model_volume = model_object->volumes[volume_idx];
|
const ModelVolume *model_volume = model_object->volumes[volume_idx];
|
||||||
|
const int extruder_id = model_volume->extruder_id();
|
||||||
int extruder_id = -1;
|
const ModelInstance *instance = model_object->instances[instance_idx];
|
||||||
if (model_volume->is_model_part())
|
|
||||||
{
|
|
||||||
const ConfigOption *opt = model_volume->config.option("extruder");
|
|
||||||
if (opt == nullptr)
|
|
||||||
opt = model_object->config.option("extruder");
|
|
||||||
extruder_id = (opt == nullptr) ? 0 : opt->getInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
const ModelInstance *instance = model_object->instances[instance_idx];
|
|
||||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||||
const TriangleMesh& mesh = model_volume->mesh;
|
const TriangleMesh& mesh = model_volume->mesh;
|
||||||
#else
|
#else
|
||||||
|
@ -822,21 +823,17 @@ void GLVolumeCollection::load_object_auxiliary(
|
||||||
bool use_VBOs)
|
bool use_VBOs)
|
||||||
{
|
{
|
||||||
assert(print_object->is_step_done(milestone));
|
assert(print_object->is_step_done(milestone));
|
||||||
|
Transform3d mesh_trafo_inv = print_object->trafo().inverse();
|
||||||
// Get the support mesh.
|
// Get the support mesh.
|
||||||
TriangleMesh mesh;
|
TriangleMesh mesh = print_object->get_mesh(milestone);
|
||||||
switch (milestone) {
|
mesh.transform(mesh_trafo_inv);
|
||||||
case slaposSupportTree: mesh = print_object->support_mesh(); break;
|
|
||||||
case slaposBasePool: mesh = print_object->pad_mesh(); break;
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
// Convex hull is required for out of print bed detection.
|
// Convex hull is required for out of print bed detection.
|
||||||
TriangleMesh convex_hull = mesh.convex_hull_3d();
|
TriangleMesh convex_hull = mesh.convex_hull_3d();
|
||||||
|
convex_hull.transform(mesh_trafo_inv);
|
||||||
for (const std::pair<size_t, size_t> &instance_idx : instances) {
|
for (const std::pair<size_t, size_t> &instance_idx : instances) {
|
||||||
const ModelInstance &model_instance = *print_object->model_object()->instances[instance_idx.first];
|
const ModelInstance &model_instance = *print_object->model_object()->instances[instance_idx.first];
|
||||||
const SLAPrintObject::Instance &print_instance = print_object->instances()[instance_idx.second];
|
const SLAPrintObject::Instance &print_instance = print_object->instances()[instance_idx.second];
|
||||||
float color[4] { 0.f, 0.f, 1.f, 1.f };
|
this->volumes.emplace_back(new GLVolume((milestone == slaposBasePool) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR));
|
||||||
this->volumes.emplace_back(new GLVolume(color));
|
|
||||||
GLVolume &v = *this->volumes.back();
|
GLVolume &v = *this->volumes.back();
|
||||||
if (use_VBOs)
|
if (use_VBOs)
|
||||||
v.indexed_vertex_array.load_mesh_full_shading(mesh);
|
v.indexed_vertex_array.load_mesh_full_shading(mesh);
|
||||||
|
@ -845,13 +842,12 @@ void GLVolumeCollection::load_object_auxiliary(
|
||||||
// finalize_geometry() clears the vertex arrays, therefore the bounding box has to be computed before finalize_geometry().
|
// finalize_geometry() clears the vertex arrays, therefore the bounding box has to be computed before finalize_geometry().
|
||||||
v.bounding_box = v.indexed_vertex_array.bounding_box();
|
v.bounding_box = v.indexed_vertex_array.bounding_box();
|
||||||
v.indexed_vertex_array.finalize_geometry(use_VBOs);
|
v.indexed_vertex_array.finalize_geometry(use_VBOs);
|
||||||
v.composite_id = GLVolume::CompositeID(obj_idx, -1, (int)instance_idx.first);
|
v.composite_id = GLVolume::CompositeID(obj_idx, -milestone, (int)instance_idx.first);
|
||||||
v.geometry_id = std::pair<size_t, size_t>(timestamp, model_instance.id().id);
|
v.geometry_id = std::pair<size_t, size_t>(timestamp, model_instance.id().id);
|
||||||
// Create a copy of the convex hull mesh for each instance. Use a move operator on the last instance.
|
// Create a copy of the convex hull mesh for each instance. Use a move operator on the last instance.
|
||||||
v.set_convex_hull((&instance_idx == &instances.back()) ? new TriangleMesh(std::move(convex_hull)) : new TriangleMesh(convex_hull), true);
|
v.set_convex_hull((&instance_idx == &instances.back()) ? new TriangleMesh(std::move(convex_hull)) : new TriangleMesh(convex_hull), true);
|
||||||
v.is_modifier = false;
|
v.is_modifier = false;
|
||||||
v.shader_outside_printer_detection_enabled = true;
|
v.shader_outside_printer_detection_enabled = true;
|
||||||
//FIXME adjust with print_instance?
|
|
||||||
v.set_instance_transformation(model_instance.get_transformation());
|
v.set_instance_transformation(model_instance.get_transformation());
|
||||||
// Leave the volume transformation at identity.
|
// Leave the volume transformation at identity.
|
||||||
// v.set_volume_transformation(model_volume->get_transformation());
|
// v.set_volume_transformation(model_volume->get_transformation());
|
||||||
|
@ -1106,7 +1102,7 @@ void GLVolumeCollection::update_colors_by_extruder(const DynamicPrintConfig* con
|
||||||
|
|
||||||
for (GLVolume* volume : volumes)
|
for (GLVolume* volume : volumes)
|
||||||
{
|
{
|
||||||
if ((volume == nullptr) || volume->is_modifier || volume->is_wipe_tower)
|
if ((volume == nullptr) || volume->is_modifier || volume->is_wipe_tower || (volume->volume_idx() < 0))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int extruder_id = volume->extruder_id - 1;
|
int extruder_id = volume->extruder_id - 1;
|
||||||
|
|
|
@ -253,6 +253,8 @@ public:
|
||||||
static const float OUTSIDE_COLOR[4];
|
static const float OUTSIDE_COLOR[4];
|
||||||
static const float SELECTED_OUTSIDE_COLOR[4];
|
static const float SELECTED_OUTSIDE_COLOR[4];
|
||||||
static const float DISABLED_COLOR[4];
|
static const float DISABLED_COLOR[4];
|
||||||
|
static const float SLA_SUPPORT_COLOR[4];
|
||||||
|
static const float SLA_PAD_COLOR[4];
|
||||||
|
|
||||||
GLVolume(float r = 1.f, float g = 1.f, float b = 1.f, float a = 1.f);
|
GLVolume(float r = 1.f, float g = 1.f, float b = 1.f, float a = 1.f);
|
||||||
GLVolume(const float *rgba) : GLVolume(rgba[0], rgba[1], rgba[2], rgba[3]) {}
|
GLVolume(const float *rgba) : GLVolume(rgba[0], rgba[1], rgba[2], rgba[3]) {}
|
||||||
|
@ -276,6 +278,8 @@ private:
|
||||||
// Whether or not is needed to recalculate the world matrix.
|
// Whether or not is needed to recalculate the world matrix.
|
||||||
mutable bool m_world_matrix_dirty;
|
mutable bool m_world_matrix_dirty;
|
||||||
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
||||||
|
// Shift in z required by sla supports+pad
|
||||||
|
double m_sla_shift_z;
|
||||||
// Bounding box of this volume, in unscaled coordinates.
|
// Bounding box of this volume, in unscaled coordinates.
|
||||||
mutable BoundingBoxf3 m_transformed_bounding_box;
|
mutable BoundingBoxf3 m_transformed_bounding_box;
|
||||||
// Whether or not is needed to recalculate the transformed bounding box.
|
// Whether or not is needed to recalculate the transformed bounding box.
|
||||||
|
@ -424,6 +428,9 @@ public:
|
||||||
const Vec3d& get_offset() const;
|
const Vec3d& get_offset() const;
|
||||||
void set_offset(const Vec3d& offset);
|
void set_offset(const Vec3d& offset);
|
||||||
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
||||||
|
|
||||||
|
double get_sla_shift_z() const { return m_sla_shift_z; }
|
||||||
|
void set_sla_shift_z(double z) { m_sla_shift_z = z; }
|
||||||
|
|
||||||
void set_convex_hull(const TriangleMesh *convex_hull, bool owned);
|
void set_convex_hull(const TriangleMesh *convex_hull, bool owned);
|
||||||
|
|
||||||
|
@ -432,7 +439,7 @@ public:
|
||||||
int instance_idx() const { return this->composite_id.instance_id; }
|
int instance_idx() const { return this->composite_id.instance_id; }
|
||||||
|
|
||||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||||
Transform3d world_matrix() const { return m_instance_transformation.get_matrix() * m_volume_transformation.get_matrix(); }
|
Transform3d world_matrix() const;
|
||||||
#else
|
#else
|
||||||
const Transform3f& world_matrix() const;
|
const Transform3f& world_matrix() const;
|
||||||
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
||||||
|
|
|
@ -1075,7 +1075,6 @@ GLCanvas3D::Selection::VolumeCache::TransformCache::TransformCache()
|
||||||
, scaling_factor(Vec3d::Ones())
|
, scaling_factor(Vec3d::Ones())
|
||||||
, rotation_matrix(Transform3d::Identity())
|
, rotation_matrix(Transform3d::Identity())
|
||||||
, scale_matrix(Transform3d::Identity())
|
, scale_matrix(Transform3d::Identity())
|
||||||
, no_position_matrix(Transform3d::Identity())
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1086,7 +1085,6 @@ GLCanvas3D::Selection::VolumeCache::TransformCache::TransformCache(const Geometr
|
||||||
{
|
{
|
||||||
rotation_matrix = Geometry::assemble_transform(Vec3d::Zero(), rotation);
|
rotation_matrix = Geometry::assemble_transform(Vec3d::Zero(), rotation);
|
||||||
scale_matrix = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), scaling_factor);
|
scale_matrix = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), scaling_factor);
|
||||||
no_position_matrix = transform.get_matrix(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GLCanvas3D::Selection::VolumeCache::VolumeCache(const Geometry::Transformation& volume_transform, const Geometry::Transformation& instance_transform)
|
GLCanvas3D::Selection::VolumeCache::VolumeCache(const Geometry::Transformation& volume_transform, const Geometry::Transformation& instance_transform)
|
||||||
|
@ -1456,7 +1454,7 @@ void GLCanvas3D::Selection::translate(const Vec3d& displacement)
|
||||||
(*m_volumes)[i]->set_instance_offset(m_cache.volumes_data[i].get_instance_position() + displacement);
|
(*m_volumes)[i]->set_instance_offset(m_cache.volumes_data[i].get_instance_position() + displacement);
|
||||||
else if (m_mode == Volume)
|
else if (m_mode == Volume)
|
||||||
{
|
{
|
||||||
Vec3d local_displacement = (m_cache.volumes_data[i].get_instance_no_position_matrix() * m_cache.volumes_data[i].get_volume_no_position_matrix()).inverse() * displacement;
|
Vec3d local_displacement = (m_cache.volumes_data[i].get_instance_rotation_matrix() * m_cache.volumes_data[i].get_volume_rotation_matrix()).inverse() * displacement;
|
||||||
(*m_volumes)[i]->set_volume_offset(m_cache.volumes_data[i].get_volume_position() + local_displacement);
|
(*m_volumes)[i]->set_volume_offset(m_cache.volumes_data[i].get_volume_position() + local_displacement);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -1940,7 +1938,14 @@ void GLCanvas3D::Selection::_update_type()
|
||||||
if (m_cache.content.size() == 1) // single object
|
if (m_cache.content.size() == 1) // single object
|
||||||
{
|
{
|
||||||
const ModelObject* model_object = m_model->objects[m_cache.content.begin()->first];
|
const ModelObject* model_object = m_model->objects[m_cache.content.begin()->first];
|
||||||
unsigned int volumes_count = (unsigned int)model_object->volumes.size();
|
unsigned int model_volumes_count = (unsigned int)model_object->volumes.size();
|
||||||
|
unsigned int sla_volumes_count = 0;
|
||||||
|
for (unsigned int i : m_list)
|
||||||
|
{
|
||||||
|
if ((*m_volumes)[i]->volume_idx() < 0)
|
||||||
|
++sla_volumes_count;
|
||||||
|
}
|
||||||
|
unsigned int volumes_count = model_volumes_count + sla_volumes_count;
|
||||||
unsigned int instances_count = (unsigned int)model_object->instances.size();
|
unsigned int instances_count = (unsigned int)model_object->instances.size();
|
||||||
unsigned int selected_instances_count = (unsigned int)m_cache.content.begin()->second.size();
|
unsigned int selected_instances_count = (unsigned int)m_cache.content.begin()->second.size();
|
||||||
if (volumes_count * instances_count == (unsigned int)m_list.size())
|
if (volumes_count * instances_count == (unsigned int)m_list.size())
|
||||||
|
@ -2659,6 +2664,43 @@ bool GLCanvas3D::Gizmos::is_running() const
|
||||||
return (curr != nullptr) ? (curr->get_state() == GLGizmoBase::On) : false;
|
return (curr != nullptr) ? (curr->get_state() == GLGizmoBase::On) : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_GIZMOS_SHORTCUT
|
||||||
|
bool GLCanvas3D::Gizmos::handle_shortcut(int key, const Selection& selection)
|
||||||
|
{
|
||||||
|
if (!m_enabled)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool handled = false;
|
||||||
|
for (GizmosMap::iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
|
||||||
|
{
|
||||||
|
if ((it->second == nullptr) || !it->second->is_selectable())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int it_key = it->second->get_shortcut_key();
|
||||||
|
|
||||||
|
if (it->second->is_activable(selection) && ((it_key == key - 64) || (it_key == key - 96)))
|
||||||
|
{
|
||||||
|
if ((it->second->get_state() == GLGizmoBase::On))
|
||||||
|
{
|
||||||
|
it->second->set_state(GLGizmoBase::Off);
|
||||||
|
m_current = Undefined;
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
else if ((it->second->get_state() == GLGizmoBase::Off))
|
||||||
|
{
|
||||||
|
it->second->set_state(GLGizmoBase::On);
|
||||||
|
m_current = it->first;
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
it->second->set_state(GLGizmoBase::Off);
|
||||||
|
}
|
||||||
|
|
||||||
|
return handled;
|
||||||
|
}
|
||||||
|
#endif // ENABLE_GIZMOS_SHORTCUT
|
||||||
|
|
||||||
bool GLCanvas3D::Gizmos::is_dragging() const
|
bool GLCanvas3D::Gizmos::is_dragging() const
|
||||||
{
|
{
|
||||||
if (!m_enabled)
|
if (!m_enabled)
|
||||||
|
@ -3800,12 +3842,13 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
||||||
|
|
||||||
struct ModelVolumeState {
|
struct ModelVolumeState {
|
||||||
ModelVolumeState(const GLVolume *volume) :
|
ModelVolumeState(const GLVolume *volume) :
|
||||||
geometry_id(volume->geometry_id), volume_idx(-1) {}
|
model_volume(nullptr), geometry_id(volume->geometry_id), volume_idx(-1) {}
|
||||||
ModelVolumeState(const ModelID &volume_id, const ModelID &instance_id, const GLVolume::CompositeID &composite_id) :
|
ModelVolumeState(const ModelVolume *model_volume, const ModelID &instance_id, const GLVolume::CompositeID &composite_id) :
|
||||||
geometry_id(std::make_pair(volume_id.id, instance_id.id)), composite_id(composite_id), volume_idx(-1) {}
|
model_volume(model_volume), geometry_id(std::make_pair(model_volume->id().id, instance_id.id)), composite_id(composite_id), volume_idx(-1) {}
|
||||||
ModelVolumeState(const ModelID &volume_id, const ModelID &instance_id) :
|
ModelVolumeState(const ModelID &volume_id, const ModelID &instance_id) :
|
||||||
geometry_id(std::make_pair(volume_id.id, instance_id.id)), volume_idx(-1) {}
|
model_volume(nullptr), geometry_id(std::make_pair(volume_id.id, instance_id.id)), volume_idx(-1) {}
|
||||||
bool new_geometry() const { return this->volume_idx == size_t(-1); }
|
bool new_geometry() const { return this->volume_idx == size_t(-1); }
|
||||||
|
const ModelVolume *model_volume;
|
||||||
// ModelID of ModelVolume + ModelID of ModelInstance
|
// ModelID of ModelVolume + ModelID of ModelInstance
|
||||||
// or timestamp of an SLAPrintObjectStep + ModelID of ModelInstance
|
// or timestamp of an SLAPrintObjectStep + ModelID of ModelInstance
|
||||||
std::pair<size_t, size_t> geometry_id;
|
std::pair<size_t, size_t> geometry_id;
|
||||||
|
@ -3844,7 +3887,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
||||||
const ModelInstance *model_instance = model_object->instances[instance_idx];
|
const ModelInstance *model_instance = model_object->instances[instance_idx];
|
||||||
for (int volume_idx = 0; volume_idx < (int)model_object->volumes.size(); ++ volume_idx) {
|
for (int volume_idx = 0; volume_idx < (int)model_object->volumes.size(); ++ volume_idx) {
|
||||||
const ModelVolume *model_volume = model_object->volumes[volume_idx];
|
const ModelVolume *model_volume = model_object->volumes[volume_idx];
|
||||||
model_volume_state.emplace_back(model_volume->id(), model_instance->id(), GLVolume::CompositeID(object_idx, volume_idx, instance_idx));
|
model_volume_state.emplace_back(model_volume, model_instance->id(), GLVolume::CompositeID(object_idx, volume_idx, instance_idx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3894,9 +3937,16 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
||||||
delete volume;
|
delete volume;
|
||||||
} else {
|
} else {
|
||||||
// This GLVolume will be reused.
|
// This GLVolume will be reused.
|
||||||
|
volume->set_sla_shift_z(0.0);
|
||||||
map_glvolume_old_to_new[volume_id] = glvolumes_new.size();
|
map_glvolume_old_to_new[volume_id] = glvolumes_new.size();
|
||||||
mvs->volume_idx = glvolumes_new.size();
|
mvs->volume_idx = glvolumes_new.size();
|
||||||
glvolumes_new.emplace_back(volume);
|
glvolumes_new.emplace_back(volume);
|
||||||
|
// Update color of the volume based on the current extruder.
|
||||||
|
if (mvs->model_volume != nullptr) {
|
||||||
|
int extruder_id = mvs->model_volume->extruder_id();
|
||||||
|
if (extruder_id != -1)
|
||||||
|
volume->extruder_id = extruder_id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3998,7 +4048,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
||||||
instances[istep].emplace_back(std::pair<size_t, size_t>(instance_idx, print_instance_idx));
|
instances[istep].emplace_back(std::pair<size_t, size_t>(instance_idx, print_instance_idx));
|
||||||
else
|
else
|
||||||
// Recycling an old GLVolume. Update the Object/Instance indices into the current Model.
|
// Recycling an old GLVolume. Update the Object/Instance indices into the current Model.
|
||||||
m_volumes.volumes[it->volume_idx]->composite_id = GLVolume::CompositeID(object_idx, -1, instance_idx);
|
m_volumes.volumes[it->volume_idx]->composite_id = GLVolume::CompositeID(object_idx, m_volumes.volumes[it->volume_idx]->volume_idx(), instance_idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4013,11 +4063,11 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
||||||
{
|
{
|
||||||
// If any volume has been added
|
// If any volume has been added
|
||||||
// Shift-up all volumes of the object so that it has the right elevation with respect to the print bed
|
// Shift-up all volumes of the object so that it has the right elevation with respect to the print bed
|
||||||
Vec3d shift_z(0.0, 0.0, print_object->get_elevation());
|
double shift_z = print_object->get_elevation();
|
||||||
for (GLVolume* volume : m_volumes.volumes)
|
for (GLVolume* volume : m_volumes.volumes)
|
||||||
{
|
{
|
||||||
if (volume->object_idx() == object_idx)
|
if (volume->object_idx() == object_idx)
|
||||||
volume->set_instance_offset(volume->get_instance_offset() + shift_z);
|
volume->set_sla_shift_z(shift_z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4273,7 +4323,16 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
|
||||||
#endif // ENABLE_MODIFIED_CAMERA_TARGET
|
#endif // ENABLE_MODIFIED_CAMERA_TARGET
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
evt.Skip();
|
#if ENABLE_GIZMOS_SHORTCUT
|
||||||
|
if (m_gizmos.handle_shortcut(keyCode, m_selection))
|
||||||
|
{
|
||||||
|
_update_gizmos_data();
|
||||||
|
render();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif // ENABLE_GIZMOS_SHORTCUT
|
||||||
|
evt.Skip();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4761,16 +4820,14 @@ void GLCanvas3D::on_key_down(wxKeyEvent& evt)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int key = evt.GetKeyCode();
|
int key = evt.GetKeyCode();
|
||||||
|
#ifdef __WXOSX__
|
||||||
|
if (key == WXK_BACK)
|
||||||
|
#else
|
||||||
if (key == WXK_DELETE)
|
if (key == WXK_DELETE)
|
||||||
|
#endif // __WXOSX__
|
||||||
post_event(SimpleEvent(EVT_GLCANVAS_REMOVE_OBJECT));
|
post_event(SimpleEvent(EVT_GLCANVAS_REMOVE_OBJECT));
|
||||||
else
|
else
|
||||||
{
|
evt.Skip();
|
||||||
#ifdef __WXOSX__
|
|
||||||
if (key == WXK_BACK)
|
|
||||||
post_event(SimpleEvent(EVT_GLCANVAS_REMOVE_OBJECT));
|
|
||||||
#endif
|
|
||||||
evt.Skip();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -384,7 +384,6 @@ public:
|
||||||
Vec3d scaling_factor;
|
Vec3d scaling_factor;
|
||||||
Transform3d rotation_matrix;
|
Transform3d rotation_matrix;
|
||||||
Transform3d scale_matrix;
|
Transform3d scale_matrix;
|
||||||
Transform3d no_position_matrix;
|
|
||||||
|
|
||||||
TransformCache();
|
TransformCache();
|
||||||
explicit TransformCache(const Geometry::Transformation& transform);
|
explicit TransformCache(const Geometry::Transformation& transform);
|
||||||
|
@ -415,14 +414,12 @@ public:
|
||||||
const Vec3d& get_volume_scaling_factor() const { return m_volume.scaling_factor; }
|
const Vec3d& get_volume_scaling_factor() const { return m_volume.scaling_factor; }
|
||||||
const Transform3d& get_volume_rotation_matrix() const { return m_volume.rotation_matrix; }
|
const Transform3d& get_volume_rotation_matrix() const { return m_volume.rotation_matrix; }
|
||||||
const Transform3d& get_volume_scale_matrix() const { return m_volume.scale_matrix; }
|
const Transform3d& get_volume_scale_matrix() const { return m_volume.scale_matrix; }
|
||||||
const Transform3d& get_volume_no_position_matrix() const { return m_volume.no_position_matrix; }
|
|
||||||
|
|
||||||
const Vec3d& get_instance_position() const { return m_instance.position; }
|
const Vec3d& get_instance_position() const { return m_instance.position; }
|
||||||
const Vec3d& get_instance_rotation() const { return m_instance.rotation; }
|
const Vec3d& get_instance_rotation() const { return m_instance.rotation; }
|
||||||
const Vec3d& get_instance_scaling_factor() const { return m_instance.scaling_factor; }
|
const Vec3d& get_instance_scaling_factor() const { return m_instance.scaling_factor; }
|
||||||
const Transform3d& get_instance_rotation_matrix() const { return m_instance.rotation_matrix; }
|
const Transform3d& get_instance_rotation_matrix() const { return m_instance.rotation_matrix; }
|
||||||
const Transform3d& get_instance_scale_matrix() const { return m_instance.scale_matrix; }
|
const Transform3d& get_instance_scale_matrix() const { return m_instance.scale_matrix; }
|
||||||
const Transform3d& get_instance_no_position_matrix() const { return m_instance.no_position_matrix; }
|
|
||||||
#else
|
#else
|
||||||
const Vec3d& get_position() const { return m_position; }
|
const Vec3d& get_position() const { return m_position; }
|
||||||
const Vec3d& get_rotation() const { return m_rotation; }
|
const Vec3d& get_rotation() const { return m_rotation; }
|
||||||
|
@ -611,6 +608,9 @@ private:
|
||||||
EType get_current_type() const;
|
EType get_current_type() const;
|
||||||
|
|
||||||
bool is_running() const;
|
bool is_running() const;
|
||||||
|
#if ENABLE_GIZMOS_SHORTCUT
|
||||||
|
bool handle_shortcut(int key, const Selection& selection);
|
||||||
|
#endif // ENABLE_GIZMOS_SHORTCUT
|
||||||
|
|
||||||
bool is_dragging() const;
|
bool is_dragging() const;
|
||||||
void start_dragging(const Selection& selection);
|
void start_dragging(const Selection& selection);
|
||||||
|
|
|
@ -30,6 +30,10 @@
|
||||||
#include "GUI_Utils.hpp"
|
#include "GUI_Utils.hpp"
|
||||||
#include "GUI_App.hpp"
|
#include "GUI_App.hpp"
|
||||||
|
|
||||||
|
#if ENABLE_GIZMOS_SHORTCUT
|
||||||
|
#include <wx/defs.h>
|
||||||
|
#endif // ENABLE_GIZMOS_SHORTCUT
|
||||||
|
|
||||||
// TODO: Display tooltips quicker on Linux
|
// TODO: Display tooltips quicker on Linux
|
||||||
|
|
||||||
static const float DEFAULT_BASE_COLOR[3] = { 0.625f, 0.625f, 0.625f };
|
static const float DEFAULT_BASE_COLOR[3] = { 0.625f, 0.625f, 0.625f };
|
||||||
|
@ -161,6 +165,9 @@ GLGizmoBase::GLGizmoBase(GLCanvas3D& parent)
|
||||||
: m_parent(parent)
|
: m_parent(parent)
|
||||||
, m_group_id(-1)
|
, m_group_id(-1)
|
||||||
, m_state(Off)
|
, m_state(Off)
|
||||||
|
#if ENABLE_GIZMOS_SHORTCUT
|
||||||
|
, m_shortcut_key(0)
|
||||||
|
#endif // ENABLE_GIZMOS_SHORTCUT
|
||||||
, m_hover_id(-1)
|
, m_hover_id(-1)
|
||||||
, m_dragging(false)
|
, m_dragging(false)
|
||||||
{
|
{
|
||||||
|
@ -639,6 +646,10 @@ bool GLGizmoRotate3D::on_init()
|
||||||
if (!m_textures[On].load_from_file(path + "rotate_on.png", false))
|
if (!m_textures[On].load_from_file(path + "rotate_on.png", false))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
#if ENABLE_GIZMOS_SHORTCUT
|
||||||
|
m_shortcut_key = WXK_CONTROL_R;
|
||||||
|
#endif // ENABLE_GIZMOS_SHORTCUT
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -713,6 +724,10 @@ bool GLGizmoScale3D::on_init()
|
||||||
m_grabbers[2].angles(0) = half_pi;
|
m_grabbers[2].angles(0) = half_pi;
|
||||||
m_grabbers[3].angles(0) = half_pi;
|
m_grabbers[3].angles(0) = half_pi;
|
||||||
|
|
||||||
|
#if ENABLE_GIZMOS_SHORTCUT
|
||||||
|
m_shortcut_key = WXK_CONTROL_S;
|
||||||
|
#endif // ENABLE_GIZMOS_SHORTCUT
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1057,6 +1072,10 @@ bool GLGizmoMove3D::on_init()
|
||||||
m_grabbers.push_back(Grabber());
|
m_grabbers.push_back(Grabber());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_GIZMOS_SHORTCUT
|
||||||
|
m_shortcut_key = WXK_CONTROL_M;
|
||||||
|
#endif // ENABLE_GIZMOS_SHORTCUT
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1213,6 +1232,10 @@ bool GLGizmoFlatten::on_init()
|
||||||
if (!m_textures[On].load_from_file(path + "layflat_on.png", false))
|
if (!m_textures[On].load_from_file(path + "layflat_on.png", false))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
#if ENABLE_GIZMOS_SHORTCUT
|
||||||
|
m_shortcut_key = WXK_CONTROL_F;
|
||||||
|
#endif // ENABLE_GIZMOS_SHORTCUT
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1542,6 +1565,10 @@ bool GLGizmoSlaSupports::on_init()
|
||||||
if (!m_textures[On].load_from_file(path + "sla_support_points_on.png", false))
|
if (!m_textures[On].load_from_file(path + "sla_support_points_on.png", false))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
#if ENABLE_GIZMOS_SHORTCUT
|
||||||
|
m_shortcut_key = WXK_CONTROL_L;
|
||||||
|
#endif // ENABLE_GIZMOS_SHORTCUT
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1893,6 +1920,10 @@ bool GLGizmoCut::on_init()
|
||||||
|
|
||||||
m_grabbers.emplace_back();
|
m_grabbers.emplace_back();
|
||||||
|
|
||||||
|
#if ENABLE_GIZMOS_SHORTCUT
|
||||||
|
m_shortcut_key = WXK_CONTROL_C;
|
||||||
|
#endif // ENABLE_GIZMOS_SHORTCUT
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,9 @@ protected:
|
||||||
|
|
||||||
int m_group_id;
|
int m_group_id;
|
||||||
EState m_state;
|
EState m_state;
|
||||||
|
#if ENABLE_GIZMOS_SHORTCUT
|
||||||
|
int m_shortcut_key;
|
||||||
|
#endif // ENABLE_GIZMOS_SHORTCUT
|
||||||
// textures are assumed to be square and all with the same size in pixels, no internal check is done
|
// textures are assumed to be square and all with the same size in pixels, no internal check is done
|
||||||
GLTexture m_textures[Num_States];
|
GLTexture m_textures[Num_States];
|
||||||
int m_hover_id;
|
int m_hover_id;
|
||||||
|
@ -100,6 +103,11 @@ public:
|
||||||
EState get_state() const { return m_state; }
|
EState get_state() const { return m_state; }
|
||||||
void set_state(EState state) { m_state = state; on_set_state(); }
|
void set_state(EState state) { m_state = state; on_set_state(); }
|
||||||
|
|
||||||
|
#if ENABLE_GIZMOS_SHORTCUT
|
||||||
|
int get_shortcut_key() const { return m_shortcut_key; }
|
||||||
|
void set_shortcut_key(int key) { m_shortcut_key = key; }
|
||||||
|
#endif // ENABLE_GIZMOS_SHORTCUT
|
||||||
|
|
||||||
bool is_activable(const GLCanvas3D::Selection& selection) const { return on_is_activable(selection); }
|
bool is_activable(const GLCanvas3D::Selection& selection) const { return on_is_activable(selection); }
|
||||||
bool is_selectable() const { return on_is_selectable(); }
|
bool is_selectable() const { return on_is_selectable(); }
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ ObjectList::ObjectList(wxWindow* parent) :
|
||||||
{
|
{
|
||||||
// Fill CATEGORY_ICON
|
// Fill CATEGORY_ICON
|
||||||
{
|
{
|
||||||
|
// ptFFF
|
||||||
CATEGORY_ICON[L("Layers and Perimeters")] = wxBitmap(from_u8(var("layers.png")), wxBITMAP_TYPE_PNG);
|
CATEGORY_ICON[L("Layers and Perimeters")] = wxBitmap(from_u8(var("layers.png")), wxBITMAP_TYPE_PNG);
|
||||||
CATEGORY_ICON[L("Infill")] = wxBitmap(from_u8(var("infill.png")), wxBITMAP_TYPE_PNG);
|
CATEGORY_ICON[L("Infill")] = wxBitmap(from_u8(var("infill.png")), wxBITMAP_TYPE_PNG);
|
||||||
CATEGORY_ICON[L("Support material")] = wxBitmap(from_u8(var("building.png")), wxBITMAP_TYPE_PNG);
|
CATEGORY_ICON[L("Support material")] = wxBitmap(from_u8(var("building.png")), wxBITMAP_TYPE_PNG);
|
||||||
|
@ -34,6 +35,9 @@ ObjectList::ObjectList(wxWindow* parent) :
|
||||||
// CATEGORY_ICON[L("Skirt and brim")] = wxBitmap(from_u8(var("box.png")), wxBITMAP_TYPE_PNG);
|
// CATEGORY_ICON[L("Skirt and brim")] = wxBitmap(from_u8(var("box.png")), wxBITMAP_TYPE_PNG);
|
||||||
// CATEGORY_ICON[L("Speed > Acceleration")] = wxBitmap(from_u8(var("time.png")), wxBITMAP_TYPE_PNG);
|
// CATEGORY_ICON[L("Speed > Acceleration")] = wxBitmap(from_u8(var("time.png")), wxBITMAP_TYPE_PNG);
|
||||||
CATEGORY_ICON[L("Advanced")] = wxBitmap(from_u8(var("wand.png")), wxBITMAP_TYPE_PNG);
|
CATEGORY_ICON[L("Advanced")] = wxBitmap(from_u8(var("wand.png")), wxBITMAP_TYPE_PNG);
|
||||||
|
// ptSLA
|
||||||
|
CATEGORY_ICON[L("Supports")] = wxBitmap(from_u8(var("building.png")), wxBITMAP_TYPE_PNG);
|
||||||
|
CATEGORY_ICON[L("Pad")] = wxBitmap(from_u8(var("brick.png")), wxBITMAP_TYPE_PNG);
|
||||||
}
|
}
|
||||||
|
|
||||||
// create control
|
// create control
|
||||||
|
@ -310,8 +314,8 @@ void ObjectList::show_context_menu()
|
||||||
if (!(m_objects_model->GetItemType(item) & (itObject | itVolume)))
|
if (!(m_objects_model->GetItemType(item) & (itObject | itVolume)))
|
||||||
return;
|
return;
|
||||||
const auto menu = m_objects_model->GetParent(item) == wxDataViewItem(0) ?
|
const auto menu = m_objects_model->GetParent(item) == wxDataViewItem(0) ?
|
||||||
create_add_part_popupmenu() :
|
create_object_popupmenu() :
|
||||||
create_part_settings_popupmenu();
|
create_part_popupmenu();
|
||||||
wxGetApp().tab_panel()->GetPage(0)->PopupMenu(menu);
|
wxGetApp().tab_panel()->GetPage(0)->PopupMenu(menu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -436,6 +440,13 @@ void ObjectList::on_drop(wxDataViewEvent &event)
|
||||||
|
|
||||||
std::vector<std::string> get_options(const bool is_part)
|
std::vector<std::string> get_options(const bool is_part)
|
||||||
{
|
{
|
||||||
|
if (wxGetApp().plater()->printer_technology() == ptSLA) {
|
||||||
|
SLAPrintObjectConfig full_sla_config;
|
||||||
|
auto options = full_sla_config.keys();
|
||||||
|
options.erase(find(options.begin(), options.end(), "layer_height"));
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
PrintRegionConfig reg_config;
|
PrintRegionConfig reg_config;
|
||||||
auto options = reg_config.keys();
|
auto options = reg_config.keys();
|
||||||
if (!is_part) {
|
if (!is_part) {
|
||||||
|
@ -463,7 +474,10 @@ void get_options_menu(settings_menu_hierarchy& settings_menu, bool is_part)
|
||||||
if (category.empty() ||
|
if (category.empty() ||
|
||||||
(category == "Extruders" && extruders_cnt == 1)) continue;
|
(category == "Extruders" && extruders_cnt == 1)) continue;
|
||||||
|
|
||||||
std::pair<std::string, std::string> option_label(option, opt->label);
|
const std::string& label = opt->label.empty() ? opt->full_label :
|
||||||
|
opt->full_label.empty() ? opt->label :
|
||||||
|
opt->full_label + " " + opt->label;;
|
||||||
|
std::pair<std::string, std::string> option_label(option, label);
|
||||||
std::vector< std::pair<std::string, std::string> > new_category;
|
std::vector< std::pair<std::string, std::string> > new_category;
|
||||||
auto& cat_opt_label = settings_menu.find(category) == settings_menu.end() ? new_category : settings_menu.at(category);
|
auto& cat_opt_label = settings_menu.find(category) == settings_menu.end() ? new_category : settings_menu.at(category);
|
||||||
cat_opt_label.push_back(option_label);
|
cat_opt_label.push_back(option_label);
|
||||||
|
@ -575,14 +589,27 @@ wxMenuItem* ObjectList::menu_item_settings(wxMenu* menu, int id, const bool is_p
|
||||||
auto menu_item = new wxMenuItem(menu, id, _(L("Add settings")));
|
auto menu_item = new wxMenuItem(menu, id, _(L("Add settings")));
|
||||||
menu_item->SetBitmap(m_bmp_cog);
|
menu_item->SetBitmap(m_bmp_cog);
|
||||||
|
|
||||||
auto sub_menu = create_add_settings_popupmenu(is_part);
|
auto sub_menu = create_settings_popupmenu(is_part);
|
||||||
menu_item->SetSubMenu(sub_menu);
|
menu_item->SetSubMenu(sub_menu);
|
||||||
return menu_item;
|
return menu_item;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxMenu* ObjectList::create_add_part_popupmenu()
|
wxMenu* ObjectList::create_object_popupmenu()
|
||||||
{
|
{
|
||||||
wxMenu *menu = new wxMenu;
|
wxMenu *menu = new wxMenu;
|
||||||
|
if (wxGetApp().plater()->printer_technology() == ptSLA)
|
||||||
|
{
|
||||||
|
wxWindowID config_id_base = NewControlId(1);
|
||||||
|
// Append settings popupmenu
|
||||||
|
menu->Append(menu_item_settings(menu, config_id_base, false));
|
||||||
|
|
||||||
|
menu->Bind(wxEVT_MENU, [menu, this](wxEvent &event) {
|
||||||
|
get_settings_choice(menu, event.GetId(), false);
|
||||||
|
});
|
||||||
|
|
||||||
|
return menu;
|
||||||
|
}
|
||||||
|
|
||||||
// Note: id accords to type of the sub-object, so sequence of the menu items is important
|
// Note: id accords to type of the sub-object, so sequence of the menu items is important
|
||||||
std::vector<std::string> menu_object_types_items = {L("Add part"), // ~ModelVolume::MODEL_PART
|
std::vector<std::string> menu_object_types_items = {L("Add part"), // ~ModelVolume::MODEL_PART
|
||||||
L("Add modifier"), // ~ModelVolume::PARAMETER_MODIFIER
|
L("Add modifier"), // ~ModelVolume::PARAMETER_MODIFIER
|
||||||
|
@ -635,7 +662,7 @@ wxMenu* ObjectList::create_add_part_popupmenu()
|
||||||
return menu;
|
return menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxMenu* ObjectList::create_part_settings_popupmenu()
|
wxMenu* ObjectList::create_part_popupmenu()
|
||||||
{
|
{
|
||||||
wxMenu *menu = new wxMenu;
|
wxMenu *menu = new wxMenu;
|
||||||
wxWindowID config_id_base = NewControlId(3);
|
wxWindowID config_id_base = NewControlId(3);
|
||||||
|
@ -671,7 +698,7 @@ wxMenu* ObjectList::create_part_settings_popupmenu()
|
||||||
return menu;
|
return menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxMenu* ObjectList::create_add_settings_popupmenu(bool is_part)
|
wxMenu* ObjectList::create_settings_popupmenu(bool is_part)
|
||||||
{
|
{
|
||||||
wxMenu *menu = new wxMenu;
|
wxMenu *menu = new wxMenu;
|
||||||
|
|
||||||
|
|
|
@ -98,9 +98,9 @@ public:
|
||||||
void menu_item_add_generic(wxMenuItem* &menu, int id, const int type);
|
void menu_item_add_generic(wxMenuItem* &menu, int id, const int type);
|
||||||
wxMenuItem* menu_item_split(wxMenu* menu, int id);
|
wxMenuItem* menu_item_split(wxMenu* menu, int id);
|
||||||
wxMenuItem* menu_item_settings(wxMenu* menu, int id, const bool is_part);
|
wxMenuItem* menu_item_settings(wxMenu* menu, int id, const bool is_part);
|
||||||
wxMenu* create_add_part_popupmenu();
|
wxMenu* create_object_popupmenu();
|
||||||
wxMenu* create_part_settings_popupmenu();
|
wxMenu* create_part_popupmenu();
|
||||||
wxMenu* create_add_settings_popupmenu(bool is_part);
|
wxMenu* create_settings_popupmenu(bool is_part);
|
||||||
|
|
||||||
void load_subobject(int type);
|
void load_subobject(int type);
|
||||||
void load_part(ModelObject* model_object, wxArrayString& part_names, int type);
|
void load_part(ModelObject* model_object, wxArrayString& part_names, int type);
|
||||||
|
|
|
@ -211,6 +211,11 @@ bool MainFrame::can_delete() const
|
||||||
{
|
{
|
||||||
return (m_plater != nullptr) ? !m_plater->is_selection_empty() : false;
|
return (m_plater != nullptr) ? !m_plater->is_selection_empty() : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MainFrame::can_delete_all() const
|
||||||
|
{
|
||||||
|
return (m_plater != nullptr) ? !m_plater->model().objects.empty() : false;
|
||||||
|
}
|
||||||
#endif // ENABLE_NEW_MENU_LAYOUT
|
#endif // ENABLE_NEW_MENU_LAYOUT
|
||||||
|
|
||||||
void MainFrame::init_menubar()
|
void MainFrame::init_menubar()
|
||||||
|
@ -319,11 +324,15 @@ void MainFrame::init_menubar()
|
||||||
editMenu = new wxMenu();
|
editMenu = new wxMenu();
|
||||||
wxMenuItem* item_select_all = append_menu_item(editMenu, wxID_ANY, L("Select all\tCtrl+A"), L("Selects all objects"),
|
wxMenuItem* item_select_all = append_menu_item(editMenu, wxID_ANY, L("Select all\tCtrl+A"), L("Selects all objects"),
|
||||||
[this](wxCommandEvent&) { m_plater->select_all(); }, "");
|
[this](wxCommandEvent&) { m_plater->select_all(); }, "");
|
||||||
|
editMenu->AppendSeparator();
|
||||||
wxMenuItem* item_delete_sel = append_menu_item(editMenu, wxID_ANY, L("Delete selected\tDel"), L("Deletes the current selection"),
|
wxMenuItem* item_delete_sel = append_menu_item(editMenu, wxID_ANY, L("Delete selected\tDel"), L("Deletes the current selection"),
|
||||||
[this](wxCommandEvent&) { m_plater->remove_selected(); }, "");
|
[this](wxCommandEvent&) { m_plater->remove_selected(); }, "");
|
||||||
|
wxMenuItem* item_delete_all = append_menu_item(editMenu, wxID_ANY, L("Delete all\tCtrl+Del"), L("Deletes all objects"),
|
||||||
|
[this](wxCommandEvent&) { m_plater->reset(); }, "");
|
||||||
|
|
||||||
Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_select()); }, item_select_all->GetId());
|
Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_select()); }, item_select_all->GetId());
|
||||||
Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_delete()); }, item_delete_sel->GetId());
|
Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_delete()); }, item_delete_sel->GetId());
|
||||||
|
Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_delete_all()); }, item_delete_all->GetId());
|
||||||
}
|
}
|
||||||
#endif // ENABLE_NEW_MENU_LAYOUT
|
#endif // ENABLE_NEW_MENU_LAYOUT
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,7 @@ class MainFrame : public wxFrame
|
||||||
bool can_change_view() const;
|
bool can_change_view() const;
|
||||||
bool can_select() const;
|
bool can_select() const;
|
||||||
bool can_delete() const;
|
bool can_delete() const;
|
||||||
|
bool can_delete_all() const;
|
||||||
#endif // ENABLE_NEW_MENU_LAYOUT
|
#endif // ENABLE_NEW_MENU_LAYOUT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -1771,9 +1771,7 @@ unsigned int Plater::priv::update_background_process()
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ptSLA:
|
case ptSLA:
|
||||||
//FIXME as of now the Print::APPLY_STATUS_INVALIDATED is not reliable, and
|
return_state |= UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE;
|
||||||
// currently the scene refresh is expensive and loses selection.
|
|
||||||
//return_state |= UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1984,13 +1982,8 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt)
|
||||||
case ptSLA:
|
case ptSLA:
|
||||||
// Update the SLAPrint from the current Model, so that the reload_scene()
|
// Update the SLAPrint from the current Model, so that the reload_scene()
|
||||||
// pulls the correct data.
|
// pulls the correct data.
|
||||||
|
if (this->update_background_process() & UPDATE_BACKGROUND_PROCESS_RESTART)
|
||||||
// FIXME: SLAPrint::apply is not ready for this. At this stage it would
|
this->schedule_background_process();
|
||||||
// invalidate the previous result and the supports would not be available
|
|
||||||
// for rendering.
|
|
||||||
// if (this->update_background_process() & UPDATE_BACKGROUND_PROCESS_RESTART)
|
|
||||||
// this->schedule_background_process();
|
|
||||||
|
|
||||||
_3DScene::reload_scene(canvas3D, true);
|
_3DScene::reload_scene(canvas3D, true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2281,6 +2274,8 @@ void Plater::select_view(const std::string& direction) { p->select_view(directio
|
||||||
void Plater::select_all() { p->select_all(); }
|
void Plater::select_all() { p->select_all(); }
|
||||||
|
|
||||||
void Plater::remove(size_t obj_idx) { p->remove(obj_idx); }
|
void Plater::remove(size_t obj_idx) { p->remove(obj_idx); }
|
||||||
|
void Plater::reset() { p->reset(); }
|
||||||
|
|
||||||
void Plater::delete_object_from_model(size_t obj_idx) { p->delete_object_from_model(obj_idx); }
|
void Plater::delete_object_from_model(size_t obj_idx) { p->delete_object_from_model(obj_idx); }
|
||||||
|
|
||||||
void Plater::remove_selected()
|
void Plater::remove_selected()
|
||||||
|
|
|
@ -130,6 +130,7 @@ public:
|
||||||
|
|
||||||
void select_all();
|
void select_all();
|
||||||
void remove(size_t obj_idx);
|
void remove(size_t obj_idx);
|
||||||
|
void reset();
|
||||||
void delete_object_from_model(size_t obj_idx);
|
void delete_object_from_model(size_t obj_idx);
|
||||||
void remove_selected();
|
void remove_selected();
|
||||||
void increase_instances(size_t num = 1);
|
void increase_instances(size_t num = 1);
|
||||||
|
|
|
@ -3011,6 +3011,7 @@ void TabSLAPrint::build()
|
||||||
optgroup->append_single_option_line("support_critical_angle");
|
optgroup->append_single_option_line("support_critical_angle");
|
||||||
optgroup->append_single_option_line("support_max_bridge_length");
|
optgroup->append_single_option_line("support_max_bridge_length");
|
||||||
|
|
||||||
|
page = add_options_page(_(L("Pad")), "brick.png");
|
||||||
optgroup = page->new_optgroup(_(L("Pad")));
|
optgroup = page->new_optgroup(_(L("Pad")));
|
||||||
optgroup->append_single_option_line("pad_enable");
|
optgroup->append_single_option_line("pad_enable");
|
||||||
optgroup->append_single_option_line("pad_wall_thickness");
|
optgroup->append_single_option_line("pad_wall_thickness");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue