diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index 24e7c26c3..f3c09033c 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -196,7 +196,8 @@ enum ConfigOptionType { coEnum = 9, // BBS: vector of enums coEnums = coEnum + coVectorType, - coPointsGroups = 10 + coVectorType + coPointsGroups = 10 + coVectorType, + coIntsGroups = 11 + coVectorType }; enum ConfigOptionMode { @@ -1647,6 +1648,110 @@ private: template void serialize(Archive& ar) { ar(cereal::base_class(this)); } }; +class ConfigOptionIntsGroups : public ConfigOptionVector> +{ +public: + ConfigOptionIntsGroups() : ConfigOptionVector>() {} + explicit ConfigOptionIntsGroups(std::initializer_list> il) : ConfigOptionVector>(std::move(il)) {} + explicit ConfigOptionIntsGroups(const std::vector> &values) : ConfigOptionVector>(values) {} + + static ConfigOptionType static_type() { return coIntsGroups; } + ConfigOptionType type() const override { return static_type(); } + ConfigOption *clone() const override { return new ConfigOptionIntsGroups(*this); } + ConfigOptionIntsGroups &operator=(const ConfigOption *opt) + { + this->set(opt); + return *this; + } + bool operator==(const ConfigOptionIntsGroups &rhs) const throw() { return this->values == rhs.values; } + bool operator==(const ConfigOption &rhs) const override + { + if (rhs.type() != this->type()) throw ConfigurationError("ConfigConfigOptionIntsGroups: Comparing incompatible types"); + assert(dynamic_cast> *>(&rhs)); + + return this->values == static_cast> *>(&rhs)->values; + } + bool operator<(const ConfigOptionIntsGroups &rhs) const throw() { + bool is_lower = true; + for (size_t i = 0; i < values.size(); ++i) { + if (this->values[i] == rhs.values[i]) + continue; + + return (this->values[i] < rhs.values[i]); + } + return is_lower; + } + 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::vector ret; + for (const auto &value : this->values) { + std::ostringstream ss; + serialize_single_value(ss, value); + 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, '#')) { + std::vector group_values; + std::istringstream iss(group_str); + std::string value_str; + while (std::getline(iss, value_str, ',')) { + int value; + std::istringstream(value_str) >> value; + group_values.push_back(value); + } + this->values.emplace_back(std::move(group_values)); + } + return true; + } + std::vector vserialize_single(int idx) const + { + std::vector ret; + assert(idx < this->size()); + for (auto iter = values[idx].begin(); iter != values[idx].end(); ++iter) { + std::ostringstream ss; + ss << (*iter); + ret.emplace_back(ss.str()); + } + return ret; + } + +protected: + void serialize_single_value(std::ostringstream &ss, const std::vector &v) const + { + for (auto iter = v.begin(); iter != v.end(); ++iter) { + if (iter - v.begin() != 0) + ss << ","; + ss << (*iter); + } + } + +private: + friend class cereal::access; + template void serialize(Archive &ar) { ar(cereal::base_class(this)); } +}; + class ConfigOptionBool : public ConfigOptionSingle { @@ -2101,6 +2206,7 @@ public: case coEnum: { auto opt = new ConfigOptionEnumGeneric(this->enum_keys_map); archive(*opt); return opt; } // BBS case coEnums: { auto opt = new ConfigOptionEnumsGeneric(this->enum_keys_map); archive(*opt); return opt; } + case coIntsGroups: { auto opt = new ConfigOptionIntsGroups(); archive(*opt); return opt; } default: throw ConfigurationError(std::string("ConfigOptionDef::load_option_from_archive(): Unknown option type for option ") + this->opt_key); } } @@ -2136,6 +2242,7 @@ public: case coEnum: archive(*static_cast(opt)); break; // BBS case coEnums: archive(*static_cast(opt)); break; + case coIntsGroups: archive(*static_cast(opt)); break; default: throw ConfigurationError(std::string("ConfigOptionDef::save_option_to_archive(): Unknown option type for option ") + this->opt_key); } } diff --git a/src/libslic3r/Format/bbs_3mf.cpp b/src/libslic3r/Format/bbs_3mf.cpp index 0b94319cf..0fb153a82 100644 --- a/src/libslic3r/Format/bbs_3mf.cpp +++ b/src/libslic3r/Format/bbs_3mf.cpp @@ -298,6 +298,7 @@ static constexpr const char* OTHER_LAYERS_PRINT_SEQUENCE_NUMS_ATTR = "other_laye static constexpr const char* SPIRAL_VASE_MODE = "spiral_mode"; static constexpr const char* FILAMENT_MAP_MODE_ATTR = "filament_map_mode"; static constexpr const char* FILAMENT_MAP_ATTR = "filament_maps"; +static constexpr const char* UNPRINTABLE_FILAMENT_MAP_ATTR = "unprintable_filament_maps"; static constexpr const char* LIMIT_FILAMENT_MAP_ATTR = "limit_filament_maps"; static constexpr const char* GCODE_FILE_ATTR = "gcode_file"; static constexpr const char* THUMBNAIL_FILE_ATTR = "thumbnail_file"; @@ -4089,6 +4090,24 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) return results; }; + auto get_vector_array_from_string = [get_vector_from_string](const std::string &str) -> std::vector> { + std::vector sub_strs; + size_t pos = 0; + size_t found = 0; + while ((found = str.find('#', pos)) != std::string::npos) { + std::string sub_str = str.substr(pos, found - pos); + sub_strs.push_back(sub_str); + pos = found + 1; + } + + std::vector> results; + for (std::string sub_str : sub_strs) { + results.emplace_back(get_vector_from_string(sub_str)); + } + + return results; + }; + if ((m_curr_plater == nullptr)&&!m_parsing_slice_info) { IdToMetadataMap::iterator object = m_objects_metadata.find(m_curr_config.object_id); @@ -4153,6 +4172,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) m_curr_plater->config.set_key_value("filament_map", new ConfigOptionInts(get_vector_from_string(value))); } + else if (key == UNPRINTABLE_FILAMENT_MAP_ATTR) + { + m_curr_plater->config.set_key_value("unprintable_filament_map", new ConfigOptionIntsGroups(get_vector_array_from_string(value))); + } else if (key == GCODE_FILE_ATTR) { m_curr_plater->gcode_file = value; @@ -7571,6 +7594,23 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) stream << "\"/>\n"; } + ConfigOptionIntsGroups *unprintable_filament_maps_opt = plate_data->config.option("unprintable_filament_map"); + if (unprintable_filament_maps_opt != nullptr) { + stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << UNPRINTABLE_FILAMENT_MAP_ATTR << "\" " << VALUE_ATTR << "=\""; + const std::vector> &values = unprintable_filament_maps_opt->values; + for (size_t i = 0; i < values.size(); ++i) { + if (i > 0) + stream << "#"; + std::vector index_values = values[i]; + for (int j = 0; j < index_values.size(); ++j) { + if (j > 0) + stream << " "; + stream << index_values[j]; + } + } + stream << "\"/>\n"; + } + if (save_gcode) stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << GCODE_FILE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << xml_escape(plate_data->gcode_file) << "\"/>\n"; if (!plate_data->gcode_file.empty()) { diff --git a/src/libslic3r/Point.hpp b/src/libslic3r/Point.hpp index 61b99aefa..5e158ddef 100644 --- a/src/libslic3r/Point.hpp +++ b/src/libslic3r/Point.hpp @@ -623,6 +623,19 @@ namespace std { return seed; } }; + + template<> + struct hash> + { + size_t operator()(const std::vector &vec) + { + size_t seed = 0; + for (const auto &element : vec) { + seed ^= std::hash()(element) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + } + return seed; + } + }; } // start Boost diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index e66caf28f..e3208e963 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -260,6 +260,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n || opt_key == "extruder_ams_count" || opt_key == "filament_map_mode" || opt_key == "filament_map" + || opt_key == "unprintable_filament_map" //|| opt_key == "wipe_tower_bridging" || opt_key == "wipe_tower_no_sparse_layers" || opt_key == "flush_volumes_matrix" @@ -2375,6 +2376,11 @@ void Print::update_filament_maps_to_config(std::vector f_maps) m_has_auto_filament_map_result = true; } +const std::vector>& Print::get_unprintable_filament_ids() const +{ + return m_config.unprintable_filament_map.values; +} + std::vector Print::get_filament_maps() const { return m_config.filament_map.values; diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 4228f7528..9e802d573 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -832,8 +832,7 @@ public: void set_extruder_filament_info(const std::vector>& filament_info) { m_extruder_filament_info = filament_info; } // 1 based ids - const std::vector>& get_unprintable_filament_ids() const { return m_unprintable_filament_ids; } - void set_unprintable_filament_ids(const std::vector> &filament_ids) { m_unprintable_filament_ids = filament_ids; } + const std::vector> &get_unprintable_filament_ids() const; std::vector get_printable_area(); std::vector> get_extruder_printable_area(); diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 7443093af..ad4ceb282 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1611,6 +1611,12 @@ void PrintConfigDef::init_fff_params() def->mode = comDevelop; def->set_default_value(new ConfigOptionInts{1}); + def = this->add("unprintable_filament_map", coIntsGroups); + def->label = L("Unprintable filament map to extruder"); + def->tooltip = L("Unprintable filament map to extruder"); + def->mode = comDevelop; + def->set_default_value(new ConfigOptionIntsGroups{}); + def = this->add("filament_map_mode", coEnum); def->label = L("filament mapping mode"); def->tooltip = ("filament mapping mode used as plate param"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 8539e1374..7439c5d90 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -982,6 +982,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionInts, required_nozzle_HRC)) ((ConfigOptionEnum, filament_map_mode)) ((ConfigOptionInts, filament_map)) + ((ConfigOptionIntsGroups, unprintable_filament_map)) //((ConfigOptionInts, filament_extruder_id)) ((ConfigOptionStrings, filament_extruder_variant)) ((ConfigOptionFloat, machine_load_filament_time)) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 7bc961f66..a7e6df80a 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -1720,7 +1720,7 @@ bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, Mo BuildVolume plate_build_volume(pp_bed_shape, build_volume.printable_height(), build_volume.extruder_areas()); const std::vector& exclude_areas = curr_plate->get_exclude_areas(); - curr_plate->clear_unprintable_filament_ids(); + std::vector> unprintable_filament_ids; for (GLVolume* volume : this->volumes) { if (! volume->is_modifier && (volume->shader_outside_printer_detection_enabled || (! volume->is_wipe_tower && volume->composite_id.volume_id >= 0))) { @@ -1738,13 +1738,14 @@ bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, Mo std::vector inside_extruders; state = plate_build_volume.check_volume_bbox_state_with_extruder_areas(bb, inside_extruders); if (state == BuildVolume::ObjectState::Limited) { + unprintable_filament_ids.resize(inside_extruders.size()); const ModelObjectPtrs &model_objects = model.objects; ModelObject *model_object = model_objects[volume->object_idx()]; ModelVolume *model_volume = model_object->volumes[volume->volume_idx()]; for (size_t i = 0; i < inside_extruders.size(); ++i) { if (!inside_extruders[i]) { std::vector extruders = model_volume->get_extruders(); - curr_plate->append_unprintable_filament_ids(i, extruders); + unprintable_filament_ids[i].insert(extruders.begin(), extruders.end()); } } } @@ -1822,6 +1823,13 @@ bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, Mo } } + std::vector> unprintable_filament_vec; + for (const std::set& filamnt_ids : unprintable_filament_ids) { + unprintable_filament_vec.emplace_back(std::vector(filamnt_ids.begin(), filamnt_ids.end())); + } + + curr_plate->set_unprintable_filament_ids(unprintable_filament_vec); + /*for (GLVolume* volume : this->volumes) { if (! volume->is_modifier && (volume->shader_outside_printer_detection_enabled || (! volume->is_wipe_tower && volume->composite_id.volume_id >= 0))) diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index b52de083b..6a3017f00 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -2518,7 +2518,6 @@ void PartPlate::update_slice_context(BackgroundSlicingProcess & process) process.select_technology(this->printer_technology); process.set_current_plate(this); m_print->set_status_callback(statuscb); - m_print->set_unprintable_filament_ids(m_unprintable_filament_ids); process.switch_print_preprocess(); return; @@ -2878,21 +2877,24 @@ std::vector PartPlate::get_filament_maps() return filament_maps; } -void PartPlate::append_unprintable_filament_ids(int extruder_id, const std::vector &filament_ids) -{ - if (extruder_id > m_unprintable_filament_ids.size()) { - m_unprintable_filament_ids.resize(extruder_id + 1); - } - m_unprintable_filament_ids[extruder_id].insert(m_unprintable_filament_ids[extruder_id].end(), filament_ids.begin(), filament_ids.end()); -} - void PartPlate::set_filament_maps(const std::vector& f_maps) { std::vector& filament_maps = m_config.option("filament_map", true)->values; - filament_maps = f_maps; } +const std::vector>& PartPlate::get_unprintable_filament_ids() +{ + std::vector> & unprintabel_filament_maps = m_config.option("unprintable_filament_map", true)->values; + return unprintabel_filament_maps; +} + +void PartPlate::set_unprintable_filament_ids(const std::vector> &filament_ids) +{ + std::vector> &unprintabel_filament_maps = m_config.option("unprintable_filament_map", true)->values; + unprintabel_filament_maps = filament_ids; +} + void PartPlate::on_extruder_count_changed(int extruder_count) { std::vector& filament_maps = m_config.option("filament_map", true)->values; diff --git a/src/slic3r/GUI/PartPlate.hpp b/src/slic3r/GUI/PartPlate.hpp index 397797a94..b37234504 100644 --- a/src/slic3r/GUI/PartPlate.hpp +++ b/src/slic3r/GUI/PartPlate.hpp @@ -111,9 +111,6 @@ private: std::vector slice_filaments_info; int m_print_index; - // filament ids of extruder - std::vector> m_unprintable_filament_ids; - std::string m_tmp_gcode_path; //use a temp path to store the gcode std::string m_temp_config_3mf_path; //use a temp path to store the config 3mf std::string m_gcode_path_from_3mf; //use a path to store the gcode loaded from 3mf @@ -493,10 +490,8 @@ public: std::vector get_filament_maps(); void set_filament_maps(const std::vector& f_maps); - const std::vector> &get_unprintable_filament_ids() const { return m_unprintable_filament_ids; } - void set_unprintable_filament_ids(const std::vector> &filament_ids) { m_unprintable_filament_ids = filament_ids; } - void clear_unprintable_filament_ids() { m_unprintable_filament_ids.clear(); } - void append_unprintable_filament_ids(int extruder_id, const std::vector &filament_ids); + const std::vector> &get_unprintable_filament_ids(); + void set_unprintable_filament_ids(const std::vector> &filament_ids); void on_extruder_count_changed(int extruder_count); void set_filament_count(int filament_count);