OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::UndoRedo::StackImpl Class Reference
Collaboration diagram for Slic3r::UndoRedo::StackImpl:

Public Member Functions

 StackImpl ()
void clear ()
bool empty () const
void set_memory_limit (size_t memsize)
size_t get_memory_limit () const
size_t memsize () const
void take_snapshot (const std::string &snapshot_name, const Slic3r::Model &model, const Slic3r::GUI::Selection &selection, const Slic3r::GUI::GLGizmosManager &gizmos, const Slic3r::GUI::PartPlateList &plate_list, const SnapshotData &snapshot_data)
void take_snapshot (const std::string &snapshot_name, const Slic3r::Model &model, const Slic3r::GUI::Selection &selection, const Slic3r::GUI::GLGizmosManager &gizmos, const SnapshotData &snapshot_data)
void reduce_noisy_snapshots (const std::string &new_name)
void load_snapshot (size_t timestamp, Slic3r::Model &model, Slic3r::GUI::GLGizmosManager &gizmos, Slic3r::GUI::PartPlateList &plate_list)
bool has_undo_snapshot () const
bool has_undo_snapshot (size_t time_to_load) const
bool has_redo_snapshot () const
bool undo (Slic3r::Model &model, const Slic3r::GUI::Selection &selection, Slic3r::GUI::GLGizmosManager &gizmos, Slic3r::GUI::PartPlateList &plate_list, const SnapshotData &snapshot_data, size_t jump_to_time)
bool redo (Slic3r::Model &model, Slic3r::GUI::GLGizmosManager &gizmos, Slic3r::GUI::PartPlateList &plate_list, size_t jump_to_time)
void release_least_recently_used ()
const std::vector< Snapshot > & snapshots () const
const Snapshot & snapshot (size_t time) const
size_t active_snapshot_time () const
bool temp_snapshot_active () const
void mark_current_as_saved ()
bool project_modified () const
bool has_real_change_from (size_t time) const
const Selection & selection_deserialized () const
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>
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>
void load_mutable_object (const Slic3r::ObjectID id, T &target)
bool valid () const

Private Member Functions

template<typename T>
ObjectID immutable_object_id (const std::shared_ptr< const T > &ptr)
ObjectID immutable_object_id_impl (const void *ptr)
void collect_garbage ()
std::vector< Snapshot >::iterator release_snapshots (std::vector< Snapshot >::iterator begin, std::vector< Snapshot >::iterator end)

Private Attributes

size_t m_memory_limit
std::map< ObjectID, std::unique_ptr< ObjectHistoryBase > > m_objects
std::map< const void *, ObjectID > m_shared_ptr_to_object_id
std::vector< Snapshot > m_snapshots
size_t m_active_snapshot_time
size_t m_saved_snapshot_time { size_t(-1) }
size_t m_current_time
Selection m_selection
std::vector< ObjectBase * > m_reusable_objects

Detailed Description

Constructor & Destructor Documentation

◆ StackImpl()

Slic3r::UndoRedo::StackImpl::StackImpl ( )
inline
#define UNDO_REDO_DEBUG_LOW_MEM_FACTOR
Definition UndoRedo.cpp:44
size_t m_memory_limit
Definition UndoRedo.cpp:691
size_t m_active_snapshot_time
Definition UndoRedo.cpp:700
size_t m_current_time
Definition UndoRedo.cpp:705
size_t total_physical_memory()
Definition utils.cpp:1819

References m_active_snapshot_time, m_current_time, m_memory_limit, Slic3r::total_physical_memory(), and UNDO_REDO_DEBUG_LOW_MEM_FACTOR.

Here is the call graph for this function:

Member Function Documentation

◆ active_snapshot_time()

size_t Slic3r::UndoRedo::StackImpl::active_snapshot_time ( ) const
inline
611{ return m_active_snapshot_time; }

References m_active_snapshot_time.

◆ clear()

void Slic3r::UndoRedo::StackImpl::clear ( )
inline
563 {
564 m_objects.clear();
566 m_snapshots.clear();
568 m_current_time = 0;
569 m_saved_snapshot_time = size_t(-1);
570 m_selection.clear();
571 }
std::vector< Snapshot > m_snapshots
Definition UndoRedo.cpp:698
std::map< const void *, ObjectID > m_shared_ptr_to_object_id
Definition UndoRedo.cpp:696
Selection m_selection
Definition UndoRedo.cpp:707
std::map< ObjectID, std::unique_ptr< ObjectHistoryBase > > m_objects
Definition UndoRedo.cpp:695
size_t m_saved_snapshot_time
Definition UndoRedo.cpp:703

References m_active_snapshot_time, m_current_time, m_objects, m_saved_snapshot_time, m_selection, m_shared_ptr_to_object_id, and m_snapshots.

◆ collect_garbage()

void Slic3r::UndoRedo::StackImpl::collect_garbage ( )
private
1182{
1183 // Purge objects with empty histories.
1184 for (auto it = m_objects.begin(); it != m_objects.end();) {
1185 if (it->second->empty()) {
1186 if (it->second->immutable_object_ptr() != nullptr)
1187 // Release the immutable object from the ptr to ObjectID map.
1188 m_shared_ptr_to_object_id.erase(it->second->immutable_object_ptr());
1189 it = m_objects.erase(it);
1190 } else
1191 ++ it;
1192 }
1193}

References m_objects, and m_shared_ptr_to_object_id.

Referenced by take_snapshot().

Here is the caller graph for this function:

◆ empty()

bool Slic3r::UndoRedo::StackImpl::empty ( ) const
inline
573 {
574 assert(m_objects.empty() == m_snapshots.empty());
575 assert(! m_objects.empty() || (m_current_time == 0 && m_active_snapshot_time == 0));
576 return m_snapshots.empty();
577 }

References m_active_snapshot_time, m_current_time, m_objects, and m_snapshots.

◆ get_memory_limit()

size_t Slic3r::UndoRedo::StackImpl::get_memory_limit ( ) const
inline
580{ return m_memory_limit; }

References m_memory_limit.

◆ has_real_change_from()

bool Slic3r::UndoRedo::StackImpl::has_real_change_from ( size_t time) const
1342{
1343 if (m_active_snapshot_time == time) return false;
1344 auto it_time = std::lower_bound(m_snapshots.begin(),
1345 m_snapshots.end(),
1346 Snapshot(time));
1347 if (it_time == m_snapshots.end()) return true;
1348 auto it_active = std::lower_bound(m_snapshots.begin(),
1349 m_snapshots.end(),
1350 Snapshot(m_active_snapshot_time));
1351 if (it_active == m_snapshots.end()) return true;
1352 if (it_active > it_time) {
1353 for (; it_time < it_active; ++it_time) {
1354 if (snapshot_modifies_project(*it_time))
1355 return true;
1356 }
1357 } else {
1358 for (; it_active < it_time; ++it_active) {
1359 if (snapshot_modifies_project(*it_active))
1360 return true;
1361 }
1362 }
1363 return false;
1364}
bool snapshot_modifies_project(SnapshotType type)
Definition UndoRedo.hpp:98

References m_active_snapshot_time, m_snapshots, and Slic3r::UndoRedo::snapshot_modifies_project().

Here is the call graph for this function:

◆ has_redo_snapshot()

bool Slic3r::UndoRedo::StackImpl::has_redo_snapshot ( ) const
1076{
1077#ifndef NDEBUG
1078 if (!this->valid())
1079 return false;
1080#endif
1081
1082 // BBS: undo-redo until modify record
1083 auto it = std::lower_bound(m_snapshots.begin(), m_snapshots.end(), Snapshot(m_active_snapshot_time));
1084 for (; it != m_snapshots.end(); ++it) {
1086 return true;
1087 }
1088 return false;
1089}
bool valid() const
Definition UndoRedo.cpp:656

References m_active_snapshot_time, m_snapshots, Slic3r::UndoRedo::snapshot_modifies_project(), and valid().

Here is the call graph for this function:

◆ has_undo_snapshot() [1/2]

bool Slic3r::UndoRedo::StackImpl::has_undo_snapshot ( ) const
1056{
1057#ifndef NDEBUG
1058 if (!this->valid())
1059 return false;
1060#endif
1061 // BBS: undo-redo until modify record
1062 auto it = std::lower_bound(m_snapshots.begin(), m_snapshots.end(), Snapshot(m_active_snapshot_time));
1063 for (auto it2 = m_snapshots.begin(); it2 != it; ++it2) {
1064 if (snapshot_modifies_project(*it2))
1065 return true;
1066 }
1067 return false;
1068}

References m_active_snapshot_time, m_snapshots, Slic3r::UndoRedo::snapshot_modifies_project(), and valid().

Here is the call graph for this function:

◆ has_undo_snapshot() [2/2]

bool Slic3r::UndoRedo::StackImpl::has_undo_snapshot ( size_t time_to_load) const
1071{
1072 return time_to_load < m_active_snapshot_time && std::binary_search(m_snapshots.begin(), m_snapshots.end(), Snapshot(time_to_load));
1073}

References m_active_snapshot_time, and m_snapshots.

◆ immutable_object_id()

template<typename T>
ObjectID Slic3r::UndoRedo::StackImpl::immutable_object_id ( const std::shared_ptr< const T > & ptr)
inlineprivate
671 {
672 return this->immutable_object_id_impl((const void*)ptr.get());
673 }
ObjectID immutable_object_id_impl(const void *ptr)
Definition UndoRedo.cpp:674

References immutable_object_id_impl().

Referenced by save_immutable_object().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ immutable_object_id_impl()

ObjectID Slic3r::UndoRedo::StackImpl::immutable_object_id_impl ( const void * ptr)
inlineprivate
674 {
675 auto it = m_shared_ptr_to_object_id.find(ptr);
676 if (it == m_shared_ptr_to_object_id.end()) {
677 // Allocate a new temporary ObjectID for this shared pointer.
678 ObjectBase object_with_id;
679 it = m_shared_ptr_to_object_id.insert(it, std::make_pair(ptr, object_with_id.id()));
680 }
681 return it->second;
682 }

References Slic3r::ObjectBase::id(), and m_shared_ptr_to_object_id.

Referenced by immutable_object_id().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ load_immutable_object()

template<typename T>
std::shared_ptr< const T > Slic3r::UndoRedo::StackImpl::load_immutable_object ( const Slic3r::ObjectID id,
bool optional )
901{
902 // First find a history stack for the ObjectID of this object instance.
903 auto it_object_history = m_objects.find(id);
904 assert(optional || it_object_history != m_objects.end());
905 if (it_object_history == m_objects.end())
906 return std::shared_ptr<const T>();
907 auto *object_history = static_cast<ImmutableObjectHistory<T>*>(it_object_history->second.get());
908 assert(object_history->has_snapshot(m_active_snapshot_time));
909 object_history->restore_optional();
910 return object_history->shared_ptr(*this);
911}

References m_active_snapshot_time, and m_objects.

Referenced by cereal::load(), and cereal::load_optional().

Here is the caller graph for this function:

◆ load_mutable_object() [1/2]

template<typename T>
T * Slic3r::UndoRedo::StackImpl::load_mutable_object ( const Slic3r::ObjectID id)
886{
887 // BBS: reuse objects for backup
888 auto it = std::find_if(m_reusable_objects.begin(), m_reusable_objects.end(), [id](auto o) { return o && o->id() == id; });
889 T* target = nullptr;
890 if (it == m_reusable_objects.end())
891 target = new T();
892 else {
893 target = static_cast<T*>(*it);
894 *it = nullptr;
895 }
896 this->load_mutable_object<T>(id, *target);
897 return target;
898}
T * load_mutable_object(const Slic3r::ObjectID id)
Definition UndoRedo.cpp:885
std::vector< ObjectBase * > m_reusable_objects
Definition UndoRedo.cpp:708

References load_mutable_object(), and m_reusable_objects.

Referenced by cereal::load(), cereal::load(), cereal::load_by_value(), load_mutable_object(), and load_snapshot().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ load_mutable_object() [2/2]

template<typename T>
void Slic3r::UndoRedo::StackImpl::load_mutable_object ( const Slic3r::ObjectID id,
T & target )
914{
915 // First find a history stack for the ObjectID of this object instance.
916 auto it_object_history = m_objects.find(id);
917 assert(it_object_history != m_objects.end());
918 auto *object_history = static_cast<const MutableObjectHistory<T>*>(it_object_history->second.get());
919 // Then get the data associated with the object history and m_active_snapshot_time.
920 std::istringstream iss(object_history->load(m_active_snapshot_time));
921 Slic3r::UndoRedo::InputArchive archive(*this, iss);
922 target.m_id = id;
923 archive(target);
924}
cereal::UserDataAdapter< StackImpl, cereal::BinaryInputArchive > InputArchive
Definition UndoRedo.cpp:711

References m_active_snapshot_time, and m_objects.

◆ load_snapshot()

void Slic3r::UndoRedo::StackImpl::load_snapshot ( size_t timestamp,
Slic3r::Model & model,
Slic3r::GUI::GLGizmosManager & gizmos,
Slic3r::GUI::PartPlateList & plate_list )
1010{
1011 // Find the snapshot by time. It must exist.
1012 const auto it_snapshot = std::lower_bound(m_snapshots.begin(), m_snapshots.end(), Snapshot(timestamp));
1013 if (it_snapshot == m_snapshots.end() || it_snapshot->timestamp != timestamp)
1014 throw Slic3r::RuntimeError((boost::format("Snapshot with timestamp %1% does not exist") % timestamp).str());
1015
1016 m_active_snapshot_time = timestamp;
1017 // BBS: reuse objects for backup, objects should clear children before load them
1019 // model.clear_objects();
1020 model.clear_materials();
1021 this->load_mutable_object<Slic3r::Model>(ObjectID(it_snapshot->model_id), model);
1023 m_selection.volumes_and_instances.clear();
1025 //gizmos.reset_all_states(); FIXME: is this really necessary? It is quite unpleasant for the gizmo undo/redo substack
1027 // Sort the volumes so that we may use binary search.
1028 std::sort(m_selection.volumes_and_instances.begin(), m_selection.volumes_and_instances.end());
1029 m_active_snapshot_time = timestamp;
1030
1031 //BBS:load the partplater related data
1032 {
1033 //Slic3r::GUI::PartPlateList& plate_list = GUI::wxGetApp().plater()->get_partplate_list();
1034 std::vector<bool> previous_slice_result;
1035 std::vector<std::string> previous_gcode_paths;
1036 plate_list.get_sliced_result(previous_slice_result, previous_gcode_paths);
1037
1038 plate_list.reset(false);
1039 this->load_mutable_object<Slic3r::GUI::PartPlateList>(plate_list.id(), plate_list);
1040 plate_list.rebuild_plates_after_deserialize(previous_slice_result, previous_gcode_paths);
1041 }
1042 this->m_active_snapshot_time = timestamp;
1043 assert(this->valid());
1044
1045 // BBS: reuse objects for backup
1046 for (auto o : m_reusable_objects) {
1047 delete o;
1048 }
1049 m_reusable_objects.clear();
1050
1051 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format("snapshot name %1%") % it_snapshot->name;
1052 plate_list.print();
1053}
void print() const
Definition PartPlate.cpp:8695
int rebuild_plates_after_deserialize(std::vector< bool > &previous_sliced_result, std::vector< std::string > &previous_gcode_paths)
Definition PartPlate.cpp:8237
void reset(bool do_init)
Definition PartPlate.cpp:6478
void get_sliced_result(std::vector< bool > &sliced_result, std::vector< std::string > &gcode_paths)
Definition PartPlate.cpp:8225
void collect_reusable_objects(std::vector< ObjectBase * > &objects)
Definition Model.cpp:731
void clear_materials()
Definition Model.cpp:776
void update_links_bottom_up_recursive()
Definition Model.cpp:218
ObjectID id() const
Definition ObjectID.hpp:69

References Slic3r::Model::clear_materials(), Slic3r::Model::collect_reusable_objects(), Slic3r::GUI::PartPlateList::get_sliced_result(), Slic3r::ObjectBase::id(), load_mutable_object(), m_active_snapshot_time, m_reusable_objects, m_selection, m_snapshots, Slic3r::GUI::PartPlateList::print(), Slic3r::GUI::PartPlateList::rebuild_plates_after_deserialize(), Slic3r::GUI::PartPlateList::reset(), Slic3r::Model::update_links_bottom_up_recursive(), and valid().

Referenced by redo(), and undo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mark_current_as_saved()

void Slic3r::UndoRedo::StackImpl::mark_current_as_saved ( )
inline

◆ memsize()

size_t Slic3r::UndoRedo::StackImpl::memsize ( ) const
inline
582 {
583 size_t memsize = 0;
584 for (const auto &object : m_objects)
585 memsize += object.second->memsize();
586 return memsize;
587 }
size_t memsize() const
Definition UndoRedo.cpp:582

References m_objects, and memsize().

Referenced by memsize(), release_least_recently_used(), and set_memory_limit().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ project_modified()

bool Slic3r::UndoRedo::StackImpl::project_modified ( ) const
1303{
1304 assert(! m_snapshots.empty());
1305
1306 if (m_saved_snapshot_time == size_t(-1))
1307 // Don't know anything about the project state.
1308 return true;
1310 // Just saved at this step.
1311 return false;
1312
1313 assert(m_saved_snapshot_time >= m_snapshots.front().timestamp && m_saved_snapshot_time <= m_snapshots.back().timestamp);
1314
1315 auto it_saved = std::lower_bound(m_snapshots.begin(), m_snapshots.end(), Snapshot(m_saved_snapshot_time));
1316 assert(it_saved != m_snapshots.end() && it_saved->timestamp == m_saved_snapshot_time);
1317
1318#ifndef NDEBUG
1319 // Verify that there is a snapshot with "current time".
1320 auto it_current = std::lower_bound(m_snapshots.begin(), m_snapshots.end(), Snapshot(m_active_snapshot_time));
1321 assert(it_current != m_snapshots.end() && it_current->timestamp == m_active_snapshot_time);
1322#endif // NDEBUG
1323
1325 // Search upwards. Ignore state of the "active" snapshot.
1326 for (auto it = it_saved; it->timestamp < m_active_snapshot_time; ++ it)
1328 return true;
1329 } else {
1330 // Search downwards. Ignore state of the "saved" snapshot.
1332 for (auto it = it_saved - 1; it->timestamp >= m_active_snapshot_time; -- it)
1334 return true;
1335 }
1336
1337 return false;
1338}

References m_active_snapshot_time, m_saved_snapshot_time, m_snapshots, and Slic3r::UndoRedo::snapshot_modifies_project().

Here is the call graph for this function:

◆ redo()

bool Slic3r::UndoRedo::StackImpl::redo ( Slic3r::Model & model,
Slic3r::GUI::GLGizmosManager & gizmos,
Slic3r::GUI::PartPlateList & plate_list,
size_t jump_to_time )
1133{
1134 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(":time_to_load %1%") % time_to_load;
1135 assert(this->valid());
1136 if (time_to_load == SIZE_MAX) {
1137 auto it_current = std::lower_bound(m_snapshots.begin(), m_snapshots.end(), Snapshot(m_active_snapshot_time));
1138 if (++ it_current == m_snapshots.end())
1139 return false;
1140 time_to_load = it_current->timestamp;
1141 }
1142 assert(time_to_load > m_active_snapshot_time);
1143 assert(std::binary_search(m_snapshots.begin(), m_snapshots.end(), Snapshot(time_to_load)));
1144 this->load_snapshot(time_to_load, model, gizmos, plate_list);
1145#ifdef SLIC3R_UNDOREDO_DEBUG
1146 std::cout << "After redo" << std::endl;
1147 this->print();
1148#endif /* SLIC3R_UNDOREDO_DEBUG */
1149 return true;
1150}
void load_snapshot(size_t timestamp, Slic3r::Model &model, Slic3r::GUI::GLGizmosManager &gizmos, Slic3r::GUI::PartPlateList &plate_list)
Definition UndoRedo.cpp:1009

References load_snapshot(), m_active_snapshot_time, m_snapshots, and valid().

Here is the call graph for this function:

◆ reduce_noisy_snapshots()

void Slic3r::UndoRedo::StackImpl::reduce_noisy_snapshots ( const std::string & new_name)
984{
985 // Preceding snapshot must be a "leave gizmo" snapshot.
986 assert(! m_snapshots.empty() && m_snapshots.back().is_topmost() && m_snapshots.back().timestamp == m_active_snapshot_time);
987 auto it_last = m_snapshots.end();
988 -- it_last; -- it_last;
989 assert(it_last != m_snapshots.begin() && (it_last->snapshot_data.snapshot_type == SnapshotType::LeavingGizmoNoAction || it_last->snapshot_data.snapshot_type == SnapshotType::LeavingGizmoWithAction));
990 if (it_last->snapshot_data.snapshot_type == SnapshotType::LeavingGizmoWithAction) {
991 for (-- it_last; it_last->snapshot_data.snapshot_type != SnapshotType::EnteringGizmo; -- it_last) {
992 if (it_last->snapshot_data.snapshot_type == SnapshotType::GizmoAction) {
993 it_last->name = new_name;
994 auto it = it_last;
995 for (-- it; it->snapshot_data.snapshot_type == SnapshotType::GizmoAction; -- it) ;
996 if (++ it < it_last) {
997 // Drop (it, it_last>
998 for (auto &kvp : m_objects)
999 // Drop products of <it + 1, it_last + 1>
1000 kvp.second->release_between_timestamps(it->timestamp, (it_last + 1)->timestamp);
1001 it_last = this->release_snapshots(it + 1, it_last + 1);
1002 }
1003 }
1004 assert(it_last != m_snapshots.begin());
1005 }
1006 }
1007}
std::vector< Snapshot >::iterator release_snapshots(std::vector< Snapshot >::iterator begin, std::vector< Snapshot >::iterator end)
Definition UndoRedo.cpp:1154
@ EnteringGizmo
Definition UndoRedo.hpp:42
@ LeavingGizmoNoAction
Definition UndoRedo.hpp:45
@ GizmoAction
Definition UndoRedo.hpp:36
@ LeavingGizmoWithAction
Definition UndoRedo.hpp:48

References Slic3r::UndoRedo::EnteringGizmo, Slic3r::UndoRedo::GizmoAction, Slic3r::UndoRedo::LeavingGizmoNoAction, Slic3r::UndoRedo::LeavingGizmoWithAction, m_active_snapshot_time, m_objects, m_snapshots, and release_snapshots().

Here is the call graph for this function:

◆ release_least_recently_used()

void Slic3r::UndoRedo::StackImpl::release_least_recently_used ( )
1196{
1197 assert(this->valid());
1198 size_t current_memsize = this->memsize();
1199#ifdef SLIC3R_UNDOREDO_DEBUG
1200 bool released = false;
1201#endif
1202 // First try to release the optional immutable data (for example the convex hulls),
1203 // or the shared vertices of triangle meshes.
1204 for (auto it = m_objects.begin(); current_memsize > m_memory_limit && it != m_objects.end();) {
1205 const void *ptr = it->second->immutable_object_ptr();
1206 size_t mem_released = it->second->release_optional();
1207 if (it->second->empty()) {
1208 if (ptr != nullptr)
1209 // Release the immutable object from the ptr to ObjectID map.
1210 m_shared_ptr_to_object_id.erase(ptr);
1211 mem_released += it->second->memsize();
1212 it = m_objects.erase(it);
1213 } else
1214 ++ it;
1215 assert(current_memsize >= mem_released);
1216 if (current_memsize >= mem_released)
1217 current_memsize -= mem_released;
1218 else
1219 current_memsize = 0;
1220 }
1221 while (current_memsize > m_memory_limit && m_snapshots.size() >= 3) {
1222 // From which side to remove a snapshot?
1223 assert(m_snapshots.front().timestamp < m_active_snapshot_time);
1224 size_t mem_released = 0;
1225 if (m_snapshots[1].timestamp == m_active_snapshot_time) {
1226 // Remove the last snapshot.
1227#if 0
1228 for (auto it = m_objects.begin(); it != m_objects.end();) {
1229 mem_released += it->second->release_after_timestamp(m_snapshots.back().timestamp);
1230 if (it->second->empty()) {
1231 if (it->second->immutable_object_ptr() != nullptr)
1232 // Release the immutable object from the ptr to ObjectID map.
1233 m_shared_ptr_to_object_id.erase(it->second->immutable_object_ptr());
1234 mem_released += it->second->memsize();
1235 it = m_objects.erase(it);
1236 } else
1237 ++ it;
1238 }
1239 m_snapshots.pop_back();
1240 m_snapshots.back().name = topmost_snapshot_name;
1241#else
1242 // Rather don't release the last snapshot as it will be very confusing to the user
1243 // as of why he cannot jump to the top most state. The Undo / Redo stack maximum size
1244 // should be set low enough to accomodate for the top most snapshot.
1245 break;
1246#endif
1247 } else {
1248 // FIX: reduce_noisy_snapshots
1249 if (m_snapshots.front().snapshot_data.snapshot_type == SnapshotType::EnteringGizmo) {
1250 auto it_last = m_snapshots.begin() + 1;
1251 if (it_last->snapshot_data.snapshot_type == SnapshotType::GizmoAction) {
1252 auto it = m_snapshots.begin();
1253 // Drop (it, it_last>
1254 for (auto &kvp : m_objects)
1255 // Drop products of <it + 1, it_last + 1>
1256 mem_released += kvp.second->release_between_timestamps(it->timestamp, (it_last + 1)->timestamp);
1257 m_snapshots.erase(it + 1, it_last + 1);
1258 assert(current_memsize >= mem_released);
1259 if (current_memsize >= mem_released)
1260 current_memsize -= mem_released;
1261 else
1262 current_memsize = 0;
1263 continue;
1264 }
1265 if (it_last->snapshot_data.snapshot_type != SnapshotType::LeavingGizmoWithAction &&
1266 it_last->snapshot_data.snapshot_type != SnapshotType::LeavingGizmoNoAction)
1267 break;
1268 }
1269 // Remove the first snapshot.
1270 for (auto it = m_objects.begin(); it != m_objects.end();) {
1271 mem_released += it->second->release_before_timestamp(m_snapshots[1].timestamp);
1272 if (it->second->empty()) {
1273 if (it->second->immutable_object_ptr() != nullptr)
1274 // Release the immutable object from the ptr to ObjectID map.
1275 m_shared_ptr_to_object_id.erase(it->second->immutable_object_ptr());
1276 mem_released += it->second->memsize();
1277 it = m_objects.erase(it);
1278 } else
1279 ++ it;
1280 }
1281 //FIXME update the "saved" snapshot time. DONE
1282 if (m_snapshots.front().timestamp == m_saved_snapshot_time)
1283 m_saved_snapshot_time = size_t(-1);
1284 m_snapshots.erase(m_snapshots.begin());
1285 }
1286 assert(current_memsize >= mem_released);
1287 if (current_memsize >= mem_released)
1288 current_memsize -= mem_released;
1289 else
1290 current_memsize = 0;
1291#ifdef SLIC3R_UNDOREDO_DEBUG
1292 released = true;
1293#endif
1294 }
1295 assert(this->valid());
1296#ifdef SLIC3R_UNDOREDO_DEBUG
1297 std::cout << "After release_least_recently_used" << std::endl;
1298 this->print();
1299#endif /* SLIC3R_UNDOREDO_DEBUG */
1300}
static std::string topmost_snapshot_name
Definition UndoRedo.cpp:59

References Slic3r::UndoRedo::EnteringGizmo, Slic3r::UndoRedo::GizmoAction, Slic3r::UndoRedo::LeavingGizmoNoAction, Slic3r::UndoRedo::LeavingGizmoWithAction, m_active_snapshot_time, m_memory_limit, m_objects, m_saved_snapshot_time, m_shared_ptr_to_object_id, m_snapshots, memsize(), Slic3r::UndoRedo::topmost_snapshot_name, and valid().

Here is the call graph for this function:

◆ release_snapshots()

std::vector< Snapshot >::iterator Slic3r::UndoRedo::StackImpl::release_snapshots ( std::vector< Snapshot >::iterator begin,
std::vector< Snapshot >::iterator end )
private
1155{
1156 assert(! m_snapshots.empty());
1157 assert(begin <= end);
1158 if (m_saved_snapshot_time != size_t(-1) && m_saved_snapshot_time >= begin->timestamp && (end == m_snapshots.end() || m_saved_snapshot_time < end->timestamp)) {
1159 assert(m_saved_snapshot_time <= m_snapshots.back().timestamp);
1160 auto it_saved = std::lower_bound(begin, end, Snapshot(m_saved_snapshot_time));
1161 assert(it_saved != m_snapshots.end() && it_saved->timestamp == m_saved_snapshot_time);
1162 auto it = it_saved;
1163 for (; it != begin && ! snapshot_modifies_project(*it); -- it) ;
1164 if (it == begin && ! snapshot_modifies_project(*it)) {
1165 // Found a snapshot before begin, which captures the same project state.
1166 m_saved_snapshot_time = (-- it)->timestamp;
1167 } else {
1168 auto it = it_saved;
1169 for (; it != end && ! snapshot_modifies_project(*it); ++ it) ;
1170 if (it == end && end != m_snapshots.end())
1171 // Found a snapshot after end, which captures the same project state.
1172 m_saved_snapshot_time = (-- it)->timestamp;
1173 else
1174 // State of the project is being lost. Indicate a "likely modified" project state until the project is saved again.
1175 m_saved_snapshot_time = size_t(-1);
1176 }
1177 }
1178 return m_snapshots.erase(begin, end);
1179}
T * begin(Slic3r::Mat< N, M, T > &mat)
Definition Point.hpp:838
T * end(Slic3r::Mat< N, M, T > &mat)
Definition Point.hpp:841

References m_saved_snapshot_time, m_snapshots, and Slic3r::UndoRedo::snapshot_modifies_project().

Referenced by reduce_noisy_snapshots(), and take_snapshot().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ save_immutable_object()

template<typename T>
ObjectID Slic3r::UndoRedo::StackImpl::save_immutable_object ( std::shared_ptr< const T > & object,
bool optional )
871{
872 // First allocate a temporary ObjectID for this pointer.
873 ObjectID object_id = this->immutable_object_id(object);
874 // and find or allocate a history stack for the ObjectID associated to this shared_ptr.
875 auto it_object_history = m_objects.find(object_id);
876 if (it_object_history == m_objects.end())
877 it_object_history = m_objects.emplace_hint(it_object_history, object_id, std::unique_ptr<ImmutableObjectHistory<T>>(new ImmutableObjectHistory<T>(object, optional)));
878 else
879 assert(it_object_history->second.get()->is_optional() == optional);
880 // Then save the interval.
881 static_cast<ImmutableObjectHistory<T>*>(it_object_history->second.get())->save(m_active_snapshot_time, m_current_time);
882 return object_id;
883}
ObjectID immutable_object_id(const std::shared_ptr< const T > &ptr)
Definition UndoRedo.cpp:671

References immutable_object_id(), m_active_snapshot_time, m_current_time, m_objects, and Slic3r::UndoRedo::ImmutableObjectHistory< T >::save().

Here is the call graph for this function:

◆ save_mutable_object()

template<typename T>
ObjectID Slic3r::UndoRedo::StackImpl::save_mutable_object ( const T & object)
844{
845 // First find or allocate a history stack for the ObjectID of this object instance.
846 auto it_object_history = m_objects.find(object.id());
847 if (it_object_history == m_objects.end())
848 it_object_history = m_objects.insert(it_object_history, std::make_pair(object.id(), std::unique_ptr<MutableObjectHistory<T>>(new MutableObjectHistory<T>())));
849 auto *object_history = static_cast<MutableObjectHistory<T>*>(it_object_history->second.get());
850 bool needs_to_save = true;
851 {
852 // If the timestamp returned is non zero, then it is considered reliable.
853 // The caller is supposed to serialize the timestamp first.
854 uint64_t timestamp = object.timestamp();
855 if (timestamp > 0)
856 needs_to_save = ! object_history->try_save_timestamp(m_active_snapshot_time, m_current_time, timestamp);
857 }
858 if (needs_to_save) {
859 // Serialize the object into a string.
860 std::ostringstream oss;
861 {
862 Slic3r::UndoRedo::OutputArchive archive(*this, oss);
863 archive(object);
864 }
865 object_history->save(m_active_snapshot_time, m_current_time, oss.str());
866 }
867 return object.id();
868}
cereal::UserDataAdapter< StackImpl, cereal::BinaryOutputArchive > OutputArchive
Definition UndoRedo.cpp:712

References m_active_snapshot_time, m_current_time, and m_objects.

Referenced by take_snapshot().

Here is the caller graph for this function:

◆ selection_deserialized()

const Selection & Slic3r::UndoRedo::StackImpl::selection_deserialized ( ) const
inline
621{ return m_selection; }

References m_selection.

◆ set_memory_limit()

void Slic3r::UndoRedo::StackImpl::set_memory_limit ( size_t memsize)
inline

References m_memory_limit, and memsize().

Here is the call graph for this function:

◆ snapshot()

const Snapshot & Slic3r::UndoRedo::StackImpl::snapshot ( size_t time) const
inline
604 {
605 const auto it = std::lower_bound(m_snapshots.cbegin(), m_snapshots.cend(), UndoRedo::Snapshot(time));
606 assert(it != m_snapshots.end() && it->timestamp == time);
607 return *it;
608 }

References m_snapshots.

◆ snapshots()

const std::vector< Snapshot > & Slic3r::UndoRedo::StackImpl::snapshots ( ) const
inline
603{ return m_snapshots; }

References m_snapshots.

◆ take_snapshot() [1/2]

void Slic3r::UndoRedo::StackImpl::take_snapshot ( const std::string & snapshot_name,
const Slic3r::Model & model,
const Slic3r::GUI::Selection & selection,
const Slic3r::GUI::GLGizmosManager & gizmos,
const Slic3r::GUI::PartPlateList & plate_list,
const SnapshotData & snapshot_data )
938{
939 // Release old snapshot data.
941 for (auto &kvp : m_objects)
942 kvp.second->release_after_timestamp(m_active_snapshot_time);
943 bool topmost_saved = false;
944 if (! m_snapshots.empty()) {
945 // If the project was saved for the topmost snapshot, restore the "saved" state after the "topmost" snapshot is taken.
946 topmost_saved = m_active_snapshot_time == m_saved_snapshot_time && m_active_snapshot_time == m_snapshots.back().timestamp;
947 auto it = std::lower_bound(m_snapshots.begin(), m_snapshots.end(), Snapshot(m_active_snapshot_time));
948 this->release_snapshots(it, m_snapshots.end());
949 }
950 // Take new snapshots.
952 m_selection.volumes_and_instances.clear();
953 m_selection.volumes_and_instances.reserve(selection.get_volume_idxs().size());
954 m_selection.mode = selection.get_mode();
955 for (unsigned int volume_idx : selection.get_volume_idxs())
956 m_selection.volumes_and_instances.emplace_back(selection.get_volume(volume_idx)->geometry_id);
959
960 //BBS:save the partplater related data
962
963 // Save the snapshot info.
964 m_snapshots.emplace_back(snapshot_name, m_current_time, model.id().id, snapshot_data);
965 if (topmost_saved)
966 // Restore the "saved" timestamp.
969 // Save snapshot info of the last "current" aka "top most" state, that is only being serialized
970 // if undoing an action. Such a snapshot has an invalid Model ID assigned if it was not taken yet.
971 m_snapshots.emplace_back(topmost_snapshot_name, m_active_snapshot_time, 0, snapshot_data);
972 // Release empty objects from the history.
973 this->collect_garbage();
974 assert(this->valid());
975#ifdef SLIC3R_UNDOREDO_DEBUG
976 std::cout << "After snapshot" << std::endl;
977 this->print();
978#endif /* SLIC3R_UNDOREDO_DEBUG */
979 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format("snapshot name %1%") % snapshot_name;
980 plate_list.print();
981}
std::pair< size_t, size_t > geometry_id
Definition 3DScene.hpp:196
EMode get_mode() const
Definition Selection.hpp:222
const IndicesList & get_volume_idxs() const
Definition Selection.hpp:315
const GLVolume * get_volume(unsigned int volume_idx) const
Definition Selection.cpp:984
size_t id
Definition ObjectID.hpp:39
void collect_garbage()
Definition UndoRedo.cpp:1181
ObjectID save_mutable_object(const T &object)
Definition UndoRedo.cpp:843

References collect_garbage(), Slic3r::GLVolume::geometry_id, Slic3r::GUI::Selection::get_mode(), Slic3r::GUI::Selection::get_volume(), Slic3r::GUI::Selection::get_volume_idxs(), Slic3r::ObjectBase::id(), Slic3r::ObjectID::id, m_active_snapshot_time, m_current_time, m_objects, m_saved_snapshot_time, m_selection, m_snapshots, Slic3r::GUI::PartPlateList::print(), release_snapshots(), save_mutable_object(), Slic3r::UndoRedo::topmost_snapshot_name, and valid().

Referenced by take_snapshot(), and undo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ take_snapshot() [2/2]

void Slic3r::UndoRedo::StackImpl::take_snapshot ( const std::string & snapshot_name,
const Slic3r::Model & model,
const Slic3r::GUI::Selection & selection,
const Slic3r::GUI::GLGizmosManager & gizmos,
const SnapshotData & snapshot_data )
928{
929 Slic3r::GUI::PartPlateList& plate_list = GUI::wxGetApp().plater()->get_partplate_list();
930
931 take_snapshot(snapshot_name, model, selection, gizmos, plate_list, snapshot_data);
932
933 return;
934}
void take_snapshot(const std::string &snapshot_name, const Slic3r::Model &model, const Slic3r::GUI::Selection &selection, const Slic3r::GUI::GLGizmosManager &gizmos, const Slic3r::GUI::PartPlateList &plate_list, const SnapshotData &snapshot_data)
Definition UndoRedo.cpp:937

References take_snapshot().

Here is the call graph for this function:

◆ temp_snapshot_active()

bool Slic3r::UndoRedo::StackImpl::temp_snapshot_active ( ) const
inline
612{ return m_snapshots.back().timestamp == m_active_snapshot_time && ! m_snapshots.back().is_topmost_captured(); }

References m_active_snapshot_time, and m_snapshots.

◆ undo()

bool Slic3r::UndoRedo::StackImpl::undo ( Slic3r::Model & model,
const Slic3r::GUI::Selection & selection,
Slic3r::GUI::GLGizmosManager & gizmos,
Slic3r::GUI::PartPlateList & plate_list,
const SnapshotData & snapshot_data,
size_t jump_to_time )
1092{
1093 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(":time_to_load %1%") % time_to_load;
1094 assert(this->valid());
1095 if (time_to_load == SIZE_MAX) {
1096 auto it_current = std::lower_bound(m_snapshots.begin(), m_snapshots.end(), Snapshot(m_active_snapshot_time));
1097 if (-- it_current == m_snapshots.begin())
1098 return false;
1099 time_to_load = it_current->timestamp;
1100 }
1101 assert(time_to_load < m_active_snapshot_time);
1102 assert(std::binary_search(m_snapshots.begin(), m_snapshots.end(), Snapshot(time_to_load)));
1103 bool new_snapshot_taken = false;
1104 if (m_active_snapshot_time == m_snapshots.back().timestamp && ! m_snapshots.back().is_topmost_captured()) {
1105 // The current state is temporary. The current state needs to be captured to be redoable.
1106 this->take_snapshot(topmost_snapshot_name, model, selection, gizmos, plate_list, snapshot_data);
1107 // The line above entered another topmost_snapshot_name.
1108 assert(m_snapshots.back().is_topmost());
1109 assert(! m_snapshots.back().is_topmost_captured());
1110 // Pop it back, it is not needed as there is now a captured topmost state.
1111 m_snapshots.pop_back();
1112 // current_time was extended, but it should not cause any harm. Resetting it back may complicate the logic unnecessarily.
1113 //-- m_current_time;
1114 assert(m_snapshots.back().is_topmost());
1115 assert(m_snapshots.back().is_topmost_captured());
1116 new_snapshot_taken = true;
1117 }
1118 this->load_snapshot(time_to_load, model, gizmos, plate_list);
1119 if (new_snapshot_taken) {
1120 // Release old snapshots if the memory allocated due to capturing the top most state is excessive.
1121 // Don't release the snapshots here, release them first after the scene and background processing gets updated, as this will release some references
1122 // to the shared TriangleMeshes.
1123 //this->release_least_recently_used();
1124 }
1125#ifdef SLIC3R_UNDOREDO_DEBUG
1126 std::cout << "After undo" << std::endl;
1127 this->print();
1128#endif /* SLIC3R_UNDOREDO_DEBUG */
1129 return true;
1130}

References load_snapshot(), m_active_snapshot_time, m_snapshots, take_snapshot(), and valid().

Here is the call graph for this function:

◆ valid()

bool Slic3r::UndoRedo::StackImpl::valid ( ) const
inline
656 {
657 //assert(! m_snapshots.empty());
658 if (m_snapshots.empty())
659 return false;
660 assert(m_snapshots.back().is_topmost());
661 auto it = std::lower_bound(m_snapshots.begin(), m_snapshots.end(), Snapshot(m_active_snapshot_time));
662 assert(it != m_snapshots.begin() && it != m_snapshots.end() && it->timestamp == m_active_snapshot_time);
663 assert(m_active_snapshot_time <= m_snapshots.back().timestamp);
664 for (auto it = m_objects.begin(); it != m_objects.end(); ++ it)
665 assert(it->second->valid());
666 return true;
667 }

References m_active_snapshot_time, m_objects, and m_snapshots.

Referenced by has_redo_snapshot(), has_undo_snapshot(), load_snapshot(), redo(), release_least_recently_used(), take_snapshot(), and undo().

Here is the caller graph for this function:

Member Data Documentation

◆ m_active_snapshot_time

◆ m_current_time

size_t Slic3r::UndoRedo::StackImpl::m_current_time
private

◆ m_memory_limit

size_t Slic3r::UndoRedo::StackImpl::m_memory_limit
private

◆ m_objects

◆ m_reusable_objects

std::vector<ObjectBase*> Slic3r::UndoRedo::StackImpl::m_reusable_objects
private

◆ m_saved_snapshot_time

size_t Slic3r::UndoRedo::StackImpl::m_saved_snapshot_time { size_t(-1) }
private

◆ m_selection

Selection Slic3r::UndoRedo::StackImpl::m_selection
private

◆ m_shared_ptr_to_object_id

std::map<const void*, ObjectID> Slic3r::UndoRedo::StackImpl::m_shared_ptr_to_object_id
private

◆ m_snapshots


The documentation for this class was generated from the following file:
  • /home/runner/work/OrcaSlicer/OrcaSlicer/src/slic3r/Utils/UndoRedo.cpp