feat(slicing): enforce filament flow-type restrictions in auto grouping

Filament grouping already consumed per-filament forbidden nozzle volume
types, but every call site passed an empty map, so a variant-restricted
filament (e.g. one limited to "Direct Drive TPU High Flow") could be
auto-grouped onto an incompatible nozzle flow type on multi-variant
printers.

- add convert_to_nvt_type() to parse extruder variant strings
- add Print::get_filament_unprintable_flow(): forbidden volume types =
  printer extruder variants minus the filament's declared variants;
  filaments declaring no variants stay unrestricted
- feed the map into grouping at the by-object path (Print.cpp) and all
  six mapping/planning sites in reorder_extruders_for_minimum_flush_volume
- unit-test the string parser

Non-restricted configurations produce an empty map, so existing
printers' grouping and g-code are unchanged.
This commit is contained in:
SoftFever
2026-07-10 15:10:46 +08:00
parent 9e8ac03476
commit b2eeed2622
7 changed files with 121 additions and 7 deletions

View File

@@ -689,6 +689,35 @@ std::vector<std::string> save_extruder_ams_count_to_string(const std::vector<std
return extruder_ams_count_str;
}
// Maps a full extruder variant string such as "Direct Drive High Flow" to its
// NozzleVolumeType: the extruder-type prefix is stripped, the remainder is trimmed
// and looked up as a volume-type name. Returns nvtHybrid when the string cannot
// be parsed.
NozzleVolumeType convert_to_nvt_type(const std::string &variant_str) {
const auto &ext_types = ConfigOptionEnum<ExtruderType>::get_enum_names();
auto trim = [](std::string &s) {
s.erase(s.find_last_not_of(" \t\r\n") + 1);
s.erase(0, s.find_first_not_of(" \t\r\n"));
};
for (auto ext_type : ext_types) {
size_t pos = variant_str.find(ext_type);
if (pos == std::string::npos)
continue;
std::string result = variant_str;
result.erase(pos, ext_type.size());
trim(result);
auto iter = s_keys_map_NozzleVolumeType.find(result);
if (iter != s_keys_map_NozzleVolumeType.end())
return NozzleVolumeType(iter->second);
}
return nvtHybrid;
}
// Parses the extruder_nozzle_stats option: one "|"-separated token list per
// extruder, each token
// "<volume_type_name>#<count>". Empty string => no per-type stats for that extruder.