#ifndef BBS_3MF_hpp_ #define BBS_3MF_hpp_ #include "../GCode/ThumbnailData.hpp" #include "libslic3r/MultiNozzleUtils.hpp" #include "libslic3r/Semver.hpp" #include "libslic3r/ProjectTask.hpp" #include "libslic3r/GCode/GCodeProcessor.hpp" #include #include #include #include #include #include #include #include #include #include #include namespace Slic3r { class Model; class ModelObject; struct ConfigSubstitutionContext; class DynamicPrintConfig; class Preset; struct FilamentInfo; struct ThumbnailData; #define PLATE_THUMBNAIL_SMALL_WIDTH 128 #define PLATE_THUMBNAIL_SMALL_HEIGHT 128 #define GCODE_FILE_FORMAT "Metadata/plate_%1%.gcode" #define STATISTICS_FILE_FORMAT "Metadata/plate_%1%.statistics.json" #define THUMBNAIL_FILE_FORMAT "Metadata/plate_%1%.png" #define NO_LIGHT_THUMBNAIL_FILE_FORMAT "Metadata/plate_no_light_%1%.png" #define TOP_FILE_FORMAT "Metadata/top_%1%.png" #define PICK_FILE_FORMAT "Metadata/pick_%1%.png" //#define PATTERN_FILE_FORMAT "Metadata/plate_%1%_pattern_layer_0.png" #define PATTERN_CONFIG_FILE_FORMAT "Metadata/plate_%1%.json" #define EMBEDDED_PRINT_FILE_FORMAT "Metadata/process_settings_%1%.config" #define EMBEDDED_FILAMENT_FILE_FORMAT "Metadata/filament_settings_%1%.config" #define EMBEDDED_PRINTER_FILE_FORMAT "Metadata/machine_settings_%1%.config" #define BBL_DESIGNER_MODEL_TITLE_TAG "Title" #define BBL_DESIGNER_PROFILE_ID_TAG "DesignProfileId" #define BBL_DESIGNER_PROFILE_TITLE_TAG "ProfileTitle" #define BBL_DESIGNER_MODEL_ID_TAG "DesignModelId" //BBS: define assistant struct to store temporary variable during exporting 3mf class PackingTemporaryData { public: std::string _3mf_thumbnail; std::string _3mf_printer_thumbnail_middle; std::string _3mf_printer_thumbnail_small; PackingTemporaryData() {} }; // Mixed (virtual) filament used by a plate. Mixed filaments are virtual slots that get // resolved to their physical components before g-code statistics, so they never appear in // slice_filaments_info. They are recorded here separately so a plate's mixed-color usage // can be recovered from slice_info. struct PlateMixedFilamentInfo { int id{0}; // 1-based virtual filament slot id std::string type; std::string color; // blended display color, "#RRGGBB" std::string components; // 1-based physical component ids, comma separated, e.g. "1,3" }; //BBS: define plate data list related structures struct PlateData { PlateData(int plate_id, std::set> &obj_to_inst_list, bool lock_state) : plate_index(plate_id), locked(lock_state) { objects_and_instances.clear(); for (std::set>::iterator it = obj_to_inst_list.begin(); it != obj_to_inst_list.end(); ++it) objects_and_instances.emplace_back(it->first, it->second); } PlateData() : plate_index(-1), locked(false) { objects_and_instances.clear(); } ~PlateData() { objects_and_instances.clear(); } void parse_filament_info(GCodeProcessorResult *result); int plate_index; std::vector> objects_and_instances; std::map> obj_inst_map; std::string printer_model_id; std::string nozzle_diameters; std::string nozzle_volume_types; std::string gcode_file; std::string gcode_file_md5; // The G-code's statistics as JSON, stored with the G-code when not empty. std::string statistics; std::string thumbnail_file; std::string no_light_thumbnail_file; ThumbnailData plate_thumbnail; std::string top_file; std::string pick_file; //ThumbnailData pattern_thumbnail; //std::string pattern_file; std::string pattern_bbox_file; std::string gcode_prediction; std::string gcode_weight; std::string first_layer_time; std::string plate_name; std::vector slice_filaments_info; // Mixed (virtual) filaments used by this plate; empty when no mixed filament is used. std::vector mixed_filaments_info; std::vector skipped_objects; DynamicPrintConfig config; bool is_support_used {false}; bool is_sliced_valid = false; bool toolpath_outside {false}; bool is_label_object_enabled {false}; int timelapse_warning_code = 0; // 1<<0 sprial vase, 1<<1 by object std::vector filament_maps; // 1 base using LayerFilaments = std::unordered_map, std::vector>, GCodeProcessorResult::FilamentSequenceHash>; LayerFilaments layer_filaments; std::vector filament_change_sequence; std::vector nozzle_change_sequence; std::vector optimal_assignment; // Multi-nozzle grouping surface. nozzles_info accumulates the tags read from a // gcode.3mf; nozzle_group_result is the slicer's per-filament→nozzle assignment carried into the // saved 3mf metadata (write) and reconstructed on load. Both are empty/nullopt for single-nozzle // prints, so the saved-3mf output for single-nozzle printers is byte-identical. std::vector nozzles_info; std::optional nozzle_group_result; // Hexadecimal number, // the 0th digit corresponds to extruder 1 // the 1th digit corresponds to extruder 2 // ... and so on. // 0 means can be print on this extruder, 1 means cannot std::vector limit_filament_maps; std::vector warnings; std::string get_gcode_prediction_str() { return gcode_prediction; } std::string get_gcode_weight_str() { return gcode_weight; } bool locked; }; // BBS: encrypt enum class SaveStrategy { Default = 0, FullPathSources = 1, Zip64 = 1 << 1, ProductionExt = 1 << 2, SecureContentExt = 1 << 3, WithGcode = 1 << 4, Silence = 1 << 5, SkipStatic = 1 << 6, SkipModel = 1 << 7, WithSliceInfo = 1 << 8, SkipAuxiliary = 1 << 9, UseLoadedId = 1 << 10, ShareMesh = 1 << 11, // Keep this separate from SplitModel, which uses the 0x1000 bit as part of its // production-extension value. MinimalPublished = 1 << 13, // With WithGcode, also the G-code's statistics. WithStatistics = 1 << 14, SplitModel = 0x1000 | ProductionExt, Encrypted = SecureContentExt | SplitModel, Backup = 0x10000 | WithGcode | Silence | SkipStatic | SplitModel, }; // Model metadata keys of a "published" 3MF (see MinimalPublished): the flag marks a minimal, // tag-less publish export, the others carry the author-selected settings payload. Namespaced // with the "orca_published" prefix because metadata_items round-trips verbatim through other // slicers, where a bare "published" key could collide. inline constexpr const char *ORCA_PUBLISHED_TAG = "orca_published"; inline constexpr const char *ORCA_PUBLISHED_KEYS_TAG = "orca_published_keys"; inline constexpr const char *ORCA_PUBLISHED_MATERIAL_TAG = "orca_published_material_keys"; inline constexpr const char *ORCA_PUBLISHED_CONFIG_TAG = "orca_published_config"; // Published files are produced with "1". The importer and the GUI loader both gate on this // exact value, so a "0"/"false"/unknown value is rejected consistently. bool is_published_3mf_flag(const std::string &value); inline SaveStrategy operator | (SaveStrategy lhs, SaveStrategy rhs) { using T = std::underlying_type_t ; return static_cast(static_cast(lhs) | static_cast(rhs)); } inline bool operator & (SaveStrategy & lhs, SaveStrategy rhs) { using T = std::underlying_type_t ; return ((static_cast(lhs) & static_cast(rhs))) == static_cast(rhs); } enum { brim_points_format_version = 0 }; enum class LoadStrategy { Default = 0, AddDefaultInstances = 1, CheckVersion = 2, LoadModel = 4, LoadConfig = 8, LoadAuxiliary = 16, Silence = 32, ImperialUnits = 64, Restore = 0x10000 | LoadModel | LoadConfig | LoadAuxiliary | Silence, }; inline LoadStrategy operator | (LoadStrategy lhs, LoadStrategy rhs) { using T = std::underlying_type_t ; return static_cast(static_cast(lhs) | static_cast(rhs)); } inline bool operator & (LoadStrategy & lhs, LoadStrategy rhs) { using T = std::underlying_type_t ; return (static_cast(lhs) & static_cast(rhs)) == static_cast(rhs); } const int EXPORT_STAGE_OPEN_3MF = 0; const int EXPORT_STAGE_CONTENT_TYPES = 1; const int EXPORT_STAGE_ADD_THUMBNAILS = 2; const int EXPORT_STAGE_ADD_RELATIONS = 3; const int EXPORT_STAGE_ADD_MODELS = 4; const int EXPORT_STAGE_ADD_LAYER_RANGE = 5; const int EXPORT_STAGE_ADD_SUPPORT = 6; const int EXPORT_STAGE_ADD_CUSTOM_GCODE = 7; const int EXPORT_STAGE_ADD_PRINT_CONFIG = 8; const int EXPORT_STAGE_ADD_PROJECT_CONFIG = 9; const int EXPORT_STAGE_ADD_CONFIG_FILE = 10; const int EXPORT_STAGE_ADD_SLICE_INFO = 11; const int EXPORT_STAGE_ADD_GCODE = 12; const int EXPORT_STAGE_ADD_AUXILIARIES = 13; const int EXPORT_STAGE_FINISH = 14; const int IMPORT_STAGE_RESTORE = 0; const int IMPORT_STAGE_OPEN = 1; const int IMPORT_STAGE_READ_FILES = 2; const int IMPORT_STAGE_EXTRACT = 3; const int IMPORT_STAGE_LOADING_OBJECTS = 4; const int IMPORT_STAGE_LOADING_PLATES = 5; const int IMPORT_STAGE_FINISH = 6; const int IMPORT_STAGE_ADD_INSTANCE = 7; const int IMPORT_STAGE_UPDATE_GCODE = 8; const int IMPORT_STAGE_CHECK_MODE_GCODE = 9; const int UPDATE_GCODE_RESULT = 10; const int IMPORT_LOAD_CONFIG = 11; const int IMPORT_LOAD_MODEL_OBJECTS = 12; const int IMPORT_STAGE_MAX = 13; //BBS export 3mf progress typedef std::function Export3mfProgressFn; typedef std::function Import3mfProgressFn; typedef std::vector PlateDataPtrs; typedef std::map PlateDataMaps; struct StoreParams { std::string path; Model* model = nullptr; PlateDataPtrs plate_data_list; int export_plate_idx = -1; std::vector project_presets; DynamicPrintConfig* config; std::vector thumbnail_data; std::vector no_light_thumbnail_data; std::vector top_thumbnail_data; std::vector pick_thumbnail_data; std::vector calibration_thumbnail_data; SaveStrategy strategy = SaveStrategy::Zip64; Export3mfProgressFn proFn = nullptr; std::vector id_bboxes; BBLProject* project = nullptr; BBLProfile* profile = nullptr; StoreParams() {} }; //BBS: add plate data list related logic // add restore logic // Load the content of a 3mf file into the given model and preset bundle. extern bool load_bbs_3mf(const char* path, DynamicPrintConfig* config, ConfigSubstitutionContext* config_substitutions, Model* model, PlateDataPtrs* plate_data_list, std::vector* project_presets, bool* is_bbl_3mf, bool* is_orca_3mf, Semver* file_version, Import3mfProgressFn proFn = nullptr, LoadStrategy strategy = LoadStrategy::Default, BBLProject *project = nullptr, int plate_id = 0); extern std::string bbs_3mf_get_thumbnail(const char * path); // Lightweight check: does this 3mf carry the "published" (orca_published == "1") marker? Only reads the 3D/3dmodel.model metadata node extern bool bbs_3mf_is_published(const std::string &path); extern bool load_gcode_3mf_from_stream(std::istream & data, DynamicPrintConfig* config, Model* model, PlateDataPtrs* plate_data_list, Semver* file_version); //BBS: add plate data list related logic // add backup logic // Save the given model and the config data contained in the given Print into a 3mf file. // The model could be modified during the export process if meshes are not repaired or have no shared vertices /* extern bool store_bbs_3mf(const char* path, Model* model, PlateDataPtrs& plate_data_list, std::vector& project_presets, const DynamicPrintConfig* config, bool fullpath_sources, const std::vector& thumbnail_data, bool zip64 = true, bool skip_static = false, Export3mfProgressFn proFn = nullptr, bool silence = true); */ extern bool store_bbs_3mf(StoreParams& store_params); extern void release_PlateData_list(PlateDataPtrs& plate_data_list); // backup & restore project extern void save_object_mesh(ModelObject& object); extern void delete_object_mesh(ModelObject& object); extern void backup_soon(); extern void remove_backup(Model& model, bool removeAll); extern void set_backup_interval(long interval); extern void set_backup_callback(std::function callback); extern void run_backup_ui_tasks(); extern bool has_restore_data(std::string & path, std::string & origin); extern void put_other_changes(); extern void clear_other_changes(bool backup); extern bool has_other_changes(bool backup); class SaveObjectGaurd { public: SaveObjectGaurd(ModelObject& object); ~SaveObjectGaurd(); }; } // namespace Slic3r #endif /* BBS_3MF_hpp_ */