diff --git a/src/libslic3r/Format/STEP.cpp b/src/libslic3r/Format/STEP.cpp index fe189d576..95ffd3a5b 100644 --- a/src/libslic3r/Format/STEP.cpp +++ b/src/libslic3r/Format/STEP.cpp @@ -34,9 +34,6 @@ #include "TopExp_Explorer.hxx" #include "BRep_Tool.hxx" -const double STEP_TRANS_CHORD_ERROR = 0.003; -const double STEP_TRANS_ANGLE_RES = 0.5; - namespace Slic3r { @@ -220,7 +217,10 @@ static void getNamedSolids(const TopLoc_Location& location, const std::string& p } } -bool load_step(const char *path, Model *model, bool& is_cancel, ImportStepProgressFn stepFn, StepIsUtf8Fn isUtf8Fn) +bool load_step(const char *path, Model *model, bool& is_cancel, + double linear_defletion/*=0.003*/, + double angle_defletion/*= 0.5*/, + ImportStepProgressFn stepFn, StepIsUtf8Fn isUtf8Fn, long& mesh_face_num) { bool cb_cancel = false; if (stepFn) { @@ -275,7 +275,7 @@ bool load_step(const char *path, Model *model, bool& is_cancel, ImportStepProgre stl.resize(namedSolids.size()); tbb::parallel_for(tbb::blocked_range(0, namedSolids.size()), [&](const tbb::blocked_range &range) { for (size_t i = range.begin(); i < range.end(); i++) { - BRepMesh_IncrementalMesh mesh(namedSolids[i].solid, STEP_TRANS_CHORD_ERROR, false, STEP_TRANS_ANGLE_RES, true); + BRepMesh_IncrementalMesh mesh(namedSolids[i].solid, linear_defletion, false, angle_defletion, true); // BBS: calculate total number of the nodes and triangles int aNbNodes = 0; int aNbTriangles = 0; @@ -348,6 +348,14 @@ bool load_step(const char *path, Model *model, bool& is_cancel, ImportStepProgre } }); + if (mesh_face_num != -1) { + for (size_t i = 0; i < stl.size(); i++) { + // Test for overflow + mesh_face_num += stl[i].stats.number_of_facets; + } + return true; + } + ModelObject *new_object = model->add_object(); const char * last_slash = strrchr(path, DIR_SEPARATOR); new_object->name.assign((last_slash == nullptr) ? path : last_slash + 1); diff --git a/src/libslic3r/Format/STEP.hpp b/src/libslic3r/Format/STEP.hpp index b86933a34..72f832710 100644 --- a/src/libslic3r/Format/STEP.hpp +++ b/src/libslic3r/Format/STEP.hpp @@ -17,7 +17,13 @@ typedef std::function StepIsUtf8Fn; //BBS: Load an step file into a provided model. -extern bool load_step(const char *path, Model *model, bool& is_cancel, ImportStepProgressFn proFn = nullptr, StepIsUtf8Fn isUtf8Fn = nullptr); +extern bool load_step(const char *path, Model *model, + bool& is_cancel, + double linear_defletion = 0.003, + double angle_defletion = 0.5, + ImportStepProgressFn proFn = nullptr, + StepIsUtf8Fn isUtf8Fn = nullptr, + long& mesh_face_num = *(new long(-1))); //BBS: Used to detect what kind of encoded type is used in name field of step // If is encoded in UTF8, the file don't need to be handled, then return the original path directly. diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index a1bf6bad1..08922f250 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -30,6 +30,7 @@ #include "SVG.hpp" #include +#include #include "GCodeWriter.hpp" // BBS: for segment @@ -183,7 +184,8 @@ Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* c StepIsUtf8Fn stepIsUtf8Fn, BBLProject * project, int plate_id, - ObjImportColorFn objFn) + ObjImportColorFn objFn, + std::function step_mesh_fn) { Model model; @@ -208,9 +210,19 @@ Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* c bool is_cb_cancel = false; std::string message; if (boost::algorithm::iends_with(input_file, ".stp") || - boost::algorithm::iends_with(input_file, ".step")) - result = load_step(input_file.c_str(), &model, is_cb_cancel, stepFn, stepIsUtf8Fn); - else if (boost::algorithm::iends_with(input_file, ".stl")) + boost::algorithm::iends_with(input_file, ".step")) { + double linear_defletion = 0.003; + double angle_defletion = 0.5; + if (step_mesh_fn) { + if (step_mesh_fn(linear_defletion, angle_defletion) == -1) { + result = false; + goto end; + } + } + result = load_step(input_file.c_str(), &model, is_cb_cancel, linear_defletion, angle_defletion, stepFn, stepIsUtf8Fn); + end: + BOOST_LOG_TRIVIAL(info) << "Cancel step mesh dialog"; + } else if (boost::algorithm::iends_with(input_file, ".stl")) result = load_stl(input_file.c_str(), &model, nullptr, stlFn); else if (boost::algorithm::iends_with(input_file, ".oltp")) result = load_stl(input_file.c_str(), &model, nullptr, stlFn,256); diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index afea23735..5f7774495 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -1579,7 +1579,8 @@ public: StepIsUtf8Fn stepIsUtf8Fn = nullptr, BBLProject * project = nullptr, int plate_id = 0, - ObjImportColorFn objFn = nullptr + ObjImportColorFn objFn = nullptr, + std::function step_mesh_fn = nullptr ); // BBS static bool obj_import_vertex_color_deal(const std::vector &vertex_filament_ids, const unsigned char &first_extruder_id, Model *model); diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index f67fd88bb..1f10f7b89 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -295,6 +295,8 @@ set(SLIC3R_GUI_SOURCES GUI/RemovableDriveManager.hpp GUI/SendSystemInfoDialog.cpp GUI/SendSystemInfoDialog.hpp + GUI/StepMeshDialog.cpp + GUI/StepMeshDialog.hpp GUI/PlateSettingsDialog.cpp GUI/PlateSettingsDialog.hpp GUI/ImGuiWrapper.hpp diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index cdfdda7cd..bdb920714 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -139,6 +139,7 @@ #include "PlateSettingsDialog.hpp" #include "DailyTips.hpp" #include "CreatePresetsDialog.hpp" +#include "StepMeshDialog.hpp" using boost::optional; namespace fs = boost::filesystem; @@ -3973,7 +3974,20 @@ std::vector Plater::priv::load_files(const std::vector& input_ filament_ids.clear(); } }; - model = Slic3r::Model::read_from_file( + auto step_mesh = [this, &path, &is_user_cancel](double& linear_value, double& angle_value)-> int { + if (boost::iends_with(path.string(), ".step") || + boost::iends_with(path.string(), ".stp")){ + StepMeshDialog mesh_dlg(nullptr, path); + if (mesh_dlg.ShowModal() == wxID_OK) { + linear_value = mesh_dlg.get_linear_defletion(); + angle_value = mesh_dlg.get_angle_defletion(); + return 1; + } + } + is_user_cancel = false; + return -1; + }; + 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) { @@ -4003,7 +4017,7 @@ std::vector Plater::priv::load_files(const std::vector& input_ Slic3r::GUI::show_info(nullptr, _L("Name of components inside step file is not UTF8 format!") + "\n\n" + _L("The name may show garbage characters!"), _L("Attention!")); }, - nullptr, 0, obj_color_fun); + nullptr, 0, obj_color_fun, step_mesh); if (designer_model_id.empty() && boost::algorithm::iends_with(path.string(), ".stl")) { diff --git a/src/slic3r/GUI/StepMeshDialog.cpp b/src/slic3r/GUI/StepMeshDialog.cpp new file mode 100644 index 000000000..60d2acde1 --- /dev/null +++ b/src/slic3r/GUI/StepMeshDialog.cpp @@ -0,0 +1,216 @@ +#include "StepMeshDialog.hpp" +#include "BBLStatusBar.hpp" +#include "I18N.hpp" +#include "GUI_App.hpp" +#include "Widgets/Button.hpp" +#include "MainFrame.hpp" +#include +#include + +using namespace Slic3r; +using namespace Slic3r::GUI; + +static int _scale(const int val) { return val * Slic3r::GUI::wxGetApp().em_unit() / 10; } +static int _ITEM_WIDTH() { return _scale(30); } +#define MIN_DIALOG_WIDTH FromDIP(400) +#define SLIDER_WIDTH FromDIP(150) +#define TEXT_CTRL_WIDTH FromDIP(40) +#define BUTTON_SIZE wxSize(FromDIP(58), FromDIP(24)) +#define BUTTON_BORDER FromDIP(int(400 - 58 * 2) / 8) +#define SLIDER_SCALE(val) ((val) / 0.001) +#define SLIDER_UNSCALE(val) ((val) * 0.001) +#define SLIDER_SCALE_10(val) ((val) / 0.01) +#define SLIDER_UNSCALE_10(val) ((val) * 0.01) +#define LEFT_RIGHT_PADING FromDIP(20) + +void StepMeshDialog::on_dpi_changed(const wxRect& suggested_rect) { +}; + +bool StepMeshDialog:: validate_number_range(const wxString& value, double min, double max) { + double num; + if (!value.ToDouble(&num)) { + return false; + } + return (num >= min && num <= max); +} + +StepMeshDialog::StepMeshDialog(wxWindow* parent, fs::path file) + : DPIDialog(parent ? parent : static_cast(wxGetApp().mainframe), + wxID_ANY, + _(L("Step file import parameters")), + wxDefaultPosition, + wxDefaultSize, + wxDEFAULT_DIALOG_STYLE /* | wxRESIZE_BORDER*/), m_file(file) +{ + std::string icon_path = (boost::format("%1%/images/BambuStudioTitle.ico") + % Slic3r::resources_dir()).str(); + SetIcon(wxIcon(Slic3r::encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO)); + + SetBackgroundColour(*wxWHITE); + + wxBoxSizer* bSizer = new wxBoxSizer(wxVERTICAL); + bSizer->SetMinSize(wxSize(MIN_DIALOG_WIDTH, -1)); + + wxBoxSizer* linear_sizer = new wxBoxSizer(wxHORIZONTAL); + //linear_sizer->SetMinSize(wxSize(MIN_DIALOG_WIDTH, -1)); + wxStaticText* linear_title = new wxStaticText(this, + wxID_ANY, + _L("Linear Deflection:")); + linear_sizer->Add(linear_title, 0, wxALIGN_LEFT); + linear_sizer->AddStretchSpacer(1); + wxSlider* linear_slider = new wxSlider(this, wxID_ANY, + SLIDER_SCALE(get_linear_defletion()), + 1, 100, wxDefaultPosition, + wxSize(SLIDER_WIDTH, -1), + wxSL_HORIZONTAL); + linear_sizer->Add(linear_slider, 0, wxALIGN_RIGHT | wxLEFT, FromDIP(5)); + wxTextValidator valid_number(wxFILTER_NUMERIC); + wxTextCtrl* linear_textctrl = new wxTextCtrl(this, wxID_ANY, + m_linear_last, + wxDefaultPosition, wxSize(TEXT_CTRL_WIDTH, -1), + 0, valid_number); + linear_sizer->Add(linear_textctrl, 0, wxALIGN_RIGHT | wxLEFT, FromDIP(5)); + // textctrl loss focus + linear_textctrl->Bind(wxEVT_KILL_FOCUS, ([this, linear_textctrl](wxFocusEvent& e) { + wxString value = linear_textctrl->GetValue(); + if(!validate_number_range(value, 0.001, 0.1)) { + linear_textctrl->SetValue(m_linear_last); + } + m_linear_last = value; + update_mesh_number_text(); + e.Skip(); + })); + // slider bind textctrl + linear_slider->Bind(wxEVT_SLIDER, ([this, linear_slider, linear_textctrl](wxCommandEvent& e) { + double slider_value = SLIDER_UNSCALE(linear_slider->GetValue()); + linear_textctrl->SetValue(wxString::Format("%.3f", slider_value)); + m_linear_last = wxString::Format("%.3f", slider_value); + update_mesh_number_text(); + })); + // textctrl bind slider + linear_textctrl->Bind(wxEVT_TEXT, ([this, linear_textctrl, linear_slider](wxCommandEvent& e) { + double slider_value_long; + int slider_value; + wxString value = linear_textctrl->GetValue(); + if (value.ToDouble(&slider_value_long)) { + slider_value = SLIDER_SCALE(slider_value_long); + if (slider_value >= linear_slider->GetMin() && slider_value <= linear_slider->GetMax()) { + linear_slider->SetValue(slider_value); + } + } + })); + + bSizer->Add(linear_sizer, 1, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, LEFT_RIGHT_PADING); + + wxBoxSizer* angle_sizer = new wxBoxSizer(wxHORIZONTAL); + wxStaticText* angle_title = new wxStaticText(this, + wxID_ANY, + _L("Angle Deflection:")); + angle_sizer->Add(angle_title, 0, wxALIGN_LEFT); + angle_sizer->AddStretchSpacer(1); + wxSlider* angle_slider = new wxSlider(this, wxID_ANY, + SLIDER_SCALE_10(get_angle_defletion()), + 1, 100, wxDefaultPosition, + wxSize(SLIDER_WIDTH, -1), + wxSL_HORIZONTAL); + angle_sizer->Add(angle_slider, 0, wxALIGN_RIGHT | wxLEFT, FromDIP(5)); + wxTextCtrl* angle_textctrl = new wxTextCtrl(this, wxID_ANY, + m_angle_last, + wxDefaultPosition, wxSize(TEXT_CTRL_WIDTH, -1), + 0, valid_number); + angle_sizer->Add(angle_textctrl, 0, wxALIGN_RIGHT | wxLEFT, FromDIP(5)); + // textctrl loss focus + angle_textctrl->Bind(wxEVT_KILL_FOCUS, ([this, angle_textctrl](wxFocusEvent& e) { + wxString value = angle_textctrl->GetValue(); + if (!validate_number_range(value, 0.01, 1)) { + angle_textctrl->SetValue(m_angle_last); + } + m_angle_last = value; + update_mesh_number_text(); + e.Skip(); + })); + // slider bind textctrl + angle_slider->Bind(wxEVT_SLIDER, ([this, angle_slider, angle_textctrl](wxCommandEvent& e) { + double slider_value = SLIDER_UNSCALE_10(angle_slider->GetValue()); + angle_textctrl->SetValue(wxString::Format("%.2f", slider_value)); + m_angle_last = wxString::Format("%.2f", slider_value); + update_mesh_number_text(); + })); + // textctrl bind slider + linear_textctrl->Bind(wxEVT_TEXT, ([this, angle_slider, angle_textctrl](wxCommandEvent& e) { + double slider_value_long; + int slider_value; + wxString value = angle_textctrl->GetValue(); + if (value.ToDouble(&slider_value_long)) { + slider_value = SLIDER_SCALE_10(slider_value_long); + if (slider_value >= angle_slider->GetMin() && slider_value <= angle_slider->GetMax()) { + angle_slider->SetValue(slider_value); + } + } + })); + + bSizer->Add(angle_sizer, 1, wxEXPAND | wxLEFT | wxRIGHT, LEFT_RIGHT_PADING); + + + mesh_face_number_text = new wxStaticText(this, wxID_ANY, _L("Number of generated surfaces: 0")); + bSizer->Add(mesh_face_number_text, 1, wxEXPAND | wxLEFT | wxRIGHT, LEFT_RIGHT_PADING); + + wxBoxSizer* bSizer_button = new wxBoxSizer(wxHORIZONTAL); + bSizer_button->SetMinSize(wxSize(FromDIP(100), -1)); + + StateColor btn_bg_green(std::pair(wxColour(27, 136, 68), StateColor::Pressed), std::pair(wxColour(61, 203, 115), StateColor::Hovered), + std::pair(AMS_CONTROL_BRAND_COLOUR, StateColor::Normal)); + m_button_ok = new Button(this, _L("OK")); + m_button_ok->SetBackgroundColor(btn_bg_green); + m_button_ok->SetBorderColor(*wxWHITE); + m_button_ok->SetTextColor(wxColour(0xFFFFFE)); + m_button_ok->SetFont(Label::Body_12); + m_button_ok->SetSize(BUTTON_SIZE); + m_button_ok->SetMinSize(BUTTON_SIZE); + m_button_ok->SetCornerRadius(FromDIP(12)); + bSizer_button->Add(m_button_ok, 0, wxALIGN_RIGHT, BUTTON_BORDER); + + m_button_ok->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& e) { EndModal(wxID_OK); }); + + StateColor btn_bg_white(std::pair(wxColour(206, 206, 206), StateColor::Pressed), std::pair(wxColour(238, 238, 238), StateColor::Hovered), + std::pair(*wxWHITE, StateColor::Normal)); + + m_button_cancel = new Button(this, _L("Cancel")); + m_button_cancel->SetBackgroundColor(btn_bg_white); + m_button_cancel->SetBorderColor(wxColour(38, 46, 48)); + m_button_cancel->SetFont(Label::Body_12); + m_button_cancel->SetSize(BUTTON_SIZE); + m_button_cancel->SetMinSize(BUTTON_SIZE); + m_button_cancel->SetCornerRadius(FromDIP(12)); + bSizer_button->Add(m_button_cancel, 0, wxALIGN_RIGHT | wxLEFT, BUTTON_BORDER); + + m_button_cancel->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& e) { EndModal(wxID_CANCEL); }); + + bSizer->Add(bSizer_button, 0, wxALIGN_RIGHT | wxRIGHT| wxBOTTOM, LEFT_RIGHT_PADING); + + this->SetSizer(bSizer); + update_mesh_number_text(); + this->Layout(); + bSizer->Fit(this); + + this->Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent& e) { }); + + wxGetApp().UpdateDlgDarkUI(this); +} + +long StepMeshDialog::get_mesh_number() +{ + Model model; + long number = 0; + const std::string file_path = m_file.string(); + bool is_cb_cancel = false; + bool result = load_step(file_path.c_str(), &model, is_cb_cancel, get_linear_defletion(), get_angle_defletion(), nullptr, nullptr, number); + return number; +} + +void StepMeshDialog::update_mesh_number_text() +{ + long number = get_mesh_number(); + wxString newText = wxString::Format("Number of generated surfaces: %d", number); + mesh_face_number_text->SetLabel(newText); +} \ No newline at end of file diff --git a/src/slic3r/GUI/StepMeshDialog.hpp b/src/slic3r/GUI/StepMeshDialog.hpp new file mode 100644 index 000000000..24754cd13 --- /dev/null +++ b/src/slic3r/GUI/StepMeshDialog.hpp @@ -0,0 +1,42 @@ +#ifndef _STEP_MESH_DIALOG_H_ +#define _STEP_MESH_DIALOG_H_ + +#include "GUI_Utils.hpp" +#include +#include +class Button; +namespace fs = boost::filesystem; +class StepMeshDialog : public Slic3r::GUI::DPIDialog +{ +public: + StepMeshDialog(wxWindow* parent, fs::path file); + void on_dpi_changed(const wxRect& suggested_rect) override; + inline double get_linear_defletion() { + double value; + if (m_linear_last.ToDouble(&value)) { + return value; + }else { + return 0.003; + } + } + inline double get_angle_defletion() { + double value; + if (m_angle_last.ToDouble(&value)) { + return value; + } else { + return 0.5; + } + } + long get_mesh_number(); +private: + fs::path m_file; + Button* m_button_ok = nullptr; + Button* m_button_cancel = nullptr; + wxString m_linear_last = wxString::Format("%.3f", 0.003); + wxString m_angle_last = wxString::Format("%.2f", 0.5); + wxStaticText* mesh_face_number_text; + bool validate_number_range(const wxString& value, double min, double max); + void update_mesh_number_text(); +}; + +#endif // _STEP_MESH_DIALOG_H_ \ No newline at end of file