diff --git a/src/BambuStudio.cpp b/src/BambuStudio.cpp index 02847d50a..47f4eebf1 100644 --- a/src/BambuStudio.cpp +++ b/src/BambuStudio.cpp @@ -3142,14 +3142,8 @@ int CLI::run(int argc, char **argv) //computing ConfigOptionBools* filament_is_support = m_print_config.option("filament_is_support", true); - std::vector& flush_vol_matrix = m_print_config.option("flush_volumes_matrix", true)->values; - //std::vector& flush_vol_vector = m_print_config.option("flush_volumes_vector", true)->values; - flush_vol_matrix.resize(project_filament_count*project_filament_count, 0.f); - //flush_vol_vector.resize(project_filament_count); - //set multiplier to 1? - m_print_config.option("flush_multiplier", true)->set(new ConfigOptionFloat(1.f)); - const std::vector& min_flush_volumes = Slic3r::GUI::get_min_flush_volumes(m_print_config); + const std::vector &min_flush_volumes = Slic3r::GUI::get_min_flush_volumes(m_print_config, 0); if (filament_is_support->size() != project_filament_count) { @@ -3165,40 +3159,50 @@ int CLI::run(int argc, char **argv) BOOST_LOG_TRIVIAL(info) << boost::format("filament_is_support: %1%") % filament_is_support->serialize(); BOOST_LOG_TRIVIAL(info) << boost::format("flush_volumes_matrix before computing: %1%") % m_print_config.option("flush_volumes_matrix")->serialize(); } - for (int from_idx = 0; from_idx < project_filament_count; from_idx++) { - const std::string& from_color = project_filament_colors[from_idx]; - unsigned char from_rgb[4] = {}; - Slic3r::GUI::BitmapCache::parse_color4(from_color, from_rgb); - bool is_from_support = filament_is_support->get_at(from_idx); - for (int to_idx = 0; to_idx < project_filament_count; to_idx++) { - bool is_to_support = filament_is_support->get_at(to_idx); - if (from_idx == to_idx) { - flush_vol_matrix[project_filament_count*from_idx + to_idx] = 0.f; - } - else { - int flushing_volume = 0; - if (is_to_support) { - flushing_volume = Slic3r::g_flush_volume_to_support; - } - else { - const std::string& to_color = project_filament_colors[to_idx]; - unsigned char to_rgb[4] = {}; - Slic3r::GUI::BitmapCache::parse_color4(to_color, to_rgb); - //BOOST_LOG_TRIVIAL(info) << boost::format("src_idx %1%, src color %2%, dst idex %3%, dst color %4%")%from_idx %from_color %to_idx %to_color; - //BOOST_LOG_TRIVIAL(info) << boost::format("src_rgba {%1%,%2%,%3%,%4%} dst_rgba {%5%,%6%,%7%,%8%}")%(unsigned int)(from_rgb[0]) %(unsigned int)(from_rgb[1]) %(unsigned int)(from_rgb[2]) %(unsigned int)(from_rgb[3]) - // %(unsigned int)(to_rgb[0]) %(unsigned int)(to_rgb[1]) %(unsigned int)(to_rgb[2]) %(unsigned int)(to_rgb[3]); - Slic3r::FlushVolCalculator calculator(min_flush_volumes[from_idx], Slic3r::g_max_flush_volume); + size_t nozzle_nums = 1; + auto opt_nozzle_diameters = m_print_config.option("nozzle_diameter"); + if (opt_nozzle_diameters != nullptr) { + nozzle_nums = opt_nozzle_diameters->values.size(); + } - flushing_volume = calculator.calc_flush_vol(from_rgb[3], from_rgb[0], from_rgb[1], from_rgb[2], to_rgb[3], to_rgb[0], to_rgb[1], to_rgb[2]); - if (is_from_support) { - flushing_volume = std::max(Slic3r::g_min_flush_volume_from_support, flushing_volume); + std::vector &flush_vol_matrix = m_print_config.option("flush_volumes_matrix", true)->values; + flush_vol_matrix.resize(project_filament_count * project_filament_count * nozzle_nums, 0.f); + + // set multiplier to 1? + std::vector& flush_multipliers = m_print_config.option("flush_multiplier", true)->values; + flush_multipliers.resize(nozzle_nums, 1.f); + + for (size_t nozzle_id = 0; nozzle_id < nozzle_nums; ++nozzle_id) { + std::vector flush_vol_mtx = get_flush_volumes_matrix(flush_vol_matrix, nozzle_id, nozzle_nums); + for (int from_idx = 0; from_idx < project_filament_count; from_idx++) { + const std::string &from_color = project_filament_colors[from_idx]; + unsigned char from_rgb[4] = {}; + Slic3r::GUI::BitmapCache::parse_color4(from_color, from_rgb); + bool is_from_support = filament_is_support->get_at(from_idx); + for (int to_idx = 0; to_idx < project_filament_count; to_idx++) { + bool is_to_support = filament_is_support->get_at(to_idx); + if (from_idx == to_idx) { + flush_vol_mtx[project_filament_count * from_idx + to_idx] = 0.f; + } else { + int flushing_volume = 0; + if (is_to_support) { + flushing_volume = Slic3r::g_flush_volume_to_support; + } else { + const std::string &to_color = project_filament_colors[to_idx]; + unsigned char to_rgb[4] = {}; + Slic3r::GUI::BitmapCache::parse_color4(to_color, to_rgb); + + Slic3r::FlushVolCalculator calculator(min_flush_volumes[from_idx], Slic3r::g_max_flush_volume); + + flushing_volume = calculator.calc_flush_vol(from_rgb[3], from_rgb[0], from_rgb[1], from_rgb[2], to_rgb[3], to_rgb[0], to_rgb[1], to_rgb[2]); + if (is_from_support) { flushing_volume = std::max(Slic3r::g_min_flush_volume_from_support, flushing_volume); } } - } - flush_vol_matrix[project_filament_count * from_idx + to_idx] = flushing_volume; - //flushing_volume = int(flushing_volume * get_flush_multiplier()); + flush_vol_mtx[project_filament_count * from_idx + to_idx] = flushing_volume; + } } + set_flush_volumes_matrix(flush_vol_matrix, flush_vol_mtx, nozzle_id, nozzle_nums); } } BOOST_LOG_TRIVIAL(info) << boost::format("flush_volumes_matrix after computed: %1%")%m_print_config.option("flush_volumes_matrix")->serialize(); diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index c0daca1b1..cb7eb81c4 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -3195,7 +3195,7 @@ GCode::LayerResult GCode::process_layer( // BBS: get next extruder according to flush and soluble auto get_next_extruder = [&](int current_extruder,const std::vector&extruders) { - std::vector flush_matrix(cast(m_config.flush_volumes_matrix.values)); + std::vector flush_matrix(cast(get_flush_volumes_matrix(m_config.flush_volumes_matrix.values, 0, m_config.nozzle_diameter.values.size()))); const unsigned int number_of_extruders = (unsigned int)(sqrt(flush_matrix.size()) + EPSILON); // Extract purging volumes for each extruder pair: std::vector> wipe_volumes; @@ -5370,8 +5370,8 @@ std::string GCode::set_extruder(unsigned int filament_id, double print_z, bool b //BBS: add handling for filament change in start gcode int previous_filament_id = -1; if (m_writer.extruder() != nullptr || m_start_gcode_filament != -1) { - std::vector flush_matrix(cast(m_config.flush_volumes_matrix.values)); - const unsigned int number_of_extruders = (unsigned int)(sqrt(flush_matrix.size()) + EPSILON); + std::vector flush_matrix(cast(get_flush_volumes_matrix(m_config.flush_volumes_matrix.values, 0, m_config.nozzle_diameter.values.size()))); + const unsigned int number_of_extruders = (unsigned int) (m_config.filament_colour.values.size()); // if is multi_extruder only use the fist extruder matrix if (m_writer.extruder() != nullptr) assert(m_writer.extruder()->id() < number_of_extruders); else @@ -5384,7 +5384,7 @@ std::string GCode::set_extruder(unsigned int filament_id, double print_z, bool b old_retract_length_toolchange = m_config.retract_length_toolchange.get_at(previous_extruder_id); old_filament_temp = this->on_first_layer()? m_config.nozzle_temperature_initial_layer.get_at(previous_filament_id) : m_config.nozzle_temperature.get_at(previous_filament_id); wipe_volume = flush_matrix[previous_filament_id * number_of_extruders + filament_id]; - wipe_volume *= m_config.flush_multiplier; + wipe_volume *= m_config.flush_multiplier.get_at(0); // if is multi_extruder only use the fist extruder matrix old_filament_e_feedrate = (int) (60.0 * m_config.filament_max_volumetric_speed.get_at(previous_filament_id) / filament_area); old_filament_e_feedrate = old_filament_e_feedrate == 0 ? 100 : old_filament_e_feedrate; //BBS: must clean m_start_gcode_filament diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index ad473884a..b1c77d10f 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -829,6 +829,12 @@ void ToolOrdering::collect_extruder_statistics(bool prime_multi_material) void ToolOrdering::reorder_extruders_for_minimum_flush_volume() { + bool is_multi_extruder = false; + if (is_multi_extruder) { + reorder_extruders_for_minimum_flush_volume_multi_extruder(); + return; + } + const PrintConfig *print_config = m_print_config_ptr; if (!print_config && m_print_object_ptr) { print_config = &(m_print_object_ptr->print()->config()); @@ -922,6 +928,132 @@ void ToolOrdering::reorder_extruders_for_minimum_flush_volume() } } +void ToolOrdering::reorder_extruders_for_minimum_flush_volume_multi_extruder() +{ + const PrintConfig *print_config = m_print_config_ptr; + if (!print_config && m_print_object_ptr) { + print_config = &(m_print_object_ptr->print()->config()); + } + + if (!print_config || m_layer_tools.empty()) + return; + + const unsigned int number_of_extruders = (unsigned int) (print_config->filament_colour.values.size() + EPSILON); + // todo multi_extruders: get filament_maps + std::vector filament_maps; + for (int i = 0; i <= number_of_extruders / 2; ++i) { + filament_maps.push_back(1); + } + for (int i = number_of_extruders / 2 + 1; i < number_of_extruders; ++i) { + filament_maps.push_back(2); + } + + using FlushMatrix = std::vector>; + size_t nozzle_nums = print_config->nozzle_diameter.values.size(); + std::vector nozzle_flush_mtx; + for (size_t nozzle_id = 0; nozzle_id < nozzle_nums; ++nozzle_id) { + std::vector flush_matrix(cast(get_flush_volumes_matrix(print_config->flush_volumes_matrix.values, nozzle_id, nozzle_nums))); + std::vector> wipe_volumes; + for (unsigned int i = 0; i < number_of_extruders; ++i) + wipe_volumes.push_back(std::vector(flush_matrix.begin() + i * number_of_extruders, flush_matrix.begin() + (i + 1) * number_of_extruders)); + + nozzle_flush_mtx.emplace_back(wipe_volumes); + } + + auto extruders_to_hash_key = [](const std::vector &extruders, std::optional initial_extruder_id) -> uint32_t { + uint32_t hash_key = 0; + // high 16 bit define initial extruder ,low 16 bit define extruder set + if (initial_extruder_id) hash_key |= (1 << (16 + *initial_extruder_id)); + for (auto item : extruders) hash_key |= (1 << item); + return hash_key; + }; + + std::vector other_layers_seqs; + const ConfigOptionInts * other_layers_print_sequence_op = print_config->option("other_layers_print_sequence"); + const ConfigOptionInt * other_layers_print_sequence_nums_op = print_config->option("other_layers_print_sequence_nums"); + if (other_layers_print_sequence_op && other_layers_print_sequence_nums_op) { + const std::vector &print_sequence = other_layers_print_sequence_op->values; + int sequence_nums = other_layers_print_sequence_nums_op->value; + other_layers_seqs = get_other_layers_print_sequence(sequence_nums, print_sequence); + } + + // other_layers_seq: the layer_idx and extruder_idx are base on 1 + auto get_custom_seq = [&other_layers_seqs](int layer_idx, std::vector &out_seq) -> bool { + for (size_t idx = other_layers_seqs.size() - 1; idx != size_t(-1); --idx) { + const auto &other_layers_seq = other_layers_seqs[idx]; + if (layer_idx + 1 >= other_layers_seq.first.first && layer_idx + 1 <= other_layers_seq.first.second) { + out_seq = other_layers_seq.second; + return true; + } + } + return false; + }; + + std::optional current_extruder_id; + + std::vector> nozzle_to_cur_filaments; + + for (int i = 0; i < m_layer_tools.size(); ++i) { + LayerTools < = m_layer_tools[i]; + if (lt.extruders.empty()) + continue; + + std::vector custom_extruder_seq; + if (get_custom_seq(i, custom_extruder_seq) && !custom_extruder_seq.empty()) { + std::vector unsign_custom_extruder_seq; + for (int extruder : custom_extruder_seq) { + unsigned int unsign_extruder = static_cast(extruder) - 1; + auto it = std::find(lt.extruders.begin(), lt.extruders.end(), unsign_extruder); + if (it != lt.extruders.end()) { + unsign_custom_extruder_seq.emplace_back(unsign_extruder); + nozzle_to_cur_filaments[filament_maps[unsign_extruder]] = unsign_extruder; + } + } + assert(lt.extruders.size() == unsign_custom_extruder_seq.size()); + lt.extruders = unsign_custom_extruder_seq; + current_extruder_id = lt.extruders.back(); + continue; + } + + // The algorithm complexity is O(n2*2^n) + if (i != 0) { + std::vector> nozzle_filaments; + nozzle_filaments.resize(nozzle_nums); + + for (unsigned int filament_id : lt.extruders) { + nozzle_filaments[filament_maps[filament_id] - 1].emplace_back(filament_id); + } + + for (size_t nozzle_id = 0; nozzle_id < nozzle_nums; ++nozzle_id) + { + auto hash_key = extruders_to_hash_key(nozzle_filaments[nozzle_id], nozzle_to_cur_filaments[nozzle_id]); + auto iter = m_tool_order_cache.find(hash_key); + if (iter == m_tool_order_cache.end()) { + nozzle_filaments[nozzle_id] = get_extruders_order(nozzle_flush_mtx[nozzle_id], nozzle_filaments[nozzle_id], nozzle_to_cur_filaments[nozzle_id]); + std::vector hash_val; + hash_val.reserve(nozzle_filaments[nozzle_id].size()); + for (auto item : nozzle_filaments[nozzle_id]) + hash_val.emplace_back(static_cast(item)); + m_tool_order_cache[hash_key] = hash_val; + } else { + std::vector extruder_order; + extruder_order.reserve(iter->second.size()); + for (auto item : iter->second) + extruder_order.emplace_back(static_cast(item)); + nozzle_filaments[nozzle_id] = std::move(extruder_order); + } + nozzle_to_cur_filaments[nozzle_id] = nozzle_filaments[nozzle_id].back(); + } + + lt.extruders.clear(); + for (size_t nozzle_id = 0; nozzle_id < nozzle_nums; ++nozzle_id) { + lt.extruders.insert(lt.extruders.end(), nozzle_filaments[nozzle_id].begin(), nozzle_filaments[nozzle_id].end()); + } + } + current_extruder_id = lt.extruders.back(); + } +} + // Layers are marked for infinite skirt aka draft shield. Not all the layers have to be printed. void ToolOrdering::mark_skirt_layers(const PrintConfig &config, coordf_t max_layer_height) { diff --git a/src/libslic3r/GCode/ToolOrdering.hpp b/src/libslic3r/GCode/ToolOrdering.hpp index 8c0ecdd4c..ae4a329ea 100644 --- a/src/libslic3r/GCode/ToolOrdering.hpp +++ b/src/libslic3r/GCode/ToolOrdering.hpp @@ -197,6 +197,7 @@ private: void mark_skirt_layers(const PrintConfig &config, coordf_t max_layer_height); void collect_extruder_statistics(bool prime_multi_material); void reorder_extruders_for_minimum_flush_volume(); + void reorder_extruders_for_minimum_flush_volume_multi_extruder(); // BBS std::vector generate_first_layer_tool_order(const Print& print); diff --git a/src/libslic3r/PlaceholderParser.cpp b/src/libslic3r/PlaceholderParser.cpp index ff88122db..d8cf2d5b9 100644 --- a/src/libslic3r/PlaceholderParser.cpp +++ b/src/libslic3r/PlaceholderParser.cpp @@ -831,14 +831,14 @@ namespace client // Not a percent, just return the value. output.set_d(opt_floats->get_at(index).value); } else { - // Resolve dependencies using the "ratio_over" link to a parent value. - const ConfigOptionDef *opt_def = print_config_def.get(opt_key); - assert(opt_def != nullptr); - assert(opt_def->type() == coFloatsOrPercents); FloatOrPercent opt_value = opt_floats->get_at(index); double v = opt_value.value; if (opt_value.percent) { + // Resolve dependencies using the "ratio_over" link to a parent value. + const ConfigOptionDef *opt_def = print_config_def.get(opt_key); + assert(opt_def != nullptr); + assert(opt_def->type == coFloatsOrPercents); v *= 0.01; while (true) { const ConfigOption *opt_parent = opt_def->ratio_over.empty() ? nullptr : ctx->resolve_symbol(opt_def->ratio_over); diff --git a/src/libslic3r/PresetBundle.cpp b/src/libslic3r/PresetBundle.cpp index 2d32c5c51..0250f714d 100644 --- a/src/libslic3r/PresetBundle.cpp +++ b/src/libslic3r/PresetBundle.cpp @@ -1627,9 +1627,9 @@ void PresetBundle::load_selections(AppConfig &config, const PresetPreferences& p project_config.option("flush_volumes_vector")->values = std::vector(flush_volumes_vector.begin(), flush_volumes_vector.end()); } if (config.has("app", "flush_multiplier")) { - std::string str_flush_multiplier = config.get("app", "flush_multiplier"); - if (!str_flush_multiplier.empty()) - project_config.option("flush_multiplier")->set(new ConfigOptionFloat(std::stof(str_flush_multiplier))); + boost::algorithm::split(matrix, config.get("app", "flush_multiplier"), boost::algorithm::is_any_of("|")); + auto flush_multipliers = matrix | boost::adaptors::transformed(boost::lexical_cast); + project_config.option("flush_multiplier")->values = std::vector(flush_multipliers.begin(), flush_multipliers.end()); } // Update visibility of presets based on their compatibility with the active printer. @@ -1706,8 +1706,11 @@ void PresetBundle::export_selections(AppConfig &config) config.set("presets", PRESET_PRINTER_NAME, printers.get_selected_preset_name()); - auto flush_multi_opt = project_config.option("flush_multiplier"); - config.set("flush_multiplier", std::to_string(flush_multi_opt ? flush_multi_opt->getFloat() : 1.0f)); + std::string flush_multiplier_str = boost::algorithm::join(project_config.option("flush_multiplier")->values | + boost::adaptors::transformed(static_cast(std::to_string)), + "|"); + config.set("flush_multiplier", flush_multiplier_str); + // BBS //config.set("presets", "sla_print", sla_prints.get_selected_preset_name()); //config.set("presets", "sla_material", sla_materials.get_selected_preset_name()); @@ -3631,7 +3634,9 @@ void PresetBundle::update_multi_material_filament_presets() // Now verify if flush_volumes_matrix has proper size (it is used to deduce number of extruders in wipe tower generator): std::vector old_matrix = this->project_config.option("flush_volumes_matrix")->values; - size_t old_number_of_filaments = size_t(sqrt(old_matrix.size())+EPSILON); + + size_t nozzle_nums = full_config().option("nozzle_diameter")->values.size(); + size_t old_number_of_filaments = size_t(sqrt(old_matrix.size() / nozzle_nums) + EPSILON); if (num_filaments != old_number_of_filaments) { // First verify if purging volumes presets for each extruder matches number of extruders std::vector& filaments = this->project_config.option("flush_volumes_vector")->values; @@ -3644,16 +3649,38 @@ void PresetBundle::update_multi_material_filament_presets() filaments.pop_back(); } - std::vector new_matrix; - for (unsigned int i=0;i< num_filaments;++i) - for (unsigned int j=0;j< num_filaments;++j) { - // append the value for this pair from the old matrix (if it's there): - if (i < old_number_of_filaments && j < old_number_of_filaments) - new_matrix.push_back(old_matrix[i* old_number_of_filaments + j]); - else - new_matrix.push_back( i == j ? 0. : filaments[2 * i] + filaments[2 * j + 1]); // so it matches new extruder volumes - } - this->project_config.option("flush_volumes_matrix")->values = new_matrix; + if (nozzle_nums > 1) { + size_t old_matrix_size = old_number_of_filaments * old_number_of_filaments; + size_t new_matrix_size = num_filaments * num_filaments; + std::vector new_matrix(new_matrix_size * nozzle_nums, 0); + for (unsigned int i = 0; i < num_filaments; ++i) + for (unsigned int j = 0; j < num_filaments; ++j) { + if (i < old_number_of_filaments && j < old_number_of_filaments) { + for (size_t nozzle_id = 0; nozzle_id < nozzle_nums; ++nozzle_id) { + new_matrix[i * num_filaments + j + new_matrix_size * nozzle_id] = old_matrix[i * old_number_of_filaments + j + old_matrix_size * nozzle_id]; + } + } + else { + for (size_t nozzle_id = 0; nozzle_id < nozzle_nums; ++nozzle_id) { + new_matrix[i * num_filaments + j + new_matrix_size * nozzle_id] = (i == j ? 0. : filaments[2 * i] + filaments[2 * j + 1]); + } + } + } + this->project_config.option("flush_volumes_matrix")->values = new_matrix; + } + else { + std::vector new_matrix; + for (unsigned int i = 0; i < num_filaments; ++i) + for (unsigned int j = 0; j < num_filaments; ++j) { + // append the value for this pair from the old matrix (if it's there): + if (i < old_number_of_filaments && j < old_number_of_filaments) + new_matrix.push_back(old_matrix[i * old_number_of_filaments + j]); + else + new_matrix.push_back(i == j ? 0. : filaments[2 * i] + filaments[2 * j + 1]); // so it matches new extruder volumes + } + this->project_config.option("flush_volumes_matrix")->values = new_matrix; + } + } } diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index b3ef12e61..bd07a4b48 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -2346,15 +2346,8 @@ void Print::_make_wipe_tower() { m_wipe_tower_data.clear(); - // Get wiping matrix to get number of extruders and convert vector to vector: - std::vector flush_matrix(cast(m_config.flush_volumes_matrix.values)); - // BBS - const unsigned int number_of_extruders = (unsigned int)(sqrt(flush_matrix.size()) + EPSILON); - // Extract purging volumes for each extruder pair: - std::vector> wipe_volumes; - for (unsigned int i = 0; i(flush_matrix.begin()+i*number_of_extruders, flush_matrix.begin()+(i+1)*number_of_extruders)); + const unsigned int number_of_extruders = (unsigned int)(m_config.filament_colour.values.size()); // Let the ToolOrdering class know there will be initial priming extrusions at the start of the print. // BBS: priming logic is removed, so don't consider it in tool ordering @@ -2406,9 +2399,6 @@ void Print::_make_wipe_tower() WipeTower wipe_tower(m_config, m_plate_index, m_origin, m_config.prime_volume, m_wipe_tower_data.tool_ordering.first_extruder(), m_wipe_tower_data.tool_ordering.empty() ? 0.f : m_wipe_tower_data.tool_ordering.back().print_z); - //wipe_tower.set_retract(); - //wipe_tower.set_zhop(); - // Set the extruder & material properties at the wipe tower object. for (size_t i = 0; i < number_of_extruders; ++ i) wipe_tower.set_extruder(i, m_config); @@ -2420,45 +2410,119 @@ void Print::_make_wipe_tower() // Lets go through the wipe tower layers and determine pairs of extruder changes for each // to pass to wipe_tower (so that it can use it for planning the layout of the tower) { - // BBS: priming logic is removed, so get the initial extruder by first_extruder() - unsigned int current_extruder_id = m_wipe_tower_data.tool_ordering.first_extruder(); - for (auto &layer_tools : m_wipe_tower_data.tool_ordering.layer_tools()) { // for all layers - if (!layer_tools.has_wipe_tower) continue; - bool first_layer = &layer_tools == &m_wipe_tower_data.tool_ordering.front(); - wipe_tower.plan_toolchange((float)layer_tools.print_z, (float)layer_tools.wipe_tower_layer_height, current_extruder_id, current_extruder_id); + // Get wiping matrix to get number of extruders and convert vector to vector: + bool is_mutli_extruder = m_config.nozzle_diameter.values.size() > 1; + size_t nozzle_nums = m_config.nozzle_diameter.values.size(); + if (is_mutli_extruder) { + using FlushMatrix = std::vector>; + std::vector multi_extruder_flush; + for (size_t nozzle_id = 0; nozzle_id < nozzle_nums; ++nozzle_id) { + std::vector flush_matrix(cast(get_flush_volumes_matrix(m_config.flush_volumes_matrix.values, nozzle_id, nozzle_nums))); + std::vector> wipe_volumes; + for (unsigned int i = 0; i < number_of_extruders; ++i) + wipe_volumes.push_back(std::vector(flush_matrix.begin() + i * number_of_extruders, flush_matrix.begin() + (i + 1) * number_of_extruders)); - for (const auto extruder_id : layer_tools.extruders) { - // BBS: priming logic is removed, so no need to do toolchange for first extruder - if (/*(first_layer && extruder_id == m_wipe_tower_data.tool_ordering.all_extruders().back()) || */extruder_id != current_extruder_id) { - float volume_to_purge = wipe_volumes[current_extruder_id][extruder_id]; - volume_to_purge *= m_config.flush_multiplier; + multi_extruder_flush.emplace_back(wipe_volumes); + } - // Not all of that can be used for infill purging: - //volume_to_purge -= (float)m_config.filament_minimal_purge_on_wipe_tower.get_at(extruder_id); + // todo multi_extruders: get filament_maps + std::vector filament_maps; + for (int i = 0; i <= number_of_extruders / 2; ++i) { + filament_maps.push_back(1); + } + for (int i = number_of_extruders / 2 + 1; i < number_of_extruders; ++i) { + filament_maps.push_back(2); + } - // try to assign some infills/objects for the wiping: - volume_to_purge = layer_tools.wiping_extrusions().mark_wiping_extrusions(*this, current_extruder_id, extruder_id, volume_to_purge); + std::vector nozzle_cur_filament_ids(nozzle_nums, -1); + unsigned int current_filament_id = m_wipe_tower_data.tool_ordering.first_extruder(); + size_t cur_nozzle_id = filament_maps[current_filament_id] - 1; + nozzle_cur_filament_ids[cur_nozzle_id] = current_filament_id; - // add back the minimal amount toforce on the wipe tower: - //volume_to_purge += (float)m_config.filament_minimal_purge_on_wipe_tower.get_at(extruder_id); + for (auto &layer_tools : m_wipe_tower_data.tool_ordering.layer_tools()) { // for all layers + if (!layer_tools.has_wipe_tower) continue; + bool first_layer = &layer_tools == &m_wipe_tower_data.tool_ordering.front(); + wipe_tower.plan_toolchange((float) layer_tools.print_z, (float) layer_tools.wipe_tower_layer_height, current_filament_id, current_filament_id); - // request a toolchange at the wipe tower with at least volume_to_wipe purging amount - wipe_tower.plan_toolchange((float)layer_tools.print_z, (float)layer_tools.wipe_tower_layer_height, - current_extruder_id, extruder_id, m_config.prime_volume, volume_to_purge); - current_extruder_id = extruder_id; + for (const auto filament_id : layer_tools.extruders) { + if (filament_id == current_filament_id) + continue; + + int nozzle_id = filament_maps[filament_id] - 1; + unsigned int pre_filament_id = nozzle_cur_filament_ids[nozzle_id]; + if (pre_filament_id == filament_id) + continue; + + float volume_to_purge = multi_extruder_flush[nozzle_id][pre_filament_id][filament_id]; + volume_to_purge *= m_config.flush_multiplier.get_at(nozzle_id); + volume_to_purge = pre_filament_id == -1 ? 0 : + layer_tools.wiping_extrusions().mark_wiping_extrusions(*this, current_filament_id, filament_id, volume_to_purge); + wipe_tower.plan_toolchange((float) layer_tools.print_z, (float) layer_tools.wipe_tower_layer_height, current_filament_id, filament_id, + m_config.prime_volume, volume_to_purge); + current_filament_id = filament_id; + nozzle_cur_filament_ids[nozzle_id] = filament_id; } - } - layer_tools.wiping_extrusions().ensure_perimeters_infills_order(*this); + layer_tools.wiping_extrusions().ensure_perimeters_infills_order(*this); - // if enable timelapse, slice all layer - if (enable_timelapse_print()) { - if (layer_tools.wipe_tower_partitions == 0) - wipe_tower.set_last_layer_extruder_fill(false); - continue; - } + // if enable timelapse, slice all layer + if (enable_timelapse_print()) { + if (layer_tools.wipe_tower_partitions == 0) wipe_tower.set_last_layer_extruder_fill(false); + continue; + } - if (&layer_tools == &m_wipe_tower_data.tool_ordering.back() || (&layer_tools + 1)->wipe_tower_partitions == 0) - break; + if (&layer_tools == &m_wipe_tower_data.tool_ordering.back() || (&layer_tools + 1)->wipe_tower_partitions == 0) + break; + } + } + else { + std::vector flush_matrix(cast(get_flush_volumes_matrix(m_config.flush_volumes_matrix.values, 0, nozzle_nums))); + + // Extract purging volumes for each extruder pair: + std::vector> wipe_volumes; + for (unsigned int i = 0; i < number_of_extruders; ++i) + wipe_volumes.push_back(std::vector(flush_matrix.begin() + i * number_of_extruders, flush_matrix.begin() + (i + 1) * number_of_extruders)); + + + // BBS: priming logic is removed, so get the initial extruder by first_extruder() + unsigned int current_extruder_id = m_wipe_tower_data.tool_ordering.first_extruder(); + for (auto &layer_tools : m_wipe_tower_data.tool_ordering.layer_tools()) { // for all layers + if (!layer_tools.has_wipe_tower) continue; + bool first_layer = &layer_tools == &m_wipe_tower_data.tool_ordering.front(); + wipe_tower.plan_toolchange((float)layer_tools.print_z, (float)layer_tools.wipe_tower_layer_height, current_extruder_id, current_extruder_id); + + for (const auto extruder_id : layer_tools.extruders) { + // BBS: priming logic is removed, so no need to do toolchange for first extruder + if (/*(first_layer && extruder_id == m_wipe_tower_data.tool_ordering.all_extruders().back()) || */extruder_id != current_extruder_id) { + float volume_to_purge = wipe_volumes[current_extruder_id][extruder_id]; + volume_to_purge *= m_config.flush_multiplier.get_at(0); + + // Not all of that can be used for infill purging: + //volume_to_purge -= (float)m_config.filament_minimal_purge_on_wipe_tower.get_at(extruder_id); + + // try to assign some infills/objects for the wiping: + volume_to_purge = layer_tools.wiping_extrusions().mark_wiping_extrusions(*this, current_extruder_id, extruder_id, volume_to_purge); + + // add back the minimal amount toforce on the wipe tower: + //volume_to_purge += (float)m_config.filament_minimal_purge_on_wipe_tower.get_at(extruder_id); + + // request a toolchange at the wipe tower with at least volume_to_wipe purging amount + wipe_tower.plan_toolchange((float)layer_tools.print_z, (float)layer_tools.wipe_tower_layer_height, + current_extruder_id, extruder_id, m_config.prime_volume, volume_to_purge); + current_extruder_id = extruder_id; + } + } + layer_tools.wiping_extrusions().ensure_perimeters_infills_order(*this); + + // if enable timelapse, slice all layer + if (enable_timelapse_print()) { + if (layer_tools.wipe_tower_partitions == 0) + wipe_tower.set_last_layer_extruder_fill(false); + continue; + } + + if (&layer_tools == &m_wipe_tower_data.tool_ordering.back() || (&layer_tools + 1)->wipe_tower_partitions == 0) + break; + } } } diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index d25d2121e..3648a3eb8 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -375,7 +375,7 @@ static const t_config_enum_values s_keys_map_ZHopType = { CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(ZHopType) static const t_config_enum_values s_keys_map_ExtruderType = { - { "DirectDrive", etDirectDrive }, + { "Direct drive", etDirectDrive }, { "Bowden", etBowden } }; CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(ExtruderType) @@ -404,6 +404,7 @@ std::string get_extruder_variant_string(ExtruderType extruder_type, NozzleVolume variant_string = s_keys_names_ExtruderType[extruder_type]; variant_string+= " "; variant_string+= s_keys_names_NozzleVolumeType[nozzle_volume_type]; + return variant_string; } static void assign_printer_technology_to_unknown(t_optiondef_map &options, PrinterTechnology printer_technology) @@ -3903,11 +3904,11 @@ void PrintConfigDef::init_fff_params() 280.f, 280.f, 0.f, 280.f, 280.f, 280.f, 280.f, 0.f }); - def = this->add("flush_multiplier", coFloat); + def = this->add("flush_multiplier", coFloats); def->label = L("Flush multiplier"); def->tooltip = L("The actual flushing volumes is equal to the flush multiplier multiplied by the flushing volumes in the table."); def->sidetext = ""; - def->set_default_value(new ConfigOptionFloat(1.0)); + def->set_default_value(new ConfigOptionFloats{1.0}); // BBS def = this->add("prime_volume", coFloat); @@ -5405,8 +5406,8 @@ int DynamicPrintConfig::get_index_for_extruder(int extruder_id, std::string id_n auto variant_opt = dynamic_cast(this->option(variant_name)); auto id_opt = dynamic_cast(this->option(id_name)); if ((variant_opt != nullptr)&&(id_opt != nullptr)) { - int v_size = variant_opt->size(); - int i_size = variant_opt->size(); + int v_size = variant_opt->values.size(); + int i_size = id_opt->values.size(); std::string extruder_variant = get_extruder_variant_string(extruder_type, nozzle_volume_type); for (int index = 0; index < v_size; index++) { diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 846112cb2..7bbcf1074 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1135,7 +1135,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( ((ConfigOptionFloats, flush_volumes_vector)) // BBS: wipe tower is only used for priming ((ConfigOptionFloat, prime_volume)) - ((ConfigOptionFloat, flush_multiplier)) + ((ConfigOptionFloats, flush_multiplier)) //((ConfigOptionFloat, z_offset)) // BBS: project filaments ((ConfigOptionFloats, filament_colour_new)) @@ -1547,6 +1547,34 @@ private: static uint64_t s_last_timestamp; }; + +// const std::vector &fv_matrix: origin matrix from json +// size_t extruder_id: -1 means single-nozzle for old file, 0 means the 1st extruder, 1 means the 2nd extruder +template +static std::vector get_flush_volumes_matrix(const std::vector &fv_matrix, size_t extruder_id = -1, size_t nozzle_nums = 1) +{ + if (extruder_id != -1 && nozzle_nums != 1) { + return std::vector(fv_matrix.begin() + size_t(fv_matrix.size() / nozzle_nums * extruder_id + EPSILON), + fv_matrix.begin() + size_t(fv_matrix.size() / nozzle_nums * (extruder_id + 1) + EPSILON)); + } + return fv_matrix; +} + +// std::vector &out_matrix: +// const std::vector &fv_matrix: the matrix of one nozzle +// size_t extruder_id: -1 means single-nozzle for old file, 0 means the 1st extruder, 1 means the 2nd extruder +template +static void set_flush_volumes_matrix(std::vector &out_matrix, const std::vector &fv_matrix, size_t extruder_id = -1, size_t nozzle_nums = 1) +{ + bool is_multi_extruder = false; + if (extruder_id != -1 && nozzle_nums != 1) { + std::copy(fv_matrix.begin(), fv_matrix.end(), out_matrix.begin() + size_t(out_matrix.size() / nozzle_nums * extruder_id + EPSILON)); + } + else { + out_matrix = std::vector(fv_matrix.begin(), fv_matrix.end()); + } +} + } // namespace Slic3r // Serialization through the Cereal library diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 9ee96b722..ee50a61e2 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -484,8 +484,11 @@ void Sidebar::priv::hide_rich_tip(wxButton* btn) } #endif -std::vector get_min_flush_volumes(const DynamicPrintConfig& full_config) +std::vector get_min_flush_volumes(const DynamicPrintConfig &full_config, size_t nozzle_id) { + //todo multi_extruder: + nozzle_id = 0; + std::vectorextra_flush_volumes; //const auto& full_config = wxGetApp().preset_bundle->full_config(); //auto& printer_config = wxGetApp().preset_bundle->printers.get_edited_preset().config; @@ -502,7 +505,7 @@ std::vector get_min_flush_volumes(const DynamicPrintConfig& full_config) const ConfigOptionBools* long_retractions_when_cut_opt = full_config.option("long_retractions_when_cut"); bool machine_activated = false; if (long_retractions_when_cut_opt) { - machine_activated = long_retractions_when_cut_opt->values[0] == 1; + machine_activated = long_retractions_when_cut_opt->values[nozzle_id] == 1; BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": get long_retractions_when_cut from config, value=%1%, activated=%2%")%long_retractions_when_cut_opt->values[0] %machine_activated; } @@ -529,7 +532,7 @@ std::vector get_min_flush_volumes(const DynamicPrintConfig& full_config) for (size_t idx = 0; idx < filament_size; ++idx) { int extra_flush_volume = nozzle_volume_val; - int retract_length = machine_enabled_level && machine_activated ? printer_retraction_distance_when_cut[0] : 0; + int retract_length = machine_enabled_level && machine_activated ? printer_retraction_distance_when_cut[nozzle_id] : 0; unsigned char filament_activated = filament_long_retractions_when_cut[idx]; double filament_retract_length = filament_retraction_distance_when_cut[idx]; @@ -540,7 +543,7 @@ std::vector get_min_flush_volumes(const DynamicPrintConfig& full_config) if (!std::isnan(filament_retract_length)) retract_length = (int)filament_retraction_distance_when_cut[idx]; else - retract_length = printer_retraction_distance_when_cut[0]; + retract_length = printer_retraction_distance_when_cut[nozzle_id]; } extra_flush_volume -= PI * 1.75 * 1.75 / 4 * retract_length; @@ -1040,19 +1043,30 @@ Sidebar::Sidebar(Plater *parent) auto& project_config = wxGetApp().preset_bundle->project_config; const std::vector& init_matrix = (project_config.option("flush_volumes_matrix"))->values; const std::vector& init_extruders = (project_config.option("flush_volumes_vector"))->values; - ConfigOptionFloat* flush_multi_opt = project_config.option("flush_multiplier"); - float flush_multiplier = flush_multi_opt ? flush_multi_opt->getFloat() : 1.f; - + const std::vector extruder_colours = wxGetApp().plater()->get_extruder_colors_from_plater_config(); const auto& full_config = wxGetApp().preset_bundle->full_config(); - const auto& extra_flush_volumes = get_min_flush_volumes(full_config); - WipingDialog dlg(parent, cast(init_matrix), cast(init_extruders), extruder_colours, extra_flush_volumes, flush_multiplier); + const auto& extra_flush_volumes = get_min_flush_volumes(full_config, 0); // todo multi_extruder: always display nozzle 1 + + size_t nozzle_nums = full_config.option("nozzle_diameter")->values.size(); + + std::vector flush_multiplier; + ConfigOptionFloats *flush_multi_opt = project_config.option("flush_multiplier"); + if (flush_multi_opt) + flush_multiplier = cast(flush_multi_opt->values); + else { + for (size_t nozzle_id = 0; nozzle_id < nozzle_nums; ++nozzle_id) { + flush_multiplier.push_back(1.f); + } + } + WipingDialog dlg(parent, cast(init_matrix), cast(init_extruders), extruder_colours, extra_flush_volumes, flush_multiplier, nozzle_nums); if (dlg.ShowModal() == wxID_OK) { std::vector matrix = dlg.get_matrix(); std::vector extruders = dlg.get_extruders(); + std::vector flush_multipliers = dlg.get_flush_multiplier_vector(); (project_config.option("flush_volumes_matrix"))->values = std::vector(matrix.begin(), matrix.end()); (project_config.option("flush_volumes_vector"))->values = std::vector(extruders.begin(), extruders.end()); - (project_config.option("flush_multiplier"))->set(new ConfigOptionFloat(dlg.get_flush_multiplier())); + (project_config.option("flush_multiplier"))->values = std::vector(flush_multipliers.begin(), flush_multipliers.end()); wxGetApp().preset_bundle->export_selections(*wxGetApp().app_config); @@ -2223,94 +2237,96 @@ void Sidebar::auto_calc_flushing_volumes(const int modify_id) auto& ams_multi_color_filament = preset_bundle->ams_multi_color_filment; auto& ams_filament_list = preset_bundle->filament_ams_list; - const std::vector& init_matrix = (project_config.option("flush_volumes_matrix"))->values; - const std::vector& init_extruders = (project_config.option("flush_volumes_vector"))->values; + size_t nozzle_nums = preset_bundle->full_config().option("nozzle_diameter")->values.size(); + for (size_t nozzle_id = 0; nozzle_id < nozzle_nums; ++nozzle_id) + { + std::vector init_matrix = get_flush_volumes_matrix((project_config.option("flush_volumes_matrix"))->values, nozzle_id, nozzle_nums); - const std::vector& min_flush_volumes= get_min_flush_volumes(full_config); - - ConfigOptionFloat* flush_multi_opt = project_config.option("flush_multiplier"); - float flush_multiplier = flush_multi_opt ? flush_multi_opt->getFloat() : 1.f; - std::vector matrix = init_matrix; - int m_max_flush_volume = Slic3r::g_max_flush_volume; - unsigned int m_number_of_extruders = (int)(sqrt(init_matrix.size()) + 0.001); - - const std::vector extruder_colours = wxGetApp().plater()->get_extruder_colors_from_plater_config(); - std::vector> multi_colours; - - // Support for multi-color filament - for (int i = 0; i < extruder_colours.size(); ++i) { - std::vector single_filament; - if (i < ams_multi_color_filament.size()) { - if (!ams_multi_color_filament[i].empty()) { - std::vector colors = ams_multi_color_filament[i]; - for (int j = 0; j < colors.size(); ++j) { - single_filament.push_back(wxColour(colors[j])); + const std::vector& min_flush_volumes= get_min_flush_volumes(full_config, nozzle_id); + + ConfigOptionFloat* flush_multi_opt = project_config.option("flush_multiplier"); + float flush_multiplier = flush_multi_opt ? flush_multi_opt->getFloat() : 1.f; + std::vector matrix = init_matrix; + int m_max_flush_volume = Slic3r::g_max_flush_volume; + unsigned int m_number_of_extruders = (int)(sqrt(init_matrix.size()) + 0.001); + + const std::vector extruder_colours = wxGetApp().plater()->get_extruder_colors_from_plater_config(); + std::vector> multi_colours; + + // Support for multi-color filament + for (int i = 0; i < extruder_colours.size(); ++i) { + std::vector single_filament; + if (i < ams_multi_color_filament.size()) { + if (!ams_multi_color_filament[i].empty()) { + std::vector colors = ams_multi_color_filament[i]; + for (int j = 0; j < colors.size(); ++j) { + single_filament.push_back(wxColour(colors[j])); + } + multi_colours.push_back(single_filament); + continue; } - multi_colours.push_back(single_filament); - continue; } + + single_filament.push_back(wxColour(extruder_colours[i])); + multi_colours.push_back(single_filament); } - - single_filament.push_back(wxColour(extruder_colours[i])); - multi_colours.push_back(single_filament); - } - - if (modify_id >= 0 && modify_id < multi_colours.size()) { - for (int i = 0; i < multi_colours.size(); ++i) { - // from to modify - int from_idx = i; - if (from_idx != modify_id) { - Slic3r::FlushVolCalculator calculator(min_flush_volumes[from_idx], m_max_flush_volume); - int flushing_volume = 0; - bool is_from_support = is_support_filament(from_idx); - bool is_to_support = is_support_filament(modify_id); - if (is_to_support) { - flushing_volume = Slic3r::g_flush_volume_to_support; - } - else { - for (int j = 0; j < multi_colours[from_idx].size(); ++j) { - const wxColour& from = multi_colours[from_idx][j]; - for (int k = 0; k < multi_colours[modify_id].size(); ++k) { - const wxColour& to = multi_colours[modify_id][k]; - int volume = calculator.calc_flush_vol(from.Alpha(), from.Red(), from.Green(), from.Blue(), to.Alpha(), to.Red(), to.Green(), to.Blue()); - flushing_volume = std::max(flushing_volume, volume); - } + + if (modify_id >= 0 && modify_id < multi_colours.size()) { + for (int i = 0; i < multi_colours.size(); ++i) { + // from to modify + int from_idx = i; + if (from_idx != modify_id) { + Slic3r::FlushVolCalculator calculator(min_flush_volumes[from_idx], m_max_flush_volume); + int flushing_volume = 0; + bool is_from_support = is_support_filament(from_idx); + bool is_to_support = is_support_filament(modify_id); + if (is_to_support) { + flushing_volume = Slic3r::g_flush_volume_to_support; } - if (is_from_support) - flushing_volume = std::max(flushing_volume, Slic3r::g_min_flush_volume_from_support); - } - matrix[m_number_of_extruders * from_idx + modify_id] = flushing_volume; - } - - // modify to to - int to_idx = i; - if (to_idx != modify_id) { - Slic3r::FlushVolCalculator calculator(min_flush_volumes[modify_id], m_max_flush_volume); - bool is_from_support = is_support_filament(modify_id); - bool is_to_support = is_support_filament(to_idx); - int flushing_volume = 0; - if (is_to_support) { - flushing_volume = Slic3r::g_flush_volume_to_support; - } - else { - for (int j = 0; j < multi_colours[modify_id].size(); ++j) { - const wxColour& from = multi_colours[modify_id][j]; - for (int k = 0; k < multi_colours[to_idx].size(); ++k) { - const wxColour& to = multi_colours[to_idx][k]; - int volume = calculator.calc_flush_vol(from.Alpha(), from.Red(), from.Green(), from.Blue(), to.Alpha(), to.Red(), to.Green(), to.Blue()); - flushing_volume = std::max(flushing_volume, volume); + else { + for (int j = 0; j < multi_colours[from_idx].size(); ++j) { + const wxColour& from = multi_colours[from_idx][j]; + for (int k = 0; k < multi_colours[modify_id].size(); ++k) { + const wxColour& to = multi_colours[modify_id][k]; + int volume = calculator.calc_flush_vol(from.Alpha(), from.Red(), from.Green(), from.Blue(), to.Alpha(), to.Red(), to.Green(), to.Blue()); + flushing_volume = std::max(flushing_volume, volume); + } } + if (is_from_support) + flushing_volume = std::max(flushing_volume, Slic3r::g_min_flush_volume_from_support); + } + matrix[m_number_of_extruders * from_idx + modify_id] = flushing_volume; + } + + // modify to to + int to_idx = i; + if (to_idx != modify_id) { + Slic3r::FlushVolCalculator calculator(min_flush_volumes[modify_id], m_max_flush_volume); + bool is_from_support = is_support_filament(modify_id); + bool is_to_support = is_support_filament(to_idx); + int flushing_volume = 0; + if (is_to_support) { + flushing_volume = Slic3r::g_flush_volume_to_support; + } + else { + for (int j = 0; j < multi_colours[modify_id].size(); ++j) { + const wxColour& from = multi_colours[modify_id][j]; + for (int k = 0; k < multi_colours[to_idx].size(); ++k) { + const wxColour& to = multi_colours[to_idx][k]; + int volume = calculator.calc_flush_vol(from.Alpha(), from.Red(), from.Green(), from.Blue(), to.Alpha(), to.Red(), to.Green(), to.Blue()); + flushing_volume = std::max(flushing_volume, volume); + } + } + if (is_from_support) + flushing_volume = std::max(flushing_volume, Slic3r::g_min_flush_volume_from_support); + + matrix[m_number_of_extruders * modify_id + to_idx] = flushing_volume; } - if (is_from_support) - flushing_volume = std::max(flushing_volume, Slic3r::g_min_flush_volume_from_support); - - matrix[m_number_of_extruders * modify_id + to_idx] = flushing_volume; } } } + set_flush_volumes_matrix((project_config.option("flush_volumes_matrix"))->values, matrix, nozzle_id, nozzle_nums); } - (project_config.option("flush_volumes_matrix"))->values = std::vector(matrix.begin(), matrix.end()); - wxGetApp().preset_bundle->export_selections(*wxGetApp().app_config); wxGetApp().plater()->update_project_dirty_from_presets(); @@ -13160,6 +13176,13 @@ void Plater::on_config_change(const DynamicPrintConfig &config) bool bed_shape_changed = false; //bool print_sequence_changed = false; t_config_option_keys diff_keys = p->config->diff(config); + + std::string old_model_id; + auto * printer_model = p->config->opt("printer_model"); + if (printer_model != nullptr && !printer_model->value.empty()) { + old_model_id = printer_model->value; + } + for (auto opt_key : diff_keys) { if (opt_key == "filament_colour") { update_scheduled = true; // update should be scheduled (for update 3DScene) #2738 @@ -13218,6 +13241,8 @@ void Plater::on_config_change(const DynamicPrintConfig &config) } else if (opt_key == "printer_model") { p->reset_gcode_toolpaths(); + update_flush_volume_matrix(config, old_model_id); + // update to force bed selection(for texturing) bed_shape_changed = true; update_scheduled = true; @@ -13241,6 +13266,35 @@ void Plater::on_config_change(const DynamicPrintConfig &config) this->p->schedule_background_process(); } +void Plater::update_flush_volume_matrix(const Slic3r::DynamicPrintConfig& config, const std::string& old_model_id) +{ + auto is_multi_extruder_printer = [](const std::string &model_id) { + return model_id == "Bambu Lab O1 Dual"; + }; + + auto *printer_model = config.opt("printer_model"); + if (printer_model != nullptr && !printer_model->value.empty()) { + size_t nozzle_nums = wxGetApp().preset_bundle->full_config().option("nozzle_diameter")->values.size(); + if (!is_multi_extruder_printer(old_model_id) && is_multi_extruder_printer(printer_model->value)) { + Slic3r::DynamicPrintConfig *project_config = &wxGetApp().preset_bundle->project_config; + std::vector flush_volume_mtx = get_flush_volumes_matrix(project_config->option("flush_volumes_matrix")->values, -1, nozzle_nums); + flush_volume_mtx.insert(flush_volume_mtx.end(), flush_volume_mtx.begin(), flush_volume_mtx.end()); + set_flush_volumes_matrix(project_config->option("flush_volumes_matrix")->values, flush_volume_mtx, -1, nozzle_nums); + + double first_value = project_config->option("flush_multiplier")->values.at(0); + project_config->option("flush_multiplier")->values = std::vector({first_value, 1.0}); + } + else if (is_multi_extruder_printer(old_model_id) && !is_multi_extruder_printer(printer_model->value)) { + Slic3r::DynamicPrintConfig *project_config = &wxGetApp().preset_bundle->project_config; + std::vector flush_volume_mtx = get_flush_volumes_matrix(project_config->option("flush_volumes_matrix")->values, 0, nozzle_nums); + set_flush_volumes_matrix(project_config->option("flush_volumes_matrix")->values, flush_volume_mtx, -1, nozzle_nums); + + double first_value = project_config->option("flush_multiplier")->values.at(0); + project_config->option("flush_multiplier")->values = std::vector({first_value}); + } + } +} + void Plater::set_bed_shape() const { std::string texture_filename; diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 424a70b4c..814d14a14 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -608,6 +608,8 @@ public: const Mouse3DController& get_mouse3d_controller() const; Mouse3DController& get_mouse3d_controller(); + //BBS: update when switch muilti_extruder printer + void update_flush_volume_matrix(const Slic3r::DynamicPrintConfig &config, const std::string &old_model_id); //BBS: add bed exclude area void set_bed_shape() const; void set_bed_shape(const Pointfs& shape, const Pointfs& exclude_area, const double printable_height, const std::string& custom_texture, const std::string& custom_model, bool force_as_custom = false) const; @@ -791,7 +793,7 @@ private: bool m_was_scheduled; }; -std::vector get_min_flush_volumes(const DynamicPrintConfig& full_config); +std::vector get_min_flush_volumes(const DynamicPrintConfig &full_config, size_t nozzle_id); std::string check_boolean_possible(const std::vector& volumes); } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/WipeTowerDialog.cpp b/src/slic3r/GUI/WipeTowerDialog.cpp index d6b1a62cd..2de5848ec 100644 --- a/src/slic3r/GUI/WipeTowerDialog.cpp +++ b/src/slic3r/GUI/WipeTowerDialog.cpp @@ -168,6 +168,13 @@ wxBoxSizer* WipingPanel::create_calc_btn_sizer(wxWindow* parent) { btn_sizer->Add(calc_btn, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, BTN_GAP); calc_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { calc_flushing_volumes(); }); + ComboBox *extruder_combo = new ComboBox(parent, wxID_ANY, "", wxDefaultPosition, wxSize(FromDIP(100), FromDIP(24)), 0, nullptr, wxCB_READONLY); + extruder_combo->AppendString(_L("extruder 1")); + extruder_combo->AppendString(_L("extruder 2")); + extruder_combo->SetSelection(0); + extruder_combo->Bind(wxEVT_COMBOBOX, &WipingPanel::on_select_extruder, this); + btn_sizer->Add(extruder_combo); + return btn_sizer; } void WipingDialog::on_dpi_changed(const wxRect &suggested_rect) @@ -194,7 +201,7 @@ void WipingDialog::on_dpi_changed(const wxRect &suggested_rect) // Parent dialog for purging volume adjustments - it fathers WipingPanel widget (that contains all controls) and a button to toggle simple/advanced mode: WipingDialog::WipingDialog(wxWindow* parent, const std::vector& matrix, const std::vector& extruders, const std::vector& extruder_colours, - const std::vector&extra_flush_volume, float flush_multiplier) + const std::vector&extra_flush_volume, const std::vector& flush_multiplier, size_t nozzle_nums) : DPIDialog(parent ? parent : static_cast(wxGetApp().mainframe), wxID_ANY, _(L("Flushing volumes for filament change")), @@ -212,7 +219,7 @@ WipingDialog::WipingDialog(wxWindow* parent, const std::vector& matrix, c this->SetMinSize(wxSize(MIN_WIPING_DIALOG_WIDTH, -1)); - m_panel_wiping = new WipingPanel(this, matrix, extruders, extruder_colours, nullptr, extra_flush_volume, flush_multiplier); + m_panel_wiping = new WipingPanel(this, matrix, extruders, 0, extruder_colours, nullptr, extra_flush_volume, flush_multiplier, nozzle_nums); auto main_sizer = new wxBoxSizer(wxVERTICAL); main_sizer->Add(m_line_top, 0, wxEXPAND, 0); @@ -293,19 +300,29 @@ void WipingPanel::create_panels(wxWindow* parent, const int num) { } // This panel contains all control widgets for both simple and advanced mode (these reside in separate sizers) -WipingPanel::WipingPanel(wxWindow* parent, const std::vector& matrix, const std::vector& extruders, const std::vector& extruder_colours, Button* calc_button, - const std::vector& extra_flush_volume, float flush_multiplier) -: wxPanel(parent,wxID_ANY, wxDefaultPosition, wxDefaultSize/*,wxBORDER_RAISED*/) -,m_matrix(matrix), m_min_flush_volume(extra_flush_volume), m_max_flush_volume(Slic3r::g_max_flush_volume) +WipingPanel::WipingPanel(wxWindow* parent, const std::vector& matrix, const std::vector& extruders, + size_t cur_extruder_id, + const std::vector& extruder_colours, Button* calc_button, + const std::vector& extra_flush_volume, const std::vector& flush_multiplier, size_t nozzle_nums) + : wxPanel(parent,wxID_ANY, wxDefaultPosition, wxDefaultSize/*,wxBORDER_RAISED*/) + , m_flush_multiplier(flush_multiplier) + , m_matrix(matrix) + , m_cur_extruder_id(cur_extruder_id) + , m_min_flush_volume(extra_flush_volume) + , m_max_flush_volume(Slic3r::g_max_flush_volume) + , m_nozzle_nums(nozzle_nums) { - m_number_of_extruders = (int)(sqrt(matrix.size())+0.001); + m_number_of_extruders = (unsigned int)extruder_colours.size(); + + generate_display_matrix(); + assert(m_display_matrix.size() == extruders.size() ^ 2); for (const std::string& color : extruder_colours) { //unsigned char rgb[3]; //Slic3r::GUI::BitmapCache::parse_color(color, rgb); m_colours.push_back(wxColor(color)); } - auto sizer_width = (int)((sqrt(matrix.size())) * ITEM_WIDTH() + (sqrt(matrix.size()) + 1) * HEADER_BEG_PADDING); + auto sizer_width = (int)((sqrt(m_display_matrix.size())) * ITEM_WIDTH() + (sqrt(m_display_matrix.size()) + 1) * HEADER_BEG_PADDING); sizer_width = sizer_width > MIN_WIPING_DIALOG_WIDTH ? sizer_width : MIN_WIPING_DIALOG_WIDTH; // Create two switched panels with their own sizers m_sizer_simple = new wxBoxSizer(wxVERTICAL); @@ -341,7 +358,7 @@ WipingPanel::WipingPanel(wxWindow* parent, const std::vector& matrix, con edit_boxes[i][j]->Bind(wxEVT_SET_FOCUS, [this](wxFocusEvent&) {}); } else { - edit_boxes[i][j]->SetValue(wxString("") << int(m_matrix[m_number_of_extruders * j + i] * flush_multiplier)); + edit_boxes[i][j]->SetValue(wxString("") << int(m_display_matrix[m_number_of_extruders * j + i] * m_flush_multiplier[m_cur_extruder_id])); edit_boxes[i][j]->Bind(wxEVT_TEXT, [this, i, j](wxCommandEvent& e) { wxString str = edit_boxes[i][j]->GetValue(); @@ -358,7 +375,7 @@ WipingPanel::WipingPanel(wxWindow* parent, const std::vector& matrix, con auto on_apply_text_modify = [this, i, j](wxEvent &e) { wxString str = edit_boxes[i][j]->GetValue(); int value = wxAtoi(str); - m_matrix[m_number_of_extruders * j + i] = value / get_flush_multiplier(); + m_display_matrix[m_number_of_extruders * j + i] = value / get_flush_multiplier(); this->update_warning_texts(); e.Skip(); }; @@ -434,14 +451,18 @@ WipingPanel::WipingPanel(wxWindow* parent, const std::vector& matrix, con if (multiplier < g_min_flush_multiplier || multiplier > g_max_flush_multiplier) { str = wxString::Format(("%.2f"), multiplier < g_min_flush_multiplier ? g_min_flush_multiplier : g_max_flush_multiplier); m_flush_multiplier_ebox->SetValue(str); + m_flush_multiplier[m_cur_extruder_id] = wxAtof(m_flush_multiplier_ebox->GetValue()); MessageDialog dlg(nullptr, wxString::Format(_L("The multiplier should be in range [%.2f, %.2f]."), g_min_flush_multiplier, g_max_flush_multiplier), _L("Warning"), wxICON_WARNING | wxOK); dlg.ShowModal(); } + else { + m_flush_multiplier[m_cur_extruder_id] = multiplier; + } for (unsigned int i = 0; i < m_number_of_extruders; ++i) { for (unsigned int j = 0; j < m_number_of_extruders; ++j) { - edit_boxes[i][j]->SetValue(to_string(int(m_matrix[m_number_of_extruders * j + i] * multiplier))); + edit_boxes[i][j]->SetValue(to_string(int(m_display_matrix[m_number_of_extruders * j + i] * multiplier))); } } @@ -456,7 +477,7 @@ WipingPanel::WipingPanel(wxWindow* parent, const std::vector& matrix, con param_sizer->Add(flush_multiplier_title, 0, wxALIGN_CENTER | wxALL, 0); param_sizer->AddSpacer(FromDIP(5)); m_flush_multiplier_ebox = new wxTextCtrl(m_page_advanced, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(FromDIP(50), -1), wxTE_PROCESS_ENTER); - m_flush_multiplier_ebox->SetValue(wxString::Format(("%.2f"), flush_multiplier)); + m_flush_multiplier_ebox->SetValue(wxString::Format(("%.2f"), m_flush_multiplier[m_cur_extruder_id])); m_flush_multiplier_ebox->SetValidator(wxTextValidator(wxFILTER_NUMERIC)); param_sizer->Add(m_flush_multiplier_ebox, 0, wxALIGN_CENTER | wxALL, 0); param_sizer->AddStretchSpacer(1); @@ -475,6 +496,10 @@ WipingPanel::WipingPanel(wxWindow* parent, const std::vector& matrix, con if (multiplier < g_min_flush_multiplier || multiplier > g_max_flush_multiplier) { str = wxString::Format(("%.2f"), multiplier < g_min_flush_multiplier ? g_min_flush_multiplier : g_max_flush_multiplier); m_flush_multiplier_ebox->SetValue(str); + m_flush_multiplier[m_cur_extruder_id] = wxAtof(m_flush_multiplier_ebox->GetValue()); + } + else { + m_flush_multiplier[m_cur_extruder_id] = multiplier; } m_flush_multiplier_ebox->SetInsertionPointEnd(); }); @@ -677,7 +702,7 @@ void WipingPanel::calc_flushing_volumes() } } - m_matrix[m_number_of_extruders * from_idx + to_idx] = flushing_volume; + m_display_matrix[m_number_of_extruders * from_idx + to_idx] = flushing_volume; flushing_volume = int(flushing_volume * get_flush_multiplier()); edit_boxes[to_idx][from_idx]->SetValue(std::to_string(flushing_volume)); } @@ -714,7 +739,9 @@ std::vector WipingPanel::read_matrix_values() { } } } - return output; + m_display_matrix = output; + back_matrix(); + return m_matrix; } // Reads values from simple mode to save them for next time: @@ -737,7 +764,46 @@ void WipingPanel::fill_in_matrix() { } } +void WipingPanel::generate_display_matrix() +{ + m_display_matrix = get_flush_volumes_matrix(m_matrix, m_cur_extruder_id, m_nozzle_nums); +} +void WipingPanel::back_matrix() +{ + set_flush_volumes_matrix(m_matrix, m_display_matrix, m_cur_extruder_id, m_nozzle_nums); +} + +void WipingPanel::update_table() +{ + for (unsigned int i = 0; i < m_number_of_extruders; ++i) { + for (unsigned int j = 0; j < m_number_of_extruders; ++j) { + if (i == j) { + edit_boxes[i][j]->SetValue(wxString("0")); + edit_boxes[i][j]->SetEditable(false); + } else { + edit_boxes[i][j]->SetValue(wxString("") << int(m_display_matrix[m_number_of_extruders * j + i] * m_flush_multiplier[m_cur_extruder_id])); + } + } + } + wxString str = wxString::Format(("%.2f"), m_flush_multiplier[m_cur_extruder_id]); + m_flush_multiplier_ebox->SetValue(str); + update_warning_texts(); +} + +void WipingPanel::on_select_extruder(wxCommandEvent &evt) +{ + ComboBox *comboBox = dynamic_cast(evt.GetEventObject()); + if (comboBox) { + int selection = comboBox->GetSelection(); + if (m_cur_extruder_id != selection) { + read_matrix_values(); + m_cur_extruder_id = selection; + generate_display_matrix(); + update_table(); + } + } +} // Function to check if simple and advanced settings are matching bool WipingPanel::advanced_matches_simple() { diff --git a/src/slic3r/GUI/WipeTowerDialog.hpp b/src/slic3r/GUI/WipeTowerDialog.hpp index b7d62a555..9b5a20fb7 100644 --- a/src/slic3r/GUI/WipeTowerDialog.hpp +++ b/src/slic3r/GUI/WipeTowerDialog.hpp @@ -15,8 +15,9 @@ class Label; class WipingPanel : public wxPanel { public: // BBS - WipingPanel(wxWindow* parent, const std::vector& matrix, const std::vector& extruders, const std::vector& extruder_colours, Button* calc_button, - const std::vector& extra_flush_volume, float flush_multiplier); + WipingPanel(wxWindow* parent, const std::vector& matrix, const std::vector& extruders, size_t cur_extruder_id, + const std::vector& extruder_colours, Button* calc_button, + const std::vector& extra_flush_volume, const std::vector& flush_multiplier, size_t nozzle_nums); std::vector read_matrix_values(); std::vector read_extruders_values(); void toggle_advanced(bool user_action = false); @@ -33,7 +34,13 @@ public: return wxAtof(m_flush_multiplier_ebox->GetValue()); } + std::vector get_flush_multiplier_vector() { return m_flush_multiplier; } + private: + void on_select_extruder(wxCommandEvent &evt); + void generate_display_matrix(); // generate display_matrix frem matrix + void back_matrix(); + void update_table(); // if matrix is modified update the table void fill_in_matrix(); bool advanced_matches_simple(); int calc_flushing_volume(const wxColour& from, const wxColour& to,int min_flush_volume); @@ -64,7 +71,11 @@ private: wxTextCtrl* m_flush_multiplier_ebox = nullptr; wxStaticText* m_min_flush_label = nullptr; + std::vector m_flush_multiplier; std::vector m_matrix; + std::vector m_display_matrix; + size_t m_cur_extruder_id; + size_t m_nozzle_nums; }; @@ -75,7 +86,7 @@ class WipingDialog : public Slic3r::GUI::DPIDialog { public: WipingDialog(wxWindow* parent, const std::vector& matrix, const std::vector& extruders, const std::vector& extruder_colours, - const std::vector&extra_flush_volume,float flush_multiplier); + const std::vector&extra_flush_volume, const std::vector& flush_multiplier, size_t nozzle_nums); std::vector get_matrix() const { return m_output_matrix; } std::vector get_extruders() const { return m_output_extruders; } wxBoxSizer* create_btn_sizer(long flags); @@ -88,6 +99,12 @@ public: return m_panel_wiping->get_flush_multiplier(); } + std::vector get_flush_multiplier_vector() const { + if (m_panel_wiping == nullptr) + return {1.f, 1.f}; + return m_panel_wiping->get_flush_multiplier_vector(); + } + void on_dpi_changed(const wxRect &suggested_rect) override; private: