FIX: some filament group issues

1. Add filament_is_support field. Format the filament type
2. Optimize machine filament info logic

jira:STUDIO-10326

Signed-off-by: xun.zhang <xun.zhang@bambulab.com>
Change-Id: Ia8bfc37095339e73c98209b4e3f1e0804e511e88
This commit is contained in:
xun.zhang 2025-02-12 18:28:28 +08:00 committed by lane.wei
parent 964a6c8320
commit 001144400b
8 changed files with 142 additions and 70 deletions

View File

@ -116,17 +116,15 @@ namespace Slic3r
*
* @param map_lists Group list with similar flush count
* @param used_filaments Idx of used filaments
* @param used_filament_colors Colors of used filaments
* @param used_filament_types Filament types of used filaments
* @param used_filament_info Information of filaments used
* @param machine_filament_info Information of filaments loaded in printer
* @param color_threshold Threshold for considering colors to be similar
* @return The group that best fits the filament distribution in AMS
*/
std::vector<int> select_best_group_for_ams(const std::vector<std::vector<int>>& map_lists,
const std::vector<unsigned int>& used_filaments,
const std::vector<Color>& used_filament_colors,
const std::vector<std::string>& used_filament_types,
const std::vector<std::vector<FilamentInfo>>& machine_filament_info,
const std::vector<FilamentInfo>& used_filament_info,
const std::vector<std::vector<MachineFilamentInfo>>& machine_filament_info_,
const double color_threshold)
{
using namespace FlushPredict;
@ -135,16 +133,9 @@ namespace Slic3r
const int fail_cost = 9999;
std::vector<std::vector<Color>>ams_filament_colors(2);
std::vector<std::vector<std::string>> ams_filament_types(2);
for (size_t idx = 0; idx < std::min(ams_filament_colors.size(), machine_filament_info.size()); ++idx) {
for (size_t j = 0; j < machine_filament_info[idx].size(); ++j) {
ams_filament_colors[idx].emplace_back(machine_filament_info[idx][j].color);
ams_filament_types[idx].emplace_back(machine_filament_info[idx][j].type);
}
}
// these code is to make we machine filament info size is 2
std::vector<std::vector<MachineFilamentInfo>> machine_filament_info = machine_filament_info_;
machine_filament_info.resize(2);
int best_cost = std::numeric_limits<int>::max();
std::vector<int>best_map;
@ -155,7 +146,7 @@ namespace Slic3r
for (size_t i = 0; i < used_filaments.size(); ++i) {
int target_group = map[used_filaments[i]] == 0 ? 0 : 1;
group_colors[target_group].emplace_back(used_filament_colors[i]);
group_colors[target_group].emplace_back(used_filament_info[i].color);
group_filaments[target_group].emplace_back(i);
}
@ -163,31 +154,32 @@ namespace Slic3r
for (size_t i = 0; i < 2; ++i) {
if (group_colors[i].empty())
continue;
if (ams_filament_colors.empty()) {
if (machine_filament_info[i].empty()) {
group_cost += group_colors.size() * fail_cost;
continue;
}
std::vector<std::vector<float>>distance_matrix(group_colors[i].size(), std::vector<float>(ams_filament_colors[i].size()));
std::vector<std::vector<float>>distance_matrix(group_colors[i].size(), std::vector<float>(machine_filament_info[i].size()));
// calculate color distance matrix
for (size_t src = 0; src < group_colors[i].size(); ++src) {
for (size_t dst = 0; dst < ams_filament_colors[i].size(); ++dst) {
for (size_t dst = 0; dst < machine_filament_info[i].size(); ++dst) {
distance_matrix[src][dst] = calc_color_distance(
RGBColor(group_colors[i][src].r, group_colors[i][src].g, group_colors[i][src].b),
RGBColor(ams_filament_colors[i][dst].r, ams_filament_colors[i][dst].g, ams_filament_colors[i][dst].b)
RGBColor(machine_filament_info[i][dst].color.r, machine_filament_info[i][dst].color.g, machine_filament_info[i][dst].color.b)
);
}
}
// get min cost by min cost max flow
std::vector<int>l_nodes(group_colors[i].size()), r_nodes(ams_filament_colors[i].size());
std::vector<int>l_nodes(group_colors[i].size()), r_nodes(machine_filament_info[i].size());
std::iota(l_nodes.begin(), l_nodes.end(), 0);
std::iota(r_nodes.begin(), r_nodes.end(), 0);
std::unordered_map<int, std::vector<int>>unlink_limits;
for (size_t from = 0; from < group_filaments[i].size(); ++from) {
for (size_t to = 0; to < ams_filament_types[i].size(); ++to) {
if (used_filament_types[group_filaments[i][from]] != ams_filament_types[i][to]) {
for (size_t to = 0; to < machine_filament_info[i].size(); ++to) {
if (used_filament_info[group_filaments[i][from]].type != machine_filament_info[i][to].type ||
used_filament_info[group_filaments[i][from]].is_support != machine_filament_info[i][to].is_support) {
unlink_limits[from].emplace_back(to);
}
}
@ -504,16 +496,12 @@ namespace Slic3r
using namespace FlushPredict;
auto used_filaments = collect_sorted_used_filaments(ctx.model_info.layer_filaments);
std::vector<Color> used_colors;
std::vector<std::string> used_types;
std::vector<FilamentInfo> used_filament_list;
for (auto f : used_filaments)
used_filament_list.emplace_back(ctx.model_info.filament_info[f]);
for (auto& f : used_filaments) {
used_colors.emplace_back(Color(ctx.model_info.filament_colors[f]));
used_types.emplace_back(ctx.model_info.filament_types[f]);
}
std::vector<FilamentInfo> machine_filament_list;
std::map<FilamentInfo, std::set<int>> machine_filament_set;
std::vector<MachineFilamentInfo> machine_filament_list;
std::map<MachineFilamentInfo, std::set<int>> machine_filament_set;
for (size_t eid = 0; eid < ctx.machine_info.machine_filament_info.size();++eid) {
for (auto& filament : ctx.machine_info.machine_filament_info[eid]) {
machine_filament_set[filament].insert(machine_filament_list.size());
@ -527,11 +515,11 @@ namespace Slic3r
std::map<int, int> unprintable_limit_indices; // key stores filament idx in used_filament, value stores unprintable extruder
extract_unprintable_limit_indices(ctx.model_info.unprintable_filaments, used_filaments, unprintable_limit_indices);
std::vector<std::vector<float>> color_dist_matrix(used_colors.size(), std::vector<float>(machine_filament_list.size()));
for (size_t i = 0; i < used_colors.size(); ++i) {
std::vector<std::vector<float>> color_dist_matrix(used_filament_list.size(), std::vector<float>(machine_filament_list.size()));
for (size_t i = 0; i < used_filament_list.size(); ++i) {
for (size_t j = 0; j < machine_filament_list.size(); ++j) {
color_dist_matrix[i][j] = calc_color_distance(
RGBColor(used_colors[i].r, used_colors[i].g, used_colors[i].b),
RGBColor(used_filament_list[i].color.r, used_filament_list[i].color.g, used_filament_list[i].color.b),
RGBColor(machine_filament_list[j].color.r, machine_filament_list[j].color.g, machine_filament_list[j].color.b)
);
}
@ -632,8 +620,9 @@ namespace Slic3r
std::vector<int> group(ctx.group_info.total_filament_num, ctx.machine_info.master_extruder_id);
std::vector<int> ungrouped_filaments;
auto unlink_limits_full = build_unlink_limits(l_nodes, r_nodes, [&used_types, &machine_filament_list, is_extruder_filament_compatible](int used_filament_idx, int machine_filament_idx) {
return used_types[used_filament_idx] == machine_filament_list[machine_filament_idx].type &&
auto unlink_limits_full = build_unlink_limits(l_nodes, r_nodes, [&used_filament_list, &machine_filament_list, is_extruder_filament_compatible](int used_filament_idx, int machine_filament_idx) {
return used_filament_list[used_filament_idx].type == machine_filament_list[machine_filament_idx].type &&
used_filament_list[used_filament_idx].is_support == machine_filament_list[machine_filament_idx].is_support &&
is_extruder_filament_compatible(used_filament_idx, machine_filament_list[machine_filament_idx].extruder_id);
});
@ -697,14 +686,12 @@ namespace Slic3r
if (optimized_ret != ret)
memoryed_maps.insert(memoryed_maps.begin(), optimized_ret);
std::vector<Color> used_colors;
std::vector<std::string> used_types;
for (const auto& f : used_filaments) {
used_colors.push_back(Color(ctx.model_info.filament_colors[f]));
used_types.push_back(ctx.model_info.filament_types[f]);
std::vector<FilamentGroupUtils::FilamentInfo> used_filament_info;
for (auto f : used_filaments) {
used_filament_info.emplace_back(ctx.model_info.filament_info[f]);
}
ret = select_best_group_for_ams(memoryed_maps, used_filaments, used_colors,used_types, ctx.machine_info.machine_filament_info);
ret = select_best_group_for_ams(memoryed_maps, used_filaments, used_filament_info, ctx.machine_info.machine_filament_info);
return ret;
}

View File

@ -72,8 +72,7 @@ namespace Slic3r
struct ModelInfo {
std::vector<FlushMatrix> flush_matrix;
std::vector<std::vector<unsigned int>> layer_filaments;
std::vector<std::string> filament_colors;
std::vector<std::string> filament_types;
std::vector<FilamentGroupUtils::FilamentInfo> filament_info;
std::vector<std::set<int>> unprintable_filaments;
} model_info;
@ -87,7 +86,7 @@ namespace Slic3r
struct MachineInfo {
std::vector<int> max_group_size;
std::vector<std::vector<FilamentGroupUtils::FilamentInfo>> machine_filament_info;
std::vector<std::vector<FilamentGroupUtils::MachineFilamentInfo>> machine_filament_info;
std::vector<std::pair<std::set<int>, int>> extruder_group_size;
int master_extruder_id;
} machine_info;
@ -95,9 +94,8 @@ namespace Slic3r
std::vector<int> select_best_group_for_ams(const std::vector<std::vector<int>>& map_lists,
const std::vector<unsigned int>& used_filaments,
const std::vector<FilamentGroupUtils::Color>& used_filament_colors,
const std::vector<std::string>& used_filament_types,
const std::vector<std::vector<FilamentGroupUtils::FilamentInfo>>& machine_filament_info,
const std::vector<FilamentGroupUtils::FilamentInfo>& used_filament_info,
const std::vector<std::vector<FilamentGroupUtils::MachineFilamentInfo>>& machine_filament_info,
const double color_delta_threshold = 20);
std::vector<int> optimize_group_for_master_extruder(const std::vector<unsigned int>& used_filaments, const FilamentGroupContext& ctx, const std::vector<int>& filament_map);

View File

@ -45,10 +45,11 @@ namespace FilamentGroupUtils
return r != other.r || g != other.g || b != other.b || a != other.a;
}
bool FilamentInfo::operator<(const FilamentInfo& other) const
bool MachineFilamentInfo::operator<(const MachineFilamentInfo& other) const
{
if (color != other.color) return color < other.color;
return type < other.type;
if (type != other.type) return type < other.type;
return is_support <other.is_support;
}
@ -71,24 +72,42 @@ namespace FilamentGroupUtils
}
static std::vector<std::vector<FilamentInfo>> build_full_machine_filaments(const std::vector<std::vector<DynamicPrintConfig>>& filament_configs)
static std::vector<std::vector<MachineFilamentInfo>> build_full_machine_filaments(const std::vector<std::vector<DynamicPrintConfig>>& filament_configs)
{
auto extract_filament_type = [](const std::string& s)->std::string {
std::regex r1(R"(^Sup.(\w+)$)");
std::regex r2(R"(^(\w+)-S$)");
std::smatch m;
if (std::regex_match(s, m, r1))
return m[1].str();
if (std::regex_match(s, m, r2))
return m[1].str();
return s;
};
// change filament type to type format in preset
// defualt size set to 2
std::vector<std::vector<FilamentInfo>> machine_filaments(2);
std::vector<std::vector<MachineFilamentInfo>> machine_filaments(2);
for (size_t idx = 0; idx < filament_configs.size(); ++idx) {
auto& arr = filament_configs[idx];
for (auto& item : arr) {
FilamentInfo temp;
MachineFilamentInfo temp;
std::string type;
std::string color;
std::string tray_name;
bool is_support_filament = false;
if (auto color_ptr = item.option<ConfigOptionStrings>("filament_colour"); color_ptr)
color = color_ptr->get_at(0);
if (auto type_ptr = item.option<ConfigOptionStrings>("filament_type"); type_ptr)
if (auto type_ptr = item.option<ConfigOptionStrings>("filament_type"); type_ptr) {
type = type_ptr->get_at(0);
type = extract_filament_type(type);
}
if (auto tray_ptr = item.option<ConfigOptionStrings>("tray_name"); tray_ptr)
tray_name = tray_ptr->get_at(0);
if (auto support_ptr = item.option<ConfigOptionBools>("filament_is_support"); support_ptr)
is_support_filament = support_ptr->get_at(0);
if (color.empty() || type.empty() || tray_name.empty())
continue;
@ -97,17 +116,18 @@ namespace FilamentGroupUtils
temp.type =type;
temp.extruder_id = idx;
temp.is_extended = tray_name == "Ext"; // hard-coded ext flag
temp.is_support = is_support_filament;
machine_filaments[idx].emplace_back(std::move(temp));
}
}
return machine_filaments;
}
std::vector<std::vector<FilamentInfo>> build_machine_filaments(const std::vector<std::vector<DynamicPrintConfig>>& filament_configs, const std::vector<std::map<int, int>>& ams_counts, bool ignore_ext_filament)
std::vector<std::vector<MachineFilamentInfo>> build_machine_filaments(const std::vector<std::vector<DynamicPrintConfig>>& filament_configs, const std::vector<std::map<int, int>>& ams_counts, bool ignore_ext_filament)
{
std::vector<std::vector<FilamentInfo>> ret(2);
std::vector<std::vector<MachineFilamentInfo>> ret(2);
std::vector<int> ams_size(2, 0);
std::vector<std::vector<FilamentInfo>> full_machine_filaments = build_full_machine_filaments(filament_configs);
std::vector<std::vector<MachineFilamentInfo>> full_machine_filaments = build_full_machine_filaments(filament_configs);
assert(full_machine_filaments.size() == 2);
for (size_t idx = 0; idx < std::min(ams_counts.size(),ams_size.size()); ++idx) {
const auto& ams_count = ams_counts[idx];
@ -118,16 +138,22 @@ namespace FilamentGroupUtils
assert(full_machine_filaments.size() == ams_size.size());
for (size_t idx = 0; idx < std::min(ams_size.size(), full_machine_filaments.size()); ++idx) {
std::vector<FilamentInfo> tmp;
bool accept_ext_filament = ams_size[idx] == 0 && !ignore_ext_filament;
std::vector<MachineFilamentInfo> tmp;
for (size_t j = 0; j < full_machine_filaments[idx].size(); ++j) {
auto machine_filament = full_machine_filaments[idx][j];
if (!full_machine_filaments[idx][j].is_extended)
tmp.emplace_back(machine_filament);
else if (accept_ext_filament)
auto& machine_filament = full_machine_filaments[idx][j];
if (!machine_filament.is_extended)
tmp.emplace_back(machine_filament);
}
// if do not have valid ams filament, try to use ext filament
if (tmp.empty() && !ignore_ext_filament) {
for (size_t j = 0; j < full_machine_filaments[idx].size(); ++j) {
auto& machine_filament = full_machine_filaments[idx][j];
if (machine_filament.is_extended)
tmp.emplace_back(machine_filament);
}
}
ret[idx] = std::move(tmp);
}
return ret;

View File

@ -29,9 +29,13 @@ namespace Slic3r
struct FilamentInfo {
Color color;
std::string type;
bool is_support;
};
struct MachineFilamentInfo: public FilamentInfo {
int extruder_id;
bool is_extended;
bool operator<(const FilamentInfo& other) const;
bool operator<(const MachineFilamentInfo& other) const;
};
@ -62,7 +66,7 @@ namespace Slic3r
std::vector<int> calc_max_group_size(const std::vector<std::map<int, int>>& ams_counts,bool ignore_ext_filament);
std::vector<std::vector<FilamentInfo>> build_machine_filaments(const std::vector<std::vector<DynamicPrintConfig>>& filament_configs, const std::vector<std::map<int, int>>& ams_counts, bool ignore_ext_filament);
std::vector<std::vector<MachineFilamentInfo>> build_machine_filaments(const std::vector<std::vector<DynamicPrintConfig>>& filament_configs, const std::vector<std::map<int, int>>& ams_counts, bool ignore_ext_filament);
bool collect_unprintable_limits(const std::vector<std::set<int>>& physical_unprintables, const std::vector<std::set<int>>& geometric_unprintables, std::vector<std::set<int>>& unprintable_limits);

View File

@ -1007,6 +1007,7 @@ std::vector<int> ToolOrdering::get_recommended_filament_maps(const std::vector<s
std::vector<std::string> filament_types = print_config.filament_type.values;
std::vector<std::string> filament_colours = print_config.filament_colour.values;
std::vector<unsigned char> filament_is_support = print_config.filament_is_support.values;
// speacially handle tpu filaments
auto used_filaments = collect_sorted_used_filaments(layer_filaments);
@ -1021,8 +1022,14 @@ std::vector<int> ToolOrdering::get_recommended_filament_maps(const std::vector<s
context.model_info.flush_matrix = std::move(nozzle_flush_mtx);
context.model_info.unprintable_filaments = ext_unprintable_filaments;
context.model_info.layer_filaments = layer_filaments;
context.model_info.filament_colors = filament_colours;
context.model_info.filament_types = filament_types;
for (size_t idx = 0; idx < filament_types.size(); ++idx) {
FilamentGroupUtils::FilamentInfo info;
info.color = filament_colours[idx];
info.type = filament_types[idx];
info.is_support = filament_is_support[idx];
context.model_info.filament_info.emplace_back(std::move(info));
}
context.machine_info.machine_filament_info = machine_filament_info;
context.machine_info.max_group_size = std::move(group_size);

View File

@ -326,6 +326,38 @@ Semver PresetBundle::get_vendor_profile_version(std::string vendor_name)
return result_ver;
}
std::optional<FilamentBaseInfo> PresetBundle::get_filament_by_filament_id(const std::string& filament_id) const
{
if (filament_id.empty())
return {};
// basic filament info should be same in the parent preset and child preset
// so just match the filament id is enough
for (auto iter = filaments.begin(); iter != filaments.end(); ++iter) {
const Preset& filament_preset = *iter;
const auto& config = filament_preset.config;
if (filament_preset.filament_id == filament_id) {
FilamentBaseInfo info;
info.filament_id = filament_id;
info.is_system = filament_preset.is_system;
info.filament_name = filament_preset.alias;
if (config.has("filament_is_support"))
info.is_support = config.option<ConfigOptionBools>("filament_is_support")->values[0];
if (config.has("filament_type"))
info.filament_type = config.option<ConfigOptionStrings>("filament_type")->values[0];
if (config.has("filament_vendor"))
info.vendor = config.option<ConfigOptionStrings>("filament_vendor")->values[0];
if (config.has("nozzle_temperature_range_high"))
info.nozzle_temp_range_high = config.option<ConfigOptionInts>("nozzle_temperature_range_high")->values[0];
if (config.has("nozzle_temperature_range_low"))
info.nozzle_temp_range_low = config.option<ConfigOptionInts>("nozzle_temperature_range_low")->values[0];
return info;
}
}
return {};
}
//BBS: load project embedded presets
PresetsConfigSubstitutions PresetBundle::load_project_embedded_presets(std::vector<Preset*> project_presets, ForwardCompatibilitySubstitutionRule substitution_rule)
{

View File

@ -47,6 +47,20 @@ struct MergeFilamentInfo {
std::vector<std::vector<int>> merges;
bool is_empty() { return merges.empty();}
};
struct FilamentBaseInfo
{
std::string filament_name;
std::string filament_id;
std::string filament_type;
std::string vendor;
int nozzle_temp_range_low;
int nozzle_temp_range_high;
bool is_support;
bool is_system;
};
// Bundle of Print + Filament + Printer presets.
class PresetBundle
{
@ -104,9 +118,12 @@ public:
Preset* get_preset_differed_for_save(Preset& preset);
int get_differed_values_to_update(Preset& preset, std::map<std::string, std::string>& key_values);
//BBS: get vendor's current version
Semver get_vendor_profile_version(std::string vendor_name);
std::optional<FilamentBaseInfo> get_filament_by_filament_id(const std::string& filament_id) const;
//BBS: project embedded preset logic
PresetsConfigSubstitutions load_project_embedded_presets(std::vector<Preset*> project_presets, ForwardCompatibilitySubstitutionRule substitution_rule);
std::vector<Preset*> get_current_project_embedded_presets();

View File

@ -2800,8 +2800,9 @@ std::map<int, DynamicPrintConfig> Sidebar::build_filament_ams_list(MachineObject
tray_config.set_key_value("tray_name", new ConfigOptionStrings{ name });
tray_config.set_key_value("filament_colour", new ConfigOptionStrings{into_u8(wxColour("#" + tray.color).GetAsString(wxC2S_HTML_SYNTAX))});
tray_config.set_key_value("filament_exist", new ConfigOptionBools{tray.is_exists});
tray_config.set_key_value("filament_multi_colors", new ConfigOptionStrings{});
auto info = wxGetApp().preset_bundle->get_filament_by_filament_id(tray.setting_id);
tray_config.set_key_value("filament_is_support", new ConfigOptionBools{ info ? info->is_support : false });
for (int i = 0; i < tray.cols.size(); ++i) {
tray_config.opt<ConfigOptionStrings>("filament_multi_colors")->values.push_back(into_u8(wxColour("#" + tray.cols[i]).GetAsString(wxC2S_HTML_SYNTAX)));
}