diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index 22b052c777..45381e8f75 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -475,6 +475,30 @@ std::vector MenuFactory::get_svg_volume_bitmaps() return volume_bmps; } +wxString MenuFactory::get_repaire_result_message( + const std::vector& succes_models, + const std::vector>& failed_models) +{ + // Show info notification + wxString msg; + wxString bullet_suf = "\n - "; + if (!succes_models.empty()) { + msg = _L_PLURAL("The following model was repaired successfully", "The following models were repaired successfully", succes_models.size()) + ":"; + for (auto& model : succes_models) + msg += bullet_suf + from_u8(model); + msg += "\n\n"; + } + if (!failed_models.empty()) { + msg += _L_PLURAL("Folowing model repair failed", "Folowing models repair failed", failed_models.size()) + ":\n"; + for (auto& model : failed_models) + msg += bullet_suf + from_u8(model.first) + ": " + _(model.second); + } + if (msg.IsEmpty()) + msg = _L("Repairing was canceled"); + + return msg; +} + void MenuFactory::append_menu_item_delete(wxMenu* menu) { append_menu_item(menu, wxID_ANY, _L("Delete") + "\tDel", _L("Remove the selected object"), diff --git a/src/slic3r/GUI/GUI_Factories.hpp b/src/slic3r/GUI/GUI_Factories.hpp index 945e22eca9..e7706a8a15 100644 --- a/src/slic3r/GUI/GUI_Factories.hpp +++ b/src/slic3r/GUI/GUI_Factories.hpp @@ -41,6 +41,9 @@ public: static std::vector get_text_volume_bitmaps(); static std::vector get_svg_volume_bitmaps(); + static wxString get_repaire_result_message(const std::vector& succes_models, + const std::vector>& failed_models); + MenuFactory(); ~MenuFactory() = default; diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index db5b666ed6..2d5aee71ab 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -4670,21 +4670,7 @@ void ObjectList::fix_through_winsdk() progress_dlg.Update(100, ""); // Show info notification - wxString msg; - wxString bullet_suf = "\n - "; - if (!succes_models.empty()) { - msg = _L_PLURAL("The following model was repaired successfully", "The following models were repaired successfully", succes_models.size()) + ":"; - for (auto& model : succes_models) - msg += bullet_suf + from_u8(model); - msg += "\n\n"; - } - if (!failed_models.empty()) { - msg += _L_PLURAL("Folowing model repair failed", "Folowing models repair failed", failed_models.size()) + ":\n"; - for (auto& model : failed_models) - msg += bullet_suf + from_u8(model.first) + ": " + _(model.second); - } - if (msg.IsEmpty()) - msg = _L("Repairing was canceled"); + wxString msg = MenuFactory::get_repaire_result_message(succes_models, failed_models); plater->get_notification_manager()->push_notification(NotificationType::RepairFinished, NotificationManager::NotificationLevel::PrintInfoShortNotificationLevel, boost::nowide::narrow(msg)); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index c56802fa0d..c25b32b6de 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -12,8 +12,10 @@ #include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/GUI_ObjectManipulation.hpp" +#include "slic3r/GUI/GUI_Factories.hpp" #include "slic3r/GUI/format.hpp" #include "slic3r/Utils/UndoRedo.hpp" +#include "slic3r/Utils/FixModelByWin10.hpp" #include "libslic3r/AppConfig.hpp" #include "libslic3r/TriangleMeshSlicer.hpp" @@ -3259,6 +3261,8 @@ void update_object_cut_id(CutObjectBase& cut_id, ModelObjectCutAttributes attrib static void check_objects_after_cut(const ModelObjectPtrs& objects) { std::vector err_objects_names; + std::vector err_objects_idxs; + int obj_idx{ 0 }; for (const ModelObject* object : objects) { std::vector connectors_names; connectors_names.reserve(object->volumes.size()); @@ -3269,17 +3273,87 @@ static void check_objects_after_cut(const ModelObjectPtrs& objects) sort_remove_duplicates(connectors_names); if (connectors_count != connectors_names.size()) err_objects_names.push_back(object->name); - } - if (err_objects_names.empty()) - return; - wxString names = from_u8(err_objects_names[0]); - for (size_t i = 1; i < err_objects_names.size(); i++) - names += ", " + from_u8(err_objects_names[i]); - WarningDialog(wxGetApp().plater(), format_wxstr("Objects(%1%) have duplicated connectors. " - "Some connectors may be missing in slicing result.\n" - "Please report to PrusaSlicer team in which scenario this issue happened.\n" - "Thank you.", names)).ShowModal(); + // check manifol/repairs + auto stats = object->get_object_stl_stats(); + if (!stats.manifold() || stats.repaired()) + err_objects_idxs.push_back(obj_idx); + obj_idx++; + } + + auto plater = wxGetApp().plater(); + + if (!err_objects_names.empty()) { + wxString names = from_u8(err_objects_names[0]); + for (size_t i = 1; i < err_objects_names.size(); i++) + names += ", " + from_u8(err_objects_names[i]); + WarningDialog(plater, format_wxstr("Objects(%1%) have duplicated connectors. " + "Some connectors may be missing in slicing result.\n" + "Please report to PrusaSlicer team in which scenario this issue happened.\n" + "Thank you.", names)).ShowModal(); + } + + if (is_windows10() && !err_objects_idxs.empty()) { + auto dlg = WarningDialog(plater, _L("Cut is performed and open eages or auto-repaired errors are detected in result objects.\n" + "You can fix them by Windows repair algorithm.\n\n" + "Do you want to fix cut objects?"), + _L("Detected errors in cut objects"), wxYES_NO); + if (dlg.ShowModal() == wxID_YES) { + // model_name + std::vector succes_models; + // model_name failing reason + std::vector> failed_models; + + std::vector model_names; + + for (int obj_idx : err_objects_idxs) + model_names.push_back(objects[obj_idx]->name); + + auto fix_and_update_progress = [plater, model_names, &objects](const int obj_idx, int model_idx, + wxProgressDialog& progress_dlg, + std::vector& succes_models, + std::vector>& failed_models) -> bool + { + const std::string& model_name = model_names[model_idx]; + wxString msg = _L("Repairing model"); + if (model_names.size() == 1) + msg += ": " + from_u8(model_name) + "\n"; + else { + msg += ":\n"; + for (int i = 0; i < int(model_names.size()); ++i) + msg += (i == model_idx ? " > " : " ") + from_u8(model_names[i]) + "\n"; + msg += "\n"; + } + + std::string res; + if (!fix_model_by_win10_sdk_gui(*objects[obj_idx], -1, progress_dlg, msg, res)) + return false; + + if (res.empty()) + succes_models.push_back(model_name); + else + failed_models.push_back({ model_name, res }); + return true; + }; + + // Open a progress dialog. + wxProgressDialog progress_dlg(_L("Fixing by Windows repair algorithm"), "", 100, find_toplevel_parent(plater), + wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT); + int model_idx{ 0 }; + for (int obj_idx : err_objects_idxs) { + if (!fix_and_update_progress(obj_idx, model_idx, progress_dlg, succes_models, failed_models)) + break; + model_idx++; + } + + // Close the progress dialog + progress_dlg.Update(100, ""); + + // Show info dialog + wxString msg = MenuFactory::get_repaire_result_message(succes_models, failed_models); + InfoDialog(plater, _L("Repairing result"), msg).ShowModal(); + } + } } void synchronize_model_after_cut(Model& model, const CutObjectBase& cut_id)