1054 {
1055 using namespace FlushPredict;
1056 constexpr int SupportPreferScore = 3;
1057
1059 std::vector<FilamentGroupUtils::FilamentInfo> used_filament_list;
1060 for (
auto f : used_filaments)
1061 used_filament_list.emplace_back(
ctx.model_info.filament_info[
f]);
1062
1063 std::vector<MachineFilamentInfo> machine_filament_list;
1064 std::map<MachineFilamentInfo, std::set<int>> machine_filament_set;
1065 for (
size_t eid = 0; eid <
ctx.machine_info.machine_filament_info.size();++eid) {
1066 for (
auto& filament :
ctx.machine_info.machine_filament_info[eid]) {
1067 machine_filament_set[filament].insert(machine_filament_list.size());
1068 machine_filament_list.emplace_back(filament);
1069 }
1070 }
1071
1072 if (machine_filament_list.empty())
1074
1075 std::map<int, int> unprintable_limit_indices;
1078
1079 std::vector<std::vector<float>> color_dist_matrix(used_filament_list.size(), std::vector<float>(machine_filament_list.size()));
1080 for (size_t i = 0; i < used_filament_list.size(); ++i) {
1081 for (size_t j = 0; j < machine_filament_list.size(); ++j) {
1083 RGBColor(used_filament_list[i].color.r, used_filament_list[i].color.g, used_filament_list[i].color.b),
1084 RGBColor(machine_filament_list[j].color.r, machine_filament_list[j].color.g, machine_filament_list[j].color.b)
1085 );
1086 }
1087 }
1088
1089 std::vector<int>l_nodes(used_filaments.size());
1090 std::iota(l_nodes.begin(), l_nodes.end(), 0);
1091 std::vector<int>r_nodes(machine_filament_list.size());
1092 std::iota(r_nodes.begin(), r_nodes.end(), 0);
1093 std::vector<int>machine_filament_capacity(machine_filament_list.size(),l_nodes.size());
1094 std::vector<int>extruder_filament_count(2, 0);
1095
1096 auto is_extruder_filament_compatible = [&unprintable_limit_indices](int filament_idx, int extruder_id) {
1097 auto iter = unprintable_limit_indices.find(filament_idx);
1098 if (iter != unprintable_limit_indices.end() && iter->second == extruder_id)
1099 return false;
1100 return true;
1101 };
1102
1103 auto build_unlink_limits = [](const std::vector<int>& l_nodes, const std::vector<int>& r_nodes, const std::function<bool(int, int)>& can_link) {
1104 std::unordered_map<int, std::vector<int>> unlink_limits;
1105 for (size_t i = 0; i < l_nodes.size(); ++i) {
1106 std::vector<int> unlink_filaments;
1107 for (size_t j = 0; j < r_nodes.size(); ++j) {
1108 if (!can_link(l_nodes[i], r_nodes[j]))
1109 unlink_filaments.emplace_back(j);
1110 }
1111 if (!unlink_filaments.empty())
1112 unlink_limits.emplace(i, std::move(unlink_filaments));
1113 }
1114 return unlink_limits;
1115 };
1116
1117 auto optimize_map_to_machine_filament = [&](
const std::vector<int>& map_to_machine_filament,
const std::vector<int>& l_nodes,
const std::vector<int>& r_nodes, std::vector<int>&
filament_map) {
1118 std::vector<int> ungrouped_filaments;
1119 std::vector<int> filaments_to_optimize;
1120
1121 auto map_filament_to_machine_filament = [&](int filament_idx, int machine_filament_idx) {
1122 auto& machine_filament = machine_filament_list[machine_filament_idx];
1123 filament_map[used_filaments[filament_idx]] = machine_filament.extruder_id;
1124 extruder_filament_count[machine_filament.extruder_id] += 1;
1125 };
1126 auto unmap_filament_to_machine_filament = [&](int filament_idx, int machine_filament_idx) {
1127 auto& machine_filament = machine_filament_list[machine_filament_idx];
1128 extruder_filament_count[machine_filament.extruder_id] -= 1;
1129 };
1130
1131 for (size_t idx = 0; idx < map_to_machine_filament.size(); ++idx) {
1133 ungrouped_filaments.emplace_back(l_nodes[idx]);
1134 continue;
1135 }
1136 int used_filament_idx = l_nodes[idx];
1137 int machine_filament_idx = r_nodes[map_to_machine_filament[idx]];
1138 auto& machine_filament = machine_filament_list[machine_filament_idx];
1139 if (machine_filament_set[machine_filament].size() > 1 && unprintable_limit_indices.count(used_filament_idx) == 0)
1140 filaments_to_optimize.emplace_back(idx);
1141
1142 map_filament_to_machine_filament(used_filament_idx, machine_filament_idx);
1143 }
1144
1145 for (auto idx : filaments_to_optimize) {
1146 int filament_idx = l_nodes[idx];
1148 int old_machine_filament_idx = r_nodes[map_to_machine_filament[idx]];
1149 auto& old_machine_filament = machine_filament_list[old_machine_filament_idx];
1150
1151 unmap_filament_to_machine_filament(filament_idx, old_machine_filament_idx);
1152
1153 auto optional_filaments = machine_filament_set[old_machine_filament];
1154
1155
1156 std::vector<std::pair<int, int>> valid_candidates;
1157 for (auto machine_filament : optional_filaments) {
1158 int new_extruder_id = machine_filament_list[machine_filament].extruder_id;
1159
1160
1161 int preference_score = 0;
1162 bool new_extruder_prefer_support =
ctx.machine_info.prefer_non_model_filament[new_extruder_id];
1163
1164
1165 if (is_support_filament && new_extruder_prefer_support) {
1166 preference_score += SupportPreferScore;
1167 }
1168
1169 valid_candidates.emplace_back(machine_filament, preference_score);
1170 }
1171
1172 int best_preference_score = 0;
1173 for (const auto& candidate : valid_candidates) {
1174 if (candidate.second >= best_preference_score) {
1175 best_preference_score = candidate.second;
1176 }
1177 }
1178
1179
1180 int best_candidate = -1;
1181 int best_gap = std::numeric_limits<int>::max();
1182
1183 for (const auto& candidate : valid_candidates) {
1184
1185 int machine_filament = candidate.first;
1186 int score = candidate.second;
1187 if (score == best_preference_score) {
1188 int new_extruder_id = machine_filament_list[machine_filament].extruder_id;
1189 int new_gap = std::abs(extruder_filament_count[new_extruder_id] + 1 - extruder_filament_count[1 - new_extruder_id]);
1190
1191
1192 if (new_gap < best_gap) {
1193 best_gap = new_gap;
1194 best_candidate = machine_filament;
1195 }
1196 }
1197 }
1198
1199 if (best_candidate != -1) {
1200 map_filament_to_machine_filament(filament_idx, best_candidate);
1201 } else {
1202 map_filament_to_machine_filament(filament_idx, old_machine_filament_idx);
1203 }
1204 }
1205 return ungrouped_filaments;
1206 };
1207
1208 std::vector<int> group(
ctx.group_info.total_filament_num,
ctx.machine_info.master_extruder_id);
1209 std::vector<int> ungrouped_filaments;
1210
1211 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) {
1212 return used_filament_list[used_filament_idx].type == machine_filament_list[machine_filament_idx].type &&
1213 used_filament_list[used_filament_idx].is_support == machine_filament_list[machine_filament_idx].is_support &&
1214 is_extruder_filament_compatible(used_filament_idx, machine_filament_list[machine_filament_idx].extruder_id);
1215 });
1216
1217 {
1218 MatchModeGroupSolver s(color_dist_matrix, l_nodes, r_nodes, machine_filament_capacity, unlink_limits_full);
1219 ungrouped_filaments = optimize_map_to_machine_filament(s.solve(), l_nodes, r_nodes,group);
1220 if (ungrouped_filaments.empty())
1221 return group;
1222 }
1223
1224
1225 {
1226 l_nodes = ungrouped_filaments;
1227 auto unlink_limits = build_unlink_limits(l_nodes, r_nodes, [&machine_filament_list, is_extruder_filament_compatible](int used_filament_idx, int machine_filament_idx) {
1228 return is_extruder_filament_compatible(used_filament_idx, machine_filament_list[machine_filament_idx].extruder_id);
1229 });
1230
1231 MatchModeGroupSolver s(color_dist_matrix, l_nodes, r_nodes, machine_filament_capacity, unlink_limits);
1232 ungrouped_filaments = optimize_map_to_machine_filament(s.solve(), l_nodes, r_nodes, group);
1233 if (ungrouped_filaments.empty())
1234 return group;
1235 }
1236
1237
1238 {
1239 l_nodes = ungrouped_filaments;
1240 MatchModeGroupSolver s(color_dist_matrix, l_nodes, r_nodes, machine_filament_capacity, {});
1241 auto ret = optimize_map_to_machine_filament(s.solve(), l_nodes, r_nodes, group);
1242 for (size_t idx = 0; idx < ret.size(); ++idx) {
1244 assert(false);
1245 else
1246 group[used_filaments[l_nodes[idx]]] = machine_filament_list[r_nodes[ret[idx]]].extruder_id;
1247 }
1248 }
1249
1250 return group;
1251 }
@ EmptyAmsFilaments
Definition FilamentGroupUtils.hpp:54
std::map< int, int > rebuild_unprintables(const std::vector< unsigned int > &used_filaments, const std::map< int, int > &extruder_unprintables)
Definition FilamentGroup.cpp:925
float calc_color_distance(const LABColor &lab1, const LABColor &lab2)
Definition FlushVolPredictor.cpp:73
void extract_unprintable_limit_indices(const std::vector< std::set< int > > &unprintable_elems, const std::vector< unsigned int > &used_filaments, std::map< int, int > &unplaceable_limits)
Definition FilamentGroupUtils.cpp:247
bool is_support_filament(int extruder_id, bool strict_check)
Definition GUI_App.cpp:10492
const int INVALID_ID
Definition ToolOrderUtils.hpp:21
@ SupportOnly
Definition PrintConfig.hpp:70
zaa_minimize_perimeter_height filament_map((ConfigOptionInts, filament_volume_map))((ConfigOptionInts