mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-11-02 04:31:17 -07:00
Merge remote-tracking branch 'origin/vb_filament_overrides' into ys_overrides
This commit is contained in:
commit
62f997d167
12 changed files with 659 additions and 313 deletions
|
|
@ -102,7 +102,7 @@ protected:
|
|||
#ifndef BOOST_NOWIDE_DO_LENGTH_MBSTATE_CONST
|
||||
return from - save_from;
|
||||
#else
|
||||
return save_max - max;
|
||||
return int(save_max - max);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -211,25 +211,35 @@ std::vector<std::string> ConfigOptionDef::cli_args(const std::string &key) const
|
|||
|
||||
ConfigOption* ConfigOptionDef::create_empty_option() const
|
||||
{
|
||||
switch (this->type) {
|
||||
case coFloat: return new ConfigOptionFloat();
|
||||
case coFloats: return new ConfigOptionFloats();
|
||||
case coInt: return new ConfigOptionInt();
|
||||
case coInts: return new ConfigOptionInts();
|
||||
case coString: return new ConfigOptionString();
|
||||
case coStrings: return new ConfigOptionStrings();
|
||||
case coPercent: return new ConfigOptionPercent();
|
||||
case coPercents: return new ConfigOptionPercents();
|
||||
case coFloatOrPercent: return new ConfigOptionFloatOrPercent();
|
||||
case coPoint: return new ConfigOptionPoint();
|
||||
case coPoints: return new ConfigOptionPoints();
|
||||
case coPoint3: return new ConfigOptionPoint3();
|
||||
// case coPoint3s: return new ConfigOptionPoint3s();
|
||||
case coBool: return new ConfigOptionBool();
|
||||
case coBools: return new ConfigOptionBools();
|
||||
case coEnum: return new ConfigOptionEnumGeneric(this->enum_keys_map);
|
||||
default: throw std::runtime_error(std::string("Unknown option type for option ") + this->label);
|
||||
}
|
||||
if (this->nullable) {
|
||||
switch (this->type) {
|
||||
case coFloats: return new ConfigOptionFloatsNullable();
|
||||
case coInts: return new ConfigOptionIntsNullable();
|
||||
case coPercents: return new ConfigOptionPercentsNullable();
|
||||
case coBools: return new ConfigOptionBoolsNullable();
|
||||
default: throw std::runtime_error(std::string("Unknown option type for nullable option ") + this->label);
|
||||
}
|
||||
} else {
|
||||
switch (this->type) {
|
||||
case coFloat: return new ConfigOptionFloat();
|
||||
case coFloats: return new ConfigOptionFloats();
|
||||
case coInt: return new ConfigOptionInt();
|
||||
case coInts: return new ConfigOptionInts();
|
||||
case coString: return new ConfigOptionString();
|
||||
case coStrings: return new ConfigOptionStrings();
|
||||
case coPercent: return new ConfigOptionPercent();
|
||||
case coPercents: return new ConfigOptionPercents();
|
||||
case coFloatOrPercent: return new ConfigOptionFloatOrPercent();
|
||||
case coPoint: return new ConfigOptionPoint();
|
||||
case coPoints: return new ConfigOptionPoints();
|
||||
case coPoint3: return new ConfigOptionPoint3();
|
||||
// case coPoint3s: return new ConfigOptionPoint3s();
|
||||
case coBool: return new ConfigOptionBool();
|
||||
case coBools: return new ConfigOptionBools();
|
||||
case coEnum: return new ConfigOptionEnumGeneric(this->enum_keys_map);
|
||||
default: throw std::runtime_error(std::string("Unknown option type for option ") + this->label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConfigOption* ConfigOptionDef::create_default_option() const
|
||||
|
|
@ -254,6 +264,13 @@ ConfigOptionDef* ConfigDef::add(const t_config_option_key &opt_key, ConfigOption
|
|||
return opt;
|
||||
}
|
||||
|
||||
ConfigOptionDef* ConfigDef::add_nullable(const t_config_option_key &opt_key, ConfigOptionType type)
|
||||
{
|
||||
ConfigOptionDef *def = this->add(opt_key, type);
|
||||
def->nullable = true;
|
||||
return def;
|
||||
}
|
||||
|
||||
std::string ConfigOptionDef::nocli = "~~~noCLI";
|
||||
|
||||
std::ostream& ConfigDef::print_cli_help(std::ostream& out, bool show_defaults, std::function<bool(const ConfigOptionDef &)> filter) const
|
||||
|
|
@ -642,6 +659,17 @@ void ConfigBase::save(const std::string &file) const
|
|||
c.close();
|
||||
}
|
||||
|
||||
// Set all the nullable values to nils.
|
||||
void ConfigBase::null_nullables()
|
||||
{
|
||||
for (const std::string &opt_key : this->keys()) {
|
||||
ConfigOption *opt = this->optptr(opt_key, false);
|
||||
assert(opt != nullptr);
|
||||
if (opt->nullable())
|
||||
opt->deserialize("nil");
|
||||
}
|
||||
}
|
||||
|
||||
bool DynamicConfig::operator==(const DynamicConfig &rhs) const
|
||||
{
|
||||
auto it1 = this->options.begin();
|
||||
|
|
@ -655,6 +683,19 @@ bool DynamicConfig::operator==(const DynamicConfig &rhs) const
|
|||
return it1 == it1_end && it2 == it2_end;
|
||||
}
|
||||
|
||||
// Remove options with all nil values, those are optional and it does not help to hold them.
|
||||
size_t DynamicConfig::remove_nil_options()
|
||||
{
|
||||
size_t cnt_removed = 0;
|
||||
for (auto it = options.begin(); it != options.end();)
|
||||
if (it->second->is_nil()) {
|
||||
it = options.erase(it);
|
||||
++ cnt_removed;
|
||||
} else
|
||||
++ it;
|
||||
return cnt_removed;
|
||||
}
|
||||
|
||||
ConfigOption* DynamicConfig::optptr(const t_config_option_key &opt_key, bool create)
|
||||
{
|
||||
auto it = options.find(opt_key);
|
||||
|
|
@ -838,18 +879,22 @@ CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionVector<Slic3r::Vec2d>)
|
|||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionVector<unsigned char>)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionFloat)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionFloats)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionFloatsNullable)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionInt)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionInts)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionIntsNullable)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionString)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionStrings)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPercent)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPercents)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPercentsNullable)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionFloatOrPercent)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPoint)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPoints)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPoint3)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionBool)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionBools)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionBoolsNullable)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionEnumGeneric)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigBase)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::DynamicConfig)
|
||||
|
|
@ -868,17 +913,21 @@ CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVectorBase, Slic3r::Con
|
|||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVectorBase, Slic3r::ConfigOptionVector<unsigned char>)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<double>, Slic3r::ConfigOptionFloat)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<double>, Slic3r::ConfigOptionFloats)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<double>, Slic3r::ConfigOptionFloatsNullable)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<int>, Slic3r::ConfigOptionInt)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<int>, Slic3r::ConfigOptionInts)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<int>, Slic3r::ConfigOptionIntsNullable)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<std::string>, Slic3r::ConfigOptionString)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<std::string>, Slic3r::ConfigOptionStrings)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionFloat, Slic3r::ConfigOptionPercent)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionFloats, Slic3r::ConfigOptionPercents)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionFloats, Slic3r::ConfigOptionPercentsNullable)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionPercent, Slic3r::ConfigOptionFloatOrPercent)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<Slic3r::Vec2d>, Slic3r::ConfigOptionPoint)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<Slic3r::Vec2d>, Slic3r::ConfigOptionPoints)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<Slic3r::Vec3d>, Slic3r::ConfigOptionPoint3)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<bool>, Slic3r::ConfigOptionBool)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<unsigned char>, Slic3r::ConfigOptionBools)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<unsigned char>, Slic3r::ConfigOptionBoolsNullable)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionInt, Slic3r::ConfigOptionEnumGeneric)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigBase, Slic3r::DynamicConfig)
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include "clonable_ptr.hpp"
|
||||
#include "Point.hpp"
|
||||
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
|
|
@ -124,6 +125,10 @@ public:
|
|||
bool operator!=(const ConfigOption &rhs) const { return ! (*this == rhs); }
|
||||
bool is_scalar() const { return (int(this->type()) & int(coVectorType)) == 0; }
|
||||
bool is_vector() const { return ! this->is_scalar(); }
|
||||
// If this option is nullable, then it may have its value or values set to nil.
|
||||
virtual bool nullable() const { return false; }
|
||||
// A scalar is nil, or all values of a vector are nil.
|
||||
virtual bool is_nil() const { return false; }
|
||||
};
|
||||
|
||||
typedef ConfigOption* ConfigOptionPtr;
|
||||
|
|
@ -183,6 +188,8 @@ public:
|
|||
virtual size_t size() const = 0;
|
||||
// Is this vector empty?
|
||||
virtual bool empty() const = 0;
|
||||
// Is the value nil? That should only be possible if this->nullable().
|
||||
virtual bool is_nil(size_t idx) const = 0;
|
||||
|
||||
protected:
|
||||
// Used to verify type compatibility when assigning to / from a scalar ConfigOption.
|
||||
|
|
@ -345,26 +352,41 @@ private:
|
|||
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionSingle<double>>(this)); }
|
||||
};
|
||||
|
||||
class ConfigOptionFloats : public ConfigOptionVector<double>
|
||||
template<bool NULLABLE>
|
||||
class ConfigOptionFloatsTempl : public ConfigOptionVector<double>
|
||||
{
|
||||
public:
|
||||
ConfigOptionFloats() : ConfigOptionVector<double>() {}
|
||||
explicit ConfigOptionFloats(size_t n, double value) : ConfigOptionVector<double>(n, value) {}
|
||||
explicit ConfigOptionFloats(std::initializer_list<double> il) : ConfigOptionVector<double>(std::move(il)) {}
|
||||
explicit ConfigOptionFloats(const std::vector<double> &vec) : ConfigOptionVector<double>(vec) {}
|
||||
explicit ConfigOptionFloats(std::vector<double> &&vec) : ConfigOptionVector<double>(std::move(vec)) {}
|
||||
ConfigOptionFloatsTempl() : ConfigOptionVector<double>() {}
|
||||
explicit ConfigOptionFloatsTempl(size_t n, double value) : ConfigOptionVector<double>(n, value) {}
|
||||
explicit ConfigOptionFloatsTempl(std::initializer_list<double> il) : ConfigOptionVector<double>(std::move(il)) {}
|
||||
explicit ConfigOptionFloatsTempl(const std::vector<double> &vec) : ConfigOptionVector<double>(vec) {}
|
||||
explicit ConfigOptionFloatsTempl(std::vector<double> &&vec) : ConfigOptionVector<double>(std::move(vec)) {}
|
||||
|
||||
static ConfigOptionType static_type() { return coFloats; }
|
||||
ConfigOptionType type() const override { return static_type(); }
|
||||
ConfigOption* clone() const override { return new ConfigOptionFloats(*this); }
|
||||
bool operator==(const ConfigOptionFloats &rhs) const { return this->values == rhs.values; }
|
||||
ConfigOption* clone() const override { return new ConfigOptionFloatsTempl(*this); }
|
||||
bool operator==(const ConfigOptionFloatsTempl &rhs) const { vectors_equal(this->values, rhs.values); }
|
||||
bool operator==(const ConfigOption &rhs) const override {
|
||||
if (rhs.type() != this->type())
|
||||
throw std::runtime_error("ConfigOptionFloatsTempl: Comparing incompatible types");
|
||||
assert(dynamic_cast<const ConfigOptionVector<double>*>(&rhs));
|
||||
return vectors_equal(this->values, static_cast<const ConfigOptionVector<double>*>(&rhs)->values);
|
||||
}
|
||||
// Could a special "nil" value be stored inside the vector, indicating undefined value?
|
||||
bool nullable() const override { return NULLABLE; }
|
||||
// Special "nil" value to be stored into the vector if this->supports_nil().
|
||||
static double nil_value() { return std::numeric_limits<double>::quiet_NaN(); }
|
||||
// A scalar is nil, or all values of a vector are nil.
|
||||
bool is_nil() const override { for (auto v : this->values) if (! std::isnan(v)) return false; return true; }
|
||||
bool is_nil(size_t idx) const override { return std::isnan(v->values[idx]); }
|
||||
|
||||
std::string serialize() const override
|
||||
{
|
||||
std::ostringstream ss;
|
||||
for (std::vector<double>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
|
||||
if (it - this->values.begin() != 0) ss << ",";
|
||||
ss << *it;
|
||||
for (const double &v : this->values) {
|
||||
if (&v != &this->values.front())
|
||||
ss << ",";
|
||||
serialize_single_value(ss, v);
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
|
@ -373,14 +395,14 @@ public:
|
|||
{
|
||||
std::vector<std::string> vv;
|
||||
vv.reserve(this->values.size());
|
||||
for (std::vector<double>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
|
||||
for (const double v : this->values) {
|
||||
std::ostringstream ss;
|
||||
ss << *it;
|
||||
serialize_single_value(ss, v);
|
||||
vv.push_back(ss.str());
|
||||
}
|
||||
return vv;
|
||||
}
|
||||
|
||||
|
||||
bool deserialize(const std::string &str, bool append = false) override
|
||||
{
|
||||
if (! append)
|
||||
|
|
@ -388,25 +410,61 @@ public:
|
|||
std::istringstream is(str);
|
||||
std::string item_str;
|
||||
while (std::getline(is, item_str, ',')) {
|
||||
std::istringstream iss(item_str);
|
||||
double value;
|
||||
iss >> value;
|
||||
this->values.push_back(value);
|
||||
boost::trim(item_str);
|
||||
if (item_str == "nil") {
|
||||
if (NULLABLE)
|
||||
this->values.push_back(nil_value());
|
||||
else
|
||||
std::runtime_error("Deserializing nil into a non-nullable object");
|
||||
} else {
|
||||
std::istringstream iss(item_str);
|
||||
double value;
|
||||
iss >> value;
|
||||
this->values.push_back(value);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ConfigOptionFloats& operator=(const ConfigOption *opt)
|
||||
ConfigOptionFloatsTempl& operator=(const ConfigOption *opt)
|
||||
{
|
||||
this->set(opt);
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
void serialize_single_value(std::ostringstream &ss, const double v) const {
|
||||
if (std::isfinite(v))
|
||||
ss << v;
|
||||
else if (std::isnan(v)) {
|
||||
if (NULLABLE)
|
||||
ss << "nil";
|
||||
else
|
||||
std::runtime_error("Serializing NaN");
|
||||
} else
|
||||
std::runtime_error("Serializing invalid number");
|
||||
}
|
||||
static bool vectors_equal(const std::vector<double> &v1, const std::vector<double> &v2) {
|
||||
if (NULLABLE) {
|
||||
if (v1.size() != v2.size())
|
||||
return false;
|
||||
for (auto it1 = v1.begin(), it2 = v2.begin(); it1 != v1.end(); ++ it1, ++ it2)
|
||||
if (! ((std::isnan(*it1) && std::isnan(*it2)) || *it1 == *it2))
|
||||
return false;
|
||||
return true;
|
||||
} else
|
||||
// Not supporting nullable values, the default vector compare is cheaper.
|
||||
return v1 == v2;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class cereal::access;
|
||||
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionVector<double>>(this)); }
|
||||
};
|
||||
|
||||
using ConfigOptionFloats = ConfigOptionFloatsTempl<false>;
|
||||
using ConfigOptionFloatsNullable = ConfigOptionFloatsTempl<true>;
|
||||
|
||||
class ConfigOptionInt : public ConfigOptionSingle<int>
|
||||
{
|
||||
public:
|
||||
|
|
@ -447,35 +505,45 @@ private:
|
|||
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionSingle<int>>(this)); }
|
||||
};
|
||||
|
||||
class ConfigOptionInts : public ConfigOptionVector<int>
|
||||
template<bool NULLABLE>
|
||||
class ConfigOptionIntsTempl : public ConfigOptionVector<int>
|
||||
{
|
||||
public:
|
||||
ConfigOptionInts() : ConfigOptionVector<int>() {}
|
||||
explicit ConfigOptionInts(size_t n, int value) : ConfigOptionVector<int>(n, value) {}
|
||||
explicit ConfigOptionInts(std::initializer_list<int> il) : ConfigOptionVector<int>(std::move(il)) {}
|
||||
ConfigOptionIntsTempl() : ConfigOptionVector<int>() {}
|
||||
explicit ConfigOptionIntsTempl(size_t n, int value) : ConfigOptionVector<int>(n, value) {}
|
||||
explicit ConfigOptionIntsTempl(std::initializer_list<int> il) : ConfigOptionVector<int>(std::move(il)) {}
|
||||
|
||||
static ConfigOptionType static_type() { return coInts; }
|
||||
ConfigOptionType type() const override { return static_type(); }
|
||||
ConfigOption* clone() const override { return new ConfigOptionInts(*this); }
|
||||
ConfigOptionInts& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
|
||||
bool operator==(const ConfigOptionInts &rhs) const { return this->values == rhs.values; }
|
||||
ConfigOption* clone() const override { return new ConfigOptionIntsTempl(*this); }
|
||||
ConfigOptionIntsTempl& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
|
||||
bool operator==(const ConfigOptionIntsTempl &rhs) const { return this->values == rhs.values; }
|
||||
// Could a special "nil" value be stored inside the vector, indicating undefined value?
|
||||
bool nullable() const override { return NULLABLE; }
|
||||
// Special "nil" value to be stored into the vector if this->supports_nil().
|
||||
static int nil_value() { return std::numeric_limits<int>::max(); }
|
||||
// A scalar is nil, or all values of a vector are nil.
|
||||
bool is_nil() const override { for (auto v : this->values) if (v != nil_value()) return false; return true; }
|
||||
bool is_nil(size_t idx) const override { return v->values[idx] == nil_value(); }
|
||||
|
||||
std::string serialize() const override {
|
||||
std::string serialize() const override
|
||||
{
|
||||
std::ostringstream ss;
|
||||
for (std::vector<int>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
|
||||
if (it - this->values.begin() != 0) ss << ",";
|
||||
ss << *it;
|
||||
for (const int &v : this->values) {
|
||||
if (&v != &this->values.front())
|
||||
ss << ",";
|
||||
serialize_single_value(ss, v);
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::vector<std::string> vserialize() const override
|
||||
std::vector<std::string> vserialize() const override
|
||||
{
|
||||
std::vector<std::string> vv;
|
||||
vv.reserve(this->values.size());
|
||||
for (std::vector<int>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
|
||||
for (const int v : this->values) {
|
||||
std::ostringstream ss;
|
||||
ss << *it;
|
||||
serialize_single_value(ss, v);
|
||||
vv.push_back(ss.str());
|
||||
}
|
||||
return vv;
|
||||
|
|
@ -488,19 +556,40 @@ public:
|
|||
std::istringstream is(str);
|
||||
std::string item_str;
|
||||
while (std::getline(is, item_str, ',')) {
|
||||
std::istringstream iss(item_str);
|
||||
int value;
|
||||
iss >> value;
|
||||
this->values.push_back(value);
|
||||
boost::trim(item_str);
|
||||
if (item_str == "nil") {
|
||||
if (NULLABLE)
|
||||
this->values.push_back(nil_value());
|
||||
else
|
||||
std::runtime_error("Deserializing nil into a non-nullable object");
|
||||
} else {
|
||||
std::istringstream iss(item_str);
|
||||
int value;
|
||||
iss >> value;
|
||||
this->values.push_back(value);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
void serialize_single_value(std::ostringstream &ss, const int v) const {
|
||||
if (v == nil_value()) {
|
||||
if (NULLABLE)
|
||||
ss << "nil";
|
||||
else
|
||||
std::runtime_error("Serializing NaN");
|
||||
} else
|
||||
ss << v;
|
||||
}
|
||||
|
||||
friend class cereal::access;
|
||||
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionVector<int>>(this)); }
|
||||
};
|
||||
|
||||
using ConfigOptionInts = ConfigOptionIntsTempl<false>;
|
||||
using ConfigOptionIntsNullable = ConfigOptionIntsTempl<true>;
|
||||
|
||||
class ConfigOptionString : public ConfigOptionSingle<std::string>
|
||||
{
|
||||
public:
|
||||
|
|
@ -603,64 +692,61 @@ private:
|
|||
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionFloat>(this)); }
|
||||
};
|
||||
|
||||
class ConfigOptionPercents : public ConfigOptionFloats
|
||||
template<bool NULLABLE>
|
||||
class ConfigOptionPercentsTempl : public ConfigOptionFloatsTempl<NULLABLE>
|
||||
{
|
||||
public:
|
||||
ConfigOptionPercents() : ConfigOptionFloats() {}
|
||||
explicit ConfigOptionPercents(size_t n, double value) : ConfigOptionFloats(n, value) {}
|
||||
explicit ConfigOptionPercents(std::initializer_list<double> il) : ConfigOptionFloats(std::move(il)) {}
|
||||
ConfigOptionPercentsTempl() : ConfigOptionFloatsTempl<NULLABLE>() {}
|
||||
explicit ConfigOptionPercentsTempl(size_t n, double value) : ConfigOptionFloatsTempl<NULLABLE>(n, value) {}
|
||||
explicit ConfigOptionPercentsTempl(std::initializer_list<double> il) : ConfigOptionFloatsTempl<NULLABLE>(std::move(il)) {}
|
||||
explicit ConfigOptionPercentsTempl(const std::vector<double>& vec) : ConfigOptionFloatsTempl<NULLABLE>(vec) {}
|
||||
explicit ConfigOptionPercentsTempl(std::vector<double>&& vec) : ConfigOptionFloatsTempl<NULLABLE>(std::move(vec)) {}
|
||||
|
||||
static ConfigOptionType static_type() { return coPercents; }
|
||||
ConfigOptionType type() const override { return static_type(); }
|
||||
ConfigOption* clone() const override { return new ConfigOptionPercents(*this); }
|
||||
ConfigOptionPercents& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
|
||||
bool operator==(const ConfigOptionPercents &rhs) const { return this->values == rhs.values; }
|
||||
ConfigOption* clone() const override { return new ConfigOptionPercentsTempl(*this); }
|
||||
ConfigOptionPercentsTempl& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
|
||||
bool operator==(const ConfigOptionPercentsTempl &rhs) const { return this->values == rhs.values; }
|
||||
|
||||
std::string serialize() const override
|
||||
{
|
||||
std::ostringstream ss;
|
||||
for (const auto &v : this->values) {
|
||||
if (&v != &this->values.front()) ss << ",";
|
||||
ss << v << "%";
|
||||
for (const double &v : this->values) {
|
||||
if (&v != &this->values.front())
|
||||
ss << ",";
|
||||
this->serialize_single_value(ss, v);
|
||||
if (! std::isnan(v))
|
||||
ss << "%";
|
||||
}
|
||||
std::string str = ss.str();
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::string> vserialize() const override
|
||||
{
|
||||
std::vector<std::string> vv;
|
||||
vv.reserve(this->values.size());
|
||||
for (const auto v : this->values) {
|
||||
for (const double v : this->values) {
|
||||
std::ostringstream ss;
|
||||
ss << v;
|
||||
std::string sout = ss.str() + "%";
|
||||
vv.push_back(sout);
|
||||
this->serialize_single_value(ss, v);
|
||||
if (! std::isnan(v))
|
||||
ss << "%";
|
||||
vv.push_back(ss.str());
|
||||
}
|
||||
return vv;
|
||||
}
|
||||
|
||||
bool deserialize(const std::string &str, bool append = false) override
|
||||
{
|
||||
if (! append)
|
||||
this->values.clear();
|
||||
std::istringstream is(str);
|
||||
std::string item_str;
|
||||
while (std::getline(is, item_str, ',')) {
|
||||
std::istringstream iss(item_str);
|
||||
double value;
|
||||
// don't try to parse the trailing % since it's optional
|
||||
iss >> value;
|
||||
this->values.push_back(value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// The float's deserialize function shall ignore the trailing optional %.
|
||||
// bool deserialize(const std::string &str, bool append = false) override;
|
||||
|
||||
private:
|
||||
friend class cereal::access;
|
||||
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionFloats>(this)); }
|
||||
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionFloatsTempl<NULLABLE>>(this)); }
|
||||
};
|
||||
|
||||
using ConfigOptionPercents = ConfigOptionPercentsTempl<false>;
|
||||
using ConfigOptionPercentsNullable = ConfigOptionPercentsTempl<true>;
|
||||
|
||||
class ConfigOptionFloatOrPercent : public ConfigOptionPercent
|
||||
{
|
||||
public:
|
||||
|
|
@ -887,18 +973,28 @@ private:
|
|||
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionSingle<bool>>(this)); }
|
||||
};
|
||||
|
||||
class ConfigOptionBools : public ConfigOptionVector<unsigned char>
|
||||
template<bool NULLABLE>
|
||||
class ConfigOptionBoolsTempl : public ConfigOptionVector<unsigned char>
|
||||
{
|
||||
public:
|
||||
ConfigOptionBools() : ConfigOptionVector<unsigned char>() {}
|
||||
explicit ConfigOptionBools(size_t n, bool value) : ConfigOptionVector<unsigned char>(n, (unsigned char)value) {}
|
||||
explicit ConfigOptionBools(std::initializer_list<bool> il) { values.reserve(il.size()); for (bool b : il) values.emplace_back((unsigned char)b); }
|
||||
ConfigOptionBoolsTempl() : ConfigOptionVector<unsigned char>() {}
|
||||
explicit ConfigOptionBoolsTempl(size_t n, bool value) : ConfigOptionVector<unsigned char>(n, (unsigned char)value) {}
|
||||
explicit ConfigOptionBoolsTempl(std::initializer_list<bool> il) { values.reserve(il.size()); for (bool b : il) values.emplace_back((unsigned char)b); }
|
||||
explicit ConfigOptionBoolsTempl(const std::vector<unsigned char>& vec) : ConfigOptionVector<unsigned char>(vec) {}
|
||||
explicit ConfigOptionBoolsTempl(std::vector<unsigned char>&& vec) : ConfigOptionVector<unsigned char>(std::move(vec)) {}
|
||||
|
||||
static ConfigOptionType static_type() { return coBools; }
|
||||
ConfigOptionType type() const override { return static_type(); }
|
||||
ConfigOption* clone() const override { return new ConfigOptionBools(*this); }
|
||||
ConfigOptionBools& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
|
||||
bool operator==(const ConfigOptionBools &rhs) const { return this->values == rhs.values; }
|
||||
ConfigOption* clone() const override { return new ConfigOptionBoolsTempl(*this); }
|
||||
ConfigOptionBoolsTempl& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
|
||||
bool operator==(const ConfigOptionBoolsTempl &rhs) const { return this->values == rhs.values; }
|
||||
// Could a special "nil" value be stored inside the vector, indicating undefined value?
|
||||
bool nullable() const override { return NULLABLE; }
|
||||
// Special "nil" value to be stored into the vector if this->supports_nil().
|
||||
static unsigned char nil_value() { return std::numeric_limits<unsigned char>::max(); }
|
||||
// A scalar is nil, or all values of a vector are nil.
|
||||
bool is_nil() const override { for (auto v : this->values) if (v != nil_value()) return false; return true; }
|
||||
bool is_nil(size_t idx) const override { return v->values[idx] == nil_value(); }
|
||||
|
||||
bool& get_at(size_t i) {
|
||||
assert(! this->values.empty());
|
||||
|
|
@ -911,19 +1007,20 @@ public:
|
|||
std::string serialize() const override
|
||||
{
|
||||
std::ostringstream ss;
|
||||
for (std::vector<unsigned char>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
|
||||
if (it - this->values.begin() != 0) ss << ",";
|
||||
ss << (*it ? "1" : "0");
|
||||
}
|
||||
for (const unsigned char &v : this->values) {
|
||||
if (&v != &this->values.front())
|
||||
ss << ",";
|
||||
this->serialize_single_value(ss, v);
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::vector<std::string> vserialize() const override
|
||||
{
|
||||
std::vector<std::string> vv;
|
||||
for (std::vector<unsigned char>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
|
||||
std::ostringstream ss;
|
||||
ss << (*it ? "1" : "0");
|
||||
for (const unsigned char v : this->values) {
|
||||
std::ostringstream ss;
|
||||
this->serialize_single_value(ss, v);
|
||||
vv.push_back(ss.str());
|
||||
}
|
||||
return vv;
|
||||
|
|
@ -936,16 +1033,37 @@ public:
|
|||
std::istringstream is(str);
|
||||
std::string item_str;
|
||||
while (std::getline(is, item_str, ',')) {
|
||||
this->values.push_back(item_str.compare("1") == 0);
|
||||
boost::trim(item_str);
|
||||
if (item_str == "nil") {
|
||||
if (NULLABLE)
|
||||
this->values.push_back(nil_value());
|
||||
else
|
||||
std::runtime_error("Deserializing nil into a non-nullable object");
|
||||
} else
|
||||
this->values.push_back(item_str.compare("1") == 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
void serialize_single_value(std::ostringstream &ss, const unsigned char v) const {
|
||||
if (v == nil_value()) {
|
||||
if (NULLABLE)
|
||||
ss << "nil";
|
||||
else
|
||||
std::runtime_error("Serializing NaN");
|
||||
} else
|
||||
ss << (v ? "1" : "0");
|
||||
}
|
||||
|
||||
private:
|
||||
friend class cereal::access;
|
||||
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionVector<unsigned char>>(this)); }
|
||||
};
|
||||
|
||||
using ConfigOptionBools = ConfigOptionBoolsTempl<false>;
|
||||
using ConfigOptionBoolsNullable = ConfigOptionBoolsTempl<true>;
|
||||
|
||||
// Map from an enum integer value to an enum name.
|
||||
typedef std::vector<std::string> t_config_enum_names;
|
||||
// Map from an enum name to an enum integer value.
|
||||
|
|
@ -1096,6 +1214,8 @@ public:
|
|||
t_config_option_key opt_key;
|
||||
// What type? bool, int, string etc.
|
||||
ConfigOptionType type = coNone;
|
||||
// If a type is nullable, then it accepts a "nil" value (scalar) or "nil" values (vector).
|
||||
bool nullable = false;
|
||||
// Default value of this option. The default value object is owned by ConfigDef, it is released in its destructor.
|
||||
Slic3r::clonable_ptr<const ConfigOption> default_value;
|
||||
void set_default_value(const ConfigOption* ptr) { this->default_value = Slic3r::clonable_ptr<const ConfigOption>(ptr); }
|
||||
|
|
@ -1107,45 +1227,65 @@ public:
|
|||
ConfigOption* create_default_option() const;
|
||||
|
||||
template<class Archive> ConfigOption* load_option_from_archive(Archive &archive) const {
|
||||
switch (this->type) {
|
||||
case coFloat: { auto opt = new ConfigOptionFloat(); archive(*opt); return opt; }
|
||||
case coFloats: { auto opt = new ConfigOptionFloats(); archive(*opt); return opt; }
|
||||
case coInt: { auto opt = new ConfigOptionInt(); archive(*opt); return opt; }
|
||||
case coInts: { auto opt = new ConfigOptionInts(); archive(*opt); return opt; }
|
||||
case coString: { auto opt = new ConfigOptionString(); archive(*opt); return opt; }
|
||||
case coStrings: { auto opt = new ConfigOptionStrings(); archive(*opt); return opt; }
|
||||
case coPercent: { auto opt = new ConfigOptionPercent(); archive(*opt); return opt; }
|
||||
case coPercents: { auto opt = new ConfigOptionPercents(); archive(*opt); return opt; }
|
||||
case coFloatOrPercent: { auto opt = new ConfigOptionFloatOrPercent(); archive(*opt); return opt; }
|
||||
case coPoint: { auto opt = new ConfigOptionPoint(); archive(*opt); return opt; }
|
||||
case coPoints: { auto opt = new ConfigOptionPoints(); archive(*opt); return opt; }
|
||||
case coPoint3: { auto opt = new ConfigOptionPoint3(); archive(*opt); return opt; }
|
||||
case coBool: { auto opt = new ConfigOptionBool(); archive(*opt); return opt; }
|
||||
case coBools: { auto opt = new ConfigOptionBools(); archive(*opt); return opt; }
|
||||
case coEnum: { auto opt = new ConfigOptionEnumGeneric(this->enum_keys_map); archive(*opt); return opt; }
|
||||
default: throw std::runtime_error(std::string("ConfigOptionDef::load_option_from_archive(): Unknown option type for option ") + this->opt_key);
|
||||
}
|
||||
if (this->nullable) {
|
||||
switch (this->type) {
|
||||
case coFloats: { auto opt = new ConfigOptionFloatsNullable(); archive(*opt); return opt; }
|
||||
case coInts: { auto opt = new ConfigOptionIntsNullable(); archive(*opt); return opt; }
|
||||
case coPercents: { auto opt = new ConfigOptionPercentsNullable();archive(*opt); return opt; }
|
||||
case coBools: { auto opt = new ConfigOptionBoolsNullable(); archive(*opt); return opt; }
|
||||
default: throw std::runtime_error(std::string("ConfigOptionDef::load_option_from_archive(): Unknown nullable option type for option ") + this->opt_key);
|
||||
}
|
||||
} else {
|
||||
switch (this->type) {
|
||||
case coFloat: { auto opt = new ConfigOptionFloat(); archive(*opt); return opt; }
|
||||
case coFloats: { auto opt = new ConfigOptionFloats(); archive(*opt); return opt; }
|
||||
case coInt: { auto opt = new ConfigOptionInt(); archive(*opt); return opt; }
|
||||
case coInts: { auto opt = new ConfigOptionInts(); archive(*opt); return opt; }
|
||||
case coString: { auto opt = new ConfigOptionString(); archive(*opt); return opt; }
|
||||
case coStrings: { auto opt = new ConfigOptionStrings(); archive(*opt); return opt; }
|
||||
case coPercent: { auto opt = new ConfigOptionPercent(); archive(*opt); return opt; }
|
||||
case coPercents: { auto opt = new ConfigOptionPercents(); archive(*opt); return opt; }
|
||||
case coFloatOrPercent: { auto opt = new ConfigOptionFloatOrPercent(); archive(*opt); return opt; }
|
||||
case coPoint: { auto opt = new ConfigOptionPoint(); archive(*opt); return opt; }
|
||||
case coPoints: { auto opt = new ConfigOptionPoints(); archive(*opt); return opt; }
|
||||
case coPoint3: { auto opt = new ConfigOptionPoint3(); archive(*opt); return opt; }
|
||||
case coBool: { auto opt = new ConfigOptionBool(); archive(*opt); return opt; }
|
||||
case coBools: { auto opt = new ConfigOptionBools(); archive(*opt); return opt; }
|
||||
case coEnum: { auto opt = new ConfigOptionEnumGeneric(this->enum_keys_map); archive(*opt); return opt; }
|
||||
default: throw std::runtime_error(std::string("ConfigOptionDef::load_option_from_archive(): Unknown option type for option ") + this->opt_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class Archive> ConfigOption* save_option_to_archive(Archive &archive, const ConfigOption *opt) const {
|
||||
switch (this->type) {
|
||||
case coFloat: archive(*static_cast<const ConfigOptionFloat*>(opt)); break;
|
||||
case coFloats: archive(*static_cast<const ConfigOptionFloats*>(opt)); break;
|
||||
case coInt: archive(*static_cast<const ConfigOptionInt*>(opt)); break;
|
||||
case coInts: archive(*static_cast<const ConfigOptionInts*>(opt)); break;
|
||||
case coString: archive(*static_cast<const ConfigOptionString*>(opt)); break;
|
||||
case coStrings: archive(*static_cast<const ConfigOptionStrings*>(opt)); break;
|
||||
case coPercent: archive(*static_cast<const ConfigOptionPercent*>(opt)); break;
|
||||
case coPercents: archive(*static_cast<const ConfigOptionPercents*>(opt)); break;
|
||||
case coFloatOrPercent: archive(*static_cast<const ConfigOptionFloatOrPercent*>(opt)); break;
|
||||
case coPoint: archive(*static_cast<const ConfigOptionPoint*>(opt)); break;
|
||||
case coPoints: archive(*static_cast<const ConfigOptionPoints*>(opt)); break;
|
||||
case coPoint3: archive(*static_cast<const ConfigOptionPoint3*>(opt)); break;
|
||||
case coBool: archive(*static_cast<const ConfigOptionBool*>(opt)); break;
|
||||
case coBools: archive(*static_cast<const ConfigOptionBools*>(opt)); break;
|
||||
case coEnum: archive(*static_cast<const ConfigOptionEnumGeneric*>(opt)); break;
|
||||
default: throw std::runtime_error(std::string("ConfigOptionDef::save_option_to_archive(): Unknown option type for option ") + this->opt_key);
|
||||
}
|
||||
if (this->nullable) {
|
||||
switch (this->type) {
|
||||
case coFloats: archive(*static_cast<const ConfigOptionFloatsNullable*>(opt)); break;
|
||||
case coInts: archive(*static_cast<const ConfigOptionIntsNullable*>(opt)); break;
|
||||
case coPercents: archive(*static_cast<const ConfigOptionPercentsNullable*>(opt));break;
|
||||
case coBools: archive(*static_cast<const ConfigOptionBoolsNullable*>(opt)); break;
|
||||
default: throw std::runtime_error(std::string("ConfigOptionDef::save_option_to_archive(): Unknown nullable option type for option ") + this->opt_key);
|
||||
}
|
||||
} else {
|
||||
switch (this->type) {
|
||||
case coFloat: archive(*static_cast<const ConfigOptionFloat*>(opt)); break;
|
||||
case coFloats: archive(*static_cast<const ConfigOptionFloats*>(opt)); break;
|
||||
case coInt: archive(*static_cast<const ConfigOptionInt*>(opt)); break;
|
||||
case coInts: archive(*static_cast<const ConfigOptionInts*>(opt)); break;
|
||||
case coString: archive(*static_cast<const ConfigOptionString*>(opt)); break;
|
||||
case coStrings: archive(*static_cast<const ConfigOptionStrings*>(opt)); break;
|
||||
case coPercent: archive(*static_cast<const ConfigOptionPercent*>(opt)); break;
|
||||
case coPercents: archive(*static_cast<const ConfigOptionPercents*>(opt)); break;
|
||||
case coFloatOrPercent: archive(*static_cast<const ConfigOptionFloatOrPercent*>(opt)); break;
|
||||
case coPoint: archive(*static_cast<const ConfigOptionPoint*>(opt)); break;
|
||||
case coPoints: archive(*static_cast<const ConfigOptionPoints*>(opt)); break;
|
||||
case coPoint3: archive(*static_cast<const ConfigOptionPoint3*>(opt)); break;
|
||||
case coBool: archive(*static_cast<const ConfigOptionBool*>(opt)); break;
|
||||
case coBools: archive(*static_cast<const ConfigOptionBools*>(opt)); break;
|
||||
case coEnum: archive(*static_cast<const ConfigOptionEnumGeneric*>(opt)); break;
|
||||
default: throw std::runtime_error(std::string("ConfigOptionDef::save_option_to_archive(): Unknown option type for option ") + this->opt_key);
|
||||
}
|
||||
}
|
||||
// Make the compiler happy, shut up the warnings.
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -1263,6 +1403,7 @@ public:
|
|||
|
||||
protected:
|
||||
ConfigOptionDef* add(const t_config_option_key &opt_key, ConfigOptionType type);
|
||||
ConfigOptionDef* add_nullable(const t_config_option_key &opt_key, ConfigOptionType type);
|
||||
};
|
||||
|
||||
// An abstract configuration store.
|
||||
|
|
@ -1347,6 +1488,9 @@ public:
|
|||
void load(const boost::property_tree::ptree &tree);
|
||||
void save(const std::string &file) const;
|
||||
|
||||
// Set all the nullable values to nils.
|
||||
void null_nullables();
|
||||
|
||||
private:
|
||||
// Set a configuration value from a string.
|
||||
bool set_deserialize_raw(const t_config_option_key &opt_key_src, const std::string &str, bool append);
|
||||
|
|
@ -1444,6 +1588,9 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
// Remove options with all nil values, those are optional and it does not help to hold them.
|
||||
size_t remove_nil_options();
|
||||
|
||||
// Allow DynamicConfig to be instantiated on ints own without a definition.
|
||||
// If the definition is not defined, the method requiring the definition will throw NoDefinitionException.
|
||||
const ConfigDef* def() const override { return nullptr; };
|
||||
|
|
|
|||
|
|
@ -1783,47 +1783,7 @@ std::string Print::output_filename(const std::string &filename_base) const
|
|||
DynamicConfig config = this->finished() ? this->print_statistics().config() : this->print_statistics().placeholders();
|
||||
return this->PrintBase::output_filename(m_config.output_filename_format.value, ".gcode", filename_base, &config);
|
||||
}
|
||||
/*
|
||||
// Shorten the dhms time by removing the seconds, rounding the dhm to full minutes
|
||||
// and removing spaces.
|
||||
static std::string short_time(const std::string &time)
|
||||
{
|
||||
// Parse the dhms time format.
|
||||
int days = 0;
|
||||
int hours = 0;
|
||||
int minutes = 0;
|
||||
int seconds = 0;
|
||||
if (time.find('d') != std::string::npos)
|
||||
::sscanf(time.c_str(), "%dd %dh %dm %ds", &days, &hours, &minutes, &seconds);
|
||||
else if (time.find('h') != std::string::npos)
|
||||
::sscanf(time.c_str(), "%dh %dm %ds", &hours, &minutes, &seconds);
|
||||
else if (time.find('m') != std::string::npos)
|
||||
::sscanf(time.c_str(), "%dm %ds", &minutes, &seconds);
|
||||
else if (time.find('s') != std::string::npos)
|
||||
::sscanf(time.c_str(), "%ds", &seconds);
|
||||
// Round to full minutes.
|
||||
if (days + hours + minutes > 0 && seconds >= 30) {
|
||||
if (++ minutes == 60) {
|
||||
minutes = 0;
|
||||
if (++ hours == 24) {
|
||||
hours = 0;
|
||||
++ days;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Format the dhm time.
|
||||
char buffer[64];
|
||||
if (days > 0)
|
||||
::sprintf(buffer, "%dd%dh%dm", days, hours, minutes);
|
||||
else if (hours > 0)
|
||||
::sprintf(buffer, "%dh%dm", hours, minutes);
|
||||
else if (minutes > 0)
|
||||
::sprintf(buffer, "%dm", minutes);
|
||||
else
|
||||
::sprintf(buffer, "%ds", seconds);
|
||||
return buffer;
|
||||
}
|
||||
*/
|
||||
|
||||
DynamicConfig PrintStatistics::config() const
|
||||
{
|
||||
DynamicConfig config;
|
||||
|
|
|
|||
|
|
@ -2228,6 +2228,30 @@ void PrintConfigDef::init_fff_params()
|
|||
def->sidetext = L("mm");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(0));
|
||||
|
||||
// Declare retract values for filament profile, overriding the printer's extruder profile.
|
||||
for (const char *opt_key : {
|
||||
// floats
|
||||
"retract_length", "retract_lift", "retract_lift_above", "retract_lift_below", "retract_speed", "deretract_speed", "retract_restart_extra", "retract_before_travel",
|
||||
// bools
|
||||
"retract_layer_change", "wipe",
|
||||
// percents
|
||||
"retract_before_wipe"}) {
|
||||
auto it_opt = options.find(opt_key);
|
||||
assert(it_opt != options.end());
|
||||
def = this->add_nullable(std::string("filament_") + opt_key, it_opt->second.type);
|
||||
def->label = it_opt->second.label;
|
||||
def->full_label = it_opt->second.full_label;
|
||||
def->tooltip = it_opt->second.tooltip;
|
||||
def->sidetext = it_opt->second.sidetext;
|
||||
def->mode = it_opt->second.mode;
|
||||
switch (def->type) {
|
||||
case coFloats : def->set_default_value(new ConfigOptionFloatsNullable (static_cast<const ConfigOptionFloats* >(it_opt->second.default_value.get())->values)); break;
|
||||
case coPercents : def->set_default_value(new ConfigOptionPercentsNullable(static_cast<const ConfigOptionPercents*>(it_opt->second.default_value.get())->values)); break;
|
||||
case coBools : def->set_default_value(new ConfigOptionBoolsNullable (static_cast<const ConfigOptionBools* >(it_opt->second.default_value.get())->values)); break;
|
||||
default: assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PrintConfigDef::init_sla_params()
|
||||
|
|
@ -2987,7 +3011,7 @@ std::string FullPrintConfig::validate()
|
|||
}
|
||||
case coFloats:
|
||||
case coPercents:
|
||||
for (double v : static_cast<const ConfigOptionFloats*>(opt)->values)
|
||||
for (double v : static_cast<const ConfigOptionVector<double>*>(opt)->values)
|
||||
if (v < optdef->min || v > optdef->max) {
|
||||
out_of_range = true;
|
||||
break;
|
||||
|
|
@ -3000,7 +3024,7 @@ std::string FullPrintConfig::validate()
|
|||
break;
|
||||
}
|
||||
case coInts:
|
||||
for (int v : static_cast<const ConfigOptionInts*>(opt)->values)
|
||||
for (int v : static_cast<const ConfigOptionVector<int>*>(opt)->values)
|
||||
if (v < optdef->min || v > optdef->max) {
|
||||
out_of_range = true;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -3725,9 +3725,10 @@ void Plater::priv::take_snapshot(const std::string& snapshot_name)
|
|||
if (this->m_prevent_snapshots > 0)
|
||||
return;
|
||||
assert(this->m_prevent_snapshots >= 0);
|
||||
unsigned int flags = 0;
|
||||
UndoRedo::SnapshotData snapshot_data;
|
||||
snapshot_data.printer_technology = this->printer_technology;
|
||||
if (this->view3D->is_layers_editing_enabled())
|
||||
flags |= UndoRedo::Snapshot::VARIABLE_LAYER_EDITING_ACTIVE;
|
||||
snapshot_data.flags |= UndoRedo::SnapshotData::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) {
|
||||
|
|
@ -3735,7 +3736,7 @@ void Plater::priv::take_snapshot(const std::string& snapshot_name)
|
|||
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(), snapshot_data);
|
||||
this->undo_redo_stack.release_least_recently_used();
|
||||
// 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();
|
||||
|
|
@ -3769,11 +3770,11 @@ void Plater::priv::undo_redo_to(size_t time_to_load)
|
|||
void Plater::priv::undo_redo_to(std::vector<UndoRedo::Snapshot>::const_iterator it_snapshot)
|
||||
{
|
||||
bool temp_snapshot_was_taken = this->undo_redo_stack.temp_snapshot_active();
|
||||
PrinterTechnology new_printer_technology = it_snapshot->printer_technology;
|
||||
PrinterTechnology new_printer_technology = it_snapshot->snapshot_data.printer_technology;
|
||||
bool printer_technology_changed = this->printer_technology != new_printer_technology;
|
||||
if (printer_technology_changed) {
|
||||
// Switching the printer technology when jumping forwards / backwards in time. Switch to the last active printer profile of the other type.
|
||||
std::string s_pt = (it_snapshot->printer_technology == ptFFF) ? "FFF" : "SLA";
|
||||
std::string s_pt = (it_snapshot->snapshot_data.printer_technology == ptFFF) ? "FFF" : "SLA";
|
||||
if (! wxGetApp().check_unsaved_changes(from_u8((boost::format(_utf8(
|
||||
L("%1% printer was active at the time the target Undo / Redo snapshot was taken. Switching to %1% printer requires reloading of %1% presets."))) % s_pt).str())))
|
||||
// Don't switch the profiles.
|
||||
|
|
@ -3789,17 +3790,18 @@ void Plater::priv::undo_redo_to(std::vector<UndoRedo::Snapshot>::const_iterator
|
|||
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;
|
||||
unsigned int new_flags = it_snapshot->snapshot_data.flags;
|
||||
UndoRedo::SnapshotData top_snapshot_data;
|
||||
top_snapshot_data.printer_technology = this->printer_technology;
|
||||
if (this->view3D->is_layers_editing_enabled())
|
||||
top_snapshot_flags |= UndoRedo::Snapshot::VARIABLE_LAYER_EDITING_ACTIVE;
|
||||
bool new_variable_layer_editing_active = (new_flags & UndoRedo::Snapshot::VARIABLE_LAYER_EDITING_ACTIVE) != 0;
|
||||
top_snapshot_data.flags |= UndoRedo::SnapshotData::VARIABLE_LAYER_EDITING_ACTIVE;
|
||||
bool new_variable_layer_editing_active = (new_flags & UndoRedo::SnapshotData::VARIABLE_LAYER_EDITING_ACTIVE) != 0;
|
||||
// Disable layer editing before the Undo / Redo jump.
|
||||
if (!new_variable_layer_editing_active && view3D->is_layers_editing_enabled())
|
||||
view3D->get_canvas3d()->force_main_toolbar_left_action(view3D->get_canvas3d()->get_main_toolbar_item_id("layersediting"));
|
||||
// Do the jump in time.
|
||||
if (it_snapshot->timestamp < this->undo_redo_stack.active_snapshot_time() ?
|
||||
this->undo_redo_stack.undo(model, this->view3D->get_canvas3d()->get_selection(), this->view3D->get_canvas3d()->get_gizmos_manager(), this->printer_technology, top_snapshot_flags, it_snapshot->timestamp) :
|
||||
this->undo_redo_stack.undo(model, this->view3D->get_canvas3d()->get_selection(), this->view3D->get_canvas3d()->get_gizmos_manager(), top_snapshot_data, it_snapshot->timestamp) :
|
||||
this->undo_redo_stack.redo(model, this->view3D->get_canvas3d()->get_gizmos_manager(), it_snapshot->timestamp)) {
|
||||
if (printer_technology_changed) {
|
||||
// Switch to the other printer technology. Switch to the last printer active for that particular technology.
|
||||
|
|
|
|||
|
|
@ -400,6 +400,10 @@ const std::vector<std::string>& Preset::filament_options()
|
|||
"temperature", "first_layer_temperature", "bed_temperature", "first_layer_bed_temperature", "fan_always_on", "cooling", "min_fan_speed",
|
||||
"max_fan_speed", "bridge_fan_speed", "disable_fan_first_layers", "fan_below_layer_time", "slowdown_below_layer_time", "min_print_speed",
|
||||
"start_filament_gcode", "end_filament_gcode",
|
||||
// Retract overrides
|
||||
"filament_retract_length", "filament_retract_lift", "filament_retract_lift_above", "filament_retract_lift_below", "filament_retract_speed", "filament_deretract_speed", "filament_retract_restart_extra", "filament_retract_before_travel",
|
||||
"filament_retract_layer_change", "filament_wipe", "filament_retract_before_wipe",
|
||||
// Profile compatibility
|
||||
"compatible_prints", "compatible_prints_condition", "compatible_printers", "compatible_printers_condition", "inherits"
|
||||
};
|
||||
return s_opts;
|
||||
|
|
|
|||
|
|
@ -72,6 +72,8 @@ PresetBundle::PresetBundle() :
|
|||
this->filaments.default_preset().config.option<ConfigOptionStrings>("filament_settings_id", true)->values = { "" };
|
||||
this->filaments.default_preset().compatible_printers_condition();
|
||||
this->filaments.default_preset().inherits();
|
||||
// Set all the nullable values to nils.
|
||||
this->filaments.default_preset().config.null_nullables();
|
||||
|
||||
this->sla_materials.default_preset().config.optptr("sla_material_settings_id", true);
|
||||
this->sla_materials.default_preset().compatible_printers_condition();
|
||||
|
|
|
|||
|
|
@ -35,6 +35,10 @@
|
|||
namespace Slic3r {
|
||||
namespace UndoRedo {
|
||||
|
||||
SnapshotData::SnapshotData() : printer_technology(ptUnknown), flags(0)
|
||||
{
|
||||
}
|
||||
|
||||
static std::string topmost_snapshot_name = "@@@ Topmost @@@";
|
||||
|
||||
bool Snapshot::is_topmost() const
|
||||
|
|
@ -496,12 +500,12 @@ public:
|
|||
}
|
||||
|
||||
// Store the current application state onto the Undo / Redo stack, remove all snapshots after m_active_snapshot_time.
|
||||
void take_snapshot(const std::string& snapshot_name, const Slic3r::Model& model, const Slic3r::GUI::Selection& selection, const Slic3r::GUI::GLGizmosManager& gizmos, Slic3r::PrinterTechnology printer_technology, unsigned int flags);
|
||||
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 load_snapshot(size_t timestamp, Slic3r::Model& model, Slic3r::GUI::GLGizmosManager& gizmos);
|
||||
|
||||
bool has_undo_snapshot() const;
|
||||
bool has_redo_snapshot() const;
|
||||
bool undo(Slic3r::Model &model, const Slic3r::GUI::Selection &selection, Slic3r::GUI::GLGizmosManager &gizmos, PrinterTechnology printer_technology, unsigned int flags, size_t jump_to_time);
|
||||
bool undo(Slic3r::Model &model, const Slic3r::GUI::Selection &selection, Slic3r::GUI::GLGizmosManager &gizmos, const SnapshotData &snapshot_data, size_t jump_to_time);
|
||||
bool redo(Slic3r::Model &model, Slic3r::GUI::GLGizmosManager &gizmos, size_t jump_to_time);
|
||||
void release_least_recently_used();
|
||||
|
||||
|
|
@ -786,7 +790,7 @@ template<typename T> void StackImpl::load_mutable_object(const Slic3r::ObjectID
|
|||
}
|
||||
|
||||
// Store the current application state onto the Undo / Redo stack, remove all snapshots after m_active_snapshot_time.
|
||||
void StackImpl::take_snapshot(const std::string& snapshot_name, const Slic3r::Model& model, const Slic3r::GUI::Selection& selection, const Slic3r::GUI::GLGizmosManager& gizmos, Slic3r::PrinterTechnology printer_technology, unsigned int flags)
|
||||
void 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)
|
||||
{
|
||||
// Release old snapshot data.
|
||||
assert(m_active_snapshot_time <= m_current_time);
|
||||
|
|
@ -806,11 +810,11 @@ void StackImpl::take_snapshot(const std::string& snapshot_name, const Slic3r::Mo
|
|||
this->save_mutable_object<Selection>(m_selection);
|
||||
this->save_mutable_object<Slic3r::GUI::GLGizmosManager>(gizmos);
|
||||
// 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, snapshot_data);
|
||||
m_active_snapshot_time = m_current_time;
|
||||
// Save snapshot info of the last "current" aka "top most" state, that is only being serialized
|
||||
// if undoing an action. Such a snapshot has an invalid Model ID assigned if it was not taken yet.
|
||||
m_snapshots.emplace_back(topmost_snapshot_name, m_active_snapshot_time, 0, printer_technology, flags);
|
||||
m_snapshots.emplace_back(topmost_snapshot_name, m_active_snapshot_time, 0, snapshot_data);
|
||||
// Release empty objects from the history.
|
||||
this->collect_garbage();
|
||||
assert(this->valid());
|
||||
|
|
@ -856,7 +860,7 @@ bool StackImpl::has_redo_snapshot() const
|
|||
return ++ it != m_snapshots.end();
|
||||
}
|
||||
|
||||
bool StackImpl::undo(Slic3r::Model &model, const Slic3r::GUI::Selection &selection, Slic3r::GUI::GLGizmosManager &gizmos, PrinterTechnology printer_technology, unsigned int flags, size_t time_to_load)
|
||||
bool StackImpl::undo(Slic3r::Model &model, const Slic3r::GUI::Selection &selection, Slic3r::GUI::GLGizmosManager &gizmos, const SnapshotData &snapshot_data, size_t time_to_load)
|
||||
{
|
||||
assert(this->valid());
|
||||
if (time_to_load == SIZE_MAX) {
|
||||
|
|
@ -870,7 +874,7 @@ bool StackImpl::undo(Slic3r::Model &model, const Slic3r::GUI::Selection &selecti
|
|||
bool new_snapshot_taken = false;
|
||||
if (m_active_snapshot_time == m_snapshots.back().timestamp && ! m_snapshots.back().is_topmost_captured()) {
|
||||
// The current state is temporary. The current state needs to be captured to be redoable.
|
||||
this->take_snapshot(topmost_snapshot_name, model, selection, gizmos, printer_technology, flags);
|
||||
this->take_snapshot(topmost_snapshot_name, model, selection, gizmos, snapshot_data);
|
||||
// The line above entered another topmost_snapshot_name.
|
||||
assert(m_snapshots.back().is_topmost());
|
||||
assert(! m_snapshots.back().is_topmost_captured());
|
||||
|
|
@ -1019,12 +1023,12 @@ void Stack::set_memory_limit(size_t memsize) { pimpl->set_memory_limit(memsize);
|
|||
size_t Stack::get_memory_limit() const { return pimpl->get_memory_limit(); }
|
||||
size_t Stack::memsize() const { return pimpl->memsize(); }
|
||||
void Stack::release_least_recently_used() { pimpl->release_least_recently_used(); }
|
||||
void Stack::take_snapshot(const std::string& snapshot_name, const Slic3r::Model& model, const Slic3r::GUI::Selection& selection, const Slic3r::GUI::GLGizmosManager& gizmos, Slic3r::PrinterTechnology printer_technology, unsigned int flags)
|
||||
{ pimpl->take_snapshot(snapshot_name, model, selection, gizmos, printer_technology, flags); }
|
||||
void Stack::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)
|
||||
{ pimpl->take_snapshot(snapshot_name, model, selection, gizmos, snapshot_data); }
|
||||
bool Stack::has_undo_snapshot() const { return pimpl->has_undo_snapshot(); }
|
||||
bool Stack::has_redo_snapshot() const { return pimpl->has_redo_snapshot(); }
|
||||
bool Stack::undo(Slic3r::Model& model, const Slic3r::GUI::Selection& selection, Slic3r::GUI::GLGizmosManager& gizmos, PrinterTechnology printer_technology, unsigned int flags, size_t time_to_load)
|
||||
{ return pimpl->undo(model, selection, gizmos, printer_technology, flags, time_to_load); }
|
||||
bool Stack::undo(Slic3r::Model& model, const Slic3r::GUI::Selection& selection, Slic3r::GUI::GLGizmosManager& gizmos, const SnapshotData &snapshot_data, size_t time_to_load)
|
||||
{ return pimpl->undo(model, selection, gizmos, snapshot_data, time_to_load); }
|
||||
bool Stack::redo(Slic3r::Model& model, Slic3r::GUI::GLGizmosManager& gizmos, size_t time_to_load) { return pimpl->redo(model, gizmos, time_to_load); }
|
||||
const Selection& Stack::selection_deserialized() const { return pimpl->selection_deserialized(); }
|
||||
|
||||
|
|
|
|||
|
|
@ -21,23 +21,36 @@ namespace GUI {
|
|||
|
||||
namespace UndoRedo {
|
||||
|
||||
struct Snapshot
|
||||
// Data structure to be stored with each snapshot.
|
||||
// Storing short data (bit masks, ints) with each snapshot instead of being serialized into the Undo / Redo stack
|
||||
// is likely cheaper in term of both the runtime and memory allocation.
|
||||
// Also the SnapshotData is available without having to deserialize the snapshot from the Undo / Redo stack,
|
||||
// which may be handy sometimes.
|
||||
struct SnapshotData
|
||||
{
|
||||
Snapshot(size_t timestamp) : timestamp(timestamp) {}
|
||||
Snapshot(const std::string &name, size_t timestamp, size_t model_id, Slic3r::PrinterTechnology printer_technology, unsigned int flags) :
|
||||
name(name), timestamp(timestamp), model_id(model_id), printer_technology(printer_technology), flags(flags) {}
|
||||
// Constructor is defined in .cpp due to the forward declaration of enum PrinterTechnology.
|
||||
SnapshotData();
|
||||
|
||||
PrinterTechnology printer_technology;
|
||||
// Bitmap of Flags (see the Flags enum).
|
||||
unsigned int flags;
|
||||
|
||||
// Bitmask of various binary flags to be stored with the snapshot.
|
||||
enum Flags {
|
||||
VARIABLE_LAYER_EDITING_ACTIVE = 1,
|
||||
};
|
||||
};
|
||||
|
||||
struct Snapshot
|
||||
{
|
||||
Snapshot(size_t timestamp) : timestamp(timestamp) {}
|
||||
Snapshot(const std::string &name, size_t timestamp, size_t model_id, const SnapshotData &snapshot_data) :
|
||||
name(name), timestamp(timestamp), model_id(model_id), snapshot_data(snapshot_data) {}
|
||||
|
||||
std::string name;
|
||||
size_t timestamp;
|
||||
size_t model_id;
|
||||
PrinterTechnology printer_technology;
|
||||
// Bitmap of Flags (see the Flags enum).
|
||||
unsigned int flags;
|
||||
SnapshotData snapshot_data;
|
||||
|
||||
bool operator< (const Snapshot &rhs) const { return this->timestamp < rhs.timestamp; }
|
||||
bool operator==(const Snapshot &rhs) const { return this->timestamp == rhs.timestamp; }
|
||||
|
|
@ -77,7 +90,7 @@ public:
|
|||
void release_least_recently_used();
|
||||
|
||||
// Store the current application state onto the Undo / Redo stack, remove all snapshots after m_active_snapshot_time.
|
||||
void take_snapshot(const std::string& snapshot_name, const Slic3r::Model& model, const Slic3r::GUI::Selection& selection, const Slic3r::GUI::GLGizmosManager& gizmos, Slic3r::PrinterTechnology printer_technology, unsigned int flags);
|
||||
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);
|
||||
|
||||
// To be queried to enable / disable the Undo / Redo buttons at the UI.
|
||||
bool has_undo_snapshot() const;
|
||||
|
|
@ -85,7 +98,7 @@ public:
|
|||
|
||||
// Roll back the time. If time_to_load is SIZE_MAX, the previous snapshot is activated.
|
||||
// Undoing an action may need to take a snapshot of the current application state, so that redo to the current state is possible.
|
||||
bool undo(Slic3r::Model& model, const Slic3r::GUI::Selection& selection, Slic3r::GUI::GLGizmosManager& gizmos, PrinterTechnology printer_technology, unsigned int flags, size_t time_to_load = SIZE_MAX);
|
||||
bool undo(Slic3r::Model& model, const Slic3r::GUI::Selection& selection, Slic3r::GUI::GLGizmosManager& gizmos, const SnapshotData &snapshot_data, size_t time_to_load = SIZE_MAX);
|
||||
|
||||
// Jump forward in time. If time_to_load is SIZE_MAX, the next snapshot is activated.
|
||||
bool redo(Slic3r::Model& model, Slic3r::GUI::GLGizmosManager& gizmos, size_t time_to_load = SIZE_MAX);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue