diff --git a/src/slic3r/Utils/SnapmakerPrinterAgent.cpp b/src/slic3r/Utils/SnapmakerPrinterAgent.cpp index 8322a6fd55..9b9a6809fd 100644 --- a/src/slic3r/Utils/SnapmakerPrinterAgent.cpp +++ b/src/slic3r/Utils/SnapmakerPrinterAgent.cpp @@ -19,6 +19,50 @@ T safe_at(const std::vector& vec, int index, const T& fallback) return (index >= 0 && index < static_cast(vec.size())) ? vec[index] : fallback; } +std::string find_closest_color_preset_by_vendor_and_type(const PresetCollection& filaments, + const std::string& vendor_name, + const std::string& filament_type, + const std::string& color_rgba) +{ + std::string best_match_id = ""; + int best_color_distance = 0xffffffff; + + for (const auto& p : filaments.get_presets()) { + if (p.is_visible && p.is_compatible && + // Filament profile must be detached from parent to be considered for matching + filaments.get_preset_base(p) == &p && p.config.opt_string("filament_vendor", 0u) == vendor_name && + p.config.opt_string("filament_type", 0u) == filament_type) { + // The printer returns RGBA in the format RRGGBBAA, but profiles store color as #RRGGBB, + // so we must remove # and ignore alpha channel for distance calculation + unsigned int target_color_value = std::stoul(color_rgba.substr(0, color_rgba.length() - 2), nullptr, 16); + + std::string p_color = p.config.opt_string("default_filament_colour", 0u); + unsigned int p_color_value; + if (!p_color.empty()) { + unsigned int hash_pos = p_color.find("#"); + p_color_value = std::stoul(p_color.substr(hash_pos != std::string::npos ? hash_pos + 1 : 0), nullptr, 16); + } else { + // Default to black if no color specified in profile. Assume other profiles might be a closer color match. + // Could be a problem if the target color is also black and there exist a specific profile for that type, vendor and color + // combination. + p_color_value = 0; + } + + // Calculate Euclidean color distance in RGB space + int dr = ((target_color_value & 0xff) - (p_color_value & 0xff)); + int dg = (((target_color_value >> 8) & 0xff) - ((p_color_value >> 8) & 0xff)); + int db = (((target_color_value >> 16) & 0xff) - ((p_color_value >> 16) & 0xff)); + unsigned int distance = dr * dr + dg * dg + db * db; + + if (distance < best_color_distance) { + best_color_distance = distance; + best_match_id = p.filament_id; + } + } + } + return best_match_id; +} + } // anonymous namespace SnapmakerPrinterAgent::SnapmakerPrinterAgent(std::string log_dir) : MoonrakerPrinterAgent(std::move(log_dir)) {} @@ -113,6 +157,7 @@ bool SnapmakerPrinterAgent::fetch_filament_info(std::string dev_id) auto filament_type = ptc.value("filament_type", std::vector{}); auto filament_sub_type = ptc.value("filament_sub_type", std::vector{}); auto filament_color = ptc.value("filament_color_rgba", std::vector{}); + auto filament_vendor = ptc.value("filament_vendor", std::vector{}); const int slot_count = static_cast(filament_exist.size()); if (slot_count == 0) { @@ -141,12 +186,27 @@ bool SnapmakerPrinterAgent::fetch_filament_info(std::string dev_id) if (tray.has_filament) { tray.tray_type = combine_filament_type(safe_at(filament_type, i, empty_str), safe_at(filament_sub_type, i, empty_str)); - auto* bundle = GUI::wxGetApp().preset_bundle; - tray.tray_info_idx = bundle - ? bundle->filaments.filament_id_by_type(tray.tray_type) - : map_filament_type_to_generic_id(tray.tray_type); tray.tray_color = safe_at(filament_color, i, default_color); + auto* bundle = GUI::wxGetApp().preset_bundle; + // Try to find a matching preset for this filament based on vendor, type and color. + // If not found, default to traditional search by type only or generic type mapping. + if (bundle) { + std::string vendor = safe_at(filament_vendor, i, empty_str); + std::string filament_id = find_closest_color_preset_by_vendor_and_type(bundle->filaments, vendor, tray.tray_type, + tray.tray_color); + + if (!filament_id.empty()) { + tray.tray_info_idx = filament_id; + BOOST_LOG_TRIVIAL(warning) << "Filament sync: Found manufacturer-specific profile for slot " << i << ": " + << filament_id; + } else { + tray.tray_info_idx = bundle->filaments.filament_id_by_type(tray.tray_type); + } + } else { + tray.tray_info_idx = map_filament_type_to_generic_id(tray.tray_type); + } + // Extract NFC temperature data if available if (nfc_info.is_array() && i < static_cast(nfc_info.size()) && nfc_info[i].is_object()) { auto& nfc_slot = nfc_info[i];