Undo / Redo. Workaround for the Wipe tower.

This commit is contained in:
bubnikv 2019-07-19 15:29:04 +02:00
parent 2de6d95322
commit dbc1918193
4 changed files with 109 additions and 27 deletions

View file

@ -22,6 +22,8 @@ namespace cereal {
class BinaryOutputArchive; class BinaryOutputArchive;
template <class T> void load_optional(BinaryInputArchive &ar, std::shared_ptr<const T> &ptr); template <class T> void load_optional(BinaryInputArchive &ar, std::shared_ptr<const T> &ptr);
template <class T> void save_optional(BinaryOutputArchive &ar, const std::shared_ptr<const T> &ptr); template <class T> void save_optional(BinaryOutputArchive &ar, const std::shared_ptr<const T> &ptr);
template <class T> void load_by_value(BinaryInputArchive &ar, T &obj);
template <class T> void save_by_value(BinaryOutputArchive &ar, const T &obj);
} }
namespace Slic3r { namespace Slic3r {
@ -31,6 +33,7 @@ class ModelInstance;
class ModelMaterial; class ModelMaterial;
class ModelObject; class ModelObject;
class ModelVolume; class ModelVolume;
class ModelWipeTower;
class Print; class Print;
class SLAPrint; class SLAPrint;
@ -66,6 +69,21 @@ private:
} }
}; };
namespace Internal {
template<typename T>
class StaticSerializationWrapper
{
public:
StaticSerializationWrapper(T &wrap) : wrapped(wrap) {}
private:
friend class cereal::access;
friend class UndoRedo::StackImpl;
template<class Archive> void load(Archive &ar) { cereal::load_by_value(ar, wrapped); }
template<class Archive> void save(Archive &ar) const { cereal::save_by_value(ar, wrapped); }
T& wrapped;
};
}
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;
typedef std::map<t_model_material_attribute, std::string> t_model_material_attributes; typedef std::map<t_model_material_attribute, std::string> t_model_material_attributes;
@ -140,7 +158,8 @@ private:
ModelMaterial() : ObjectBase(-1), config(-1), m_model(nullptr) { assert(this->id().invalid()); assert(this->config.id().invalid()); } ModelMaterial() : ObjectBase(-1), config(-1), m_model(nullptr) { assert(this->id().invalid()); assert(this->config.id().invalid()); }
template<class Archive> void serialize(Archive &ar) { template<class Archive> void serialize(Archive &ar) {
assert(this->id().invalid()); assert(this->config.id().invalid()); assert(this->id().invalid()); assert(this->config.id().invalid());
ar(attributes, config); Internal::StaticSerializationWrapper<ModelConfig> config_wrapper(config);
ar(attributes, config_wrapper);
// assert(this->id().valid()); assert(this->config.id().valid()); // assert(this->id().valid()); assert(this->config.id().valid());
} }
@ -349,7 +368,8 @@ private:
} }
template<class Archive> void serialize(Archive &ar) { template<class Archive> void serialize(Archive &ar) {
ar(cereal::base_class<ObjectBase>(this)); ar(cereal::base_class<ObjectBase>(this));
ar(name, input_file, instances, volumes, config, layer_config_ranges, layer_height_profile, sla_support_points, sla_points_status, origin_translation, Internal::StaticSerializationWrapper<ModelConfig> config_wrapper(config);
ar(name, input_file, instances, volumes, config_wrapper, layer_config_ranges, layer_height_profile, sla_support_points, sla_points_status, origin_translation,
m_bounding_box, m_bounding_box_valid, m_raw_bounding_box, m_raw_bounding_box_valid, m_raw_mesh_bounding_box, m_raw_mesh_bounding_box_valid); m_bounding_box, m_bounding_box_valid, m_raw_bounding_box, m_raw_bounding_box_valid, m_raw_mesh_bounding_box, m_raw_mesh_bounding_box_valid);
} }
}; };
@ -535,7 +555,8 @@ private:
} }
template<class Archive> void load(Archive &ar) { template<class Archive> void load(Archive &ar) {
bool has_convex_hull; bool has_convex_hull;
ar(name, config, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull); ar(name, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull);
cereal::load_by_value(ar, config);
assert(m_mesh); assert(m_mesh);
if (has_convex_hull) { if (has_convex_hull) {
cereal::load_optional(ar, m_convex_hull); cereal::load_optional(ar, m_convex_hull);
@ -547,7 +568,8 @@ private:
} }
template<class Archive> void save(Archive &ar) const { template<class Archive> void save(Archive &ar) const {
bool has_convex_hull = m_convex_hull.get() != nullptr; bool has_convex_hull = m_convex_hull.get() != nullptr;
ar(name, config, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull); ar(name, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull);
cereal::save_by_value(ar, config);
if (has_convex_hull) if (has_convex_hull)
cereal::save_optional(ar, m_convex_hull); cereal::save_optional(ar, m_convex_hull);
} }
@ -650,6 +672,35 @@ private:
} }
}; };
class ModelWipeTower final : public ObjectBase
{
public:
Vec2d position;
double rotation;
private:
friend class cereal::access;
friend class UndoRedo::StackImpl;
friend class Model;
// Constructors to be only called by derived classes.
// Default constructor to assign a unique ID.
explicit ModelWipeTower() {}
// Constructor with ignored int parameter to assign an invalid ID, to be replaced
// by an existing ID copied from elsewhere.
explicit ModelWipeTower(int) : ObjectBase(-1) {}
// Copy constructor copies the ID.
explicit ModelWipeTower(const ModelWipeTower &cfg) = default;
// Disabled methods.
ModelWipeTower(ModelWipeTower &&rhs) = delete;
ModelWipeTower& operator=(const ModelWipeTower &rhs) = delete;
ModelWipeTower& operator=(ModelWipeTower &&rhs) = delete;
// For serialization / deserialization of ModelWipeTower composed into another class into the Undo / Redo stack as a separate object.
template<typename Archive> void serialize(Archive &ar) { ar(position, rotation); }
};
// The print bed content. // The print bed content.
// Description of a triangular model with multiple materials, multiple instances with various affine transformations // Description of a triangular model with multiple materials, multiple instances with various affine transformations
// and with multiple modifier meshes. // and with multiple modifier meshes.
@ -665,6 +716,8 @@ public:
ModelMaterialMap materials; ModelMaterialMap materials;
// Objects are owned by a model. Each model may have multiple instances, each instance having its own transformation (shift, scale, rotation). // Objects are owned by a model. Each model may have multiple instances, each instance having its own transformation (shift, scale, rotation).
ModelObjectPtrs objects; ModelObjectPtrs objects;
// Wipe tower object.
ModelWipeTower wipe_tower;
// Default constructor assigns a new ID to the model. // Default constructor assigns a new ID to the model.
Model() { assert(this->id().valid()); } Model() { assert(this->id().valid()); }
@ -742,7 +795,8 @@ private:
friend class cereal::access; friend class cereal::access;
friend class UndoRedo::StackImpl; friend class UndoRedo::StackImpl;
template<class Archive> void serialize(Archive &ar) { template<class Archive> void serialize(Archive &ar) {
ar(materials, objects); Internal::StaticSerializationWrapper<ModelWipeTower> wipe_tower_wrapper(wipe_tower);
ar(materials, objects, wipe_tower_wrapper);
} }
}; };
@ -778,6 +832,7 @@ void check_model_ids_equal(const Model &model1, const Model &model2);
namespace cereal namespace cereal
{ {
template <class Archive> struct specialize<Archive, Slic3r::ModelVolume, cereal::specialization::member_load_save> {}; template <class Archive> struct specialize<Archive, Slic3r::ModelVolume, cereal::specialization::member_load_save> {};
template <class Archive> struct specialize<Archive, Slic3r::ModelConfig, cereal::specialization::member_serialize> {};
} }
#endif /* slic3r_Model_hpp_ */ #endif /* slic3r_Model_hpp_ */

View file

@ -3586,6 +3586,13 @@ void Plater::priv::take_snapshot(const std::string& snapshot_name)
unsigned int flags = 0; unsigned int flags = 0;
if (this->view3D->is_layers_editing_enabled()) if (this->view3D->is_layers_editing_enabled())
flags |= UndoRedo::Snapshot::VARIABLE_LAYER_EDITING_ACTIVE; flags |= UndoRedo::Snapshot::VARIABLE_LAYER_EDITING_ACTIVE;
//FIXME updating the Wipe tower config values at the ModelWipeTower from the Print config.
// This is a workaround until we refactor the Wipe Tower position / orientation to live solely inside the Model, not in the Print config.
if (this->printer_technology == ptFFF) {
const DynamicPrintConfig &config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
model.wipe_tower.position = Vec2d(config.opt_float("wipe_tower_x"), config.opt_float("wipe_tower_y"));
model.wipe_tower.rotation = config.opt_float("wipe_tower_rotation_angle");
}
this->undo_redo_stack.take_snapshot(snapshot_name, model, view3D->get_canvas3d()->get_selection(), view3D->get_canvas3d()->get_gizmos_manager(), this->printer_technology, flags); this->undo_redo_stack.take_snapshot(snapshot_name, model, view3D->get_canvas3d()->get_selection(), view3D->get_canvas3d()->get_gizmos_manager(), this->printer_technology, flags);
this->undo_redo_stack.release_least_recently_used(); this->undo_redo_stack.release_least_recently_used();
// Save the last active preset name of a particular printer technology. // Save the last active preset name of a particular printer technology.
@ -3632,6 +3639,13 @@ void Plater::priv::undo_redo_to(std::vector<UndoRedo::Snapshot>::const_iterator
} }
// Save the last active preset name of a particular printer technology. // Save the last active preset name of a particular printer technology.
((this->printer_technology == ptFFF) ? m_last_fff_printer_profile_name : m_last_sla_printer_profile_name) = wxGetApp().preset_bundle->printers.get_selected_preset_name(); ((this->printer_technology == ptFFF) ? m_last_fff_printer_profile_name : m_last_sla_printer_profile_name) = wxGetApp().preset_bundle->printers.get_selected_preset_name();
//FIXME updating the Wipe tower config values at the ModelWipeTower from the Print config.
// This is a workaround until we refactor the Wipe Tower position / orientation to live solely inside the Model, not in the Print config.
if (this->printer_technology == ptFFF) {
const DynamicPrintConfig &config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
model.wipe_tower.position = Vec2d(config.opt_float("wipe_tower_x"), config.opt_float("wipe_tower_y"));
model.wipe_tower.rotation = config.opt_float("wipe_tower_rotation_angle");
}
// Flags made of Snapshot::Flags enum values. // Flags made of Snapshot::Flags enum values.
unsigned int new_flags = it_snapshot->flags; unsigned int new_flags = it_snapshot->flags;
unsigned int top_snapshot_flags = 0; unsigned int top_snapshot_flags = 0;
@ -3653,6 +3667,22 @@ void Plater::priv::undo_redo_to(std::vector<UndoRedo::Snapshot>::const_iterator
// Load the currently selected preset into the GUI, update the preset selection box. // Load the currently selected preset into the GUI, update the preset selection box.
// This also switches the printer technology based on the printer technology of the active printer profile. // This also switches the printer technology based on the printer technology of the active printer profile.
wxGetApp().load_current_presets(); wxGetApp().load_current_presets();
}
//FIXME updating the Print config from the Wipe tower config values at the ModelWipeTower.
// This is a workaround until we refactor the Wipe Tower position / orientation to live solely inside the Model, not in the Print config.
if (this->printer_technology == ptFFF) {
const DynamicPrintConfig &current_config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
Vec2d current_position(current_config.opt_float("wipe_tower_x"), current_config.opt_float("wipe_tower_y"));
double current_rotation = current_config.opt_float("wipe_tower_rotation_angle");
if (current_position != model.wipe_tower.position || current_rotation != model.wipe_tower.rotation) {
DynamicPrintConfig new_config;
new_config.set_key_value("wipe_tower_x", new ConfigOptionFloat(model.wipe_tower.position.x()));
new_config.set_key_value("wipe_tower_y", new ConfigOptionFloat(model.wipe_tower.position.y()));
new_config.set_key_value("wipe_tower_rotation_angle", new ConfigOptionFloat(model.wipe_tower.rotation));
Tab *tab_print = wxGetApp().get_tab(Preset::TYPE_PRINT);
tab_print->load_config(new_config);
tab_print->update_dirty();
}
} }
this->update_after_undo_redo(temp_snapshot_was_taken); this->update_after_undo_redo(temp_snapshot_was_taken);
// Enable layer editing after the Undo / Redo jump. // Enable layer editing after the Undo / Redo jump.

View file

@ -514,11 +514,11 @@ public:
const Selection& selection_deserialized() const { return m_selection; } const Selection& selection_deserialized() const { return m_selection; }
//protected: //protected:
template<typename T, typename T_AS> ObjectID save_mutable_object(const T &object); template<typename T> ObjectID save_mutable_object(const T &object);
template<typename T> ObjectID save_immutable_object(std::shared_ptr<const T> &object, bool optional); template<typename T> ObjectID save_immutable_object(std::shared_ptr<const T> &object, bool optional);
template<typename T> T* load_mutable_object(const Slic3r::ObjectID id); template<typename T> T* load_mutable_object(const Slic3r::ObjectID id);
template<typename T> std::shared_ptr<const T> load_immutable_object(const Slic3r::ObjectID id, bool optional); template<typename T> std::shared_ptr<const T> load_immutable_object(const Slic3r::ObjectID id, bool optional);
template<typename T, typename T_AS> void load_mutable_object(const Slic3r::ObjectID id, T &target); template<typename T> void load_mutable_object(const Slic3r::ObjectID id, T &target);
#ifdef SLIC3R_UNDOREDO_DEBUG #ifdef SLIC3R_UNDOREDO_DEBUG
std::string format() const { std::string format() const {
@ -601,7 +601,6 @@ class ModelObject;
class ModelVolume; class ModelVolume;
class ModelInstance; class ModelInstance;
class ModelMaterial; class ModelMaterial;
class ModelConfig;
class DynamicPrintConfig; class DynamicPrintConfig;
class TriangleMesh; class TriangleMesh;
@ -616,14 +615,13 @@ namespace cereal
template <class Archive> struct specialize<Archive, Slic3r::ModelVolume*, cereal::specialization::non_member_load_save> {}; template <class Archive> struct specialize<Archive, Slic3r::ModelVolume*, cereal::specialization::non_member_load_save> {};
template <class Archive> struct specialize<Archive, Slic3r::ModelInstance*, cereal::specialization::non_member_load_save> {}; template <class Archive> struct specialize<Archive, Slic3r::ModelInstance*, cereal::specialization::non_member_load_save> {};
template <class Archive> struct specialize<Archive, Slic3r::ModelMaterial*, cereal::specialization::non_member_load_save> {}; template <class Archive> struct specialize<Archive, Slic3r::ModelMaterial*, cereal::specialization::non_member_load_save> {};
template <class Archive> struct specialize<Archive, Slic3r::ModelConfig, cereal::specialization::non_member_load_save> {};
template <class Archive> struct specialize<Archive, std::shared_ptr<Slic3r::TriangleMesh>, cereal::specialization::non_member_load_save> {}; template <class Archive> struct specialize<Archive, std::shared_ptr<Slic3r::TriangleMesh>, cereal::specialization::non_member_load_save> {};
// Store ObjectBase derived class onto the Undo / Redo stack as a separate object, // Store ObjectBase derived class onto the Undo / Redo stack as a separate object,
// store just the ObjectID to this stream. // store just the ObjectID to this stream.
template <class T> void save(BinaryOutputArchive& ar, T* const& ptr) template <class T> void save(BinaryOutputArchive& ar, T* const& ptr)
{ {
ar(cereal::get_user_data<Slic3r::UndoRedo::StackImpl>(ar).save_mutable_object<T, T>(*ptr)); ar(cereal::get_user_data<Slic3r::UndoRedo::StackImpl>(ar).save_mutable_object<T>(*ptr));
} }
// Load ObjectBase derived class from the Undo / Redo stack as a separate object // Load ObjectBase derived class from the Undo / Redo stack as a separate object
@ -655,19 +653,18 @@ namespace cereal
// Store ObjectBase derived class onto the Undo / Redo stack as a separate object, // Store ObjectBase derived class onto the Undo / Redo stack as a separate object,
// store just the ObjectID to this stream. // store just the ObjectID to this stream.
void save(BinaryOutputArchive& ar, const Slic3r::ModelConfig &cfg) template<class T> void save_by_value(BinaryOutputArchive& ar, const T &cfg)
{ {
ar(cereal::get_user_data<Slic3r::UndoRedo::StackImpl>(ar).save_mutable_object<Slic3r::ModelConfig, Slic3r::DynamicPrintConfig>(cfg)); ar(cereal::get_user_data<Slic3r::UndoRedo::StackImpl>(ar).save_mutable_object<T>(cfg));
} }
// Load ObjectBase derived class from the Undo / Redo stack as a separate object // Load ObjectBase derived class from the Undo / Redo stack as a separate object
// based on the ObjectID loaded from this stream. // based on the ObjectID loaded from this stream.
void load(BinaryInputArchive& ar, Slic3r::ModelConfig &cfg) template<class T> void load_by_value(BinaryInputArchive& ar, T &cfg)
{ {
Slic3r::UndoRedo::StackImpl& stack = cereal::get_user_data<Slic3r::UndoRedo::StackImpl>(ar); Slic3r::UndoRedo::StackImpl& stack = cereal::get_user_data<Slic3r::UndoRedo::StackImpl>(ar);
size_t id; size_t id;
ar(id); ar(id);
stack.load_mutable_object<Slic3r::ModelConfig, Slic3r::DynamicPrintConfig>(Slic3r::ObjectID(id), cfg); stack.load_mutable_object<T>(Slic3r::ObjectID(id), cfg);
} }
// Store ObjectBase derived class onto the Undo / Redo stack as a separate object, // Store ObjectBase derived class onto the Undo / Redo stack as a separate object,
@ -723,7 +720,7 @@ template<typename T> std::shared_ptr<const T>& ImmutableObjectHistory<T>::share
return m_shared_object; return m_shared_object;
} }
template<typename T, typename T_AS> ObjectID StackImpl::save_mutable_object(const T &object) template<typename T> ObjectID StackImpl::save_mutable_object(const T &object)
{ {
// First find or allocate a history stack for the ObjectID of this object instance. // First find or allocate a history stack for the ObjectID of this object instance.
auto it_object_history = m_objects.find(object.id()); auto it_object_history = m_objects.find(object.id());
@ -734,7 +731,7 @@ template<typename T, typename T_AS> ObjectID StackImpl::save_mutable_object(cons
std::ostringstream oss; std::ostringstream oss;
{ {
Slic3r::UndoRedo::OutputArchive archive(*this, oss); Slic3r::UndoRedo::OutputArchive archive(*this, oss);
archive(static_cast<const T_AS&>(object)); archive(object);
} }
object_history->save(m_active_snapshot_time, m_current_time, oss.str()); object_history->save(m_active_snapshot_time, m_current_time, oss.str());
return object.id(); return object.id();
@ -758,7 +755,7 @@ template<typename T> ObjectID StackImpl::save_immutable_object(std::shared_ptr<c
template<typename T> T* StackImpl::load_mutable_object(const Slic3r::ObjectID id) template<typename T> T* StackImpl::load_mutable_object(const Slic3r::ObjectID id)
{ {
T *target = new T(); T *target = new T();
this->load_mutable_object<T, T>(id, *target); this->load_mutable_object<T>(id, *target);
return target; return target;
} }
@ -775,7 +772,7 @@ template<typename T> std::shared_ptr<const T> StackImpl::load_immutable_object(c
return object_history->shared_ptr(*this); return object_history->shared_ptr(*this);
} }
template<typename T, typename T_AS> void StackImpl::load_mutable_object(const Slic3r::ObjectID id, T &target) template<typename T> void StackImpl::load_mutable_object(const Slic3r::ObjectID id, T &target)
{ {
// First find a history stack for the ObjectID of this object instance. // First find a history stack for the ObjectID of this object instance.
auto it_object_history = m_objects.find(id); auto it_object_history = m_objects.find(id);
@ -785,7 +782,7 @@ template<typename T, typename T_AS> void StackImpl::load_mutable_object(const Sl
std::istringstream iss(object_history->load(m_active_snapshot_time)); std::istringstream iss(object_history->load(m_active_snapshot_time));
Slic3r::UndoRedo::InputArchive archive(*this, iss); Slic3r::UndoRedo::InputArchive archive(*this, iss);
target.m_id = id; target.m_id = id;
archive(static_cast<T_AS&>(target)); archive(target);
} }
// Store the current application state onto the Undo / Redo stack, remove all snapshots after m_active_snapshot_time. // Store the current application state onto the Undo / Redo stack, remove all snapshots after m_active_snapshot_time.
@ -800,14 +797,14 @@ void StackImpl::take_snapshot(const std::string& snapshot_name, const Slic3r::Mo
m_snapshots.erase(it, m_snapshots.end()); m_snapshots.erase(it, m_snapshots.end());
} }
// Take new snapshots. // Take new snapshots.
this->save_mutable_object<Slic3r::Model, Slic3r::Model>(model); this->save_mutable_object<Slic3r::Model>(model);
m_selection.volumes_and_instances.clear(); m_selection.volumes_and_instances.clear();
m_selection.volumes_and_instances.reserve(selection.get_volume_idxs().size()); m_selection.volumes_and_instances.reserve(selection.get_volume_idxs().size());
m_selection.mode = selection.get_mode(); m_selection.mode = selection.get_mode();
for (unsigned int volume_idx : selection.get_volume_idxs()) for (unsigned int volume_idx : selection.get_volume_idxs())
m_selection.volumes_and_instances.emplace_back(selection.get_volume(volume_idx)->geometry_id); m_selection.volumes_and_instances.emplace_back(selection.get_volume(volume_idx)->geometry_id);
this->save_mutable_object<Selection, Selection>(m_selection); this->save_mutable_object<Selection>(m_selection);
this->save_mutable_object<Slic3r::GUI::GLGizmosManager, Slic3r::GUI::GLGizmosManager>(gizmos); this->save_mutable_object<Slic3r::GUI::GLGizmosManager>(gizmos);
// Save the snapshot info. // Save the snapshot info.
m_snapshots.emplace_back(snapshot_name, m_current_time ++, model.id().id, printer_technology, flags); m_snapshots.emplace_back(snapshot_name, m_current_time ++, model.id().id, printer_technology, flags);
m_active_snapshot_time = m_current_time; m_active_snapshot_time = m_current_time;
@ -833,12 +830,12 @@ void StackImpl::load_snapshot(size_t timestamp, Slic3r::Model& model, Slic3r::GU
m_active_snapshot_time = timestamp; m_active_snapshot_time = timestamp;
model.clear_objects(); model.clear_objects();
model.clear_materials(); model.clear_materials();
this->load_mutable_object<Slic3r::Model, Slic3r::Model>(ObjectID(it_snapshot->model_id), model); this->load_mutable_object<Slic3r::Model>(ObjectID(it_snapshot->model_id), model);
model.update_links_bottom_up_recursive(); model.update_links_bottom_up_recursive();
m_selection.volumes_and_instances.clear(); m_selection.volumes_and_instances.clear();
this->load_mutable_object<Selection, Selection>(m_selection.id(), m_selection); this->load_mutable_object<Selection>(m_selection.id(), m_selection);
gizmos.reset_all_states(); gizmos.reset_all_states();
this->load_mutable_object<Slic3r::GUI::GLGizmosManager, Slic3r::GUI::GLGizmosManager>(gizmos.id(), gizmos); this->load_mutable_object<Slic3r::GUI::GLGizmosManager>(gizmos.id(), gizmos);
// Sort the volumes so that we may use binary search. // Sort the volumes so that we may use binary search.
std::sort(m_selection.volumes_and_instances.begin(), m_selection.volumes_and_instances.end()); std::sort(m_selection.volumes_and_instances.begin(), m_selection.volumes_and_instances.end());
this->m_active_snapshot_time = timestamp; this->m_active_snapshot_time = timestamp;