Add multi-variant support to the app

This commit is contained in:
SoftFever
2026-09-28 19:08:35 +08:00
parent 2ccabb5695
commit 71bb400e46
27 changed files with 846 additions and 195 deletions
+51 -6
View File
@@ -626,7 +626,8 @@ static const t_config_enum_values s_keys_map_NozzleVolumeType = {
{ "Standard", nvtStandard },
{ "High Flow", nvtHighFlow },
{ "TPU High Flow", nvtTPUHighFlow },
{ "Hybrid", nvtHybrid }
{ "Hybrid", nvtHybrid },
{ "E3D High Flow", nvtE3DHighFlow }
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(NozzleVolumeType)
@@ -676,9 +677,34 @@ int get_config_index_base(NozzleVolumeType volume_type, ExtruderType extruder_ty
for (int index = 0; index < int(variant_list.size()); ++index) {
if (extruder_variant == variant_list[index] && variant_ids_1based[index] == variant_id_1based) { return index; }
}
// Without this variant, use the id's own first variant (usually Standard), not variant index 0,
// which belongs to the first filament or extruder.
for (int index = 0; index < int(variant_list.size()); ++index) {
if (variant_ids_1based[index] == variant_id_1based) { return index; }
}
return 0;
}
std::set<NozzleVolumeType> get_extruder_supported_nozzle_volume_types(const DynamicPrintConfig &printer_config, int extruder_id)
{
std::set<NozzleVolumeType> supported_types;
auto *variant_list = printer_config.option<ConfigOptionStrings>("extruder_variant_list");
auto *extruder_types = printer_config.option<ConfigOptionEnumsGeneric>("extruder_type");
if (!variant_list || !extruder_types || extruder_id < 0 ||
extruder_id >= (int) variant_list->values.size() || extruder_id >= (int) extruder_types->values.size())
return supported_types;
const ExtruderType extruder_type = ExtruderType(extruder_types->values[extruder_id]);
for (NozzleVolumeType volume_type : get_valid_nozzle_volume_type()) {
// An unsupported extruder type yields an empty name, which would match any list.
const std::string variant = get_extruder_variant_string(extruder_type, volume_type);
if (!variant.empty() && variant_list->values[extruder_id].find(variant) != std::string::npos)
supported_types.insert(volume_type);
}
return supported_types;
}
std::string get_nozzle_volume_type_string(NozzleVolumeType nozzle_volume_type)
{
if (nozzle_volume_type > nvtMaxNozzleVolumeType) {
@@ -5923,15 +5949,18 @@ void PrintConfigDef::init_fff_params()
def->label = "Nozzle Volume Type";
def->tooltip = "Nozzle volume type for extruders.";
def->enum_keys_map = &ConfigOptionEnum<NozzleVolumeType>::get_enum_values();
// Order must match the NozzleVolumeType enum values (Standard=0, High Flow=1, Hybrid=2, TPU High Flow=3).
// Listed in display order. A position is not the enum value (E3D High Flow is 5, after the reserved 4),
// so map a position to its NozzleVolumeType through enum_keys_map.
def->enum_values.push_back(L("Standard"));
def->enum_values.push_back(L("High Flow"));
def->enum_values.push_back(L("Hybrid"));
def->enum_values.push_back(L("TPU High Flow"));
def->enum_values.push_back(L("E3D High Flow"));
def->enum_labels.push_back(L("Standard"));
def->enum_labels.push_back(L("High Flow"));
def->enum_labels.push_back(L("Hybrid"));
def->enum_labels.push_back(L("TPU High Flow"));
def->enum_labels.push_back(L("E3D High Flow"));
def->mode = comSimple;
def->set_default_value(new ConfigOptionEnumsGeneric{ NozzleVolumeType::nvtStandard });
@@ -5944,10 +5973,12 @@ void PrintConfigDef::init_fff_params()
def->enum_values.push_back(L("High Flow"));
def->enum_values.push_back(L("Hybrid"));
def->enum_values.push_back(L("TPU High Flow"));
def->enum_values.push_back(L("E3D High Flow"));
def->enum_labels.push_back(L("Standard"));
def->enum_labels.push_back(L("High Flow"));
def->enum_labels.push_back(L("Hybrid"));
def->enum_labels.push_back(L("TPU High Flow"));
def->enum_labels.push_back(L("E3D High Flow"));
def->mode = comDevelop;
def->set_default_value(new ConfigOptionEnumsGeneric{ NozzleVolumeType::nvtStandard });
@@ -5986,7 +6017,7 @@ void PrintConfigDef::init_fff_params()
// Per-nozzle volume type. Forward-compat-only registration with no slicing consumer — nothing in
// src/ reads it; the engine resolves per-nozzle volume types from `extruder_nozzle_stats` tokens
// instead. Kept registered so a project/config carrying it loads without an unknown-option
// substitution warning. Registers Standard/High Flow/TPU High Flow only (no Hybrid).
// substitution warning. Registers the physical types only (no Hybrid).
// Internal use only, no translation.
def = this->add("extruder_nozzle_volume_type", coEnums);
def->label = "Extruder nozzle volume type";
@@ -5995,9 +6026,11 @@ void PrintConfigDef::init_fff_params()
def->enum_values.push_back("Standard");
def->enum_values.push_back("High Flow");
def->enum_values.push_back("TPU High Flow");
def->enum_values.push_back("E3D High Flow");
def->enum_labels.push_back("Standard");
def->enum_labels.push_back("High Flow");
def->enum_labels.push_back("TPU High Flow");
def->enum_labels.push_back("E3D High Flow");
def->mode = comDevelop;
def->set_default_value(new ConfigOptionEnumsGeneric{ NozzleVolumeType::nvtStandard });
@@ -10070,6 +10103,13 @@ bool DynamicPrintConfig::is_using_different_extruders()
return ret;
}
bool DynamicPrintConfig::has_multi_variant_filament() const
{
auto variants = dynamic_cast<const ConfigOptionStrings*>(this->option("filament_extruder_variant"));
auto diameters = dynamic_cast<const ConfigOptionFloats*>(this->option("filament_diameter"));
return variants && diameters && variants->size() > diameters->size();
}
bool DynamicPrintConfig::support_different_extruders(int& extruder_count) const
{
std::set<std::string> variant_set;
@@ -11070,6 +11110,11 @@ void DynamicPrintConfig::update_values_to_printer_extruders_for_multiple_filamen
return;
}
std::vector<int> filament_maps = opt_filament_map->values;
auto opt_ids = id_name.empty()? nullptr: dynamic_cast<const ConfigOptionInts*>(this->option(id_name));
// Orca: a map shorter than the filament count must not drop the filaments past its end;
// they take the first extruder.
if (opt_ids && !opt_ids->values.empty())
filament_maps.resize(std::max<size_t>(filament_maps.size(), *std::max_element(opt_ids->values.begin(), opt_ids->values.end())), 1);
size_t filament_count = filament_maps.size();
//apply process settings
auto opt_extruder_type = dynamic_cast<const ConfigOptionEnumsGeneric*>(printer_config.option("extruder_type"));
@@ -11088,7 +11133,6 @@ void DynamicPrintConfig::update_values_to_printer_extruders_for_multiple_filamen
// indexed out of bounds.
if (opt_filament_volume_maps && opt_filament_volume_maps->values.size() == filament_count)
filament_volume_maps = opt_filament_volume_maps->values;
auto opt_ids = id_name.empty()? nullptr: dynamic_cast<const ConfigOptionInts*>(this->option(id_name));
std::vector<int> variant_index;
variant_index.resize(filament_count, -1);
@@ -11105,9 +11149,10 @@ void DynamicPrintConfig::update_values_to_printer_extruders_for_multiple_filamen
//variant index
variant_index[f_index] = get_index_for_extruder(f_index+1, id_name, extruder_type, nozzle_volume_type, variant_name);
if (variant_index[f_index] < 0) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(", Line %1%: could not found extruder_type %2%, nozzle_volume_type %3%, filament_index %4%, extruder index %5%")
// Orca: a filament need not define every extruder variant (a Direct Drive filament on a
// Bowden printer), so this is not an invalid state: the filament's first variant is used.
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", Line %1%: could not found extruder_type %2%, nozzle_volume_type %3%, filament_index %4%, extruder index %5%")
%__LINE__ %s_keys_names_ExtruderType[extruder_type] % s_keys_names_NozzleVolumeType[nozzle_volume_type] % (f_index+1) %filament_maps[f_index];
assert(false);
//for some updates happens in a invalid state(caused by popup window)
//we need to avoid crash
variant_index[f_index] = 0;