From af526c54f4b421fb7dda636b86d2202b635ba80a Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Mon, 19 Jul 2021 09:17:50 +0200 Subject: [PATCH] Add simplification GUI --- src/slic3r/CMakeLists.txt | 4 +- src/slic3r/GUI/GUI_ObjectList.cpp | 10 +- src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp | 231 ++++++++++++++++++ src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp | 76 ++++++ src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 13 +- src/slic3r/GUI/Gizmos/GLGizmosManager.hpp | 1 + src/slic3r/GUI/Plater.cpp | 111 ++++----- src/slic3r/GUI/Plater.hpp | 5 +- src/slic3r/GUI/SimplificationDialog.cpp | 91 ------- src/slic3r/GUI/SimplificationDialog.hpp | 25 -- tests/libslic3r/test_indexed_triangle_set.cpp | 3 +- .../libslic3r/test_mutable_priority_queue.cpp | 101 ++++++++ 12 files changed, 476 insertions(+), 195 deletions(-) create mode 100644 src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp create mode 100644 src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp delete mode 100644 src/slic3r/GUI/SimplificationDialog.cpp delete mode 100644 src/slic3r/GUI/SimplificationDialog.hpp diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 08dd66d9d..d9e849def 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -57,6 +57,8 @@ set(SLIC3R_GUI_SOURCES GUI/Gizmos/GLGizmoPainterBase.hpp GUI/Gizmos/GLGizmoSeam.cpp GUI/Gizmos/GLGizmoSeam.hpp + GUI/Gizmos/GLGizmoSimplify.cpp + GUI/Gizmos/GLGizmoSimplify.hpp GUI/Gizmos/GLGizmoMmuSegmentation.cpp GUI/Gizmos/GLGizmoMmuSegmentation.hpp GUI/GLSelectionRectangle.cpp @@ -97,8 +99,6 @@ set(SLIC3R_GUI_SOURCES GUI/SavePresetDialog.cpp GUI/PhysicalPrinterDialog.hpp GUI/PhysicalPrinterDialog.cpp - GUI/SimplificationDialog.cpp - GUI/SimplificationDialog.hpp GUI/GUI_Factories.cpp GUI/GUI_Factories.hpp GUI/GUI_ObjectList.cpp diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index cea5dbcb9..821955035 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -4,7 +4,6 @@ #include "GUI_Factories.hpp" #include "GUI_ObjectManipulation.hpp" #include "GUI_ObjectLayers.hpp" -#include "SimplificationDialog.hpp" #include "GUI_App.hpp" #include "I18N.hpp" #include "Plater.hpp" @@ -3762,13 +3761,8 @@ void ObjectList::fix_through_netfabb() void ObjectList::simplify() { - int obj_idx, vol_idx; - get_selected_item_indexes(obj_idx, vol_idx); - - SimplificationDialog dlg(this); - dlg.ShowModal(); - - wxGetApp().plater()->simplify(obj_idx, vol_idx); + GLGizmosManager& gizmos_mgr = wxGetApp().plater()->canvas3D()->get_gizmos_manager(); + gizmos_mgr.open_gizmo(GLGizmosManager::EType::Simplify); } void ObjectList::update_item_error_icon(const int obj_idx, const int vol_idx) const diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp new file mode 100644 index 000000000..ce1181347 --- /dev/null +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp @@ -0,0 +1,231 @@ +// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro. +#include "GLGizmoSimplify.hpp" +#include "slic3r/GUI/GLCanvas3D.hpp" +#include "slic3r/GUI/GUI_App.hpp" +#include "slic3r/GUI/Plater.hpp" +#include "slic3r/GUI/GUI_ObjectManipulation.hpp" +#include "libslic3r/AppConfig.hpp" +#include "libslic3r/Model.hpp" +#include "libslic3r/QuadricEdgeCollapse.hpp" + +namespace Slic3r::GUI { + +GLGizmoSimplify::GLGizmoSimplify(GLCanvas3D & parent, + const std::string &icon_filename, + unsigned int sprite_id) + : GLGizmoBase(parent, icon_filename, -1) + , state(State::settings) + , is_valid_result(false) + , progress(0) + , volume(nullptr) + , obj_index(0) + , need_reload(false) +{} + +GLGizmoSimplify::~GLGizmoSimplify() { + state = State::canceling; + if (worker.joinable()) worker.join(); +} + +bool GLGizmoSimplify::on_init() +{ + //m_grabbers.emplace_back(); + //m_shortcut_key = WXK_CONTROL_C; + return true; +} + +std::string GLGizmoSimplify::on_get_name() const +{ + return (_L("Simplify")).ToUTF8().data(); +} + +void GLGizmoSimplify::on_render() const{} +void GLGizmoSimplify::on_render_for_picking() const{} + +void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limit) +{ + const Selection &selection = m_parent.get_selection(); + int object_idx = selection.get_object_idx(); + ModelObject *obj = wxGetApp().plater()->model().objects[object_idx]; + ModelVolume *act_volume = obj->volumes.front(); + + + // Check selection of new volume + // Do not reselect object when processing + if (act_volume != volume && state == State::settings) { + obj_index = object_idx; // to remember correct object + volume = act_volume; + original_its = {}; + const TriangleMesh &tm = volume->mesh(); + c.wanted_percent = 50.; // default value + c.update_percent(tm.its.indices.size()); + is_valid_result = false; + } + + size_t triangle_count = volume->mesh().its.indices.size(); + // already reduced mesh + if (original_its.has_value()) + triangle_count = original_its->indices.size(); + + int flag = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | + ImGuiWindowFlags_NoCollapse; + m_imgui->begin(_L("Simplify mesh ") + volume->name, flag); + std::string description = "Reduce amout of triangle in mesh( " + + volume->name + " has " + + std::to_string(triangle_count) + " triangles)"; + ImGui::Text(description.c_str()); + // First initialization + fix triangle count + if (c.wanted_count > triangle_count) c.update_percent(triangle_count); + if (m_imgui->checkbox(_L("Until triangle count is less than "), c.use_count)) { + if (!c.use_count) c.use_error = true; + is_valid_result = false; + } + + m_imgui->disabled_begin(!c.use_count); + ImGui::SameLine(); + int wanted_count = c.wanted_count; + if (ImGui::SliderInt("triangles", &wanted_count, 0, + triangle_count, "%d")) { + c.wanted_count = static_cast(wanted_count); + c.update_count(triangle_count); + is_valid_result = false; + } + ImGui::SameLine(); + ImGui::SetNextItemWidth(80); + int precision = (c.wanted_percent > 10)? 0: ((c.wanted_percent > 1)? 1:2); + float step = (c.wanted_percent > 10)? 1.f: ((c.wanted_percent > 1)? 0.1f : 0.01f); + if (ImGui::InputFloat("%", &c.wanted_percent, step, 10*step, precision)) { + if (c.wanted_percent < 0.f) c.wanted_percent = 0.f; + if (c.wanted_percent > 100.f) c.wanted_percent = 100.f; + c.update_percent(triangle_count); + is_valid_result = false; + } + m_imgui->disabled_end(); // use_count + + if (m_imgui->checkbox(_L("Until error"), c.use_error)) { + if (!c.use_error) c.use_count = true; + is_valid_result = false; + } + ImGui::SameLine(); + m_imgui->disabled_begin(!c.use_error); + if (ImGui::InputFloat("(maximal quadric error)", &c.max_error, 0.01f, .1f, 2)) { + if (c.max_error < 0.f) c.max_error = 0.f; + is_valid_result = false; + } + m_imgui->disabled_end(); // use_error + + if (state == State::settings) { + if (m_imgui->button(_L("Cancel"))) { + if (original_its.has_value()) { + set_its(*original_its); + state = State::close_on_end; + } else { + close(); + } + } + ImGui::SameLine(); + if (m_imgui->button(_L("Preview"))) { + state = State::simplifying; + // simplify but not aply on mesh + process(); + } + ImGui::SameLine(); + if (m_imgui->button(_L("Aply"))) { + if (!is_valid_result) { + state = State::close_on_end; + process(); + } else { + // use preview and close + close(); + } + } + } else { + m_imgui->disabled_begin(state == State::canceling); + if (m_imgui->button(_L("Cancel"))) state = State::canceling; + m_imgui->disabled_end(); + + ImGui::SameLine(); + // draw progress bar + ImGui::Text("Processing %c \t %d / 100", + "|/-\\"[(int) (ImGui::GetTime() / 0.05f) & 3], progress); + } + m_imgui->end(); + + if (need_reload) { + need_reload = false; + + // Reload visualization of mesh - change VBO, FBO on GPU + m_parent.reload_scene(true); // deactivate gizmo?? + GLGizmosManager &gizmos_mgr = m_parent.get_gizmos_manager(); + gizmos_mgr.open_gizmo(GLGizmosManager::EType::Simplify); + + if (state == State::close_on_end) { + // fix hollowing, sla support points, modifiers, ... + auto plater = wxGetApp().plater(); + plater->changed_mesh(obj_index); // deactivate gizmo?? + // changed_mesh cause close(); + //close(); + } + + // change from simplifying | aply + state = State::settings; + + } +} + +void GLGizmoSimplify::close() { + volume = nullptr; + + // close gizmo == open it again + GLGizmosManager &gizmos_mgr = m_parent.get_gizmos_manager(); + gizmos_mgr.open_gizmo(GLGizmosManager::EType::Simplify); +} + + +void GLGizmoSimplify::process() +{ + class SimplifyCanceledException : public std::exception { + public: + const char* what() const throw() { return L("Model simplification has been canceled"); } + }; + + if (!original_its.has_value()) + original_its = volume->mesh().its; // copy + + auto plater = wxGetApp().plater(); + plater->take_snapshot(_L("Simplify ") + volume->name); + plater->clear_before_change_mesh(obj_index); + progress = 0; + if (worker.joinable()) worker.join(); + worker = std::thread([&]() { + // store original triangles + uint32_t triangle_count = (c.use_count)? c.wanted_count : 0; + float* max_error = (c.use_error)? &c.max_error : nullptr; + std::function throw_on_cancel = [&]() { if ( state == State::canceling) throw SimplifyCanceledException(); }; + std::function statusfn = [&](int percent) { progress = percent; }; + indexed_triangle_set collapsed = original_its.value(); // copy + try { + its_quadric_edge_collapse(collapsed, triangle_count, max_error, throw_on_cancel, statusfn); + set_its(collapsed); + is_valid_result = true; + } catch (SimplifyCanceledException &) { + is_valid_result = false; + } + }); +} + +void GLGizmoSimplify::set_its(indexed_triangle_set &its) { + auto tm = std::make_unique(its); + tm->repair(); + volume->set_mesh(std::move(tm)); + volume->set_new_unique_id(); + volume->get_object()->invalidate_bounding_box(); + need_reload = true; +} + +bool GLGizmoSimplify::on_is_activable() const +{ + return !m_parent.get_selection().is_empty(); +} + +} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp new file mode 100644 index 000000000..299d559c7 --- /dev/null +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp @@ -0,0 +1,76 @@ +#ifndef slic3r_GLGizmoSimplify_hpp_ +#define slic3r_GLGizmoSimplify_hpp_ + +#include "GLGizmoBase.hpp" +#include "libslic3r/Model.hpp" +#include +#include + +namespace Slic3r { +namespace GUI { + +class GLGizmoSimplify : public GLGizmoBase +{ + enum class State { + settings, + simplifying, // start processing + canceling, // canceled + successfull, // successful simplified + close_on_end + } state; + + bool is_valid_result; // differ what to do in apply + + int progress; + + ModelVolume *volume; + size_t obj_index; + std::optional original_its; + + bool need_reload; // after simplify, glReload must be on main thread + std::thread worker; +public: + GLGizmoSimplify(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); + virtual ~GLGizmoSimplify(); + void set_selectable(bool value); +protected: + virtual bool on_init() override; + virtual std::string on_get_name() const override; + virtual void on_render() const override; + virtual void on_render_for_picking() const override; + virtual void on_render_input_window(float x, float y, float bottom_limit) override; + virtual bool on_is_activable() const override; + virtual bool on_is_selectable() const override { return false; }; + +private: + void close(); + void process(); + void set_its(indexed_triangle_set &its); + struct Configuration + { + bool use_count = true; + // minimal triangle count + float wanted_percent = 50.f; + uint32_t wanted_count = 0; // initialize by percents + + bool use_error = false; + // maximal quadric error + float max_error = 1.; + + void update_count(size_t triangle_count) + { + wanted_percent = (float) wanted_count / triangle_count * 100.f; + } + void update_percent(size_t triangle_count) + { + wanted_count = static_cast( + std::round(triangle_count * wanted_percent / 100.f)); + } + }; + Configuration c; +}; + +} // namespace GUI +} // namespace Slic3r + +#endif // slic3r_GLGizmoSimplify_hpp_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index ace6c0785..577720218 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -20,6 +20,7 @@ #include "slic3r/GUI/Gizmos/GLGizmoHollow.hpp" #include "slic3r/GUI/Gizmos/GLGizmoSeam.hpp" #include "slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp" +#include "slic3r/GUI/Gizmos/GLGizmoSimplify.hpp" #include "libslic3r/Model.hpp" #include "libslic3r/PresetBundle.hpp" @@ -110,6 +111,7 @@ bool GLGizmosManager::init() m_gizmos.emplace_back(new GLGizmoFdmSupports(m_parent, "fdm_supports.svg", 7)); m_gizmos.emplace_back(new GLGizmoSeam(m_parent, "seam.svg", 8)); m_gizmos.emplace_back(new GLGizmoMmuSegmentation(m_parent, "fdm_supports.svg", 9)); + m_gizmos.emplace_back(new GLGizmoSimplify(m_parent, "cut.svg", 10)); m_common_gizmos_data.reset(new CommonGizmosDataPool(&m_parent)); @@ -169,7 +171,7 @@ void GLGizmosManager::reset_all_states() bool GLGizmosManager::open_gizmo(EType type) { int idx = int(type); - if (m_gizmos[idx]->is_selectable() && m_gizmos[idx]->is_activable()) { + if (/*m_gizmos[idx]->is_selectable() &&*/ m_gizmos[idx]->is_activable()) { activate_gizmo(m_current == idx ? Undefined : (EType)idx); update_data(); return true; @@ -1021,6 +1023,8 @@ void GLGizmosManager::do_render_overlay() const float u_offset = 1.0f / (float)tex_width; float v_offset = 1.0f / (float)tex_height; + float toolbar_top = 0.f; + float current_y = 0.f; for (size_t idx : selectable_idxs) { GLGizmoBase* gizmo = m_gizmos[idx].get(); @@ -1035,11 +1039,14 @@ void GLGizmosManager::do_render_overlay() const GLTexture::render_sub_texture(icons_texture_id, zoomed_top_x, zoomed_top_x + zoomed_icons_size, zoomed_top_y - zoomed_icons_size, zoomed_top_y, { { u_left, v_bottom }, { u_right, v_bottom }, { u_right, v_top }, { u_left, v_top } }); if (idx == m_current) { - float toolbar_top = cnv_h - wxGetApp().plater()->get_view_toolbar().get_height(); - gizmo->render_input_window(width, 0.5f * cnv_h - zoomed_top_y * zoom, toolbar_top); + toolbar_top = cnv_h - wxGetApp().plater()->get_view_toolbar().get_height(); + current_y = 0.5f * cnv_h - zoomed_top_y * zoom; } zoomed_top_y -= zoomed_stride_y; } + + if (m_current != Undefined) + m_gizmos[m_current]->render_input_window(width, current_y, toolbar_top); } float GLGizmosManager::get_scaled_total_height() const diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp index 01d7ea85c..383d7099f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp @@ -69,6 +69,7 @@ public: FdmSupports, Seam, MmuSegmentation, + Simplify, Undefined }; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 756e74bae..f2ef0b01b 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1730,7 +1730,6 @@ struct Plater::priv void replace_with_stl(); void reload_all_from_disk(); void fix_through_netfabb(const int obj_idx, const int vol_idx = -1); - void simplify(const int obj_idx, const int vol_idx = -1); void set_current_panel(wxPanel* panel); @@ -3555,70 +3554,10 @@ void Plater::priv::fix_through_netfabb(const int obj_idx, const int vol_idx/* = // 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]; - - // If there are custom supports/seams/mmu segmentation, remove them. Fixed mesh - // may be different and they would make no sense. - bool paint_removed = false; - for (ModelVolume* mv : mo->volumes) { - paint_removed |= ! mv->supported_facets.empty() || ! mv->seam_facets.empty() || ! mv->mmu_segmentation_facets.empty(); - mv->supported_facets.clear(); - mv->seam_facets.clear(); - mv->mmu_segmentation_facets.clear(); - } - if (paint_removed) { - // snapshot_time is captured by copy so the lambda knows where to undo/redo to. - notification_manager->push_notification( - NotificationType::CustomSupportsAndSeamRemovedAfterRepair, - NotificationManager::NotificationLevel::RegularNotification, - _u8L("Custom supports and seams were removed after repairing the mesh.")); -// _u8L("Undo the repair"), -// [this, snapshot_time](wxEvtHandler*){ -// // Make sure the snapshot is still available and that -// // we are in the main stack and not in a gizmo-stack. -// if (undo_redo_stack().has_undo_snapshot(snapshot_time) -// && q->canvas3D()->get_gizmos_manager().get_current() == nullptr) -// undo_redo_to(snapshot_time); -// else -// notification_manager->push_notification( -// NotificationType::CustomSupportsAndSeamRemovedAfterRepair, -// NotificationManager::NotificationLevel::RegularNotification, -// _u8L("Cannot undo to before the mesh repair!")); -// return true; -// }); - } - fix_model_by_win10_sdk_gui(*mo, vol_idx); - sla::reproject_points_and_holes(mo); - this->update(); - this->object_list_changed(); - this->schedule_background_process(); -} - -void Plater::priv::simplify(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().get_current_type() != GLGizmosManager::Undefined) { - notification_manager->push_notification( - NotificationType::CustomSupportsAndSeamRemovedAfterRepair, - NotificationManager::NotificationLevel::RegularNotification, - _u8L("ERROR: Please close all manipulators available from " - "the left toolbar before fixing the mesh.")); - return; - } - - // size_t snapshot_time = undo_redo_stack().active_snapshot_time(); - Plater::TakeSnapshot snapshot(q, _L("Symplify model")); - - // ToDo - - this->update(); - this->object_list_changed(); - this->schedule_background_process(); + q->changed_mesh(obj_idx); } void Plater::priv::set_current_panel(wxPanel* panel) @@ -6262,6 +6201,51 @@ bool Plater::set_printer_technology(PrinterTechnology printer_technology) return ret; } +void Plater::clear_before_change_mesh(int obj_idx) +{ + ModelObject* mo = model().objects[obj_idx]; + + // If there are custom supports/seams/mmu segmentation, remove them. Fixed mesh + // may be different and they would make no sense. + bool paint_removed = false; + for (ModelVolume* mv : mo->volumes) { + paint_removed |= ! mv->supported_facets.empty() || ! mv->seam_facets.empty() || ! mv->mmu_segmentation_facets.empty(); + mv->supported_facets.clear(); + mv->seam_facets.clear(); + mv->mmu_segmentation_facets.clear(); + } + if (paint_removed) { + // snapshot_time is captured by copy so the lambda knows where to undo/redo to. + get_notification_manager()->push_notification( + NotificationType::CustomSupportsAndSeamRemovedAfterRepair, + NotificationManager::NotificationLevel::RegularNotification, + _u8L("Custom supports and seams were removed after repairing the mesh.")); +// _u8L("Undo the repair"), +// [this, snapshot_time](wxEvtHandler*){ +// // Make sure the snapshot is still available and that +// // we are in the main stack and not in a gizmo-stack. +// if (undo_redo_stack().has_undo_snapshot(snapshot_time) +// && q->canvas3D()->get_gizmos_manager().get_current() == nullptr) +// undo_redo_to(snapshot_time); +// else +// notification_manager->push_notification( +// NotificationType::CustomSupportsAndSeamRemovedAfterRepair, +// NotificationManager::NotificationLevel::RegularNotification, +// _u8L("Cannot undo to before the mesh repair!")); +// return true; +// }); + } +} + +void Plater::changed_mesh(int obj_idx) +{ + ModelObject* mo = model().objects[obj_idx]; + sla::reproject_points_and_holes(mo); + update(); + p->object_list_changed(); + p->schedule_background_process(); +} + void Plater::changed_object(int obj_idx) { if (obj_idx < 0) @@ -6343,7 +6327,6 @@ void Plater::suppress_background_process(const bool stop_background_process) } void Plater::fix_through_netfabb(const int obj_idx, const int vol_idx/* = -1*/) { p->fix_through_netfabb(obj_idx, vol_idx); } -void Plater::simplify(const int obj_idx, const int vol_idx/* = -1*/) { p->simplify(obj_idx, vol_idx); } void Plater::mirror(Axis axis) { p->mirror(axis); } void Plater::split_object() { p->split_object(); } void Plater::split_volume() { p->split_volume(); } diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index d58e6b9b1..61a2da93d 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -230,13 +230,16 @@ public: void reslice_SLA_supports(const ModelObject &object, bool postpone_error_messages = false); void reslice_SLA_hollowing(const ModelObject &object, bool postpone_error_messages = false); void reslice_SLA_until_step(SLAPrintObjectStep step, const ModelObject &object, bool postpone_error_messages = false); + + void clear_before_change_mesh(int obj_idx); + void changed_mesh(int obj_idx); + void changed_object(int obj_idx); void changed_objects(const std::vector& object_idxs); void schedule_background_process(bool schedule = true); bool is_background_process_update_scheduled() const; void suppress_background_process(const bool stop_background_process) ; void fix_through_netfabb(const int obj_idx, const int vol_idx = -1); - void simplify(const int obj_idx, const int vol_idx = -1); void send_gcode(); void eject_drive(); diff --git a/src/slic3r/GUI/SimplificationDialog.cpp b/src/slic3r/GUI/SimplificationDialog.cpp deleted file mode 100644 index 780fc2407..000000000 --- a/src/slic3r/GUI/SimplificationDialog.cpp +++ /dev/null @@ -1,91 +0,0 @@ -#include "SimplificationDialog.hpp" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "GUI.hpp" -#include "GUI_App.hpp" -#include "format.hpp" -#include "wxExtensions.hpp" -#include "I18N.hpp" -#include "libslic3r/Utils.hpp" - - -namespace Slic3r { -namespace GUI { - -#define BORDER_W 10 - -SimplificationDialog::SimplificationDialog(wxWindow* parent) : - DPIDialog(parent, wxID_ANY, _L("Name of Dialog"), wxDefaultPosition, wxSize(45 * wxGetApp().em_unit(), -1), wxDEFAULT_DIALOG_STYLE/* | wxRESIZE_BORDER*/) -{ - SetFont(wxGetApp().normal_font()); - - wxStaticText* label_top = new wxStaticText(this, wxID_ANY, _L("Some text") + ":"); - - wxFlexGridSizer* grid_sizer = new wxFlexGridSizer(3, 2, 1, 2); - grid_sizer->AddGrowableCol(1, 1); - grid_sizer->SetFlexibleDirection(wxBOTH); - - for (int i = 0; i < 3; i++) { - auto* text = new wxStaticText(this, wxID_ANY, _L("Text") + " " + std::to_string(i) + " :"); - -#ifdef _WIN32 - long style = wxBORDER_SIMPLE; -#else - long style = 0 -#endif - auto value = new wxTextCtrl(this, wxID_ANY, "Some Value", wxDefaultPosition, wxDefaultSize, style); - - grid_sizer->Add(text, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxRIGHT, 4); - grid_sizer->Add(value, 1, wxEXPAND | wxBOTTOM, 1); - } - - wxStdDialogButtonSizer* btns = this->CreateStdDialogButtonSizer(wxOK | wxCANCEL); - this->Bind(wxEVT_BUTTON, &SimplificationDialog::OnOK, this, wxID_OK); - - wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL); - - topSizer->Add(label_top , 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, BORDER_W); - topSizer->Add(grid_sizer, 1, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, BORDER_W); - topSizer->Add(btns , 0, wxEXPAND | wxALL, BORDER_W); - - SetSizer(topSizer); - topSizer->SetSizeHints(this); - - wxGetApp().UpdateDlgDarkUI(this); - - this->CenterOnScreen(); -} - -SimplificationDialog::~SimplificationDialog() -{ -} - -void SimplificationDialog::on_dpi_changed(const wxRect& suggested_rect) -{ - const int& em = em_unit(); - msw_buttons_rescale(this, em, { wxID_OK, wxID_CANCEL }); - - const wxSize& size = wxSize(45 * em, 35 * em); - SetMinSize(size); - - Fit(); - Refresh(); -} - -void SimplificationDialog::OnOK(wxEvent& event) -{ - event.Skip(); -} - -}} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/SimplificationDialog.hpp b/src/slic3r/GUI/SimplificationDialog.hpp deleted file mode 100644 index 4c0210ee8..000000000 --- a/src/slic3r/GUI/SimplificationDialog.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef slic3r_SimplificationDialog_hpp_ -#define slic3r_SimplificationDialog_hpp_ - -#include "GUI_Utils.hpp" - -namespace Slic3r { -namespace GUI { - -class SimplificationDialog : public DPIDialog -{ - void OnOK(wxEvent& event); - -public: - SimplificationDialog(wxWindow* parent); - ~SimplificationDialog(); - -protected: - void on_dpi_changed(const wxRect& suggested_rect) override; -}; - - -} // namespace GUI -} // namespace Slic3r - -#endif //slic3r_SimplificationDialog_hpp_ diff --git a/tests/libslic3r/test_indexed_triangle_set.cpp b/tests/libslic3r/test_indexed_triangle_set.cpp index e079cb302..06ca3635e 100644 --- a/tests/libslic3r/test_indexed_triangle_set.cpp +++ b/tests/libslic3r/test_indexed_triangle_set.cpp @@ -231,9 +231,10 @@ TEST_CASE("Reduce one edge by Quadric Edge Collapse", "[its]") } #include "test_utils.hpp" -TEST_CASE("Symplify mesh by Quadric edge collapse to 5%", "[its]") +TEST_CASE("Simplify mesh by Quadric edge collapse to 5%", "[its]") { TriangleMesh mesh = load_model("frog_legs.obj"); + //TriangleMesh mesh; load_obj("C:/Users/filip/Documents/models/scarecrow_torso.obj", &mesh); double original_volume = its_volume(mesh.its); uint32_t wanted_count = mesh.its.indices.size() * 0.05; REQUIRE_FALSE(mesh.empty()); diff --git a/tests/libslic3r/test_mutable_priority_queue.cpp b/tests/libslic3r/test_mutable_priority_queue.cpp index 37b244432..ece655365 100644 --- a/tests/libslic3r/test_mutable_priority_queue.cpp +++ b/tests/libslic3r/test_mutable_priority_queue.cpp @@ -339,3 +339,104 @@ TEST_CASE("Mutable priority queue - reshedule first", "[MutableSkipHeapPriorityQ } } } + +TEST_CASE("Mutable priority queue - first pop", "[MutableSkipHeapPriorityQueue]") +{ + struct MyValue{ + int id; + float val; + }; + size_t count = 50000; + std::vector idxs(count, {0}); + std::vector dels(count, false); + auto q = make_miniheap_mutable_priority_queue( + [&](MyValue &v, size_t idx) { + idxs[v.id] = idx; + }, + [](MyValue &l, MyValue &r) { return l.val < r.val; }); + q.reserve(count); + for (size_t id = 0; id < count; id++) { + MyValue mv; + mv.id = id; + mv.val = rand(); + q.push(mv); + } + MyValue it = q.top(); // copy + q.pop(); + bool valid = (it.id != 0) && (idxs[0] < 3 * count); + CHECK(valid); +} + +TEST_CASE("Mutable priority queue complex", "[MutableSkipHeapPriorityQueue]") +{ + struct MyValue { + int id; + float val; + }; + size_t count = 5000; + std::vector idxs(count, {0}); + std::vector dels(count, false); + auto q = make_miniheap_mutable_priority_queue( + [&](MyValue &v, size_t idx) { idxs[v.id] = idx; }, + [](MyValue &l, MyValue &r) { return l.val < r.val; }); + q.reserve(count); + + auto rand_val = [&]()->float { return (rand() % 53) / 10.f; }; + int ord = 0; + for (size_t id = 0; id < count; id++) { + MyValue mv; + mv.id = ord++; + mv.val = rand_val(); + q.push(mv); + } + auto check = [&]()->bool{ + for (size_t i = 0; i < idxs.size(); ++i) { + if (dels[i]) continue; + size_t qid = idxs[i]; + if (qid > 3*count) { + return false; + } + MyValue &mv = q[qid]; + if (mv.id != i) { + return false; // ERROR + } + } + return true; + }; + + CHECK(check()); // initial check + + auto get_valid_id = [&]()->int { + int id = 0; + do { + id = rand() % count; + } while (dels[id]); + return id; + }; + for (size_t i = 0; i < 100; i++) { + MyValue it = q.top(); // copy + q.pop(); + dels[it.id] = true; + CHECK(check()); + if (i % 20 == 0) { + it.val = rand_val(); + q.push(it); + dels[it.id] = false; + CHECK(check()); + continue; + } + + int id = get_valid_id(); + q.remove(idxs[id]); + dels[id] = true; + CHECK(check()); + for (size_t j = 0; j < 5; j++) { + int id = get_valid_id(); + size_t qid = idxs[id]; + MyValue &mv = q[qid]; + mv.val = rand_val(); + q.update(qid); + CHECK(check()); + } + } +}