From 92fa0ff010f9ee8dee24f4c00b5217f92ecb04f6 Mon Sep 17 00:00:00 2001 From: "xun.zhang" Date: Fri, 23 Aug 2024 15:29:15 +0800 Subject: [PATCH] ENH: add ConfigOptionPointsGroups 1.Add extruder printable area jira:NONE Signed-off-by: xun.zhang Change-Id: I753344917a67e3d8ac361c15c3d374b5ef951d21 --- src/libslic3r/Config.cpp | 100 ++++++++++++++++++++++----------- src/libslic3r/Config.hpp | 101 ++++++++++++++++++++++++++++++++++ src/libslic3r/Point.hpp | 15 +++++ src/libslic3r/Preset.cpp | 3 +- src/libslic3r/PrintConfig.cpp | 7 +++ src/libslic3r/PrintConfig.hpp | 1 + 6 files changed, 194 insertions(+), 33 deletions(-) diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp index d3ff332ed..ac1e46416 100644 --- a/src/libslic3r/Config.cpp +++ b/src/libslic3r/Config.cpp @@ -800,6 +800,50 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex CNumericLocalesSetter locales_setter; + std::function parse_str_arr = [&parse_str_arr](const json::const_iterator& it, const char single_sep,const char array_sep,const bool escape_string_style,std::string& value_str)->bool { + // must have consistent type name + std::string consistent_type; + for (auto iter = it.value().begin(); iter != it.value().end(); ++iter) { + if (consistent_type.empty()) + consistent_type = iter.value().type_name(); + else { + if (consistent_type != iter.value().type_name()) + return false; + } + } + + bool first = true; + for (auto iter = it.value().begin(); iter != it.value().end(); iter++) { + if (iter.value().is_array()) { + if (!first) + value_str += array_sep; + else + first = false; + bool success = parse_str_arr(iter, single_sep, array_sep,escape_string_style, value_str); + if (!success) + return false; + } + else if (iter.value().is_string()) { + if (!first) + value_str += single_sep; + else + first = false; + if (!escape_string_style) + value_str += iter.value(); + else { + value_str += "\""; + value_str += escape_string_cstyle(iter.value()); + value_str += "\""; + } + } + else { + //should not happen + return false; + } + } + return true; + }; + try { boost::nowide::ifstream ifs(file); ifs >> j; @@ -882,8 +926,7 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex substitution_context.unrecogized_keys.push_back(opt_key_src); continue; } - bool valid = true, first = true, use_comma = true; - //bool test2 = (it.key() == std::string("filament_end_gcode")); + bool valid = true, first = true; const ConfigOptionDef* optdef = config_def->get(opt_key); if (optdef == nullptr) { // If we didn't find an option, look for any other option having this as an alias. @@ -900,35 +943,30 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex } } - if (optdef && optdef->type == coStrings) { - use_comma = false; - } - for (auto iter = it.value().begin(); iter != it.value().end(); iter++) { - if (iter.value().is_string()) { - if (!first) { - if (use_comma) - value_str += ","; - else - value_str += ";"; - } - else - first = false; - - if (use_comma) - value_str += iter.value(); - else { - value_str += "\""; - value_str += escape_string_cstyle(iter.value()); - value_str += "\""; - } - } - else { - //should not happen - BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": parse "<type) + { + case coStrings: + escape_string_type = true; + single_sep = ';'; + break; + case coPointsGroups: + single_sep = '#'; + break; + default: break; } } + + // BBS: we only support 2 depth array + valid = parse_str_arr(it, single_sep, array_sep,escape_string_type, value_str); + if (!valid) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": parse " << file << " error, invalid json array for " << it.key(); + break; + } if (valid) this->set_deserialize(opt_key, value_str, substitution_context); } @@ -1409,14 +1447,14 @@ void ConfigBase::save_to_json(const std::string &file, const std::string &name, j[opt_key] = opt->serialize(); } else { - const ConfigOptionVectorBase *vec = static_cast(opt); + const ConfigOptionVectorBase* vec = static_cast(opt); //if (!vec->empty()) std::vector string_values = vec->vserialize(); /*for (int i = 0; i < string_values.size(); i++) { - std::string string_value = escape_string_cstyle(string_values[i]); - j[opt_key][i] = string_value; + std::string string_value = escape_string_cstyle(string_values[i]); + j[opt_key][i] = string_value; }*/ json j_array(string_values); diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index 4ab8484be..24e7c26c3 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -196,6 +196,7 @@ enum ConfigOptionType { coEnum = 9, // BBS: vector of enums coEnums = coEnum + coVectorType, + coPointsGroups = 10 + coVectorType }; enum ConfigOptionMode { @@ -1547,6 +1548,106 @@ private: template void serialize(Archive &ar) { ar(cereal::base_class>(this)); } }; +class ConfigOptionPointsGroups :public ConfigOptionVector +{ +public: + ConfigOptionPointsGroups() :ConfigOptionVector() {} + explicit ConfigOptionPointsGroups(std::initializer_list il) :ConfigOptionVector(std::move(il)) {} + explicit ConfigOptionPointsGroups(const std::vector& values) :ConfigOptionVector(values) {} + + static ConfigOptionType static_type() { return coPointsGroups; } + ConfigOptionType type()const override { return static_type(); } + ConfigOption* clone()const override { return new ConfigOptionPointsGroups(*this); } + ConfigOptionPointsGroups& operator=(const ConfigOption* opt) { this->set(opt); return *this; } + bool operator == (const ConfigOptionPointsGroups& rhs)const throw() { return this->values == rhs.values; } + bool operator == (const ConfigOption& rhs) const override { + if (rhs.type() != this->type()) + throw ConfigurationError("ConfigOptionPointsGroupsTempl: Comparing incompatible types"); + assert(dynamic_cast*>(&rhs)); + + return this->values == static_cast*>(&rhs)->values; + } + bool nullable() const override { return false; } + bool is_nil(size_t) const override { return false; } + + std::string serialize()const override + { + std::ostringstream ss; + for (auto iter = this->values.begin(); iter != this->values.end(); ++iter) { + if (iter != this->values.begin()) + ss << "#"; + serialize_single_value(ss, *iter); + } + + return ss.str(); + } + + std::vector vserialize()const override + { + std::vectorret; + for (const auto& points : this->values) { + std::ostringstream ss; + serialize_single_value(ss, points); + ret.emplace_back(ss.str()); + } + return ret; + } + + bool deserialize(const std::string& str, bool append = false) override + { + if (!append) + this->values.clear(); + std::istringstream is(str); + std::string group_str; + while (std::getline(is, group_str, '#')) { + Vec2ds group; + std::istringstream iss(group_str); + std::string point_str; + while (std::getline(iss, point_str, ',')) { + Vec2d point(Vec2d::Zero()); + std::istringstream iss(point_str); + std::string coord_str; + if (std::getline(iss, coord_str, 'x')) { + std::istringstream(coord_str) >> point(0); + if (std::getline(iss, coord_str, 'x')) { + std::istringstream(coord_str) >> point(1); + } + } + group.push_back(point); + } + this->values.emplace_back(std::move(group)); + } + return true; + } + std::vector vserialize_single(int idx) const + { + std::vectorret; + assert(idx < this->size()); + for (auto iter = values[idx].begin(); iter != values[idx].end(); ++iter) { + std::ostringstream ss; + ss << (*iter)(0); + ss << "x"; + ss << (*iter)(1); + ret.emplace_back(ss.str()); + } + return ret; + } +protected: + void serialize_single_value(std::ostringstream& ss, const Vec2ds& v) const { + for (auto iter = v.begin(); iter != v.end(); ++iter) { + if (iter - v.begin() != 0) + ss << ","; + ss << (*iter)(0); + ss << "x"; + ss << (*iter)(1); + } + } +private: + friend class cereal::access; + template void serialize(Archive& ar) { ar(cereal::base_class(this)); } +}; + + class ConfigOptionBool : public ConfigOptionSingle { public: diff --git a/src/libslic3r/Point.hpp b/src/libslic3r/Point.hpp index 3082dd033..61b99aefa 100644 --- a/src/libslic3r/Point.hpp +++ b/src/libslic3r/Point.hpp @@ -610,6 +610,21 @@ inline Point align_to_grid(Point coord, Point spacing, Point base) } } // namespace Slic3r +// requseted by ConfigOptionPointsGroups +namespace std { + template<> + struct hash { + size_t operator()(const Slic3r::Vec2ds& vec) { + size_t seed = 0; + for (const auto& element : vec) { + seed ^= std::hash()(element[0]) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + seed ^= std::hash()(element[1]) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + } + return seed; + } + }; +} + // start Boost #include #include diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 0018b8d03..181f69e0e 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -523,7 +523,6 @@ bool Preset::save(DynamicPrintConfig* parent_config) if (parent_config) { DynamicPrintConfig temp_config; std::vector dirty_options = config.diff(*parent_config); - std::string extruder_id_name, extruder_variant_name; std::set *key_set1 = nullptr, *key_set2 = nullptr; Preset::get_extruder_names_and_keysets(type, extruder_id_name, extruder_variant_name, &key_set1, &key_set2); @@ -942,7 +941,7 @@ static std::vector s_Preset_machine_limits_options { static std::vector s_Preset_printer_options { "printer_technology", - "printable_area", "bed_exclude_area","bed_custom_texture", "bed_custom_model", "gcode_flavor", + "printable_area", "extruder_printable_area", "bed_exclude_area","bed_custom_texture", "bed_custom_model", "gcode_flavor", "single_extruder_multi_material", "machine_start_gcode", "machine_end_gcode","printing_by_object_gcode","before_layer_change_gcode", "layer_change_gcode", "time_lapse_gcode", "change_filament_gcode", "printer_model", "printer_variant", "printer_extruder_id", "printer_extruder_variant", "extruder_variant_list", "default_nozzle_volume_type", "printable_height", "extruder_clearance_radius", "extruder_clearance_max_radius","extruder_clearance_height_to_lid", "extruder_clearance_height_to_rod", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 816f49098..1b6965c06 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -489,6 +489,12 @@ void PrintConfigDef::init_common_params() def->gui_type = ConfigOptionDef::GUIType::one_string; def->set_default_value(new ConfigOptionPoints{ Vec2d(0, 0), Vec2d(200, 0), Vec2d(200, 200), Vec2d(0, 200) }); + def = this->add("extruder_printable_area", coPointsGroups); + def->label = L("Extruder printable area"); + def->mode = comAdvanced; + def->gui_type = ConfigOptionDef::GUIType::one_string; + def->set_default_value(new ConfigOptionPointsGroups{ { Vec2d(0, 0), Vec2d(200, 0), Vec2d(200, 200), Vec2d(0, 200) } }); + //BBS: add "bed_exclude_area" def = this->add("bed_exclude_area", coPoints); def->label = L("Bed exclude area"); @@ -5187,6 +5193,7 @@ std::set printer_extruder_options = { "extruder_type", "nozzle_diameter", "default_nozzle_volume_type", + "extruder_printable_area", "min_layer_height", "max_layer_height" }; diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 4d22efb07..637347e24 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1054,6 +1054,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( ((ConfigOptionBool, reduce_crossing_wall)) ((ConfigOptionFloatOrPercent, max_travel_detour_distance)) ((ConfigOptionPoints, printable_area)) + ((ConfigOptionPointsGroups, extruder_printable_area)) ((ConfigOptionFloats, extruder_change_length)) //BBS: add bed_exclude_area ((ConfigOptionPoints, bed_exclude_area))