mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-12 01:07:57 -06:00
New class ModelConfig wrapping DynamicPrintConfig and a timestamp
to help with detecting "not changed" event when taking Undo/Redo snapshot or synchronizing with the back-end. Converted layer height profile and supports / seam painted areas to the same timestamp controlled structure.
This commit is contained in:
parent
0d6eb842b0
commit
54976e29bb
28 changed files with 366 additions and 215 deletions
|
@ -1369,6 +1369,96 @@ Points get_bed_shape(const DynamicPrintConfig &cfg);
|
|||
Points get_bed_shape(const PrintConfig &cfg);
|
||||
Points get_bed_shape(const SLAPrinterConfig &cfg);
|
||||
|
||||
// ModelConfig is a wrapper around DynamicPrintConfig with an addition of a timestamp.
|
||||
// Each change of ModelConfig is tracked by assigning a new timestamp from a global counter.
|
||||
// The counter is used for faster synchronization of the background slicing thread
|
||||
// with the front end by skipping synchronization of equal config dictionaries.
|
||||
// The global counter is also used for avoiding unnecessary serialization of config
|
||||
// dictionaries when taking an Undo snapshot.
|
||||
//
|
||||
// The global counter is NOT thread safe, therefore it is recommended to use ModelConfig from
|
||||
// the main thread only.
|
||||
//
|
||||
// As there is a global counter and it is being increased with each change to any ModelConfig,
|
||||
// if two ModelConfig dictionaries differ, they should differ with their timestamp as well.
|
||||
// Therefore copying the ModelConfig including its timestamp is safe as there is no harm
|
||||
// in having multiple ModelConfig with equal timestamps as long as their dictionaries are equal.
|
||||
//
|
||||
// The timestamp is used by the Undo/Redo stack. As zero timestamp means invalid timestamp
|
||||
// to the Undo/Redo stack (zero timestamp means the Undo/Redo stack needs to serialize and
|
||||
// compare serialized data for differences), zero timestamp shall never be used.
|
||||
// Timestamp==1 shall only be used for empty dictionaries.
|
||||
class ModelConfig
|
||||
{
|
||||
public:
|
||||
void clear() { m_data.clear(); m_timestamp = 1; }
|
||||
|
||||
// Modification of the ModelConfig is not thread safe due to the global timestamp counter!
|
||||
// Don't call modification methods from the back-end!
|
||||
void assign_config(const ModelConfig &rhs) {
|
||||
if (m_timestamp != rhs.m_timestamp) {
|
||||
m_data = rhs.m_data;
|
||||
m_timestamp = rhs.m_timestamp;
|
||||
}
|
||||
}
|
||||
void assign_config(ModelConfig &&rhs) {
|
||||
if (m_timestamp != rhs.m_timestamp) {
|
||||
m_data = std::move(rhs.m_data);
|
||||
m_timestamp = rhs.m_timestamp;
|
||||
rhs.clear();
|
||||
}
|
||||
}
|
||||
// Assign methods don't assign if src==dst to not having to bump the timestamp in case they are equal.
|
||||
void assign_config(const DynamicPrintConfig &rhs) { if (m_data != rhs) { m_data = rhs; this->touch(); } }
|
||||
void assign_config(DynamicPrintConfig &&rhs) { if (m_data != rhs) { m_data = std::move(rhs); this->touch(); } }
|
||||
void apply(const ModelConfig &other, bool ignore_nonexistent = false) { this->apply(other.get(), ignore_nonexistent); }
|
||||
void apply(const ConfigBase &other, bool ignore_nonexistent = false) { m_data.apply_only(other, other.keys(), ignore_nonexistent); this->touch(); }
|
||||
void apply_only(const ModelConfig &other, const t_config_option_keys &keys, bool ignore_nonexistent = false) { this->apply_only(other.get(), keys, ignore_nonexistent); }
|
||||
void apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false) { m_data.apply_only(other, keys, ignore_nonexistent); this->touch(); }
|
||||
bool set_key_value(const std::string &opt_key, ConfigOption *opt) { bool out = m_data.set_key_value(opt_key, opt); this->touch(); return out; }
|
||||
template<typename T>
|
||||
void set(const std::string &opt_key, T value) { m_data.set(opt_key, value, true); this->touch(); }
|
||||
void set_deserialize(const t_config_option_key &opt_key, const std::string &str, bool append = false)
|
||||
{ m_data.set_deserialize(opt_key, str, append); this->touch(); }
|
||||
bool erase(const t_config_option_key &opt_key) { bool out = m_data.erase(opt_key); if (out) this->touch(); return out; }
|
||||
|
||||
// Getters are thread safe.
|
||||
// The following implicit conversion breaks the Cereal serialization.
|
||||
// operator const DynamicPrintConfig&() const throw() { return this->get(); }
|
||||
const DynamicPrintConfig& get() const throw() { return m_data; }
|
||||
bool empty() const throw() { return m_data.empty(); }
|
||||
size_t size() const throw() { return m_data.size(); }
|
||||
auto cbegin() const { return m_data.cbegin(); }
|
||||
auto cend() const { return m_data.cend(); }
|
||||
t_config_option_keys keys() const { return m_data.keys(); }
|
||||
bool has(const t_config_option_key &opt_key) const { return m_data.has(opt_key); }
|
||||
const ConfigOption* option(const t_config_option_key &opt_key) const { return m_data.option(opt_key); }
|
||||
int opt_int(const t_config_option_key &opt_key) const { return m_data.opt_int(opt_key); }
|
||||
int extruder() const { return opt_int("extruder"); }
|
||||
double opt_float(const t_config_option_key &opt_key) const { return m_data.opt_float(opt_key); }
|
||||
std::string opt_serialize(const t_config_option_key &opt_key) const { return m_data.opt_serialize(opt_key); }
|
||||
|
||||
// Return an optional timestamp of this object.
|
||||
// If the timestamp returned is non-zero, then the serialization framework will
|
||||
// only save this object on the Undo/Redo stack if the timestamp is different
|
||||
// from the timestmap of the object at the top of the Undo / Redo stack.
|
||||
virtual uint64_t timestamp() const throw() { return m_timestamp; }
|
||||
bool timestamp_matches(const ModelConfig &rhs) const throw() { return m_timestamp == rhs.m_timestamp; }
|
||||
// Not thread safe! Should not be called from other than the main thread!
|
||||
void touch() { m_timestamp = ++ s_last_timestamp; }
|
||||
|
||||
private:
|
||||
friend class cereal::access;
|
||||
template<class Archive> void serialize(Archive& ar) { ar(m_timestamp); ar(m_data); }
|
||||
|
||||
uint64_t m_timestamp { 1 };
|
||||
DynamicPrintConfig m_data;
|
||||
|
||||
static uint64_t s_last_timestamp;
|
||||
};
|
||||
|
||||
template<typename CONFIG> void normalize_and_apply_config(CONFIG& dst, const ModelConfig& src) { normalize_and_apply_config(dst, src.get()); }
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
// Serialization through the Cereal library
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue