diff --git a/src/admesh/stl.h b/src/admesh/stl.h index 28d5ee1553..65527e6f6b 100644 --- a/src/admesh/stl.h +++ b/src/admesh/stl.h @@ -45,6 +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 enum { eNormal, // normal face eSmallOverhang, // small overhang @@ -244,7 +246,7 @@ struct indexed_triangle_set } }; -extern bool stl_open(stl_file *stl, const char *file); +extern bool stl_open(stl_file *stl, const char *file, ImportstlProgressFn stlFn = nullptr); extern void stl_stats_out(stl_file *stl, FILE *file, char *input_file); extern bool stl_print_neighbors(stl_file *stl, char *file); extern bool stl_write_ascii(stl_file *stl, const char *file, const char *label); @@ -398,7 +400,7 @@ extern void stl_calculate_volume(stl_file *stl); extern void stl_repair(stl_file *stl, bool fixall_flag, bool exact_flag, bool tolerance_flag, float tolerance, bool increment_flag, float increment, bool nearby_flag, int iterations, bool remove_unconnected_flag, bool fill_holes_flag, bool normal_directions_flag, bool normal_values_flag, bool reverse_all_flag, bool verbose_flag); extern void stl_allocate(stl_file *stl); -extern void stl_read(stl_file *stl, int first_facet, bool first); +extern void stl_read(stl_file *stl, int first_facet, bool first, ImportstlProgressFn stlFn = nullptr); extern void stl_facet_stats(stl_file *stl, stl_facet facet, bool &first); extern void stl_reallocate(stl_file *stl); extern void stl_add_facet(stl_file *stl, const stl_facet *new_facet); diff --git a/src/admesh/stlinit.cpp b/src/admesh/stlinit.cpp index 29131b1c75..f1be4ac77c 100644 --- a/src/admesh/stlinit.cpp +++ b/src/admesh/stlinit.cpp @@ -31,6 +31,7 @@ #include #include "stl.h" +#include "libslic3r/Format/STL.hpp" #include "libslic3r/LocalesUtils.hpp" @@ -42,6 +43,8 @@ extern void stl_internal_reverse_quads(char *buf, size_t cnt); #endif /* BOOST_ENDIAN_BIG_BYTE */ +const int LOAD_STL_UNIT_NUM = 5; + static FILE* stl_open_count_facets(stl_file *stl, const char *file) { // Open the file in binary mode first. @@ -145,7 +148,7 @@ static FILE* stl_open_count_facets(stl_file *stl, const char *file) /* Reads the contents of the file pointed to by fp into the stl structure, starting at facet first_facet. The second argument says if it's our first time running this for the stl and therefore we should reset our max and min stats. */ -static bool stl_read(stl_file *stl, FILE *fp, int first_facet, bool first) +static bool stl_read(stl_file *stl, FILE *fp, int first_facet, bool first, ImportstlProgressFn stlFn) { if (stl->stats.type == binary) fseek(fp, HEADER_SIZE, SEEK_SET); @@ -153,7 +156,19 @@ static bool stl_read(stl_file *stl, FILE *fp, int first_facet, bool first) rewind(fp); char normal_buf[3][32]; - for (uint32_t i = first_facet; i < stl->stats.number_of_facets; ++ i) { + + uint32_t facets_num = stl->stats.number_of_facets; + uint32_t unit = facets_num / LOAD_STL_UNIT_NUM + 1; + for (uint32_t i = first_facet; i < facets_num; ++ i) { + if ((i % unit) == 0) { + bool cb_cancel = false; + if (stlFn) { + stlFn(i, facets_num, cb_cancel); + if (cb_cancel) + return false; + } + } + stl_facet facet; if (stl->stats.type == binary) { @@ -232,7 +247,7 @@ static bool stl_read(stl_file *stl, FILE *fp, int first_facet, bool first) return true; } -bool stl_open(stl_file *stl, const char *file) +bool stl_open(stl_file *stl, const char *file, ImportstlProgressFn stlFn) { Slic3r::CNumericLocalesSetter locales_setter; stl->clear(); @@ -240,7 +255,7 @@ bool stl_open(stl_file *stl, const char *file) if (fp == nullptr) return false; stl_allocate(stl); - bool result = stl_read(stl, fp, 0, true); + bool result = stl_read(stl, fp, 0, true, stlFn); fclose(fp); return result; } diff --git a/src/libslic3r/Format/STEP.cpp b/src/libslic3r/Format/STEP.cpp index f055540146..2b388199be 100644 --- a/src/libslic3r/Format/STEP.cpp +++ b/src/libslic3r/Format/STEP.cpp @@ -31,9 +31,6 @@ const double STEP_TRANS_CHORD_ERROR = 0.005; const double STEP_TRANS_ANGLE_RES = 1; -const int LOAD_STEP_STAGE_READ_FILE = 0; -const int LOAD_STEP_STAGE_GET_SOLID = 1; -const int LOAD_STEP_STAGE_GET_MESH = 2; namespace Slic3r { @@ -213,11 +210,11 @@ static void getNamedSolids(const TopLoc_Location& location, const std::string& p } } -bool load_step(const char *path, Model *model, ImportStepProgressFn proFn, StepIsUtf8Fn isUtf8Fn) +bool load_step(const char *path, Model *model, ImportStepProgressFn stepFn, StepIsUtf8Fn isUtf8Fn) { bool cb_cancel = false; - if (proFn) { - proFn(LOAD_STEP_STAGE_READ_FILE, 0, 1, cb_cancel); + if (stepFn) { + stepFn(LOAD_STEP_STAGE_READ_FILE, 0, 1, cb_cancel); if (cb_cancel) return false; } @@ -245,9 +242,13 @@ bool load_step(const char *path, Model *model, ImportStepProgressFn proFn, StepI unsigned int id{1}; Standard_Integer topShapeLength = topLevelShapes.Length() + 1; + auto stage_unit2 = topShapeLength / LOAD_STEP_STAGE_UNIT_NUM + 1; + for (Standard_Integer iLabel = 1; iLabel < topShapeLength; ++iLabel) { - if (proFn) { - proFn(LOAD_STEP_STAGE_GET_SOLID, iLabel, topShapeLength, cb_cancel); + if (stepFn) { + if ((iLabel % stage_unit2) == 0) { + stepFn(LOAD_STEP_STAGE_GET_SOLID, iLabel, topShapeLength, cb_cancel); + } if (cb_cancel) { shapeTool.reset(nullptr); application->Close(document); @@ -338,9 +339,13 @@ bool load_step(const char *path, Model *model, ImportStepProgressFn proFn, StepI const char * last_slash = strrchr(path, DIR_SEPARATOR); new_object->name.assign((last_slash == nullptr) ? path : last_slash + 1); new_object->input_file = path; + + auto stage_unit3 = stl.size() / LOAD_STEP_STAGE_UNIT_NUM + 1; for (size_t i = 0; i < stl.size(); i++) { - if (proFn) { - proFn(LOAD_STEP_STAGE_GET_MESH, i, namedSolids.size(), cb_cancel); + if (stepFn) { + if ((i % stage_unit3) == 0) { + stepFn(LOAD_STEP_STAGE_GET_MESH, i, stl.size(), cb_cancel); + } if (cb_cancel) { model->delete_object(new_object); shapeTool.reset(nullptr); diff --git a/src/libslic3r/Format/STEP.hpp b/src/libslic3r/Format/STEP.hpp index 14d1db21fc..13965d4112 100644 --- a/src/libslic3r/Format/STEP.hpp +++ b/src/libslic3r/Format/STEP.hpp @@ -6,6 +6,13 @@ namespace Slic3r { class TriangleMesh; class ModelObject; +// load step stage +const int LOAD_STEP_STAGE_READ_FILE = 0; +const int LOAD_STEP_STAGE_GET_SOLID = 1; +const int LOAD_STEP_STAGE_GET_MESH = 2; +const int LOAD_STEP_STAGE_NUM = 3; +const int LOAD_STEP_STAGE_UNIT_NUM = 5; + typedef std::function ImportStepProgressFn; typedef std::function StepIsUtf8Fn; diff --git a/src/libslic3r/Format/STL.cpp b/src/libslic3r/Format/STL.cpp index 2f2c9ec7fb..3ba514dc9b 100644 --- a/src/libslic3r/Format/STL.cpp +++ b/src/libslic3r/Format/STL.cpp @@ -14,10 +14,10 @@ namespace Slic3r { -bool load_stl(const char *path, Model *model, const char *object_name_in) +bool load_stl(const char *path, Model *model, const char *object_name_in, ImportstlProgressFn stlFn) { TriangleMesh mesh; - if (! mesh.ReadSTLFile(path)) { + if (! mesh.ReadSTLFile(path, true, stlFn)) { // die "Failed to open $file\n" if !-e $path; return false; } diff --git a/src/libslic3r/Format/STL.hpp b/src/libslic3r/Format/STL.hpp index cff7dc0869..5f2f838bfe 100644 --- a/src/libslic3r/Format/STL.hpp +++ b/src/libslic3r/Format/STL.hpp @@ -1,13 +1,16 @@ #ifndef slic3r_Format_STL_hpp_ #define slic3r_Format_STL_hpp_ +#include + namespace Slic3r { +class Model; class TriangleMesh; class ModelObject; // Load an STL file into a provided model. -extern bool load_stl(const char *path, Model *model, const char *object_name = nullptr); +extern bool load_stl(const char *path, Model *model, const char *object_name = nullptr, ImportstlProgressFn stlFn = nullptr); extern bool store_stl(const char *path, TriangleMesh *mesh, bool binary); extern bool store_stl(const char *path, ModelObject *model_object, bool binary); diff --git a/src/libslic3r/Format/bbs_3mf.hpp b/src/libslic3r/Format/bbs_3mf.hpp index ff47b05aee..d7a90fba7f 100644 --- a/src/libslic3r/Format/bbs_3mf.hpp +++ b/src/libslic3r/Format/bbs_3mf.hpp @@ -166,6 +166,7 @@ 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; diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 888edd6c21..3788b286b6 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -137,7 +137,7 @@ Model::~Model() // Loading model from a file, it may be a simple geometry file as STL or OBJ, however it may be a project file as well. Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* config, ConfigSubstitutionContext* config_substitutions, LoadStrategy options, PlateDataPtrs* plate_data, std::vector* project_presets, bool *is_xxx, Semver* file_version, Import3mfProgressFn proFn, - ImportStepProgressFn stepFn, StepIsUtf8Fn stepIsUtf8Fn, BBLProject* project) + ImportstlProgressFn stlFn, ImportStepProgressFn stepFn, StepIsUtf8Fn stepIsUtf8Fn, BBLProject* project) { Model model; @@ -163,7 +163,7 @@ Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* c boost::algorithm::iends_with(input_file, ".step")) result = load_step(input_file.c_str(), &model, stepFn, stepIsUtf8Fn); else if (boost::algorithm::iends_with(input_file, ".stl")) - result = load_stl(input_file.c_str(), &model); + result = load_stl(input_file.c_str(), &model, nullptr, stlFn); else if (boost::algorithm::iends_with(input_file, ".obj")) result = load_obj(input_file.c_str(), &model); //BBS: remove the old .amf.xml files diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 4629998021..ef134fcfc0 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -18,6 +18,8 @@ #include "Format/bbs_3mf.hpp" //BBS: add step #include "Format/STEP.hpp" +//BBS: add stl +#include "Format/STL.hpp" #include #include @@ -1282,7 +1284,7 @@ public: DynamicPrintConfig* config = nullptr, ConfigSubstitutionContext* config_substitutions = nullptr, LoadStrategy options = LoadStrategy::AddDefaultInstances, PlateDataPtrs* plate_data = nullptr, std::vector* project_presets = nullptr, bool* is_xxx = nullptr, Semver* file_version = nullptr, Import3mfProgressFn proFn = nullptr, - ImportStepProgressFn stepFn = nullptr, StepIsUtf8Fn stepIsUtf8Fn = nullptr, BBLProject* project = nullptr); + ImportstlProgressFn stlFn = nullptr, ImportStepProgressFn stepFn = nullptr, StepIsUtf8Fn stepIsUtf8Fn = nullptr, BBLProject* project = nullptr); // BBS static double findMaxSpeed(const ModelObject* object); static double getThermalLength(const ModelVolume* modelVolumePtr); diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index e732cc177f..5fa3611192 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -9,7 +9,7 @@ #include "Execution/ExecutionTBB.hpp" #include "Execution/ExecutionSeq.hpp" #include "Utils.hpp" - +#include "Format/STL.hpp" #include #include #include @@ -208,10 +208,10 @@ bool TriangleMesh::from_stl(stl_file& stl, bool repair) return true; } -bool TriangleMesh::ReadSTLFile(const char* input_file, bool repair) +bool TriangleMesh::ReadSTLFile(const char* input_file, bool repair, ImportstlProgressFn stlFn) { stl_file stl; - if (! stl_open(&stl, input_file)) + if (! stl_open(&stl, input_file, stlFn)) return false; return from_stl(stl, repair); } diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index 3ebd3105c8..3fece644bd 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -10,7 +10,7 @@ #include "Point.hpp" #include "Polygon.hpp" #include "ExPolygon.hpp" - +#include "Format/STL.hpp" namespace Slic3r { class TriangleMesh; @@ -94,7 +94,7 @@ public: explicit TriangleMesh(indexed_triangle_set &&M, const RepairedMeshErrors& repaired_errors = RepairedMeshErrors()); void clear() { this->its.clear(); this->m_stats.clear(); } bool from_stl(stl_file& stl, bool repair = true); - bool ReadSTLFile(const char* input_file, bool repair = true); + bool ReadSTLFile(const char* input_file, bool repair = true, ImportstlProgressFn stlFn = nullptr); bool write_ascii(const char* output_file); bool write_binary(const char* output_file); float volume(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 7a73c657ba..858905065f 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1,5 +1,4 @@ #include "Plater.hpp" - #include #include #include @@ -41,6 +40,7 @@ #include "libslic3r/libslic3r.h" #include "libslic3r/Format/STL.hpp" +#include "libslic3r/Format/STEP.hpp" #include "libslic3r/Format/AMF.hpp" //#include "libslic3r/Format/3mf.hpp" #include "libslic3r/Format/bbs_3mf.hpp" @@ -2576,7 +2576,39 @@ std::vector Plater::priv::load_files(const std::vector& input_ int answer_convert_from_imperial_units = wxOK_DEFAULT; int tolal_model_count = 0; + int progress_percent = 0; + int total_files = input_files.size(); + const int stage_percent[IMPORT_STAGE_MAX+1] = { + 5, // IMPORT_STAGE_RESTORE + 10, // IMPORT_STAGE_OPEN + 30, // IMPORT_STAGE_READ_FILES + 50, // IMPORT_STAGE_EXTRACT + 60, // IMPORT_STAGE_LOADING_OBJECTS + 70, // IMPORT_STAGE_LOADING_PLATES + 80, // IMPORT_STAGE_FINISH + 85, // IMPORT_STAGE_ADD_INSTANCE + 90, // IMPORT_STAGE_UPDATE_GCODE + 92, // IMPORT_STAGE_CHECK_MODE_GCODE + 95, // UPDATE_GCODE_RESULT + 98, // IMPORT_LOAD_CONFIG + 99, // IMPORT_LOAD_MODEL_OBJECTS + 100 + }; + const int step_percent[LOAD_STEP_STAGE_NUM+1] = { + 5, // LOAD_STEP_STAGE_READ_FILE + 30, // LOAD_STEP_STAGE_GET_SOLID + 60, // LOAD_STEP_STAGE_GET_MESH + 100 + }; + + const float INPUT_FILES_RATIO = 0.7; + const float INIT_MODEL_RATIO = 0.75; + const float CENTER_AROUND_ORIGIN_RATIO = 0.8; + const float LOAD_MODEL_RATIO = 0.9; + for (size_t i = 0; i < input_files.size(); ++i) { + int file_percent = 0; + #ifdef _WIN32 auto path = input_files[i]; // On Windows, we swap slashes to back slashes, see GH #6803 as read_from_file() does not understand slashes on Windows thus it assignes full path to names of loaded objects. @@ -2586,15 +2618,13 @@ std::vector Plater::priv::load_files(const std::vector& input_ const auto &path = input_files[i]; #endif // _WIN32 const auto filename = path.filename(); - int progress_percent = static_cast(100.0f * static_cast(i) / static_cast(input_files.size())); + int progress_percent = static_cast(100.0f * static_cast(i) / static_cast(input_files.size())); const auto real_filename = (strategy & LoadStrategy::Restore) ? input_files[++i].filename() : filename; const auto dlg_info = _L("Loading file") + ": " + from_path(real_filename); BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": load file %1%") % filename; dlg_cont = dlg.Update(progress_percent, dlg_info); if (!dlg_cont) return empty_result; - dlg.Fit(); - const bool type_3mf = std::regex_match(path.string(), pattern_3mf); // const bool type_zip_amf = !type_3mf && std::regex_match(path.string(), pattern_zip_amf); const bool type_any_amf = !type_3mf && std::regex_match(path.string(), pattern_any_amf); @@ -2625,13 +2655,15 @@ std::vector Plater::priv::load_files(const std::vector& input_ // BBS: backup & restore model = Slic3r::Model::read_from_archive(path.string(), &config_loaded, &config_substitutions, en_3mf_file_type, strategy, &plate_data, &project_presets, &file_version, - [this, &dlg, real_filename, progress_percent](int import_stage, int current, int total, bool &cancel) { + [this, &dlg, real_filename, &progress_percent, &file_percent, stage_percent, INPUT_FILES_RATIO, total_files, i](int import_stage, int current, int total, bool &cancel) { bool cont = true; + float percent_float = (100.0f * (float)i / (float)total_files) + INPUT_FILES_RATIO * ((float)stage_percent[import_stage] + (float)current * (float)(stage_percent[import_stage + 1] - stage_percent[import_stage]) /(float) total) / (float)total_files; + BOOST_LOG_TRIVIAL(trace) << "load_3mf_file: percent(float)=" << percent_float << ", stage = " << import_stage << ", curr = " << current << ", total = " << total; + progress_percent = (int)percent_float; wxString msg = wxString::Format(_L("Loading file: %s"), from_path(real_filename)); cont = dlg.Update(progress_percent, msg); cancel = !cont; }); - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", plate_data.size %1%, project_preset.size %2%, is_bbs_3mf %3%, file_version %4% \n") % plate_data.size() % project_presets.size() % (en_3mf_file_type == En3mfType::From_BBS) % file_version.to_string(); @@ -2866,11 +2898,25 @@ std::vector Plater::priv::load_files(const std::vector& input_ Semver file_version; model = Slic3r::Model::read_from_file( path.string(), nullptr, nullptr, strategy, &plate_data, &project_presets, &is_xxx, &file_version, nullptr, - [&dlg, real_filename, progress_percent](int import_stage, int current, int total, bool &cancel) { - bool cont = true; - wxString msg = wxString::Format("Loading file: %s", from_path(real_filename)); - cont = dlg.Update(progress_percent, msg); - cancel = !cont; + [this, &dlg, real_filename, &progress_percent, &file_percent, INPUT_FILES_RATIO, total_files, i](int current, int total, bool &cancel) + { + 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; + BOOST_LOG_TRIVIAL(trace) << "load_stl_file: percent(float)=" << percent_float << ", curr = " << current << ", total = " << total; + progress_percent = (int)percent_float; + wxString msg = wxString::Format(_L("Loading file: %s"), from_path(real_filename)); + cont = dlg.Update(progress_percent, msg); + cancel = !cont; + }, + [this, &dlg, real_filename, &progress_percent, &file_percent, step_percent, INPUT_FILES_RATIO, total_files, i](int load_stage, int current, int total, bool &cancel) + { + bool cont = true; + float percent_float = (100.0f * (float)i / (float)total_files) + INPUT_FILES_RATIO * ((float)step_percent[load_stage] + (float)current * (float)(step_percent[load_stage + 1] - step_percent[load_stage]) / (float)total) / (float)total_files; + BOOST_LOG_TRIVIAL(trace) << "load_step_file: percent(float)=" << percent_float << ", stage = " << load_stage << ", curr = " << current << ", total = " << total; + progress_percent = (int)percent_float; + wxString msg = wxString::Format(_L("Loading file: %s"), from_path(real_filename)); + cont = dlg.Update(progress_percent, msg); + cancel = !cont; }, [](int isUtf8StepFile) { if (!isUtf8StepFile) @@ -2912,6 +2958,10 @@ std::vector Plater::priv::load_files(const std::vector& input_ continue; } + progress_percent = 100.0f * (float)i / (float)total_files + INIT_MODEL_RATIO * 100.0f / (float)total_files; + dlg_cont = dlg.Update(progress_percent); + if (!dlg_cont) return empty_result; + if (load_model) { // The model should now be initialized auto convert_from_imperial_units = [](Model &model, bool only_small_volumes) { model.convert_from_imperial_units(only_small_volumes); }; @@ -2988,6 +3038,10 @@ std::vector Plater::priv::load_files(const std::vector& input_ // return obj_idxs; //} + progress_percent = 100.0f * (float)i / (float)total_files + CENTER_AROUND_ORIGIN_RATIO * 100.0f / (float)total_files; + dlg_cont = dlg.Update(progress_percent); + if (!dlg_cont) return empty_result; + int model_idx = 0; for (ModelObject *model_object : model.objects) { if (!type_3mf && !type_any_amf) model_object->center_around_origin(false); @@ -3004,6 +3058,9 @@ std::vector Plater::priv::load_files(const std::vector& input_ tolal_model_count += model_idx; + progress_percent = 100.0f * (float)i / (float)total_files + LOAD_MODEL_RATIO * 100.0f / (float)total_files; + dlg_cont = dlg.Update(progress_percent); + if (!dlg_cont) return empty_result; if (one_by_one) { // BBS: add load_old_project logic