X2D Support (#13388)

# Description

Adresses #13294 

- Adds the X2D printer definition, machine presets, process presets,
filament presets, BBL profile index entries, CLI config entries,
filament blacklist updates, and printer/load/calibration/cover assets.
- Updates dual-nozzle handling to use configured toolhead labels and
match Bambu X2D hotend placeholders.
- Adds X2D-specific wipe tower cooling placeholder support and 3MF
filament/nozzle change sequence metadata import/export plumbing.

# Note

I own a P2S and an X2D. That's all. I frankly have no idea if my changes
cause regression on other printers, and have no capability to test. I
know that for my X2D, which runs an AMS, .2mm nozzles, SuperTack, and in
LAN mode, this has been working without issue.

# Screenshots/Recordings/Graphs

<img width="606" height="380" alt="Dual nozzle control"
src="https://github.com/user-attachments/assets/0d1c1063-4621-4097-b97c-d739557bf18c"
/>

*Dual nozzle control*

<img width="726" height="260" alt="image"
src="https://github.com/user-attachments/assets/270355b7-ca67-4ca3-ad19-582b8f11411b"
/>

*Multi nozzle filament override*

<img width="416" height="202" alt="X2D Machine config and dual nozzle
support"
src="https://github.com/user-attachments/assets/6a5c07b2-0d20-4819-8f42-d60731313249"
/>

*X2D Machine config and dual nozzle support*

<img width="397" height="142" alt="Filament for Supports test prints"
src="https://github.com/user-attachments/assets/3c7546bd-0e27-4d56-89b7-d9ca18c976f9"
/>

*Filament for Supports has been used in over 20 hours of test prints*

<img width="210" height="263" alt="Left vs Right filament distinction"
src="https://github.com/user-attachments/assets/03322268-b669-4f14-8d77-c4d96843d219"
/>

*Left vs Right filament distinction*

<img width="557" height="327" alt="Custom filament mapping"
src="https://github.com/user-attachments/assets/c1c4396f-7359-474e-80bd-78fec22f9c82"
/>

*Custom filament mapping*

<img width="556" height="314" alt="Auto map"
src="https://github.com/user-attachments/assets/d83e3217-edce-4340-886e-043962003a30"
/>

*Auto map*

<img width="689" height="664" alt="LAN mode send print with X2D preview
and no errors"
src="https://github.com/user-attachments/assets/76009bbf-31d3-4a6c-979c-8643b487c824"
/>

*LAN mode send print with X2D preview and no errors, dual nozzle
selection*


## Tests

- 20 hours of dual-nozzle printing.
- 100% CTest tests passed
- Validated 208 changed JSON files.

<!--
> 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)
Fix #13294
This commit is contained in:
glowstab
2026-05-09 13:21:13 -05:00
committed by GitHub
parent 7bef75b2cd
commit 9956ad5b48
242 changed files with 53863 additions and 83 deletions

View File

@@ -210,6 +210,7 @@ const std::string BBS_PROJECT_CONFIG_FILE = "Metadata/project_settings.config";
const std::string BBS_MODEL_CONFIG_FILE = "Metadata/model_settings.config";
const std::string BBS_MODEL_CONFIG_RELS_FILE = "Metadata/_rels/model_settings.config.rels";
const std::string SLICE_INFO_CONFIG_FILE = "Metadata/slice_info.config";
const std::string FILAMENT_SEQUENCE_FILE = "Metadata/filament_sequence.json";
const std::string BBS_LAYER_HEIGHTS_PROFILE_FILE = "Metadata/layer_heights_profile.txt";
const std::string LAYER_CONFIG_RANGES_FILE = "Metadata/layer_config_ranges.xml";
const std::string BRIM_EAR_POINTS_FILE = "Metadata/brim_ear_points.txt";
@@ -251,6 +252,12 @@ static constexpr const char* FILAMENT_TYPE_TAG = "type";
static constexpr const char *FILAMENT_COLOR_TAG = "color";
static constexpr const char *FILAMENT_USED_M_TAG = "used_m";
static constexpr const char *FILAMENT_USED_G_TAG = "used_g";
static constexpr const char *FILAMENT_USED_FOR_SUPPORT = "used_for_support";
static constexpr const char *FILAMENT_USED_FOR_OBJECT = "used_for_object";
static constexpr const char *FILAMENT_NOZZLE_GROUP_ID_TAG = "group_id";
static constexpr const char *FILAMENT_NOZZLE_DIAMETER_TAG = "nozzle_diameter";
static constexpr const char *FILAMENT_NOZZLE_VOLUME_TYPE_TAG = "volume_type";
static constexpr const char *NOZZLE_TAG = "nozzle";
static constexpr const char *FILAMENT_TRAY_INFO_ID_TAG = "tray_info_idx";
static constexpr const char *LAYER_FILAMENT_LISTS_TAG = "layer_filament_lists";
static constexpr const char *LAYER_FILAMENT_LIST_TAG = "layer_filament_list";
@@ -365,6 +372,8 @@ static constexpr const char* TIMELAPSE_TYPE_ATTR = "timelapse_type";
static constexpr const char* OUTSIDE_ATTR = "outside";
static constexpr const char* SUPPORT_USED_ATTR = "support_used";
static constexpr const char* LABEL_OBJECT_ENABLED_ATTR = "label_object_enabled";
static constexpr const char* ENABLE_FILAMENT_DYNAMIC_MAP_ATTR = "enable_filament_dynamic_map";
static constexpr const char* HAS_FILAMENT_SWITCHER_ATTR = "has_filament_switcher";
static constexpr const char* SKIPPED_ATTR = "skipped";
static constexpr const char* OBJECT_TYPE = "object";
@@ -528,6 +537,40 @@ void add_vector(std::stringstream &stream, const std::vector<T> &values)
}
}
std::vector<int> parse_int_list(const std::string& value)
{
std::vector<int> out;
if (value.empty())
return out;
std::vector<std::string> tokens;
boost::split(tokens, value, boost::is_any_of(" ,"), boost::token_compress_on);
out.reserve(tokens.size());
for (const std::string& token : tokens) {
if (token.empty())
continue;
try {
out.emplace_back(boost::lexical_cast<int>(token));
} catch (...) {
}
}
std::sort(out.begin(), out.end());
out.erase(std::unique(out.begin(), out.end()), out.end());
return out;
}
std::string join_int_list_comma(const std::vector<int>& values)
{
std::stringstream stream;
for (size_t i = 0; i < values.size(); ++i) {
stream << values[i];
if (i + 1 < values.size())
stream << ",";
}
return stream.str();
}
Slic3r::Vec3f get_vec3_from_string(const std::string &pos_str)
{
Slic3r::Vec3f pos(0, 0, 0);
@@ -655,6 +698,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
info.id = it->first;
info.used_g = used_filament_g;
info.used_m = used_filament_m;
auto model_volume_it = ps.model_volumes_per_extruder.find(it->first);
auto support_volume_it = ps.support_volumes_per_extruder.find(it->first);
info.used_for_object = model_volume_it != ps.model_volumes_per_extruder.end() && model_volume_it->second > EPSILON;
info.used_for_support = support_volume_it != ps.support_volumes_per_extruder.end() && support_volume_it->second > EPSILON;
slice_filaments_info.push_back(info);
}
@@ -1142,6 +1189,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
void _extract_brim_ear_points_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
void _extract_custom_gcode_per_print_z_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
void _extract_filament_sequence_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
void _extract_print_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, DynamicPrintConfig& config, ConfigSubstitutionContext& subs_context, const std::string& archive_filename);
//BBS: add project config file logic
@@ -1535,6 +1583,9 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
_extract_xml_from_archive(archive, stat, _handle_start_config_xml_element, _handle_end_config_xml_element);
m_parsing_slice_info = false;
}
else if (boost::algorithm::iequals(name, FILAMENT_SEQUENCE_FILE)) {
_extract_filament_sequence_from_archive(archive, stat);
}
}
}
@@ -1568,6 +1619,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
plate->slice_filaments_info = it->second->slice_filaments_info;
plate->printer_model_id = it->second->printer_model_id;
plate->nozzle_diameters = it->second->nozzle_diameters;
plate->filament_maps = it->second->filament_maps;
plate->filament_change_sequence = it->second->filament_change_sequence;
plate->nozzle_change_sequence = it->second->nozzle_change_sequence;
plate->optimal_assignment = it->second->optimal_assignment;
plate->warnings = it->second->warnings;
plate->thumbnail_file = it->second->thumbnail_file;
if (plate->thumbnail_file.empty()) {
@@ -1911,6 +1966,9 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
_extract_xml_from_archive(archive, stat, _handle_start_config_xml_element, _handle_end_config_xml_element);
m_parsing_slice_info = false;
}
else if (!dont_load_config && boost::algorithm::iequals(name, FILAMENT_SEQUENCE_FILE)) {
_extract_filament_sequence_from_archive(archive, stat);
}
else if (boost::algorithm::istarts_with(name, AUXILIARY_DIR)) {
// extract auxiliary directory to temp directory, do nothing for restore
if (m_load_aux && !m_load_restore)
@@ -2231,6 +2289,12 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
plate_data_list[it->first-1]->is_label_object_enabled = it->second->is_label_object_enabled;
plate_data_list[it->first-1]->slice_filaments_info = it->second->slice_filaments_info;
plate_data_list[it->first-1]->skipped_objects = it->second->skipped_objects;
plate_data_list[it->first-1]->printer_model_id = it->second->printer_model_id;
plate_data_list[it->first-1]->nozzle_diameters = it->second->nozzle_diameters;
plate_data_list[it->first-1]->filament_maps = it->second->filament_maps;
plate_data_list[it->first-1]->filament_change_sequence = it->second->filament_change_sequence;
plate_data_list[it->first-1]->nozzle_change_sequence = it->second->nozzle_change_sequence;
plate_data_list[it->first-1]->optimal_assignment = it->second->optimal_assignment;
plate_data_list[it->first-1]->warnings = it->second->warnings;
plate_data_list[it->first-1]->thumbnail_file = (m_load_restore || it->second->thumbnail_file.empty()) ? it->second->thumbnail_file : m_backup_path + "/" + it->second->thumbnail_file;
//plate_data_list[it->first-1]->pattern_file = (m_load_restore || it->second->pattern_file.empty()) ? it->second->pattern_file : m_backup_path + "/" + it->second->pattern_file;
@@ -3226,6 +3290,62 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
}
}
void _BBS_3MF_Importer::_extract_filament_sequence_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)
{
if (stat.m_uncomp_size == 0) {
add_error("Error while reading filament sequence data to buffer");
return;
}
std::string buffer((size_t) stat.m_uncomp_size, 0);
mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*) buffer.data(), (size_t) stat.m_uncomp_size, 0);
if (res == 0) {
add_error("Error while reading filament sequence data to buffer");
return;
}
try {
const nlohmann::json sequence_json = nlohmann::json::parse(buffer);
for (auto& elem : m_plater_data) {
const std::string plate_key = "plate_" + std::to_string(elem.first);
auto plate_it = sequence_json.find(plate_key);
if (plate_it == sequence_json.end() || !plate_it->is_object())
continue;
auto filament_it = plate_it->find("filament_sequence");
if (filament_it == plate_it->end())
filament_it = plate_it->find("sequence");
auto nozzle_it = plate_it->find("nozzle_sequence");
if (filament_it == plate_it->end() || !filament_it->is_array() || nozzle_it == plate_it->end() || !nozzle_it->is_array())
continue;
std::vector<unsigned int> filament_sequence;
std::vector<unsigned int> nozzle_sequence;
std::vector<int> optimal_assignment;
for (const auto& item : *filament_it) {
const unsigned int filament_id = item.get<unsigned int>();
filament_sequence.push_back(filament_id > 0 ? filament_id - 1 : 0);
}
for (const auto& item : *nozzle_it)
nozzle_sequence.push_back(item.get<unsigned int>());
auto optimal_assignment_it = plate_it->find("optimal_assignment");
if (optimal_assignment_it != plate_it->end() && optimal_assignment_it->is_array()) {
for (const auto& item : *optimal_assignment_it)
optimal_assignment.emplace_back(item.get<int>());
}
elem.second->filament_change_sequence = std::move(filament_sequence);
elem.second->nozzle_change_sequence = std::move(nozzle_sequence);
if (!optimal_assignment.empty())
elem.second->optimal_assignment = std::move(optimal_assignment);
}
} catch (const std::exception& e) {
add_error(std::string("Error while parsing filament sequence JSON: ") + e.what());
}
}
void _BBS_3MF_Importer::_handle_start_model_xml_element(const char* name, const char** attributes)
{
if (m_xml_parser == nullptr)
@@ -4294,7 +4414,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
else if (key == BED_TYPE_ATTR)
{
BedType bed_type = BedType::btPC;
ConfigOptionEnum<BedType>::from_string(value, bed_type);
const std::string bed_type_value = value == "SuperTack Plate" ? "Supertack Plate" : value;
ConfigOptionEnum<BedType>::from_string(bed_type_value, bed_type);
m_curr_plater->config.set_key_value("curr_bed_type", new ConfigOptionEnum<BedType>(bed_type));
}
else if (key == PRINT_SEQUENCE_ATTR)
@@ -4334,6 +4455,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
filament_map[idx] = 1;
}
}
m_curr_plater->filament_maps = filament_map;
m_curr_plater->config.set_key_value("filament_map", new ConfigOptionInts(filament_map));
}
}
@@ -4425,6 +4547,22 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
if (m_curr_plater)
std::istringstream(value) >> std::boolalpha >> m_curr_plater->is_label_object_enabled;
}
else if (key == ENABLE_FILAMENT_DYNAMIC_MAP_ATTR)
{
if (m_curr_plater) {
bool enable_filament_dynamic_map = false;
std::istringstream(value) >> std::boolalpha >> enable_filament_dynamic_map;
m_curr_plater->config.set_key_value("enable_filament_dynamic_map", new ConfigOptionBool(enable_filament_dynamic_map));
}
}
else if (key == HAS_FILAMENT_SWITCHER_ATTR)
{
if (m_curr_plater) {
bool has_filament_switcher = false;
std::istringstream(value) >> std::boolalpha >> has_filament_switcher;
m_curr_plater->config.set_key_value("has_filament_switcher", new ConfigOptionBool(has_filament_switcher));
}
}
else if (key == PRINTER_MODEL_ID_ATTR)
{
if (m_curr_plater)
@@ -4455,6 +4593,11 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
std::string used_m = bbs_get_attribute_value_string(attributes, num_attributes, FILAMENT_USED_M_TAG);
std::string used_g = bbs_get_attribute_value_string(attributes, num_attributes, FILAMENT_USED_G_TAG);
std::string filament_id = bbs_get_attribute_value_string(attributes, num_attributes, FILAMENT_TRAY_INFO_ID_TAG);
std::string used_for_object = bbs_get_attribute_value_string(attributes, num_attributes, FILAMENT_USED_FOR_OBJECT);
std::string used_for_support = bbs_get_attribute_value_string(attributes, num_attributes, FILAMENT_USED_FOR_SUPPORT);
std::string group_id = bbs_get_attribute_value_string(attributes, num_attributes, FILAMENT_NOZZLE_GROUP_ID_TAG);
std::string nozzle_diameter = bbs_get_attribute_value_string(attributes, num_attributes, FILAMENT_NOZZLE_DIAMETER_TAG);
std::string volume_type = bbs_get_attribute_value_string(attributes, num_attributes, FILAMENT_NOZZLE_VOLUME_TYPE_TAG);
FilamentInfo filament_info;
filament_info.id = atoi(id.c_str()) - 1;
filament_info.type = type;
@@ -4462,6 +4605,11 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
filament_info.used_m = atof(used_m.c_str());
filament_info.used_g = atof(used_g.c_str());
filament_info.filament_id = filament_id;
std::istringstream(used_for_object) >> std::boolalpha >> filament_info.used_for_object;
std::istringstream(used_for_support) >> std::boolalpha >> filament_info.used_for_support;
filament_info.group_id = parse_int_list(group_id);
filament_info.nozzle_diameter = atof(nozzle_diameter.c_str());
filament_info.nozzle_volume_type = volume_type;
m_curr_plater->slice_filaments_info.push_back(filament_info);
}
return true;
@@ -5756,6 +5904,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
bool _add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list, const ObjectToObjectDataMap &objects_data, const DynamicPrintConfig& config, int export_plate_idx = -1, bool save_gcode = true, bool use_loaded_id = false);
bool _add_cut_information_file_to_archive(mz_zip_archive &archive, Model &model);
bool _add_slice_info_config_file_to_archive(mz_zip_archive &archive, const Model &model, PlateDataPtrs &plate_data_list, const ObjectToObjectDataMap &objects_data, const DynamicPrintConfig& config);
bool _add_filament_sequence_file_to_archive(mz_zip_archive& archive, const PlateDataPtrs& plate_data_list);
bool _add_gcode_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list, Export3mfProgressFn proFn = nullptr);
bool _add_custom_gcode_per_print_z_file_to_archive(mz_zip_archive& archive, Model& model, const DynamicPrintConfig* config);
bool _add_auxiliary_dir_to_archive(mz_zip_archive &archive, const std::string &aux_dir, PackingTemporaryData &data);
@@ -6294,6 +6443,11 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
return false;
}
if (!_add_filament_sequence_file_to_archive(archive, plate_data_list)) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", _add_filament_sequence_file_to_archive failed\n");
return false;
}
//BBS progress point
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(", before add auxiliary dir to 3mf\n");
if (proFn) {
@@ -7950,6 +8104,39 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
return true;
}
bool _BBS_3MF_Exporter::_add_filament_sequence_file_to_archive(mz_zip_archive& archive, const PlateDataPtrs& plate_data_list)
{
nlohmann::json sequence_json;
for (size_t idx = 0; idx < plate_data_list.size(); ++idx) {
const PlateData* plate_data = plate_data_list[idx];
if (!plate_data)
continue;
std::vector<unsigned int> filament_sequence = plate_data->filament_change_sequence;
std::transform(filament_sequence.begin(), filament_sequence.end(), filament_sequence.begin(),
[](unsigned int filament_id) { return filament_id + 1; });
const std::string plate_key = "plate_" + std::to_string(idx + 1);
sequence_json[plate_key]["sequence"] = filament_sequence;
sequence_json[plate_key]["nozzle_sequence"] = plate_data->nozzle_change_sequence;
sequence_json[plate_key]["optimal_assignment"] = plate_data->optimal_assignment;
}
if (sequence_json.empty())
return true;
const std::string out = sequence_json.dump();
if (!mz_zip_writer_add_mem(&archive, FILAMENT_SEQUENCE_FILE.c_str(), out.c_str(), out.size(), MZ_DEFAULT_COMPRESSION)) {
add_error("Unable to add filament sequence file to archive");
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__
<< boost::format(", store filament sequence to 3mf, length %1%, failed\n") % out.length();
return false;
}
return true;
}
bool _BBS_3MF_Exporter::_add_slice_info_config_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list, const ObjectToObjectDataMap &objects_data, const DynamicPrintConfig& config)
{
std::stringstream stream;
@@ -7987,6 +8174,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
std::vector<int> extruder_types = config.option<ConfigOptionEnumsGeneric>("extruder_type")->values;
std::vector<int> nozzle_volume_types = config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type")->values;
auto* nozzle_volume_type_option = dynamic_cast<const ConfigOptionEnumsGeneric*>(config.option("nozzle_volume_type"));
stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << EXTRUDER_TYPE_ATTR << "\" " << VALUE_ATTR << "=\"";
add_vector(stream, extruder_types);
@@ -8010,6 +8198,11 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << OUTSIDE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha<< plate_data->toolpath_outside << "\"/>\n";
stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << SUPPORT_USED_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha<< plate_data->is_support_used << "\"/>\n";
stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << LABEL_OBJECT_ENABLED_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha<< plate_data->is_label_object_enabled << "\"/>\n";
stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << ENABLE_FILAMENT_DYNAMIC_MAP_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << false << "\"/>\n";
{
bool has_filament_switcher = config.has("has_filament_switcher") ? config.opt_bool("has_filament_switcher") : false;
stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << HAS_FILAMENT_SWITCHER_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << has_filament_switcher << "\"/>\n";
}
std::vector<int> filament_maps = plate_data->filament_maps;
if (filament_maps.empty())
@@ -8053,20 +8246,69 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
<< "\" />\n";
}
auto get_nozzle_group_id = [&filament_maps](int filament_id) {
if (filament_id >= 0 && filament_id < static_cast<int>(filament_maps.size()) && filament_maps[filament_id] > 0)
return filament_maps[filament_id] - 1;
return 0;
};
auto get_nozzle_diameter = [nozzle_diameter_option](int nozzle_group_id) {
if (!nozzle_diameter_option || nozzle_diameter_option->values.empty())
return 0.0;
if (nozzle_group_id >= 0 && nozzle_group_id < static_cast<int>(nozzle_diameter_option->values.size()))
return nozzle_diameter_option->values[nozzle_group_id];
return nozzle_diameter_option->values.front();
};
auto get_nozzle_diameter_str = [&get_nozzle_diameter](int nozzle_group_id) {
std::ostringstream diameter_stream;
diameter_stream << std::defaultfloat << get_nozzle_diameter(nozzle_group_id);
return diameter_stream.str();
};
auto get_nozzle_volume_type = [nozzle_volume_type_option](int nozzle_group_id) {
if (!nozzle_volume_type_option || nozzle_volume_type_option->values.empty())
return std::string();
int nozzle_volume_type = nozzle_volume_type_option->values.front();
if (nozzle_group_id >= 0 && nozzle_group_id < static_cast<int>(nozzle_volume_type_option->values.size()))
nozzle_volume_type = nozzle_volume_type_option->values[nozzle_group_id];
if (nozzle_volume_type < 0 || nozzle_volume_type > nvtMaxNozzleVolumeType)
nozzle_volume_type = nvtStandard;
return get_nozzle_volume_type_string(static_cast<NozzleVolumeType>(nozzle_volume_type));
};
std::vector<int> used_nozzle_groups;
for (auto it = plate_data->slice_filaments_info.begin(); it != plate_data->slice_filaments_info.end(); it++)
{
int nozzle_group_id = get_nozzle_group_id(it->id);
if (std::find(used_nozzle_groups.begin(), used_nozzle_groups.end(), nozzle_group_id) == used_nozzle_groups.end())
used_nozzle_groups.push_back(nozzle_group_id);
const std::string filament_nozzle_group_id = it->group_id.empty() ? std::to_string(nozzle_group_id) : join_int_list_comma(it->group_id);
const double filament_nozzle_diameter = it->nozzle_diameter > 0.0 ? it->nozzle_diameter : get_nozzle_diameter(nozzle_group_id);
const std::string filament_nozzle_volume_type = it->nozzle_volume_type.empty() ? get_nozzle_volume_type(nozzle_group_id) : it->nozzle_volume_type;
stream << " <" << FILAMENT_TAG << " " << FILAMENT_ID_TAG << "=\"" << std::to_string(it->id + 1) << "\" "
<< FILAMENT_TRAY_INFO_ID_TAG <<"=\""<< it->filament_id <<"\" "
<< FILAMENT_TYPE_TAG << "=\"" << it->type << "\" "
<< FILAMENT_COLOR_TAG << "=\"" << it->color << "\" "
<< FILAMENT_USED_M_TAG << "=\"" << it->used_m << "\" "
<< FILAMENT_USED_G_TAG << "=\"" << it->used_g << "\" />\n";
<< FILAMENT_USED_G_TAG << "=\"" << it->used_g << "\" "
<< FILAMENT_NOZZLE_GROUP_ID_TAG << "=\"" << filament_nozzle_group_id << "\" "
<< FILAMENT_NOZZLE_DIAMETER_TAG << "=\"" << filament_nozzle_diameter << "\" "
<< FILAMENT_NOZZLE_VOLUME_TYPE_TAG << "=\"" << filament_nozzle_volume_type << "\" "
<< FILAMENT_USED_FOR_OBJECT << "=\"" << std::boolalpha << it->used_for_object << "\" "
<< FILAMENT_USED_FOR_SUPPORT << "=\"" << std::boolalpha << it->used_for_support << "\"/>\n";
}
for (auto it = plate_data->warnings.begin(); it != plate_data->warnings.end(); it++) {
stream << " <" << SLICE_WARNING_TAG << " msg=\"" << it->msg << "\" level=\"" << std::to_string(it->level) << "\" error_code =\"" << it->error_code << "\" />\n";
}
for (int nozzle_group_id : used_nozzle_groups) {
stream << " <" << NOZZLE_TAG << " "
<< "id=\"" << nozzle_group_id << "\" "
<< "extruder_id=\"" << nozzle_group_id + 1 << "\" "
<< "nozzle_diameter=\"" << get_nozzle_diameter_str(nozzle_group_id) << "\" "
<< "volume_type=\"" << get_nozzle_volume_type(nozzle_group_id) << "\"/>\n";
}
if (!plate_data->layer_filaments.empty()) {
stream << " <" << LAYER_FILAMENT_LISTS_TAG << ">\n";
for (auto iter = plate_data->layer_filaments.begin(); iter != plate_data->layer_filaments.end(); ++iter) {

View File

@@ -98,6 +98,9 @@ struct PlateData
std::vector<int> filament_maps; // 1 base
using LayerFilaments = std::unordered_map<std::vector<unsigned int>, std::vector<std::pair<int, int>>, GCodeProcessorResult::FilamentSequenceHash>;
LayerFilaments layer_filaments;
std::vector<unsigned int> filament_change_sequence;
std::vector<unsigned int> nozzle_change_sequence;
std::vector<int> optimal_assignment;
// Hexadecimal number,
// the 0th digit corresponds to extruder 1

View File

@@ -94,6 +94,16 @@ static const float g_purge_volume_one_time = 135.f;
static const int g_max_flush_count = 4;
static const size_t g_max_label_object = 64;
static bool is_bambu_x2d_printer(const FullPrintConfig &config)
{
return config.printer_model.value == "Bambu Lab X2D";
}
static int hotend_id_for_gcode_placeholder(const FullPrintConfig &config, int hotend_id)
{
return is_bambu_x2d_printer(config) ? -1 : hotend_id;
}
Vec2d travel_point_1;
Vec2d travel_point_2;
Vec2d travel_point_3;
@@ -835,6 +845,10 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
config.set_key_value("previous_extruder", new ConfigOptionInt(old_filament_id));
config.set_key_value("next_extruder", new ConfigOptionInt(new_filament_id));
config.set_key_value("current_hotend", new ConfigOptionInt(old_extruder_id >= 0 ?
hotend_id_for_gcode_placeholder(gcodegen.m_config, old_extruder_id) : -1));
config.set_key_value("next_hotend",
new ConfigOptionInt(hotend_id_for_gcode_placeholder(gcodegen.m_config, (int) gcodegen.get_extruder_id(new_filament_id))));
config.set_key_value("layer_num", new ConfigOptionInt(gcodegen.m_layer_index));
config.set_key_value("layer_z", new ConfigOptionFloat(tcr.print_z));
config.set_key_value("toolchange_z", new ConfigOptionFloat(z));
@@ -916,6 +930,7 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
auto flush_v_speed = m_print_config->filament_flush_volumetric_speed.values;
auto flush_temps = m_print_config->filament_flush_temp.values;
auto filament_cooling_before_tower = m_print_config->filament_cooling_before_tower.values;
for (size_t idx = 0; idx < flush_v_speed.size(); ++idx) {
if (flush_v_speed[idx] == 0)
flush_v_speed[idx] = m_print_config->filament_max_volumetric_speed.get_at(idx);
@@ -924,8 +939,13 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
if (flush_temps[idx] == 0)
flush_temps[idx] = m_print_config->nozzle_temperature_range_high.get_at(idx);
}
if (filament_cooling_before_tower.size() < m_print_config->filament_type.values.size())
filament_cooling_before_tower.resize(m_print_config->filament_type.values.size(), m_print_config->filament_cooling_before_tower.get_at(0));
if (tcr.is_contact || gcodegen.m_layer_index == 0)
std::fill(filament_cooling_before_tower.begin(), filament_cooling_before_tower.end(), 0);
config.set_key_value("flush_volumetric_speeds", new ConfigOptionFloats(flush_v_speed));
config.set_key_value("flush_temperatures", new ConfigOptionInts(flush_temps));
config.set_key_value("filament_cooling_before_tower", new ConfigOptionFloats(filament_cooling_before_tower));
config.set_key_value("flush_length", new ConfigOptionFloat(purge_length));
config.set_key_value("wipe_avoid_perimeter", new ConfigOptionBool(is_used_travel_avoid_perimeter));
config.set_key_value("wipe_avoid_pos_x", new ConfigOptionFloat(wipe_avoid_pos_x));
@@ -2791,7 +2811,10 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
this->placeholder_parser().set("first_non_support_filaments", new ConfigOptionInts(first_non_support_filaments));
this->placeholder_parser().set("initial_no_support_tool", initial_non_support_extruder_id);
this->placeholder_parser().set("initial_no_support_extruder", initial_non_support_extruder_id);
this->placeholder_parser().set("initial_no_support_hotend",
hotend_id_for_gcode_placeholder(m_config, (int) get_extruder_id(initial_non_support_extruder_id)));
this->placeholder_parser().set("current_extruder", initial_extruder_id);
this->placeholder_parser().set("current_hotend", hotend_id_for_gcode_placeholder(m_config, extruder_id));
//Orca: set the key for compatibilty
this->placeholder_parser().set("retraction_distance_when_cut", m_config.retraction_distances_when_cut.get_at(initial_extruder_id));
this->placeholder_parser().set("long_retraction_when_cut", m_config.long_retractions_when_cut.get_at(initial_extruder_id));
@@ -2806,7 +2829,9 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
this->placeholder_parser().set("long_retractions_when_ec",new ConfigOptionBoolsNullable(m_config.long_retractions_when_ec));
this->placeholder_parser().set("max_additional_fan", max_additional_fan);
this->placeholder_parser().set("first_x_layer_fan_speed", 0); // TODO: Orca hack to support BBL profiles
this->placeholder_parser().set("first_x_layer_fan_speed", new ConfigOptionFloats(m_config.first_x_layer_fan_speed));
this->placeholder_parser().set("close_additional_fan_first_x_layers", new ConfigOptionInts(m_config.close_additional_fan_first_x_layers));
this->placeholder_parser().set("additional_fan_full_speed_layer", new ConfigOptionInts(m_config.additional_fan_full_speed_layer));
auto flush_v_speed = m_config.filament_flush_volumetric_speed.values;
auto flush_temps = m_config.filament_flush_temp.values;
@@ -2820,6 +2845,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
}
this->placeholder_parser().set("flush_volumetric_speeds", new ConfigOptionFloats(flush_v_speed));
this->placeholder_parser().set("flush_temperatures", new ConfigOptionInts(flush_temps));
this->placeholder_parser().set("filament_cooling_before_tower", new ConfigOptionFloatsNullable(m_config.filament_cooling_before_tower));
//Set variable for total layer count so it can be used in custom gcode.
this->placeholder_parser().set("total_layer_count", m_layer_count);
// Useful for sequential prints.
@@ -3520,6 +3546,30 @@ void GCode::export_layer_filaments(GCodeProcessorResult* result)
iter->second.emplace_back(idx, idx);
}
}
result->filament_change_sequence.clear();
result->nozzle_change_sequence.clear();
int prev_sequence_filament = -1;
int prev_sequence_nozzle = -1;
for (size_t layer_idx = 0; layer_idx < m_sorted_layer_filaments.size(); ++layer_idx) {
for (unsigned int filament_id : m_sorted_layer_filaments[layer_idx]) {
int nozzle_id = 0;
if (filament_id < filament_map.size() && filament_map[filament_id] > 0)
nozzle_id = filament_map[filament_id] - 1;
if (prev_sequence_nozzle != nozzle_id || prev_sequence_filament != static_cast<int>(filament_id)) {
result->nozzle_change_sequence.emplace_back(static_cast<unsigned int>(nozzle_id));
result->filament_change_sequence.emplace_back(filament_id);
prev_sequence_nozzle = nozzle_id;
prev_sequence_filament = static_cast<int>(filament_id);
}
}
}
result->optimal_assignment.clear();
result->optimal_assignment.reserve(filament_map.size());
for (int nozzle_id : filament_map)
result->optimal_assignment.emplace_back(nozzle_id > 0 ? nozzle_id - 1 : 0);
}
//BBS
@@ -6320,7 +6370,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
}
// calculate effective extrusion length per distance unit (e_per_mm)
double filament_flow_ratio = m_config.option<ConfigOptionFloats>("filament_flow_ratio")->get_at(0);
double filament_flow_ratio = FILAMENT_CONFIG(filament_flow_ratio);
// We set _mm3_per_mm to effectove flow = Geometric volume * print flow ratio * filament flow ratio * role-based-flow-ratios
auto _mm3_per_mm = path.mm3_per_mm * this->config().print_flow_ratio;
_mm3_per_mm *= filament_flow_ratio;
@@ -6516,7 +6566,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
if (ref_speed == 0)
ref_speed = FILAMENT_CONFIG(filament_max_volumetric_speed) / _mm3_per_mm;
if (EXTRUDER_CONFIG(filament_max_volumetric_speed) > 0) {
if (FILAMENT_CONFIG(filament_max_volumetric_speed) > 0) {
ref_speed = std::min(ref_speed, FILAMENT_CONFIG(filament_max_volumetric_speed) / _mm3_per_mm);
}
if (sloped) {
@@ -7660,6 +7710,7 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo
float filament_area = float((M_PI / 4.f) * pow(m_config.filament_diameter.get_at(new_filament_id), 2));
//BBS: add handling for filament change in start gcode
int old_filament_id = -1;
int old_extruder_id = -1;
if (m_writer.filament() != nullptr || m_start_gcode_filament != -1) {
std::vector<float> flush_matrix(cast<float>(get_flush_volumes_matrix(m_config.flush_volumes_matrix.values, new_extruder_id, m_config.nozzle_diameter.values.size())));
const unsigned int number_of_extruders = (unsigned int) (m_config.filament_colour.values.size()); // if is multi_extruder only use the fist extruder matrix
@@ -7669,7 +7720,7 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo
assert(m_start_gcode_filament < number_of_extruders);
old_filament_id = m_writer.filament() != nullptr ? m_writer.filament()->id() : m_start_gcode_filament;
int old_extruder_id = m_writer.filament() != nullptr ? m_writer.filament()->extruder_id() : get_extruder_id(m_start_gcode_filament);
old_extruder_id = m_writer.filament() != nullptr ? m_writer.filament()->extruder_id() : get_extruder_id(m_start_gcode_filament);
old_retract_length = m_config.retraction_length.get_at(old_filament_id);
old_retract_length_toolchange = m_config.retract_length_toolchange.get_at(old_filament_id);
@@ -7715,6 +7766,9 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo
dyn_config.set_key_value("outer_wall_volumetric_speed", new ConfigOptionFloat(outer_wall_volumetric_speed));
dyn_config.set_key_value("previous_extruder", new ConfigOptionInt(old_filament_id));
dyn_config.set_key_value("next_extruder", new ConfigOptionInt((int)new_filament_id));
dyn_config.set_key_value("current_hotend",
new ConfigOptionInt(old_filament_id >= 0 ? hotend_id_for_gcode_placeholder(m_config, old_extruder_id) : -1));
dyn_config.set_key_value("next_hotend", new ConfigOptionInt(hotend_id_for_gcode_placeholder(m_config, new_extruder_id)));
dyn_config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
dyn_config.set_key_value("layer_z", new ConfigOptionFloat(print_z));
dyn_config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
@@ -7767,7 +7821,8 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo
}
auto flush_v_speed = m_print->config().filament_flush_volumetric_speed.values;
auto flush_temps =m_print->config().filament_flush_temp.values;
auto flush_temps = m_print->config().filament_flush_temp.values;
auto filament_cooling_before_tower = m_print->config().filament_cooling_before_tower.values;
for (size_t idx = 0; idx < flush_v_speed.size(); ++idx) {
if (flush_v_speed[idx] == 0)
flush_v_speed[idx] = m_print->config().filament_max_volumetric_speed.get_at(idx);
@@ -7776,8 +7831,12 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo
if (flush_temps[idx] == 0)
flush_temps[idx] = m_print->config().nozzle_temperature_range_high.get_at(idx);
}
if (filament_cooling_before_tower.size() < m_print->config().filament_type.values.size())
filament_cooling_before_tower.resize(m_print->config().filament_type.values.size(), m_print->config().filament_cooling_before_tower.get_at(0));
std::fill(filament_cooling_before_tower.begin(), filament_cooling_before_tower.end(), 0);
dyn_config.set_key_value("flush_volumetric_speeds", new ConfigOptionFloats(flush_v_speed));
dyn_config.set_key_value("flush_temperatures", new ConfigOptionInts(flush_temps));
dyn_config.set_key_value("filament_cooling_before_tower", new ConfigOptionFloats(filament_cooling_before_tower));
dyn_config.set_key_value("flush_length", new ConfigOptionFloat(wipe_length));
int flush_count = std::min(g_max_flush_count, (int)std::round(wipe_volume / g_purge_volume_one_time));
@@ -7850,6 +7909,7 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo
}
this->placeholder_parser().set("current_extruder", new_filament_id);
this->placeholder_parser().set("current_hotend", hotend_id_for_gcode_placeholder(m_config, new_extruder_id));
this->placeholder_parser().set("retraction_distance_when_cut", m_config.retraction_distances_when_cut.get_at(new_filament_id));
this->placeholder_parser().set("long_retraction_when_cut", m_config.long_retractions_when_cut.get_at(new_filament_id));
this->placeholder_parser().set("retraction_distance_when_ec", m_config.retraction_distances_when_ec.get_at(new_filament_id));

View File

@@ -1582,6 +1582,9 @@ void GCodeProcessorResult::reset() {
custom_gcode_per_print_z = std::vector<CustomGCode::Item>();
spiral_vase_mode = false;
layer_filaments.clear();
filament_change_sequence.clear();
nozzle_change_sequence.clear();
optimal_assignment.clear();
filament_change_count_map.clear();
warnings.clear();

View File

@@ -251,6 +251,9 @@ class Print;
std::vector<NozzleType> nozzle_type;
// first key stores filaments, second keys stores the layer ranges(enclosed) that use the filaments
std::unordered_map<std::vector<unsigned int>, std::vector<std::pair<int, int>>,FilamentSequenceHash> layer_filaments;
std::vector<unsigned int> nozzle_change_sequence;
std::vector<unsigned int> filament_change_sequence;
std::vector<int> optimal_assignment;
// first key stores `from` filament, second keys stores the `to` filament
std::map<std::pair<int,int>, int > filament_change_count_map;
@@ -288,6 +291,9 @@ class Print;
limit_filament_maps = other.limit_filament_maps;
filament_printable_reuslt = other.filament_printable_reuslt;
layer_filaments = other.layer_filaments;
filament_change_sequence = other.filament_change_sequence;
nozzle_change_sequence = other.nozzle_change_sequence;
optimal_assignment = other.optimal_assignment;
filament_change_count_map = other.filament_change_count_map;
initial_layer_time = other.initial_layer_time;
#if ENABLE_GCODE_VIEWER_STATISTICS

View File

@@ -1281,7 +1281,7 @@ static std::vector<std::string> s_Preset_filament_options {/*"filament_colour",
// "bed_type",
//BBS:temperature_vitrification
"temperature_vitrification", "reduce_fan_stop_start_freq","dont_slow_down_outer_wall", "slow_down_for_layer_cooling", "fan_min_speed",
"fan_max_speed", "enable_overhang_bridge_fan", "overhang_fan_speed", "overhang_fan_threshold", "close_fan_the_first_x_layers", "full_fan_speed_layer", "fan_cooling_layer_time", "slow_down_layer_time", "slow_down_min_speed",
"fan_max_speed", "enable_overhang_bridge_fan", "overhang_fan_speed", "overhang_fan_threshold", "close_fan_the_first_x_layers", "close_additional_fan_first_x_layers", "first_x_layer_fan_speed", "full_fan_speed_layer", "additional_fan_full_speed_layer", "fan_cooling_layer_time", "slow_down_layer_time", "slow_down_min_speed",
"filament_start_gcode", "filament_end_gcode", "filament_change_extrusion_role_gcode",
//exhaust fan control
"activate_air_filtration","activate_air_filtration_during_print","activate_air_filtration_on_completion","during_print_exhaust_fan_speed","complete_print_exhaust_fan_speed",
@@ -1305,7 +1305,7 @@ static std::vector<std::string> s_Preset_filament_options {/*"filament_colour",
"filament_multitool_ramming", "filament_multitool_ramming_volume", "filament_multitool_ramming_flow", "activate_chamber_temp_control",
"filament_long_retractions_when_cut","filament_retraction_distances_when_cut", "idle_temperature",
//BBS filament change length while the extruder color
"filament_change_length","filament_flush_volumetric_speed","filament_flush_temp",
"filament_change_length","filament_flush_volumetric_speed","filament_flush_temp", "filament_cooling_before_tower",
"long_retractions_when_ec", "retraction_distances_when_ec"
};

View File

@@ -11,6 +11,7 @@
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/log/trivial.hpp>
@@ -446,7 +447,7 @@ CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(OverhangFanThreshold)
// BBS
static const t_config_enum_values s_keys_map_BedType = {
{ "Default Plate", btDefault },
{ "SuperTack Plate", btSuperTack },
{ "Supertack Plate", btSuperTack },
{ "Cool Plate", btPC },
{ "Engineering Plate", btEP },
{ "High Temp Plate", btPEI },
@@ -1014,7 +1015,7 @@ void PrintConfigDef::init_fff_params()
def->enum_values.emplace_back("High Temp Plate");
def->enum_values.emplace_back("Textured PEI Plate");
def->enum_values.emplace_back("Textured Cool Plate");
def->enum_values.emplace_back("SuperTack Plate");
def->enum_values.emplace_back("Supertack Plate");
def->enum_labels.emplace_back(L("Smooth Cool Plate"));
def->enum_labels.emplace_back(L("Engineering Plate"));
def->enum_labels.emplace_back(L("Smooth High Temp Plate"));
@@ -2637,6 +2638,14 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloats { 15. });
def = this->add("filament_cooling_before_tower", coFloats);
def->label = L("Wipe tower cooling");
def->tooltip = L("Temperature drop before entering filament tower");
def->sidetext = L(u8"\u2103" /* °C */); // degrees Celsius, CIS languages need translation
def->mode = comDevelop;
def->nullable = true;
def->set_default_value(new ConfigOptionFloatsNullable { 10. });
def = this->add("filament_tower_interface_pre_extrusion_dist", coFloats);
def->label = L("Interface layer pre-extrusion distance");
def->tooltip = L("Pre-extrusion distance for prime tower interface layer (where different materials meet).");
@@ -4524,6 +4533,33 @@ void PrintConfigDef::init_fff_params()
def->mode = comSimple;
def->set_default_value(new ConfigOptionInts { 0 });
def = this->add("close_additional_fan_first_x_layers", coInts);
def->label = L("For the first");
def->tooltip = L("Set special auxiliary cooling fan for the first certain layers.");
def->sidetext = L("layers");
def->min = 0;
def->max = 1000;
def->mode = comSimple;
def->set_default_value(new ConfigOptionInts { 1 });
def = this->add("additional_fan_full_speed_layer", coInts);
def->label = L("Full fan speed at layer");
def->tooltip = L("Auxiliary fan speed will be ramped up linearly from layer \"For the first\" to maximum at layer \"Full fan speed at layer\". "
"\"Full fan speed at layer\" will be ignored if lower than \"For the first\", in which case the fan will run at maximum allowed speed at layer \"For the first\" + 1.");
def->min = 0;
def->max = 1000;
def->mode = comSimple;
def->set_default_value(new ConfigOptionInts { 0 });
def = this->add("first_x_layer_fan_speed", coFloats);
def->label = L("Fan speed");
def->tooltip = L("Special auxiliary cooling fan speed, effective only for the first x layers.");
def->sidetext = "%";
def->min = 0;
def->max = 100;
def->mode = comSimple;
def->set_default_value(new ConfigOptionFloats { 0 });
def = this->add("min_layer_height", coFloats);
def->label = L("Min");
def->tooltip = L("The lowest printable layer height for the extruder. "
@@ -7680,7 +7716,9 @@ void PrintConfigDef::init_sla_params()
void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &value)
{
//BBS: handle legacy options
if (opt_key == "enable_wipe_tower") {
if (opt_key == "curr_bed_type" && value == "SuperTack Plate") {
value = "Supertack Plate";
} else if (opt_key == "enable_wipe_tower") {
opt_key = "enable_prime_tower";
} else if (opt_key == "wipe_tower_width") {
opt_key = "prime_tower_width";
@@ -8023,6 +8061,7 @@ std::set<std::string> filament_options_with_variant = {
"nozzle_temperature",
"filament_flush_volumetric_speed",
"filament_flush_temp",
"filament_cooling_before_tower",
"volumetric_speed_coefficients",
"filament_adaptive_volumetric_speed",
"filament_ironing_flow",
@@ -8581,16 +8620,37 @@ int DynamicPrintConfig::get_index_for_extruder(int extruder_or_filament_id, std:
auto variant_opt = dynamic_cast<const ConfigOptionStrings*>(this->option(variant_name));
const ConfigOptionInts* id_opt = id_name.empty()?nullptr: dynamic_cast<const ConfigOptionInts*>(this->option(id_name));
const ConfigOptionStrings* extruder_variant_list_opt = dynamic_cast<const ConfigOptionStrings*>(this->option("extruder_variant_list"));
auto generated_extruder_id = [extruder_variant_list_opt](int target_index) {
if (!extruder_variant_list_opt)
return 0;
int variant_index = 0;
for (int extruder_index = 0; extruder_index < int(extruder_variant_list_opt->values.size()); ++extruder_index) {
std::vector<std::string> variants_list;
boost::split(variants_list, extruder_variant_list_opt->get_at(extruder_index), boost::is_any_of(","), boost::token_compress_on);
for (std::string variant : variants_list) {
boost::trim(variant);
if (variant.empty())
continue;
if (variant_index == target_index)
return extruder_index + 1;
++variant_index;
}
}
return 0;
};
if (variant_opt != nullptr) {
int v_size = variant_opt->values.size();
//int i_size = id_opt->values.size();
const bool has_complete_id_map = id_opt && int(id_opt->values.size()) >= v_size;
std::string extruder_variant = get_extruder_variant_string(extruder_type, nozzle_volume_type);
for (int index = 0; index < v_size; index++)
{
const std::string variant = variant_opt->get_at(index);
if (extruder_variant == variant) {
if (id_opt) {
const int id = id_opt->get_at(index);
const int id = has_complete_id_map ? id_opt->get_at(index) : generated_extruder_id(index);
if (id == extruder_or_filament_id) {
ret = index * stride;
break;

View File

@@ -1400,6 +1400,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionInts, filament_cooling_moves))
((ConfigOptionFloats, filament_cooling_initial_speed))
((ConfigOptionFloats, filament_minimal_purge_on_wipe_tower))
((ConfigOptionFloatsNullable, filament_cooling_before_tower))
((ConfigOptionFloats, filament_tower_interface_pre_extrusion_dist))
((ConfigOptionFloats, filament_tower_interface_pre_extrusion_length))
((ConfigOptionFloats, filament_tower_ironing_area))
@@ -1430,6 +1431,9 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
//BBS
((ConfigOptionInts, additional_cooling_fan_speed))
((ConfigOptionInts, close_additional_fan_first_x_layers))
((ConfigOptionInts, additional_fan_full_speed_layer))
((ConfigOptionFloats, first_x_layer_fan_speed))
((ConfigOptionBool, reduce_crossing_wall))
((ConfigOptionFloatOrPercent, max_travel_detour_distance))
((ConfigOptionPoints, printable_area))

View File

@@ -49,6 +49,11 @@ struct FilamentInfo
int ctype = 0;
std::vector<std::string> colors = std::vector<std::string>();
int mapping_result = 0;
bool used_for_support{false};
bool used_for_object{false};
std::vector<int> group_id;
double nozzle_diameter{0.0};
std::string nozzle_volume_type;
/*for new ams mapping*/
std::string ams_id;