From f9814370bb812ba301d41bedbac77b09adfdf5fa Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Mon, 17 Feb 2025 16:22:42 +0800 Subject: [PATCH] ENH:brim ears are saved in 3MF Cherry-picked from bambulab/BambuStudio@a45a2eec5457089800565215cc385b86cb927527 Co-authored-by: Mack --- src/libslic3r/Format/bbs_3mf.cpp | 132 ++++++++++++++++++++++++++++++- src/libslic3r/Format/bbs_3mf.hpp | 4 + 2 files changed, 132 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/Format/bbs_3mf.cpp b/src/libslic3r/Format/bbs_3mf.cpp index f13181ad2..38f4f3430 100644 --- a/src/libslic3r/Format/bbs_3mf.cpp +++ b/src/libslic3r/Format/bbs_3mf.cpp @@ -170,6 +170,7 @@ const std::string BBS_MODEL_CONFIG_RELS_FILE = "Metadata/_rels/model_settings.co const std::string SLICE_INFO_CONFIG_FILE = "Metadata/slice_info.config"; 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"; /*const std::string SLA_SUPPORT_POINTS_FILE = "Metadata/Slic3r_PE_sla_support_points.txt"; const std::string SLA_DRAIN_HOLES_FILE = "Metadata/Slic3r_PE_sla_drain_holes.txt";*/ const std::string CUSTOM_GCODE_PER_PRINT_Z_FILE = "Metadata/custom_gcode_per_layer.xml"; @@ -807,10 +808,11 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) //typedef std::map IdToAliasesMap; typedef std::vector InstancesList; typedef std::map IdToMetadataMap; + typedef std::map IdToCutObjectInfoMap; //typedef std::map IdToGeometryMap; typedef std::map> IdToLayerHeightsProfileMap; typedef std::map IdToLayerConfigRangesMap; - typedef std::map IdToCutObjectInfoMap; + typedef std::map IdToBrimPointsMap; /*typedef std::map> IdToSlaSupportPointsMap; typedef std::map> IdToSlaDrainHolesMap;*/ using PathToEmbossShapeFileMap = std::map>; @@ -1000,9 +1002,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) //IdToGeometryMap m_orig_geometries; // backup & restore CurrentConfig m_curr_config; IdToMetadataMap m_objects_metadata; - IdToCutObjectInfoMap m_cut_object_infos; + IdToCutObjectInfoMap m_cut_object_infos; IdToLayerHeightsProfileMap m_layer_heights_profiles; IdToLayerConfigRangesMap m_layer_config_ranges; + IdToBrimPointsMap m_brim_ear_points; /*IdToSlaSupportPointsMap m_sla_support_points; IdToSlaDrainHolesMap m_sla_drain_holes;*/ PathToEmbossShapeFileMap m_path_to_emboss_shape_files; @@ -1064,11 +1067,12 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) bool _extract_xml_from_archive(mz_zip_archive& archive, std::string const & path, XML_StartElementHandler start_handler, XML_EndElementHandler end_handler); bool _extract_xml_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, XML_StartElementHandler start_handler, XML_EndElementHandler end_handler); bool _extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat); - void _extract_cut_information_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, ConfigSubstitutionContext& config_substitutions); + void _extract_cut_information_from_archive(mz_zip_archive &archive, const mz_zip_archive_file_stat &stat, ConfigSubstitutionContext &config_substitutions); void _extract_layer_heights_profile_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat); void _extract_layer_config_ranges_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, ConfigSubstitutionContext& config_substitutions); void _extract_sla_support_points_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat); void _extract_sla_drain_holes_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat); + 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); @@ -1270,6 +1274,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) m_objects_metadata.clear(); m_layer_heights_profiles.clear(); m_layer_config_ranges.clear(); + m_brim_ear_points.clear(); //m_sla_support_points.clear(); m_curr_metadata_name.clear(); m_curr_characters.clear(); @@ -1759,6 +1764,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) // extract slic3r layer config ranges file _extract_layer_config_ranges_from_archive(archive, stat, config_substitutions); } + else if (boost::algorithm::iequals(name, BRIM_EAR_POINTS_FILE)) { + // extract slic3r config file + _extract_brim_ear_points_from_archive(archive, stat); + } //BBS: disable SLA related files currently /*else if (boost::algorithm::iequals(name, SLA_SUPPORT_POINTS_FILE)) { // extract sla support points file @@ -1942,6 +1951,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) if (obj_layer_config_ranges != m_layer_config_ranges.end()) model_object->layer_config_ranges = std::move(obj_layer_config_ranges->second); + IdToBrimPointsMap::iterator obj_brim_points = m_brim_ear_points.find(object.second + 1); + if (obj_brim_points != m_brim_ear_points.end()) + model_object->brim_points = std::move(obj_brim_points->second); + // m_sla_support_points are indexed by a 1 based model object index. /*IdToSlaSupportPointsMap::iterator obj_sla_support_points = m_sla_support_points.find(object.second + 1); if (obj_sla_support_points != m_sla_support_points.end() && !obj_sla_support_points->second.empty()) { @@ -2762,6 +2775,77 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) } } } + + void _BBS_3MF_Importer::_extract_brim_ear_points_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat) + { + if (stat.m_uncomp_size > 0) { + std::string buffer((size_t)stat.m_uncomp_size, 0); + mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0); + if (res == 0) { + add_error("Error while reading brim ear points data to buffer"); + return; + } + + if (buffer.back() == '\n') + buffer.pop_back(); + + std::vector objects; + boost::split(objects, buffer, boost::is_any_of("\n"), boost::token_compress_off); + + // Info on format versioning - see bbs_3mf.hpp + int version = 0; + std::string key("brim_points_format_version="); + if (!objects.empty() && objects[0].find(key) != std::string::npos) { + objects[0].erase(objects[0].begin(), objects[0].begin() + long(key.size())); // removes the string + version = std::stoi(objects[0]); + objects.erase(objects.begin()); // pop the header + } + + for (const std::string& object : objects) { + std::vector object_data; + boost::split(object_data, object, boost::is_any_of("|"), boost::token_compress_off); + + if (object_data.size() != 2) { + add_error("Error while reading object data"); + continue; + } + + std::vector object_data_id; + boost::split(object_data_id, object_data[0], boost::is_any_of("="), boost::token_compress_off); + if (object_data_id.size() != 2) { + add_error("Error while reading object id"); + continue; + } + + int object_id = std::atoi(object_data_id[1].c_str()); + if (object_id == 0) { + add_error("Found invalid object id"); + continue; + } + + IdToBrimPointsMap::iterator object_item = m_brim_ear_points.find(object_id); + if (object_item != m_brim_ear_points.end()) { + add_error("Found duplicated brim ear points"); + continue; + } + + std::vector object_data_points; + boost::split(object_data_points, object_data[1], boost::is_any_of(" "), boost::token_compress_off); + + std::vector brim_ear_points; + if (version == 0) { + for (unsigned int i=0; i const &flush, ObjectData const &object_data) const; bool _add_build_to_model_stream(std::stringstream& stream, const BuildItemsList& build_items) const; - bool _add_cut_information_file_to_archive(mz_zip_archive& archive, Model& model); bool _add_layer_height_profile_file_to_archive(mz_zip_archive& archive, Model& model); bool _add_layer_config_ranges_file_to_archive(mz_zip_archive& archive, Model& model); + bool _add_brim_ear_points_file_to_archive(mz_zip_archive& archive, Model& model); bool _add_sla_support_points_file_to_archive(mz_zip_archive& archive, Model& model); bool _add_sla_drain_holes_file_to_archive(mz_zip_archive& archive, Model& model); bool _add_print_config_file_to_archive(mz_zip_archive& archive, const DynamicPrintConfig &config); @@ -5515,6 +5599,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) //BBS: add project embedded preset files bool _add_project_embedded_presets_to_archive(mz_zip_archive& archive, Model& model, std::vector project_presets); bool _add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list, const ObjectToObjectDataMap &objects_data, 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_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); @@ -5914,6 +5999,11 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) return false; } + if (!_add_brim_ear_points_file_to_archive(archive, model)) { + close_zip_writer(&archive); + return false; + } + // BBS progress point /*BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format("export 3mf EXPORT_STAGE_ADD_SUPPORT\n"); if (proFn) { @@ -7159,6 +7249,40 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) return true; } + bool _BBS_3MF_Exporter::_add_brim_ear_points_file_to_archive(mz_zip_archive& archive, Model& model) + { + std::string out = ""; + char buffer[1024]; + + unsigned int count = 0; + for (const ModelObject* object : model.objects) { + ++count; + const BrimPoints& brim_points = object->brim_points; + if (!brim_points.empty()) { + sprintf(buffer, "object_id=%d|", count); + out += buffer; + + // Store the layer height profile as a single space separated list. + for (size_t i = 0; i < brim_points.size(); ++i) { + sprintf(buffer, (i==0 ? "%f %f %f %f" : " %f %f %f %f"), brim_points[i].pos(0), brim_points[i].pos(1), brim_points[i].pos(2), brim_points[i].head_front_radius); + out += buffer; + } + out += "\n"; + } + } + + if (!out.empty()) { + // Adds version header at the beginning: + out = std::string("brim_points_format_version=") + std::to_string(brim_points_format_version) + std::string("\n") + out; + + if (!mz_zip_writer_add_mem(&archive, BRIM_EAR_POINTS_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION)) { + add_error("Unable to add brim ear points file to archive"); + return false; + } + } + return true; + } + /* bool _BBS_3MF_Exporter::_add_sla_support_points_file_to_archive(mz_zip_archive& archive, Model& model) { diff --git a/src/libslic3r/Format/bbs_3mf.hpp b/src/libslic3r/Format/bbs_3mf.hpp index 6d0c092b7..6a4c40480 100644 --- a/src/libslic3r/Format/bbs_3mf.hpp +++ b/src/libslic3r/Format/bbs_3mf.hpp @@ -141,6 +141,10 @@ inline bool operator & (SaveStrategy & lhs, SaveStrategy rhs) return ((static_cast(lhs) & static_cast(rhs))) == static_cast(rhs); } +enum { + brim_points_format_version = 0 +}; + enum class LoadStrategy { Default = 0,