Implemented possibility to fix several objects at once
This commit is contained in:
parent
fe94a3c8c5
commit
03a692cfd1
@ -689,7 +689,7 @@ wxMenuItem* MenuFactory::append_menu_item_fix_through_netfabb(wxMenu* menu)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
wxMenuItem* menu_item = append_menu_item(menu, wxID_ANY, _L("Fix through the Netfabb"), "",
|
wxMenuItem* menu_item = append_menu_item(menu, wxID_ANY, _L("Fix through the Netfabb"), "",
|
||||||
[](wxCommandEvent&) { obj_list()->fix_through_netfabb(); }, "", menu,
|
[](wxCommandEvent&) { obj_list()->fix_through_netfabb(); }, "", menu,
|
||||||
[]() {return plater()->can_fix_through_netfabb(); }, plater());
|
[]() {return plater()->can_fix_through_netfabb(); }, m_parent);
|
||||||
|
|
||||||
return menu_item;
|
return menu_item;
|
||||||
}
|
}
|
||||||
@ -698,7 +698,7 @@ wxMenuItem* MenuFactory::append_menu_item_simplify(wxMenu* menu)
|
|||||||
{
|
{
|
||||||
wxMenuItem* menu_item = append_menu_item(menu, wxID_ANY, _L("Simplify model"), "",
|
wxMenuItem* menu_item = append_menu_item(menu, wxID_ANY, _L("Simplify model"), "",
|
||||||
[](wxCommandEvent&) { obj_list()->simplify(); }, "", menu,
|
[](wxCommandEvent&) { obj_list()->simplify(); }, "", menu,
|
||||||
[]() {return plater()->can_simplify(); }, plater());
|
[]() {return plater()->can_simplify(); }, m_parent);
|
||||||
menu->AppendSeparator();
|
menu->AppendSeparator();
|
||||||
|
|
||||||
return menu_item;
|
return menu_item;
|
||||||
@ -779,7 +779,7 @@ void MenuFactory::append_menu_item_change_extruder(wxMenu* menu)
|
|||||||
}
|
}
|
||||||
|
|
||||||
append_submenu(menu, extruder_selection_menu, wxID_ANY, name, _L("Use another extruder"),
|
append_submenu(menu, extruder_selection_menu, wxID_ANY, name, _L("Use another extruder"),
|
||||||
"edit_uni"/* : "change_extruder"*/, []() {return true; }, GUI::wxGetApp().plater());
|
"edit_uni"/* : "change_extruder"*/, []() {return true; }, m_parent);
|
||||||
|
|
||||||
// menu->AppendSubMenu(extruder_selection_menu, name);
|
// menu->AppendSubMenu(extruder_selection_menu, name);
|
||||||
}
|
}
|
||||||
@ -1061,6 +1061,7 @@ wxMenu* MenuFactory::multi_selection_menu()
|
|||||||
|
|
||||||
wxMenu* menu = new MenuWithSeparators();
|
wxMenu* menu = new MenuWithSeparators();
|
||||||
|
|
||||||
|
append_menu_item_fix_through_netfabb(menu);
|
||||||
append_menu_item_reload_from_disk(menu);
|
append_menu_item_reload_from_disk(menu);
|
||||||
append_menu_items_convert_unit(menu);
|
append_menu_items_convert_unit(menu);
|
||||||
if (obj_list()->can_merge_to_multipart_object())
|
if (obj_list()->can_merge_to_multipart_object())
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "Selection.hpp"
|
#include "Selection.hpp"
|
||||||
#include "format.hpp"
|
#include "format.hpp"
|
||||||
#include "NotificationManager.hpp"
|
#include "NotificationManager.hpp"
|
||||||
|
#include "MsgDialog.hpp"
|
||||||
|
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
#include <wx/progdlg.h>
|
#include <wx/progdlg.h>
|
||||||
@ -369,7 +370,7 @@ void ObjectList::get_selection_indexes(std::vector<int>& obj_idxs, std::vector<i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(obj_idxs.begin(), obj_idxs.end(), std::greater<int>());
|
std::sort(obj_idxs.begin(), obj_idxs.end(), std::less<int>());
|
||||||
obj_idxs.erase(std::unique(obj_idxs.begin(), obj_idxs.end()), obj_idxs.end());
|
obj_idxs.erase(std::unique(obj_idxs.begin(), obj_idxs.end()), obj_idxs.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4013,13 +4014,124 @@ void ObjectList::rename_item()
|
|||||||
|
|
||||||
void ObjectList::fix_through_netfabb()
|
void ObjectList::fix_through_netfabb()
|
||||||
{
|
{
|
||||||
int obj_idx, vol_idx;
|
// Do not fix anything when a gizmo is open. There might be issues with updates
|
||||||
get_selected_item_indexes(obj_idx, vol_idx);
|
// and what is worse, the snapshot time would refer to the internal stack.
|
||||||
|
if (!wxGetApp().plater()->canvas3D()->get_gizmos_manager().check_gizmos_closed_except(GLGizmosManager::Undefined))
|
||||||
|
return;
|
||||||
|
|
||||||
wxGetApp().plater()->fix_through_netfabb(obj_idx, vol_idx);
|
// model_name
|
||||||
|
std::vector<std::string> succes_models;
|
||||||
update_item_error_icon(obj_idx, vol_idx);
|
// model_name failing reason
|
||||||
update_info_items(obj_idx);
|
std::vector<std::pair<std::string, std::string>> failed_models;
|
||||||
|
|
||||||
|
std::vector<int> obj_idxs, vol_idxs;
|
||||||
|
get_selection_indexes(obj_idxs, vol_idxs);
|
||||||
|
|
||||||
|
std::vector<std::string> model_names;
|
||||||
|
|
||||||
|
// clear selections from the non-broken models if any exists
|
||||||
|
// and than fill names of models to repairing
|
||||||
|
if (vol_idxs.empty()) {
|
||||||
|
for (int i = int(obj_idxs.size())-1; i >= 0; --i)
|
||||||
|
if (object(obj_idxs[i])->get_mesh_errors_count() == 0)
|
||||||
|
obj_idxs.erase(obj_idxs.begin()+i);
|
||||||
|
for (int obj_idx : obj_idxs)
|
||||||
|
model_names.push_back(object(obj_idx)->name);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ModelObject* obj = object(obj_idxs.front());
|
||||||
|
for (int i = int(vol_idxs.size()) - 1; i >= 0; --i)
|
||||||
|
if (obj->get_mesh_errors_count(vol_idxs[i]) == 0)
|
||||||
|
vol_idxs.erase(vol_idxs.begin() + i);
|
||||||
|
for (int vol_idx : vol_idxs)
|
||||||
|
model_names.push_back(obj->volumes[vol_idx]->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto plater = wxGetApp().plater();
|
||||||
|
|
||||||
|
auto fix_and_update_progress = [this, plater, model_names](const int obj_idx, const int vol_idx,
|
||||||
|
int model_idx,
|
||||||
|
wxProgressDialog& progress_dlg,
|
||||||
|
std::vector<std::string>& succes_models,
|
||||||
|
std::vector<std::pair<std::string, std::string>>& failed_models)
|
||||||
|
{
|
||||||
|
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 (size_t i = 0; i < model_names.size(); ++i)
|
||||||
|
msg += (i == model_idx ? " > " : " ") + from_u8(model_names[i]) + "\n";
|
||||||
|
msg += "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
plater->clear_before_change_mesh(obj_idx);
|
||||||
|
std::string res;
|
||||||
|
if (!fix_model_by_win10_sdk_gui(*(object(obj_idx)), vol_idx, progress_dlg, msg, res))
|
||||||
|
return false;
|
||||||
|
wxGetApp().plater()->changed_mesh(obj_idx);
|
||||||
|
|
||||||
|
plater->changed_mesh(obj_idx);
|
||||||
|
|
||||||
|
if (res.empty())
|
||||||
|
succes_models.push_back(model_name);
|
||||||
|
else
|
||||||
|
failed_models.push_back({ model_name, res });
|
||||||
|
|
||||||
|
update_item_error_icon(obj_idx, vol_idx);
|
||||||
|
update_info_items(obj_idx);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
Plater::TakeSnapshot snapshot(plater, _L("Fix through NetFabb"));
|
||||||
|
|
||||||
|
// Open a progress dialog.
|
||||||
|
wxProgressDialog progress_dlg(_L("Fixing through NetFabb"), "", 100,
|
||||||
|
nullptr, // ! parent of the wxProgressDialog should be nullptr to avoid flickering during the model fixing
|
||||||
|
wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT);
|
||||||
|
int model_idx{ 0 };
|
||||||
|
if (vol_idxs.empty()) {
|
||||||
|
int vol_idx{ -1 };
|
||||||
|
for (int obj_idx : obj_idxs) {
|
||||||
|
if (object(obj_idx)->get_mesh_errors_count(vol_idx) == 0)
|
||||||
|
continue;
|
||||||
|
if (!fix_and_update_progress(obj_idx, vol_idx, model_idx, progress_dlg, succes_models, failed_models))
|
||||||
|
break;
|
||||||
|
model_idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int obj_idx{ obj_idxs.front() };
|
||||||
|
for (int vol_idx : vol_idxs) {
|
||||||
|
if (!fix_and_update_progress(obj_idx, vol_idx, model_idx, progress_dlg, succes_models, failed_models))
|
||||||
|
break;
|
||||||
|
model_idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Close the progress dialog
|
||||||
|
progress_dlg.Update(100, "");
|
||||||
|
|
||||||
|
// Show info message
|
||||||
|
wxString msg;
|
||||||
|
wxString bullet_suf = "\n - ";
|
||||||
|
if (!succes_models.empty()) {
|
||||||
|
msg = _L_PLURAL("Folowing model is repaired successfully", "Folowing models are 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");
|
||||||
|
// !!! Use wxMessageDialog instead of MessageDialog here
|
||||||
|
// It will not be "dark moded" but the Application will not lose a focus after model repairing
|
||||||
|
wxMessageDialog(nullptr, msg, _L("Model Repair by the Netfabb service"), wxICON_INFORMATION | wxOK).ShowModal();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectList::simplify()
|
void ObjectList::simplify()
|
||||||
|
@ -1722,7 +1722,6 @@ struct Plater::priv
|
|||||||
#endif // ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
|
#endif // ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
|
||||||
void replace_with_stl();
|
void replace_with_stl();
|
||||||
void reload_all_from_disk();
|
void reload_all_from_disk();
|
||||||
void fix_through_netfabb(const int obj_idx, const int vol_idx = -1);
|
|
||||||
void create_simplify_notification(const std::vector<size_t>& obj_ids);
|
void create_simplify_notification(const std::vector<size_t>& obj_ids);
|
||||||
void set_current_panel(wxPanel* panel);
|
void set_current_panel(wxPanel* panel);
|
||||||
|
|
||||||
@ -3664,27 +3663,6 @@ void Plater::priv::reload_all_from_disk()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::priv::fix_through_netfabb(const int obj_idx, const int vol_idx/* = -1*/)
|
|
||||||
{
|
|
||||||
if (obj_idx < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Do not fix anything when a gizmo is open. There might be issues with updates
|
|
||||||
// and what is worse, the snapshot time would refer to the internal stack.
|
|
||||||
if (! q->canvas3D()->get_gizmos_manager().check_gizmos_closed_except(GLGizmosManager::Undefined))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// size_t snapshot_time = undo_redo_stack().active_snapshot_time();
|
|
||||||
Plater::TakeSnapshot snapshot(q, _L("Fix through NetFabb"));
|
|
||||||
|
|
||||||
q->clear_before_change_mesh(obj_idx);
|
|
||||||
ModelObject* mo = model.objects[obj_idx];
|
|
||||||
fix_model_by_win10_sdk_gui(*mo, vol_idx);
|
|
||||||
q->changed_mesh(obj_idx);
|
|
||||||
// workaround to fix the issue, when PrusaSlicer lose a focus after model fixing
|
|
||||||
q->SetFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Plater::priv::create_simplify_notification(const std::vector<size_t>& obj_ids) {
|
void Plater::priv::create_simplify_notification(const std::vector<size_t>& obj_ids) {
|
||||||
const uint32_t triangles_to_suggest_simplify = 1000000;
|
const uint32_t triangles_to_suggest_simplify = 1000000;
|
||||||
|
|
||||||
@ -4168,7 +4146,8 @@ void Plater::priv::on_right_click(RBtnEvent& evt)
|
|||||||
const bool is_some_full_instances = get_selection().is_single_full_instance() ||
|
const bool is_some_full_instances = get_selection().is_single_full_instance() ||
|
||||||
get_selection().is_single_full_object() ||
|
get_selection().is_single_full_object() ||
|
||||||
get_selection().is_multiple_full_instance();
|
get_selection().is_multiple_full_instance();
|
||||||
menu = is_some_full_instances ? menus.object_menu() : menus.part_menu();
|
menu = is_some_full_instances ? menus.object_menu() :
|
||||||
|
get_selection().is_single_volume() ? menus.part_menu() : menus.multi_selection_menu();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4521,11 +4500,22 @@ bool Plater::priv::can_delete_all() const
|
|||||||
|
|
||||||
bool Plater::priv::can_fix_through_netfabb() const
|
bool Plater::priv::can_fix_through_netfabb() const
|
||||||
{
|
{
|
||||||
int obj_idx = get_selected_object_idx();
|
std::vector<int> obj_idxs, vol_idxs;
|
||||||
if (obj_idx < 0)
|
sidebar->obj_list()->get_selection_indexes(obj_idxs, vol_idxs);
|
||||||
return false;
|
|
||||||
|
|
||||||
return model.objects[obj_idx]->get_mesh_errors_count() > 0;
|
if (vol_idxs.empty()) {
|
||||||
|
for (auto obj_idx : obj_idxs)
|
||||||
|
if (model.objects[obj_idx]->get_mesh_errors_count() > 0)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int obj_idx = obj_idxs.front();
|
||||||
|
for (auto vol_idx : vol_idxs)
|
||||||
|
if (model.objects[obj_idx]->get_mesh_errors_count(vol_idx) > 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -6468,7 +6458,6 @@ void Plater::suppress_background_process(const bool stop_background_process)
|
|||||||
this->p->suppressed_backround_processing_update = true;
|
this->p->suppressed_backround_processing_update = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::fix_through_netfabb(const int obj_idx, const int vol_idx/* = -1*/) { p->fix_through_netfabb(obj_idx, vol_idx); }
|
|
||||||
void Plater::mirror(Axis axis) { p->mirror(axis); }
|
void Plater::mirror(Axis axis) { p->mirror(axis); }
|
||||||
void Plater::split_object() { p->split_object(); }
|
void Plater::split_object() { p->split_object(); }
|
||||||
void Plater::split_volume() { p->split_volume(); }
|
void Plater::split_volume() { p->split_volume(); }
|
||||||
|
@ -235,7 +235,6 @@ public:
|
|||||||
void schedule_background_process(bool schedule = true);
|
void schedule_background_process(bool schedule = true);
|
||||||
bool is_background_process_update_scheduled() const;
|
bool is_background_process_update_scheduled() const;
|
||||||
void suppress_background_process(const bool stop_background_process) ;
|
void suppress_background_process(const bool stop_background_process) ;
|
||||||
void fix_through_netfabb(const int obj_idx, const int vol_idx = -1);
|
|
||||||
void send_gcode();
|
void send_gcode();
|
||||||
void eject_drive();
|
void eject_drive();
|
||||||
|
|
||||||
|
@ -318,7 +318,10 @@ public:
|
|||||||
const char* what() const throw() { return "Model repair has been canceled"; }
|
const char* what() const throw() { return "Model repair has been canceled"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
void fix_model_by_win10_sdk_gui(ModelObject &model_object, int volume_idx)
|
// returt FALSE, if fixing was canceled
|
||||||
|
// fix_result is empty, if fixing finished successfully
|
||||||
|
// fix_result containes a message if fixing failed
|
||||||
|
bool fix_model_by_win10_sdk_gui(ModelObject &model_object, int volume_idx, wxProgressDialog& progress_dialog, const wxString& msg_header, std::string& fix_result)
|
||||||
{
|
{
|
||||||
std::mutex mutex;
|
std::mutex mutex;
|
||||||
std::condition_variable condition;
|
std::condition_variable condition;
|
||||||
@ -337,11 +340,6 @@ void fix_model_by_win10_sdk_gui(ModelObject &model_object, int volume_idx)
|
|||||||
else
|
else
|
||||||
volumes.emplace_back(model_object.volumes[volume_idx]);
|
volumes.emplace_back(model_object.volumes[volume_idx]);
|
||||||
|
|
||||||
// Open a progress dialog.
|
|
||||||
wxProgressDialog progress_dialog(
|
|
||||||
_L("Model fixing"),
|
|
||||||
_L("Exporting model") + "...",
|
|
||||||
100, nullptr, wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT); // ! parent of the wxProgressDialog should be nullptr to avoid flickering during the model fixing
|
|
||||||
// Executing the calculation in a background thread, so that the COM context could be created with its own threading model.
|
// Executing the calculation in a background thread, so that the COM context could be created with its own threading model.
|
||||||
// (It seems like wxWidgets initialize the COM contex as single threaded and we need a multi-threaded context).
|
// (It seems like wxWidgets initialize the COM contex as single threaded and we need a multi-threaded context).
|
||||||
bool success = false;
|
bool success = false;
|
||||||
@ -423,21 +421,23 @@ void fix_model_by_win10_sdk_gui(ModelObject &model_object, int volume_idx)
|
|||||||
});
|
});
|
||||||
while (! finished) {
|
while (! finished) {
|
||||||
condition.wait_for(lock, std::chrono::milliseconds(500), [&progress]{ return progress.updated; });
|
condition.wait_for(lock, std::chrono::milliseconds(500), [&progress]{ return progress.updated; });
|
||||||
if (! progress_dialog.Update(progress.percent, _(progress.message)))
|
// decrease progress.percent value to avoid closing of the progress dialog
|
||||||
|
if (!progress_dialog.Update(progress.percent-1, msg_header + _(progress.message)))
|
||||||
canceled = true;
|
canceled = true;
|
||||||
|
else
|
||||||
|
progress_dialog.Fit();
|
||||||
progress.updated = false;
|
progress.updated = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canceled) {
|
if (canceled) {
|
||||||
// Nothing to show.
|
// Nothing to show.
|
||||||
} else if (success) {
|
} else if (success) {
|
||||||
Slic3r::GUI::MessageDialog dlg(nullptr, _L("Model repaired successfully"), _L("Model Repair by the Netfabb service"), wxICON_INFORMATION | wxOK);
|
fix_result = "";
|
||||||
dlg.ShowModal();
|
|
||||||
} else {
|
} else {
|
||||||
Slic3r::GUI::MessageDialog dlg(nullptr, _L("Model repair failed:") + " \n" + _(progress.message), _L("Model Repair by the Netfabb service"), wxICON_ERROR | wxOK);
|
fix_result = progress.message;
|
||||||
dlg.ShowModal();
|
|
||||||
}
|
}
|
||||||
worker_thread.join();
|
worker_thread.join();
|
||||||
|
return !canceled;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
@ -12,12 +12,14 @@ class Print;
|
|||||||
#ifdef HAS_WIN10SDK
|
#ifdef HAS_WIN10SDK
|
||||||
|
|
||||||
extern bool is_windows10();
|
extern bool is_windows10();
|
||||||
extern void fix_model_by_win10_sdk_gui(ModelObject &model_object, int volume_idx);
|
// returt false, if fixing was canceled
|
||||||
|
extern bool fix_model_by_win10_sdk_gui(ModelObject &model_object, int volume_idx, wxProgressDialog& progress_dlg, const wxString& msg_header, std::string& fix_result);
|
||||||
|
|
||||||
#else /* HAS_WIN10SDK */
|
#else /* HAS_WIN10SDK */
|
||||||
|
|
||||||
inline bool is_windows10() { return false; }
|
inline bool is_windows10() { return false; }
|
||||||
inline void fix_model_by_win10_sdk_gui(ModelObject &, int) {}
|
// returt false, if fixing was canceled
|
||||||
|
inline bool fix_model_by_win10_sdk_gui(ModelObject&, int, wxProgressDialog&, const wxString&, std::string&) { return false; }
|
||||||
|
|
||||||
#endif /* HAS_WIN10SDK */
|
#endif /* HAS_WIN10SDK */
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user