mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-27 10:51:22 +00:00
redesign filament_id (#15513)
# Description This PR redesigns `filament_id` across OrcaSlicer's profile library, so that one filament product now carries one consistent id everywhere it ships, instead of a hand-written value that unrelated materials routinely shared. Minting scripts and CI checks come with it so future profiles comply by construction: a new filament takes its id from the tool, and the checks reject a hand-written, duplicated or drifted one before it can merge. Unique, non-duplicated ids are a precondition for AMS-style spool syncing to be dependable — the id is what a printer matches a physical spool against, and while two products share one, the match is a coin toss. This PR lays that groundwork. A follow-up PR will publish an OrcaSlicer materials reference on the wiki, giving every system profile one place to point at. `filament_id` names one filament product, and it is what a device matches a physical spool against: Bambu AMS, Creality CFS, the Qidi box, Klipper and Snapmaker all resolve a tray to a preset by id alone, first hit wins. Those ids were written by hand, and on `main` 99 of them stand for 674 different products — `GFL99` alone covers 132, from Anycubic PLA to Bambu PLA Matte. Every consequence is silent: a spool resolves to whichever preset happens to load first, tray names and support-material flags are read off the wrong material, and the second preset holding a duplicated id disappears from the tray-edit dialog entirely. The id is now a hash of `(filament_vendor, filament_type, filament name)`, so one spool product carries one id in every bundle that ships it, two vendors shipping the same product converge on it without coordinating, and a collision cannot be authored by hand. Every ambiguity across 48 vendors is fixed rather than excused — no grandfather list and no per-vendor carve-out, Bambu's bundle included — and the resulting landscape is frozen in `scripts/filament_id_snapshot.json`, so a change to any filament's identity lands as a reviewable diff to one file. CI now runs the duplicate-subtype validation tree-wide instead of over Bambu only. Letting the id follow the product meant correcting the identities themselves. Generics that shipped under a vendor prefix now have one name and one id everywhere (`Blocks Generic PETG` is `Generic PETG @Blocks`), presets whose `filament_vendor` or `filament_type` contradicted the spool are fixed, and duplicate pairs are collapsed onto the better-configured survivor. Renames carry `renamed_from`, so existing projects and user presets keep resolving. Bambu's printers, its AMS and its cloud know only Bambu's own catalog ids, so those ids leave the profiles entirely. The Bambu bundle mints like every other vendor, and the printer agent swaps in the catalog value only where an id crosses to or from a Bambu printer — outbound MQTT and FTP, the AMS mapping sent with a job, the ids written into a 3mf the printer will read — mapping back on the way in, so status messages, SD-card prints and projects saved by an older Orca or by BambuStudio all still resolve. The correspondence is generated from BambuStudio's own shipped bundle by `scripts/update_bambu_filament_ids.py`; an id with no row is forwarded untouched, a missing or malformed map degrades to no translation rather than taking the app down, and an agent whose printers already speak Orca's ids translates nothing. Two device-side bugs this work surfaced are fixed here as well. The Orca Filament Library was missing from the AMS material and calibration dialogs, which treated a filament with no `compatible_printers` as compatible with nothing while the rest of the app treats it as compatible with everything; and Creality CFS sync on a K2-family stock 0.4 nozzle picked the wrong preset, an imprecise matcher that duplicate ids had been masking. `docs/HLSD/filament_id.md` is the authoring rule for all of this. `scripts/orca_id_tool.py` mints both `filament_id` and `setting_id`, replacing `assign_vendor_setting_ids.py`, and the local `check_profile` scripts gained per-vendor scoping so one vendor can be checked without a tree-wide run. `scripts/tests/` covers the tooling; `tests/slic3rutils/` covers the boundary translation and the CFS matcher. Ids change for most products and nothing forwards the old value, so a tray or a calibration record still holding one falls back to matching by filament type until the filament is selected once. Beyond the profile fixes above no print settings change, except that a few presets stop claiming printers a dedicated variant already covers. # Screenshots/Recordings/Graphs <!-- > Please attach relevant screenshots to showcase the UI changes. > Please attach images that can help explain the changes. --> ## Tests <!-- > Please describe the tests that you have conducted to verify the changes made in this PR. --> `scripts/check_profile.sh`, the local twin of the "Check profiles" CI job, with `scripts/check_profile.bat` as its Windows entry point, passes on this branch: the extra JSON check reports no errors and no warnings, system validation and the now tree-wide filament-subtype check load all 66 vendors cleanly, all 1013 printer presets slice, and custom-preset validation passes against every fixture archive from v1.9.0 to v2.4.2. The id tooling has 176 unit tests (`python -m unittest discover -s scripts/tests`). The C++ suites pass too — 332 in `tests/libslic3r` and 126 in `tests/slic3rutils`, the latter including the boundary-translation and Creality CFS matching cases added here. <!-- > A guide for users on how to download the artifacts from this PR. --> [How to Download Pull Requests Artifacts for Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts)
This commit is contained in:
@@ -1511,6 +1511,10 @@ void AMSDryCtrWin::update_filament_guide_info(DevAms* dev_ams)
|
||||
m_temperature_input->GetValue().ToLong(&input_temp);
|
||||
bool can_start = true;
|
||||
|
||||
// "GFA00" is Bambu's PLA id; GetFilamentDryingPreset is keyed by our OF ids.
|
||||
auto* agent = wxGetApp().getAgent();
|
||||
const std::string pla_filament_id = agent ? agent->to_orca_filament_id("GFA00") : std::string("GFA00");
|
||||
|
||||
int slot_count = 0, empty_count = 0;
|
||||
for (auto& tray_pair : dev_ams->GetTrays()) {
|
||||
if (!tray_pair.second) {
|
||||
@@ -1526,13 +1530,15 @@ void AMSDryCtrWin::update_filament_guide_info(DevAms* dev_ams)
|
||||
wxString filament_type = tray_pair.second->get_display_filament_type();
|
||||
DevFilamentDryingPreset preset;
|
||||
if (filament_type.IsEmpty()) {
|
||||
auto fallback_preset = DevUtilBackend::GetFilamentDryingPreset("GFA00");
|
||||
auto fallback_preset = DevUtilBackend::GetFilamentDryingPreset(pla_filament_id);
|
||||
if (!fallback_preset) continue; // no PLA preset (e.g. the id map is missing): skip, don't throw
|
||||
preset = fallback_preset.value();
|
||||
filament_type = "?";
|
||||
} else if (preset_opt.has_value()) {
|
||||
preset = preset_opt.value();
|
||||
} else {
|
||||
auto fallback_preset = DevUtilBackend::GetFilamentDryingPreset("GFA00");
|
||||
auto fallback_preset = DevUtilBackend::GetFilamentDryingPreset(pla_filament_id);
|
||||
if (!fallback_preset) continue;
|
||||
preset = fallback_preset.value();
|
||||
}
|
||||
std::string icon_path = "dev_ams_dry_ctr_enable";
|
||||
@@ -1594,39 +1600,21 @@ int AMSDryCtrWin::update_filament_list(DevAms* dev_ams, MachineObject* obj)
|
||||
}
|
||||
stream << std::fixed << std::setprecision(1) << obj->GetExtderSystem()->GetNozzleDiameter(extruder_id);
|
||||
std::string nozzle_diameter_str = stream.str();
|
||||
std::set<std::string> printer_names = preset_bundle->get_printer_names_by_printer_type_and_nozzle(
|
||||
DevPrinterConfigUtil::get_printer_display_name(obj->printer_type), nozzle_diameter_str);
|
||||
|
||||
for (auto filament_it = filaments.begin(); filament_it != filaments.end(); ++filament_it) {
|
||||
Preset& preset = *filament_it;
|
||||
// Filter by system preset: root preset and (system preset or user preset is supported)
|
||||
if (filaments.get_preset_base(*filament_it) != &preset || (!filament_it->is_system && !obj->is_support_user_preset)) {
|
||||
for (Preset *filament_it : preset_bundle->get_filament_presets_for_machine(
|
||||
DevPrinterConfigUtil::get_printer_display_name(obj->printer_type), nozzle_diameter_str, obj->is_support_user_preset)) {
|
||||
if (!filament_id_set.insert(filament_it->filament_id).second)
|
||||
continue;
|
||||
const std::string filament_alias = filaments.get_preset_alias(*filament_it, true);
|
||||
if (filament_alias.empty())
|
||||
continue;
|
||||
auto opt_info = preset_bundle->get_filament_by_filament_id(filament_it->filament_id);
|
||||
if (!opt_info.has_value())
|
||||
continue;
|
||||
}
|
||||
|
||||
ConfigOption * printer_opt = filament_it->config.option("compatible_printers");
|
||||
ConfigOptionStrings *printer_strs = dynamic_cast<ConfigOptionStrings *>(printer_opt);
|
||||
if (!printer_strs) continue;
|
||||
|
||||
for (auto printer_str : printer_strs->values) {
|
||||
if (printer_names.find(printer_str) != printer_names.end()) {
|
||||
if (filament_id_set.find(filament_it->filament_id) != filament_id_set.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
filament_id_set.insert(filament_it->filament_id);
|
||||
auto filament_alias = filaments.get_preset_alias(*filament_it, true);
|
||||
if (!filament_alias.empty()) {
|
||||
auto opt_info = preset_bundle->get_filament_by_filament_id(filament_it->filament_id);
|
||||
if (opt_info.has_value()) {
|
||||
auto real_info = opt_info.value();
|
||||
real_info.filament_name = filament_alias;
|
||||
m_tray_ids.push_back(std::move(real_info));
|
||||
m_trays_combo->Append(wxString::FromUTF8(filament_alias));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
opt_info->filament_name = filament_alias;
|
||||
m_tray_ids.push_back(std::move(*opt_info));
|
||||
m_trays_combo->Append(wxString::FromUTF8(filament_alias));
|
||||
}
|
||||
|
||||
if (m_tray_ids.empty()) {
|
||||
@@ -1701,9 +1689,10 @@ int AMSDryCtrWin::update_filament_list(DevAms* dev_ams, MachineObject* obj)
|
||||
|
||||
// Select recommended drying temperature and default filament
|
||||
float min_dry_temp = std::numeric_limits<float>::max();
|
||||
std::string default_filament_id = "GFA00";
|
||||
auto* agent = wxGetApp().getAgent();
|
||||
std::string default_filament_id = agent ? agent->to_orca_filament_id("GFA00") : std::string("GFA00"); // compared against m_tray_ids[i].filament_id (our OF ids) below
|
||||
bool has_ready = false;
|
||||
const auto fallback_preset = DevUtilBackend::GetFilamentDryingPreset("GFA00");
|
||||
const auto fallback_preset = DevUtilBackend::GetFilamentDryingPreset(default_filament_id);
|
||||
for (const auto& tray_pair : dev_ams->GetTrays()) {
|
||||
if (!tray_pair.second || !tray_pair.second->is_tray_info_ready()) continue;
|
||||
has_ready = true;
|
||||
|
||||
@@ -681,6 +681,19 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event)
|
||||
}
|
||||
|
||||
|
||||
// Orca: log the tray payload this dialog hands the printer, so the filament_id resolved from the
|
||||
// dropdown selection can be checked against the tray_info_idx the AMS actually receives. A
|
||||
// BBL-tagged (RFID) tray is read-only here, so nothing is published for it.
|
||||
BOOST_LOG_TRIVIAL(info) << "ams_materials_setting: " << (m_is_third ? "sending" : "NOT sending (BBL RFID tray, read-only)")
|
||||
<< ", ams_id = " << ams_id << ", slot_id = " << slot_id
|
||||
<< ", selected = " << m_comboBox_filament->GetValue().ToStdString()
|
||||
<< ", tray_info_idx (filament_id) = " << ams_filament_id
|
||||
<< ", setting_id = " << ams_setting_id
|
||||
<< ", tray_type = " << m_filament_type
|
||||
<< ", tray_color = " << col_buf
|
||||
<< ", nozzle_temp_min = " << nozzle_temp_min_int
|
||||
<< ", nozzle_temp_max = " << nozzle_temp_max_int;
|
||||
|
||||
// set filament
|
||||
if (m_is_third) {
|
||||
obj->command_ams_filament_settings(ams_id, slot_id, ams_filament_id, ams_setting_id, std::string(col_buf), m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int);
|
||||
@@ -802,7 +815,10 @@ void AMSMaterialsSetting::set_color(wxColour color)
|
||||
fila_color.m_colors.insert(color);
|
||||
fila_color.EndSet(m_clr_picker->ctype);
|
||||
auto clr_query = GUI::wxGetApp().get_filament_color_code_query();
|
||||
m_clr_name->SetLabelText(clr_query->GetFilaColorName(ams_filament_id, fila_color));
|
||||
// ams_filament_id is our OF id; GetFilaColorName looks up filaments_color_codes.json,
|
||||
// downloaded from Bambu and keyed by the printer's own ids, so translate for this lookup only.
|
||||
auto* agent = GUI::wxGetApp().getAgent();
|
||||
m_clr_name->SetLabelText(clr_query->GetFilaColorName(agent ? agent->from_orca_filament_id(ams_filament_id) : ams_filament_id, fila_color));
|
||||
}
|
||||
|
||||
void AMSMaterialsSetting::set_empty_color(wxColour color)
|
||||
@@ -823,7 +839,10 @@ void AMSMaterialsSetting::set_colors(std::vector<wxColour> colors)
|
||||
for (const auto& clr : colors) { fila_color.m_colors.insert(clr); }
|
||||
fila_color.EndSet(m_clr_picker->ctype);
|
||||
auto clr_query = GUI::wxGetApp().get_filament_color_code_query();
|
||||
m_clr_name->SetLabelText(clr_query->GetFilaColorName(ams_filament_id, fila_color));
|
||||
// ams_filament_id is our OF id; GetFilaColorName looks up filaments_color_codes.json,
|
||||
// downloaded from Bambu and keyed by the printer's own ids, so translate for this lookup only.
|
||||
auto* agent = GUI::wxGetApp().getAgent();
|
||||
m_clr_name->SetLabelText(clr_query->GetFilaColorName(agent ? agent->from_orca_filament_id(ams_filament_id) : ams_filament_id, fila_color));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -932,7 +951,6 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi
|
||||
m_input_k_val->GetTextCtrl()->SetValue(k);
|
||||
m_input_n_val->GetTextCtrl()->SetValue(n);
|
||||
|
||||
int idx = 0;
|
||||
wxArrayString filament_items;
|
||||
wxString bambu_filament_name;
|
||||
wxString hint_filament_name; // the hint type to be selected
|
||||
@@ -940,6 +958,9 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi
|
||||
std::unordered_map<wxString, wxString> query_filament_types; //
|
||||
|
||||
std::set<std::string> filament_id_set;
|
||||
// The alias keyed map has to start empty: it is a member, so a stale alias left by an earlier
|
||||
// popup (a different printer, a different nozzle) would resolve to that printer's filament_id.
|
||||
map_filament_items.clear();
|
||||
PresetBundle * preset_bundle = wxGetApp().preset_bundle;
|
||||
std::ostringstream stream;
|
||||
// Defensive: this dialog is opened only from StatusPanel (BBL-only) today, so the fallback fires
|
||||
@@ -952,83 +973,48 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi
|
||||
}
|
||||
stream << std::fixed << std::setprecision(1) << machine_diameter;
|
||||
std::string nozzle_diameter_str = stream.str();
|
||||
std::set<std::string> printer_names = preset_bundle->get_printer_names_by_printer_type_and_nozzle(DevPrinterConfigUtil::get_printer_display_name(obj->printer_type), nozzle_diameter_str);
|
||||
|
||||
if (preset_bundle) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "system_preset_bundle filament number=" << preset_bundle->filaments.size();
|
||||
for (auto filament_it = preset_bundle->filaments.begin(); filament_it != preset_bundle->filaments.end(); filament_it++) {
|
||||
//filter by system preset
|
||||
Preset& preset = *filament_it;
|
||||
/*The situation where the user preset is not displayed is as follows:
|
||||
1. Not a root preset
|
||||
2. Not system preset and the printer firmware does not support user preset */
|
||||
if (preset_bundle->filaments.get_preset_base(*filament_it) != &preset || (!filament_it->is_system && !obj->is_support_user_preset)) {
|
||||
for (Preset *filament_it : preset_bundle->get_filament_presets_for_machine(
|
||||
DevPrinterConfigUtil::get_printer_display_name(obj->printer_type), nozzle_diameter_str, obj->is_support_user_preset)) {
|
||||
if (!filament_id_set.insert(filament_it->filament_id).second)
|
||||
continue;
|
||||
const std::string alias = preset_bundle->filaments.get_preset_alias(*filament_it, true);
|
||||
if (alias.empty())
|
||||
continue;
|
||||
}
|
||||
|
||||
ConfigOption * printer_opt = filament_it->config.option("compatible_printers");
|
||||
ConfigOptionStrings *printer_strs = dynamic_cast<ConfigOptionStrings *>(printer_opt);
|
||||
for (auto printer_str : printer_strs->values) {
|
||||
if (printer_names.find(printer_str) != printer_names.end()) {
|
||||
if (filament_id_set.find(filament_it->filament_id) != filament_id_set.end()) {
|
||||
continue;
|
||||
} else {
|
||||
filament_id_set.insert(filament_it->filament_id);
|
||||
// name matched
|
||||
if (filament_it->is_system) {
|
||||
filament_items.push_back(filament_it->alias);
|
||||
_collect_filament_info(filament_it->alias, preset, query_filament_vendors, query_filament_types);
|
||||
filament_items.push_back(alias);
|
||||
_collect_filament_info(alias, *filament_it, query_filament_vendors, query_filament_types);
|
||||
|
||||
FilamentInfos filament_infos;
|
||||
filament_infos.filament_id = filament_it->filament_id;
|
||||
filament_infos.setting_id = filament_it->setting_id;
|
||||
map_filament_items[filament_it->alias] = filament_infos;
|
||||
} else {
|
||||
char target = '@';
|
||||
size_t pos = filament_it->name.find(target);
|
||||
if (pos != std::string::npos) {
|
||||
std::string user_preset_alias = filament_it->name.substr(0, pos - 1);
|
||||
wxString wx_user_preset_alias = wxString(user_preset_alias.c_str(), wxConvUTF8);
|
||||
user_preset_alias = wx_user_preset_alias.ToStdString();
|
||||
FilamentInfos filament_infos;
|
||||
filament_infos.filament_id = filament_it->filament_id;
|
||||
filament_infos.setting_id = filament_it->setting_id;
|
||||
map_filament_items[alias] = filament_infos;
|
||||
|
||||
filament_items.push_back(user_preset_alias);
|
||||
_collect_filament_info(user_preset_alias, preset, query_filament_vendors, query_filament_types);
|
||||
|
||||
FilamentInfos filament_infos;
|
||||
filament_infos.filament_id = filament_it->filament_id;
|
||||
filament_infos.setting_id = filament_it->setting_id;
|
||||
map_filament_items[user_preset_alias] = filament_infos;
|
||||
}
|
||||
}
|
||||
|
||||
if (filament_it->filament_id == ams_filament_id) {
|
||||
hint_filament_name = from_u8(filament_it->alias);
|
||||
bambu_filament_name = from_u8(filament_it->alias);
|
||||
if (filament_it->filament_id == ams_filament_id) {
|
||||
hint_filament_name = from_u8(alias);
|
||||
bambu_filament_name = from_u8(alias);
|
||||
|
||||
|
||||
// update if nozzle_temperature_range is found
|
||||
ConfigOption *opt_min = filament_it->config.option("nozzle_temperature_range_low");
|
||||
if (opt_min) {
|
||||
ConfigOptionInts *opt_min_ints = dynamic_cast<ConfigOptionInts *>(opt_min);
|
||||
if (opt_min_ints) {
|
||||
wxString text_nozzle_temp_min = wxString::Format("%d", opt_min_ints->get_at(0));
|
||||
m_input_nozzle_min->GetTextCtrl()->SetValue(text_nozzle_temp_min);
|
||||
}
|
||||
}
|
||||
ConfigOption *opt_max = filament_it->config.option("nozzle_temperature_range_high");
|
||||
if (opt_max) {
|
||||
ConfigOptionInts *opt_max_ints = dynamic_cast<ConfigOptionInts *>(opt_max);
|
||||
if (opt_max_ints) {
|
||||
wxString text_nozzle_temp_max = wxString::Format("%d", opt_max_ints->get_at(0));
|
||||
m_input_nozzle_max->GetTextCtrl()->SetValue(text_nozzle_temp_max);
|
||||
}
|
||||
}
|
||||
}
|
||||
idx++;
|
||||
// update if nozzle_temperature_range is found
|
||||
ConfigOption *opt_min = filament_it->config.option("nozzle_temperature_range_low");
|
||||
if (opt_min) {
|
||||
ConfigOptionInts *opt_min_ints = dynamic_cast<ConfigOptionInts *>(opt_min);
|
||||
if (opt_min_ints) {
|
||||
wxString text_nozzle_temp_min = wxString::Format("%d", opt_min_ints->get_at(0));
|
||||
m_input_nozzle_min->GetTextCtrl()->SetValue(text_nozzle_temp_min);
|
||||
}
|
||||
}
|
||||
ConfigOption *opt_max = filament_it->config.option("nozzle_temperature_range_high");
|
||||
if (opt_max) {
|
||||
ConfigOptionInts *opt_max_ints = dynamic_cast<ConfigOptionInts *>(opt_max);
|
||||
if (opt_max_ints) {
|
||||
wxString text_nozzle_temp_max = wxString::Format("%d", opt_max_ints->get_at(0));
|
||||
m_input_nozzle_max->GetTextCtrl()->SetValue(text_nozzle_temp_max);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1251,56 +1237,47 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt)
|
||||
stream << std::fixed << std::setprecision(1) << machine_diameter;
|
||||
}
|
||||
std::string nozzle_diameter_str = stream.str();
|
||||
std::set<std::string> printer_names = preset_bundle->get_printer_names_by_printer_type_and_nozzle(DevPrinterConfigUtil::get_printer_display_name(obj->printer_type),
|
||||
nozzle_diameter_str);
|
||||
for (auto it = preset_bundle->filaments.begin(); it != preset_bundle->filaments.end(); it++) {
|
||||
if (!m_comboBox_filament->GetValue().IsEmpty()) {
|
||||
auto filament_item = map_filament_items[m_comboBox_filament->GetValue().ToStdString()];
|
||||
std::string filament_id = filament_item.filament_id;
|
||||
if (it->filament_id.compare(filament_id) == 0) {
|
||||
ConfigOption * printer_opt = it->config.option("compatible_printers");
|
||||
ConfigOptionStrings *printer_strs = dynamic_cast<ConfigOptionStrings *>(printer_opt);
|
||||
bool has_compatible_printer = false;
|
||||
for (auto printer_str : printer_strs->values) {
|
||||
if (printer_names.find(printer_str) != printer_names.end()) {
|
||||
has_compatible_printer = true;
|
||||
break;
|
||||
}
|
||||
// Resolve the selection against the same list Popup() built the dropdown from, so the two
|
||||
// halves of the dialog cannot disagree about which filaments this machine can use.
|
||||
const std::string selected = m_comboBox_filament->GetValue().ToStdString();
|
||||
if (!selected.empty()) {
|
||||
const std::string filament_id = map_filament_items[selected].filament_id;
|
||||
for (Preset *it : preset_bundle->get_filament_presets_for_machine(
|
||||
DevPrinterConfigUtil::get_printer_display_name(obj->printer_type), nozzle_diameter_str, obj->is_support_user_preset)) {
|
||||
if (it->filament_id != filament_id)
|
||||
continue;
|
||||
// ) if nozzle_temperature_range is found
|
||||
ConfigOption* opt_min = it->config.option("nozzle_temperature_range_low");
|
||||
if (opt_min) {
|
||||
ConfigOptionInts* opt_min_ints = dynamic_cast<ConfigOptionInts*>(opt_min);
|
||||
if (opt_min_ints) {
|
||||
wxString text_nozzle_temp_min = wxString::Format("%d", opt_min_ints->get_at(0));
|
||||
m_input_nozzle_min->GetTextCtrl()->SetValue(text_nozzle_temp_min);
|
||||
}
|
||||
if (!it->is_system && !has_compatible_printer) continue;
|
||||
// ) if nozzle_temperature_range is found
|
||||
ConfigOption* opt_min = it->config.option("nozzle_temperature_range_low");
|
||||
if (opt_min) {
|
||||
ConfigOptionInts* opt_min_ints = dynamic_cast<ConfigOptionInts*>(opt_min);
|
||||
if (opt_min_ints) {
|
||||
wxString text_nozzle_temp_min = wxString::Format("%d", opt_min_ints->get_at(0));
|
||||
m_input_nozzle_min->GetTextCtrl()->SetValue(text_nozzle_temp_min);
|
||||
}
|
||||
}
|
||||
ConfigOption* opt_max = it->config.option("nozzle_temperature_range_high");
|
||||
if (opt_max) {
|
||||
ConfigOptionInts* opt_max_ints = dynamic_cast<ConfigOptionInts*>(opt_max);
|
||||
if (opt_max_ints) {
|
||||
wxString text_nozzle_temp_max = wxString::Format("%d", opt_max_ints->get_at(0));
|
||||
m_input_nozzle_max->GetTextCtrl()->SetValue(text_nozzle_temp_max);
|
||||
}
|
||||
}
|
||||
ConfigOption* opt_type = it->config.option("filament_type");
|
||||
bool found_filament_type = false;
|
||||
if (opt_type) {
|
||||
ConfigOptionStrings* opt_type_strs = dynamic_cast<ConfigOptionStrings*>(opt_type);
|
||||
if (opt_type_strs) {
|
||||
found_filament_type = true;
|
||||
//m_filament_type = opt_type_strs->get_at(0);
|
||||
std::string display_filament_type;
|
||||
m_filament_type = it->config.get_filament_type(display_filament_type);
|
||||
}
|
||||
}
|
||||
if (!found_filament_type)
|
||||
m_filament_type = "";
|
||||
|
||||
break;
|
||||
}
|
||||
ConfigOption* opt_max = it->config.option("nozzle_temperature_range_high");
|
||||
if (opt_max) {
|
||||
ConfigOptionInts* opt_max_ints = dynamic_cast<ConfigOptionInts*>(opt_max);
|
||||
if (opt_max_ints) {
|
||||
wxString text_nozzle_temp_max = wxString::Format("%d", opt_max_ints->get_at(0));
|
||||
m_input_nozzle_max->GetTextCtrl()->SetValue(text_nozzle_temp_max);
|
||||
}
|
||||
}
|
||||
ConfigOption* opt_type = it->config.option("filament_type");
|
||||
bool found_filament_type = false;
|
||||
if (opt_type) {
|
||||
ConfigOptionStrings* opt_type_strs = dynamic_cast<ConfigOptionStrings*>(opt_type);
|
||||
if (opt_type_strs) {
|
||||
found_filament_type = true;
|
||||
//m_filament_type = opt_type_strs->get_at(0);
|
||||
std::string display_filament_type;
|
||||
m_filament_type = it->config.get_filament_type(display_filament_type);
|
||||
}
|
||||
}
|
||||
if (!found_filament_type)
|
||||
m_filament_type = "";
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -702,7 +702,6 @@ wxArrayString NewCalibrationHistoryDialog::get_all_filaments(const MachineObject
|
||||
|
||||
wxArrayString filament_items;
|
||||
std::set<std::string> filament_id_set;
|
||||
std::set<std::string> printer_names;
|
||||
std::ostringstream stream;
|
||||
// If the machine didn't report a nozzle diameter (0.0 = unknown), fall back to the currently
|
||||
// selected printer preset so the filament list isn't empty.
|
||||
@@ -714,67 +713,21 @@ wxArrayString NewCalibrationHistoryDialog::get_all_filaments(const MachineObject
|
||||
stream << std::fixed << std::setprecision(1) << machine_diameter;
|
||||
std::string nozzle_diameter_str = stream.str();
|
||||
|
||||
for (auto printer_it = preset_bundle->printers.begin(); printer_it != preset_bundle->printers.end(); printer_it++) {
|
||||
// filter by system preset
|
||||
if (!printer_it->is_system)
|
||||
continue;
|
||||
// get printer_model
|
||||
ConfigOption * printer_model_opt = printer_it->config.option("printer_model");
|
||||
ConfigOptionString *printer_model_str = dynamic_cast<ConfigOptionString *>(printer_model_opt);
|
||||
if (!printer_model_str)
|
||||
continue;
|
||||
|
||||
// use printer_model as printer type
|
||||
if (printer_model_str->value != DevPrinterConfigUtil::get_printer_display_name(obj->printer_type))
|
||||
continue;
|
||||
|
||||
if (printer_it->name.find(nozzle_diameter_str) != std::string::npos)
|
||||
printer_names.insert(printer_it->name);
|
||||
}
|
||||
|
||||
if (preset_bundle) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "system_preset_bundle filament number=" << preset_bundle->filaments.size();
|
||||
for (auto filament_it = preset_bundle->filaments.begin(); filament_it != preset_bundle->filaments.end(); filament_it++) {
|
||||
// filter by system preset
|
||||
Preset &preset = *filament_it;
|
||||
/*The situation where the user preset is not displayed is as follows:
|
||||
1. Not a root preset
|
||||
2. Not system preset and the printer firmware does not support user preset */
|
||||
if (preset_bundle->filaments.get_preset_base(*filament_it) != &preset || (!filament_it->is_system && ! obj->is_support_user_preset)) { continue; }
|
||||
for (Preset *filament_it : preset_bundle->get_filament_presets_for_machine(
|
||||
DevPrinterConfigUtil::get_printer_display_name(obj->printer_type), nozzle_diameter_str, obj->is_support_user_preset)) {
|
||||
if (!filament_id_set.insert(filament_it->filament_id).second)
|
||||
continue;
|
||||
const std::string alias = preset_bundle->filaments.get_preset_alias(*filament_it, true);
|
||||
if (alias.empty())
|
||||
continue;
|
||||
|
||||
ConfigOption * printer_opt = filament_it->config.option("compatible_printers");
|
||||
ConfigOptionStrings *printer_strs = dynamic_cast<ConfigOptionStrings *>(printer_opt);
|
||||
for (auto printer_str : printer_strs->values) {
|
||||
if (printer_names.find(printer_str) != printer_names.end()) {
|
||||
if (filament_id_set.find(filament_it->filament_id) != filament_id_set.end()) {
|
||||
continue;
|
||||
} else {
|
||||
filament_id_set.insert(filament_it->filament_id);
|
||||
// name matched
|
||||
if (filament_it->is_system) {
|
||||
filament_items.push_back(filament_it->alias);
|
||||
FilamentInfos filament_infos;
|
||||
filament_infos.filament_id = filament_it->filament_id;
|
||||
filament_infos.setting_id = filament_it->setting_id;
|
||||
map_filament_items[filament_it->alias] = filament_infos;
|
||||
} else {
|
||||
char target = '@';
|
||||
size_t pos = filament_it->name.find(target);
|
||||
if (pos != std::string::npos) {
|
||||
std::string user_preset_alias = filament_it->name.substr(0, pos - 1);
|
||||
wxString wx_user_preset_alias = wxString(user_preset_alias.c_str(), wxConvUTF8);
|
||||
user_preset_alias = wx_user_preset_alias.ToStdString();
|
||||
|
||||
filament_items.push_back(user_preset_alias);
|
||||
FilamentInfos filament_infos;
|
||||
filament_infos.filament_id = filament_it->filament_id;
|
||||
filament_infos.setting_id = filament_it->setting_id;
|
||||
map_filament_items[user_preset_alias] = filament_infos;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
filament_items.push_back(alias);
|
||||
FilamentInfos filament_infos;
|
||||
filament_infos.filament_id = filament_it->filament_id;
|
||||
filament_infos.setting_id = filament_it->setting_id;
|
||||
map_filament_items[alias] = filament_infos;
|
||||
}
|
||||
}
|
||||
return filament_items;
|
||||
|
||||
@@ -62,10 +62,16 @@ std::string decompose_basic_type_from_source(size_t source_config_idx,
|
||||
auto& project_config = wxGetApp().preset_bundle->project_config;
|
||||
if (auto* filament_id_opt = project_config.option<ConfigOptionStrings>("filament_id")) {
|
||||
if (source_config_idx < filament_id_opt->values.size()) {
|
||||
const std::string& filament_id = filament_id_opt->values[source_config_idx];
|
||||
if (filament_id == kDecomposePetgFilamentId)
|
||||
// Dead in practice: "filament_id" is not in PresetBundle's s_project_options, so this
|
||||
// option() lookup (create=false) always returns null and the block never runs. Kept as
|
||||
// found, with the translation the values would need: they would be our OF ids, and the
|
||||
// two constants are the printer's own ids.
|
||||
auto* agent = wxGetApp().getAgent();
|
||||
const std::string& orca_filament_id = filament_id_opt->values[source_config_idx];
|
||||
const std::string printer_filament_id = agent ? agent->from_orca_filament_id(orca_filament_id) : orca_filament_id;
|
||||
if (printer_filament_id == kDecomposePetgFilamentId)
|
||||
return kDecomposePetgBasicType;
|
||||
if (filament_id == kDecomposePlaFilamentId)
|
||||
if (printer_filament_id == kDecomposePlaFilamentId)
|
||||
return kDecomposePlaBasicType;
|
||||
}
|
||||
}
|
||||
@@ -82,9 +88,14 @@ std::string decompose_basic_type_from_source(size_t source_config_idx,
|
||||
|
||||
std::string decompose_basic_filament_id(const std::string& basic_type)
|
||||
{
|
||||
if (basic_type == kDecomposePetgBasicType)
|
||||
return kDecomposePetgFilamentId;
|
||||
return kDecomposePlaFilamentId;
|
||||
// The result becomes DecomposeOfficialComponent::filament_id, which the rest of this file
|
||||
// reads as one of our OF ids (translating back before it compares against the printer's
|
||||
// ids), so translate on the way out; kDecompose*FilamentId itself stays the printer-side
|
||||
// literal. The only place that would carry it further, project_config's "filament_id", is
|
||||
// dead code: that key is not in PresetBundle's s_project_options.
|
||||
const std::string printer_filament_id = basic_type == kDecomposePetgBasicType ? kDecomposePetgFilamentId : kDecomposePlaFilamentId;
|
||||
auto* agent = wxGetApp().getAgent();
|
||||
return agent ? agent->to_orca_filament_id(printer_filament_id) : printer_filament_id;
|
||||
}
|
||||
|
||||
void set_created_standard_component_metadata(size_t config_idx, const DecomposeOfficialComponent& component)
|
||||
@@ -98,8 +109,11 @@ void set_created_standard_component_metadata(size_t config_idx, const DecomposeO
|
||||
}
|
||||
}
|
||||
|
||||
const std::string type = component.filament_id == kDecomposePetgFilamentId ? kDecomposePetgShortType :
|
||||
component.filament_id == kDecomposePlaFilamentId ? kDecomposePlaShortType : "";
|
||||
// component.filament_id is our OF id; the two constants are the printer's own ids.
|
||||
auto* agent = wxGetApp().getAgent();
|
||||
const std::string printer_filament_id = agent ? agent->from_orca_filament_id(component.filament_id) : component.filament_id;
|
||||
const std::string type = printer_filament_id == kDecomposePetgFilamentId ? kDecomposePetgShortType :
|
||||
printer_filament_id == kDecomposePlaFilamentId ? kDecomposePlaShortType : "";
|
||||
if (!type.empty()) {
|
||||
if (auto* type_opt = project_config.option<ConfigOptionStrings>("filament_type")) {
|
||||
while (type_opt->values.size() <= config_idx)
|
||||
@@ -151,7 +165,12 @@ DecomposeOfficialComponent lookup_decompose_official_component(
|
||||
continue;
|
||||
if (item.contains("fila_color") && item["fila_color"].is_array() && !item["fila_color"].empty())
|
||||
result.color_hex = decompose_normalize_color_hex(item["fila_color"][0].get<std::string>());
|
||||
result.filament_id = item.value("fila_id", result.filament_id);
|
||||
// fila_id from this shipped, Bambu-keyed color table is a printer-side id; translate it so
|
||||
// result.filament_id stays an OF id like the rest of this struct (the fallback default,
|
||||
// result.filament_id, is already OF and passes through unchanged).
|
||||
const std::string fila_id = item.value("fila_id", result.filament_id);
|
||||
auto* agent = wxGetApp().getAgent();
|
||||
result.filament_id = agent ? agent->to_orca_filament_id(fila_id) : fila_id;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -211,8 +230,11 @@ int find_existing_decompose_component(
|
||||
auto* type_opt = project_config.option<ConfigOptionStrings>("filament_type");
|
||||
const PresetBundle& preset_bundle = *wxGetApp().preset_bundle;
|
||||
const size_t num_physical = physical_colors.size();
|
||||
const std::string expected_basic_type = component.filament_id == kDecomposePetgFilamentId ? kDecomposePetgBasicType :
|
||||
component.filament_id == kDecomposePlaFilamentId ? kDecomposePlaBasicType : "";
|
||||
// component.filament_id is our OF id; the two constants are the printer's own ids.
|
||||
auto* agent = wxGetApp().getAgent();
|
||||
const std::string printer_filament_id = agent ? agent->from_orca_filament_id(component.filament_id) : component.filament_id;
|
||||
const std::string expected_basic_type = printer_filament_id == kDecomposePetgFilamentId ? kDecomposePetgBasicType :
|
||||
printer_filament_id == kDecomposePlaFilamentId ? kDecomposePlaBasicType : "";
|
||||
const std::string expected_short_type = expected_basic_type == kDecomposePetgBasicType ? kDecomposePetgShortType :
|
||||
expected_basic_type == kDecomposePlaBasicType ? kDecomposePlaShortType : "";
|
||||
const std::string expected_preset_part = expected_basic_type.empty() ? "" : std::string(kDecomposeBambuPresetPrefix) + expected_basic_type;
|
||||
|
||||
@@ -241,8 +241,11 @@ void check_filaments(const DevFilaBlacklist::CheckFilamentInfo& check_info, DevF
|
||||
std::set<std::string> white_fila_ids = filament_item.contains("white_fila_ids") ? filament_item["white_fila_ids"].get<std::set<std::string>>() : std::set<std::string>();
|
||||
if (!white_fila_ids.empty() && !check_info.fila_id.empty())
|
||||
{
|
||||
auto it = std::find_if(white_fila_ids.begin(), white_fila_ids.end(), [&check_info](const std::string& white_fila_id) {
|
||||
return white_fila_id == check_info.fila_id;
|
||||
// check_info.fila_id is our OF id; white_fila_ids in filaments_blacklist.json holds the printer's own.
|
||||
auto* agent = Slic3r::GUI::wxGetApp().getAgent();
|
||||
const std::string printer_filament_id = agent ? agent->from_orca_filament_id(check_info.fila_id) : check_info.fila_id;
|
||||
auto it = std::find_if(white_fila_ids.begin(), white_fila_ids.end(), [&printer_filament_id](const std::string& white_fila_id) {
|
||||
return white_fila_id == printer_filament_id;
|
||||
});
|
||||
if (it != white_fila_ids.end()) { continue; }
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
// TODO: remove this include
|
||||
#include "slic3r/GUI/DeviceManager.hpp"
|
||||
#include "slic3r/GUI/I18N.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
|
||||
#include "DevUtil.h"
|
||||
#include "DevUtilBackend.h"
|
||||
@@ -95,7 +96,12 @@ std::string DevAmsTray::get_filament_type()
|
||||
if (m_fila_type == "Sup.ABS") { return "ABS-S"; }
|
||||
if (m_fila_type == "Support W") { return "PLA-S"; }
|
||||
if (m_fila_type == "Support G") { return "PA-S"; }
|
||||
if (m_fila_type == "Support") { if (setting_id == "GFS00") { m_fila_type = "PLA-S"; } else if (setting_id == "GFS01") { m_fila_type = "PA-S"; } else { return "PLA-S"; } }
|
||||
// setting_id is our OF id; GFS00/GFS01 are the printer's own support-filament ids.
|
||||
if (m_fila_type == "Support") {
|
||||
auto* agent = GUI::wxGetApp().getAgent();
|
||||
const std::string printer_filament_id = agent ? agent->from_orca_filament_id(setting_id) : setting_id;
|
||||
if (printer_filament_id == "GFS00") { m_fila_type = "PLA-S"; } else if (printer_filament_id == "GFS01") { m_fila_type = "PA-S"; } else { return "PLA-S"; }
|
||||
}
|
||||
|
||||
return m_fila_type;
|
||||
}
|
||||
@@ -654,11 +660,14 @@ void DevFilaSystemParser::ParseV1_0(const json& jj, MachineObject* obj, DevFilaS
|
||||
curr_tray->setting_id = (*tray_it)["tray_info_idx"].get<std::string>();
|
||||
//std::string type = (*tray_it)["tray_type"].get<std::string>();
|
||||
std::string type = MachineObject::setting_id_to_type(curr_tray->setting_id, (*tray_it)["tray_type"].get<std::string>());
|
||||
if (curr_tray->setting_id == "GFS00")
|
||||
// curr_tray->setting_id is our OF id; GFS00/GFS01 are the printer's own support-filament ids.
|
||||
auto* agent = GUI::wxGetApp().getAgent();
|
||||
const std::string printer_filament_id = agent ? agent->from_orca_filament_id(curr_tray->setting_id) : curr_tray->setting_id;
|
||||
if (printer_filament_id == "GFS00")
|
||||
{
|
||||
curr_tray->m_fila_type = "PLA-S";
|
||||
}
|
||||
else if (curr_tray->setting_id == "GFS01")
|
||||
else if (printer_filament_id == "GFS01")
|
||||
{
|
||||
curr_tray->m_fila_type = "PA-S";
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ public:
|
||||
|
||||
std::string id;
|
||||
std::string tag_uid; // tag_uid
|
||||
std::string setting_id; // tray_info_idx
|
||||
std::string setting_id; // tray_info_idx, map to the filament_id
|
||||
std::string filament_setting_id; // setting_id
|
||||
std::string m_fila_type;
|
||||
std::string sub_brands;
|
||||
|
||||
@@ -110,7 +110,9 @@ bool Slic3r::is_stringing_prone_filament(const std::string& filament_id, float n
|
||||
if (filament_id.empty()) return false;
|
||||
const auto* set = pick_stringing_set(nozzle_diameter);
|
||||
if (!set) return false;
|
||||
return set->count(filament_id) > 0;
|
||||
// filament_id is one of our content-addressed OF ids; the table above is keyed by the printer's own.
|
||||
auto* agent = Slic3r::GUI::wxGetApp().getAgent();
|
||||
return set->count(agent ? agent->from_orca_filament_id(filament_id) : filament_id) > 0;
|
||||
}
|
||||
|
||||
wxString Slic3r::get_stage_string(int stage)
|
||||
@@ -5048,10 +5050,13 @@ DevAmsTray MachineObject::parse_vt_tray(json vtray)
|
||||
vt_tray.setting_id = vtray["tray_info_idx"].get<std::string>();
|
||||
//std::string type = vtray["tray_type"].get<std::string>();
|
||||
std::string type = setting_id_to_type(vt_tray.setting_id, vtray["tray_type"].get<std::string>());
|
||||
if (vt_tray.setting_id == "GFS00") {
|
||||
// vt_tray.setting_id is our OF id (translated on the way in); the two support ids below are the printer's own.
|
||||
auto* agent = GUI::wxGetApp().getAgent();
|
||||
const std::string printer_filament_id = agent ? agent->from_orca_filament_id(vt_tray.setting_id) : vt_tray.setting_id;
|
||||
if (printer_filament_id == "GFS00") {
|
||||
vt_tray.m_fila_type = "PLA-S";
|
||||
}
|
||||
else if (vt_tray.setting_id == "GFS01") {
|
||||
else if (printer_filament_id == "GFS01") {
|
||||
vt_tray.m_fila_type = "PA-S";
|
||||
}
|
||||
else {
|
||||
@@ -5592,7 +5597,10 @@ void MachineObject::update_filament_list()
|
||||
|
||||
for (auto it = filament_list.begin(); it != filament_list.end(); it++) {
|
||||
if (m_filament_list.find(it->first) != m_filament_list.end()) {
|
||||
assert(it->first.size() == 8 && it->first[0] == 'P');
|
||||
// User roots may legitimately carry adopted system-shaped ids (GF*/OF*/P-hex
|
||||
// system), so a non-'P' id here is expected, not an invariant violation.
|
||||
if (it->first.size() != 8 || it->first[0] != 'P')
|
||||
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": user-root filament_id is not user-shaped: " << it->first;
|
||||
|
||||
if (it->second.first != m_filament_list[it->first].first) {
|
||||
BOOST_LOG_TRIVIAL(info) << "old min temp is not equal to new min temp and filament id: " << it->first;
|
||||
@@ -5654,6 +5662,17 @@ void MachineObject::update_printer_preset_name()
|
||||
void MachineObject::check_ams_filament_valid()
|
||||
{
|
||||
PresetBundle * preset_bundle = Slic3r::GUI::wxGetApp().preset_bundle;
|
||||
// A tray id carried by ANY system filament preset is not a dangling user-preset id
|
||||
// (ten shipped P-hex system ids pass the 'P' shape gates below), so the destructive
|
||||
// tray-wipe / temp-rewrite handling must never fire for it.
|
||||
auto is_system_filament_id = [preset_bundle](const std::string &id) {
|
||||
if (!preset_bundle)
|
||||
return false;
|
||||
for (auto it = preset_bundle->filaments.begin(); it != preset_bundle->filaments.end(); it++)
|
||||
if (it->is_system && it->filament_id == id)
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
auto printer_model = DevPrinterConfigUtil::get_printer_display_name(this->printer_type);
|
||||
std::map<std::string, std::set<std::string>> need_checked_filament_id;
|
||||
for (auto &ams_pair : m_fila_system->GetAmsList()) {
|
||||
@@ -5675,6 +5694,8 @@ void MachineObject::check_ams_filament_valid()
|
||||
auto &checked_filament = data.checked_filament;
|
||||
for (const auto &[slot_id, curr_tray] : ams->GetTrays()) {
|
||||
|
||||
if (curr_tray->setting_id.size() == 8 && curr_tray->setting_id[0] == 'P' && is_system_filament_id(curr_tray->setting_id))
|
||||
continue;
|
||||
if (curr_tray->setting_id.size() == 8 && curr_tray->setting_id[0] == 'P' && filament_list.find(curr_tray->setting_id) == filament_list.end()) {
|
||||
if (checked_filament.find(curr_tray->setting_id) != checked_filament.end()) {
|
||||
need_checked_filament_id[nozzle_diameter_str].insert(curr_tray->setting_id);
|
||||
@@ -5735,6 +5756,8 @@ void MachineObject::check_ams_filament_valid()
|
||||
auto &data = m_nozzle_filament_data[nozzle_diameter_str];
|
||||
auto &checked_filament = data.checked_filament;
|
||||
auto &filament_list = data.filament_list;
|
||||
if (vt_tray.setting_id.size() == 8 && vt_tray.setting_id[0] == 'P' && is_system_filament_id(vt_tray.setting_id))
|
||||
continue;
|
||||
if (vt_tray.setting_id.size() == 8 && vt_tray.setting_id[0] == 'P' && filament_list.find(vt_tray.setting_id) == filament_list.end()) {
|
||||
if (checked_filament.find(vt_tray.setting_id) != checked_filament.end()) {
|
||||
need_checked_filament_id[nozzle_diameter_str].insert(vt_tray.setting_id);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "GUI_App.hpp"
|
||||
#include "MsgDialog.hpp"
|
||||
#include "libslic3r/Preset.hpp"
|
||||
#include <algorithm>
|
||||
#include "I18N.hpp"
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <wx/dcgraph.h>
|
||||
@@ -599,8 +600,10 @@ void ExtrusionCalibration::update_combobox_filaments()
|
||||
PresetBundle* preset_bundle = wxGetApp().preset_bundle;
|
||||
if (preset_bundle && obj) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "system_preset_bundle filament number=" << preset_bundle->filaments.size();
|
||||
std::string printer_type = obj->printer_type;
|
||||
std::set<std::string> printer_preset_list;
|
||||
double nozzle_value = 0.4;
|
||||
m_comboBox_nozzle_dia->GetValue().ToDouble(&nozzle_value);
|
||||
|
||||
std::vector<PresetWithVendorProfile> printer_profiles;
|
||||
for (auto printer_it = preset_bundle->printers.begin(); printer_it != preset_bundle->printers.end(); printer_it++) {
|
||||
// only use system printer preset
|
||||
if (!printer_it->is_system) continue;
|
||||
@@ -610,49 +613,42 @@ void ExtrusionCalibration::update_combobox_filaments()
|
||||
ConfigOptionFloats* printer_nozzle_vals = nullptr;
|
||||
if (printer_nozzle_opt)
|
||||
printer_nozzle_vals = dynamic_cast<ConfigOptionFloats*>(printer_nozzle_opt);
|
||||
double nozzle_value = 0.4;
|
||||
wxString nozzle_value_str = m_comboBox_nozzle_dia->GetValue();
|
||||
try {
|
||||
nozzle_value_str.ToDouble(&nozzle_value);
|
||||
} catch(...) {
|
||||
;
|
||||
}
|
||||
if (!model_id.empty() && model_id.compare(obj->printer_type) == 0
|
||||
&& printer_nozzle_vals
|
||||
&& abs(printer_nozzle_vals->get_at(0) - nozzle_value) < 1e-3) {
|
||||
printer_preset_list.insert(printer_it->name);
|
||||
printer_profiles.push_back(preset_bundle->printers.get_preset_with_vendor_profile(*printer_it));
|
||||
BOOST_LOG_TRIVIAL(trace) << "extrusion_cali: printer_model = " << model_id;
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(error) << "extrusion_cali: printer_model = " << model_id;
|
||||
}
|
||||
}
|
||||
|
||||
// Unlike the AMS dialogs this one offers every matching preset by full name rather than one
|
||||
// root preset per alias, so it filters the collection itself instead of calling
|
||||
// PresetBundle::get_filament_presets_for_machine().
|
||||
for (auto filament_it = preset_bundle->filaments.begin(); filament_it != preset_bundle->filaments.end(); filament_it++) {
|
||||
ConfigOption* printer_opt = filament_it->config.option("compatible_printers");
|
||||
ConfigOptionStrings* printer_strs = dynamic_cast<ConfigOptionStrings*>(printer_opt);
|
||||
for (auto printer_str : printer_strs->values) {
|
||||
if (printer_preset_list.find(printer_str) != printer_preset_list.end()) {
|
||||
user_filaments.push_back(&(*filament_it));
|
||||
const PresetWithVendorProfile filament = preset_bundle->filaments.get_preset_with_vendor_profile(*filament_it);
|
||||
if (std::none_of(printer_profiles.begin(), printer_profiles.end(),
|
||||
[&filament](const PresetWithVendorProfile &printer) { return is_compatible_with_printer(filament, printer); }))
|
||||
continue;
|
||||
|
||||
// set default filament id
|
||||
filament_index++;
|
||||
if (filament_it->is_system
|
||||
&& !ams_filament_id.empty()
|
||||
&& filament_it->filament_id == ams_filament_id
|
||||
) {
|
||||
curr_selection = filament_index;
|
||||
}
|
||||
user_filaments.push_back(&(*filament_it));
|
||||
|
||||
if (filament_it->name == obj->extrusion_cali_filament_name && !obj->extrusion_cali_filament_name.empty())
|
||||
{
|
||||
curr_selection = filament_index;
|
||||
}
|
||||
|
||||
wxString filament_name = wxString::FromUTF8(filament_it->name);
|
||||
filament_items.Add(filament_name);
|
||||
break;
|
||||
}
|
||||
// set default filament id
|
||||
filament_index++;
|
||||
if (filament_it->is_system
|
||||
&& !ams_filament_id.empty()
|
||||
&& filament_it->filament_id == ams_filament_id
|
||||
) {
|
||||
curr_selection = filament_index;
|
||||
}
|
||||
|
||||
if (filament_it->name == obj->extrusion_cali_filament_name && !obj->extrusion_cali_filament_name.empty())
|
||||
{
|
||||
curr_selection = filament_index;
|
||||
}
|
||||
|
||||
filament_items.Add(wxString::FromUTF8(filament_it->name));
|
||||
}
|
||||
m_comboBox_filament->Set(filament_items);
|
||||
m_comboBox_filament->SetSelection(curr_selection);
|
||||
|
||||
@@ -8824,6 +8824,11 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
||||
if (wipe_tower_y_opt)
|
||||
file_wipe_tower_y = *wipe_tower_y_opt;
|
||||
|
||||
if (auto* agent = wxGetApp().getAgent()) {
|
||||
if (auto* ids = config.opt<ConfigOptionStrings>("filament_ids"))
|
||||
for (std::string& id : ids->values)
|
||||
id = agent->to_orca_filament_id(id);
|
||||
}
|
||||
preset_bundle->load_config_model(filename.string(), std::move(config), file_version);
|
||||
|
||||
ConfigOption* bed_type_opt = preset_bundle->project_config.option("curr_bed_type");
|
||||
@@ -18671,6 +18676,8 @@ int Plater::export_3mf(const boost::filesystem::path& output_path, SaveStrategy
|
||||
nozzle_diameter_str = nozzle_diameter_option->serialize();
|
||||
|
||||
std::string printer_model_id = preset_bundle.printers.get_edited_preset().get_printer_type(&preset_bundle);
|
||||
// The printer reads slice_info.config and knows only its own catalog ids.
|
||||
auto* id_agent = preset_bundle.is_bbl_vendor() ? wxGetApp().getAgent() : nullptr;
|
||||
|
||||
for (int i = 0; i < plate_data_list.size(); i++) {
|
||||
PlateData *plate_data = plate_data_list[i];
|
||||
@@ -18680,6 +18687,8 @@ int Plater::export_3mf(const boost::filesystem::path& output_path, SaveStrategy
|
||||
std::string display_filament_type;
|
||||
it->type = cfg.get_filament_type(display_filament_type, it->id);
|
||||
it->filament_id = filament_id_opt ? filament_id_opt->get_at(it->id) : "";
|
||||
if (id_agent)
|
||||
it->filament_id = id_agent->from_orca_filament_id(it->filament_id);
|
||||
it->color = filament_color ? filament_color->get_at(it->id) : "#FFFFFF";
|
||||
// save filament info used in curr plate
|
||||
int index = p->partplate_list.get_curr_plate_index();
|
||||
|
||||
@@ -873,10 +873,15 @@ PlaterPresetComboBox::PlaterPresetComboBox(wxWindow *parent, Preset::Type preset
|
||||
auto fila_type = Preset::remove_suffix_modified(GetValue().ToUTF8().data());
|
||||
bool is_official = boost::algorithm::starts_with(fila_type, "Bambu");
|
||||
if (is_official) {
|
||||
// Get filament_id from filament_presets
|
||||
// Get filament_id from filament_presets. FilamentPickerDialog looks up
|
||||
// filaments_color_codes.json, which is downloaded from Bambu and keyed by the
|
||||
// printer's own ids, so translate our OF id (the "GFA00" fallback is already one).
|
||||
const std::string& preset_name = m_preset_bundle->filament_presets[m_filament_idx];
|
||||
const Preset* selected_preset = m_collection->find_preset(preset_name);
|
||||
wxString fila_id = selected_preset ? wxString::FromUTF8(selected_preset->filament_id) : "GFA00";
|
||||
auto* agent = wxGetApp().getAgent();
|
||||
wxString fila_id = "GFA00";
|
||||
if (selected_preset)
|
||||
fila_id = wxString::FromUTF8(agent ? agent->from_orca_filament_id(selected_preset->filament_id) : selected_preset->filament_id);
|
||||
FilamentColor fila_color = get_cur_color_info();
|
||||
|
||||
// Show filament picker dialog
|
||||
|
||||
@@ -3845,8 +3845,12 @@ int SelectMachineDialog::update_print_required_data(Slic3r::DynamicPrintConfig c
|
||||
m_required_data_config = config;
|
||||
m_required_data_model = model;
|
||||
//m_required_data_plate_data_list = plate_data_list;
|
||||
auto* agent = wxGetApp().getAgent();
|
||||
for (auto i = 0; i < plate_data_list.size(); i++) {
|
||||
if (!plate_data_list[i]->gcode_file.empty()) {
|
||||
if (agent)
|
||||
for (auto& info : plate_data_list[i]->slice_filaments_info)
|
||||
info.filament_id = agent->to_orca_filament_id(info.filament_id);
|
||||
m_required_data_plate_data_list.push_back(plate_data_list[i]);
|
||||
}
|
||||
}
|
||||
@@ -5051,8 +5055,11 @@ void SelectMachineDialog::update_show_status(MachineObject* obj_)
|
||||
const auto& warning_tpu_filaments =
|
||||
DevPrinterConfigUtil::get_value_from_config<std::vector<std::string>>(obj_->printer_type, "auto_on_cali_warning_tpu_filaments");
|
||||
if (!warning_tpu_filaments.empty()) {
|
||||
auto* agent = wxGetApp().getAgent();
|
||||
for (const auto& fila : m_ams_mapping_result) {
|
||||
if (std::find(warning_tpu_filaments.begin(), warning_tpu_filaments.end(), fila.filament_id) != warning_tpu_filaments.end()) {
|
||||
// fila.filament_id is our OF id; the printer config list holds the printer's own.
|
||||
const std::string printer_filament_id = agent ? agent->from_orca_filament_id(fila.filament_id) : fila.filament_id;
|
||||
if (std::find(warning_tpu_filaments.begin(), warning_tpu_filaments.end(), printer_filament_id) != warning_tpu_filaments.end()) {
|
||||
show_status(PrintDialogStatus::PrintStatusTPUUnsuggestCali,
|
||||
{ _L("If 'Dynamic Flow Calibration' is set to Auto/On, the system will use the manual calibration value or the default value and skip the flow calibration process. You can perform a manual flow calibration for TPU filament on the 'Calibration' page.") });
|
||||
break;
|
||||
@@ -5208,9 +5215,12 @@ bool SelectMachineDialog::can_support_pa_auto_cali()
|
||||
|
||||
std::vector<std::string> unsupport_auto_cali_filaments = DevPrinterConfigUtil::get_unsupport_auto_cali_filaments(obj->printer_type);
|
||||
if (!unsupport_auto_cali_filaments.empty()) {
|
||||
auto* agent = wxGetApp().getAgent();
|
||||
auto iter = std::find_if(m_filaments.begin(), m_filaments.end(),
|
||||
[&unsupport_auto_cali_filaments](const FilamentInfo &item) {
|
||||
auto iter = std::find(unsupport_auto_cali_filaments.begin(), unsupport_auto_cali_filaments.end(), item.filament_id);
|
||||
[&unsupport_auto_cali_filaments, agent](const FilamentInfo &item) {
|
||||
// item.filament_id is our OF id; the printer config list holds the printer's own.
|
||||
const std::string printer_filament_id = agent ? agent->from_orca_filament_id(item.filament_id) : item.filament_id;
|
||||
auto iter = std::find(unsupport_auto_cali_filaments.begin(), unsupport_auto_cali_filaments.end(), printer_filament_id);
|
||||
return iter != unsupport_auto_cali_filaments.end();
|
||||
});
|
||||
|
||||
|
||||
@@ -1,11 +1,121 @@
|
||||
#include "BBLPrinterAgent.hpp"
|
||||
#include "BBLNetworkPlugin.hpp"
|
||||
#include "NetworkAgentFactory.hpp"
|
||||
#include "libslic3r/Utils.hpp"
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
#include <nlohmann/json.hpp>
|
||||
using json = nlohmann::json;
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
namespace {
|
||||
|
||||
// Bambu's own catalog ids for every filament this app ships, Bambu's own included, since Orca
|
||||
// content-addresses those too. Keyed both ways so each of the four translation entry points
|
||||
// below is a single lookup. Loaded once per process, on first use. A missing or malformed file
|
||||
// logs once and leaves both maps empty, so every translation degrades to identity. Same shape
|
||||
// as DevFilaBlacklist::load_filaments_blacklist_config.
|
||||
struct BambuFilamentIdMap { std::unordered_map<std::string, std::string> to_bambu, to_orca; };
|
||||
|
||||
const BambuFilamentIdMap& bambu_filament_id_map()
|
||||
{
|
||||
static const BambuFilamentIdMap map = [] {
|
||||
BambuFilamentIdMap m;
|
||||
const std::string path = resources_dir() + "/printers/bambu_filament_ids.json";
|
||||
try {
|
||||
boost::nowide::ifstream file(path);
|
||||
if (!file.is_open()) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Bambu filament id map not found, ids pass through untranslated: " << path;
|
||||
return m;
|
||||
}
|
||||
json doc;
|
||||
file >> doc;
|
||||
for (const auto& [orca_filament_id, row] : doc.at("filaments").items()) {
|
||||
const std::string bambu_id = row.at("bambu_id").get<std::string>();
|
||||
m.to_bambu.emplace(orca_filament_id, bambu_id);
|
||||
m.to_orca.emplace(bambu_id, orca_filament_id);
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Bambu filament id map unreadable, ids pass through untranslated: " << e.what();
|
||||
m = {};
|
||||
}
|
||||
return m;
|
||||
}();
|
||||
return map;
|
||||
}
|
||||
|
||||
// Rewrites every string under "tray_info_idx", "filament_id" or "filamentId", at any depth, in place.
|
||||
void rewrite_filament_ids(json& j, const std::unordered_map<std::string, std::string>& map)
|
||||
{
|
||||
if (j.is_object()) {
|
||||
for (auto& [key, value] : j.items()) {
|
||||
if (value.is_string() && (key == "tray_info_idx" || key == "filament_id" || key == "filamentId")) {
|
||||
auto it = map.find(value.get_ref<const std::string&>());
|
||||
if (it != map.end())
|
||||
value = it->second;
|
||||
} else
|
||||
rewrite_filament_ids(value, map);
|
||||
}
|
||||
} else if (j.is_array())
|
||||
for (auto& element : j)
|
||||
rewrite_filament_ids(element, map);
|
||||
}
|
||||
|
||||
// Text that does not parse as JSON, or that mentions none of the id keys, comes back byte-identical.
|
||||
std::string rewrite_filament_ids(std::string text, const std::unordered_map<std::string, std::string>& map)
|
||||
{
|
||||
if (map.empty() || (text.find("tray_info_idx") == std::string::npos && text.find("filament_id") == std::string::npos &&
|
||||
text.find("filamentId") == std::string::npos))
|
||||
return text; // nothing to map, skip the parse (moved, not copied)
|
||||
try {
|
||||
json j = json::parse(text);
|
||||
rewrite_filament_ids(j, map);
|
||||
return j.dump();
|
||||
} catch (const std::exception&) {
|
||||
return text; // not JSON: forward as received
|
||||
}
|
||||
}
|
||||
|
||||
// Wraps an inbound message callback so every Bambu id it delivers arrives already translated.
|
||||
// A null fn is a deregistration (see GUI_App.cpp's shutdown phase 1 and NetworkAgent::apply_printer_callbacks
|
||||
// clearing callbacks with {}), and must stay null rather than become a live wrapper around an empty target.
|
||||
OnMessageFn to_orca_messages(OnMessageFn fn)
|
||||
{
|
||||
if (!fn)
|
||||
return fn;
|
||||
return [fn = std::move(fn)](std::string dev_id, std::string msg) { fn(std::move(dev_id), BBLPrinterAgent::to_orca_payload(std::move(msg))); };
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string BBLPrinterAgent::to_orca_filament_id(const std::string& printer_filament_id) const
|
||||
{
|
||||
const auto& map = bambu_filament_id_map().to_orca;
|
||||
auto it = map.find(printer_filament_id);
|
||||
return it != map.end() ? it->second : printer_filament_id;
|
||||
}
|
||||
|
||||
std::string BBLPrinterAgent::from_orca_filament_id(const std::string& orca_filament_id) const
|
||||
{
|
||||
const auto& map = bambu_filament_id_map().to_bambu;
|
||||
auto it = map.find(orca_filament_id);
|
||||
return it != map.end() ? it->second : orca_filament_id;
|
||||
}
|
||||
|
||||
std::string BBLPrinterAgent::to_orca_payload(std::string json_text)
|
||||
{
|
||||
return rewrite_filament_ids(std::move(json_text), bambu_filament_id_map().to_orca);
|
||||
}
|
||||
|
||||
std::string BBLPrinterAgent::from_orca_payload(std::string json_text)
|
||||
{
|
||||
return rewrite_filament_ids(std::move(json_text), bambu_filament_id_map().to_bambu);
|
||||
}
|
||||
|
||||
BBLPrinterAgent::BBLPrinterAgent() = default;
|
||||
|
||||
BBLPrinterAgent::~BBLPrinterAgent() = default;
|
||||
@@ -22,6 +132,7 @@ void BBLPrinterAgent::set_cloud_agent(std::shared_ptr<ICloudServiceAgent> cloud)
|
||||
|
||||
int BBLPrinterAgent::send_message(std::string dev_id, std::string json_str, int qos, int flag)
|
||||
{
|
||||
json_str = from_orca_payload(std::move(json_str));
|
||||
auto& plugin = BBLNetworkPlugin::instance();
|
||||
auto agent = plugin.get_agent();
|
||||
auto func = plugin.get_send_message();
|
||||
@@ -67,6 +178,7 @@ int BBLPrinterAgent::disconnect_printer()
|
||||
|
||||
int BBLPrinterAgent::send_message_to_printer(std::string dev_id, std::string json_str, int qos, int flag)
|
||||
{
|
||||
json_str = from_orca_payload(std::move(json_str));
|
||||
auto& plugin = BBLNetworkPlugin::instance();
|
||||
auto agent = plugin.get_agent();
|
||||
auto func = plugin.get_send_message_to_printer();
|
||||
@@ -321,6 +433,7 @@ int dispatch_start(CurrentFn func, PrintParams& params, const CallbackFns&... ca
|
||||
auto agent = plugin.get_agent();
|
||||
if (!func || !agent)
|
||||
return -1;
|
||||
params.ams_mapping_info = BBLPrinterAgent::from_orca_payload(std::move(params.ams_mapping_info));
|
||||
switch (plugin.network_abi()) {
|
||||
case NetworkAbi::Legacy:
|
||||
return reinterpret_cast<LegacyFn>(func)(agent, BBLNetworkPlugin::as_legacy(params), callbacks...);
|
||||
@@ -408,7 +521,7 @@ int BBLPrinterAgent::set_on_message_fn(OnMessageFn fn)
|
||||
auto agent = plugin.get_agent();
|
||||
auto func = plugin.get_set_on_message_fn();
|
||||
if (func && agent) {
|
||||
return func(agent, fn);
|
||||
return func(agent, to_orca_messages(std::move(fn)));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -441,7 +554,7 @@ int BBLPrinterAgent::set_on_local_message_fn(OnMessageFn fn)
|
||||
auto agent = plugin.get_agent();
|
||||
auto func = plugin.get_set_on_local_message_fn();
|
||||
if (func && agent) {
|
||||
return func(agent, fn);
|
||||
return func(agent, to_orca_messages(std::move(fn)));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -84,6 +84,20 @@ public:
|
||||
int set_queue_on_main_fn(QueueOnMainFn fn) override;
|
||||
FilamentSyncMode get_filament_sync_mode() const override;
|
||||
|
||||
// Bambu's own catalog ids. Orca content-addresses every system filament, Bambu's included;
|
||||
// the printer, the AMS and Bambu's cloud know only Bambu's ids, so this agent translates at
|
||||
// the boundary through resources/printers/bambu_filament_ids.json (generated by
|
||||
// scripts/update_bambu_filament_ids.py). An id without a map row is returned as it is.
|
||||
std::string to_orca_filament_id(const std::string& printer_filament_id) const override;
|
||||
std::string from_orca_filament_id(const std::string& orca_filament_id) const override;
|
||||
|
||||
// Rewrite every string under "tray_info_idx", "filament_id" or "filamentId", at any depth,
|
||||
// in a JSON document (an MQTT payload or PrintParams::ams_mapping_info). Text that does not
|
||||
// parse, or contains none of the keys, is returned unchanged.
|
||||
// Taken by value: most outbound traffic carries no filament id and is moved straight back out.
|
||||
static std::string to_orca_payload(std::string json_text);
|
||||
static std::string from_orca_payload(std::string json_text);
|
||||
|
||||
private:
|
||||
std::shared_ptr<ICloudServiceAgent> m_cloud_agent;
|
||||
};
|
||||
|
||||
@@ -62,22 +62,29 @@ std::vector<std::string> not_support_auto_pa_cali_filaments = {
|
||||
|
||||
void get_default_k_n_value(const std::string &filament_id, float &k, float &n)
|
||||
{
|
||||
if (filament_id.compare("GFU01") == 0) {
|
||||
// filament_id is our OF id; the literals below are the printer's own. An id the agent has
|
||||
// no mapping for (e.g. a caller still on the old id) passes through unchanged.
|
||||
auto* agent = wxGetApp().getAgent();
|
||||
const std::string printer_filament_id = agent ? agent->from_orca_filament_id(filament_id) : filament_id;
|
||||
if (printer_filament_id.compare("GFU01") == 0) {
|
||||
/* TPU 95A */
|
||||
k = 0.25;
|
||||
n = 1.0;
|
||||
} else if (filament_id.compare("GFU03") == 0) {
|
||||
} else if (printer_filament_id.compare("GFU03") == 0) {
|
||||
/* TPU 90A */
|
||||
k = 0.35;
|
||||
n = 1.0;
|
||||
} else if (filament_id.compare("GFU04") == 0) {
|
||||
} else if (printer_filament_id.compare("GFU04") == 0) {
|
||||
/* TPU 85A */
|
||||
k = 0.65;
|
||||
n = 1.0;
|
||||
} else if (filament_id.compare("GFG00") == 0 || filament_id.compare("GFG01") == 0 || filament_id.compare("GFG60") == 0 || filament_id.compare("GFL06") == 0 ||
|
||||
filament_id.compare("GFL55") == 0 || filament_id.compare("GFG99") == 0 || filament_id.compare("GFG98") == 0 || filament_id.compare("GFG97") == 0 ||
|
||||
filament_id.compare("GFG50") == 0 || filament_id.compare("GFU02") == 0 || filament_id.compare("GFU98") == 0 || filament_id.compare("GFS00") == 0 ||
|
||||
filament_id.compare("GFS02") == 0) {
|
||||
} else if (printer_filament_id.compare("GFG00") == 0 || printer_filament_id.compare("GFG01") == 0 ||
|
||||
printer_filament_id.compare("GFG60") == 0 || printer_filament_id.compare("GFL06") == 0 ||
|
||||
printer_filament_id.compare("GFL55") == 0 || printer_filament_id.compare("GFG99") == 0 ||
|
||||
printer_filament_id.compare("GFG98") == 0 || printer_filament_id.compare("GFG97") == 0 ||
|
||||
printer_filament_id.compare("GFG50") == 0 || printer_filament_id.compare("GFU02") == 0 ||
|
||||
printer_filament_id.compare("GFU98") == 0 || printer_filament_id.compare("GFS00") == 0 ||
|
||||
printer_filament_id.compare("GFS02") == 0) {
|
||||
/* 0.04 filaments */
|
||||
k = 0.04;
|
||||
n = 1.0;
|
||||
@@ -1393,7 +1400,10 @@ void CalibUtils::calib_retraction(const CalibInfo &calib_info, wxString &error_m
|
||||
|
||||
bool CalibUtils::is_support_auto_pa_cali(std::string filament_id)
|
||||
{
|
||||
auto iter = std::find(not_support_auto_pa_cali_filaments.begin(), not_support_auto_pa_cali_filaments.end(), filament_id);
|
||||
// filament_id is our OF id; not_support_auto_pa_cali_filaments holds the printer's own ids.
|
||||
auto* agent = wxGetApp().getAgent();
|
||||
const std::string printer_filament_id = agent ? agent->from_orca_filament_id(filament_id) : filament_id;
|
||||
auto iter = std::find(not_support_auto_pa_cali_filaments.begin(), not_support_auto_pa_cali_filaments.end(), printer_filament_id);
|
||||
if (iter != not_support_auto_pa_cali_filaments.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@@ -16,6 +18,12 @@ namespace {
|
||||
|
||||
constexpr const char* CrealityPrintAgent_VERSION = "0.1.0";
|
||||
|
||||
std::string to_lower(std::string s)
|
||||
{
|
||||
for (auto& c : s) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
|
||||
return s;
|
||||
}
|
||||
|
||||
bool has_visible_base_preset(const PresetCollection& filaments, const std::string& filament_id)
|
||||
{
|
||||
for (const auto& p : filaments.get_presets()) {
|
||||
@@ -27,19 +35,47 @@ bool has_visible_base_preset(const PresetCollection& filaments, const std::strin
|
||||
return false;
|
||||
}
|
||||
|
||||
// Lower-case words of a preset name with the "@scope" suffix dropped:
|
||||
// "Generic PLA Matte @Creality K2-all" -> {"generic", "pla", "matte"}.
|
||||
std::vector<std::string> name_words(const std::string& name)
|
||||
{
|
||||
std::vector<std::string> words;
|
||||
std::string word;
|
||||
for (char c : name.substr(0, name.find('@'))) {
|
||||
if (std::isalnum(static_cast<unsigned char>(c))) {
|
||||
word += static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
|
||||
} else if (!word.empty()) {
|
||||
words.push_back(word);
|
||||
word.clear();
|
||||
}
|
||||
}
|
||||
if (!word.empty())
|
||||
words.push_back(word);
|
||||
return words;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Score visible compatible filament presets against the CFS spool metadata and
|
||||
// return the best-matching filament_id. Scoring:
|
||||
// +20 preset name contains brand_name as a substring
|
||||
// (e.g. "Hyper PLA" in "Hyper PLA @Creality K2 0.4 nozzle")
|
||||
// +10 preset name contains the vendor substring (e.g. "Creality")
|
||||
// Tiebreak: prefer the SYSTEM (shipped) preset over user copies. Brand-
|
||||
// specific system presets carry their own filament_id; user copies of
|
||||
// generic presets inherit a generic filament_id from their parent, so
|
||||
// preferring the user copy can collapse a brand-specific match back to
|
||||
// "Generic PLA" via the inherited id. Plus: this code targets upstream
|
||||
// OrcaSlicer where shipping the user's local tuning would be wrong.
|
||||
// +10 the preset belongs to the spool's vendor - by its owning VendorProfile OR by
|
||||
// its name. The profile test is what finds the vendor's own generics, which are
|
||||
// named "Generic <material> @<scope>" and do not repeat the vendor; the name test
|
||||
// still finds a third party filament shipped inside that vendor's bundle, which
|
||||
// carries the bundle owner's profile but names its real brand.
|
||||
// -5 per word of the preset name the spool never mentioned ("generic" excepted -
|
||||
// it marks the unbranded base product rather than a qualifier), so the least
|
||||
// specific preset that still explains the spool wins. Without it a spool
|
||||
// reporting only "PLA" scores "Generic PLA High Speed" and "Generic PLA Matte"
|
||||
// exactly as high as "Generic PLA"; those are three products with three
|
||||
// filament_ids, so whichever sorted first won and the printer got the wrong
|
||||
// one. Applied after the score gate, so it only reorders genuine matches.
|
||||
// Tiebreak: prefer the SYSTEM (shipped) preset over user copies, then by name so the
|
||||
// winner never depends on how std::sort leaves equal elements. User copies of generic
|
||||
// presets inherit a generic filament_id from their parent, so preferring the user copy
|
||||
// can collapse a brand-specific match back to "Generic PLA" via the inherited id.
|
||||
// Requires the preset's declared filament_type to equal the spool's base type
|
||||
// (PLA/PETG/ABS/...) so we never auto-pick a PETG preset for a PLA spool.
|
||||
// Falls back to filaments.filament_id_by_type(base_type) when nothing scores.
|
||||
@@ -48,15 +84,17 @@ std::string CrealityPrintAgent::match_filament_preset(const PresetCollection& fi
|
||||
const std::string& brand_name,
|
||||
const std::string& base_type)
|
||||
{
|
||||
auto to_lower = [](std::string s) {
|
||||
for (auto& c : s) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
|
||||
return s;
|
||||
};
|
||||
|
||||
const std::string vendor_lower = to_lower(vendor);
|
||||
const std::string brand_lower = to_lower(brand_name);
|
||||
const std::string type_lower = to_lower(base_type);
|
||||
|
||||
// Everything the spool told us about itself, as words. A word in a preset's name
|
||||
// that is not in here is a qualifier the spool never claimed.
|
||||
std::set<std::string> spool_words{"generic"};
|
||||
for (const std::string& src : {brand_lower, vendor_lower, type_lower})
|
||||
for (auto& w : name_words(src))
|
||||
spool_words.insert(std::move(w));
|
||||
|
||||
struct Match {
|
||||
const Preset* preset;
|
||||
int score;
|
||||
@@ -83,11 +121,20 @@ std::string CrealityPrintAgent::match_filament_preset(const PresetCollection& fi
|
||||
int score = 0;
|
||||
if (!brand_lower.empty() && name_lower.find(brand_lower) != std::string::npos)
|
||||
score += 20;
|
||||
if (!vendor_lower.empty() && name_lower.find(vendor_lower) != std::string::npos)
|
||||
// Profile OR name - neither alone covers both the vendor's own generics and the
|
||||
// third party filaments shipped inside its bundle. See the header comment.
|
||||
if (!vendor_lower.empty()
|
||||
&& ((p.vendor != nullptr && to_lower(p.vendor->name) == vendor_lower)
|
||||
|| name_lower.find(vendor_lower) != std::string::npos))
|
||||
score += 10;
|
||||
|
||||
if (score > 0)
|
||||
matches.push_back({&p, score, !p.is_system && !p.is_default});
|
||||
if (score == 0) continue;
|
||||
|
||||
for (const auto& w : name_words(p.name))
|
||||
if (spool_words.count(w) == 0)
|
||||
score -= 5;
|
||||
|
||||
matches.push_back({&p, score, !p.is_system && !p.is_default});
|
||||
}
|
||||
|
||||
if (matches.empty()) {
|
||||
@@ -105,7 +152,7 @@ std::string CrealityPrintAgent::match_filament_preset(const PresetCollection& fi
|
||||
[](const Match& a, const Match& b) {
|
||||
if (a.score != b.score) return a.score > b.score;
|
||||
if (a.is_user != b.is_user) return !a.is_user; // prefer system over user
|
||||
return false;
|
||||
return a.preset->name < b.preset->name; // keep the winner deterministic
|
||||
});
|
||||
|
||||
BOOST_LOG_TRIVIAL(info)
|
||||
|
||||
@@ -290,6 +290,16 @@ public:
|
||||
* Populates the MachineObject's DevFilaSystem with fetched filament data.
|
||||
*/
|
||||
virtual bool fetch_filament_info(std::string dev_id) { return false; }
|
||||
|
||||
/**
|
||||
* Translate one filament id across the printer boundary.
|
||||
*
|
||||
* Orca content-addresses every system filament; a printer, its AMS and its vendor cloud
|
||||
* know only that vendor's own catalog ids. An agent whose printers already speak Orca's
|
||||
* ids leaves them alone, and so does an id with no mapping.
|
||||
*/
|
||||
virtual std::string to_orca_filament_id(const std::string& printer_filament_id) const { return printer_filament_id; }
|
||||
virtual std::string from_orca_filament_id(const std::string& orca_filament_id) const { return orca_filament_id; }
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <cctype>
|
||||
#include <map>
|
||||
#include <thread>
|
||||
|
||||
namespace {
|
||||
@@ -619,51 +620,70 @@ std::string MoonrakerPrinterAgent::map_filament_type_to_generic_id(const std::st
|
||||
{
|
||||
const std::string upper = trim_and_upper(filament_type);
|
||||
|
||||
// Map to OrcaFilamentLibrary preset IDs (compatible with all printers)
|
||||
// Source: resources/profiles/OrcaFilamentLibrary/filament/
|
||||
// Normalize reported material names (trimmed, uppercased) to an OrcaFilamentLibrary
|
||||
// generic family. The family's filament_id is resolved from the loaded system presets
|
||||
// below rather than hardcoded, so profile id re-mints never require touching this table.
|
||||
// scripts/test_moonraker_lane_data.py parses this initializer; keep the {"A", "B"} format.
|
||||
static const std::map<std::string, std::string> type_to_ofl_family = {
|
||||
// PLA variants
|
||||
{"PLA", "PLA"},
|
||||
{"PLA-CF", "PLA-CF"},
|
||||
{"PLA SILK", "PLA Silk"},
|
||||
{"PLA-SILK", "PLA Silk"},
|
||||
{"PLA HIGH SPEED", "PLA High Speed"},
|
||||
{"PLA-HS", "PLA High Speed"},
|
||||
{"PLA HS", "PLA High Speed"},
|
||||
|
||||
// PLA variants
|
||||
if (upper == "PLA") return "OGFL99";
|
||||
if (upper == "PLA-CF") return "OGFL98";
|
||||
if (upper == "PLA SILK" || upper == "PLA-SILK") return "OGFL96";
|
||||
if (upper == "PLA HIGH SPEED" || upper == "PLA-HS" || upper == "PLA HS") return "OGFL95";
|
||||
// ABS/ASA variants
|
||||
{"ABS", "ABS"},
|
||||
{"ASA", "ASA"},
|
||||
|
||||
// ABS/ASA variants
|
||||
if (upper == "ABS") return "OGFB99";
|
||||
if (upper == "ASA") return "OGFB98";
|
||||
// PETG/PET variants
|
||||
{"PETG", "PETG"},
|
||||
{"PET", "PETG"},
|
||||
{"PCTG", "PCTG"},
|
||||
|
||||
// PETG/PET variants
|
||||
if (upper == "PETG" || upper == "PET") return "OGFG99";
|
||||
if (upper == "PCTG") return "OGFG97";
|
||||
// PA/Nylon variants
|
||||
{"PA", "PA"},
|
||||
{"NYLON", "PA"},
|
||||
{"PA-CF", "PA-CF"},
|
||||
{"PPA", "PPA-CF"},
|
||||
{"PPA-CF", "PPA-CF"},
|
||||
{"PPA-GF", "PPA-GF"},
|
||||
|
||||
// PA/Nylon variants
|
||||
if (upper == "PA" || upper == "NYLON") return "OGFN99";
|
||||
if (upper == "PA-CF") return "OGFN98";
|
||||
if (upper == "PPA" || upper == "PPA-CF") return "OGFN97";
|
||||
if (upper == "PPA-GF") return "OGFN96";
|
||||
// PC variants
|
||||
{"PC", "PC"},
|
||||
|
||||
// PC variants
|
||||
if (upper == "PC") return "OGFC99";
|
||||
// PP/PE variants
|
||||
{"PE", "PE"},
|
||||
{"PP", "PP"},
|
||||
|
||||
// PP/PE variants
|
||||
if (upper == "PE") return "OGFP99";
|
||||
if (upper == "PP") return "OGFP97";
|
||||
// Support materials
|
||||
{"PVA", "PVA"},
|
||||
{"HIPS", "HIPS"},
|
||||
{"BVOH", "BVOH"},
|
||||
|
||||
// Support materials
|
||||
if (upper == "PVA") return "OGFS99";
|
||||
if (upper == "HIPS") return "OGFS98";
|
||||
if (upper == "BVOH") return "OGFS97";
|
||||
// TPU variants
|
||||
{"TPU", "TPU"},
|
||||
|
||||
// TPU variants
|
||||
if (upper == "TPU") return "OGFU99";
|
||||
// Other materials
|
||||
{"EVA", "EVA"},
|
||||
{"PHA", "PHA"},
|
||||
{"COPE", "CoPE"},
|
||||
{"SBS", "SBS"},
|
||||
};
|
||||
|
||||
// Other materials
|
||||
if (upper == "EVA") return "OGFR99";
|
||||
if (upper == "PHA") return "OGFR98";
|
||||
if (upper == "COPE") return "OGFLC99";
|
||||
if (upper == "SBS") return "OFLSBS99";
|
||||
auto it = type_to_ofl_family.find(upper);
|
||||
if (it == type_to_ofl_family.end())
|
||||
return UNKNOWN_FILAMENT_ID;
|
||||
|
||||
// Unknown material
|
||||
if (auto* bundle = GUI::wxGetApp().preset_bundle) {
|
||||
const Preset* preset = bundle->filaments.find_preset("Generic " + it->second + " @System");
|
||||
if (preset != nullptr && preset->is_system && !preset->filament_id.empty())
|
||||
return preset->filament_id;
|
||||
}
|
||||
|
||||
// Unknown material, or no loaded preset data to resolve against
|
||||
return UNKNOWN_FILAMENT_ID;
|
||||
}
|
||||
|
||||
|
||||
@@ -929,6 +929,20 @@ bool NetworkAgent::fetch_filament_info(std::string dev_id)
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string NetworkAgent::to_orca_filament_id(const std::string& printer_filament_id) const
|
||||
{
|
||||
if (m_printer_agent)
|
||||
return m_printer_agent->to_orca_filament_id(printer_filament_id);
|
||||
return printer_filament_id;
|
||||
}
|
||||
|
||||
std::string NetworkAgent::from_orca_filament_id(const std::string& orca_filament_id) const
|
||||
{
|
||||
if (m_printer_agent)
|
||||
return m_printer_agent->from_orca_filament_id(orca_filament_id);
|
||||
return orca_filament_id;
|
||||
}
|
||||
|
||||
int NetworkAgent::request_bind_ticket(std::string* ticket)
|
||||
{
|
||||
if (m_printer_agent)
|
||||
|
||||
@@ -165,6 +165,8 @@ public:
|
||||
int start_sdcard_print(PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn);
|
||||
FilamentSyncMode get_filament_sync_mode() const;
|
||||
bool fetch_filament_info(std::string dev_id);
|
||||
std::string to_orca_filament_id(const std::string& printer_filament_id) const;
|
||||
std::string from_orca_filament_id(const std::string& orca_filament_id) const;
|
||||
int request_bind_ticket(std::string* ticket);
|
||||
int get_hms_snapshot(std::string dev_id, std::string file_name, std::function<void(std::string, int)> callback);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user