Configuration layer: Support for vectors of FloatsOrPercents and

FloatsOrPercentsNullable, to support further filament overrides
of Print preset values, namely Avoid Crossing Perimeters.
This commit is contained in:
Vojtech Bubnik 2020-12-14 15:58:39 +01:00
parent cdb05d103a
commit 7b9f2093bb
2 changed files with 145 additions and 0 deletions

View File

@ -233,6 +233,7 @@ ConfigOption* ConfigOptionDef::create_empty_option() const
case coFloats: return new ConfigOptionFloatsNullable();
case coInts: return new ConfigOptionIntsNullable();
case coPercents: return new ConfigOptionPercentsNullable();
case coFloatsOrPercents: return new ConfigOptionFloatsOrPercentsNullable();
case coBools: return new ConfigOptionBoolsNullable();
default: throw Slic3r::RuntimeError(std::string("Unknown option type for nullable option ") + this->label);
}
@ -247,6 +248,7 @@ ConfigOption* ConfigOptionDef::create_empty_option() const
case coPercent: return new ConfigOptionPercent();
case coPercents: return new ConfigOptionPercents();
case coFloatOrPercent: return new ConfigOptionFloatOrPercent();
case coFloatsOrPercents: return new ConfigOptionFloatsOrPercents();
case coPoint: return new ConfigOptionPoint();
case coPoints: return new ConfigOptionPoints();
case coPoint3: return new ConfigOptionPoint3();
@ -950,6 +952,8 @@ CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPercent)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPercents)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPercentsNullable)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionFloatOrPercent)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionFloatsOrPercents)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionFloatsOrPercentsNullable)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPoint)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPoints)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPoint3)
@ -984,6 +988,8 @@ CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionFloat, Slic3r::ConfigOp
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::ConfigOptionVector<Slic3r::FloatOrPercent>, Slic3r::ConfigOptionFloatsOrPercents)
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<Slic3r::FloatOrPercent>, Slic3r::ConfigOptionFloatsOrPercentsNullable)
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)

View File

@ -86,6 +86,8 @@ enum ConfigOptionType {
coPercents = coPercent + coVectorType,
// a fraction or an absolute value
coFloatOrPercent = 5,
// vector of the above
coFloatsOrPercents = coFloatOrPercent + coVectorType,
// single 2d point (Point2f). Currently not used.
coPoint = 6,
// vector of 2d points (Point2f). Currently used for the definition of the print bed and for the extruder offsets.
@ -889,6 +891,143 @@ private:
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionPercent>(this), percent); }
};
struct FloatOrPercent
{
double value;
bool percent;
private:
friend class cereal::access;
template<class Archive> void serialize(Archive & ar) { ar(this->value); ar(this->percent); }
};
inline bool operator==(const FloatOrPercent &l, const FloatOrPercent &r)
{
return l.value == r.value && l.percent == r.percent;
}
inline bool operator!=(const FloatOrPercent& l, const FloatOrPercent& r)
{
return !(l == r);
}
template<bool NULLABLE>
class ConfigOptionFloatsOrPercentsTempl : public ConfigOptionVector<FloatOrPercent>
{
public:
ConfigOptionFloatsOrPercentsTempl() : ConfigOptionVector<FloatOrPercent>() {}
explicit ConfigOptionFloatsOrPercentsTempl(size_t n, FloatOrPercent value) : ConfigOptionVector<FloatOrPercent>(n, value) {}
explicit ConfigOptionFloatsOrPercentsTempl(std::initializer_list<FloatOrPercent> il) : ConfigOptionVector<FloatOrPercent>(std::move(il)) {}
explicit ConfigOptionFloatsOrPercentsTempl(const std::vector<FloatOrPercent> &vec) : ConfigOptionVector<FloatOrPercent>(vec) {}
explicit ConfigOptionFloatsOrPercentsTempl(std::vector<FloatOrPercent> &&vec) : ConfigOptionVector<FloatOrPercent>(std::move(vec)) {}
static ConfigOptionType static_type() { return coFloatsOrPercents; }
ConfigOptionType type() const override { return static_type(); }
ConfigOption* clone() const override { return new ConfigOptionFloatsOrPercentsTempl(*this); }
bool operator==(const ConfigOptionFloatsOrPercentsTempl &rhs) const { return vectors_equal(this->values, rhs.values); }
bool operator==(const ConfigOption &rhs) const override {
if (rhs.type() != this->type())
throw Slic3r::RuntimeError("ConfigOptionFloatsOrPercentsTempl: Comparing incompatible types");
assert(dynamic_cast<const ConfigOptionVector<FloatOrPercent>*>(&rhs));
return vectors_equal(this->values, static_cast<const ConfigOptionVector<FloatOrPercent>*>(&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 FloatOrPercent nil_value() { return { std::numeric_limits<double>::quiet_NaN(), false }; }
// 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.value)) return false; return true; }
bool is_nil(size_t idx) const override { return std::isnan(this->values[idx].value); }
std::string serialize() const override
{
std::ostringstream ss;
for (const FloatOrPercent &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> vv;
vv.reserve(this->values.size());
for (const FloatOrPercent &v : this->values) {
std::ostringstream ss;
serialize_single_value(ss, v);
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, ',')) {
boost::trim(item_str);
if (item_str == "nil") {
if (NULLABLE)
this->values.push_back(nil_value());
else
throw Slic3r::RuntimeError("Deserializing nil into a non-nullable object");
} else {
bool percent = item_str.find_first_of("%") != std::string::npos;
std::istringstream iss(item_str);
double value;
iss >> value;
this->values.push_back({ value, percent });
}
}
return true;
}
ConfigOptionFloatsOrPercentsTempl& operator=(const ConfigOption *opt)
{
this->set(opt);
return *this;
}
protected:
void serialize_single_value(std::ostringstream &ss, const FloatOrPercent &v) const {
if (std::isfinite(v.value)) {
ss << v.value;
if (v.percent)
ss << "%";
} else if (std::isnan(v.value)) {
if (NULLABLE)
ss << "nil";
else
throw Slic3r::RuntimeError("Serializing NaN");
} else
throw Slic3r::RuntimeError("Serializing invalid number");
}
static bool vectors_equal(const std::vector<FloatOrPercent> &v1, const std::vector<FloatOrPercent> &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->value) && std::isnan(it2->value)) || *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<FloatOrPercent>>(this)); }
};
using ConfigOptionFloatsOrPercents = ConfigOptionFloatsOrPercentsTempl<false>;
using ConfigOptionFloatsOrPercentsNullable = ConfigOptionFloatsOrPercentsTempl<true>;
class ConfigOptionPoint : public ConfigOptionSingle<Vec2d>
{
public: