diff --git a/src/libslic3r/SLA/Rotfinder.cpp b/src/libslic3r/SLA/Rotfinder.cpp index 79be5e1ec4..eb54b02dc2 100644 --- a/src/libslic3r/SLA/Rotfinder.cpp +++ b/src/libslic3r/SLA/Rotfinder.cpp @@ -92,9 +92,9 @@ Transform3f to_transform3f(const XYRotation &rot) } // namespace -Vec2d find_best_rotation(const SLAPrintObject & po, - float accuracy, - std::function statuscb) +Vec2d find_best_misalignment_rotation(const SLAPrintObject & po, + float accuracy, + std::function statuscb) { static const unsigned MAX_TRIES = 1000; @@ -156,12 +156,4 @@ Vec2d find_best_rotation(const SLAPrintObject & po, return {rot[0], rot[1]}; } -double get_model_supportedness(const SLAPrintObject &po, const Transform3f &tr) -{ - TriangleMesh mesh = po.model_object()->raw_mesh(); - mesh.require_shared_vertices(); - - return get_model_supportedness(mesh, tr); -} - }} // namespace Slic3r::sla diff --git a/src/libslic3r/SLA/Rotfinder.hpp b/src/libslic3r/SLA/Rotfinder.hpp index 2b92c52b8d..56884565fa 100644 --- a/src/libslic3r/SLA/Rotfinder.hpp +++ b/src/libslic3r/SLA/Rotfinder.hpp @@ -9,9 +9,12 @@ namespace Slic3r { class SLAPrintObject; +class TriangleMesh; namespace sla { +using RotOptimizeStatusCB = std::function; + /** * The function should find the best rotation for SLA upside down printing. * @@ -28,14 +31,13 @@ namespace sla { * * @return Returns the rotations around each axis (x, y, z) */ -Vec2d find_best_rotation( +Vec2d find_best_misalignment_rotation( const SLAPrintObject& modelobj, float accuracy = 1.0f, - std::function statuscb = [] (int) { return true; } + RotOptimizeStatusCB statuscb = [] (int) { return true; } ); -double get_model_supportedness(const SLAPrintObject &mesh, - const Transform3f & tr); + } // namespace sla } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index c5060a88ed..b44bc01f03 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -7,9 +7,10 @@ #include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/GUI.hpp" +#include "slic3r/GUI/Plater.hpp" #include "libslic3r/PresetBundle.hpp" -#include "libslic3r/SLA/Rotfinder.hpp" +#include "slic3r/GUI/Jobs/RotoptimizeJob.hpp" namespace Slic3r { namespace GUI { @@ -204,6 +205,23 @@ void GLGizmoRotate3D::on_render_input_window(float x, float y, float bottom_limi { if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA) return; + + RotoptimzeWindow popup{m_imgui, m_rotoptimizewin_state, {x, y, bottom_limit}}; +} + +void GLGizmoRotate3D::load_rotoptimize_state() +{ + std::string accuracy_str = + wxGetApp().app_config->get("rotoptimize", "accuracy"); + + std::string method_str = + wxGetApp().app_config->get("rotoptimize", "method_id"); + + if (!accuracy_str.empty()) + m_rotoptimizewin_state.accuracy = std::stof(accuracy_str); + + if (!method_str.empty()) + m_rotoptimizewin_state.method_id = std::stoi(method_str); } void GLGizmoRotate::render_circle() const @@ -436,6 +454,9 @@ GLGizmoRotate3D::GLGizmoRotate3D(GLCanvas3D& parent, const std::string& icon_fil { m_gizmos[i].set_group_id(i); } + + std::cout << "Load rotopt state" << std::endl; + load_rotoptimize_state(); } bool GLGizmoRotate3D::on_init() @@ -492,5 +513,57 @@ void GLGizmoRotate3D::on_render() const m_gizmos[Z].render(); } +const char * GLGizmoRotate3D::RotoptimzeWindow::options[RotoptimizeJob::get_methods_count()]; +bool GLGizmoRotate3D::RotoptimzeWindow::options_valid = false; + +GLGizmoRotate3D::RotoptimzeWindow::RotoptimzeWindow(ImGuiWrapper * imgui, + State & state, + const Alignment &alignment) + : m_imgui{imgui} +{ + imgui->begin(_L("Optimize orientation"), ImGuiWindowFlags_NoMove | + ImGuiWindowFlags_AlwaysAutoResize | + ImGuiWindowFlags_NoCollapse); + + // adjust window position to avoid overlap the view toolbar + float win_h = ImGui::GetWindowHeight(); + float x = alignment.x, y = alignment.y; + y = std::min(y, alignment.bottom_limit - win_h); + ImGui::SetWindowPos(ImVec2(x, y), ImGuiCond_Always); + + ImGui::PushItemWidth(200.f); + + size_t methods_cnt = RotoptimizeJob::get_methods_count(); + if (!options_valid) { + for (size_t i = 0; i < methods_cnt; ++i) + options[i] = RotoptimizeJob::get_method_names()[i].c_str(); + + options_valid = true; + } + + int citem = state.method_id; + if (ImGui::Combo(_L("Choose method").c_str(), &citem, options, methods_cnt) ) { + state.method_id = citem; + wxGetApp().app_config->set("rotoptimize", "method_id", std::to_string(state.method_id)); + } + + float accuracy = state.accuracy; + if (imgui->slider_float(_L("Accuracy/Speed"), &accuracy, 0.01f, 1.f, "%.1f")) { + state.accuracy = accuracy; + wxGetApp().app_config->set("rotoptimize", "accuracy", std::to_string(state.accuracy)); + } + + ImGui::Separator(); + + if ( imgui->button(_L("Optimize")) ) { + wxGetApp().plater()->optimize_rotation(); + } +} + +GLGizmoRotate3D::RotoptimzeWindow::~RotoptimzeWindow() +{ + m_imgui->end(); +} + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp index 126c97b1dd..c18d0eefd9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp @@ -2,6 +2,7 @@ #define slic3r_GLGizmoRotate_hpp_ #include "GLGizmoBase.hpp" +#include "../Jobs/RotoptimizeJob.hpp" namespace Slic3r { @@ -136,6 +137,39 @@ protected: } void on_render_input_window(float x, float y, float bottom_limit) override; + +private: + + class RotoptimzeWindow { + ImGuiWrapper *m_imgui = nullptr; + + static const char * options []; + static bool options_valid; + + public: + + struct State { + float accuracy = 1.f; + int method_id = 0; + }; + + struct Alignment { float x, y, bottom_limit; }; + + RotoptimzeWindow(ImGuiWrapper * imgui, + State & state, + const Alignment &bottom_limit); + + ~RotoptimzeWindow(); + + RotoptimzeWindow(const RotoptimzeWindow&) = delete; + RotoptimzeWindow(RotoptimzeWindow &&) = delete; + RotoptimzeWindow& operator=(const RotoptimzeWindow &) = delete; + RotoptimzeWindow& operator=(RotoptimzeWindow &&) = delete; + }; + + RotoptimzeWindow::State m_rotoptimizewin_state = {}; + + void load_rotoptimize_state(); }; } // namespace GUI diff --git a/src/slic3r/GUI/Jobs/RotoptimizeJob.cpp b/src/slic3r/GUI/Jobs/RotoptimizeJob.cpp index 7e1bfaeebd..2e83bbf962 100644 --- a/src/slic3r/GUI/Jobs/RotoptimizeJob.cpp +++ b/src/slic3r/GUI/Jobs/RotoptimizeJob.cpp @@ -8,8 +8,29 @@ #include "slic3r/GUI/Plater.hpp" +#include "slic3r/GUI/GUI_App.hpp" +#include "libslic3r/AppConfig.hpp" + namespace Slic3r { namespace GUI { +void RotoptimizeJob::prepare() +{ + std::string accuracy_str = + wxGetApp().app_config->get("rotoptimize", "accuracy"); + + std::string method_str = + wxGetApp().app_config->get("rotoptimize", "method_id"); + + if (!accuracy_str.empty()) + m_accuracy = std::stof(accuracy_str); + + if (!method_str.empty()) + m_method_id = std::stoi(method_str); + + m_accuracy = std::max(0.f, std::min(m_accuracy, 1.f)); + m_method_id = std::max(size_t(0), std::min(get_methods_count() - 1, m_method_id)); +} + void RotoptimizeJob::process() { int obj_idx = m_plater->get_selected_object_idx(); @@ -21,7 +42,7 @@ void RotoptimizeJob::process() if (!o || !po) return; - Vec2d r = sla::find_best_rotation(*po, 0.75f, [this](int s) { + Vec2d r = Methods[m_method_id].findfn(*po, m_accuracy, [this](int s) { if (s > 0 && s < 100) update_status(s, _(L("Searching for optimal orientation"))); diff --git a/src/slic3r/GUI/Jobs/RotoptimizeJob.hpp b/src/slic3r/GUI/Jobs/RotoptimizeJob.hpp index 06688b52d9..3570364404 100644 --- a/src/slic3r/GUI/Jobs/RotoptimizeJob.hpp +++ b/src/slic3r/GUI/Jobs/RotoptimizeJob.hpp @@ -3,17 +3,58 @@ #include "PlaterJob.hpp" -namespace Slic3r { namespace GUI { +#include "libslic3r/SLA/Rotfinder.hpp" + +namespace Slic3r { + +class SLAPrintObject; + +namespace GUI { class RotoptimizeJob : public PlaterJob { + using FindFn = std::function; + + struct FindMethod { std::string name; FindFn findfn; }; + + static inline const FindMethod Methods[] = { + { L("Best misalignment"), sla::find_best_misalignment_rotation }, + { L("Least supports"), sla::find_best_misalignment_rotation } + }; + + size_t m_method_id = 0; + float m_accuracy = 0.75; +protected: + + void prepare() override; + public: + RotoptimizeJob(std::shared_ptr pri, Plater *plater) : PlaterJob{std::move(pri), plater} {} void process() override; void finalize() override; + + static constexpr size_t get_methods_count() { return std::size(Methods); } + static const auto & get_method_names() + { + static bool m_method_names_valid = false; + static std::array m_method_names; + + if (!m_method_names_valid) { + + for (size_t i = 0; i < std::size(Methods); ++i) + m_method_names[i] = _utf8(Methods[i].name); + + m_method_names_valid = true; + } + + return m_method_names; + } }; }} // namespace Slic3r::GUI