mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-29 22:02:10 +00:00
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:
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user