Files
OrcaSlicer/docs/U1_Filament_Compatibility_Fix.md
xiaoyeliu 5989d15428 feature: add filename validation & check the compatiblity of the filament from device (#132)
* Fix: didn't check the compatiblity of the filament which is gotten from machine

* Optimize the filename validation
2026-01-22 18:30:38 +08:00

7.1 KiB
Raw Blame History

U1设备耗材兼容性检查修复

问题描述

当连接 Snapmaker U1 设备时,如果设备上编辑的耗材是 "Snapmaker PETG",耗材下拉框的 "Machine Filament" 部分会显示该耗材。然而,Snapmaker PETG.json 配置文件的 compatible_printers 列表中不包含 U1 设备(仅包含 A250/A350 系列),导致显示了一个不兼容的耗材配置。

现象

  • 引导页和选择耗材页没有 "Snapmaker PETG @U1" 选项(正常)
  • 连接 U1 设备后,下拉框 "Machine Filament" 部分 "Snapmaker PETG"(问题)
  • Snapmaker PETGcompatible_printers 不包含 U1配置不匹配

根本原因

代码位置

src/slic3r/GUI/PresetComboBoxes.cpp

  • 第一处:第 1151-1164 行(PlaterPresetComboBox::update() 函数)
  • 第二处:第 1725-1738 行(另一个同名函数,可能是不同类)

问题代码

// 修改前的代码
for (auto iter = machine_filaments.begin(); iter != machine_filaments.end();) {
    std::string filament_name = iter->second.first;
    // 1. 精确匹配名称
    auto item_iter = std::find_if(filaments.begin(), filaments.end(),
                            [&filament_name, this](auto& f) { return f.name == filament_name; });

    // 2. 如果没找到,尝试带 @U1 后缀
    if (item_iter == filaments.end()) {
        item_iter = std::find_if(filaments.begin(), filaments.end(),
                            [&filament_name, this](auto& f) { return f.name == filament_name + " @U1"; });
    }

    // 3. 只要找到就添加,没有检查 is_compatible
    if (item_iter != filaments.end()) {
        const_cast<Preset&>(*item_iter).is_visible = true;
        // ... 添加到下拉框
    }
}

缺少的检查

代码只检查了耗材名称是否匹配,没有检查 is_compatible 标志。这个标志是由 PresetCollection::update_compatible_internal() 函数根据 compatible_printers 配置计算的。

耗材同步流程

  1. 设备连接时,通过 SSWCP_Instance::update_filament_info()SSWCP.cpp:1440-1588同步耗材
  2. 设备发送:filament_vendor="Snapmaker", filament_type="PETG", filament_sub_type="NONE"
  3. 构建耗材名称:"Snapmaker PETG"不带 @U1 后缀
  4. 存储到 wxGetApp().preset_bundle->machine_filaments
  5. 下拉框更新时尝试匹配此名称

修复方案

修改内容

在两次匹配的 lambda 表达式中都增加 && f.is_compatible 检查:

// 修改后的代码
for (auto iter = machine_filaments.begin(); iter != machine_filaments.end();) {
    std::string filament_name = iter->second.first;

    // 第一次匹配: 精确匹配名称 + 兼容性检查
    auto item_iter = std::find_if(filaments.begin(), filaments.end(),
                             [&filament_name, this](auto& f) { return f.name == filament_name && f.is_compatible; });

    // 第二次匹配: 如果第一次失败,尝试带 @U1 后缀 + 兼容性检查
    if (item_iter == filaments.end()) {
        item_iter = std::find_if(filaments.begin(), filaments.end(),
                            [&filament_name, this](auto& f) { return f.name == filament_name + " @U1" && f.is_compatible; });
    }

    if (item_iter != filaments.end()) {
        const_cast<Preset&>(*item_iter).is_visible = true;
        // ... 添加到下拉框
    } else {
        iter = machine_filaments.erase(iter);
    }
}

修复逻辑

  1. 第一次匹配:精确匹配 "Snapmaker PETG" + 检查 is_compatible

    • 如果 Snapmaker PETG.jsoncompatible_printers 不包含 U1
    • is_compatible = false,匹配失败
  2. 第二次匹配:尝试 "Snapmaker PETG @U1" + 检查 is_compatible

    • 如果在 Snapmaker.json 中注册了 "Snapmaker PETG @U1"
    • 且其 compatible_printers 包含 U1
    • 则匹配成功
  3. 结果:只有名称匹配且兼容的耗材才会显示

技术细节

is_compatible 计算逻辑

位置:src/libslic3r/Preset.cpp:639-670

bool is_compatible_with_printer(const PresetWithVendorProfile &preset,
                                const PresetWithVendorProfile &active_printer,
                                const DynamicPrintConfig *extra_config)
{
    auto *compatible_printers = preset.preset.config.option("compatible_printers");
    bool has_compatible_printers = compatible_printers != nullptr &&
                                   !compatible_printers->values.empty();

    return preset.preset.is_default ||
           active_printer.preset.name.empty() ||
           !has_compatible_printers ||
           std::find(compatible_printers->values.begin(),
                     compatible_printers->values.end(),
                     active_printer.preset.name) != compatible_printers->values.end();
}

下拉框填充顺序

PlaterPresetComboBox::update() 函数按以下顺序填充下拉框:

  1. Machine Filament - 从设备同步的耗材(本次修复部分)
  2. Project-inside presets - 项目内嵌预设
  3. User presets - 用户自定义预设
  4. System presets - 系统预设(本来就检查 is_compatible,第 1073 行)

两处修改的原因

PresetComboBoxes.cpp 中有两处几乎相同的代码,可能属于不同的类或重载函数:

  • 第 1151-1164 行:PlaterPresetComboBox::update()
  • 第 1725-1738 行:另一个相同的逻辑(可能是不同 UI 组件)

两处都需要修改以确保一致性。

相关配置文件

Snapmaker PETG.json

位置:resources/profiles/Snapmaker/filament/Snapmaker PETG.json

{
  "type": "filament",
  "name": "Snapmaker PETG",
  "compatible_printers": [
    "Snapmaker A250 (0.4 nozzle)",
    "Snapmaker A250 (0.6 nozzle)",
    ...
    "Snapmaker A350 QSKit (0.8 nozzle)"
  ]
}

不包含 U1 设备

Snapmaker PETG @U1.json

位置:resources/profiles/Snapmaker/filament/Snapmaker PETG @U1.json

{
  "type": "filament",
  "name": "Snapmaker PETG @U1",
  "compatible_printers": [
    "Snapmaker U1 (0.4 nozzle)"
  ]
}

文件存在但未在 Snapmaker.json 中注册

后续建议

要让 U1 设备正确识别 Snapmaker PETG 耗材,需要以下操作之一:

选项 A注册 @U1 专用配置(推荐)

resources/profiles/Snapmaker.jsonfilament_list 中添加:

{
  "name": "Snapmaker PETG @U1",
  "sub_path": "filament/Snapmaker PETG @U1.json"
}

选项 B扩展通用配置的兼容性

resources/profiles/Snapmaker/filament/Snapmaker PETG.jsoncompatible_printers 中添加:

"compatible_printers": [
  ...existing...,
  "Snapmaker U1 (0.4 nozzle)"
]

测试建议

  1. 测试不兼容耗材不显示

    • 连接 U1 设备
    • 确认下拉框 "Machine Filament" 部分不显示 "Snapmaker PETG"(如果不兼容)
  2. 测试兼容耗材正常显示

    • 在 Snapmaker.json 中注册 "Snapmaker PETG @U1"
    • 连接 U1 设备
    • 确认下拉框正确显示 "Snapmaker PETG @U1"
  3. 测试其他耗材不受影响

    • 确认其他已注册的 U1 兼容耗材(如 "Snapmaker ABS @U1")正常显示

修改文件

  • src/slic3r/GUI/PresetComboBoxes.cpp(两处修改)

修改日期

2026-01-22