Add nozzle flow variant & make some options multi-variant (#13712)

# Description

Port BBS per-extruder config variants toggle, thanks Bambu!

Also fix invalid num error when resetting multi-variant filament
overrides.

TODOs:

- [x] Make more configs multi-variant (such as speeds)
- [x] Add flow variant (normal/high flow) combo box
- [x] Add botton to sync config to other variant


# Screenshots/Recordings/Graphs

<img width="846" height="1494" alt="image"
src="https://github.com/user-attachments/assets/47abf053-f5b8-4c86-ac0b-c0323ed8b242"
/>

<img width="1478" height="1189" alt="707420e5be01c30af3e6ede1f3dc9b67"
src="https://github.com/user-attachments/assets/11268712-da65-42ab-9cb8-3cede7790a5c"
/>

<img width="1478" height="1189" alt="81d5d3877f4d5bf9dccd44d7f0b30aa7"
src="https://github.com/user-attachments/assets/cda5ea51-07c3-48fc-bfbb-1428dca14e26"
/>


## Tests

<!--
> Please describe the tests that you have conducted to verify the
changes made in this PR.
-->

<!--
> A guide for users on how to download the artifacts from this PR.
-->

[How to Download Pull Requests Artifacts for
Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts)
Fix #10336
This commit is contained in:
SoftFever
2026-06-28 22:30:40 +08:00
committed by GitHub
53 changed files with 2727 additions and 1353 deletions
+88 -17
View File
@@ -89,6 +89,73 @@ wxString get_nozzle_volume_type_name(NozzleVolumeType type)
return wxString();
}
void update_speed_parameter( const std::string& key)
{
auto preset_bundle = wxGetApp().preset_bundle;
auto& printer_config = preset_bundle->printers.get_edited_preset().config;
auto& filament_config = preset_bundle->filaments.get_edited_preset().config;
auto& print_config = preset_bundle->prints.get_edited_preset().config;
int extruder_nums = preset_bundle->get_printer_extruder_count();
std::vector<int> extruder_types = printer_config.option<ConfigOptionEnumsGeneric>("extruder_type")->values;
std::vector<int> nozzle_volume_types = preset_bundle->project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type")->values;
float nozzle_diameter = printer_config.option<ConfigOptionFloats>("nozzle_diameter")->values[0];
float layer_height = print_config.option<ConfigOptionFloat>("layer_height")->value;
float line_width = print_config.get_abs_value("line_width", nozzle_diameter);
if (line_width <= 0.) line_width = Flow::auto_extrusion_width(frPerimeter, nozzle_diameter);
Flow flow = Flow(line_width, layer_height, nozzle_diameter);
for (size_t i = 0; i < extruder_nums; ++i) {
int index = get_index_for_extruder_parameter(filament_config, "filament_max_volumetric_speed", i, ExtruderType(extruder_types[i]), NozzleVolumeType(nozzle_volume_types[i]));
double filament_max_volumetric_speed = filament_config.option<ConfigOptionFloats>("filament_max_volumetric_speed")->get_at(index);
double max_speed = filament_max_volumetric_speed / flow.mm3_per_mm();
index = get_index_for_extruder_parameter(print_config, key, i, ExtruderType(extruder_types[i]), NozzleVolumeType(nozzle_volume_types[i]));
ConfigOptionFloatsNullable *speed_opt = print_config.option<ConfigOptionFloatsNullable>(key);
speed_opt->values[index] = max_speed;
}
}
std::vector<double> generate_max_speed_parameter_value(const std::string &key, const bool linear, const int pass)
{
auto preset_bundle = wxGetApp().preset_bundle;
auto &printer_config = preset_bundle->printers.get_edited_preset().config;
auto &filament_config = preset_bundle->filaments.get_edited_preset().config;
auto &print_config = preset_bundle->prints.get_edited_preset().config;
int extruder_nums = preset_bundle->get_printer_extruder_count();
std::vector<int> extruder_types = printer_config.option<ConfigOptionEnumsGeneric>("extruder_type")->values;
std::vector<int> nozzle_volume_types = preset_bundle->project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type")->values;
float nozzle_diameter = printer_config.option<ConfigOptionFloats>("nozzle_diameter")->values[0];
float layer_height = print_config.option<ConfigOptionFloat>("layer_height")->value;
float line_width = print_config.get_abs_value("line_width", nozzle_diameter);
Flow flow = Flow(line_width, layer_height, nozzle_diameter);
std::vector<double> speed_values;
speed_values.reserve(extruder_nums * nozzle_volume_types.size());
for (size_t i = 0; i < extruder_nums; ++i) {
int index = get_index_for_extruder_parameter(filament_config, "filament_max_volumetric_speed", i, ExtruderType(extruder_types[i]),
NozzleVolumeType(nozzle_volume_types[i]));
double filament_max_volumetric_speed = filament_config.option<ConfigOptionFloats>("filament_max_volumetric_speed")->get_at(index);
double cur_flowrate = filament_config.option<ConfigOptionFloats>("filament_flow_ratio")->get_at(index);
double max_speed = linear ? filament_max_volumetric_speed / (flow.mm3_per_mm() * (cur_flowrate + (pass == 2 ? 0.035 : 0.05)) / cur_flowrate) :
filament_max_volumetric_speed / (flow.mm3_per_mm() * (pass == 1 ? 1.2 : 1));
index = get_index_for_extruder_parameter(print_config, key, i, ExtruderType(extruder_types[i]), NozzleVolumeType(nozzle_volume_types[i]));
ConfigOptionFloatsNullable *speed_opt = print_config.option<ConfigOptionFloatsNullable>(key);
double speed_value = std::floor(std::min(speed_opt->values[index], max_speed));
for (size_t v_id = 0; v_id < nozzle_volume_types.size(); ++v_id) {
speed_values.emplace_back(speed_value);
}
}
return speed_values;
}
static int get_physical_extruder_idx(std::vector<int> physical_extruder_maps, int extruder_id)
{
for (size_t index = 0; index < physical_extruder_maps.size(); ++index) {
@@ -646,8 +713,8 @@ bool CalibUtils::calib_flowrate(int pass, const CalibInfo &calib_info, wxString
int index = get_index_for_extruder_parameter(filament_config, "filament_max_volumetric_speed", calib_info.extruder_id, calib_info.extruder_type, calib_info.nozzle_volume_type);
double filament_max_volumetric_speed = filament_config.option<ConfigOptionFloats>("filament_max_volumetric_speed")->get_at(index);
double max_infill_speed = filament_max_volumetric_speed / (infill_flow.mm3_per_mm() * (pass == 1 ? 1.2 : 1));
double internal_solid_speed = std::floor(std::min(print_config.opt_float("internal_solid_infill_speed"), max_infill_speed));
double top_surface_speed = std::floor(std::min(print_config.opt_float("top_surface_speed"), max_infill_speed));
double internal_solid_speed = std::floor(std::min(print_config.opt_float_nullable("internal_solid_infill_speed", 0), max_infill_speed));
double top_surface_speed = std::floor(std::min(print_config.opt_float_nullable("top_surface_speed", 0), max_infill_speed));
// adjust parameters
filament_config.set_key_value("curr_bed_type", new ConfigOptionEnum<BedType>(calib_info.bed_type));
@@ -668,8 +735,8 @@ bool CalibUtils::calib_flowrate(int pass, const CalibInfo &calib_info, wxString
_obj->config.set_key_value("top_solid_infill_flow_ratio", new ConfigOptionFloat(1.0f));
_obj->config.set_key_value("infill_direction", new ConfigOptionFloat(45));
_obj->config.set_key_value("ironing_type", new ConfigOptionEnum<IroningType>(IroningType::NoIroning));
_obj->config.set_key_value("internal_solid_infill_speed", new ConfigOptionFloat(internal_solid_speed));
_obj->config.set_key_value("top_surface_speed", new ConfigOptionFloat(top_surface_speed));
_obj->config.set_key_value("internal_solid_infill_speed", new ConfigOptionFloatsNullable({internal_solid_speed}));
_obj->config.set_key_value("top_surface_speed", new ConfigOptionFloatsNullable({top_surface_speed}));
// extract flowrate from name, filename format: flowrate_xxx
std::string obj_name = _obj->name;
@@ -720,14 +787,14 @@ void CalibUtils::calib_pa_pattern(const CalibInfo &calib_info, Model& model)
float nozzle_diameter = printer_config.option<ConfigOptionFloats>("nozzle_diameter")->get_at(0);
for (const auto& opt : config_pattern.float_pairs) {
print_config.set_key_value(opt.first, new ConfigOptionFloat(opt.second));
for (const auto& opt : config_pattern.floats_pairs) {
print_config.set_key_value(opt.first, new ConfigOptionFloatsNullable(opt.second));
}
print_config.set_key_value("outer_wall_speed",
new ConfigOptionFloat(CalibPressureAdvance::find_optimal_PA_speed(
full_config, print_config.get_abs_value("line_width"),
print_config.get_abs_value("layer_height"), calib_info.extruder_id, 0)));
int index = get_index_for_extruder_parameter(print_config, "outer_wall_speed", calib_info.extruder_id, calib_info.extruder_type, calib_info.nozzle_volume_type);
float wall_speed = CalibPressureAdvance::find_optimal_PA_speed(full_config, print_config.get_abs_value("line_width"), print_config.get_abs_value("layer_height"), calib_info.extruder_id, 0);
ConfigOptionFloatsNullable *wall_speed_speed_opt = print_config.option<ConfigOptionFloatsNullable>("outer_wall_speed");
wall_speed_speed_opt->values[index] = wall_speed;
for (const auto& opt : config_pattern.nozzle_ratio_pairs) {
print_config.set_key_value(opt.first, new ConfigOptionFloatOrPercent(nozzle_diameter * opt.second / 100, false));
@@ -770,7 +837,7 @@ void CalibUtils::set_for_auto_pa_model_and_config(const std::vector<CalibInfo> &
const auto& config_pattern = SuggestedConfigCalibPAPattern();
for (const auto& opt : config_pattern.float_pairs) { print_config.set_key_value(opt.first, new ConfigOptionFloat(opt.second)); }
for (const auto& opt : config_pattern.floats_pairs) { print_config.set_key_value(opt.first, new ConfigOptionFloatsNullable(opt.second)); }
std::vector<CalibInfo> sorted_calib_infos = calib_infos;
std::sort(sorted_calib_infos.begin(), sorted_calib_infos.end(), [](const CalibInfo &left_item, const CalibInfo &right_item) {
@@ -778,11 +845,15 @@ void CalibUtils::set_for_auto_pa_model_and_config(const std::vector<CalibInfo> &
});
for (const CalibInfo &calib_info : calib_infos) {
int index = get_index_for_extruder_parameter(print_config, "outer_wall_speed", calib_info.extruder_id, calib_info.extruder_type, calib_info.nozzle_volume_type);
float wall_speed = CalibPressureAdvance::find_optimal_PA_speed(full_config, print_config.get_abs_value("line_width"), print_config.get_abs_value("layer_height"),
calib_info.extruder_id, 0);
ConfigOptionFloatsNullable *wall_speed_speed_opt = print_config.option<ConfigOptionFloatsNullable>("outer_wall_speed");
std::vector<double> new_speeds = wall_speed_speed_opt->values;
new_speeds[index] = wall_speed;
ModelObject* object = model.objects[calib_info.index];
object->config.set_key_value("outer_wall_speed",
new ConfigOptionFloat(CalibPressureAdvance::find_optimal_PA_speed(
full_config, print_config.get_abs_value("line_width"),
print_config.get_abs_value("layer_height"), calib_info.extruder_id, 0)));
object->config.set_key_value("outer_wall_speed", new ConfigOptionFloatsNullable(new_speeds));
}
for (const auto& opt : config_pattern.nozzle_ratio_pairs) {
@@ -1123,7 +1194,7 @@ void CalibUtils::calib_max_vol_speed(const CalibInfo &calib_info, wxString &erro
filament_config.set_key_value("slow_down_layer_time", new ConfigOptionInts{0});
filament_config.set_key_value("curr_bed_type", new ConfigOptionEnum<BedType>(calib_info.bed_type));
print_config.set_key_value("enable_overhang_speed", new ConfigOptionBool{false});
print_config.set_key_value("enable_overhang_speed", new ConfigOptionBoolsNullable({false}));
print_config.set_key_value("timelapse_type", new ConfigOptionEnum<TimelapseType>(tlTraditional));
print_config.set_key_value("wall_loops", new ConfigOptionInt(1));
print_config.set_key_value("alternate_extra_wall", new ConfigOptionBool(false));
@@ -1185,7 +1256,7 @@ void CalibUtils::calib_VFA(const CalibInfo &calib_info, wxString &error_message)
filament_config.set_key_value("filament_max_volumetric_speed", new ConfigOptionFloats{200});
filament_config.set_key_value("curr_bed_type", new ConfigOptionEnum<BedType>(calib_info.bed_type));
print_config.set_key_value("enable_overhang_speed", new ConfigOptionBool{false});
print_config.set_key_value("enable_overhang_speed", new ConfigOptionBoolsNullable({false}));
print_config.set_key_value("timelapse_type", new ConfigOptionEnum<TimelapseType>(tlTraditional));
print_config.set_key_value("wall_loops", new ConfigOptionInt(1));
print_config.set_key_value("detect_thin_wall", new ConfigOptionBool(false));
+3
View File
@@ -95,5 +95,8 @@ extern void get_tray_ams_and_slot_id(MachineObject* obj, int in_tray_id, int &am
extern void get_default_k_n_value(const std::string &filament_id, float &k, float &n);
extern wxString get_nozzle_volume_type_name(NozzleVolumeType type);
extern void update_speed_parameter(const std::string &key);
extern std::vector<double> generate_max_speed_parameter_value(const std::string &key, bool linear, int pass);
}
}