diff --git a/src/admesh/stl.h b/src/admesh/stl.h index 0f1a0cec8..0a4d07f5d 100644 --- a/src/admesh/stl.h +++ b/src/admesh/stl.h @@ -45,7 +45,8 @@ typedef Eigen::Matrix stl_triangle_vertex_indices static_assert(sizeof(stl_vertex) == 12, "size of stl_vertex incorrect"); static_assert(sizeof(stl_normal) == 12, "size of stl_normal incorrect"); -typedef std::function ImportstlProgressFn; +typedef std::function ImportstlProgressFn; typedef enum { eNormal, // normal face diff --git a/src/admesh/stlinit.cpp b/src/admesh/stlinit.cpp index 8196bf10c..96532e248 100644 --- a/src/admesh/stlinit.cpp +++ b/src/admesh/stlinit.cpp @@ -46,6 +46,9 @@ extern void stl_internal_reverse_quads(char *buf, size_t cnt); const int LOAD_STL_UNIT_NUM = 5; static std::string model_id = ""; static std::string country_code = ""; +static std::string ml_name = ""; +static std::string ml_id = ""; +static std::string ml_region = ""; static FILE *stl_open_count_facets(stl_file *stl, const char *file, unsigned int custom_header_length) { @@ -162,30 +165,61 @@ static bool stl_read(stl_file *stl, FILE *fp, int first_facet, bool first, Impor else { rewind(fp); try{ - char solid_name[256]; - int res_solid = fscanf(fp, " solid %[^\n]", solid_name); + char solid_content[256]; + int res_solid = fscanf(fp, " solid %[^\n]", solid_content); if (res_solid == 1) { - char* mw_position = strstr(solid_name, "MW"); - if (mw_position != NULL) { - // Extract the value after "MW" - char version_str[16]; - char model_id_str[128]; - char country_code_str[16]; - int num_values = sscanf(mw_position + 3, "%s %s %s", version_str, model_id_str, country_code_str); - if (num_values == 3) { - if (strcmp(version_str, "1.0") == 0) { - model_id = model_id_str; - country_code = country_code_str; + /*include ml info*/ + std::string ext_content(solid_content); + std::string ml_content; + std::string mw_content; + + size_t pos = ext_content.find('&'); + if (pos != std::string::npos) { + mw_content = ext_content.substr(0, pos); + ml_content = ext_content.substr(pos + 1); + } + + if (ml_content.empty() && ext_content.find("ML") != std::string::npos) { + ml_content = ext_content; + } + + if (mw_content.empty() && ext_content.find("MW") != std::string::npos) { + mw_content = ext_content; + } + + /*parse ml info*/ + if (!ml_content.empty()) { + std::istringstream iss(ml_content); + std::string token; + std::vector result; + while (iss >> token) { + if (token.find(' ') == std::string::npos) { + result.push_back(token); } } - else { - model_id = ""; - country_code = ""; + + if (result.size() == 4 && result[0] == "ML") { + ml_region = result[1]; + ml_name = result[2]; + ml_id = result[3]; } } - else { - model_id = ""; // No MW format found - country_code = ""; + + /*parse mw info*/ + if (!mw_content.empty()) { + std::istringstream iss(mw_content); + std::string token; + std::vector result; + while (iss >> token) { + if (token.find(' ') == std::string::npos) { + result.push_back(token); + } + } + + if (result.size() == 4 && result[0] == "MW") { + model_id = result[2]; + country_code = result[3]; + } } } } @@ -204,7 +238,7 @@ static bool stl_read(stl_file *stl, FILE *fp, int first_facet, bool first, Impor if ((i % unit) == 0) { bool cb_cancel = false; if (stlFn) { - stlFn(i, facets_num, cb_cancel, model_id, country_code); + stlFn(i, facets_num, cb_cancel, model_id, country_code, ml_region, ml_name, ml_id); if (cb_cancel) return false; } diff --git a/src/libslic3r/Format/OBJ.cpp b/src/libslic3r/Format/OBJ.cpp index abaae3692..9a90c522e 100644 --- a/src/libslic3r/Format/OBJ.cpp +++ b/src/libslic3r/Format/OBJ.cpp @@ -33,6 +33,11 @@ bool load_obj(const char *path, TriangleMesh *meshptr, ObjInfo& obj_info, std::s message = _L("load_obj: failed to parse"); return false; } + + obj_info.ml_region = data.ml_region; + obj_info.ml_name = data.ml_name; + obj_info.ml_id = data.ml_id; + bool exist_mtl = false; if (data.mtllibs.size() > 0) { // read mtl for (auto mtl_name : data.mtllibs) { diff --git a/src/libslic3r/Format/OBJ.hpp b/src/libslic3r/Format/OBJ.hpp index 9b618bd27..7fccb6fca 100644 --- a/src/libslic3r/Format/OBJ.hpp +++ b/src/libslic3r/Format/OBJ.hpp @@ -1,13 +1,15 @@ #ifndef slic3r_Format_OBJ_hpp_ #define slic3r_Format_OBJ_hpp_ #include "libslic3r/Color.hpp" +#include "objparser.hpp" #include namespace Slic3r { class TriangleMesh; class Model; class ModelObject; -typedef std::function &input_colors, bool is_single_color, std::vector &filament_ids, unsigned char &first_extruder_id)> ObjImportColorFn; +typedef std::function &input_colors, bool is_single_color, std::vector &filament_ids, unsigned char &first_extruder_id, + std::string& ml_region, std::string& ml_name, std::string& ml_id)> ObjImportColorFn; // Load an OBJ file into a provided model. struct ObjInfo { std::vector vertex_colors; @@ -19,6 +21,9 @@ struct ObjInfo { std::unordered_map uv_map_pngs; bool has_uv_png{false}; + std::string ml_region; + std::string ml_name; + std::string ml_id; }; extern bool load_obj(const char *path, TriangleMesh *mesh, ObjInfo &vertex_colors, std::string &message); extern bool load_obj(const char *path, Model *model, ObjInfo &vertex_colors, std::string &message, const char *object_name = nullptr); diff --git a/src/libslic3r/Format/bbs_3mf.cpp b/src/libslic3r/Format/bbs_3mf.cpp index 03a2b6800..f4193321f 100644 --- a/src/libslic3r/Format/bbs_3mf.cpp +++ b/src/libslic3r/Format/bbs_3mf.cpp @@ -137,6 +137,10 @@ const std::string BBL_APPLICATION_TAG = "Application"; const std::string BBL_MAKERLAB_TAG = "MakerLab"; const std::string BBL_MAKERLAB_VERSION_TAG = "MakerLabVersion"; +const std::string BBL_MAKERLAB_NAME = "MakerLab"; +const std::string BBL_MAKERLAB_REGION = "MakerLabRegion"; +const std::string BBL_MAKERLAB_ID = "MakerLabFileId"; + const std::string BBL_PROFILE_TITLE_TAG = "ProfileTitle"; const std::string BBL_PROFILE_COVER_TAG = "ProfileCover"; @@ -6459,6 +6463,15 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) metadata_item_map[BBL_MAKERLAB_VERSION_TAG] = xml_escape(model.mk_version); BOOST_LOG_TRIVIAL(info) << "saved mk_version " << model.mk_version; } + + + /*for ml*/ + if (model.mk_name.empty() && !model.makerlab_name.empty()) { + metadata_item_map[BBL_MAKERLAB_NAME] = model.makerlab_name; + metadata_item_map[BBL_MAKERLAB_REGION] = model.makerlab_region; + metadata_item_map[BBL_MAKERLAB_ID] = model.makerlab_id; + } + if (!model.md_name.empty()) { for (unsigned int i = 0; i < model.md_name.size(); i++) { diff --git a/src/libslic3r/Format/objparser.cpp b/src/libslic3r/Format/objparser.cpp index 82bf2b496..d1b909daf 100644 --- a/src/libslic3r/Format/objparser.cpp +++ b/src/libslic3r/Format/objparser.cpp @@ -577,6 +577,8 @@ bool objparse(const char *path, ObjData &data) char buf[65536 * 2]; size_t len = 0; size_t lenPrev = 0; + size_t lineCount = 0; + while ((len = ::fread(buf + lenPrev, 1, 65536, pFile)) != 0) { len += lenPrev; size_t lastLine = 0; @@ -589,6 +591,13 @@ bool objparse(const char *path, ObjData &data) //FIXME check the return value and exit on error? // Will it break parsing of some obj files? obj_parseline(c, data); + + /*for ml*/ + if (lineCount == 0) { data.ml_region = parsemlinfo(c, "region:");} + if (lineCount == 1) { data.ml_name = parsemlinfo(c, "ml_name:"); } + if (lineCount == 2) { data.ml_id = parsemlinfo(c, "ml_file_id:");} + + ++lineCount; lastLine = i + 1; } lenPrev = len - lastLine; @@ -607,6 +616,28 @@ bool objparse(const char *path, ObjData &data) return true; } +std::string parsemlinfo(const char* input, const char* condition) { + const char* regionPtr = std::strstr(input, condition); + + std::string regionContent = ""; + + if (regionPtr != nullptr) { + regionPtr += std::strlen(condition); + + while (*regionPtr == ' ' || *regionPtr == '\t') { + ++regionPtr; + } + + const char* endPtr = std::strchr(regionPtr, '\n'); + size_t length = (endPtr != nullptr) ? (endPtr - regionPtr) : std::strlen(regionPtr); + + regionContent = std::string(regionPtr, length); + } + + return regionContent; +} + + bool mtlparse(const char *path, MtlData &data) { Slic3r::CNumericLocalesSetter locales_setter; @@ -664,6 +695,14 @@ bool objparse(std::istream &stream, ObjData &data) while (*c == ' ' || *c == '\t') ++ c; obj_parseline(c, data); + + /*for ml*/ + if (lastLine < 3) { + data.ml_region = parsemlinfo(c, "region"); + data.ml_name = parsemlinfo(c, "ml_name"); + data.ml_id = parsemlinfo(c, "ml_file_id"); + } + lastLine = i + 1; } lenPrev = len - lastLine; diff --git a/src/libslic3r/Format/objparser.hpp b/src/libslic3r/Format/objparser.hpp index 48493de3d..df9b4ba32 100644 --- a/src/libslic3r/Format/objparser.hpp +++ b/src/libslic3r/Format/objparser.hpp @@ -115,6 +115,10 @@ struct ObjData { // List of faces, delimited by an ObjVertex with all members set to -1. std::vector vertices; + + std::string ml_region; + std::string ml_name; + std::string ml_id; }; struct MtlData @@ -127,6 +131,8 @@ extern bool objparse(const char *path, ObjData &data); extern bool mtlparse(const char *path, MtlData &data); extern bool objparse(std::istream &stream, ObjData &data); +extern std::string parsemlinfo(const char* input, const char* condition); + extern bool objbinsave(const char *path, const ObjData &data); extern bool objbinload(const char *path, ObjData &data); diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index ed986c03a..dbcd8e976 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -90,8 +90,15 @@ Model& Model::assign_copy(const Model &rhs) this->design_id = rhs.design_id; this->stl_design_id = rhs.stl_design_id; this->stl_design_country = rhs.stl_design_country; + this->makerlab_region = rhs.makerlab_region; + this->makerlab_name = rhs.makerlab_name; + this->makerlab_id = rhs.makerlab_id; this->profile_info = rhs.profile_info; + this->makerlab_region = rhs.makerlab_region; + this->makerlab_name = rhs.makerlab_name; + this->makerlab_id = rhs.makerlab_id; + this->mk_name = rhs.mk_name; this->mk_version = rhs.mk_version; this->md_name = rhs.md_name; @@ -127,6 +134,9 @@ Model& Model::assign_copy(Model &&rhs) this->design_id = rhs.design_id; this->stl_design_id = rhs.stl_design_id; this->stl_design_country = rhs.stl_design_country; + this->makerlab_region = rhs.makerlab_region; + this->makerlab_name = rhs.makerlab_name; + this->makerlab_id = rhs.makerlab_id; this->mk_name = rhs.mk_name; this->mk_version = rhs.mk_version; this->md_name = rhs.md_name; @@ -234,7 +244,7 @@ Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* c if (obj_info.vertex_colors.size() > 0) { std::vector vertex_filament_ids; if (objFn) { // 1.result is ok and pop up a dialog - objFn(obj_info.vertex_colors, false, vertex_filament_ids, first_extruder_id); + objFn(obj_info.vertex_colors, false, vertex_filament_ids, first_extruder_id, obj_info.ml_region, obj_info.ml_name, obj_info.ml_id); if (vertex_filament_ids.size() > 0) { result = obj_import_vertex_color_deal(vertex_filament_ids, first_extruder_id, & model); } @@ -242,7 +252,7 @@ Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* c } else if (obj_info.face_colors.size() > 0 && obj_info.has_uv_png == false) { // mtl file std::vector face_filament_ids; if (objFn) { // 1.result is ok and pop up a dialog - objFn(obj_info.face_colors, obj_info.is_single_mtl, face_filament_ids, first_extruder_id); + objFn(obj_info.face_colors, obj_info.is_single_mtl, face_filament_ids, first_extruder_id, obj_info.ml_region, obj_info.ml_name, obj_info.ml_id); if (face_filament_ids.size() > 0) { result = obj_import_face_color_deal(face_filament_ids, first_extruder_id, &model); } @@ -999,6 +1009,9 @@ void Model::load_from(Model& model) design_id = model.design_id; stl_design_id = model.stl_design_id; stl_design_country = model.stl_design_country; + makerlab_region = model.makerlab_region; + makerlab_name = model.makerlab_name; + makerlab_id = model.makerlab_id; model_info = model.model_info; profile_info = model.profile_info; mk_name = model.mk_name; diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 0a95d5c6e..0c54c0476 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -1531,6 +1531,11 @@ public: std::string stl_design_id; std::string design_id; std::string stl_design_country; + + std::string makerlab_region; + std::string makerlab_name; + std::string makerlab_id; + std::shared_ptr design_info = nullptr; std::shared_ptr model_info = nullptr; std::shared_ptr profile_info = nullptr; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index bbab69549..26090bc26 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3411,7 +3411,8 @@ BoundingBox Plater::priv::scaled_bed_shape_bb() const } -void read_binary_stl(const std::string& filename, std::string& model_id, std::string& code) { +void read_binary_stl(const std::string& filename, std::string& model_id, std::string& code, + std::string& ml_name, std::string& ml_region, std::string& ml_id) { std::ifstream file( encode_path(filename.c_str()), std::ios::binary); if (!file) { return; @@ -3431,42 +3432,60 @@ void read_binary_stl(const std::string& filename, std::string& model_id, std::st return; } - char magic[2] = { data[0], data[1] }; - if (magic[0] != 'M' || magic[1] != 'W') { - file.close(); - return; + /*include ml info*/ + std::string ext_content(data); + std::string ml_content; + std::string mw_content; + + size_t pos = ext_content.find('&'); + if (pos != std::string::npos) { + ml_content = ext_content.substr(0, pos); + mw_content = ext_content.substr(pos + 1); } - if (data[2] != ' ') { - file.close(); - return; + if (ml_content.empty() && ext_content.find("ML") != std::string::npos) { + ml_content = ext_content; } - char protocol_version[3] = { data[3], data[4], data[5] }; - - //version - if (protocol_version[0] != '1' || protocol_version[1] != '.' || protocol_version[2] != '0') { - file.close(); - return; + if (mw_content.empty() && ext_content.find("MW") != std::string::npos) { + mw_content = ext_content; } - std::vector tokens; - std::istringstream iss(data); - std::string token; - while (std::getline(iss, token, ' ')) { - char* tokenPtr = new char[token.length() + 1]; - std::strcpy(tokenPtr, token.c_str()); - tokens.push_back(tokenPtr); + /*parse ml info*/ + if (!ml_content.empty()) { + std::istringstream iss(ml_content); + std::string token; + std::vector result; + while (iss >> token) { + if (token.find(' ') == std::string::npos) { + result.push_back(token); + } + } + + if (result.size() == 4 && result[0] == "ML") { + ml_region = result[1]; + ml_name = result[2]; + ml_id = result[3]; + } } - //model id - if (tokens.size() < 4) { - file.close(); - return; + /*parse mw info*/ + if (!mw_content.empty()) { + std::istringstream iss(mw_content); + std::string token; + std::vector result; + while (iss >> token) { + if (token.find(' ') == std::string::npos) { + result.push_back(token); + } + } + + if (result.size() == 4 && result[0] == "MW") { + model_id = result[2]; + code = result[3]; + } } - model_id = tokens[2]; - code = tokens[3]; file.close(); } catch (...) { @@ -3513,6 +3532,9 @@ std::vector Plater::priv::load_files(const std::vector& input_ std::string designer_model_id; std::string designer_country_code; + std::string makerlab_region; + std::string makerlab_name; + std::string makerlab_id; int answer_convert_from_meters = wxOK_DEFAULT; int answer_convert_from_imperial_units = wxOK_DEFAULT; @@ -3975,8 +3997,13 @@ std::vector Plater::priv::load_files(const std::vector& input_ bool is_xxx; Semver file_version; //ObjImportColorFn obj_color_fun=nullptr; - auto obj_color_fun = [this, &path](std::vector &input_colors, bool is_single_color, std::vector &filament_ids, - unsigned char &first_extruder_id) { + auto obj_color_fun = [this, &path, &makerlab_region, &makerlab_name, &makerlab_id](std::vector &input_colors, bool is_single_color, std::vector &filament_ids, + unsigned char& first_extruder_id, std::string ml_origin, std::string ml_name, std::string ml_id) { + + makerlab_region = ml_origin; + makerlab_name = ml_name; + makerlab_id = ml_id; + if (!boost::iends_with(path.string(), ".obj")) { return; } const std::vector extruder_colours = wxGetApp().plater()->get_extruder_colors_from_plater_config(); ObjColorDialog color_dlg(nullptr, input_colors, is_single_color, extruder_colours, filament_ids, first_extruder_id); @@ -3999,10 +4026,14 @@ std::vector Plater::priv::load_files(const std::vector& input_ }; model = Slic3r::Model:: read_from_file( path.string(), nullptr, nullptr, strategy, &plate_data, &project_presets, &is_xxx, &file_version, nullptr, - [this, &dlg, real_filename, &progress_percent, &file_percent, INPUT_FILES_RATIO, total_files, i, &designer_model_id, &designer_country_code](int current, int total, bool &cancel, std::string &mode_id, std::string &code) + [this, &dlg, real_filename, &progress_percent, &file_percent, INPUT_FILES_RATIO, total_files, i, &designer_model_id, &designer_country_code, &makerlab_region, &makerlab_name, &makerlab_id](int current, int total, bool &cancel, + std::string &mode_id, std::string &code, std::string &ml_region, std::string &ml_name, std::string &ml_id) { - designer_model_id = mode_id; - designer_country_code = code; + designer_model_id = mode_id; + designer_country_code = code; + makerlab_region = ml_region; + makerlab_name = ml_name; + makerlab_id = ml_id; bool cont = true; float percent_float = (100.0f * (float)i / (float)total_files) + INPUT_FILES_RATIO * 100.0f * ((float)current / (float)total) / (float)total_files; @@ -4031,7 +4062,7 @@ std::vector Plater::priv::load_files(const std::vector& input_ if (designer_model_id.empty() && boost::algorithm::iends_with(path.string(), ".stl")) { - read_binary_stl(path.string(), designer_model_id, designer_country_code); + read_binary_stl(path.string(), designer_model_id, designer_country_code, makerlab_name, makerlab_region, makerlab_id); } if (type_any_amf && is_xxx) imperial_units = true; @@ -4342,6 +4373,10 @@ std::vector Plater::priv::load_files(const std::vector& input_ //set designer_model_id q->model().stl_design_id = designer_model_id; q->model().stl_design_country = designer_country_code; + q->model().makerlab_region = makerlab_region; + q->model().makerlab_name = makerlab_name; + q->model().makerlab_id = makerlab_id; + //if (!designer_model_id.empty() && q->model().stl_design_id.empty() && !designer_country_code.empty()) { // q->model().stl_design_id = designer_model_id; // q->model().stl_design_country = designer_country_code; @@ -5772,7 +5807,8 @@ void Plater::priv::reload_from_disk() // load one file at a time for (size_t i = 0; i < input_paths.size(); ++i) { const auto& path = input_paths[i].string(); - auto obj_color_fun = [this, &path](std::vector &input_colors, bool is_single_color, std::vector &filament_ids, unsigned char &first_extruder_id) { + auto obj_color_fun = [this, &path](std::vector &input_colors, bool is_single_color, std::vector &filament_ids, unsigned char &first_extruder_id, + std::string ml_origin, std::string ml_name, std::string ml_id) { if (!boost::iends_with(path, ".obj")) { return; } const std::vector extruder_colours = wxGetApp().plater()->get_extruder_colors_from_plater_config(); ObjColorDialog color_dlg(nullptr, input_colors, is_single_color, extruder_colours, filament_ids, first_extruder_id);