diff --git a/src/dev-utils/OrcaSlicer_profile_validator.cpp b/src/dev-utils/OrcaSlicer_profile_validator.cpp index e41ce737ca..c328c565c8 100644 --- a/src/dev-utils/OrcaSlicer_profile_validator.cpp +++ b/src/dev-utils/OrcaSlicer_profile_validator.cpp @@ -308,8 +308,8 @@ DynamicPrintConfig slice_config(PresetBundle &bundle) // type (Direct Drive + Bowden) the mismatched lookup spams [error] lines. Single-nozzle and non-BBL // printers keep the default map (their toolchange rides the AMS/tool-changer path unchanged). const bool pin_filament_map = bundle.is_bbl_vendor() && nozzles > 1; + auto &fmap = bundle.project_config.option("filament_map", true)->values; if (pin_filament_map) { - auto &fmap = bundle.project_config.option("filament_map", true)->values; for (size_t i = 0; i < fmap.size(); ++i) fmap[i] = int(i % nozzles) + 1; } @@ -317,9 +317,8 @@ DynamicPrintConfig slice_config(PresetBundle &bundle) // A fresh printer selection uses its declared nozzle volumes, just like the // app. Otherwise a high-flow preset is silently sliced with Standard tuning. bundle.reset_default_nozzle_volume_type(); - auto &filament_map = bundle.project_config.option("filament_map", true)->values; bundle.project_config.option("filament_volume_map", true)->values = - bundle.get_default_nozzle_volume_types_for_filaments(filament_map); + bundle.get_default_nozzle_volume_types_for_filaments(fmap); DynamicPrintConfig cfg = bundle.full_config(); cfg.set_key_value("enable_prime_tower", new ConfigOptionBool(true)); // force a purge tower so the change is detectable diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 90cca3f084..dedd024f2b 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1258,7 +1258,7 @@ static std::vector get_path_of_change_filament(const Print& print) config.set_key_value("old_filament_temp", new ConfigOptionInt(old_filament_temp)); int interface_temp = full_config.filament_tower_interface_print_temp.get_at(new_filament_id); if (interface_temp == -1) - interface_temp = full_config.nozzle_temperature_range_high.get_at(new_filament_id); + interface_temp = full_config.nozzle_temperature_range_high.get_at(new_fi); if (full_config.enable_tower_interface_features && tcr.is_contact) new_filament_temp = interface_temp; config.set_key_value("new_filament_temp", new ConfigOptionInt(new_filament_temp)); @@ -1309,7 +1309,7 @@ static std::vector get_path_of_change_filament(const Print& print) flush_temps[idx] = use_fast_flush ? m_print_config->filament_flush_temp_fast.get_at(fi) : m_print_config->filament_flush_temp.get_at(fi); if (flush_temps[idx] == 0) - flush_temps[idx] = m_print_config->nozzle_temperature_range_high.get_at(idx); + flush_temps[idx] = m_print_config->nozzle_temperature_range_high.get_at(fi); filament_cooling_before_tower[idx] = m_print_config->filament_cooling_before_tower.get_at(fi); } if (tcr.is_contact || gcodegen.m_layer_index == 0) @@ -1563,7 +1563,7 @@ static std::vector get_path_of_change_filament(const Print& print) const bool will_go_down = !is_approx(z, current_z); const bool is_ramming = (gcodegen.config().single_extruder_multi_material) || (!gcodegen.config().single_extruder_multi_material && - gcodegen.config().filament_multitool_ramming.get_at(tcr.initial_tool)); + gcodegen.config().filament_multitool_ramming.get_at(gcodegen.get_filament_config_index(tcr.initial_tool))); // Orca: user-facing override (Printer Settings > Wipe tower > "Tool change on wipe tower"). // Forces the toolhead to travel over the wipe tower before issuing Tx even on multi-toolhead // printers without ramming, where Orca would otherwise emit Tx in place (potentially over the part). @@ -1620,7 +1620,7 @@ static std::vector get_path_of_change_filament(const Print& print) if (gcodegen.config().enable_tower_interface_features && tcr.is_contact) { interface_temp = gcodegen.config().filament_tower_interface_print_temp.get_at(new_extruder_id); if (interface_temp == -1) - interface_temp = gcodegen.config().nozzle_temperature_range_high.get_at(new_extruder_id); + interface_temp = gcodegen.config().nozzle_temperature_range_high.get_at(gcodegen.get_filament_config_index(new_extruder_id)); toolchange_temp_override = interface_temp; } toolchange_gcode_str = gcodegen.set_extruder(new_extruder_id, tcr.print_z, false, toolchange_temp_override, @@ -4342,6 +4342,12 @@ size_t GCode::get_filament_config_index(int filament_id) const return filament_id; } +size_t GCode::get_filament_config_index(int filament_id, size_t layer_id) const +{ + // Orca: uncached, as the stages after the generator run concurrently with it. + return m_print ? m_print->get_filament_config_indx(filament_id, (int) layer_id, false) : filament_id; +} + size_t GCode::get_nozzle_config_index(int filament_id) const { if (m_print) { @@ -9409,10 +9415,13 @@ void GCode::update_placeholder_parser_with_variant_params() // Helper: remap config arrays from variant index space to filament_id index space. // After remapping, gcode templates can use param[filament_id] directly. + std::vector config_index(num_filaments); + for (size_t i = 0; i < num_filaments; ++i) + config_index[i] = get_filament_config_index(i); auto remap_by_filament = [&](const auto &src) { std::decay_t dst(num_filaments); for (size_t i = 0; i < num_filaments; ++i) - dst[i] = src.get_at(get_filament_config_index(i)); + dst[i] = src.get_at(config_index[i]); return dst; }; @@ -9427,6 +9436,16 @@ void GCode::update_placeholder_parser_with_variant_params() this->placeholder_parser().set("first_layer_temperature", new ConfigOptionInts(remap_by_filament(m_config.nozzle_temperature_initial_layer))); this->placeholder_parser().set("pressure_advance", new ConfigOptionFloats(remap_by_filament(m_config.pressure_advance))); this->placeholder_parser().set("enable_pressure_advance", new ConfigOptionBools(remap_by_filament(m_config.enable_pressure_advance))); + this->placeholder_parser().set("fan_min_speed", new ConfigOptionFloats(remap_by_filament(m_config.fan_min_speed))); + this->placeholder_parser().set("fan_max_speed", new ConfigOptionFloats(remap_by_filament(m_config.fan_max_speed))); + this->placeholder_parser().set("additional_cooling_fan_speed", new ConfigOptionInts(remap_by_filament(m_config.additional_cooling_fan_speed))); + this->placeholder_parser().set("filament_minimal_purge_on_wipe_tower", new ConfigOptionFloats(remap_by_filament(m_config.filament_minimal_purge_on_wipe_tower))); + this->placeholder_parser().set("filament_multitool_ramming", new ConfigOptionBools(remap_by_filament(m_config.filament_multitool_ramming))); + this->placeholder_parser().set("filament_multitool_ramming_volume", new ConfigOptionFloats(remap_by_filament(m_config.filament_multitool_ramming_volume))); + this->placeholder_parser().set("filament_multitool_ramming_flow", new ConfigOptionFloats(remap_by_filament(m_config.filament_multitool_ramming_flow))); + this->placeholder_parser().set("nozzle_temperature_range_low", new ConfigOptionInts(remap_by_filament(m_config.nozzle_temperature_range_low))); + const auto nozzle_temperature_range_high = remap_by_filament(m_config.nozzle_temperature_range_high); + this->placeholder_parser().set("nozzle_temperature_range_high", new ConfigOptionInts(nozzle_temperature_range_high)); // --- printer_options_with_variant_1: in m_config these are already merged as filament-indexed --- this->placeholder_parser().set("retraction_distances_when_cut", new ConfigOptionFloats(remap_by_filament(m_config.retraction_distances_when_cut))); @@ -9447,7 +9466,7 @@ void GCode::update_placeholder_parser_with_variant_params() if (flush_v_speed[i] == 0) flush_v_speed[i] = filament_max_v[i]; if (flush_temps[i] == 0) - flush_temps[i] = m_config.nozzle_temperature_range_high.get_at(i); + flush_temps[i] = nozzle_temperature_range_high[i]; } this->placeholder_parser().set("flush_volumetric_speeds", new ConfigOptionFloats(flush_v_speed)); this->placeholder_parser().set("flush_temperatures", new ConfigOptionInts(flush_temps)); @@ -9706,7 +9725,7 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo { int interface_temp = m_config.filament_tower_interface_print_temp.get_at(new_filament_id); if (interface_temp == -1) - interface_temp = m_config.nozzle_temperature_range_high.get_at(new_filament_id); + interface_temp = m_config.nozzle_temperature_range_high.get_at(new_fi); dyn_config.set_key_value("filament_tower_interface_print_temp", new ConfigOptionInt(interface_temp)); } if (toolchange_temp_override > 0) { @@ -9745,7 +9764,7 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo flush_temps[idx] = use_fast_flush ? m_print->config().filament_flush_temp_fast.get_at(fi) : m_print->config().filament_flush_temp.get_at(fi); if (flush_temps[idx] == 0) - flush_temps[idx] = m_print->config().nozzle_temperature_range_high.get_at(idx); + flush_temps[idx] = m_print->config().nozzle_temperature_range_high.get_at(fi); filament_cooling_before_tower[idx] = m_print->config().filament_cooling_before_tower.get_at(fi); } std::fill(filament_cooling_before_tower.begin(), filament_cooling_before_tower.end(), 0); diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index bded77d9d1..6516a3f6fd 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -296,6 +296,9 @@ public: // resolver keys filament-indexed arrays, the nozzle resolver keys (extruder x volume-type) // slot arrays. Both degenerate to filament_id / extruder index on single-volume printers. size_t get_filament_config_index(int filament_id) const; + // The filament resolver for a given layer, for the export pipeline stages after the generator, + // which run behind the current layer and concurrently with the generator. + size_t get_filament_config_index(int filament_id, size_t layer_id) const; size_t get_nozzle_config_index(int filament_id) const; // Object and support extrusions of the same PrintObject at the same print_z. diff --git a/src/libslic3r/GCode/CoolingBuffer.cpp b/src/libslic3r/GCode/CoolingBuffer.cpp index e55b89212e..7f6e9c67d5 100644 --- a/src/libslic3r/GCode/CoolingBuffer.cpp +++ b/src/libslic3r/GCode/CoolingBuffer.cpp @@ -18,7 +18,7 @@ namespace Slic3r { -CoolingBuffer::CoolingBuffer(GCode &gcodegen) : m_config(gcodegen.config()), m_toolchange_prefix(gcodegen.writer().toolchange_prefix()), m_current_extruder(0), m_current_nozzle(0) +CoolingBuffer::CoolingBuffer(GCode &gcodegen) : m_config(gcodegen.config()), m_gcodegen(gcodegen), m_toolchange_prefix(gcodegen.writer().toolchange_prefix()), m_current_extruder(0), m_current_nozzle(0) { this->reset(gcodegen.writer().get_position()); @@ -737,10 +737,12 @@ std::string CoolingBuffer::apply_layer_cooldown( &ironing_fan_control, &ironing_fan_speed ](bool immediately_apply) { #define EXTRUDER_CONFIG(OPT) m_config.OPT.get_at(m_current_extruder) - float fan_min_speed = EXTRUDER_CONFIG(fan_min_speed); + // The per-variant options take the extruder variant the filament prints with on this layer + const size_t config_index = m_gcodegen.get_filament_config_index(m_current_extruder, layer_id); + float fan_min_speed = m_config.fan_min_speed.get_at(config_index); float fan_speed_new = EXTRUDER_CONFIG(reduce_fan_stop_start_freq) ? fan_min_speed : 0; //BBS - int additional_fan_speed_new = EXTRUDER_CONFIG(additional_cooling_fan_speed); + int additional_fan_speed_new = m_config.additional_cooling_fan_speed.get_at(config_index); int close_fan_the_first_x_layers = EXTRUDER_CONFIG(close_fan_the_first_x_layers); // Is the fan speed ramp enabled? int full_fan_speed_layer = EXTRUDER_CONFIG(full_fan_speed_layer); @@ -776,7 +778,7 @@ std::string CoolingBuffer::apply_layer_cooldown( // additional_fan_speed_new is left at its configured value (auxiliary fan is independent of the // part-cooling override). } else if (int(layer_id) >= close_fan_the_first_x_layers) { - float fan_max_speed = EXTRUDER_CONFIG(fan_max_speed); + float fan_max_speed = m_config.fan_max_speed.get_at(config_index); float slow_down_layer_time = float(EXTRUDER_CONFIG(slow_down_layer_time)); float fan_cooling_layer_time = float(EXTRUDER_CONFIG(fan_cooling_layer_time)); //BBS: always enable the fan speed interpolation according to layer time diff --git a/src/libslic3r/GCode/CoolingBuffer.hpp b/src/libslic3r/GCode/CoolingBuffer.hpp index 9b0a5ab9df..742b8f78b7 100644 --- a/src/libslic3r/GCode/CoolingBuffer.hpp +++ b/src/libslic3r/GCode/CoolingBuffer.hpp @@ -54,6 +54,8 @@ private: // Referencs GCode::m_config, which is FullPrintConfig. While the PrintObjectConfig slice of FullPrintConfig is being modified, // the PrintConfig slice of FullPrintConfig is constant, thus no thread synchronization is required. const PrintConfig &m_config; + // Resolves the filament config index of the per-variant options. + const GCode &m_gcodegen; unsigned int m_current_extruder; unsigned int m_current_nozzle; //BBS: current fan speed diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index 7ea46cf8a7..5026323d54 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -1230,15 +1230,21 @@ void ToolOrdering::cal_most_used_extruder(const PrintConfig &config) float ToolOrdering::cal_max_additional_fan(const PrintConfig &config) { - // record + std::set used_filaments; + for (const LayerTools &layer_tools : m_layer_tools) + used_filaments.insert(layer_tools.extruders.begin(), layer_tools.extruders.end()); + if (used_filaments.empty()) + return 0; + + // Orca: additional_cooling_fan_speed can hold one value per extruder variant a filament prints with; + // filament_self_index maps such a column to its filament. + const std::vector &self_index = config.filament_self_index.values; + const size_t columns = std::max(config.additional_cooling_fan_speed.size(), size_t(*used_filaments.rbegin()) + 1); float max_fan = 0; - for (LayerTools &layer_tools : m_layer_tools) { - std::vector filaments = layer_tools.extruders; - std::set layer_extruder_count; - // count once only - for (unsigned int &filament : filaments) - if (max_fan < config.additional_cooling_fan_speed.get_at(filament)) - max_fan = config.additional_cooling_fan_speed.get_at(filament); + for (size_t column = 0; column < columns; ++column) { + const unsigned int filament_id = self_index.size() == columns ? self_index[column] - 1 : column; + if (used_filaments.count(filament_id) && max_fan < config.additional_cooling_fan_speed.get_at(column)) + max_fan = config.additional_cooling_fan_speed.get_at(column); } return max_fan; } diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index be4e217d5c..5f5592cfce 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -4329,9 +4329,9 @@ bool Print::is_dynamic_group_reorder() const return true; } -int Print::get_filament_config_indx(int filament_id, int layer_id) +int Print::get_filament_config_indx(int filament_id, int layer_id, bool use_cache) { - return get_config_index(filament_id, layer_id, m_config.filament_extruder_variant.values, m_filament_self_index, m_filament_index_map); + return get_config_index(filament_id, layer_id, m_config.filament_extruder_variant.values, m_filament_self_index, use_cache ? &m_filament_index_map : nullptr); } void Print::update_filament_self_index_cache() @@ -4374,7 +4374,7 @@ int Print::get_nozzle_config_index(int filament_id, int layer_id) return get_config_index(filament_id, layer_id, m_default_region_config.print_extruder_variant.values, m_default_region_config.print_extruder_id.values, m_nozzle_index_map); } -int Print::get_config_index(int filament_id, int layer_id, const std::vector &variant_list, const std::vector& self_index_list, FilamentIndexMap &index_map) +int Print::get_config_index(int filament_id, int layer_id, const std::vector &variant_list, const std::vector& self_index_list, FilamentIndexMap *index_map) { auto group_result = get_layered_nozzle_group_result(); // Orca: defensive — when no grouping producer has published a result yet, fall back to the @@ -4385,7 +4385,8 @@ int Print::get_config_index(int filament_id, int layer_id, const std::vectorextruder_id)); NozzleVolumeType nozzle_volume_type = nozzle_info->volume_type; + if (!index_map) + return get_config_index_base(nozzle_volume_type, extruder_type, filament_id + 1, variant_list, self_index_list); FilamentIndexKey key{filament_id, extruder_type, nozzle_volume_type}; - auto iter = index_map.find(key); - if (iter == index_map.end()) { + auto iter = index_map->find(key); + if (iter == index_map->end()) { int index = get_config_index_base(nozzle_volume_type, extruder_type, filament_id + 1, variant_list, self_index_list); - index_map[key] = index; + (*index_map)[key] = index; return index; } else { - return index_map[key]; + return iter->second; } } diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index dc4323e537..f185962b1e 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -1222,7 +1222,9 @@ public: // Post-slicing config-slot resolvers: map a (filament, layer) pair to the index of its // per-(extruder x volume type) column in the expanded variant arrays, cached by grouping context. - int get_filament_config_indx(int filament_id, int layer_id); + // Orca: without use_cache, the filament resolver leaves the cache alone, for the G-code export + // pipeline's cooling stage, which runs concurrently with the generator stage filling it. + int get_filament_config_indx(int filament_id, int layer_id, bool use_cache = true); int get_nozzle_config_index(int filament_id, int layer_id); // Orca: Implement prusa's filament shrink compensation approach @@ -1282,7 +1284,7 @@ protected: }; using FilamentIndexMap = std::unordered_map; using PrintIndexMap = std::unordered_map; - int get_config_index(int filament_id, int layer_id, const std::vector &variant_list, const std::vector& self_index_list, FilamentIndexMap &index_map); + int get_config_index(int filament_id, int layer_id, const std::vector &variant_list, const std::vector& self_index_list, FilamentIndexMap *index_map); int get_config_index(int filament_id, int layer_id, const std::vector &variant_list, const std::vector& self_index_list, PrintIndexMap &index_map); // Invalidates the step, and its depending steps in Print. diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 9eb1e95e5d..58bfc60852 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -9463,17 +9463,6 @@ std::set print_options_with_variant = { std::set filament_options_with_variant = { "filament_flow_ratio", "filament_max_volumetric_speed", - "enable_pressure_advance", - "pressure_advance", - "fan_min_speed", - "fan_max_speed", - "additional_cooling_fan_speed", - "filament_minimal_purge_on_wipe_tower", - "filament_multitool_ramming", - "filament_multitool_ramming_volume", - "filament_multitool_ramming_flow", - "nozzle_temperature_range_low", - "nozzle_temperature_range_high", // Per-variant ramming / pre-cooling / nozzle-change filament overrides "filament_ramming_volumetric_speed", "filament_pre_cooling_temperature", @@ -9527,6 +9516,16 @@ std::set filament_options_with_variant = { "adaptive_pressure_advance_model", "adaptive_pressure_advance_overhangs", "adaptive_pressure_advance_bridges", + // Orca: cooling fans, multi-tool ramming and recommended nozzle temperature range + "fan_min_speed", + "fan_max_speed", + "additional_cooling_fan_speed", + "filament_minimal_purge_on_wipe_tower", + "filament_multitool_ramming", + "filament_multitool_ramming_volume", + "filament_multitool_ramming_flow", + "nozzle_temperature_range_low", + "nozzle_temperature_range_high", "activate_air_filtration", "activate_air_filtration_during_print", "activate_air_filtration_on_completion", diff --git a/tests/fff_print/test_multifilament.cpp b/tests/fff_print/test_multifilament.cpp index c39efaccf5..445b1c0694 100644 --- a/tests/fff_print/test_multifilament.cpp +++ b/tests/fff_print/test_multifilament.cpp @@ -893,3 +893,65 @@ TEST_CASE("Each filament sets the pressure advance of its extruder variant on a CHECK(gcode.find("; start pressure advance " + pressure_advance + "\n") != std::string::npos); } } + +// The speeds, in percent, a G-code turns a fan on at: the part cooling fan for `M106 S`, the auxiliary +// fan for `M106 P2 S`. +static std::set fan_speeds(const std::string &gcode, const std::string &command) +{ + std::set speeds; + std::istringstream stream(gcode); + for (std::string line; std::getline(stream, line);) + if (line.rfind(command, 0) == 0) + if (const int pwm = std::stoi(line.substr(command.size())); pwm > 0) + speeds.insert(int(std::lround(pwm * 100. / 255.))); + return speeds; +} + +// The fan speeds and the recommended nozzle temperature range are tuned per extruder variant like the +// other filament variant settings. +TEST_CASE("Each filament cools with the fan speeds of its extruder variant", "[MultiFilament]") +{ + auto [nozzle_volume_type, filament, fan_min_speed, fan_max_speed, additional_fan_speed, range_high] = GENERATE(table({ + { nvtStandard, 1, 15, 25, 10, 240 }, + { nvtHighFlow, 1, 35, 45, 20, 260 }, + { nvtHighFlow, 2, 55, 65, 40, 280 }, // filament 2 defines no High Flow variant + })); + // Layers printed faster than slow_down_layer_time run the fan at its maximum speed, layers slower than + // fan_cooling_layer_time at its minimum. + const bool fast_layers = GENERATE(false, true); + DYNAMIC_SECTION(get_nozzle_volume_type_string(nozzle_volume_type) << " nozzle, filament " << filament << (fast_layers ? ", fast layers" : ", slow layers")) { + DynamicPrintConfig config = multifilament_config(2, { + { "extruder_variant_list", "Direct Drive Standard,Direct Drive High Flow" }, + // filament 1 defines Standard and High Flow, filament 2 Standard + { "filament_extruder_variant", "Direct Drive Standard;Direct Drive High Flow;Direct Drive Standard" }, + { "filament_self_index", "1,1,2" }, + { "fan_min_speed", "15,35,55" }, + { "fan_max_speed", "25,45,65" }, + { "additional_cooling_fan_speed", "10,20,40" }, + { "nozzle_temperature_range_high", "240,260,280" }, + { "auxiliary_fan", 1 }, + { "reduce_fan_stop_start_freq", "1,1" }, + { "slow_down_layer_time", fast_layers ? "1000,1000" : "0,0" }, + { "fan_cooling_layer_time", fast_layers ? "1000,1000" : "0,0" }, + { "slow_down_for_layer_cooling", "0,0" }, + { "enable_overhang_bridge_fan", "0,0" }, + { "sparse_infill_filament_id", filament }, + { "internal_solid_filament_id", filament }, + { "top_surface_filament_id", filament }, + { "bottom_surface_filament_id", filament }, + { "outer_wall_filament_id", filament }, + { "inner_wall_filament_id", filament }, + { "enable_prime_tower", 0 }, + { "skirt_loops", 0 }, + { "brim_type", "no_brim" }, + // custom G-code indexes the per-filament arrays by filament + { "machine_start_gcode", "; start range high {nozzle_temperature_range_high[initial_extruder]}" }, + }); + config.option("nozzle_volume_type", true)->values = { nozzle_volume_type }; + const std::string gcode = slice({ cube(20) }, config); + + CHECK(fan_speeds(gcode, "M106 S") == std::set{ fast_layers ? fan_max_speed : fan_min_speed }); + CHECK(fan_speeds(gcode, "M106 P2 S") == std::set{ additional_fan_speed }); + CHECK(gcode.find("; start range high " + std::to_string(range_high) + "\n") != std::string::npos); + } +} diff --git a/tests/libslic3r/test_config_variant_expansion.cpp b/tests/libslic3r/test_config_variant_expansion.cpp index 17cf7fc305..f30ad985e3 100644 --- a/tests/libslic3r/test_config_variant_expansion.cpp +++ b/tests/libslic3r/test_config_variant_expansion.cpp @@ -52,20 +52,18 @@ TEST_CASE("Filament cooling and pressure settings follow the selected nozzle var {"nozzle_temperature_range_high", "255", "280"}, }; const int variant_index = GENERATE(0, 1, 2, 3); - const int value_count = 4; const bool load_preset = GENERATE(false, true); const bool high_flow = variant_index % 2 != 0; for (const Setting &setting : settings) { - DYNAMIC_SECTION(setting.key << " variant=" << variant_index << " values=" << value_count << " loaded=" << load_preset) { + DYNAMIC_SECTION(setting.key << " variant=" << variant_index << " loaded=" << load_preset) { DynamicPrintConfig printer = make_hybrid_printer_config(); if (variant_index >= 2) printer.option("extruder_type")->values[1] = etBowden; DynamicPrintConfig filament; filament.option("filament_extruder_variant", true)->values = {"Direct Drive Standard", "Direct Drive High Flow", "Bowden Standard", "Bowden High Flow"}; - std::string values = setting.standard; - for (int i = 1; i < value_count; ++i) - values += std::string(",") + (i % 2 ? setting.high_flow : setting.standard); + // one value per variant of filament_extruder_variant + const std::string values = std::string(setting.standard) + "," + setting.high_flow + "," + setting.standard + "," + setting.high_flow; REQUIRE(filament.option(setting.key, true)->deserialize(values)); if (load_preset) { @@ -88,35 +86,6 @@ TEST_CASE("Filament cooling and pressure settings follow the selected nozzle var } } -TEST_CASE("Filaments on the same hybrid tool keep their own cooling and pressure variants", "[Config][FilamentVariants]") -{ - DynamicPrintConfig config = make_hybrid_printer_config(); - config.option("filament_self_index", true)->values = {1, 1, 2, 2}; - config.option("filament_extruder_variant", true)->values = - {"Direct Drive Standard", "Direct Drive High Flow", "Direct Drive Standard", "Direct Drive High Flow"}; - config.option("filament_map", true)->values = {2, 2}; - config.option("filament_volume_map", true)->values = {nvtHighFlow, nvtStandard}; - config.option("fan_max_speed", true)->values = {15., 60., 20., 80.}; - config.option("pressure_advance", true)->values = {0.04, 0.02, 0.05, 0.03}; - config.option("filament_multitool_ramming", true)->values = {false, true, false, true}; - std::vector> nozzle_types; - const int count = config.get_extruder_nozzle_volume_count(2, nozzle_types); - std::set keys = filament_options_with_variant; - keys.insert("filament_self_index"); - config.update_values_to_printer_extruders_for_multiple_filaments(config, 2, count, keys, - "filament_self_index", "filament_extruder_variant"); - const auto &fan = config.option("fan_max_speed")->values; - REQUIRE(fan.size() == 2); - REQUIRE_THAT(fan[0], Catch::Matchers::WithinAbs(60., 1e-9)); - REQUIRE_THAT(fan[1], Catch::Matchers::WithinAbs(20., 1e-9)); - const auto &pa = config.option("pressure_advance")->values; - REQUIRE(pa.size() == 2); - REQUIRE_THAT(pa[0], Catch::Matchers::WithinAbs(0.02, 1e-9)); - REQUIRE_THAT(pa[1], Catch::Matchers::WithinAbs(0.05, 1e-9)); - REQUIRE(config.option("filament_multitool_ramming")->get_at(0)); - REQUIRE_FALSE(config.option("filament_multitool_ramming")->get_at(1)); -} - TEST_CASE("apply_override fills nil entries from the 0-based default index", "[Config]") { ConfigOptionFloats machine({10., 20., 30.}); @@ -495,6 +464,8 @@ TEST_CASE("update_values_to_printer_extruders_for_multiple_filaments resolves pe config.option("filament_extruder_variant", true)->values = {"Direct Drive Standard", "Direct Drive High Flow", "Direct Drive Standard", "Direct Drive High Flow"}; config.option("filament_max_volumetric_speed", true)->values = {12., 20., 13., 21.}; + config.option("fan_max_speed", true)->values = {15., 60., 20., 80.}; + config.option("filament_multitool_ramming", true)->values = {false, true, false, true}; }; std::set filament_keys = filament_options_with_variant; @@ -514,6 +485,8 @@ TEST_CASE("update_values_to_printer_extruders_for_multiple_filaments resolves pe "filament_self_index", "filament_extruder_variant"); REQUIRE(config.option("filament_max_volumetric_speed")->values == std::vector({12., 21.})); + REQUIRE(config.option("fan_max_speed")->values == std::vector({15., 80.})); + REQUIRE(config.option("filament_multitool_ramming")->values == std::vector({0, 1})); REQUIRE(config.option("filament_extruder_variant")->values == std::vector({"Direct Drive Standard", "Direct Drive High Flow"})); REQUIRE(config.option("filament_self_index")->values == std::vector({1, 2})); diff --git a/tests/libslic3r/test_toolordering_nozzle_group.cpp b/tests/libslic3r/test_toolordering_nozzle_group.cpp index d9a5d70406..4074a80995 100644 --- a/tests/libslic3r/test_toolordering_nozzle_group.cpp +++ b/tests/libslic3r/test_toolordering_nozzle_group.cpp @@ -948,6 +948,9 @@ TEST_CASE("Filaments ordered after a migrator shift columns and the resolver tra config.option("nozzle_temperature", true)->values = {200, 210, 220, 230, 240, 250}; config.option("filament_retraction_length", true)->values = {0.5, 0.5, 0.7, 0.9, 1.4, 1.4}; config.option("retraction_length", true)->values = {0.8, 0.9, 1.0, 1.1}; + config.option("fan_max_speed", true)->values = {10, 10, 20, 60, 30, 30}; + config.option("additional_cooling_fan_speed", true)->values = {1, 1, 2, 6, 3, 3}; + config.option("nozzle_temperature_range_high", true)->values = {230, 230, 240, 280, 250, 250}; Model model; model.add_object("cube", "", make_cube(20, 20, 20))->add_instance(); @@ -988,6 +991,21 @@ TEST_CASE("Filaments ordered after a migrator shift columns and the resolver tra REQUIRE(merged.size() == 4); REQUIRE_THAT(merged[3], Catch::Matchers::WithinAbs(1.4, 1e-9)); REQUIRE_THAT(merged[2], Catch::Matchers::WithinAbs(0.9, 1e-9)); + + // The cooling and temperature range options follow the variant as well. + const PrintConfig &resolved = print.config(); + REQUIRE(resolved.fan_max_speed.values == std::vector{10, 20, 60, 30}); + CHECK(resolved.fan_max_speed.get_at(print.get_filament_config_indx(1, 0)) == 20); + CHECK(resolved.fan_max_speed.get_at(print.get_filament_config_indx(1, 1)) == 60); + CHECK(resolved.additional_cooling_fan_speed.get_at(print.get_filament_config_indx(2, 1)) == 3); + CHECK(resolved.nozzle_temperature_range_high.get_at(print.get_filament_config_indx(2, 1)) == 250); + // The auxiliary fan maximum takes every variant of the filaments used, and only theirs. + ToolOrdering ordering; + ordering.layer_tools().emplace_back(0.2); + ordering.layer_tools().back().extruders = {0, 2}; + CHECK(ordering.cal_max_additional_fan(resolved) == 3); + ordering.layer_tools().back().extruders = {1}; + CHECK(ordering.cal_max_additional_fan(resolved) == 6); } TEST_CASE("Selector slicing keeps the result valid across re-apply", "[Print][H2C][Dynamic]")