diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index d5ee6a048..81880831f 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -169,6 +169,9 @@ static inline Point wipe_tower_point_to_object_point(GCode &gcodegen, const Vec2 std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::ToolChangeResult &tcr, int new_extruder_id) const { + if (new_extruder_id != -1 && new_extruder_id != tcr.new_tool) + throw std::invalid_argument("Error: WipeTowerIntegration::append_tcr was asked to do a toolchange it didn't expect."); + std::string gcode; // Toolchangeresult.gcode assumes the wipe tower corner is at the origin @@ -182,8 +185,11 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T end_pos = Eigen::Rotation2Df(alpha) * end_pos; end_pos += m_wipe_tower_pos; } - std::string tcr_rotated_gcode = tcr.priming ? tcr.gcode : rotate_wipe_tower_moves(tcr.gcode, tcr.start_pos, m_wipe_tower_pos, alpha); - + + Vec2f wipe_tower_offset = tcr.priming ? Vec2f::Zero() : m_wipe_tower_pos; + float wipe_tower_rotation = tcr.priming ? 0.f : alpha; + + std::string tcr_rotated_gcode = post_process_wipe_tower_moves(tcr, wipe_tower_offset, wipe_tower_rotation); // Disable linear advance for the wipe tower operations. gcode += (gcodegen.config().gcode_flavor == gcfRepRap ? std::string("M572 D0 S0\n") : std::string("M900 K0\n")); @@ -285,17 +291,21 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T // This function postprocesses gcode_original, rotates and moves all G1 extrusions and returns resulting gcode // Starting position has to be supplied explicitely (otherwise it would fail in case first G1 command only contained one coordinate) -std::string WipeTowerIntegration::rotate_wipe_tower_moves(const std::string& gcode_original, const Vec2f& start_pos, const Vec2f& translation, float angle) const +std::string WipeTowerIntegration::post_process_wipe_tower_moves(const WipeTower::ToolChangeResult& tcr, const Vec2f& translation, float angle) const { - std::istringstream gcode_str(gcode_original); + Vec2f extruder_offset = m_extruder_offsets[tcr.initial_tool].cast(); + + std::istringstream gcode_str(tcr.gcode); std::string gcode_out; std::string line; - Vec2f pos = start_pos; - Vec2f transformed_pos; + Vec2f pos = tcr.start_pos; + Vec2f transformed_pos = pos; Vec2f old_pos(-1000.1f, -1000.1f); while (gcode_str) { std::getline(gcode_str, line); // we read the gcode line by line + + // All G1 commands should be translated and rotated if (line.find("G1 ") == 0) { std::ostringstream line_out; std::istringstream line_str(line); @@ -317,17 +327,34 @@ std::string WipeTowerIntegration::rotate_wipe_tower_moves(const std::string& gco if (transformed_pos != old_pos) { line = line_out.str(); - char buf[2048] = "G1"; + std::ostringstream oss; + oss << std::fixed << std::setprecision(3) << "G1 "; if (transformed_pos.x() != old_pos.x()) - sprintf(buf + strlen(buf), " X%.3f", transformed_pos.x()); + oss << " X" << transformed_pos.x() - extruder_offset.x(); if (transformed_pos.y() != old_pos.y()) - sprintf(buf + strlen(buf), " Y%.3f", transformed_pos.y()); + oss << " Y" << transformed_pos.y() - extruder_offset.y(); - line.replace(line.find("G1 "), 3, buf); + line.replace(line.find("G1 "), 3, oss.str()); old_pos = transformed_pos; } } + gcode_out += line + "\n"; + + // If this was a toolchange command, we should change current extruder offset + if (line == "[toolchange_gcode]") { + extruder_offset = m_extruder_offsets[tcr.new_tool].cast(); + + // If the extruder offset changed, add an extra move so everything is continuous + if (extruder_offset != m_extruder_offsets[tcr.initial_tool].cast()) { + std::ostringstream oss; + oss << std::fixed << std::setprecision(3) + << "G1 X" << transformed_pos.x() - extruder_offset.x() + << " Y" << transformed_pos.y() - extruder_offset.y() + << "\n"; + gcode_out += oss.str(); + } + } } return gcode_out; } diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 4b81b42aa..f2a67f600 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -90,6 +90,7 @@ public: m_right(float(/*print_config.wipe_tower_x.value +*/ print_config.wipe_tower_width.value)), m_wipe_tower_pos(float(print_config.wipe_tower_x.value), float(print_config.wipe_tower_y.value)), m_wipe_tower_rotation(float(print_config.wipe_tower_rotation_angle)), + m_extruder_offsets(print_config.extruder_offset.values), m_priming(priming), m_tool_changes(tool_changes), m_final_purge(final_purge), @@ -107,14 +108,16 @@ private: WipeTowerIntegration& operator=(const WipeTowerIntegration&); std::string append_tcr(GCode &gcodegen, const WipeTower::ToolChangeResult &tcr, int new_extruder_id) const; - // Postprocesses gcode: rotates and moves all G1 extrusions and returns result - std::string rotate_wipe_tower_moves(const std::string& gcode_original, const Vec2f& start_pos, const Vec2f& translation, float angle) const; + // Postprocesses gcode: rotates and moves G1 extrusions and returns result + std::string post_process_wipe_tower_moves(const WipeTower::ToolChangeResult& tcr, const Vec2f& translation, float angle) const; // Left / right edges of the wipe tower, for the planning of wipe moves. const float m_left; const float m_right; const Vec2f m_wipe_tower_pos; const float m_wipe_tower_rotation; + const std::vector m_extruder_offsets; + // Reference to cached values at the Printer class. const std::vector &m_priming; const std::vector> &m_tool_changes; diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index 37e4040d1..354ec6d9e 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -553,7 +553,7 @@ std::vector WipeTower::prime( result.elapsed_time = writer.elapsed_time(); result.extrusions = writer.extrusions(); result.start_pos = writer.start_pos_rotated(); - result.end_pos = writer.pos_rotated(); + result.end_pos = writer.pos(); results.push_back(std::move(result)); @@ -643,7 +643,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change(unsigned int tool, bool last_ m_is_first_layer ? m_filpar[tool].first_layer_temperature : m_filpar[tool].temperature); toolchange_Change(writer, tool, m_filpar[tool].material); // Change the tool, set a speed override for soluble and flex materials. toolchange_Load(writer, cleaning_box); - writer.travel(writer.x(),writer.y()-m_perimeter_width); // cooling and loading were done a bit down the road + writer.travel(writer.x(), writer.y()-m_perimeter_width); // cooling and loading were done a bit down the road toolchange_Wipe(writer, cleaning_box, wipe_volume); // Wipe the newly loaded filament until the end of the assigned wipe area. ++ m_num_tool_changes; } else diff --git a/src/libslic3r/GCode/WipeTower.hpp b/src/libslic3r/GCode/WipeTower.hpp index c18a502b1..badb3e8b2 100644 --- a/src/libslic3r/GCode/WipeTower.hpp +++ b/src/libslic3r/GCode/WipeTower.hpp @@ -139,13 +139,15 @@ public: m_perimeter_width = nozzle_diameter * Width_To_Nozzle_Ratio; // all extruders are now assumed to have the same diameter - std::stringstream stream{m_semm ? ramming_parameters : std::string()}; - float speed = 0.f; - stream >> m_filpar[idx].ramming_line_width_multiplicator >> m_filpar[idx].ramming_step_multiplicator; - m_filpar[idx].ramming_line_width_multiplicator /= 100; - m_filpar[idx].ramming_step_multiplicator /= 100; - while (stream >> speed) - m_filpar[idx].ramming_speed.push_back(speed); + if (m_semm) { + std::stringstream stream{ramming_parameters}; + float speed = 0.f; + stream >> m_filpar[idx].ramming_line_width_multiplicator >> m_filpar[idx].ramming_step_multiplicator; + m_filpar[idx].ramming_line_width_multiplicator /= 100; + m_filpar[idx].ramming_step_multiplicator /= 100; + while (stream >> speed) + m_filpar[idx].ramming_speed.push_back(speed); + } m_used_filament_length.resize(std::max(m_used_filament_length.size(), idx + 1)); // makes sure that the vector is big enough so we don't have to check later } @@ -241,8 +243,8 @@ public: int cooling_moves = 0; float cooling_initial_speed = 0.f; float cooling_final_speed = 0.f; - float ramming_line_width_multiplicator = 0.f; - float ramming_step_multiplicator = 0.f; + float ramming_line_width_multiplicator = 1.f; + float ramming_step_multiplicator = 1.f; float max_e_speed = std::numeric_limits::max(); std::vector ramming_speed; float nozzle_diameter; diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 66532e9ea..21e155793 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1971,4 +1971,4 @@ CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ObjectBase, Slic3r::ModelObject) CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ObjectBase, Slic3r::ModelVolume) CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ObjectBase, Slic3r::ModelInstance) CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ObjectBase, Slic3r::Model) -#endif \ No newline at end of file +#endif diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 2b4a6d978..f03d53153 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -22,6 +22,8 @@ namespace cereal { class BinaryOutputArchive; template void load_optional(BinaryInputArchive &ar, std::shared_ptr &ptr); template void save_optional(BinaryOutputArchive &ar, const std::shared_ptr &ptr); + template void load_by_value(BinaryInputArchive &ar, T &obj); + template void save_by_value(BinaryOutputArchive &ar, const T &obj); } namespace Slic3r { @@ -31,6 +33,7 @@ class ModelInstance; class ModelMaterial; class ModelObject; class ModelVolume; +class ModelWipeTower; class Print; class SLAPrint; @@ -66,6 +69,21 @@ private: } }; +namespace Internal { + template + class StaticSerializationWrapper + { + public: + StaticSerializationWrapper(T &wrap) : wrapped(wrap) {} + private: + friend class cereal::access; + friend class UndoRedo::StackImpl; + template void load(Archive &ar) { cereal::load_by_value(ar, wrapped); } + template 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_attribute; typedef std::map 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()); } template void serialize(Archive &ar) { assert(this->id().invalid()); assert(this->config.id().invalid()); - ar(attributes, config); + Internal::StaticSerializationWrapper config_wrapper(config); + ar(attributes, config_wrapper); // assert(this->id().valid()); assert(this->config.id().valid()); } @@ -349,7 +368,8 @@ private: } template void serialize(Archive &ar) { ar(cereal::base_class(this)); - ar(name, input_file, instances, volumes, config, layer_config_ranges, layer_height_profile, sla_support_points, sla_points_status, origin_translation, + Internal::StaticSerializationWrapper 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); } }; @@ -535,7 +555,8 @@ private: } template void load(Archive &ar) { 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); if (has_convex_hull) { cereal::load_optional(ar, m_convex_hull); @@ -547,7 +568,8 @@ private: } template void save(Archive &ar) const { 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) 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 void serialize(Archive &ar) { ar(position, rotation); } +}; + // The print bed content. // Description of a triangular model with multiple materials, multiple instances with various affine transformations // and with multiple modifier meshes. @@ -665,6 +716,8 @@ public: ModelMaterialMap materials; // Objects are owned by a model. Each model may have multiple instances, each instance having its own transformation (shift, scale, rotation). ModelObjectPtrs objects; + // Wipe tower object. + ModelWipeTower wipe_tower; // Default constructor assigns a new ID to the model. Model() { assert(this->id().valid()); } @@ -742,7 +795,8 @@ private: friend class cereal::access; friend class UndoRedo::StackImpl; template void serialize(Archive &ar) { - ar(materials, objects); + Internal::StaticSerializationWrapper 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 { template struct specialize {}; + template struct specialize {}; } #endif /* slic3r_Model_hpp_ */ diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 76b16f055..5b8d6eca3 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3586,6 +3586,13 @@ void Plater::priv::take_snapshot(const std::string& snapshot_name) unsigned int flags = 0; if (this->view3D->is_layers_editing_enabled()) 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.release_least_recently_used(); // Save the last active preset name of a particular printer technology. @@ -3632,6 +3639,13 @@ void Plater::priv::undo_redo_to(std::vector::const_iterator } // 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(); + //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. unsigned int new_flags = it_snapshot->flags; unsigned int top_snapshot_flags = 0; @@ -3654,6 +3668,22 @@ void Plater::priv::undo_redo_to(std::vector::const_iterator // This also switches the printer technology based on the printer technology of the active printer profile. 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 ¤t_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); // Enable layer editing after the Undo / Redo jump. if (! view3D->is_layers_editing_enabled() && this->layers_height_allowed() && new_variable_layer_editing_active) diff --git a/src/slic3r/Utils/UndoRedo.cpp b/src/slic3r/Utils/UndoRedo.cpp index 2605bd2a7..a8f9cc134 100644 --- a/src/slic3r/Utils/UndoRedo.cpp +++ b/src/slic3r/Utils/UndoRedo.cpp @@ -514,11 +514,11 @@ public: const Selection& selection_deserialized() const { return m_selection; } //protected: - template ObjectID save_mutable_object(const T &object); + template ObjectID save_mutable_object(const T &object); template ObjectID save_immutable_object(std::shared_ptr &object, bool optional); template T* load_mutable_object(const Slic3r::ObjectID id); template std::shared_ptr load_immutable_object(const Slic3r::ObjectID id, bool optional); - template void load_mutable_object(const Slic3r::ObjectID id, T &target); + template void load_mutable_object(const Slic3r::ObjectID id, T &target); #ifdef SLIC3R_UNDOREDO_DEBUG std::string format() const { @@ -601,7 +601,6 @@ class ModelObject; class ModelVolume; class ModelInstance; class ModelMaterial; -class ModelConfig; class DynamicPrintConfig; class TriangleMesh; @@ -616,14 +615,13 @@ namespace cereal template struct specialize {}; template struct specialize {}; template struct specialize {}; - template struct specialize {}; template struct specialize, cereal::specialization::non_member_load_save> {}; // Store ObjectBase derived class onto the Undo / Redo stack as a separate object, // store just the ObjectID to this stream. template void save(BinaryOutputArchive& ar, T* const& ptr) { - ar(cereal::get_user_data(ar).save_mutable_object(*ptr)); + ar(cereal::get_user_data(ar).save_mutable_object(*ptr)); } // 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 just the ObjectID to this stream. - void save(BinaryOutputArchive& ar, const Slic3r::ModelConfig &cfg) + template void save_by_value(BinaryOutputArchive& ar, const T &cfg) { - ar(cereal::get_user_data(ar).save_mutable_object(cfg)); + ar(cereal::get_user_data(ar).save_mutable_object(cfg)); } - // Load ObjectBase derived class from the Undo / Redo stack as a separate object // based on the ObjectID loaded from this stream. - void load(BinaryInputArchive& ar, Slic3r::ModelConfig &cfg) + template void load_by_value(BinaryInputArchive& ar, T &cfg) { Slic3r::UndoRedo::StackImpl& stack = cereal::get_user_data(ar); size_t id; ar(id); - stack.load_mutable_object(Slic3r::ObjectID(id), cfg); + stack.load_mutable_object(Slic3r::ObjectID(id), cfg); } // Store ObjectBase derived class onto the Undo / Redo stack as a separate object, @@ -723,7 +720,7 @@ template std::shared_ptr& ImmutableObjectHistory::share return m_shared_object; } -template ObjectID StackImpl::save_mutable_object(const T &object) +template ObjectID StackImpl::save_mutable_object(const T &object) { // First find or allocate a history stack for the ObjectID of this object instance. auto it_object_history = m_objects.find(object.id()); @@ -734,7 +731,7 @@ template ObjectID StackImpl::save_mutable_object(cons std::ostringstream oss; { Slic3r::UndoRedo::OutputArchive archive(*this, oss); - archive(static_cast(object)); + archive(object); } object_history->save(m_active_snapshot_time, m_current_time, oss.str()); return object.id(); @@ -758,7 +755,7 @@ template ObjectID StackImpl::save_immutable_object(std::shared_ptr T* StackImpl::load_mutable_object(const Slic3r::ObjectID id) { T *target = new T(); - this->load_mutable_object(id, *target); + this->load_mutable_object(id, *target); return target; } @@ -775,7 +772,7 @@ template std::shared_ptr StackImpl::load_immutable_object(c return object_history->shared_ptr(*this); } -template void StackImpl::load_mutable_object(const Slic3r::ObjectID id, T &target) +template void StackImpl::load_mutable_object(const Slic3r::ObjectID id, T &target) { // First find a history stack for the ObjectID of this object instance. auto it_object_history = m_objects.find(id); @@ -785,7 +782,7 @@ template void StackImpl::load_mutable_object(const Sl std::istringstream iss(object_history->load(m_active_snapshot_time)); Slic3r::UndoRedo::InputArchive archive(*this, iss); target.m_id = id; - archive(static_cast(target)); + archive(target); } // 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()); } // Take new snapshots. - this->save_mutable_object(model); + this->save_mutable_object(model); m_selection.volumes_and_instances.clear(); m_selection.volumes_and_instances.reserve(selection.get_volume_idxs().size()); m_selection.mode = selection.get_mode(); for (unsigned int volume_idx : selection.get_volume_idxs()) m_selection.volumes_and_instances.emplace_back(selection.get_volume(volume_idx)->geometry_id); - this->save_mutable_object(m_selection); - this->save_mutable_object(gizmos); + this->save_mutable_object(m_selection); + this->save_mutable_object(gizmos); // Save the snapshot info. m_snapshots.emplace_back(snapshot_name, m_current_time ++, model.id().id, printer_technology, flags); 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; model.clear_objects(); model.clear_materials(); - this->load_mutable_object(ObjectID(it_snapshot->model_id), model); + this->load_mutable_object(ObjectID(it_snapshot->model_id), model); model.update_links_bottom_up_recursive(); m_selection.volumes_and_instances.clear(); - this->load_mutable_object(m_selection.id(), m_selection); + this->load_mutable_object(m_selection.id(), m_selection); gizmos.reset_all_states(); - this->load_mutable_object(gizmos.id(), gizmos); + this->load_mutable_object(gizmos.id(), gizmos); // Sort the volumes so that we may use binary search. std::sort(m_selection.volumes_and_instances.begin(), m_selection.volumes_and_instances.end()); this->m_active_snapshot_time = timestamp;