From 7afe7326b6787b4e8114f69e7f779c5e8bb4d885 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 20 Sep 2019 12:42:08 +0200 Subject: [PATCH 01/28] WIP: Duplicated the SLA gizmo for the FDM, removed what was not needed Clipping plane and the m_model_object pointer keeping was duplicated --- src/slic3r/CMakeLists.txt | 2 + src/slic3r/GUI/GLCanvas3D.cpp | 17 +- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 422 +++++++++++++++++++ src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp | 87 ++++ src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp | 3 - src/slic3r/GUI/Gizmos/GLGizmos.hpp | 1 + src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 23 +- src/slic3r/GUI/Gizmos/GLGizmosManager.hpp | 6 +- 8 files changed, 548 insertions(+), 13 deletions(-) create mode 100644 src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp create mode 100644 src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index c8589903e..3744a8ac4 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -43,6 +43,8 @@ set(SLIC3R_GUI_SOURCES GUI/Gizmos/GLGizmoScale.hpp GUI/Gizmos/GLGizmoSlaSupports.cpp GUI/Gizmos/GLGizmoSlaSupports.hpp + GUI/Gizmos/GLGizmoFdmSupports.cpp + GUI/Gizmos/GLGizmoFdmSupports.hpp GUI/Gizmos/GLGizmoFlatten.cpp GUI/Gizmos/GLGizmoFlatten.hpp GUI/Gizmos/GLGizmoCut.cpp diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index d3b83057e..718aec736 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1596,10 +1596,15 @@ void GLCanvas3D::toggle_sla_auxiliaries_visibility(bool visible, const ModelObje void GLCanvas3D::toggle_model_objects_visibility(bool visible, const ModelObject* mo, int instance_idx) { for (GLVolume* vol : m_volumes.volumes) { - if ((mo == nullptr || m_model->objects[vol->composite_id.object_id] == mo) - && (instance_idx == -1 || vol->composite_id.instance_id == instance_idx)) { - vol->is_active = visible; - vol->force_native_color = (instance_idx != -1); + if (vol->composite_id.object_id == 1000) { // wipe tower + vol->is_active = (visible && mo == nullptr); + } + else { + if ((mo == nullptr || m_model->objects[vol->composite_id.object_id] == mo) + && (instance_idx == -1 || vol->composite_id.instance_id == instance_idx)) { + vol->is_active = visible; + vol->force_native_color = (instance_idx != -1); + } } } if (visible && !mo) @@ -4794,7 +4799,7 @@ void GLCanvas3D::_picking_pass() const glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); - m_camera_clipping_plane = m_gizmos.get_sla_clipping_plane(); + m_camera_clipping_plane = m_gizmos.get_clipping_plane(); if (m_camera_clipping_plane.is_active()) { ::glClipPlane(GL_CLIP_PLANE0, (GLdouble*)m_camera_clipping_plane.get_data()); ::glEnable(GL_CLIP_PLANE0); @@ -4962,7 +4967,7 @@ void GLCanvas3D::_render_objects() const #endif // !ENABLE_THUMBNAIL_GENERATOR glsafe(::glEnable(GL_DEPTH_TEST)); - m_camera_clipping_plane = m_gizmos.get_sla_clipping_plane(); + m_camera_clipping_plane = m_gizmos.get_clipping_plane(); if (m_picking_enabled) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp new file mode 100644 index 000000000..dfe4bc9a5 --- /dev/null +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -0,0 +1,422 @@ +// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro. +#include "GLGizmoFdmSupports.hpp" +#include "slic3r/GUI/GLCanvas3D.hpp" +#include "slic3r/GUI/Gizmos/GLGizmos.hpp" + +#include + +#include "slic3r/GUI/GUI_App.hpp" +#include "slic3r/GUI/MeshUtils.hpp" +#include "slic3r/GUI/PresetBundle.hpp" + + + +namespace Slic3r { +namespace GUI { + +GLGizmoFdmSupports::GLGizmoFdmSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) + : GLGizmoBase(parent, icon_filename, sprite_id) + , m_quadric(nullptr) + , m_its(nullptr) +{ + m_clipping_plane.reset(new ClippingPlane(Vec3d::Zero(), 0.)); + m_quadric = ::gluNewQuadric(); + if (m_quadric != nullptr) + // using GLU_FILL does not work when the instance's transformation + // contains mirroring (normals are reverted) + ::gluQuadricDrawStyle(m_quadric, GLU_FILL); +} + +GLGizmoFdmSupports::~GLGizmoFdmSupports() +{ + if (m_quadric != nullptr) + ::gluDeleteQuadric(m_quadric); +} + +bool GLGizmoFdmSupports::on_init() +{ + m_shortcut_key = WXK_CONTROL_L; + + m_desc["head_diameter"] = _(L("Head diameter")) + ": "; + m_desc["lock_supports"] = _(L("Lock supports under new islands")); + m_desc["remove_selected"] = _(L("Remove selected points")); + m_desc["remove_all"] = _(L("Remove all points")); + m_desc["apply_changes"] = _(L("Apply changes")); + m_desc["discard_changes"] = _(L("Discard changes")); + m_desc["minimal_distance"] = _(L("Minimal points distance")) + ": "; + m_desc["points_density"] = _(L("Support points density")) + ": "; + m_desc["auto_generate"] = _(L("Auto-generate points")); + m_desc["manual_editing"] = _(L("Manual editing")); + m_desc["clipping_of_view"] = _(L("Clipping of view"))+ ": "; + m_desc["reset_direction"] = _(L("Reset direction")); + + return true; +} + +void GLGizmoFdmSupports::set_fdm_support_data(ModelObject* model_object, const Selection& selection) +{ + if (! model_object || selection.is_empty()) { + m_model_object = nullptr; + return; + } + + if (m_model_object != model_object || m_model_object_id != model_object->id()) + m_model_object = model_object; + + m_active_instance = selection.get_instance_idx(); + + if (model_object && selection.is_from_single_instance()) + { + // Cache the bb - it's needed for dealing with the clipping plane quite often + // It could be done inside update_mesh but one has to account for scaling of the instance. + //FIXME calling ModelObject::instance_bounding_box() is expensive! + m_active_instance_bb_radius = m_model_object->instance_bounding_box(m_active_instance).radius(); + + if (is_mesh_update_necessary()) + update_mesh(); + + if (m_state == On) { + m_parent.toggle_model_objects_visibility(false); + m_parent.toggle_model_objects_visibility(true, m_model_object, m_active_instance); + } + else + m_parent.toggle_model_objects_visibility(true, nullptr, -1); + } +} + + + +void GLGizmoFdmSupports::on_render() const +{ + const Selection& selection = m_parent.get_selection(); + + // If current m_model_object does not match selection, ask GLCanvas3D to turn us off + if (m_state == On + && (m_model_object != selection.get_model()->objects[selection.get_object_idx()] + || m_active_instance != selection.get_instance_idx() + || m_model_object_id != m_model_object->id())) { + m_parent.post_event(SimpleEvent(EVT_GLCANVAS_RESETGIZMOS)); + return; + } + + if (! m_its || ! m_mesh) + const_cast(this)->update_mesh(); + + glsafe(::glEnable(GL_BLEND)); + glsafe(::glEnable(GL_DEPTH_TEST)); + + + render_clipping_plane(selection); + + glsafe(::glDisable(GL_BLEND)); +} + + + +void GLGizmoFdmSupports::render_clipping_plane(const Selection& selection) const +{ + if (m_clipping_plane_distance == 0.f) + return; + + // Get transformation of the instance + const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin()); + Geometry::Transformation trafo = vol->get_instance_transformation(); + + + // Now initialize the TMS for the object, perform the cut and save the result. + if (! m_object_clipper) { + m_object_clipper.reset(new MeshClipper); + m_object_clipper->set_mesh(*m_mesh); + } + m_object_clipper->set_plane(*m_clipping_plane); + m_object_clipper->set_transformation(trafo); + + // At this point we have the triangulated cuts for both the object and supports - let's render. + if (! m_object_clipper->get_triangles().empty()) { + ::glPushMatrix(); + ::glColor3f(1.0f, 0.37f, 0.0f); + ::glBegin(GL_TRIANGLES); + for (const Vec3f& point : m_object_clipper->get_triangles()) + ::glVertex3f(point(0), point(1), point(2)); + ::glEnd(); + ::glPopMatrix(); + } +} + + +void GLGizmoFdmSupports::on_render_for_picking() const +{ + +} + + + + +bool GLGizmoFdmSupports::is_point_clipped(const Vec3d& point) const +{ + if (m_clipping_plane_distance == 0.f) + return false; + + Vec3d transformed_point = m_model_object->instances.front()->get_transformation().get_matrix() * point; + return m_clipping_plane->distance(transformed_point) < 0.; +} + + + +bool GLGizmoFdmSupports::is_mesh_update_necessary() const +{ + return ((m_state == On) && (m_model_object != nullptr) && !m_model_object->instances.empty()) + && ((m_model_object->id() != m_model_object_id) || m_its == nullptr); +} + + + +void GLGizmoFdmSupports::update_mesh() +{ + if (! m_model_object) + return; + + wxBusyCursor wait; + // this way we can use that mesh directly. + // This mesh does not account for the possible Z up SLA offset. + m_mesh = &m_model_object->volumes.front()->mesh(); + m_its = &m_mesh->its; + + // If this is different mesh than last time or if the AABB tree is uninitialized, recalculate it. + if (m_model_object_id != m_model_object->id() || ! m_mesh_raycaster) + m_mesh_raycaster.reset(new MeshRaycaster(*m_mesh)); + + m_model_object_id = m_model_object->id(); +} + + + +// Unprojects the mouse position on the mesh and saves hit point and normal of the facet into pos_and_normal +// Return false if no intersection was found, true otherwise. +bool GLGizmoFdmSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair& pos_and_normal) +{ + // if the gizmo doesn't have the V, F structures for igl, calculate them first: + if (! m_mesh_raycaster) + update_mesh(); + + const Camera& camera = m_parent.get_camera(); + const Selection& selection = m_parent.get_selection(); + const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); + Geometry::Transformation trafo = volume->get_instance_transformation(); + trafo.set_offset(trafo.get_offset()); + + // The raycaster query + Vec3f hit; + Vec3f normal; + if (m_mesh_raycaster->unproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, hit, normal, m_clipping_plane.get())) { + // Return both the point and the facet normal. + pos_and_normal = std::make_pair(hit, normal); + return true; + } + else + return false; +} + +// Following function is called from GLCanvas3D to inform the gizmo about a mouse/keyboard event. +// The gizmo has an opportunity to react - if it does, it should return true so that the Canvas3D is +// aware that the event was reacted to and stops trying to make different sense of it. If the gizmo +// concludes that the event was not intended for it, it should return false. +bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down) +{ + if (action == SLAGizmoEventType::MouseWheelUp && control_down) { + m_clipping_plane_distance = std::min(1.f, m_clipping_plane_distance + 0.01f); + update_clipping_plane(true); + return true; + } + + if (action == SLAGizmoEventType::MouseWheelDown && control_down) { + m_clipping_plane_distance = std::max(0.f, m_clipping_plane_distance - 0.01f); + update_clipping_plane(true); + return true; + } + + if (action == SLAGizmoEventType::ResetClippingPlane) { + update_clipping_plane(); + return true; + } + + return false; +} + + + + +ClippingPlane GLGizmoFdmSupports::get_fdm_clipping_plane() const +{ + if (!m_model_object || m_state == Off || m_clipping_plane_distance == 0.f) + return ClippingPlane::ClipsNothing(); + else + return ClippingPlane(-m_clipping_plane->get_normal(), m_clipping_plane->get_data()[3]); +} + + + +void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_limit) +{ + if (!m_model_object) + return; + + const float approx_height = m_imgui->scaled(18.0f); + y = std::min(y, bottom_limit - approx_height); + m_imgui->set_next_window_pos(x, y, ImGuiCond_Always); + m_imgui->set_next_window_bg_alpha(0.5f); + m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse); + + // First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that: + + const float settings_sliders_left = std::max(m_imgui->calc_text_size(m_desc.at("minimal_distance")).x, m_imgui->calc_text_size(m_desc.at("points_density")).x) + m_imgui->scaled(1.f); + const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x, m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + m_imgui->scaled(1.5f); + const float diameter_slider_left = m_imgui->calc_text_size(m_desc.at("head_diameter")).x + m_imgui->scaled(1.f); + const float minimal_slider_width = m_imgui->scaled(4.f); + const float buttons_width_approx = m_imgui->calc_text_size(m_desc.at("apply_changes")).x + m_imgui->calc_text_size(m_desc.at("discard_changes")).x + m_imgui->scaled(1.5f); + const float lock_supports_width_approx = m_imgui->calc_text_size(m_desc.at("lock_supports")).x + m_imgui->scaled(2.f); + + float window_width = minimal_slider_width + std::max(std::max(settings_sliders_left, clipping_slider_left), diameter_slider_left); + window_width = std::max(std::max(window_width, buttons_width_approx), lock_supports_width_approx); + + + // Following is rendered in both editing and non-editing mode: + m_imgui->text(""); + if (m_clipping_plane_distance == 0.f) + m_imgui->text(m_desc.at("clipping_of_view")); + else { + if (m_imgui->button(m_desc.at("reset_direction"))) { + wxGetApp().CallAfter([this](){ + update_clipping_plane(); + }); + } + } + + ImGui::SameLine(clipping_slider_left); + ImGui::PushItemWidth(window_width - clipping_slider_left); + if (ImGui::SliderFloat(" ", &m_clipping_plane_distance, 0.f, 1.f, "%.2f")) + update_clipping_plane(true); + + + m_imgui->end(); +} + +bool GLGizmoFdmSupports::on_is_activable() const +{ + const Selection& selection = m_parent.get_selection(); + + if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptFFF + || !selection.is_from_single_instance()) + return false; + + // Check that none of the selected volumes is outside. Only SLA auxiliaries (supports) are allowed outside. + const Selection::IndicesList& list = selection.get_volume_idxs(); + for (const auto& idx : list) + if (selection.get_volume(idx)->is_outside) + return false; + + return true; +} + +bool GLGizmoFdmSupports::on_is_selectable() const +{ + return (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptFFF ); +} + +std::string GLGizmoFdmSupports::on_get_name() const +{ + return (_(L("FDM Support Editing")) + " [L]").ToUTF8().data(); +} + + + +void GLGizmoFdmSupports::on_set_state() +{ + if (m_state == On) + std::cout << "zapinam se..." << std::endl; + else + std::cout << "vypinam se..." << std::endl; + return; + // m_model_object pointer can be invalid (for instance because of undo/redo action), + // we should recover it from the object id + m_model_object = nullptr; + for (const auto mo : wxGetApp().model().objects) { + if (mo->id() == m_model_object_id) { + m_model_object = mo; + break; + } + } + + if (m_state == m_old_state) + return; + + if (m_state == On && m_old_state != On) { // the gizmo was just turned on + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned on"))); + if (is_mesh_update_necessary()) + update_mesh(); + + // we'll now reload support points: + if (m_model_object) + ;// !!!! reload_cache(); + + m_parent.toggle_model_objects_visibility(false); + if (m_model_object) + m_parent.toggle_model_objects_visibility(true, m_model_object, m_active_instance); + } + if (m_state == Off && m_old_state != Off) { // the gizmo was just turned Off + // we are actually shutting down + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("FDM gizmo turned off"))); + m_parent.toggle_model_objects_visibility(true); + m_clipping_plane_distance = 0.f; + // Release clippers and the AABB raycaster. + m_its = nullptr; + m_object_clipper.reset(); + m_mesh_raycaster.reset(); + } + m_old_state = m_state; +} + + + +void GLGizmoFdmSupports::on_start_dragging() +{ + +} + + +void GLGizmoFdmSupports::on_stop_dragging() +{ + +} + + + +void GLGizmoFdmSupports::on_load(cereal::BinaryInputArchive& ar) +{ + +} + + + +void GLGizmoFdmSupports::on_save(cereal::BinaryOutputArchive& ar) const +{ + +} + + +void GLGizmoFdmSupports::update_clipping_plane(bool keep_normal) const +{ + Vec3d normal = (keep_normal && m_clipping_plane->get_normal() != Vec3d::Zero() ? + m_clipping_plane->get_normal() : -m_parent.get_camera().get_dir_forward()); + + const Vec3d& center = m_model_object->instances[m_active_instance]->get_offset(); + float dist = normal.dot(center); + *m_clipping_plane = ClippingPlane(normal, (dist - (-m_active_instance_bb_radius) - m_clipping_plane_distance * 2*m_active_instance_bb_radius)); + m_parent.set_as_dirty(); +} + + + + +} // namespace GUI +} // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp new file mode 100644 index 000000000..02a0877ee --- /dev/null +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp @@ -0,0 +1,87 @@ +#ifndef slic3r_GLGizmoFdmSupports_hpp_ +#define slic3r_GLGizmoFdmSupports_hpp_ + +#include "GLGizmoBase.hpp" + +//#include "libslic3r/SLA/SLACommon.hpp" +//#include + +#include + + +namespace Slic3r { +namespace GUI { + +class ClippingPlane; +class MeshClipper; +class MeshRaycaster; +enum class SLAGizmoEventType : unsigned char; + +class GLGizmoFdmSupports : public GLGizmoBase +{ +private: + ModelObject* m_model_object = nullptr; + ObjectID m_model_object_id = 0; + int m_active_instance = -1; + float m_active_instance_bb_radius; // to cache the bb + bool unproject_on_mesh(const Vec2d& mouse_pos, std::pair& pos_and_normal); + + + GLUquadricObj* m_quadric; + + std::unique_ptr m_mesh_raycaster; + const TriangleMesh* m_mesh; + const indexed_triangle_set* m_its; + mutable std::vector m_triangles; + + +public: + GLGizmoFdmSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); + ~GLGizmoFdmSupports() override; + void set_fdm_support_data(ModelObject* model_object, const Selection& selection); + bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down); + ClippingPlane get_fdm_clipping_plane() const; + + +private: + bool on_init() override; + void on_render() const override; + void on_render_for_picking() const override; + + void render_clipping_plane(const Selection& selection) const; + bool is_mesh_update_necessary() const; + void update_mesh(); + + float m_clipping_plane_distance = 0.f; + std::unique_ptr m_clipping_plane; + + // This map holds all translated description texts, so they can be easily referenced during layout calculations + // etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect. + std::map m_desc; + + bool m_wait_for_up_event = false; + EState m_old_state = Off; // to be able to see that the gizmo has just been closed (see on_set_state) + + mutable std::unique_ptr m_object_clipper; + + + bool is_point_clipped(const Vec3d& point) const; + void update_clipping_plane(bool keep_normal = false) const; + +protected: + void on_set_state() override; + void on_start_dragging() override; + void on_stop_dragging() override; + void on_render_input_window(float x, float y, float bottom_limit) override; + std::string on_get_name() const override; + bool on_is_activable() const override; + bool on_is_selectable() const override; + void on_load(cereal::BinaryInputArchive& ar) override; + void on_save(cereal::BinaryOutputArchive& ar) const override; +}; + + +} // namespace GUI +} // namespace Slic3r + +#endif // slic3r_GLGizmoFdmSupports_hpp_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index bd48ecd65..b671af52c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -32,8 +32,6 @@ private: const float RenderPointScale = 1.f; GLUquadricObj* m_quadric; - typedef Eigen::Map> MapMatrixXfUnaligned; - typedef Eigen::Map> MapMatrixXiUnaligned; //std::unique_ptr m_mesh_raycaster; //const TriangleMesh* m_mesh; @@ -142,7 +140,6 @@ private: void auto_generate(); void switch_to_editing_mode(); void disable_editing_mode(); - void reset_clipping_plane_normal() const; protected: void on_set_state() override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmos.hpp b/src/slic3r/GUI/Gizmos/GLGizmos.hpp index 9f97c42b4..e8e73959c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmos.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmos.hpp @@ -31,6 +31,7 @@ enum class SLAGizmoEventType : unsigned char { #include "slic3r/GUI/Gizmos/GLGizmoRotate.hpp" #include "slic3r/GUI/Gizmos/GLGizmoFlatten.hpp" #include "slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp" +#include "slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp" #include "slic3r/GUI/Gizmos/GLGizmoCut.hpp" #include "slic3r/GUI/Gizmos/GLGizmoHollow.hpp" diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index d465196f3..17cc6ff0c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -94,11 +94,13 @@ bool GLGizmosManager::init() m_gizmos.emplace_back(new GLGizmoCut(m_parent, "cut.svg", 4)); m_gizmos.emplace_back(new GLGizmoHollow(m_parent, "hollow.svg", 5)); m_gizmos.emplace_back(new GLGizmoSlaSupports(m_parent, "sla_supports.svg", 6)); + m_gizmos.emplace_back(new GLGizmoFdmSupports(m_parent, "sla_supports.svg", 7)); m_common_gizmos_data.reset(new CommonGizmosData()); dynamic_cast(m_gizmos[Hollow].get())->set_common_data_ptr(m_common_gizmos_data.get()); dynamic_cast(m_gizmos[SlaSupports].get())->set_common_data_ptr(m_common_gizmos_data.get()); + for (auto& gizmo : m_gizmos) { if (! gizmo->init()) { m_gizmos.clear(); @@ -204,6 +206,7 @@ void GLGizmosManager::update_data() ModelObject* model_object = selection.get_model()->objects[selection.get_object_idx()]; set_flattening_data(model_object); set_sla_support_data(model_object); + set_fdm_support_data(model_object); } else if (selection.is_single_volume() || selection.is_single_modifier()) { @@ -212,6 +215,7 @@ void GLGizmosManager::update_data() set_rotation(Vec3d::Zero()); set_flattening_data(nullptr); set_sla_support_data(nullptr); + set_fdm_support_data(nullptr); } else if (is_wipe_tower) { @@ -220,6 +224,7 @@ void GLGizmosManager::update_data() set_rotation(Vec3d(0., 0., (M_PI/180.) * dynamic_cast(config.option("wipe_tower_rotation_angle"))->value)); set_flattening_data(nullptr); set_sla_support_data(nullptr); + set_fdm_support_data(nullptr); } else { @@ -227,6 +232,7 @@ void GLGizmosManager::update_data() set_rotation(Vec3d::Zero()); set_flattening_data(selection.is_from_single_object() ? selection.get_model()->objects[selection.get_object_idx()] : nullptr); set_sla_support_data(nullptr); + set_fdm_support_data(nullptr); } } @@ -366,6 +372,14 @@ void GLGizmosManager::set_sla_support_data(ModelObject* model_object) gizmo_hollow->set_sla_support_data(model_object, m_parent.get_selection()); } +void GLGizmosManager::set_fdm_support_data(ModelObject* model_object) +{ + if (!m_enabled || m_gizmos.empty()) + return; + + dynamic_cast(m_gizmos[FdmSupports].get())->set_fdm_support_data(model_object, m_parent.get_selection()); +} + // Returns true if the gizmo used the event to do something, false otherwise. bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down) { @@ -379,15 +393,17 @@ bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_p return false; } -ClippingPlane GLGizmosManager::get_sla_clipping_plane() const +ClippingPlane GLGizmosManager::get_clipping_plane() const { - if (!m_enabled || (m_current != SlaSupports && m_current != Hollow) || m_gizmos.empty()) + if (!m_enabled || (m_current != SlaSupports && m_current != Hollow && m_current != FdmSupports) || m_gizmos.empty()) return ClippingPlane::ClipsNothing(); if (m_current == SlaSupports) return dynamic_cast(m_gizmos[SlaSupports].get())->get_sla_clipping_plane(); - else + else if (m_current == Hollow) return dynamic_cast(m_gizmos[Hollow].get())->get_sla_clipping_plane(); + else + return dynamic_cast(m_gizmos[FdmSupports].get())->get_fdm_clipping_plane(); } bool GLGizmosManager::wants_reslice_supports_on_undo() const @@ -407,6 +423,7 @@ void GLGizmosManager::render_current_gizmo() const void GLGizmosManager::render_current_gizmo_for_picking_pass() const { if (! m_enabled || m_current == Undefined) + return; m_gizmos[m_current]->render_for_picking(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp index 2eac470f9..52e68e4ef 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp @@ -64,6 +64,7 @@ public: Cut, Hollow, SlaSupports, + FdmSupports, Undefined }; @@ -197,8 +198,11 @@ public: void set_flattening_data(const ModelObject* model_object); void set_sla_support_data(ModelObject* model_object); + + void set_fdm_support_data(ModelObject* model_object); + bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position = Vec2d::Zero(), bool shift_down = false, bool alt_down = false, bool control_down = false); - ClippingPlane get_sla_clipping_plane() const; + ClippingPlane get_clipping_plane() const; bool wants_reslice_supports_on_undo() const; void render_current_gizmo() const; From 08daddb5de22747106db08fb74015048881215b4 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 26 Sep 2019 13:30:22 +0200 Subject: [PATCH 02/28] WIP: First working implementation of the triangle selector for the FDM support gizmo --- src/libslic3r/SLA/Common.cpp | 8 ++- src/libslic3r/SLA/EigenMesh3D.hpp | 2 + src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 60 ++++++++++++++++---- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp | 8 +-- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 21 ++++--- src/slic3r/GUI/MeshUtils.cpp | 29 +++++++++- src/slic3r/GUI/MeshUtils.hpp | 8 ++- 7 files changed, 108 insertions(+), 28 deletions(-) diff --git a/src/libslic3r/SLA/Common.cpp b/src/libslic3r/SLA/Common.cpp index d2aac18fd..6d53eca4f 100644 --- a/src/libslic3r/SLA/Common.cpp +++ b/src/libslic3r/SLA/Common.cpp @@ -303,8 +303,10 @@ EigenMesh3D::query_ray_hit(const Vec3d &s, const Vec3d &dir) const ret.m_t = double(hit.t); ret.m_dir = dir; ret.m_source = s; - if(!std::isinf(hit.t) && !std::isnan(hit.t)) + if(!std::isinf(hit.t) && !std::isnan(hit.t)) { ret.m_normal = this->normal_by_face_id(hit.id); + ret.m_face_id = hit.id; + } return ret; } @@ -340,8 +342,10 @@ EigenMesh3D::query_ray_hits(const Vec3d &s, const Vec3d &dir) const outs.back().m_t = double(hit.t); outs.back().m_dir = dir; outs.back().m_source = s; - if(!std::isinf(hit.t) && !std::isnan(hit.t)) + if(!std::isinf(hit.t) && !std::isnan(hit.t)) { outs.back().m_normal = this->normal_by_face_id(hit.id); + outs.back().m_face_id = hit.id; + } } return outs; diff --git a/src/libslic3r/SLA/EigenMesh3D.hpp b/src/libslic3r/SLA/EigenMesh3D.hpp index bcf94ec16..014a57e82 100644 --- a/src/libslic3r/SLA/EigenMesh3D.hpp +++ b/src/libslic3r/SLA/EigenMesh3D.hpp @@ -55,6 +55,7 @@ public: class hit_result { // m_t holds a distance from m_source to the intersection. double m_t = infty(); + int m_face_id = -1; const EigenMesh3D *m_mesh = nullptr; Vec3d m_dir; Vec3d m_source; @@ -74,6 +75,7 @@ public: inline const Vec3d& direction() const { return m_dir; } inline const Vec3d& source() const { return m_source; } inline Vec3d position() const { return m_source + m_dir * m_t; } + inline int face() const { return m_face_id; } inline bool is_valid() const { return m_mesh != nullptr; } inline bool is_hit() const { return !std::isinf(m_t); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index dfe4bc9a5..6c42a8cd1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -105,13 +105,40 @@ void GLGizmoFdmSupports::on_render() const glsafe(::glEnable(GL_BLEND)); glsafe(::glEnable(GL_DEPTH_TEST)); - + render_triangles(selection); render_clipping_plane(selection); glsafe(::glDisable(GL_BLEND)); } +void GLGizmoFdmSupports::render_triangles(const Selection& selection) const +{ + if (! m_mesh) + return; + // Get transformation of the instance + const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin()); + Transform3d trafo = vol->get_instance_transformation().get_matrix(); + + ::glColor3f(0.0f, 0.37f, 1.0f); + + for (size_t facet_idx : m_selected_facets) { + stl_normal normal = 0.01f * MeshRaycaster::get_triangle_normal(m_mesh->its, facet_idx); + ::glPushMatrix(); + ::glTranslatef(normal(0), normal(1), normal(2)); + ::glMultMatrixd(trafo.data()); + + ::glBegin(GL_TRIANGLES); + ::glVertex3f(m_mesh->its.vertices[m_mesh->its.indices[facet_idx](0)](0), m_mesh->its.vertices[m_mesh->its.indices[facet_idx](0)](1), m_mesh->its.vertices[m_mesh->its.indices[facet_idx](0)](2)); + ::glVertex3f(m_mesh->its.vertices[m_mesh->its.indices[facet_idx](1)](0), m_mesh->its.vertices[m_mesh->its.indices[facet_idx](1)](1), m_mesh->its.vertices[m_mesh->its.indices[facet_idx](1)](2)); + ::glVertex3f(m_mesh->its.vertices[m_mesh->its.indices[facet_idx](2)](0), m_mesh->its.vertices[m_mesh->its.indices[facet_idx](2)](1), m_mesh->its.vertices[m_mesh->its.indices[facet_idx](2)](2)); + ::glEnd(); + ::glPopMatrix(); + } + + + +} void GLGizmoFdmSupports::render_clipping_plane(const Selection& selection) const { @@ -193,7 +220,7 @@ void GLGizmoFdmSupports::update_mesh() // Unprojects the mouse position on the mesh and saves hit point and normal of the facet into pos_and_normal // Return false if no intersection was found, true otherwise. -bool GLGizmoFdmSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair& pos_and_normal) +bool GLGizmoFdmSupports::unproject_on_mesh(const Vec2d& mouse_pos, size_t& facet_idx) { // if the gizmo doesn't have the V, F structures for igl, calculate them first: if (! m_mesh_raycaster) @@ -208,11 +235,8 @@ bool GLGizmoFdmSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pairunproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, hit, normal, m_clipping_plane.get())) { - // Return both the point and the facet normal. - pos_and_normal = std::make_pair(hit, normal); + if (m_mesh_raycaster->unproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, hit, normal, m_clipping_plane.get(), &facet_idx)) return true; - } else return false; } @@ -240,6 +264,22 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous return true; } + if (action == SLAGizmoEventType::LeftDown || (action == SLAGizmoEventType::Dragging && m_wait_for_up_event)) { + size_t facet_idx = 0; + if (unproject_on_mesh(mouse_position, facet_idx)) { + m_selected_facets.push_back(facet_idx); + m_wait_for_up_event = true; + return true; + } + if (action == SLAGizmoEventType::Dragging && m_wait_for_up_event) + return true; + } + + if (action == SLAGizmoEventType::LeftUp && m_wait_for_up_event) { + m_wait_for_up_event = false; + return true; + } + return false; } @@ -332,11 +372,9 @@ std::string GLGizmoFdmSupports::on_get_name() const void GLGizmoFdmSupports::on_set_state() { - if (m_state == On) - std::cout << "zapinam se..." << std::endl; - else - std::cout << "vypinam se..." << std::endl; + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! return; + // m_model_object pointer can be invalid (for instance because of undo/redo action), // we should recover it from the object id m_model_object = nullptr; @@ -351,7 +389,7 @@ void GLGizmoFdmSupports::on_set_state() return; if (m_state == On && m_old_state != On) { // the gizmo was just turned on - Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned on"))); + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("FDM gizmo turned on"))); if (is_mesh_update_necessary()) update_mesh(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp index 02a0877ee..1b1cfd134 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp @@ -3,9 +3,6 @@ #include "GLGizmoBase.hpp" -//#include "libslic3r/SLA/SLACommon.hpp" -//#include - #include @@ -24,7 +21,7 @@ private: ObjectID m_model_object_id = 0; int m_active_instance = -1; float m_active_instance_bb_radius; // to cache the bb - bool unproject_on_mesh(const Vec2d& mouse_pos, std::pair& pos_and_normal); + bool unproject_on_mesh(const Vec2d& mouse_pos, size_t& facet_idx); GLUquadricObj* m_quadric; @@ -34,6 +31,8 @@ private: const indexed_triangle_set* m_its; mutable std::vector m_triangles; + std::vector m_selected_facets; + public: GLGizmoFdmSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); @@ -48,6 +47,7 @@ private: void on_render() const override; void on_render_for_picking() const override; + void render_triangles(const Selection& selection) const; void render_clipping_plane(const Selection& selection) const; bool is_mesh_update_necessary() const; void update_mesh(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 17cc6ff0c..d66304195 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -388,9 +388,12 @@ bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_p if (m_current == SlaSupports) return dynamic_cast(m_gizmos[SlaSupports].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down); - if (m_current == Hollow) + else if (m_current == Hollow) return dynamic_cast(m_gizmos[Hollow].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down); - return false; + else if (m_current == FdmSupports) + return dynamic_cast(m_gizmos[FdmSupports].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down); + else + return false; } ClippingPlane GLGizmosManager::get_clipping_plane() const @@ -444,7 +447,7 @@ bool GLGizmosManager::on_mouse_wheel(wxMouseEvent& evt) { bool processed = false; - if (m_current == SlaSupports || m_current == Hollow) { + if (m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports) { float rot = (float)evt.GetWheelRotation() / (float)evt.GetWheelDelta(); if (gizmo_event((rot > 0.f ? SLAGizmoEventType::MouseWheelUp : SLAGizmoEventType::MouseWheelDown), Vec2d::Zero(), evt.ShiftDown(), evt.AltDown(), evt.ControlDown())) processed = true; @@ -502,7 +505,8 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt) if (evt.LeftDown()) { - if ((m_current == SlaSupports || m_current == Hollow) && gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, evt.ShiftDown(), evt.AltDown(), evt.ControlDown())) + if ((m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports) + && gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, evt.ShiftDown(), evt.AltDown(), evt.ControlDown())) // the gizmo got the event and took some action, there is no need to do anything more processed = true; else if (!selection.is_empty() && grabber_contains_mouse()) { @@ -530,7 +534,8 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt) else if (evt.Dragging() && (m_parent.get_move_volume_id() != -1) && (m_current == SlaSupports || m_current == Hollow)) // don't allow dragging objects with the Sla gizmo on processed = true; - else if (evt.Dragging() && (m_current == SlaSupports || m_current == Hollow) && gizmo_event(SLAGizmoEventType::Dragging, mouse_pos, evt.ShiftDown(), evt.AltDown(), evt.ControlDown())) + else if (evt.Dragging() && (m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports ) + && gizmo_event(SLAGizmoEventType::Dragging, mouse_pos, evt.ShiftDown(), evt.AltDown(), evt.ControlDown())) { // the gizmo got the event and took some action, no need to do anything more here m_parent.set_as_dirty(); @@ -603,9 +608,9 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt) processed = true; } - else if (evt.LeftUp() && (m_current == SlaSupports || m_current == Hollow) && !m_parent.is_mouse_dragging()) + else if (evt.LeftUp() && (m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports) && !m_parent.is_mouse_dragging()) { - // in case SLA gizmo is selected, we just pass the LeftUp event and stop processing - neither + // in case SLA/FDM gizmo is selected, we just pass the LeftUp event and stop processing - neither // object moving or selecting is suppressed in that case gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, evt.ShiftDown(), evt.AltDown(), evt.ControlDown()); processed = true; @@ -702,7 +707,7 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt) case 'r' : case 'R' : { - if ((m_current == SlaSupports || m_current == Hollow) && gizmo_event(SLAGizmoEventType::ResetClippingPlane)) + if ((m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports) && gizmo_event(SLAGizmoEventType::ResetClippingPlane)) processed = true; break; diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index 37b6efd87..7e886a486 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -95,9 +95,16 @@ void MeshClipper::recalculate_triangles() } +Vec3f MeshRaycaster::get_triangle_normal(const indexed_triangle_set& its, size_t facet_idx) +{ + Vec3f a(its.vertices[its.indices[facet_idx](1)] - its.vertices[its.indices[facet_idx](0)]); + Vec3f b(its.vertices[its.indices[facet_idx](2)] - its.vertices[its.indices[facet_idx](0)]); + return Vec3f(a.cross(b)).normalized(); +} bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, - Vec3f& position, Vec3f& normal, const ClippingPlane* clipping_plane) const + Vec3f& position, Vec3f& normal, const ClippingPlane* clipping_plane, + size_t* facet_idx) const { const std::array& viewport = camera.get_viewport(); const Transform3d& model_mat = camera.get_view_matrix(); @@ -112,7 +119,21 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& pt1 = inv * pt1; pt2 = inv * pt2; - std::vector hits = m_emesh.query_ray_hits(pt1, pt2-pt1); + point = pt1; + direction = pt2-pt1; +} + + +bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, + Vec3f& position, Vec3f& normal, const ClippingPlane* clipping_plane, + size_t* facet_idx) const +{ + Vec3d point; + Vec3d direction; + line_from_mouse_pos(mouse_pos, trafo, camera, point, direction); + + std::vector hits = m_emesh.query_ray_hits(point, direction); + if (hits.empty()) return false; // no intersection found @@ -134,6 +155,10 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& // Now stuff the points in the provided vector and calculate normals if asked about them: position = hits[i].position().cast(); normal = hits[i].normal().cast(); + + if (facet_idx) + *facet_idx = hits[i].face(); + return true; } diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp index b4ad03011..3c9580e59 100644 --- a/src/slic3r/GUI/MeshUtils.hpp +++ b/src/slic3r/GUI/MeshUtils.hpp @@ -4,6 +4,8 @@ #include "libslic3r/Point.hpp" #include "libslic3r/Geometry.hpp" #include "libslic3r/SLA/EigenMesh3D.hpp" +#include "admesh/stl.h" + #include @@ -118,7 +120,8 @@ public: const Camera& camera, // current camera position Vec3f& position, // where to save the positibon of the hit (mesh coords) Vec3f& normal, // normal of the triangle that was hit - const ClippingPlane* clipping_plane = nullptr // clipping plane (if active) + const ClippingPlane* clipping_plane = nullptr, // clipping plane (if active) + size_t* facet_idx = nullptr // index of the facet hit ) const; // Given a vector of points in woorld coordinates, this returns vector @@ -134,8 +137,11 @@ public: // Given a point in world coords, the method returns closest point on the mesh. // The output is in mesh coords. // normal* can be used to also get normal of the respective triangle. + Vec3f get_closest_point(const Vec3f& point, Vec3f* normal = nullptr) const; + static Vec3f get_triangle_normal(const indexed_triangle_set& its, size_t facet_idx); + private: sla::EigenMesh3D m_emesh; }; From 2e71dcefc386fac838c309634545da9bfdf47856 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 8 Oct 2019 10:15:06 +0200 Subject: [PATCH 03/28] WIP: Added a circle cursor and naive logic to select triangles inside Deselection is possible when holding shift Triangles obscured by the mesh are selected nonetheless (so far) --- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 136 +++++++++++++++++-- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp | 10 +- src/slic3r/GUI/MeshUtils.cpp | 15 +- src/slic3r/GUI/MeshUtils.hpp | 3 + 4 files changed, 141 insertions(+), 23 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 6c42a8cd1..c5c9f798b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -107,6 +107,7 @@ void GLGizmoFdmSupports::on_render() const render_triangles(selection); render_clipping_plane(selection); + render_cursor_circle(); glsafe(::glDisable(GL_BLEND)); } @@ -122,7 +123,9 @@ void GLGizmoFdmSupports::render_triangles(const Selection& selection) const ::glColor3f(0.0f, 0.37f, 1.0f); - for (size_t facet_idx : m_selected_facets) { + for (size_t facet_idx=0; facet_idxits, facet_idx); ::glPushMatrix(); ::glTranslatef(normal(0), normal(1), normal(2)); @@ -135,9 +138,6 @@ void GLGizmoFdmSupports::render_triangles(const Selection& selection) const ::glEnd(); ::glPopMatrix(); } - - - } void GLGizmoFdmSupports::render_clipping_plane(const Selection& selection) const @@ -170,6 +170,53 @@ void GLGizmoFdmSupports::render_clipping_plane(const Selection& selection) const } } +void GLGizmoFdmSupports::render_cursor_circle() const +{ + const Camera& camera = m_parent.get_camera(); + float zoom = (float)camera.get_zoom(); + float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + + std::cout << zoom << " " << inv_zoom << std::endl; + + Size cnv_size = m_parent.get_canvas_size(); + float cnv_half_width = 0.5f * (float)cnv_size.get_width(); + float cnv_half_height = 0.5f * (float)cnv_size.get_height(); + if ((cnv_half_width == 0.0f) || (cnv_half_height == 0.0f)) + return; + Vec2d mouse_pos(m_parent.get_local_mouse_position()(0), m_parent.get_local_mouse_position()(1)); + Vec2d center(mouse_pos(0) - cnv_half_width, cnv_half_height - mouse_pos(1)); + center = center * inv_zoom; + + glsafe(::glLineWidth(1.5f)); + float color[3]; + color[2] = 0.3f; + glsafe(::glColor3fv(color)); + + glsafe(::glDisable(GL_DEPTH_TEST)); + + glsafe(::glPushMatrix()); + glsafe(::glLoadIdentity()); + // ensure that the circle is renderered inside the frustrum + glsafe(::glTranslated(0.0, 0.0, -(camera.get_near_z() + 0.5))); + // ensure that the overlay fits the frustrum near z plane + double gui_scale = camera.get_gui_scale(); + glsafe(::glScaled(gui_scale, gui_scale, 1.0)); + + glsafe(::glPushAttrib(GL_ENABLE_BIT)); + glsafe(::glLineStipple(4, 0xAAAA)); + glsafe(::glEnable(GL_LINE_STIPPLE)); + + ::glBegin(GL_LINE_LOOP); + for (double angle=0; angle<2*M_PI; angle+=M_PI/20.) + ::glVertex2f(GLfloat(center.x()+m_cursor_radius*cos(angle)), GLfloat(center.y()+m_cursor_radius*sin(angle))); + glsafe(::glEnd()); + + glsafe(::glPopAttrib()); + + glsafe(::glPopMatrix()); + +} + void GLGizmoFdmSupports::on_render_for_picking() const { @@ -209,6 +256,20 @@ void GLGizmoFdmSupports::update_mesh() m_mesh = &m_model_object->volumes.front()->mesh(); m_its = &m_mesh->its; + m_selected_facets.clear(); + m_selected_facets.resize(m_mesh->its.indices.size()); + + // Prepare vector of vertex_index - facet_index pairs to quickly find adjacent facets + m_neighbors.clear(); + m_neighbors.resize(3 * m_mesh->its.indices.size()); + for (size_t i=0; iits.indices.size(); ++i) { + const stl_triangle_vertex_indices& ind = m_mesh->its.indices[i]; + m_neighbors.emplace_back(ind(0), i); + m_neighbors.emplace_back(ind(1), i); + m_neighbors.emplace_back(ind(2), i); + } + std::sort(m_neighbors.begin(), m_neighbors.end()); + // If this is different mesh than last time or if the AABB tree is uninitialized, recalculate it. if (m_model_object_id != m_model_object->id() || ! m_mesh_raycaster) m_mesh_raycaster.reset(new MeshRaycaster(*m_mesh)); @@ -218,9 +279,10 @@ void GLGizmoFdmSupports::update_mesh() -// Unprojects the mouse position on the mesh and saves hit point and normal of the facet into pos_and_normal -// Return false if no intersection was found, true otherwise. -bool GLGizmoFdmSupports::unproject_on_mesh(const Vec2d& mouse_pos, size_t& facet_idx) +// Unprojects the mouse position on the mesh and saves hit facet index into facet_idx +// Position of the hit in mesh coords is copied into *position, if provided. +// Returns false if no intersection was found, true otherwise. +bool GLGizmoFdmSupports::unproject_on_mesh(const Vec2d& mouse_pos, size_t& facet_idx, Vec3f* position) { // if the gizmo doesn't have the V, F structures for igl, calculate them first: if (! m_mesh_raycaster) @@ -235,12 +297,21 @@ bool GLGizmoFdmSupports::unproject_on_mesh(const Vec2d& mouse_pos, size_t& facet // The raycaster query Vec3f hit; Vec3f normal; - if (m_mesh_raycaster->unproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, hit, normal, m_clipping_plane.get(), &facet_idx)) + if (m_mesh_raycaster->unproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, hit, normal, m_clipping_plane.get(), &facet_idx)) { + if (position) + *position = hit; return true; + } else return false; } +bool operator<(const GLGizmoFdmSupports::NeighborData& a, const GLGizmoFdmSupports::NeighborData& b) { + return a.first < b.first; +} + + + // Following function is called from GLCanvas3D to inform the gizmo about a mouse/keyboard event. // The gizmo has an opportunity to react - if it does, it should return true so that the Canvas3D is // aware that the event was reacted to and stops trying to make different sense of it. If the gizmo @@ -266,9 +337,51 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous if (action == SLAGizmoEventType::LeftDown || (action == SLAGizmoEventType::Dragging && m_wait_for_up_event)) { size_t facet_idx = 0; - if (unproject_on_mesh(mouse_position, facet_idx)) { - m_selected_facets.push_back(facet_idx); + Vec3f hit_pos; + if (unproject_on_mesh(mouse_position, facet_idx, &hit_pos)) { + bool select = ! shift_down; + + // Calculate direction from camera to the hit (in mesh coords): + const Selection& selection = m_parent.get_selection(); + const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); + Geometry::Transformation trafo = volume->get_instance_transformation(); + trafo.set_offset(trafo.get_offset()); + Vec3f dir = ((trafo.get_matrix().inverse() * m_parent.get_camera().get_position()).cast() - hit_pos).normalized(); + + // Calculate how far can a point be from the line (in mesh coords). + // FIXME: This should account for (possibly non-uniform) scaling of the mesh. + float limit = pow(m_cursor_radius, 2.f); + + + // A lambda to calculate distance from the line: + auto squared_distance_from_line = [&hit_pos, &dir](const Vec3f point) -> float { + Vec3f diff = hit_pos - point; + return (diff - diff.dot(dir) * dir).squaredNorm(); + }; + + // Now go through the facets and de/select those close enough to the line (FIXME: efficiency) + for (size_t i=0; iits.vertices[m_mesh->its.indices[i](0)]); + if (dist < limit) + m_selected_facets[i] = select; + } + + + + //size_t vertex_idx = m_mesh->its.indices[facet_idx](0); + //auto it = m_neighbors.begin(); + //std::vector visited(m_mesh->its.indices.size(), false); + + //while (it != m_neighbors.end() && it->second == facet_idx) + // it = std::lower_bound(it, m_neighbors.end(), std::make_pair(vertex_idx, size_t(0))); + + //facet_idx = it->second; + //vertex_idx = m_mesh->its.indices[facet_idx](0); + + + m_wait_for_up_event = true; + m_parent.set_as_dirty(); return true; } if (action == SLAGizmoEventType::Dragging && m_wait_for_up_event) @@ -294,8 +407,6 @@ ClippingPlane GLGizmoFdmSupports::get_fdm_clipping_plane() const return ClippingPlane(-m_clipping_plane->get_normal(), m_clipping_plane->get_data()[3]); } - - void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_limit) { if (!m_model_object) @@ -337,6 +448,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l if (ImGui::SliderFloat(" ", &m_clipping_plane_distance, 0.f, 1.f, "%.2f")) update_clipping_plane(true); + ImGui::SliderFloat(" ", &m_cursor_radius, 0.f, 8.f, "%.2f"); m_imgui->end(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp index 1b1cfd134..fadb993c8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp @@ -21,7 +21,7 @@ private: ObjectID m_model_object_id = 0; int m_active_instance = -1; float m_active_instance_bb_radius; // to cache the bb - bool unproject_on_mesh(const Vec2d& mouse_pos, size_t& facet_idx); + bool unproject_on_mesh(const Vec2d& mouse_pos, size_t& facet_idx, Vec3f* position = nullptr); GLUquadricObj* m_quadric; @@ -30,9 +30,9 @@ private: const TriangleMesh* m_mesh; const indexed_triangle_set* m_its; mutable std::vector m_triangles; + float m_cursor_radius = 2.f; - std::vector m_selected_facets; - + std::vector m_selected_facets; public: GLGizmoFdmSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); @@ -40,6 +40,7 @@ public: void set_fdm_support_data(ModelObject* model_object, const Selection& selection); bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down); ClippingPlane get_fdm_clipping_plane() const; + using NeighborData = std::pair; private: @@ -49,6 +50,7 @@ private: void render_triangles(const Selection& selection) const; void render_clipping_plane(const Selection& selection) const; + void render_cursor_circle() const; bool is_mesh_update_necessary() const; void update_mesh(); @@ -64,6 +66,8 @@ private: mutable std::unique_ptr m_object_clipper; + std::vector m_neighbors; // pairs of vertex_index - facet_index + bool is_point_clipped(const Vec3d& point) const; void update_clipping_plane(bool keep_normal = false) const; diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index 7e886a486..6c4f5e49d 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -85,11 +85,11 @@ void MeshClipper::recalculate_triangles() tr = m_trafo.get_matrix().cast() * tr; m_triangles3d.clear(); - m_triangles3d.reserve(m_triangles2d.size()); - for (const Vec2f& pt : m_triangles2d) { - m_triangles3d.push_back(Vec3f(pt(0), pt(1), height_mesh+0.001f)); - m_triangles3d.back() = tr * m_triangles3d.back(); - } + m_triangles3d.reserve(m_triangles2d.size()); + for (const Vec2f& pt : m_triangles2d) { + m_triangles3d.push_back(Vec3f(pt(0), pt(1), height_mesh+0.001f)); + m_triangles3d.back() = tr * m_triangles3d.back(); + } m_triangles_valid = true; } @@ -102,9 +102,8 @@ Vec3f MeshRaycaster::get_triangle_normal(const indexed_triangle_set& its, size_t return Vec3f(a.cross(b)).normalized(); } -bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, - Vec3f& position, Vec3f& normal, const ClippingPlane* clipping_plane, - size_t* facet_idx) const +void MeshRaycaster::line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, + Vec3d& point, Vec3d& direction) const { const std::array& viewport = camera.get_viewport(); const Transform3d& model_mat = camera.get_view_matrix(); diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp index 3c9580e59..9d37b40ae 100644 --- a/src/slic3r/GUI/MeshUtils.hpp +++ b/src/slic3r/GUI/MeshUtils.hpp @@ -113,6 +113,9 @@ public: : m_emesh(mesh) {} + void line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, + Vec3d& point, Vec3d& direction) const; + // Given a mouse position, this returns true in case it is on the mesh. bool unproject_on_mesh( const Vec2d& mouse_pos, From 590569e8f646fee43c53deecd17caf3602e92cee Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 24 Oct 2019 11:59:41 +0200 Subject: [PATCH 04/28] WIP: Optimized the triangle selection so it does not iterate over all the triangles --- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 50 ++++++++++---------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index c5c9f798b..1c306ef98 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -176,8 +176,6 @@ void GLGizmoFdmSupports::render_cursor_circle() const float zoom = (float)camera.get_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; - std::cout << zoom << " " << inv_zoom << std::endl; - Size cnv_size = m_parent.get_canvas_size(); float cnv_half_width = 0.5f * (float)cnv_size.get_width(); float cnv_half_height = 0.5f * (float)cnv_size.get_height(); @@ -191,7 +189,6 @@ void GLGizmoFdmSupports::render_cursor_circle() const float color[3]; color[2] = 0.3f; glsafe(::glColor3fv(color)); - glsafe(::glDisable(GL_DEPTH_TEST)); glsafe(::glPushMatrix()); @@ -212,9 +209,7 @@ void GLGizmoFdmSupports::render_cursor_circle() const glsafe(::glEnd()); glsafe(::glPopAttrib()); - glsafe(::glPopMatrix()); - } @@ -311,7 +306,6 @@ bool operator<(const GLGizmoFdmSupports::NeighborData& a, const GLGizmoFdmSuppor } - // Following function is called from GLCanvas3D to inform the gizmo about a mouse/keyboard event. // The gizmo has an opportunity to react - if it does, it should return true so that the Canvas3D is // aware that the event was reacted to and stops trying to make different sense of it. If the gizmo @@ -336,9 +330,9 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous } if (action == SLAGizmoEventType::LeftDown || (action == SLAGizmoEventType::Dragging && m_wait_for_up_event)) { - size_t facet_idx = 0; + size_t facet = 0; Vec3f hit_pos; - if (unproject_on_mesh(mouse_position, facet_idx, &hit_pos)) { + if (unproject_on_mesh(mouse_position, facet, &hit_pos)) { bool select = ! shift_down; // Calculate direction from camera to the hit (in mesh coords): @@ -359,24 +353,32 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous return (diff - diff.dot(dir) * dir).squaredNorm(); }; - // Now go through the facets and de/select those close enough to the line (FIXME: efficiency) - for (size_t i=0; iits.vertices[m_mesh->its.indices[i](0)]); - if (dist < limit) - m_selected_facets[i] = select; + std::vector next_facets{facet}; + NeighborData helper_pair = std::make_pair(0, 0); + std::vector visited(m_selected_facets.size(), false); + size_t facet_idx = 0; + + while (facet_idx < next_facets.size()) { + size_t facet = next_facets[facet_idx]; + if (! visited[facet]) { + for (size_t i=0; i<3; ++i) { + helper_pair.first = m_mesh->its.indices[facet](i); // vertex index + float dist = squared_distance_from_line(m_mesh->its.vertices[helper_pair.first]); + if (dist < limit) { + auto it = std::lower_bound(m_neighbors.begin(), m_neighbors.end(), helper_pair); + while (it != m_neighbors.end() && it->first == helper_pair.first) { + next_facets.push_back(it->second); + ++it; + } + } + } + visited[facet] = true; + } + ++facet_idx; } - - - //size_t vertex_idx = m_mesh->its.indices[facet_idx](0); - //auto it = m_neighbors.begin(); - //std::vector visited(m_mesh->its.indices.size(), false); - - //while (it != m_neighbors.end() && it->second == facet_idx) - // it = std::lower_bound(it, m_neighbors.end(), std::make_pair(vertex_idx, size_t(0))); - - //facet_idx = it->second; - //vertex_idx = m_mesh->its.indices[facet_idx](0); + for (size_t next_facet : next_facets) + m_selected_facets[next_facet] = select; From 1b05ecae8c6b00b76f164f645752125fa3650245 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 24 Oct 2019 14:01:03 +0200 Subject: [PATCH 05/28] WIP: FDM gizmo: triangles not facing the camera are no more selected with fdm selection tool --- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 50 ++++++++++++-------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 1c306ef98..8c8f731ce 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -251,17 +251,15 @@ void GLGizmoFdmSupports::update_mesh() m_mesh = &m_model_object->volumes.front()->mesh(); m_its = &m_mesh->its; - m_selected_facets.clear(); - m_selected_facets.resize(m_mesh->its.indices.size()); + m_selected_facets.assign(m_mesh->its.indices.size(), false); // Prepare vector of vertex_index - facet_index pairs to quickly find adjacent facets - m_neighbors.clear(); m_neighbors.resize(3 * m_mesh->its.indices.size()); for (size_t i=0; iits.indices.size(); ++i) { const stl_triangle_vertex_indices& ind = m_mesh->its.indices[i]; - m_neighbors.emplace_back(ind(0), i); - m_neighbors.emplace_back(ind(1), i); - m_neighbors.emplace_back(ind(2), i); + m_neighbors[3*i] = std::make_pair(ind(0), i); + m_neighbors[3*i+1] = std::make_pair(ind(1), i); + m_neighbors[3*i+2] = std::make_pair(ind(2), i); } std::sort(m_neighbors.begin(), m_neighbors.end()); @@ -353,21 +351,33 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous return (diff - diff.dot(dir) * dir).squaredNorm(); }; - std::vector next_facets{facet}; - NeighborData helper_pair = std::make_pair(0, 0); - std::vector visited(m_selected_facets.size(), false); - size_t facet_idx = 0; + // A lambda to determine whether this facet is potentionally visible (still can be obscured) + auto faces_camera = [&dir, this](const size_t& facet) -> bool { + return (m_mesh->stl.facet_start[facet].normal.dot(dir) > 0.); + }; - while (facet_idx < next_facets.size()) { - size_t facet = next_facets[facet_idx]; + // Now start with the facet the pointer points to and check all adjacent facets. m_neighbors vector stores + // pairs of vertex_idx - facet_idx and is sorted with respect to the former. Neighboring facet index can be + // quickly found by finding a vertex in the list and read the respective facet ids. + std::vector facets_to_select{facet}; + NeighborData vertex = std::make_pair(0, 0); + std::vector visited(m_selected_facets.size(), false); // keep track of facets we already processed + size_t facet_idx = 0; // index into facets_to_select + auto it = m_neighbors.end(); + + while (facet_idx < facets_to_select.size()) { + size_t facet = facets_to_select[facet_idx]; if (! visited[facet]) { + // check all three vertices and in case they're close enough, find the remaining facets + // and add them to the list to be proccessed later for (size_t i=0; i<3; ++i) { - helper_pair.first = m_mesh->its.indices[facet](i); // vertex index - float dist = squared_distance_from_line(m_mesh->its.vertices[helper_pair.first]); + vertex.first = m_mesh->its.indices[facet](i); // vertex index + float dist = squared_distance_from_line(m_mesh->its.vertices[vertex.first]); if (dist < limit) { - auto it = std::lower_bound(m_neighbors.begin(), m_neighbors.end(), helper_pair); - while (it != m_neighbors.end() && it->first == helper_pair.first) { - next_facets.push_back(it->second); + it = std::lower_bound(m_neighbors.begin(), m_neighbors.end(), vertex); + while (it != m_neighbors.end() && it->first == vertex.first) { + if (it->second != facet && faces_camera(it->second)) + facets_to_select.push_back(it->second); ++it; } } @@ -376,12 +386,10 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous } ++facet_idx; } - - for (size_t next_facet : next_facets) + // Now just select all facets that passed + for (size_t next_facet : facets_to_select) m_selected_facets[next_facet] = select; - - m_wait_for_up_event = true; m_parent.set_as_dirty(); return true; From f275461354b7260f6d0eefceb9714fe8ce7ab9aa Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 1 Nov 2019 12:23:49 +0100 Subject: [PATCH 06/28] WIP: FDM supports gizmo now works with multiple part objects into some extent --- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 280 ++++++++++--------- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp | 16 +- src/slic3r/GUI/MeshUtils.hpp | 5 +- 3 files changed, 154 insertions(+), 147 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 8c8f731ce..727c7dcea 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -17,9 +17,8 @@ namespace GUI { GLGizmoFdmSupports::GLGizmoFdmSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) , m_quadric(nullptr) - , m_its(nullptr) { - m_clipping_plane.reset(new ClippingPlane(Vec3d::Zero(), 0.)); + m_clipping_plane.reset(new ClippingPlane()); m_quadric = ::gluNewQuadric(); if (m_quadric != nullptr) // using GLU_FILL does not work when the instance's transformation @@ -99,7 +98,7 @@ void GLGizmoFdmSupports::on_render() const return; } - if (! m_its || ! m_mesh) + if (m_meshes.empty()) const_cast(this)->update_mesh(); glsafe(::glEnable(GL_BLEND)); @@ -114,60 +113,67 @@ void GLGizmoFdmSupports::on_render() const void GLGizmoFdmSupports::render_triangles(const Selection& selection) const { - if (! m_mesh) - return; +// if (m_meshes.empty()) +// return; - // Get transformation of the instance - const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin()); - Transform3d trafo = vol->get_instance_transformation().get_matrix(); - ::glColor3f(0.0f, 0.37f, 1.0f); + for (size_t mesh_id=0; mesh_idits, facet_idx); - ::glPushMatrix(); - ::glTranslatef(normal(0), normal(1), normal(2)); - ::glMultMatrixd(trafo.data()); + const Transform3d trafo_matrix = + m_model_object->instances[selection.get_instance_idx()]->get_transformation().get_matrix() * + m_model_object->volumes[mesh_id]->get_matrix(); + const TriangleMesh* mesh = m_meshes[mesh_id]; - ::glBegin(GL_TRIANGLES); - ::glVertex3f(m_mesh->its.vertices[m_mesh->its.indices[facet_idx](0)](0), m_mesh->its.vertices[m_mesh->its.indices[facet_idx](0)](1), m_mesh->its.vertices[m_mesh->its.indices[facet_idx](0)](2)); - ::glVertex3f(m_mesh->its.vertices[m_mesh->its.indices[facet_idx](1)](0), m_mesh->its.vertices[m_mesh->its.indices[facet_idx](1)](1), m_mesh->its.vertices[m_mesh->its.indices[facet_idx](1)](2)); - ::glVertex3f(m_mesh->its.vertices[m_mesh->its.indices[facet_idx](2)](0), m_mesh->its.vertices[m_mesh->its.indices[facet_idx](2)](1), m_mesh->its.vertices[m_mesh->its.indices[facet_idx](2)](2)); - ::glEnd(); - ::glPopMatrix(); + + + ::glColor3f(0.0f, 0.37f, 1.0f); + + for (size_t facet_idx=0; facet_idxits, facet_idx); + ::glPushMatrix(); + ::glTranslatef(normal(0), normal(1), normal(2)); + ::glMultMatrixd(trafo_matrix.data()); + + ::glBegin(GL_TRIANGLES); + ::glVertex3f(mesh->its.vertices[mesh->its.indices[facet_idx](0)](0), mesh->its.vertices[mesh->its.indices[facet_idx](0)](1), mesh->its.vertices[mesh->its.indices[facet_idx](0)](2)); + ::glVertex3f(mesh->its.vertices[mesh->its.indices[facet_idx](1)](0), mesh->its.vertices[mesh->its.indices[facet_idx](1)](1), mesh->its.vertices[mesh->its.indices[facet_idx](1)](2)); + ::glVertex3f(mesh->its.vertices[mesh->its.indices[facet_idx](2)](0), mesh->its.vertices[mesh->its.indices[facet_idx](2)](1), mesh->its.vertices[mesh->its.indices[facet_idx](2)](2)); + ::glEnd(); + ::glPopMatrix(); + } } } void GLGizmoFdmSupports::render_clipping_plane(const Selection& selection) const { - if (m_clipping_plane_distance == 0.f) - return; +// if (m_clipping_plane_distance == 0.f) +// return; - // Get transformation of the instance - const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin()); - Geometry::Transformation trafo = vol->get_instance_transformation(); +// // Get transformation of the instance +// const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin()); +// Geometry::Transformation trafo = vol->get_instance_transformation(); - // Now initialize the TMS for the object, perform the cut and save the result. - if (! m_object_clipper) { - m_object_clipper.reset(new MeshClipper); - m_object_clipper->set_mesh(*m_mesh); - } - m_object_clipper->set_plane(*m_clipping_plane); - m_object_clipper->set_transformation(trafo); +// // Now initialize the TMS for the object, perform the cut and save the result. +// if (! m_object_clipper) { +// m_object_clipper.reset(new MeshClipper); +// m_object_clipper->set_mesh(*m_mesh); +// } +// m_object_clipper->set_plane(*m_clipping_plane); +// m_object_clipper->set_transformation(trafo); - // At this point we have the triangulated cuts for both the object and supports - let's render. - if (! m_object_clipper->get_triangles().empty()) { - ::glPushMatrix(); - ::glColor3f(1.0f, 0.37f, 0.0f); - ::glBegin(GL_TRIANGLES); - for (const Vec3f& point : m_object_clipper->get_triangles()) - ::glVertex3f(point(0), point(1), point(2)); - ::glEnd(); - ::glPopMatrix(); - } +// // At this point we have the triangulated cuts for both the object and supports - let's render. +// if (! m_object_clipper->get_triangles().empty()) { +// ::glPushMatrix(); +// ::glColor3f(1.0f, 0.37f, 0.0f); +// ::glBegin(GL_TRIANGLES); +// for (const Vec3f& point : m_object_clipper->get_triangles()) +// ::glVertex3f(point(0), point(1), point(2)); +// ::glEnd(); +// ::glPopMatrix(); +// } } void GLGizmoFdmSupports::render_cursor_circle() const @@ -187,6 +193,8 @@ void GLGizmoFdmSupports::render_cursor_circle() const glsafe(::glLineWidth(1.5f)); float color[3]; + color[0] = 0.f; + color[1] = 1.f; color[2] = 0.3f; glsafe(::glColor3fv(color)); glsafe(::glDisable(GL_DEPTH_TEST)); @@ -219,23 +227,14 @@ void GLGizmoFdmSupports::on_render_for_picking() const } - - -bool GLGizmoFdmSupports::is_point_clipped(const Vec3d& point) const -{ - if (m_clipping_plane_distance == 0.f) - return false; - - Vec3d transformed_point = m_model_object->instances.front()->get_transformation().get_matrix() * point; - return m_clipping_plane->distance(transformed_point) < 0.; -} - - - bool GLGizmoFdmSupports::is_mesh_update_necessary() const { + std::vector volumes_ids; + for (const ModelVolume* vol : m_model_object->volumes) + volumes_ids.push_back(vol->id()); + return ((m_state == On) && (m_model_object != nullptr) && !m_model_object->instances.empty()) - && ((m_model_object->id() != m_model_object_id) || m_its == nullptr); + && (m_model_object->id() != m_model_object_id || m_volumes_ids != volumes_ids); } @@ -246,26 +245,33 @@ void GLGizmoFdmSupports::update_mesh() return; wxBusyCursor wait; - // this way we can use that mesh directly. - // This mesh does not account for the possible Z up SLA offset. - m_mesh = &m_model_object->volumes.front()->mesh(); - m_its = &m_mesh->its; - m_selected_facets.assign(m_mesh->its.indices.size(), false); + size_t num_of_volumes = m_model_object->volumes.size(); + m_meshes.clear(); + m_selected_facets.resize(num_of_volumes); + m_neighbors.resize(num_of_volumes); + m_meshes_raycaster.clear(); - // Prepare vector of vertex_index - facet_index pairs to quickly find adjacent facets - m_neighbors.resize(3 * m_mesh->its.indices.size()); - for (size_t i=0; iits.indices.size(); ++i) { - const stl_triangle_vertex_indices& ind = m_mesh->its.indices[i]; - m_neighbors[3*i] = std::make_pair(ind(0), i); - m_neighbors[3*i+1] = std::make_pair(ind(1), i); - m_neighbors[3*i+2] = std::make_pair(ind(2), i); + for (size_t volume_id=0; volume_idvolumes[volume_id]->mesh(); + m_meshes.push_back(mesh); + + m_selected_facets[volume_id].assign(mesh->its.indices.size(), false); + m_neighbors[volume_id].resize(3 * mesh->its.indices.size()); + + // Prepare vector of vertex_index - facet_index pairs to quickly find adjacent facets + for (size_t i=0; iits.indices.size(); ++i) { + const stl_triangle_vertex_indices& ind = mesh->its.indices[i]; + m_neighbors[volume_id][3*i] = std::make_pair(ind(0), i); + m_neighbors[volume_id][3*i+1] = std::make_pair(ind(1), i); + m_neighbors[volume_id][3*i+2] = std::make_pair(ind(2), i); + } + std::sort(m_neighbors[volume_id].begin(), m_neighbors[volume_id].end()); + + // Recalculate raycaster. + m_meshes_raycaster.emplace_back(new MeshRaycaster(*mesh)); } - std::sort(m_neighbors.begin(), m_neighbors.end()); - - // If this is different mesh than last time or if the AABB tree is uninitialized, recalculate it. - if (m_model_object_id != m_model_object->id() || ! m_mesh_raycaster) - m_mesh_raycaster.reset(new MeshRaycaster(*m_mesh)); m_model_object_id = m_model_object->id(); } @@ -275,22 +281,21 @@ void GLGizmoFdmSupports::update_mesh() // Unprojects the mouse position on the mesh and saves hit facet index into facet_idx // Position of the hit in mesh coords is copied into *position, if provided. // Returns false if no intersection was found, true otherwise. -bool GLGizmoFdmSupports::unproject_on_mesh(const Vec2d& mouse_pos, size_t& facet_idx, Vec3f* position) +bool GLGizmoFdmSupports::unproject_on_mesh(size_t mesh_id, const Vec2d& mouse_pos, size_t& facet_idx, Vec3f* position) { // if the gizmo doesn't have the V, F structures for igl, calculate them first: - if (! m_mesh_raycaster) - update_mesh(); - + //if (! m_meshes_raycaster[mesh_id]) + // update_mesh(); const Camera& camera = m_parent.get_camera(); const Selection& selection = m_parent.get_selection(); - const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); - Geometry::Transformation trafo = volume->get_instance_transformation(); - trafo.set_offset(trafo.get_offset()); + const Transform3d trafo_matrix = + m_model_object->instances[selection.get_instance_idx()]->get_transformation().get_matrix() * + m_model_object->volumes[mesh_id]->get_matrix(); // The raycaster query Vec3f hit; Vec3f normal; - if (m_mesh_raycaster->unproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, hit, normal, m_clipping_plane.get(), &facet_idx)) { + if (m_meshes_raycaster[mesh_id]->unproject_on_mesh(mouse_pos, trafo_matrix, camera, hit, normal, m_clipping_plane.get(), &facet_idx)) { if (position) *position = hit; return true; @@ -330,66 +335,74 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous if (action == SLAGizmoEventType::LeftDown || (action == SLAGizmoEventType::Dragging && m_wait_for_up_event)) { size_t facet = 0; Vec3f hit_pos; - if (unproject_on_mesh(mouse_position, facet, &hit_pos)) { - bool select = ! shift_down; + bool mesh_was_hit = false; - // Calculate direction from camera to the hit (in mesh coords): - const Selection& selection = m_parent.get_selection(); - const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); - Geometry::Transformation trafo = volume->get_instance_transformation(); - trafo.set_offset(trafo.get_offset()); - Vec3f dir = ((trafo.get_matrix().inverse() * m_parent.get_camera().get_position()).cast() - hit_pos).normalized(); + for (size_t mesh_id=0; mesh_idvolumes.size(); ++mesh_id) { + if (unproject_on_mesh(mesh_id, mouse_position, facet, &hit_pos)) { + mesh_was_hit = true; + const TriangleMesh* mesh = m_meshes[mesh_id]; + std::vector& neighbors = m_neighbors[mesh_id]; - // Calculate how far can a point be from the line (in mesh coords). - // FIXME: This should account for (possibly non-uniform) scaling of the mesh. - float limit = pow(m_cursor_radius, 2.f); + bool select = ! shift_down; + // Calculate direction from camera to the hit (in mesh coords): + const Selection& selection = m_parent.get_selection(); + const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); + Geometry::Transformation trafo = volume->get_instance_transformation(); + trafo.set_offset(trafo.get_offset()); + Vec3f dir = ((trafo.get_matrix().inverse() * m_parent.get_camera().get_position()).cast() - hit_pos).normalized(); - // A lambda to calculate distance from the line: - auto squared_distance_from_line = [&hit_pos, &dir](const Vec3f point) -> float { - Vec3f diff = hit_pos - point; - return (diff - diff.dot(dir) * dir).squaredNorm(); - }; + // Calculate how far can a point be from the line (in mesh coords). + // FIXME: This should account for (possibly non-uniform) scaling of the mesh. + float limit = pow(m_cursor_radius, 2.f); - // A lambda to determine whether this facet is potentionally visible (still can be obscured) - auto faces_camera = [&dir, this](const size_t& facet) -> bool { - return (m_mesh->stl.facet_start[facet].normal.dot(dir) > 0.); - }; + // A lambda to calculate distance from the line: + auto squared_distance_from_line = [&hit_pos, &dir](const Vec3f point) -> float { + Vec3f diff = hit_pos - point; + return (diff - diff.dot(dir) * dir).squaredNorm(); + }; - // Now start with the facet the pointer points to and check all adjacent facets. m_neighbors vector stores - // pairs of vertex_idx - facet_idx and is sorted with respect to the former. Neighboring facet index can be - // quickly found by finding a vertex in the list and read the respective facet ids. - std::vector facets_to_select{facet}; - NeighborData vertex = std::make_pair(0, 0); - std::vector visited(m_selected_facets.size(), false); // keep track of facets we already processed - size_t facet_idx = 0; // index into facets_to_select - auto it = m_neighbors.end(); - - while (facet_idx < facets_to_select.size()) { - size_t facet = facets_to_select[facet_idx]; - if (! visited[facet]) { - // check all three vertices and in case they're close enough, find the remaining facets - // and add them to the list to be proccessed later - for (size_t i=0; i<3; ++i) { - vertex.first = m_mesh->its.indices[facet](i); // vertex index - float dist = squared_distance_from_line(m_mesh->its.vertices[vertex.first]); - if (dist < limit) { - it = std::lower_bound(m_neighbors.begin(), m_neighbors.end(), vertex); - while (it != m_neighbors.end() && it->first == vertex.first) { - if (it->second != facet && faces_camera(it->second)) - facets_to_select.push_back(it->second); - ++it; + // A lambda to determine whether this facet is potentionally visible (still can be obscured) + auto faces_camera = [&dir, this](const size_t& mesh_id, const size_t& facet) -> bool { + return (m_meshes[mesh_id]->stl.facet_start[facet].normal.dot(dir) > 0.); + }; + // Now start with the facet the pointer points to and check all adjacent facets. neighbors vector stores + // pairs of vertex_idx - facet_idx and is sorted with respect to the former. Neighboring facet index can be + // quickly found by finding a vertex in the list and read the respective facet ids. + std::vector facets_to_select{facet}; + NeighborData vertex = std::make_pair(0, 0); + std::vector visited(m_selected_facets[mesh_id].size(), false); // keep track of facets we already processed + size_t facet_idx = 0; // index into facets_to_select + auto it = neighbors.end(); + while (facet_idx < facets_to_select.size()) { + size_t facet = facets_to_select[facet_idx]; + if (! visited[facet]) { + // check all three vertices and in case they're close enough, find the remaining facets + // and add them to the list to be proccessed later + for (size_t i=0; i<3; ++i) { + vertex.first = mesh->its.indices[facet](i); // vertex index + float dist = squared_distance_from_line(mesh->its.vertices[vertex.first]); + if (dist < limit) { + it = std::lower_bound(neighbors.begin(), neighbors.end(), vertex); + while (it != neighbors.end() && it->first == vertex.first) { + if (it->second != facet && faces_camera(mesh_id, it->second)) + facets_to_select.push_back(it->second); + ++it; + } } } + visited[facet] = true; } - visited[facet] = true; + ++facet_idx; } - ++facet_idx; + // Now just select all facets that passed + for (size_t next_facet : facets_to_select) + m_selected_facets[mesh_id][next_facet] = select; } - // Now just select all facets that passed - for (size_t next_facet : facets_to_select) - m_selected_facets[next_facet] = select; + } + if (mesh_was_hit) + { m_wait_for_up_event = true; m_parent.set_as_dirty(); return true; @@ -529,9 +542,8 @@ void GLGizmoFdmSupports::on_set_state() m_parent.toggle_model_objects_visibility(true); m_clipping_plane_distance = 0.f; // Release clippers and the AABB raycaster. - m_its = nullptr; - m_object_clipper.reset(); - m_mesh_raycaster.reset(); + m_meshes_clipper.clear(); + m_meshes_raycaster.clear(); } m_old_state = m_state; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp index fadb993c8..104823e5c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp @@ -19,20 +19,20 @@ class GLGizmoFdmSupports : public GLGizmoBase private: ModelObject* m_model_object = nullptr; ObjectID m_model_object_id = 0; + std::vector m_volumes_ids; int m_active_instance = -1; float m_active_instance_bb_radius; // to cache the bb - bool unproject_on_mesh(const Vec2d& mouse_pos, size_t& facet_idx, Vec3f* position = nullptr); + bool unproject_on_mesh(size_t mesh_id, const Vec2d& mouse_pos, size_t& facet_idx, Vec3f* position = nullptr); GLUquadricObj* m_quadric; - std::unique_ptr m_mesh_raycaster; - const TriangleMesh* m_mesh; - const indexed_triangle_set* m_its; + std::vector> m_meshes_raycaster; + std::vector m_meshes; mutable std::vector m_triangles; float m_cursor_radius = 2.f; - std::vector m_selected_facets; + std::vector> m_selected_facets; public: GLGizmoFdmSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); @@ -64,12 +64,10 @@ private: bool m_wait_for_up_event = false; EState m_old_state = Off; // to be able to see that the gizmo has just been closed (see on_set_state) - mutable std::unique_ptr m_object_clipper; + mutable std::vector> m_meshes_clipper; - std::vector m_neighbors; // pairs of vertex_index - facet_index + std::vector> m_neighbors; // pairs of vertex_index - facet_index for each mesh - - bool is_point_clipped(const Vec3d& point) const; void update_clipping_plane(bool keep_normal = false) const; protected: diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp index 9d37b40ae..92f444f55 100644 --- a/src/slic3r/GUI/MeshUtils.hpp +++ b/src/slic3r/GUI/MeshUtils.hpp @@ -28,10 +28,7 @@ class ClippingPlane public: ClippingPlane() { - m_data[0] = 0.0; - m_data[1] = 0.0; - m_data[2] = 1.0; - m_data[3] = 0.0; + *this = ClipsNothing(); } ClippingPlane(const Vec3d& direction, double offset) From 6d23c08d001ac3ccef2331d3902421114ac60e1f Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 9 Mar 2020 10:02:06 +0100 Subject: [PATCH 07/28] WIP --- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 104 +++++++++++-------- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp | 2 - 2 files changed, 61 insertions(+), 45 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 727c7dcea..b578d6bdd 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -8,6 +8,7 @@ #include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/MeshUtils.hpp" #include "slic3r/GUI/PresetBundle.hpp" +#include "slic3r/GUI/Camera.hpp" @@ -278,31 +279,6 @@ void GLGizmoFdmSupports::update_mesh() -// Unprojects the mouse position on the mesh and saves hit facet index into facet_idx -// Position of the hit in mesh coords is copied into *position, if provided. -// Returns false if no intersection was found, true otherwise. -bool GLGizmoFdmSupports::unproject_on_mesh(size_t mesh_id, const Vec2d& mouse_pos, size_t& facet_idx, Vec3f* position) -{ - // if the gizmo doesn't have the V, F structures for igl, calculate them first: - //if (! m_meshes_raycaster[mesh_id]) - // update_mesh(); - const Camera& camera = m_parent.get_camera(); - const Selection& selection = m_parent.get_selection(); - const Transform3d trafo_matrix = - m_model_object->instances[selection.get_instance_idx()]->get_transformation().get_matrix() * - m_model_object->volumes[mesh_id]->get_matrix(); - - // The raycaster query - Vec3f hit; - Vec3f normal; - if (m_meshes_raycaster[mesh_id]->unproject_on_mesh(mouse_pos, trafo_matrix, camera, hit, normal, m_clipping_plane.get(), &facet_idx)) { - if (position) - *position = hit; - return true; - } - else - return false; -} bool operator<(const GLGizmoFdmSupports::NeighborData& a, const GLGizmoFdmSupports::NeighborData& b) { return a.first < b.first; @@ -333,32 +309,74 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous } if (action == SLAGizmoEventType::LeftDown || (action == SLAGizmoEventType::Dragging && m_wait_for_up_event)) { - size_t facet = 0; - Vec3f hit_pos; - bool mesh_was_hit = false; + bool select = ! shift_down; + const Camera& camera = m_parent.get_camera(); + const Selection& selection = m_parent.get_selection(); + const Transform3d& instance_trafo = m_model_object->instances[selection.get_instance_idx()]->get_transformation().get_matrix(); - for (size_t mesh_id=0; mesh_idvolumes.size(); ++mesh_id) { - if (unproject_on_mesh(mesh_id, mouse_position, facet, &hit_pos)) { - mesh_was_hit = true; + // Precalculate transformations of individual meshes + std::vector trafo_matrices; + for (const ModelVolume* mv : m_model_object->volumes) + trafo_matrices.push_back(instance_trafo * mv->get_matrix()); + + std::vector>> hit_positions_and_facet_ids(m_meshes.size()); + bool some_mesh_was_hit = false; + + // Cast a ray on all meshes, pick the closest hit and save it for the respective mesh + Vec3f normal = Vec3f::Zero(); + Vec3f hit = Vec3f::Zero(); + size_t facet = 0; + Vec3f closest_hit = Vec3f::Zero(); + double closest_hit_squared_distance = std::numeric_limits::max(); + size_t closest_facet = 0; + size_t closest_hit_mesh_id = size_t(-1); + + for (size_t mesh_id=0; mesh_idunproject_on_mesh( + mouse_position, + trafo_matrices[mesh_id], + camera, + hit, + normal, + m_clipping_plane.get(), + &facet)) + { + // Is this hit the closest to the camera so far? + double hit_squared_distance = (camera.get_position()-trafo_matrices[mesh_id]*hit.cast()).squaredNorm(); + if (hit_squared_distance < closest_hit_squared_distance) { + closest_hit_squared_distance = hit_squared_distance; + closest_facet = facet; + closest_hit_mesh_id = mesh_id; + closest_hit = hit; + } + } + } + // We now know where the ray hit, let's save it and cast another ray + if (closest_hit_mesh_id != size_t(-1)) // only if there is at least one hit + hit_positions_and_facet_ids[closest_hit_mesh_id].emplace_back(closest_hit, closest_facet); + + + // Now propagate the hits + for (size_t mesh_id=0; mesh_id& hit_and_facet : hit_positions_and_facet_ids[mesh_id]) { + some_mesh_was_hit = true; const TriangleMesh* mesh = m_meshes[mesh_id]; std::vector& neighbors = m_neighbors[mesh_id]; - bool select = ! shift_down; - // Calculate direction from camera to the hit (in mesh coords): - const Selection& selection = m_parent.get_selection(); - const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); - Geometry::Transformation trafo = volume->get_instance_transformation(); - trafo.set_offset(trafo.get_offset()); - Vec3f dir = ((trafo.get_matrix().inverse() * m_parent.get_camera().get_position()).cast() - hit_pos).normalized(); + const Transform3d& trafo_matrix = trafo_matrices[mesh_id]; + + Vec3f dir = ((trafo_matrix.inverse() * camera.get_position()).cast() - hit_and_facet.first).normalized(); // Calculate how far can a point be from the line (in mesh coords). // FIXME: This should account for (possibly non-uniform) scaling of the mesh. float limit = pow(m_cursor_radius, 2.f); - // A lambda to calculate distance from the line: - auto squared_distance_from_line = [&hit_pos, &dir](const Vec3f point) -> float { - Vec3f diff = hit_pos - point; + // A lambda to calculate distance from the centerline: + auto squared_distance_from_line = [&hit_and_facet, &dir](const Vec3f point) -> float { + Vec3f diff = hit_and_facet.first - point; return (diff - diff.dot(dir) * dir).squaredNorm(); }; @@ -369,7 +387,7 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous // Now start with the facet the pointer points to and check all adjacent facets. neighbors vector stores // pairs of vertex_idx - facet_idx and is sorted with respect to the former. Neighboring facet index can be // quickly found by finding a vertex in the list and read the respective facet ids. - std::vector facets_to_select{facet}; + std::vector facets_to_select{hit_and_facet.second}; NeighborData vertex = std::make_pair(0, 0); std::vector visited(m_selected_facets[mesh_id].size(), false); // keep track of facets we already processed size_t facet_idx = 0; // index into facets_to_select @@ -401,7 +419,7 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous } } - if (mesh_was_hit) + if (some_mesh_was_hit) { m_wait_for_up_event = true; m_parent.set_as_dirty(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp index 104823e5c..2823299c5 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp @@ -22,8 +22,6 @@ private: std::vector m_volumes_ids; int m_active_instance = -1; float m_active_instance_bb_radius; // to cache the bb - bool unproject_on_mesh(size_t mesh_id, const Vec2d& mouse_pos, size_t& facet_idx, Vec3f* position = nullptr); - GLUquadricObj* m_quadric; From 8475968025ebf0dc9c661d557f7fe90ac852cee9 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 25 Mar 2020 09:09:02 +0100 Subject: [PATCH 08/28] First installation of common gizmo data pool --- src/slic3r/CMakeLists.txt | 2 + src/slic3r/GUI/Gizmos/GLGizmoBase.hpp | 3 + src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 53 +++++++ src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 191 +++++++++++++++++++++++ 4 files changed, 249 insertions(+) create mode 100644 src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp create mode 100644 src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index c8f7e9f1c..f13c6084b 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -34,6 +34,8 @@ set(SLIC3R_GUI_SOURCES GUI/Gizmos/GLGizmos.hpp GUI/Gizmos/GLGizmosManager.cpp GUI/Gizmos/GLGizmosManager.hpp + GUI/Gizmos/GLGizmosCommon.cpp + GUI/Gizmos/GLGizmosCommon.hpp GUI/Gizmos/GLGizmoBase.cpp GUI/Gizmos/GLGizmoBase.hpp GUI/Gizmos/GLGizmoMove.cpp diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index 0d19a86af..965f195a9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -32,6 +32,7 @@ static const float CONSTRAINED_COLOR[4] = { 0.5f, 0.5f, 0.5f, 1.0f }; class ImGuiWrapper; class GLCanvas3D; class ClippingPlane; +enum class CommonGizmosDataID; class GLGizmoBase { @@ -128,6 +129,7 @@ public: bool is_activable() const { return on_is_activable(); } bool is_selectable() const { return on_is_selectable(); } + CommonGizmosDataID get_requirements() const { return on_get_requirements(); } unsigned int get_sprite_id() const { return m_sprite_id; } @@ -161,6 +163,7 @@ protected: virtual void on_set_hover_id() {} virtual bool on_is_activable() const { return true; } virtual bool on_is_selectable() const { return true; } + virtual CommonGizmosDataID on_get_requirements() const { return CommonGizmosDataID(0); } virtual void on_enable_grabber(unsigned int id) {} virtual void on_disable_grabber(unsigned int id) {} virtual void on_start_dragging() {} diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp new file mode 100644 index 000000000..89a671519 --- /dev/null +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -0,0 +1,53 @@ +#include "GLGizmosCommon.hpp" + +#include + +#include "slic3r/GUI/GLCanvas3D.hpp" + +namespace Slic3r { +namespace GUI { + + +CommonGizmosDataPool::CommonGizmosDataPool(GLCanvas3D* canvas) + : m_canvas(canvas) +{ + using namespace CommonGizmosDataObjects; + using c = CommonGizmosDataID; + m_data[c::SelectionInfo].reset( new SelectionInfo(this)); + m_data[c::InstancesHider].reset( new InstancesHider(this)); + m_data[c::HollowedMesh].reset( new HollowedMesh(this)); + m_data[c::ClippingPlaneWrapper].reset(new ClippingPlaneWrapper(this)); + m_data[c::SupportsClipper].reset( new SupportsClipper(this)); + m_data[c::MeshRaycaster].reset( new Raycaster(this)); +} + +void CommonGizmosDataPool::update(CommonGizmosDataID required) +{ + assert(check_dependencies(required)); + for (auto& [id, data] : m_data) + data->update(int(required) & int(CommonGizmosDataID(id))); +} + +#ifndef NDEBUG +bool CommonGizmosDataPool::check_dependencies(CommonGizmosDataID required) const +{ + // This should iterate over currently required data. Each of them should + // be asked about its dependencies and it must check that all dependencies + // are also in required and before the current one. + return true; +} +#endif // NDEBUG + + + + +void CommonGizmosDataObjects::SelectionInfo::update(bool required) +{ + Selection selection = m_common->get_canvas()->get_selection(); + +} + + + +} // namespace GUI +} // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp new file mode 100644 index 000000000..6d83179cb --- /dev/null +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -0,0 +1,191 @@ +#ifndef slic3r_GUI_GLGizmosCommon_hpp_ +#define slic3r_GUI_GLGizmosCommon_hpp_ + +#include +#include + +namespace Slic3r { + +class ModelObject; + + +namespace GUI { + +class GLCanvas3D; + +class CommonGizmosDataBase; +namespace CommonGizmosDataObjects { + class SelectionInfo; +} + +// Some of the gizmos use the same data that need to be updated ocassionally. +// It is also desirable that the data are not recalculated when the gizmos +// are just switched, but on the other hand, they should be released when +// they are not in use by any gizmo anymore. + +// Enumeration of various data types that the data pool can contain. +// Each gizmo can tell which of the data it wants to use through +// on_get_requirements() method. +enum class CommonGizmosDataID { + None = 0, + SelectionInfo = 1 << 0, + InstancesHider = 1 << 1, + HollowedMesh = 1 << 2, + ClippingPlaneWrapper = 1 << 3, + SupportsClipper = 1 << 4, + MeshRaycaster = 1 << 5, +}; + + +// Following class holds pointers to the common data objects and triggers +// their updating/releasing. There is just one object of this type (managed +// by GLGizmoManager, the gizmos keep a pointer to it. +class CommonGizmosDataPool { +public: + CommonGizmosDataPool(GLCanvas3D* canvas); + + // Update all resources and release what is not used. + // Accepts a bitmask of currently required resources. + void update(CommonGizmosDataID required = CommonGizmosDataID::None); + + // Getters for the data that need to be accessed from the gizmos directly. + CommonGizmosDataObjects::SelectionInfo selection_info(); + + GLCanvas3D* get_canvas() const { return m_canvas; } + +private: + std::map> m_data; + GLCanvas3D* m_canvas; + +#ifndef NDEBUG + bool check_dependencies(CommonGizmosDataID required) const; +#endif +}; + + + + + +// Base class for a wrapper object managing a single resource. +// Each of the enum values above (safe None) will have an object of this kind. +class CommonGizmosDataBase { +public: + // Pass a backpointer to the pool, so the individual + // objects can communicate with one another. + explicit CommonGizmosDataBase(CommonGizmosDataPool* cgdp) + : m_common{cgdp} {} + + // Update the resource. If it is not needed (based on argument value) + // any persistent data will be released. + virtual void update(bool required) = 0; + + // Returns whether the resource is currently maintained. + bool is_valid() const { return m_is_valid; } + +protected: + CommonGizmosDataPool* m_common = nullptr; + +private: + bool m_is_valid = false; +}; + + + +// The specializations of the CommonGizmosDataBase class live in this +// namespace to avoid clashes in GUI namespace. +namespace CommonGizmosDataObjects +{ + +class SelectionInfo : public CommonGizmosDataBase +{ +public: + explicit SelectionInfo(CommonGizmosDataPool* cgdp) : + CommonGizmosDataBase(cgdp) {} + void update(bool required) override; + + ModelObject* model_object(); + int get_active_instance(); + +private: + ModelObject* m_model_object = nullptr; + int m_active_inst = -1; +}; + + +class InstancesHider : public CommonGizmosDataBase +{ +public: + explicit InstancesHider(CommonGizmosDataPool* cgdp) : + CommonGizmosDataBase(cgdp) {} + void update(bool required) override; +}; + + + + + + + +class HollowedMesh : public CommonGizmosDataBase +{ +public: + explicit HollowedMesh(CommonGizmosDataPool* cgdp) + : CommonGizmosDataBase(cgdp) {} + void update(bool required) override; +}; + + + + + + + +class ClippingPlaneWrapper : public CommonGizmosDataBase +{ +public: + explicit ClippingPlaneWrapper(CommonGizmosDataPool* cgdp) + : CommonGizmosDataBase(cgdp) {} + void update(bool required) override; +}; + + + + + + + +class SupportsClipper : public CommonGizmosDataBase +{ +public: + explicit SupportsClipper(CommonGizmosDataPool* cgdp) + : CommonGizmosDataBase(cgdp) {} + void update(bool required) override; +}; + + + + + + + +class Raycaster : public CommonGizmosDataBase +{ +public: + explicit Raycaster(CommonGizmosDataPool* cgdp) + : CommonGizmosDataBase(cgdp) {} + void update(bool required) override; +}; + + +} // namespace CommonGizmosDataObjects + + + + + + +} // namespace GUI +} // namespace Slic3r + + +#endif // slic3r_GUI_GLGizmosCommon_hpp_ From 7c4071c541bff2c5ea7337b8f241690ac0ce4404 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 2 Apr 2020 17:05:23 +0200 Subject: [PATCH 09/28] Disabled the SLA gizmos --- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 379bd48d1..b6cd4858c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -95,12 +95,12 @@ bool GLGizmosManager::init() m_gizmos.emplace_back(new GLGizmoRotate3D(m_parent, "rotate.svg", 2)); m_gizmos.emplace_back(new GLGizmoFlatten(m_parent, "place.svg", 3)); m_gizmos.emplace_back(new GLGizmoCut(m_parent, "cut.svg", 4)); - m_gizmos.emplace_back(new GLGizmoHollow(m_parent, "hollow.svg", 5)); - m_gizmos.emplace_back(new GLGizmoSlaSupports(m_parent, "sla_supports.svg", 6)); + //m_gizmos.emplace_back(new GLGizmoHollow(m_parent, "hollow.svg", 5)); + //m_gizmos.emplace_back(new GLGizmoSlaSupports(m_parent, "sla_supports.svg", 6)); - m_common_gizmos_data.reset(new CommonGizmosData()); - dynamic_cast(m_gizmos[Hollow].get())->set_common_data_ptr(m_common_gizmos_data.get()); - dynamic_cast(m_gizmos[SlaSupports].get())->set_common_data_ptr(m_common_gizmos_data.get()); + //m_common_gizmos_data.reset(new CommonGizmosData()); + //dynamic_cast(m_gizmos[Hollow].get())->set_common_data_ptr(m_common_gizmos_data.get()); + //dynamic_cast(m_gizmos[SlaSupports].get())->set_common_data_ptr(m_common_gizmos_data.get()); for (auto& gizmo : m_gizmos) { if (! gizmo->init()) { @@ -353,7 +353,7 @@ void GLGizmosManager::set_flattening_data(const ModelObject* model_object) void GLGizmosManager::set_sla_support_data(ModelObject* model_object) { - if (! m_enabled + /*if (! m_enabled || m_gizmos.empty() || wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA) return; @@ -367,6 +367,7 @@ void GLGizmosManager::set_sla_support_data(ModelObject* model_object) // following lines are thus dependent gizmo_supports->set_sla_support_data(model_object, m_parent.get_selection()); gizmo_hollow->set_sla_support_data(model_object, m_parent.get_selection()); + */ } // Returns true if the gizmo used the event to do something, false otherwise. From 3b06332999e04592fd2f8f98889458ed436e3d58 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 2 Apr 2020 17:07:15 +0200 Subject: [PATCH 10/28] Common gizmos data are now handled by the CommonGizmosDataPool object --- src/slic3r/GUI/AppConfig.hpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoBase.hpp | 3 +++ src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 10 +++++----- src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 4 ++-- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 4 ++++ src/slic3r/GUI/Gizmos/GLGizmosManager.hpp | 5 ++++- 6 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/slic3r/GUI/AppConfig.hpp b/src/slic3r/GUI/AppConfig.hpp index 346d42b21..1e90d32e0 100644 --- a/src/slic3r/GUI/AppConfig.hpp +++ b/src/slic3r/GUI/AppConfig.hpp @@ -60,7 +60,7 @@ public: boost::trim_all(key_trimmed); assert(key_trimmed == key); assert(! key_trimmed.empty()); -#endif _NDEBUG +#endif // _NDEBUG std::string &old = m_storage[section][key]; if (old != value) { old = value; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index 965f195a9..8a2b71976 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -33,6 +33,7 @@ class ImGuiWrapper; class GLCanvas3D; class ClippingPlane; enum class CommonGizmosDataID; +class CommonGizmosDataPool; class GLGizmoBase { @@ -102,6 +103,7 @@ protected: ImGuiWrapper* m_imgui; bool m_first_input_window_render; mutable std::string m_tooltip; + CommonGizmosDataPool* m_c; public: GLGizmoBase(GLCanvas3D& parent, @@ -130,6 +132,7 @@ public: bool is_activable() const { return on_is_activable(); } bool is_selectable() const { return on_is_selectable(); } CommonGizmosDataID get_requirements() const { return on_get_requirements(); } + void set_common_data_pool(CommonGizmosDataPool* ptr) { m_c = ptr; } unsigned int get_sprite_id() const { return m_sprite_id; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index 89a671519..bcc562d8b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -14,11 +14,11 @@ CommonGizmosDataPool::CommonGizmosDataPool(GLCanvas3D* canvas) using namespace CommonGizmosDataObjects; using c = CommonGizmosDataID; m_data[c::SelectionInfo].reset( new SelectionInfo(this)); - m_data[c::InstancesHider].reset( new InstancesHider(this)); - m_data[c::HollowedMesh].reset( new HollowedMesh(this)); - m_data[c::ClippingPlaneWrapper].reset(new ClippingPlaneWrapper(this)); - m_data[c::SupportsClipper].reset( new SupportsClipper(this)); - m_data[c::MeshRaycaster].reset( new Raycaster(this)); + //m_data[c::InstancesHider].reset( new InstancesHider(this)); + //m_data[c::HollowedMesh].reset( new HollowedMesh(this)); + //m_data[c::ClippingPlaneWrapper].reset(new ClippingPlaneWrapper(this)); + //m_data[c::SupportsClipper].reset( new SupportsClipper(this)); + //m_data[c::MeshRaycaster].reset( new Raycaster(this)); } void CommonGizmosDataPool::update(CommonGizmosDataID required) diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index 6d83179cb..259de5013 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -111,7 +111,7 @@ private: int m_active_inst = -1; }; - +/* class InstancesHider : public CommonGizmosDataBase { public: @@ -175,7 +175,7 @@ public: : CommonGizmosDataBase(cgdp) {} void update(bool required) override; }; - +*/ } // namespace CommonGizmosDataObjects diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index b6cd4858c..9600b3d64 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -102,11 +102,14 @@ bool GLGizmosManager::init() //dynamic_cast(m_gizmos[Hollow].get())->set_common_data_ptr(m_common_gizmos_data.get()); //dynamic_cast(m_gizmos[SlaSupports].get())->set_common_data_ptr(m_common_gizmos_data.get()); + m_common_gizmos_data.reset(new CommonGizmosDataPool(&m_parent)); + for (auto& gizmo : m_gizmos) { if (! gizmo->init()) { m_gizmos.clear(); return false; } + gizmo->set_common_data_pool(m_common_gizmos_data.get()); } m_current = Undefined; @@ -1335,5 +1338,6 @@ void CommonGizmosData::build_AABB_if_needed() m_schedule_aabb_calculation = false; } + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp index 7ae1fa661..f01ecfd77 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp @@ -5,6 +5,7 @@ #include "slic3r/GUI/GLToolbar.hpp" #include "libslic3r/ObjectID.hpp" #include "slic3r/GUI/Gizmos/GLGizmoBase.hpp" +#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" #include @@ -20,6 +21,7 @@ class GLCanvas3D; class ClippingPlane; enum class SLAGizmoEventType : unsigned char; class CommonGizmosData; +class CommonGizmosDataPool; class Rect { @@ -115,7 +117,8 @@ private: MouseCapture m_mouse_capture; std::string m_tooltip; bool m_serializing; - std::unique_ptr m_common_gizmos_data; + //std::unique_ptr m_common_gizmos_data; + std::unique_ptr m_common_gizmos_data; public: explicit GLGizmosManager(GLCanvas3D& parent); From 593e7a1546ec8a1eaa00be9f1d807aaefeb51a19 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 3 Apr 2020 13:27:04 +0200 Subject: [PATCH 11/28] Flattening gizmo now uses the new CommonDataPool to store pointer to active object --- src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp | 48 +++++++++++------------ src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 29 +++++++++++--- src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 30 ++++++++------ src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 4 ++ 5 files changed, 71 insertions(+), 44 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp index 9fae8893a..7f33916cd 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp @@ -2,6 +2,7 @@ #include "GLGizmoFlatten.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/GUI_App.hpp" +#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" #include @@ -26,20 +27,15 @@ bool GLGizmoFlatten::on_init() void GLGizmoFlatten::on_set_state() { - // m_model_object pointer can be invalid (for instance because of undo/redo action), - // we should recover it from the object id - m_model_object = nullptr; - for (const auto mo : wxGetApp().model().objects) { - if (mo->id() == m_model_object_id) { - m_model_object = mo; - break; - } - } - if (m_state == On && is_plane_update_necessary()) update_planes(); } +CommonGizmosDataID GLGizmoFlatten::on_get_requirements() const +{ + return CommonGizmosDataID::SelectionInfo; +} + std::string GLGizmoFlatten::on_get_name() const { return (_(L("Place on face")) + " [F]").ToUTF8().data(); @@ -132,18 +128,17 @@ void GLGizmoFlatten::on_render_for_picking() const void GLGizmoFlatten::set_flattening_data(const ModelObject* model_object) { m_starting_center = Vec3d::Zero(); - if (m_model_object != model_object) { + if (model_object != m_old_model_object) { m_planes.clear(); m_planes_valid = false; } - m_model_object = model_object; - m_model_object_id = model_object ? model_object->id() : 0; } void GLGizmoFlatten::update_planes() { + const ModelObject* mo = m_c->selection_info()->model_object(); TriangleMesh ch; - for (const ModelVolume* vol : m_model_object->volumes) + for (const ModelVolume* vol : mo->volumes) { if (vol->type() != ModelVolumeType::MODEL_PART) continue; @@ -153,7 +148,7 @@ void GLGizmoFlatten::update_planes() } ch = ch.convex_hull_3d(); m_planes.clear(); - const Transform3d& inst_matrix = m_model_object->instances.front()->get_matrix(true); + const Transform3d& inst_matrix = mo->instances.front()->get_matrix(true); // Following constants are used for discarding too small polygons. const float minimal_area = 5.f; // in square mm (world coordinates) @@ -331,12 +326,13 @@ void GLGizmoFlatten::update_planes() // Planes are finished - let's save what we calculated it from: m_volumes_matrices.clear(); m_volumes_types.clear(); - for (const ModelVolume* vol : m_model_object->volumes) { + for (const ModelVolume* vol : mo->volumes) { m_volumes_matrices.push_back(vol->get_matrix()); m_volumes_types.push_back(vol->type()); } - m_first_instance_scale = m_model_object->instances.front()->get_scaling_factor(); - m_first_instance_mirror = m_model_object->instances.front()->get_mirror(); + m_first_instance_scale = mo->instances.front()->get_scaling_factor(); + m_first_instance_mirror = mo->instances.front()->get_mirror(); + m_old_model_object = mo; m_planes_valid = true; } @@ -344,20 +340,22 @@ void GLGizmoFlatten::update_planes() bool GLGizmoFlatten::is_plane_update_necessary() const { - if (m_state != On || !m_model_object || m_model_object->instances.empty()) + const ModelObject* mo = m_c->selection_info()->model_object(); + if (m_state != On || ! mo || mo->instances.empty()) return false; - if (! m_planes_valid || m_model_object->volumes.size() != m_volumes_matrices.size()) + if (! m_planes_valid || mo != m_old_model_object + || mo->volumes.size() != m_volumes_matrices.size()) return true; // We want to recalculate when the scale changes - some planes could (dis)appear. - if (! m_model_object->instances.front()->get_scaling_factor().isApprox(m_first_instance_scale) - || ! m_model_object->instances.front()->get_mirror().isApprox(m_first_instance_mirror)) + if (! mo->instances.front()->get_scaling_factor().isApprox(m_first_instance_scale) + || ! mo->instances.front()->get_mirror().isApprox(m_first_instance_mirror)) return true; - for (unsigned int i=0; i < m_model_object->volumes.size(); ++i) - if (! m_model_object->volumes[i]->get_matrix().isApprox(m_volumes_matrices[i]) - || m_model_object->volumes[i]->type() != m_volumes_types[i]) + for (unsigned int i=0; i < mo->volumes.size(); ++i) + if (! mo->volumes[i]->get_matrix().isApprox(m_volumes_matrices[i]) + || mo->volumes[i]->type() != m_volumes_types[i]) return true; return false; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp index 9cd2ab6bb..05b4ae4cd 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp @@ -30,8 +30,7 @@ private: std::vector m_planes; bool m_planes_valid = false; mutable Vec3d m_starting_center; - const ModelObject* m_model_object = nullptr; - ObjectID m_model_object_id = 0; + const ModelObject* m_old_model_object = nullptr; std::vector instances_matrices; void update_planes(); @@ -51,6 +50,7 @@ protected: virtual void on_render() const override; virtual void on_render_for_picking() const override; virtual void on_set_state() override; + virtual CommonGizmosDataID on_get_requirements() const override; }; } // namespace GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index bcc562d8b..8022b93f2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -7,11 +7,11 @@ namespace Slic3r { namespace GUI { +using namespace CommonGizmosDataObjects; CommonGizmosDataPool::CommonGizmosDataPool(GLCanvas3D* canvas) : m_canvas(canvas) { - using namespace CommonGizmosDataObjects; using c = CommonGizmosDataID; m_data[c::SelectionInfo].reset( new SelectionInfo(this)); //m_data[c::InstancesHider].reset( new InstancesHider(this)); @@ -24,8 +24,19 @@ CommonGizmosDataPool::CommonGizmosDataPool(GLCanvas3D* canvas) void CommonGizmosDataPool::update(CommonGizmosDataID required) { assert(check_dependencies(required)); - for (auto& [id, data] : m_data) - data->update(int(required) & int(CommonGizmosDataID(id))); + for (auto& [id, data] : m_data) { + if (int(required) & int(CommonGizmosDataID(id))) + data->update(); + else if (data->is_valid()) + data->release(); + } +} + + +SelectionInfo* CommonGizmosDataPool::selection_info() +{ + SelectionInfo* sel_info = dynamic_cast(m_data[CommonGizmosDataID::SelectionInfo].get()); + return sel_info; } #ifndef NDEBUG @@ -41,13 +52,19 @@ bool CommonGizmosDataPool::check_dependencies(CommonGizmosDataID required) const -void CommonGizmosDataObjects::SelectionInfo::update(bool required) +void SelectionInfo::on_update() { Selection selection = m_common->get_canvas()->get_selection(); - + if (selection.is_single_full_instance()) + m_model_object = selection.get_model()->objects[selection.get_object_idx()]; + else + m_model_object = nullptr; } - +void SelectionInfo::on_release() +{ + m_model_object = nullptr; +} } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index 259de5013..3f3854ffa 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -46,10 +46,10 @@ public: // Update all resources and release what is not used. // Accepts a bitmask of currently required resources. - void update(CommonGizmosDataID required = CommonGizmosDataID::None); + void update(CommonGizmosDataID required); // Getters for the data that need to be accessed from the gizmos directly. - CommonGizmosDataObjects::SelectionInfo selection_info(); + CommonGizmosDataObjects::SelectionInfo* selection_info(); GLCanvas3D* get_canvas() const { return m_canvas; } @@ -74,16 +74,21 @@ public: // objects can communicate with one another. explicit CommonGizmosDataBase(CommonGizmosDataPool* cgdp) : m_common{cgdp} {} + virtual ~CommonGizmosDataBase() {} - // Update the resource. If it is not needed (based on argument value) - // any persistent data will be released. - virtual void update(bool required) = 0; + // Update the resource. + void update() { on_update(); m_is_valid = true; } + + // Release any data that are stored internally. + void release() { on_release(); m_is_valid = false; } // Returns whether the resource is currently maintained. bool is_valid() const { return m_is_valid; } protected: CommonGizmosDataPool* m_common = nullptr; + virtual void on_release() = 0; + virtual void on_update() = 0; private: bool m_is_valid = false; @@ -99,13 +104,16 @@ namespace CommonGizmosDataObjects class SelectionInfo : public CommonGizmosDataBase { public: - explicit SelectionInfo(CommonGizmosDataPool* cgdp) : - CommonGizmosDataBase(cgdp) {} - void update(bool required) override; + explicit SelectionInfo(CommonGizmosDataPool* cgdp) + : CommonGizmosDataBase(cgdp) {} - ModelObject* model_object(); + ModelObject* model_object() { return m_model_object; } int get_active_instance(); +protected: + void on_update() override; + void on_release() override; + private: ModelObject* m_model_object = nullptr; int m_active_inst = -1; @@ -115,8 +123,8 @@ private: class InstancesHider : public CommonGizmosDataBase { public: - explicit InstancesHider(CommonGizmosDataPool* cgdp) : - CommonGizmosDataBase(cgdp) {} + explicit InstancesHider(CommonGizmosDataPool* cgdp) + : CommonGizmosDataBase(cgdp) {} void update(bool required) override; }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 9600b3d64..d5be7cd10 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -201,6 +201,10 @@ void GLGizmosManager::update_data() enable_grabber(Scale, i, enable_scale_xyz); } + m_common_gizmos_data->update(get_current() + ? get_current()->get_requirements() + : CommonGizmosDataID(0)); + if (selection.is_single_full_instance()) { // all volumes in the selection belongs to the same instance, any of them contains the needed data, so we take the first From 3db3a6152049bb32f2b37db3af25a55331747aca Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 3 Apr 2020 18:04:37 +0200 Subject: [PATCH 12/28] InstancesHider implementation Any gizmo can now ask for hiding all but the active instance by returning proper value from on_get_requirements --- src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 42 ++++++++++++++++++++--- src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 8 +++-- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 7 ++-- 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index 8022b93f2..3dd604b6b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -14,7 +14,7 @@ CommonGizmosDataPool::CommonGizmosDataPool(GLCanvas3D* canvas) { using c = CommonGizmosDataID; m_data[c::SelectionInfo].reset( new SelectionInfo(this)); - //m_data[c::InstancesHider].reset( new InstancesHider(this)); + m_data[c::InstancesHider].reset( new InstancesHider(this)); //m_data[c::HollowedMesh].reset( new HollowedMesh(this)); //m_data[c::ClippingPlaneWrapper].reset(new ClippingPlaneWrapper(this)); //m_data[c::SupportsClipper].reset( new SupportsClipper(this)); @@ -27,8 +27,10 @@ void CommonGizmosDataPool::update(CommonGizmosDataID required) for (auto& [id, data] : m_data) { if (int(required) & int(CommonGizmosDataID(id))) data->update(); - else if (data->is_valid()) - data->release(); + else + if (data->is_valid()) + data->release(); + } } @@ -36,6 +38,7 @@ void CommonGizmosDataPool::update(CommonGizmosDataID required) SelectionInfo* CommonGizmosDataPool::selection_info() { SelectionInfo* sel_info = dynamic_cast(m_data[CommonGizmosDataID::SelectionInfo].get()); + assert(sel_info->is_valid()); return sel_info; } @@ -54,7 +57,7 @@ bool CommonGizmosDataPool::check_dependencies(CommonGizmosDataID required) const void SelectionInfo::on_update() { - Selection selection = m_common->get_canvas()->get_selection(); + const Selection& selection = m_common->get_canvas()->get_selection(); if (selection.is_single_full_instance()) m_model_object = selection.get_model()->objects[selection.get_object_idx()]; else @@ -66,5 +69,36 @@ void SelectionInfo::on_release() m_model_object = nullptr; } +int SelectionInfo::get_active_instance() +{ + const Selection& selection = m_common->get_canvas()->get_selection(); + return selection.get_instance_idx(); +} + + + + + +void InstancesHider::on_update() +{ + const ModelObject* mo = m_common->selection_info()->model_object(); + int active_inst = m_common->selection_info()->get_active_instance(); + GLCanvas3D* canvas = m_common->get_canvas(); + + if (mo && active_inst != -1) { + canvas->toggle_model_objects_visibility(false); + canvas->toggle_model_objects_visibility(true, mo, active_inst); + } + else + canvas->toggle_model_objects_visibility(true); +} + +void InstancesHider::on_release() +{ + m_common->get_canvas()->toggle_model_objects_visibility(true); +} + + + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index 3f3854ffa..f1840837f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -119,19 +119,21 @@ private: int m_active_inst = -1; }; -/* + class InstancesHider : public CommonGizmosDataBase { public: explicit InstancesHider(CommonGizmosDataPool* cgdp) : CommonGizmosDataBase(cgdp) {} - void update(bool required) override; +protected: + void on_update() override; + void on_release() override; }; - +/* class HollowedMesh : public CommonGizmosDataBase diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index d5be7cd10..26f42ed34 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -1196,10 +1196,13 @@ void GLGizmosManager::activate_gizmo(EType type) return; // gizmo refused to be turned off, do nothing. } + m_current = type; + m_common_gizmos_data->update(get_current() + ? get_current()->get_requirements() + : CommonGizmosDataID(0)); + if (type != Undefined) m_gizmos[type]->set_state(GLGizmoBase::On); - - m_current = type; } From 7e797eaaf8bc77ba10791593b214c1be7dc6d1e2 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 6 Apr 2020 08:06:07 +0200 Subject: [PATCH 13/28] Dependencies check in debug mode Some common resources can depend on each other - this checks that the requirements are consistent --- src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 25 ++++++++++++++++++------ src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 15 +++++++++++++- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index 3dd604b6b..40ac66c71 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -43,11 +43,24 @@ SelectionInfo* CommonGizmosDataPool::selection_info() } #ifndef NDEBUG +// Check the required resources one by one and return true if all +// dependencies are met. bool CommonGizmosDataPool::check_dependencies(CommonGizmosDataID required) const { // This should iterate over currently required data. Each of them should // be asked about its dependencies and it must check that all dependencies // are also in required and before the current one. + for (auto& [id, data] : m_data) { + // in case we don't use this, the deps are irrelevant + if (! (int(required) & int(CommonGizmosDataID(id)))) + continue; + + + CommonGizmosDataID deps = data->get_dependencies(); + assert(int(deps) == (int(deps) & int(required))); + } + + return true; } #endif // NDEBUG @@ -57,7 +70,7 @@ bool CommonGizmosDataPool::check_dependencies(CommonGizmosDataID required) const void SelectionInfo::on_update() { - const Selection& selection = m_common->get_canvas()->get_selection(); + const Selection& selection = get_pool()->get_canvas()->get_selection(); if (selection.is_single_full_instance()) m_model_object = selection.get_model()->objects[selection.get_object_idx()]; else @@ -71,7 +84,7 @@ void SelectionInfo::on_release() int SelectionInfo::get_active_instance() { - const Selection& selection = m_common->get_canvas()->get_selection(); + const Selection& selection = get_pool()->get_canvas()->get_selection(); return selection.get_instance_idx(); } @@ -81,9 +94,9 @@ int SelectionInfo::get_active_instance() void InstancesHider::on_update() { - const ModelObject* mo = m_common->selection_info()->model_object(); - int active_inst = m_common->selection_info()->get_active_instance(); - GLCanvas3D* canvas = m_common->get_canvas(); + const ModelObject* mo = get_pool()->selection_info()->model_object(); + int active_inst = get_pool()->selection_info()->get_active_instance(); + GLCanvas3D* canvas = get_pool()->get_canvas(); if (mo && active_inst != -1) { canvas->toggle_model_objects_visibility(false); @@ -95,7 +108,7 @@ void InstancesHider::on_update() void InstancesHider::on_release() { - m_common->get_canvas()->toggle_model_objects_visibility(true); + get_pool()->get_canvas()->toggle_model_objects_visibility(true); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index f1840837f..5211ca48f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -85,13 +85,22 @@ public: // Returns whether the resource is currently maintained. bool is_valid() const { return m_is_valid; } +#ifndef NDEBUG + // Return a bitmask of all resources that this one relies on. + // The dependent resource must have higher ID than the one + // it depends on. + virtual CommonGizmosDataID get_dependencies() const { return CommonGizmosDataID::None; } +#endif // NDEBUG + protected: - CommonGizmosDataPool* m_common = nullptr; virtual void on_release() = 0; virtual void on_update() = 0; + CommonGizmosDataPool* get_pool() const { return m_common; } + private: bool m_is_valid = false; + CommonGizmosDataPool* m_common = nullptr; }; @@ -125,6 +134,10 @@ class InstancesHider : public CommonGizmosDataBase public: explicit InstancesHider(CommonGizmosDataPool* cgdp) : CommonGizmosDataBase(cgdp) {} +#ifndef NDEBUG + CommonGizmosDataID get_dependencies() const override { return CommonGizmosDataID::SelectionInfo; } +#endif // NDEBUG + protected: void on_update() override; void on_release() override; From 81dba7677bd3fc0183c6ccff2537481a8bbb1af5 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 6 Apr 2020 09:56:00 +0200 Subject: [PATCH 14/28] Hollowed mesh tracker implementation The class tracks state of the backend calculation and if there is a hollowed/drilled mesh, it can provide a pointer to it --- src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 73 +++++++++++++++++++++++- src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 32 +++++++---- 2 files changed, 92 insertions(+), 13 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index 40ac66c71..783081ed2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -3,6 +3,7 @@ #include #include "slic3r/GUI/GLCanvas3D.hpp" +#include "libslic3r/SLAPrint.hpp" namespace Slic3r { namespace GUI { @@ -15,7 +16,7 @@ CommonGizmosDataPool::CommonGizmosDataPool(GLCanvas3D* canvas) using c = CommonGizmosDataID; m_data[c::SelectionInfo].reset( new SelectionInfo(this)); m_data[c::InstancesHider].reset( new InstancesHider(this)); - //m_data[c::HollowedMesh].reset( new HollowedMesh(this)); + m_data[c::HollowedMesh].reset( new HollowedMesh(this)); //m_data[c::ClippingPlaneWrapper].reset(new ClippingPlaneWrapper(this)); //m_data[c::SupportsClipper].reset( new SupportsClipper(this)); //m_data[c::MeshRaycaster].reset( new Raycaster(this)); @@ -38,8 +39,15 @@ void CommonGizmosDataPool::update(CommonGizmosDataID required) SelectionInfo* CommonGizmosDataPool::selection_info() { SelectionInfo* sel_info = dynamic_cast(m_data[CommonGizmosDataID::SelectionInfo].get()); - assert(sel_info->is_valid()); - return sel_info; + assert(sel_info); + return sel_info->is_valid() ? sel_info : nullptr; +} + +HollowedMesh* CommonGizmosDataPool::hollowed_mesh() +{ + HollowedMesh* hol_mesh = dynamic_cast(m_data[CommonGizmosDataID::HollowedMesh].get()); + assert(hol_mesh); + return hol_mesh->is_valid() ? hol_mesh : nullptr; } #ifndef NDEBUG @@ -113,5 +121,64 @@ void InstancesHider::on_release() +void HollowedMesh::on_update() +{ + const ModelObject* mo = get_pool()->selection_info()->model_object(); + if (! mo) + return; + + const GLCanvas3D* canvas = get_pool()->get_canvas(); + const PrintObjects& print_objects = canvas->sla_print()->objects(); + const SLAPrintObject* print_object = m_print_object_idx != -1 + ? print_objects[m_print_object_idx] + : nullptr; + + // Find the respective SLAPrintObject. + if (m_print_object_idx < 0 || m_print_objects_count != int(print_objects.size())) { + m_print_objects_count = print_objects.size(); + m_print_object_idx = -1; + for (const SLAPrintObject* po : print_objects) { + ++m_print_object_idx; + if (po->model_object()->id() == mo->id()) { + print_object = po; + break; + } + } + } + + // If there is a valid SLAPrintObject, check state of Hollowing step. + if (print_object) { + if (print_object->is_step_done(slaposDrillHoles) && print_object->has_mesh(slaposDrillHoles)) { + size_t timestamp = print_object->step_state_with_timestamp(slaposDrillHoles).timestamp; + if (timestamp > m_old_hollowing_timestamp) { + const TriangleMesh& backend_mesh = print_object->get_mesh_to_print(); + m_hollowed_mesh_transformed.reset(new TriangleMesh(backend_mesh)); + Transform3d trafo_inv = canvas->sla_print()->sla_trafo(*mo).inverse(); + m_hollowed_mesh_transformed->transform(trafo_inv); + m_old_hollowing_timestamp = timestamp; + } + } + else { + m_hollowed_mesh_transformed.reset(nullptr); + m_old_hollowing_timestamp = 0; + } + } +} + + +void HollowedMesh::on_release() +{ + m_hollowed_mesh_transformed.reset(); + m_old_hollowing_timestamp = 0; + m_print_object_idx = -1; +} + + +const TriangleMesh* HollowedMesh::get_hollowed_mesh() const +{ + return m_hollowed_mesh_transformed.get(); +} + + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index 5211ca48f..dcd5f862f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -7,6 +7,7 @@ namespace Slic3r { class ModelObject; +class TriangleMesh; namespace GUI { @@ -16,6 +17,8 @@ class GLCanvas3D; class CommonGizmosDataBase; namespace CommonGizmosDataObjects { class SelectionInfo; + class InstancesHider; + class HollowedMesh; } // Some of the gizmos use the same data that need to be updated ocassionally. @@ -50,6 +53,8 @@ public: // Getters for the data that need to be accessed from the gizmos directly. CommonGizmosDataObjects::SelectionInfo* selection_info(); + CommonGizmosDataObjects::HollowedMesh* hollowed_mesh(); + GLCanvas3D* get_canvas() const { return m_canvas; } @@ -129,6 +134,7 @@ private: }; + class InstancesHider : public CommonGizmosDataBase { public: @@ -145,23 +151,29 @@ protected: - -/* - - class HollowedMesh : public CommonGizmosDataBase { public: explicit HollowedMesh(CommonGizmosDataPool* cgdp) : CommonGizmosDataBase(cgdp) {} - void update(bool required) override; +#ifndef NDEBUG + CommonGizmosDataID get_dependencies() const override { return CommonGizmosDataID::SelectionInfo; } +#endif // NDEBUG + + const TriangleMesh* get_hollowed_mesh() const; + +protected: + void on_update() override; + void on_release() override; + +private: + std::unique_ptr m_hollowed_mesh_transformed; + size_t m_old_hollowing_timestamp = 0; + int m_print_object_idx = -1; + int m_print_objects_count = 0; }; - - - - - +/* class ClippingPlaneWrapper : public CommonGizmosDataBase { From bf734c8f689eed87358549520f4fd7febf883e07 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 6 Apr 2020 12:24:04 +0200 Subject: [PATCH 15/28] Raycaster wrapper The raycaster manages a MeshRaycaster object that the gizmo can ask to perform raycasts If the hollowed mesh tracker is enabled and the hollowed mesh is newly calculated/invalidated, the raycaster automatically updates. --- src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 43 +++++++++++++++++++- src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 51 ++++++++++++++---------- 2 files changed, 71 insertions(+), 23 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index 783081ed2..413d5391b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -17,9 +17,10 @@ CommonGizmosDataPool::CommonGizmosDataPool(GLCanvas3D* canvas) m_data[c::SelectionInfo].reset( new SelectionInfo(this)); m_data[c::InstancesHider].reset( new InstancesHider(this)); m_data[c::HollowedMesh].reset( new HollowedMesh(this)); - //m_data[c::ClippingPlaneWrapper].reset(new ClippingPlaneWrapper(this)); + m_data[c::Raycaster].reset( new Raycaster(this)); + //m_data[c::ObjectClipper].reset(new ClippingPlaneWrapper(this)); //m_data[c::SupportsClipper].reset( new SupportsClipper(this)); - //m_data[c::MeshRaycaster].reset( new Raycaster(this)); + } void CommonGizmosDataPool::update(CommonGizmosDataID required) @@ -50,6 +51,13 @@ HollowedMesh* CommonGizmosDataPool::hollowed_mesh() return hol_mesh->is_valid() ? hol_mesh : nullptr; } +Raycaster* CommonGizmosDataPool::raycaster() +{ + Raycaster* rc = dynamic_cast(m_data[CommonGizmosDataID::Raycaster].get()); + assert(rc); + return rc->is_valid() ? rc : nullptr; +} + #ifndef NDEBUG // Check the required resources one by one and return true if all // dependencies are met. @@ -180,5 +188,36 @@ const TriangleMesh* HollowedMesh::get_hollowed_mesh() const } + + + +void Raycaster::on_update() +{ + const ModelObject* mo = get_pool()->selection_info()->model_object(); + + if (! mo) + return; + + const TriangleMesh* mesh = &mo->volumes.front()->mesh(); + const HollowedMesh* hollowed_mesh_tracker = get_pool()->hollowed_mesh(); + if (hollowed_mesh_tracker && hollowed_mesh_tracker->get_hollowed_mesh()) + mesh = hollowed_mesh_tracker->get_hollowed_mesh(); + + if (mesh != m_old_mesh) { + m_raycaster.reset(new MeshRaycaster(*mesh)); + m_old_mesh = mesh; + } +} + +void Raycaster::on_release() +{ + m_raycaster.reset(); + m_old_mesh = nullptr; +} + + + + + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index dcd5f862f..5ebe7fad3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -4,10 +4,11 @@ #include #include +#include "slic3r/GUI/MeshUtils.hpp" + namespace Slic3r { class ModelObject; -class TriangleMesh; namespace GUI { @@ -19,6 +20,7 @@ namespace CommonGizmosDataObjects { class SelectionInfo; class InstancesHider; class HollowedMesh; + class Raycaster; } // Some of the gizmos use the same data that need to be updated ocassionally. @@ -34,9 +36,10 @@ enum class CommonGizmosDataID { SelectionInfo = 1 << 0, InstancesHider = 1 << 1, HollowedMesh = 1 << 2, - ClippingPlaneWrapper = 1 << 3, - SupportsClipper = 1 << 4, - MeshRaycaster = 1 << 5, + Raycaster = 1 << 3, + ObjectClipper = 1 << 4, + SupportsClipper = 1 << 5, + }; @@ -54,6 +57,7 @@ public: // Getters for the data that need to be accessed from the gizmos directly. CommonGizmosDataObjects::SelectionInfo* selection_info(); CommonGizmosDataObjects::HollowedMesh* hollowed_mesh(); + CommonGizmosDataObjects::Raycaster* raycaster(); GLCanvas3D* get_canvas() const { return m_canvas; } @@ -173,6 +177,28 @@ private: int m_print_objects_count = 0; }; + + +class Raycaster : public CommonGizmosDataBase +{ +public: + explicit Raycaster(CommonGizmosDataPool* cgdp) + : CommonGizmosDataBase(cgdp) {} +#ifndef NDEBUG + CommonGizmosDataID get_dependencies() const override { return CommonGizmosDataID::SelectionInfo; } +#endif // NDEBUG + + const MeshRaycaster* raycaster() const { return m_raycaster.get(); } + +protected: + void on_update() override; + void on_release() override; + +private: + std::unique_ptr m_raycaster; + const TriangleMesh* m_old_mesh = nullptr; +}; + /* class ClippingPlaneWrapper : public CommonGizmosDataBase @@ -185,10 +211,6 @@ public: - - - - class SupportsClipper : public CommonGizmosDataBase { public: @@ -197,19 +219,6 @@ public: void update(bool required) override; }; - - - - - - -class Raycaster : public CommonGizmosDataBase -{ -public: - explicit Raycaster(CommonGizmosDataPool* cgdp) - : CommonGizmosDataBase(cgdp) {} - void update(bool required) override; -}; */ } // namespace CommonGizmosDataObjects From d9e5721cb79f5a75a657470941ddd873103f6a1a Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 6 Apr 2020 13:59:28 +0200 Subject: [PATCH 16/28] Raycaster can now handle multiple volumes This is necessary for future FDM supports gizmo. SLA objects only have one volume, so it wasn't needed until now. --- src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 38 ++++++++++++++++++------ src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 7 +++-- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index 413d5391b..ecbe75165 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -198,21 +198,41 @@ void Raycaster::on_update() if (! mo) return; - const TriangleMesh* mesh = &mo->volumes.front()->mesh(); - const HollowedMesh* hollowed_mesh_tracker = get_pool()->hollowed_mesh(); - if (hollowed_mesh_tracker && hollowed_mesh_tracker->get_hollowed_mesh()) - mesh = hollowed_mesh_tracker->get_hollowed_mesh(); + std::vector meshes; + const std::vector& mvs = mo->volumes; + if (mvs.size() == 1) { + assert(mvs.front()->is_model_part()); + const HollowedMesh* hollowed_mesh_tracker = get_pool()->hollowed_mesh(); + if (hollowed_mesh_tracker && hollowed_mesh_tracker->get_hollowed_mesh()) + meshes.push_back(hollowed_mesh_tracker->get_hollowed_mesh()); + } + if (meshes.empty()) { + for (const ModelVolume* mv : mvs) { + if (mv->is_model_part()) + meshes.push_back(&mv->mesh()); + } + } - if (mesh != m_old_mesh) { - m_raycaster.reset(new MeshRaycaster(*mesh)); - m_old_mesh = mesh; + if (meshes != m_old_meshes) { + m_raycasters.clear(); + for (const TriangleMesh* mesh : meshes) + m_raycasters.emplace_back(new MeshRaycaster(*mesh)); + m_old_meshes = meshes; } } void Raycaster::on_release() { - m_raycaster.reset(); - m_old_mesh = nullptr; + m_raycasters.clear(); + m_old_meshes.clear(); +} + +std::vector Raycaster::raycasters() const +{ + std::vector mrcs; + for (const auto& raycaster_unique_ptr : m_raycasters) + mrcs.push_back(raycaster_unique_ptr.get()); + return mrcs; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index 5ebe7fad3..0b327cce8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -188,15 +188,16 @@ public: CommonGizmosDataID get_dependencies() const override { return CommonGizmosDataID::SelectionInfo; } #endif // NDEBUG - const MeshRaycaster* raycaster() const { return m_raycaster.get(); } + const MeshRaycaster* raycaster() const { assert(m_raycasters.size() == 1); return m_raycasters.front().get(); } + std::vector raycasters() const; protected: void on_update() override; void on_release() override; private: - std::unique_ptr m_raycaster; - const TriangleMesh* m_old_mesh = nullptr; + std::vector> m_raycasters; + std::vector m_old_meshes; }; /* From 5d4014a4a5facca910c0d726306bb5fe8a44977d Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 7 Apr 2020 09:29:34 +0200 Subject: [PATCH 17/28] ObjectClipper implementation, hollowing gizmo reenabled ObjectClipper tracks active mesh (incl. possible hollowing), remembers clipping plane position and can render the cut on demand Hollowing gizmo uses the new infrastructure --- src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 275 ++++++++++++---------- src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp | 8 +- src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 109 ++++++++- src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 49 +++- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 13 +- 5 files changed, 305 insertions(+), 149 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index 51e6d7458..f27bc2863 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -2,20 +2,15 @@ #include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/Camera.hpp" #include "slic3r/GUI/Gizmos/GLGizmos.hpp" +#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" #include #include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/GUI_ObjectSettings.hpp" #include "slic3r/GUI/GUI_ObjectList.hpp" -#include "slic3r/GUI/MeshUtils.hpp" #include "slic3r/GUI/Plater.hpp" -#if ENABLE_NON_STATIC_CANVAS_MANAGER -#include "slic3r/GUI/Camera.hpp" -#endif // ENABLE_NON_STATIC_CANVAS_MANAGER #include "slic3r/GUI/PresetBundle.hpp" -#include "libslic3r/SLAPrint.hpp" -#include "libslic3r/TriangleMesh.hpp" namespace Slic3r { @@ -59,7 +54,14 @@ bool GLGizmoHollow::on_init() void GLGizmoHollow::set_sla_support_data(ModelObject*, const Selection&) { - if (m_c->recent_update) { + const ModelObject* mo = m_c->selection_info()->model_object(); + if (mo) { + reload_cache(); + if (m_c->hollowed_mesh()->get_hollowed_mesh()) + m_holes_in_drilled_mesh = mo->sla_drain_holes; + } + + /*if (m_c->recent_update) { if (m_state == On) m_c->build_AABB_if_needed(); @@ -85,7 +87,7 @@ void GLGizmoHollow::set_sla_support_data(ModelObject*, const Selection&) m_parent.toggle_model_objects_visibility(false); m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance); m_parent.toggle_sla_auxiliaries_visibility(m_show_supports, m_c->m_model_object, m_c->m_active_instance); - } + }*/ } @@ -93,12 +95,12 @@ void GLGizmoHollow::set_sla_support_data(ModelObject*, const Selection&) void GLGizmoHollow::on_render() const { const Selection& selection = m_parent.get_selection(); + const CommonGizmosDataObjects::SelectionInfo* sel_info = m_c->selection_info(); // If current m_c->m_model_object does not match selection, ask GLCanvas3D to turn us off if (m_state == On - && (m_c->m_model_object != selection.get_model()->objects[selection.get_object_idx()] - || m_c->m_active_instance != selection.get_instance_idx() - || m_c->m_model_object_id != m_c->m_model_object->id())) { + && (sel_info->model_object() != selection.get_model()->objects[selection.get_object_idx()] + || sel_info->get_active_instance() != selection.get_instance_idx())) { m_parent.post_event(SimpleEvent(EVT_GLCANVAS_RESETGIZMOS)); return; } @@ -106,13 +108,14 @@ void GLGizmoHollow::on_render() const glsafe(::glEnable(GL_BLEND)); glsafe(::glEnable(GL_DEPTH_TEST)); - m_z_shift = selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z(); + //m_z_shift = selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z(); if (m_quadric != nullptr && selection.is_from_single_instance()) render_points(selection, false); m_selection_rectangle.render(m_parent); - render_clipping_plane(selection); + //render_clipping_plane(selection); + m_c->object_clipper()->render_cut(); glsafe(::glDisable(GL_BLEND)); } @@ -121,6 +124,8 @@ void GLGizmoHollow::on_render() const void GLGizmoHollow::render_clipping_plane(const Selection& selection) const { + return; +/* if (m_c->m_clipping_plane_distance == 0.f) return; @@ -189,6 +194,7 @@ void GLGizmoHollow::render_clipping_plane(const Selection& selection) const ::glEnd(); ::glPopMatrix(); } +*/ } @@ -217,13 +223,14 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) cons glsafe(::glMultMatrixd(instance_matrix.data())); float render_color[4]; - size_t cache_size = m_c->m_model_object->sla_drain_holes.size(); + const sla::DrainHoles& drain_holes = m_c->selection_info()->model_object()->sla_drain_holes; + size_t cache_size = drain_holes.size(); for (size_t i = 0; i < cache_size; ++i) { - const sla::DrainHole& drain_hole = m_c->m_model_object->sla_drain_holes[i]; + const sla::DrainHole& drain_hole = drain_holes[i]; const bool& point_selected = m_selected[i]; - if (is_mesh_point_clipped((drain_hole.pos+m_c->HoleStickOutLength*drain_hole.normal).cast())) + if (is_mesh_point_clipped((drain_hole.pos+HoleStickOutLength*drain_hole.normal).cast())) continue; // First decide about the color of the point. @@ -297,12 +304,17 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) cons bool GLGizmoHollow::is_mesh_point_clipped(const Vec3d& point) const { - if (m_c->m_clipping_plane_distance == 0.f) + if (m_c->object_clipper()->get_position() == 0.) return false; - Vec3d transformed_point = m_c->m_model_object->instances[m_c->m_active_instance]->get_transformation().get_matrix() * point; - transformed_point(2) += m_z_shift; - return m_c->m_clipping_plane->is_point_clipped(transformed_point); + auto sel_info = m_c->selection_info(); + int active_inst = m_c->selection_info()->get_active_instance(); + const ModelInstance* mi = sel_info->model_object()->instances[active_inst]; + const Transform3d& trafo = mi->get_transformation().get_matrix(); + + Vec3d transformed_point = trafo * point; + transformed_point(2) += sel_info->get_sla_shift(); + return m_c->object_clipper()->get_clipping_plane()->is_point_clipped(transformed_point); } @@ -311,7 +323,7 @@ bool GLGizmoHollow::is_mesh_point_clipped(const Vec3d& point) const // Return false if no intersection was found, true otherwise. bool GLGizmoHollow::unproject_on_mesh(const Vec2d& mouse_pos, std::pair& pos_and_normal) { - if (! m_c->m_mesh_raycaster) + if (! m_c->raycaster()->raycaster()) return false; #if ENABLE_NON_STATIC_CANVAS_MANAGER @@ -322,20 +334,23 @@ bool GLGizmoHollow::unproject_on_mesh(const Vec2d& mouse_pos, std::pairget_instance_transformation(); - trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_z_shift)); + trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_c->selection_info()->get_sla_shift())); + + double clp_dist = m_c->object_clipper()->get_position(); + const ClippingPlane* clp = m_c->object_clipper()->get_clipping_plane(); // The raycaster query Vec3f hit; Vec3f normal; - if (m_c->m_mesh_raycaster->unproject_on_mesh( + if (m_c->raycaster()->raycaster()->unproject_on_mesh( mouse_pos, trafo.get_matrix(), camera, hit, normal, - m_c->m_clipping_plane_distance != 0.f ? m_c->m_clipping_plane.get() : nullptr)) + clp_dist != 0. ? clp : nullptr)) { - if (m_c->has_drilled_mesh()) { + if (m_c->hollowed_mesh() && m_c->hollowed_mesh()->get_hollowed_mesh()) { // in this case the raycaster sees the hollowed and drilled mesh. // if the point lies on the surface created by the hole, we want // to ignore it. @@ -362,6 +377,10 @@ bool GLGizmoHollow::unproject_on_mesh(const Vec2d& mouse_pos, std::pairselection_info()->model_object(); + int active_inst = m_c->selection_info()->get_active_instance(); + + // left down with shift - show the selection rectangle: if (action == SLAGizmoEventType::LeftDown && (shift_down || alt_down || control_down)) { if (m_hover_id == -1) { @@ -393,15 +412,15 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos if (unproject_on_mesh(mouse_position, pos_and_normal)) { // we got an intersection Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Add drainage hole"))); - Vec3d scaling = m_c->m_model_object->instances[m_c->m_active_instance]->get_scaling_factor(); + Vec3d scaling = mo->instances[active_inst]->get_scaling_factor(); Vec3f normal_transformed(pos_and_normal.second(0)/scaling(0), pos_and_normal.second(1)/scaling(1), pos_and_normal.second(2)/scaling(2)); - m_c->m_model_object->sla_drain_holes.emplace_back(pos_and_normal.first + m_c->HoleStickOutLength * pos_and_normal.second/* normal_transformed.normalized()*/, + mo->sla_drain_holes.emplace_back(pos_and_normal.first + HoleStickOutLength * pos_and_normal.second/* normal_transformed.normalized()*/, -pos_and_normal.second, m_new_hole_radius, m_new_hole_height); m_selected.push_back(false); - assert(m_selected.size() == m_c->m_model_object->sla_drain_holes.size()); + assert(m_selected.size() == mo->sla_drain_holes.size()); m_parent.set_as_dirty(); m_wait_for_up_event = true; } @@ -420,11 +439,11 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos GLSelectionRectangle::EState rectangle_status = m_selection_rectangle.get_state(); // First collect positions of all the points in world coordinates. - Geometry::Transformation trafo = m_c->m_model_object->instances[m_c->m_active_instance]->get_transformation(); + Geometry::Transformation trafo = mo->instances[active_inst]->get_transformation(); trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_z_shift)); std::vector points; - for (unsigned int i=0; im_model_object->sla_drain_holes.size(); ++i) - points.push_back(trafo.get_matrix() * m_c->m_model_object->sla_drain_holes[i].pos.cast()); + for (unsigned int i=0; isla_drain_holes.size(); ++i) + points.push_back(trafo.get_matrix() * mo->sla_drain_holes[i].pos.cast()); // Now ask the rectangle which of the points are inside. std::vector points_inside; @@ -434,7 +453,9 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos // Only select/deselect points that are actually visible #if ENABLE_NON_STATIC_CANVAS_MANAGER - for (size_t idx : m_c->m_mesh_raycaster->get_unobscured_idxs(trafo, wxGetApp().plater()->get_camera(), points_inside, m_c->m_clipping_plane.get())) + for (size_t idx : m_c->raycaster()->raycaster()->get_unobscured_idxs( + trafo, wxGetApp().plater()->get_camera(), points_inside, + m_c->object_clipper()->get_clipping_plane())) #else for (size_t idx : m_c->m_mesh_raycaster->get_unobscured_idxs(trafo, m_parent.get_camera(), points_inside, m_c->m_clipping_plane.get())) #endif // ENABLE_NON_STATIC_CANVAS_MANAGER @@ -491,20 +512,24 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos } if (action == SLAGizmoEventType::MouseWheelUp && control_down) { - m_c->m_clipping_plane_distance = std::min(1.f, m_c->m_clipping_plane_distance + 0.01f); - update_clipping_plane(m_c->m_clipping_plane_was_moved); - m_c->m_clipping_plane_was_moved = true; + double pos = m_c->object_clipper()->get_position(); + pos = std::min(1., pos + 0.01); + m_c->object_clipper()->set_position(pos, true); + //update_clipping_plane(/*m_c->m_clipping_plane_was_moved*/); + //m_c->m_clipping_plane_was_moved = true; return true; } if (action == SLAGizmoEventType::MouseWheelDown && control_down) { - m_c->m_clipping_plane_distance = std::max(0.f, m_c->m_clipping_plane_distance - 0.01f); - update_clipping_plane(true); + double pos = m_c->object_clipper()->get_position(); + pos = std::max(0., pos - 0.01); + m_c->object_clipper()->set_position(pos, true); + //update_clipping_plane(true); return true; } if (action == SLAGizmoEventType::ResetClippingPlane) { - update_clipping_plane(); + m_c->object_clipper()->set_position(-1., false); return true; } @@ -514,11 +539,12 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos void GLGizmoHollow::delete_selected_points() { Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Delete drainage hole"))); + sla::DrainHoles& drain_holes = m_c->selection_info()->model_object()->sla_drain_holes; - for (unsigned int idx=0; idxm_model_object->sla_drain_holes.size(); ++idx) { + for (unsigned int idx=0; idxm_model_object->sla_drain_holes.erase(m_c->m_model_object->sla_drain_holes.begin() + (idx--)); + drain_holes.erase(drain_holes.begin() + (idx--)); } } @@ -527,12 +553,14 @@ void GLGizmoHollow::delete_selected_points() void GLGizmoHollow::on_update(const UpdateData& data) { + sla::DrainHoles& drain_holes = m_c->selection_info()->model_object()->sla_drain_holes; + if (m_hover_id != -1) { std::pair pos_and_normal; if (! unproject_on_mesh(data.mouse_pos.cast(), pos_and_normal)) return; - m_c->m_model_object->sla_drain_holes[m_hover_id].pos = pos_and_normal.first + m_c->HoleStickOutLength * pos_and_normal.second; - m_c->m_model_object->sla_drain_holes[m_hover_id].normal = -pos_and_normal.second; + drain_holes[m_hover_id].pos = pos_and_normal.first + HoleStickOutLength * pos_and_normal.second; + drain_holes[m_hover_id].normal = -pos_and_normal.second; } } @@ -540,19 +568,22 @@ void GLGizmoHollow::on_update(const UpdateData& data) void GLGizmoHollow::hollow_mesh(bool postpone_error_messages) { wxGetApp().CallAfter([this, postpone_error_messages]() { - wxGetApp().plater()->reslice_SLA_hollowing(*m_c->m_model_object, postpone_error_messages); + wxGetApp().plater()->reslice_SLA_hollowing( + *m_c->selection_info()->model_object(), postpone_error_messages); }); } -std::vector> GLGizmoHollow::get_config_options(const std::vector& keys) const +std::vector> +GLGizmoHollow::get_config_options(const std::vector& keys) const { std::vector> out; + const ModelObject* mo = m_c->selection_info()->model_object(); - if (!m_c->m_model_object) + if (! mo) return out; - const DynamicPrintConfig& object_cfg = m_c->m_model_object->config; + const DynamicPrintConfig& object_cfg = mo->config; const DynamicPrintConfig& print_cfg = wxGetApp().preset_bundle->sla_prints.get_edited_preset().config; std::unique_ptr default_cfg = nullptr; @@ -575,16 +606,21 @@ std::vector> GLGizmoHollo ClippingPlane GLGizmoHollow::get_sla_clipping_plane() const { - if (!m_c->m_model_object || m_state == Off || m_c->m_clipping_plane_distance == 0.f) + if (! m_c->selection_info()->model_object() + || m_state == Off + || m_c->object_clipper()->get_position() == 0.) return ClippingPlane::ClipsNothing(); - else - return ClippingPlane(-m_c->m_clipping_plane->get_normal(), m_c->m_clipping_plane->get_data()[3]); + else { + const ClippingPlane& clp = *m_c->object_clipper()->get_clipping_plane(); + return ClippingPlane(-clp.get_normal(), clp.get_data()[3]); + } } void GLGizmoHollow::on_render_input_window(float x, float y, float bottom_limit) { - if (! m_c->m_model_object) + ModelObject* mo = m_c->selection_info()->model_object(); + if (! mo) return; bool first_run = true; // This is a hack to redraw the button when all points are removed, @@ -650,7 +686,7 @@ RENDER_AGAIN: auto opts = get_config_options({"hollowing_enable"}); m_enable_hollowing = static_cast(opts[0].first)->value; if (m_imgui->checkbox(m_desc["enable"], m_enable_hollowing)) { - m_c->m_model_object->config.opt("hollowing_enable", true)->value = m_enable_hollowing; + mo->config.opt("hollowing_enable", true)->value = m_enable_hollowing; wxGetApp().obj_list()->update_and_show_object_settings_item(); config_changed = true; } @@ -712,14 +748,14 @@ RENDER_AGAIN: } if (slider_edited || slider_released) { if (slider_released) { - m_c->m_model_object->config.opt("hollowing_min_thickness", true)->value = m_offset_stash; - m_c->m_model_object->config.opt("hollowing_quality", true)->value = m_quality_stash; - m_c->m_model_object->config.opt("hollowing_closing_distance", true)->value = m_closing_d_stash; + mo->config.opt("hollowing_min_thickness", true)->value = m_offset_stash; + mo->config.opt("hollowing_quality", true)->value = m_quality_stash; + mo->config.opt("hollowing_closing_distance", true)->value = m_closing_d_stash; Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Hollowing parameter change"))); } - m_c->m_model_object->config.opt("hollowing_min_thickness", true)->value = offset; - m_c->m_model_object->config.opt("hollowing_quality", true)->value = quality; - m_c->m_model_object->config.opt("hollowing_closing_distance", true)->value = closing_d; + mo->config.opt("hollowing_min_thickness", true)->value = offset; + mo->config.opt("hollowing_quality", true)->value = quality; + mo->config.opt("hollowing_closing_distance", true)->value = closing_d; if (slider_released) { wxGetApp().obj_list()->update_and_show_object_settings_item(); config_changed = true; @@ -750,9 +786,9 @@ RENDER_AGAIN: m_imgui->text(m_desc["hole_depth"]); ImGui::SameLine(diameter_slider_left); - m_new_hole_height -= m_c->HoleStickOutLength; + m_new_hole_height -= HoleStickOutLength; ImGui::SliderFloat(" ", &m_new_hole_height, 0.f, 10.f, "%.1f mm"); - m_new_hole_height += m_c->HoleStickOutLength; + m_new_hole_height += HoleStickOutLength; clicked |= ImGui::IsItemClicked(); edited |= ImGui::IsItemEdited(); @@ -764,19 +800,19 @@ RENDER_AGAIN: // - take correct undo/redo snapshot after the user is done with moving the slider if (! m_selection_empty) { if (clicked) { - m_holes_stash = m_c->m_model_object->sla_drain_holes; + m_holes_stash = mo->sla_drain_holes; } if (edited) { for (size_t idx=0; idxm_model_object->sla_drain_holes[idx].radius = m_new_hole_radius; - m_c->m_model_object->sla_drain_holes[idx].height = m_new_hole_height; + mo->sla_drain_holes[idx].radius = m_new_hole_radius; + mo->sla_drain_holes[idx].height = m_new_hole_height; } } if (deactivated) { // momentarily restore the old value to take snapshot - sla::DrainHoles new_holes = m_c->m_model_object->sla_drain_holes; - m_c->m_model_object->sla_drain_holes = m_holes_stash; + sla::DrainHoles new_holes = mo->sla_drain_holes; + mo->sla_drain_holes = m_holes_stash; float backup_rad = m_new_hole_radius; float backup_hei = m_new_hole_height; for (size_t i=0; im_model_object->sla_drain_holes = new_holes; + mo->sla_drain_holes = new_holes; } } @@ -797,35 +833,35 @@ RENDER_AGAIN: remove_selected = m_imgui->button(m_desc.at("remove_selected")); m_imgui->disabled_end(); - m_imgui->disabled_begin(m_c->m_model_object->sla_drain_holes.empty()); + m_imgui->disabled_begin(mo->sla_drain_holes.empty()); remove_all = m_imgui->button(m_desc.at("remove_all")); m_imgui->disabled_end(); // Following is rendered in both editing and non-editing mode: // m_imgui->text(""); ImGui::Separator(); - if (m_c->m_clipping_plane_distance == 0.f) + if (m_c->object_clipper()->get_position() == 0.f) m_imgui->text(m_desc.at("clipping_of_view")); else { if (m_imgui->button(m_desc.at("reset_direction"))) { wxGetApp().CallAfter([this](){ - update_clipping_plane(); + m_c->object_clipper()->set_position(-1., false); }); } } ImGui::SameLine(clipping_slider_left); ImGui::PushItemWidth(window_width - clipping_slider_left); - if (ImGui::SliderFloat(" ", &m_c->m_clipping_plane_distance, 0.f, 1.f, "%.2f")) { - update_clipping_plane(m_c->m_clipping_plane_was_moved); - m_c->m_clipping_plane_was_moved = true; - } + float clp_dist = m_c->object_clipper()->get_position(); + if (ImGui::SliderFloat(" ", &clp_dist, 0.f, 1.f, "%.2f")) + m_c->object_clipper()->set_position(clp_dist, true); // make sure supports are shown/hidden as appropriate - if (m_imgui->checkbox(m_desc["show_supports"], m_show_supports)) { - m_parent.toggle_sla_auxiliaries_visibility(m_show_supports, m_c->m_model_object, m_c->m_active_instance); - force_refresh = true; - } + // DODELAT + //if (m_imgui->checkbox(m_desc["show_supports"], m_show_supports)) { + // m_parent.toggle_sla_auxiliaries_visibility(m_show_supports, mo, m_c->m_active_instance); + // force_refresh = true; + //} m_imgui->end(); @@ -882,18 +918,28 @@ std::string GLGizmoHollow::on_get_name() const } +CommonGizmosDataID GLGizmoHollow::on_get_requirements() const +{ + return CommonGizmosDataID( + int(CommonGizmosDataID::SelectionInfo) + | int(CommonGizmosDataID::InstancesHider) + | int(CommonGizmosDataID::Raycaster) + | int(CommonGizmosDataID::HollowedMesh) + | int(CommonGizmosDataID::ObjectClipper)); +} + void GLGizmoHollow::on_set_state() { // m_c->m_model_object pointer can be invalid (for instance because of undo/redo action), // we should recover it from the object id - m_c->m_model_object = nullptr; + /*m_c->m_model_object = nullptr; for (const auto mo : wxGetApp().model().objects) { if (mo->id() == m_c->m_model_object_id) { m_c->m_model_object = mo; break; } - } + }*/ if (m_state == m_old_state) return; @@ -901,31 +947,31 @@ void GLGizmoHollow::on_set_state() if (m_state == On && m_old_state != On) { // the gizmo was just turned on //Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned on"))); //m_c->update_from_backend(m_parent, m_c->m_model_object); - m_c->unstash_clipping_plane(); - update_clipping_plane(m_c->m_clipping_plane_was_moved); + //m_c->unstash_clipping_plane(); + //update_clipping_plane(/*m_c->m_clipping_plane_was_moved*/); - m_c->build_AABB_if_needed(); + //m_c->build_AABB_if_needed(); // we'll now reload support points: - if (m_c->m_model_object) + if (m_c->selection_info()->model_object()) reload_cache(); - m_parent.toggle_model_objects_visibility(false); + /*m_parent.toggle_model_objects_visibility(false); if (m_c->m_model_object) { m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance); m_parent.toggle_sla_auxiliaries_visibility(m_show_supports, m_c->m_model_object, m_c->m_active_instance); - } + }*/ } if (m_state == Off && m_old_state != Off) { // the gizmo was just turned Off //Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned off"))); m_parent.post_event(SimpleEvent(EVT_GLCANVAS_FORCE_UPDATE)); m_parent.toggle_model_objects_visibility(true); - m_c->stash_clipping_plane(); - m_c->m_clipping_plane_distance = 0.f; - update_clipping_plane(true); + //m_c->stash_clipping_plane(); + //m_c->m_clipping_plane_distance = 0.f; + //update_clipping_plane(true); // Release clippers and the AABB raycaster. - m_c->m_object_clipper.reset(); - m_c->m_supports_clipper.reset(); + //m_c->m_object_clipper.reset(); + //m_c->m_supports_clipper.reset(); //m_c->m_mesh_raycaster.reset(); //m_c->m_cavity_mesh.reset(); //m_c->m_volume_with_cavity.reset(); @@ -940,7 +986,7 @@ void GLGizmoHollow::on_start_dragging() if (m_hover_id != -1) { select_point(NoPoints); select_point(m_hover_id); - m_hole_before_drag = m_c->m_model_object->sla_drain_holes[m_hover_id].pos; + m_hole_before_drag = m_c->selection_info()->model_object()->sla_drain_holes[m_hover_id].pos; } else m_hole_before_drag = Vec3f::Zero(); @@ -949,15 +995,16 @@ void GLGizmoHollow::on_start_dragging() void GLGizmoHollow::on_stop_dragging() { + sla::DrainHoles& drain_holes = m_c->selection_info()->model_object()->sla_drain_holes; if (m_hover_id != -1) { - Vec3f backup = m_c->m_model_object->sla_drain_holes[m_hover_id].pos; + Vec3f backup = drain_holes[m_hover_id].pos; if (m_hole_before_drag != Vec3f::Zero() // some point was touched && backup != m_hole_before_drag) // and it was moved, not just selected { - m_c->m_model_object->sla_drain_holes[m_hover_id].pos = m_hole_before_drag; + drain_holes[m_hover_id].pos = m_hole_before_drag; Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Move drainage hole"))); - m_c->m_model_object->sla_drain_holes[m_hover_id].pos = backup; + drain_holes[m_hover_id].pos = backup; } } m_hole_before_drag = Vec3f::Zero(); @@ -967,10 +1014,7 @@ void GLGizmoHollow::on_stop_dragging() void GLGizmoHollow::on_load(cereal::BinaryInputArchive& ar) { - ar(m_c->m_clipping_plane_distance, - *m_c->m_clipping_plane, - m_c->m_model_object_id, - m_new_hole_radius, + ar(m_new_hole_radius, m_new_hole_height, m_selected, m_selection_empty @@ -981,10 +1025,7 @@ void GLGizmoHollow::on_load(cereal::BinaryInputArchive& ar) void GLGizmoHollow::on_save(cereal::BinaryOutputArchive& ar) const { - ar(m_c->m_clipping_plane_distance, - *m_c->m_clipping_plane, - m_c->m_model_object_id, - m_new_hole_radius, + ar(m_new_hole_radius, m_new_hole_height, m_selected, m_selection_empty @@ -995,13 +1036,15 @@ void GLGizmoHollow::on_save(cereal::BinaryOutputArchive& ar) const void GLGizmoHollow::select_point(int i) { + const sla::DrainHoles& drain_holes = m_c->selection_info()->model_object()->sla_drain_holes; + if (i == AllPoints || i == NoPoints) { m_selected.assign(m_selected.size(), i == AllPoints); m_selection_empty = (i == NoPoints); if (i == AllPoints) { - m_new_hole_radius = m_c->m_model_object->sla_drain_holes[0].radius; - m_new_hole_height = m_c->m_model_object->sla_drain_holes[0].height; + m_new_hole_radius = drain_holes[0].radius; + m_new_hole_height = drain_holes[0].height; } } else { @@ -1009,8 +1052,8 @@ void GLGizmoHollow::select_point(int i) m_selected.push_back(false); m_selected[i] = true; m_selection_empty = false; - m_new_hole_radius = m_c->m_model_object->sla_drain_holes[i].radius; - m_new_hole_height = m_c->m_model_object->sla_drain_holes[i].height; + m_new_hole_radius = drain_holes[i].radius; + m_new_hole_height = drain_holes[i].height; } } @@ -1030,31 +1073,13 @@ void GLGizmoHollow::unselect_point(int i) void GLGizmoHollow::reload_cache() { m_selected.clear(); - m_selected.assign(m_c->m_model_object->sla_drain_holes.size(), false); -} - -void GLGizmoHollow::update_clipping_plane(bool keep_normal) const -{ - if (! m_c->m_model_object) - return; -#if ENABLE_NON_STATIC_CANVAS_MANAGER - Vec3d normal = (keep_normal && m_c->m_clipping_plane->get_normal() != Vec3d::Zero() ? - m_c->m_clipping_plane->get_normal() : -wxGetApp().plater()->get_camera().get_dir_forward()); -#else - Vec3d normal = (keep_normal && m_c->m_clipping_plane->get_normal() != Vec3d::Zero() ? - m_c->m_clipping_plane->get_normal() : -m_parent.get_camera().get_dir_forward()); -#endif // ENABLE_NON_STATIC_CANVAS_MANAGER - - const Vec3d& center = m_c->m_model_object->instances[m_c->m_active_instance]->get_offset() + Vec3d(0., 0., m_z_shift); - float dist = normal.dot(center); - *m_c->m_clipping_plane = ClippingPlane(normal, (dist - (-m_c->m_active_instance_bb_radius) - m_c->m_clipping_plane_distance * 2*m_c->m_active_instance_bb_radius)); - m_parent.set_as_dirty(); + m_selected.assign(m_c->selection_info()->model_object()->sla_drain_holes.size(), false); } void GLGizmoHollow::on_set_hover_id() { - if (int(m_c->m_model_object->sla_drain_holes.size()) <= m_hover_id) + if (int(m_c->selection_info()->model_object()->sla_drain_holes.size()) <= m_hover_id) m_hover_id = -1; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp index 3aafcbf55..a33721519 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp @@ -16,7 +16,7 @@ namespace GUI { class ClippingPlane; class MeshClipper; class MeshRaycaster; -class CommonGizmosData; +//class CommonGizmosData; enum class SLAGizmoEventType : unsigned char; class GLGizmoHollow : public GLGizmoBase @@ -37,8 +37,7 @@ public: ClippingPlane get_sla_clipping_plane() const; bool is_selection_rectangle_dragging() const { return m_selection_rectangle.is_dragging(); } - void update_clipping_plane(bool keep_normal = false) const; - void set_common_data_ptr(CommonGizmosData* ptr) { m_c = ptr; } + //void set_common_data_ptr(CommonGizmosData* ptr) { m_c = ptr; } private: bool on_init() override; @@ -68,7 +67,7 @@ private: sla::DrainHoles m_holes_stash; - CommonGizmosData* m_c = nullptr; + //CommonGizmosData* m_c = nullptr; //std::unique_ptr m_clipping_plane; @@ -101,6 +100,7 @@ protected: void on_start_dragging() override; void on_stop_dragging() override; void on_render_input_window(float x, float y, float bottom_limit) override; + virtual CommonGizmosDataID on_get_requirements() const override; std::string on_get_name() const override; bool on_is_activable() const override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index ecbe75165..792fd0e91 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -4,6 +4,10 @@ #include "slic3r/GUI/GLCanvas3D.hpp" #include "libslic3r/SLAPrint.hpp" +#include "slic3r/GUI/GUI_App.hpp" +#include "slic3r/GUI/Camera.hpp" + +#include namespace Slic3r { namespace GUI { @@ -18,7 +22,7 @@ CommonGizmosDataPool::CommonGizmosDataPool(GLCanvas3D* canvas) m_data[c::InstancesHider].reset( new InstancesHider(this)); m_data[c::HollowedMesh].reset( new HollowedMesh(this)); m_data[c::Raycaster].reset( new Raycaster(this)); - //m_data[c::ObjectClipper].reset(new ClippingPlaneWrapper(this)); + m_data[c::ObjectClipper].reset(new ObjectClipper(this)); //m_data[c::SupportsClipper].reset( new SupportsClipper(this)); } @@ -37,27 +41,34 @@ void CommonGizmosDataPool::update(CommonGizmosDataID required) } -SelectionInfo* CommonGizmosDataPool::selection_info() +SelectionInfo* CommonGizmosDataPool::selection_info() const { - SelectionInfo* sel_info = dynamic_cast(m_data[CommonGizmosDataID::SelectionInfo].get()); + SelectionInfo* sel_info = dynamic_cast(m_data.at(CommonGizmosDataID::SelectionInfo).get()); assert(sel_info); return sel_info->is_valid() ? sel_info : nullptr; } -HollowedMesh* CommonGizmosDataPool::hollowed_mesh() +HollowedMesh* CommonGizmosDataPool::hollowed_mesh() const { - HollowedMesh* hol_mesh = dynamic_cast(m_data[CommonGizmosDataID::HollowedMesh].get()); + HollowedMesh* hol_mesh = dynamic_cast(m_data.at(CommonGizmosDataID::HollowedMesh).get()); assert(hol_mesh); return hol_mesh->is_valid() ? hol_mesh : nullptr; } -Raycaster* CommonGizmosDataPool::raycaster() +Raycaster* CommonGizmosDataPool::raycaster() const { - Raycaster* rc = dynamic_cast(m_data[CommonGizmosDataID::Raycaster].get()); + Raycaster* rc = dynamic_cast(m_data.at(CommonGizmosDataID::Raycaster).get()); assert(rc); return rc->is_valid() ? rc : nullptr; } +ObjectClipper* CommonGizmosDataPool::object_clipper() const +{ + ObjectClipper* oc = dynamic_cast(m_data.at(CommonGizmosDataID::ObjectClipper).get()); + assert(oc); + return oc->is_valid() ? oc : nullptr; +} + #ifndef NDEBUG // Check the required resources one by one and return true if all // dependencies are met. @@ -87,8 +98,10 @@ bool CommonGizmosDataPool::check_dependencies(CommonGizmosDataID required) const void SelectionInfo::on_update() { const Selection& selection = get_pool()->get_canvas()->get_selection(); - if (selection.is_single_full_instance()) + if (selection.is_single_full_instance()) { m_model_object = selection.get_model()->objects[selection.get_object_idx()]; + m_z_shift = selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z(); + } else m_model_object = nullptr; } @@ -98,7 +111,7 @@ void SelectionInfo::on_release() m_model_object = nullptr; } -int SelectionInfo::get_active_instance() +int SelectionInfo::get_active_instance() const { const Selection& selection = get_pool()->get_canvas()->get_selection(); return selection.get_instance_idx(); @@ -239,5 +252,83 @@ std::vector Raycaster::raycasters() const +void ObjectClipper::on_update() +{ + const ModelObject* mo = get_pool()->selection_info()->model_object(); + if (! mo) + return; + + // which mesh should be cut? + const TriangleMesh* mesh = &mo->volumes.front()->mesh(); + bool has_hollowed = get_pool()->hollowed_mesh() && get_pool()->hollowed_mesh()->get_hollowed_mesh(); + if (has_hollowed) + mesh = get_pool()->hollowed_mesh()->get_hollowed_mesh(); + + if (mesh != m_old_mesh) { + m_clipper.reset(new MeshClipper); + m_clipper->set_mesh(*mesh); + m_old_mesh = mesh; + m_active_inst_bb_radius = + mo->instance_bounding_box(get_pool()->selection_info()->get_active_instance()).radius(); + //if (has_hollowed && m_clp_ratio != 0.) + // m_clp_ratio = 0.25; + } +} + + +void ObjectClipper::on_release() +{ + m_clipper.reset(); + m_old_mesh = nullptr; + m_clp.reset(); + +} + +void ObjectClipper::render_cut() const +{ + if (m_clp_ratio == 0.) + return; + const SelectionInfo* sel_info = get_pool()->selection_info(); + const ModelObject* mo = sel_info->model_object(); + Geometry::Transformation inst_trafo = mo->instances[sel_info->get_active_instance()]->get_transformation(); + Geometry::Transformation vol_trafo = mo->volumes.front()->get_transformation(); + Geometry::Transformation trafo = inst_trafo * vol_trafo; + trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., sel_info->get_sla_shift())); + + m_clipper->set_plane(*m_clp); + m_clipper->set_transformation(trafo); + + if (! m_clipper->get_triangles().empty()) { + ::glPushMatrix(); + ::glColor3f(1.0f, 0.37f, 0.0f); + ::glBegin(GL_TRIANGLES); + for (const Vec3f& point : m_clipper->get_triangles()) + ::glVertex3f(point(0), point(1), point(2)); + ::glEnd(); + ::glPopMatrix(); + } +} + + +void ObjectClipper::set_position(double pos, bool keep_normal) +{ + const ModelObject* mo = get_pool()->selection_info()->model_object(); + int active_inst = get_pool()->selection_info()->get_active_instance(); + double z_shift = get_pool()->selection_info()->get_sla_shift(); + + Vec3d normal = (keep_normal && m_clp) ? m_clp->get_normal() : -wxGetApp().plater()->get_camera().get_dir_forward(); + const Vec3d& center = mo->instances[active_inst]->get_offset() + Vec3d(0., 0., z_shift); + float dist = normal.dot(center); + + if (pos < 0.) + pos = m_clp_ratio; + + m_clp_ratio = pos; + m_clp.reset(new ClippingPlane(normal, (dist - (-m_active_inst_bb_radius) - m_clp_ratio * 2*m_active_inst_bb_radius))); + get_pool()->get_canvas()->set_as_dirty(); +} + + + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index 0b327cce8..7a9cb35b8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -15,12 +15,17 @@ namespace GUI { class GLCanvas3D; +static constexpr float HoleStickOutLength = 1.f; + + + class CommonGizmosDataBase; namespace CommonGizmosDataObjects { class SelectionInfo; class InstancesHider; class HollowedMesh; class Raycaster; + class ObjectClipper; } // Some of the gizmos use the same data that need to be updated ocassionally. @@ -55,9 +60,10 @@ public: void update(CommonGizmosDataID required); // Getters for the data that need to be accessed from the gizmos directly. - CommonGizmosDataObjects::SelectionInfo* selection_info(); - CommonGizmosDataObjects::HollowedMesh* hollowed_mesh(); - CommonGizmosDataObjects::Raycaster* raycaster(); + CommonGizmosDataObjects::SelectionInfo* selection_info() const; + CommonGizmosDataObjects::HollowedMesh* hollowed_mesh() const; + CommonGizmosDataObjects::Raycaster* raycaster() const; + CommonGizmosDataObjects::ObjectClipper* object_clipper() const; GLCanvas3D* get_canvas() const { return m_canvas; } @@ -125,8 +131,9 @@ public: explicit SelectionInfo(CommonGizmosDataPool* cgdp) : CommonGizmosDataBase(cgdp) {} - ModelObject* model_object() { return m_model_object; } - int get_active_instance(); + ModelObject* model_object() const { return m_model_object; } + int get_active_instance() const; + float get_sla_shift() const { return m_z_shift; } protected: void on_update() override; @@ -135,6 +142,7 @@ protected: private: ModelObject* m_model_object = nullptr; int m_active_inst = -1; + float m_z_shift = 0.f; }; @@ -200,6 +208,37 @@ private: std::vector m_old_meshes; }; + + +class ObjectClipper : public CommonGizmosDataBase +{ +public: + explicit ObjectClipper(CommonGizmosDataPool* cgdp) + : CommonGizmosDataBase(cgdp) {} +#ifndef NDEBUG + CommonGizmosDataID get_dependencies() const override { return CommonGizmosDataID::SelectionInfo; } +#endif // NDEBUG + + MeshClipper* get_clipper() const { return m_clipper.get(); } + void set_position(double pos, bool keep_normal); + double get_position() const { return m_clp_ratio; } + ClippingPlane* get_clipping_plane() const { return m_clp.get(); } + void render_cut() const; + + +protected: + void on_update() override; + void on_release() override; + +private: + const TriangleMesh* m_old_mesh = nullptr; + std::unique_ptr m_clipper; + std::unique_ptr m_clp; + double m_clp_ratio = 0.; + double m_active_inst_bb_radius = 0.; + +}; + /* class ClippingPlaneWrapper : public CommonGizmosDataBase diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 26f42ed34..ed9bd5de3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -95,7 +95,7 @@ bool GLGizmosManager::init() m_gizmos.emplace_back(new GLGizmoRotate3D(m_parent, "rotate.svg", 2)); m_gizmos.emplace_back(new GLGizmoFlatten(m_parent, "place.svg", 3)); m_gizmos.emplace_back(new GLGizmoCut(m_parent, "cut.svg", 4)); - //m_gizmos.emplace_back(new GLGizmoHollow(m_parent, "hollow.svg", 5)); + m_gizmos.emplace_back(new GLGizmoHollow(m_parent, "hollow.svg", 5)); //m_gizmos.emplace_back(new GLGizmoSlaSupports(m_parent, "sla_supports.svg", 6)); //m_common_gizmos_data.reset(new CommonGizmosData()); @@ -360,21 +360,22 @@ void GLGizmosManager::set_flattening_data(const ModelObject* model_object) void GLGizmosManager::set_sla_support_data(ModelObject* model_object) { - /*if (! m_enabled + if (! m_enabled || m_gizmos.empty() || wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA) return; - m_common_gizmos_data->update_from_backend(m_parent, model_object); + /*m_common_gizmos_data->update_from_backend(m_parent, model_object); auto* gizmo_supports = dynamic_cast(m_gizmos[SlaSupports].get()); - auto* gizmo_hollow = dynamic_cast(m_gizmos[Hollow].get()); + // note: sla support gizmo takes care of updating the common data. // following lines are thus dependent - gizmo_supports->set_sla_support_data(model_object, m_parent.get_selection()); - gizmo_hollow->set_sla_support_data(model_object, m_parent.get_selection()); + //gizmo_supports->set_sla_support_data(model_object, m_parent.get_selection()); */ + auto* gizmo_hollow = dynamic_cast(m_gizmos[Hollow].get()); + gizmo_hollow->set_sla_support_data(model_object, m_parent.get_selection()); } // Returns true if the gizmo used the event to do something, false otherwise. From e82ead0335df913717b7946132c69f725dff35ea Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 7 Apr 2020 11:53:46 +0200 Subject: [PATCH 18/28] InstancesHider allows to show/hide supports on demand --- src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 14 +++++++++----- src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 16 ++++++++++++++++ src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 7 +++++++ 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index f27bc2863..86ad8d0a0 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -54,6 +54,9 @@ bool GLGizmoHollow::on_init() void GLGizmoHollow::set_sla_support_data(ModelObject*, const Selection&) { + if (! m_c->selection_info()) + return; + const ModelObject* mo = m_c->selection_info()->model_object(); if (mo) { reload_cache(); @@ -857,11 +860,12 @@ RENDER_AGAIN: m_c->object_clipper()->set_position(clp_dist, true); // make sure supports are shown/hidden as appropriate - // DODELAT - //if (m_imgui->checkbox(m_desc["show_supports"], m_show_supports)) { - // m_parent.toggle_sla_auxiliaries_visibility(m_show_supports, mo, m_c->m_active_instance); - // force_refresh = true; - //} + bool show_sups = m_c->instances_hider()->are_supports_shown(); + if (m_imgui->checkbox(m_desc["show_supports"], show_sups)) { + // m_parent.toggle_sla_auxiliaries_visibility(m_show_supports, mo, m_c->m_active_instance); + m_c->instances_hider()->show_supports(show_sups); + force_refresh = true; + } m_imgui->end(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp index a33721519..178579ba1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp @@ -50,7 +50,7 @@ private: void hollow_mesh(bool postpone_error_messages = false); bool unsaved_changes() const; - bool m_show_supports = true; + // bool m_show_supports = true; float m_new_hole_radius = 2.f; // Size of a new hole. float m_new_hole_height = 6.f; mutable std::vector m_selected; // which holes are currently selected diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index 792fd0e91..a6fbabfa2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -48,6 +48,14 @@ SelectionInfo* CommonGizmosDataPool::selection_info() const return sel_info->is_valid() ? sel_info : nullptr; } + +InstancesHider* CommonGizmosDataPool::instances_hider() const +{ + InstancesHider* inst_hider = dynamic_cast(m_data.at(CommonGizmosDataID::InstancesHider).get()); + assert(inst_hider); + return inst_hider->is_valid() ? inst_hider : nullptr; +} + HollowedMesh* CommonGizmosDataPool::hollowed_mesh() const { HollowedMesh* hol_mesh = dynamic_cast(m_data.at(CommonGizmosDataID::HollowedMesh).get()); @@ -130,6 +138,7 @@ void InstancesHider::on_update() if (mo && active_inst != -1) { canvas->toggle_model_objects_visibility(false); canvas->toggle_model_objects_visibility(true, mo, active_inst); + canvas->toggle_sla_auxiliaries_visibility(m_show_supports, mo, active_inst); } else canvas->toggle_model_objects_visibility(true); @@ -140,6 +149,13 @@ void InstancesHider::on_release() get_pool()->get_canvas()->toggle_model_objects_visibility(true); } +void InstancesHider::show_supports(bool show) { + if (m_show_supports != show) { + m_show_supports = show; + on_update(); + } +} + void HollowedMesh::on_update() diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index 7a9cb35b8..a2fa598c9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -61,6 +61,7 @@ public: // Getters for the data that need to be accessed from the gizmos directly. CommonGizmosDataObjects::SelectionInfo* selection_info() const; + CommonGizmosDataObjects::InstancesHider* instances_hider() const; CommonGizmosDataObjects::HollowedMesh* hollowed_mesh() const; CommonGizmosDataObjects::Raycaster* raycaster() const; CommonGizmosDataObjects::ObjectClipper* object_clipper() const; @@ -156,9 +157,15 @@ public: CommonGizmosDataID get_dependencies() const override { return CommonGizmosDataID::SelectionInfo; } #endif // NDEBUG + void show_supports(bool show); + bool are_supports_shown() const { return m_show_supports; } + protected: void on_update() override; void on_release() override; + +private: + bool m_show_supports = false; }; From c79e90b921962543f2d6873e9aef1e72d32f5bef Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 7 Apr 2020 13:00:37 +0200 Subject: [PATCH 19/28] SupportsClipper implementation --- src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 112 +++++++++++++++++++++-- src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 38 +++++--- 3 files changed, 132 insertions(+), 22 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index 86ad8d0a0..8c705fef8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -119,6 +119,7 @@ void GLGizmoHollow::on_render() const m_selection_rectangle.render(m_parent); //render_clipping_plane(selection); m_c->object_clipper()->render_cut(); + m_c->supports_clipper()->render_cut(); glsafe(::glDisable(GL_BLEND)); } @@ -929,7 +930,8 @@ CommonGizmosDataID GLGizmoHollow::on_get_requirements() const | int(CommonGizmosDataID::InstancesHider) | int(CommonGizmosDataID::Raycaster) | int(CommonGizmosDataID::HollowedMesh) - | int(CommonGizmosDataID::ObjectClipper)); + | int(CommonGizmosDataID::ObjectClipper) + | int(CommonGizmosDataID::SupportsClipper)); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index a6fbabfa2..380aa4e7d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -18,12 +18,12 @@ CommonGizmosDataPool::CommonGizmosDataPool(GLCanvas3D* canvas) : m_canvas(canvas) { using c = CommonGizmosDataID; - m_data[c::SelectionInfo].reset( new SelectionInfo(this)); - m_data[c::InstancesHider].reset( new InstancesHider(this)); - m_data[c::HollowedMesh].reset( new HollowedMesh(this)); - m_data[c::Raycaster].reset( new Raycaster(this)); - m_data[c::ObjectClipper].reset(new ObjectClipper(this)); - //m_data[c::SupportsClipper].reset( new SupportsClipper(this)); + m_data[c::SelectionInfo].reset( new SelectionInfo(this)); + m_data[c::InstancesHider].reset( new InstancesHider(this)); + m_data[c::HollowedMesh].reset( new HollowedMesh(this)); + m_data[c::Raycaster].reset( new Raycaster(this)); + m_data[c::ObjectClipper].reset( new ObjectClipper(this)); + m_data[c::SupportsClipper].reset( new SupportsClipper(this)); } @@ -77,6 +77,13 @@ ObjectClipper* CommonGizmosDataPool::object_clipper() const return oc->is_valid() ? oc : nullptr; } +SupportsClipper* CommonGizmosDataPool::supports_clipper() const +{ + SupportsClipper* sc = dynamic_cast(m_data.at(CommonGizmosDataID::SupportsClipper).get()); + assert(sc); + return sc->is_valid() ? sc : nullptr; +} + #ifndef NDEBUG // Check the required resources one by one and return true if all // dependencies are met. @@ -346,5 +353,98 @@ void ObjectClipper::set_position(double pos, bool keep_normal) +void SupportsClipper::on_update() +{ + const ModelObject* mo = get_pool()->selection_info()->model_object(); + if (! mo) + return; + + const GLCanvas3D* canvas = get_pool()->get_canvas(); + const PrintObjects& print_objects = canvas->sla_print()->objects(); + const SLAPrintObject* print_object = m_print_object_idx != -1 + ? print_objects[m_print_object_idx] + : nullptr; + + // Find the respective SLAPrintObject. + if (m_print_object_idx < 0 || m_print_objects_count != int(print_objects.size())) { + m_print_objects_count = print_objects.size(); + m_print_object_idx = -1; + for (const SLAPrintObject* po : print_objects) { + ++m_print_object_idx; + if (po->model_object()->id() == mo->id()) { + print_object = po; + break; + } + } + } + + if (print_object + && print_object->is_step_done(slaposSupportTree) + && ! print_object->support_mesh().empty()) + { + // If the supports are already calculated, save the timestamp of the respective step + // so we can later tell they were recalculated. + size_t timestamp = print_object->step_state_with_timestamp(slaposSupportTree).timestamp; + if (! m_clipper || timestamp != m_old_timestamp) { + // The timestamp has changed. + m_clipper.reset(new MeshClipper); + // The mesh should already have the shared vertices calculated. + m_clipper->set_mesh(print_object->support_mesh()); + m_old_timestamp = timestamp; + } + } + else + // The supports are not valid. We better dump the cached data. + m_clipper.reset(); +} + + +void SupportsClipper::on_release() +{ + m_clipper.reset(); + m_old_timestamp = 0; + m_print_object_idx = -1; +} + +void SupportsClipper::render_cut() const +{ + const CommonGizmosDataObjects::ObjectClipper* ocl = get_pool()->object_clipper(); + if (ocl->get_position() == 0. + || ! get_pool()->instances_hider()->are_supports_shown() + || ! m_clipper) + return; + + const SelectionInfo* sel_info = get_pool()->selection_info(); + const ModelObject* mo = sel_info->model_object(); + Geometry::Transformation inst_trafo = mo->instances[sel_info->get_active_instance()]->get_transformation(); + Geometry::Transformation vol_trafo = mo->volumes.front()->get_transformation(); + Geometry::Transformation trafo = inst_trafo;// * vol_trafo; + trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., sel_info->get_sla_shift())); + + + // Get transformation of supports + Geometry::Transformation supports_trafo = trafo; + supports_trafo.set_offset(Vec3d(trafo.get_offset()(0), trafo.get_offset()(1), sel_info->get_sla_shift())); + supports_trafo.set_rotation(Vec3d(0., 0., trafo.get_rotation()(2))); + // I don't know why, but following seems to be correct. + supports_trafo.set_mirror(Vec3d(trafo.get_mirror()(0) * trafo.get_mirror()(1) * trafo.get_mirror()(2), + 1, + 1.)); + + m_clipper->set_plane(*ocl->get_clipping_plane()); + m_clipper->set_transformation(supports_trafo); + + if (! m_clipper->get_triangles().empty()) { + ::glPushMatrix(); + ::glColor3f(1.0f, 0.f, 0.37f); + ::glBegin(GL_TRIANGLES); + for (const Vec3f& point : m_clipper->get_triangles()) + ::glVertex3f(point(0), point(1), point(2)); + ::glEnd(); + ::glPopMatrix(); + } +} + + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index a2fa598c9..54e561f2f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -26,6 +26,7 @@ namespace CommonGizmosDataObjects { class HollowedMesh; class Raycaster; class ObjectClipper; + class SupportsClipper; } // Some of the gizmos use the same data that need to be updated ocassionally. @@ -65,6 +66,7 @@ public: CommonGizmosDataObjects::HollowedMesh* hollowed_mesh() const; CommonGizmosDataObjects::Raycaster* raycaster() const; CommonGizmosDataObjects::ObjectClipper* object_clipper() const; + CommonGizmosDataObjects::SupportsClipper* supports_clipper() const; GLCanvas3D* get_canvas() const { return m_canvas; } @@ -226,7 +228,6 @@ public: CommonGizmosDataID get_dependencies() const override { return CommonGizmosDataID::SelectionInfo; } #endif // NDEBUG - MeshClipper* get_clipper() const { return m_clipper.get(); } void set_position(double pos, bool keep_normal); double get_position() const { return m_clp_ratio; } ClippingPlane* get_clipping_plane() const { return m_clp.get(); } @@ -243,17 +244,6 @@ private: std::unique_ptr m_clp; double m_clp_ratio = 0.; double m_active_inst_bb_radius = 0.; - -}; - -/* - -class ClippingPlaneWrapper : public CommonGizmosDataBase -{ -public: - explicit ClippingPlaneWrapper(CommonGizmosDataPool* cgdp) - : CommonGizmosDataBase(cgdp) {} - void update(bool required) override; }; @@ -263,10 +253,28 @@ class SupportsClipper : public CommonGizmosDataBase public: explicit SupportsClipper(CommonGizmosDataPool* cgdp) : CommonGizmosDataBase(cgdp) {} - void update(bool required) override; -}; +#ifndef NDEBUG + CommonGizmosDataID get_dependencies() const override { + return CommonGizmosDataID( + int(CommonGizmosDataID::SelectionInfo) + | int(CommonGizmosDataID::ObjectClipper) + ); + } +#endif // NDEBUG -*/ + void render_cut() const; + + +protected: + void on_update() override; + void on_release() override; + +private: + size_t m_old_timestamp = 0; + int m_print_object_idx = -1; + int m_print_objects_count = 0; + std::unique_ptr m_clipper; +}; } // namespace CommonGizmosDataObjects From c704849a7a8ccb6c30e718257bda4b73708dbd18 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 7 Apr 2020 15:38:24 +0200 Subject: [PATCH 20/28] SLA supports gizmo is now enabled and uses the new infrastructure --- src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 261 ++++++++++++------- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp | 14 +- src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 18 +- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 14 +- src/slic3r/GUI/Gizmos/GLGizmosManager.hpp | 12 +- 6 files changed, 194 insertions(+), 127 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index 8c705fef8..46c570c19 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -971,7 +971,7 @@ void GLGizmoHollow::on_set_state() if (m_state == Off && m_old_state != Off) { // the gizmo was just turned Off //Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned off"))); m_parent.post_event(SimpleEvent(EVT_GLCANVAS_FORCE_UPDATE)); - m_parent.toggle_model_objects_visibility(true); + //m_parent.toggle_model_objects_visibility(true); //m_c->stash_clipping_plane(); //m_c->m_clipping_plane_distance = 0.f; //update_clipping_plane(true); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 064302c02..ac65d9313 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -3,6 +3,7 @@ #include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/Camera.hpp" #include "slic3r/GUI/Gizmos/GLGizmos.hpp" +#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" #include @@ -14,9 +15,6 @@ #include "slic3r/GUI/GUI.hpp" #include "slic3r/GUI/GUI_ObjectSettings.hpp" #include "slic3r/GUI/GUI_ObjectList.hpp" -#if ENABLE_NON_STATIC_CANVAS_MANAGER -#include "slic3r/GUI/Camera.hpp" -#endif // ENABLE_NON_STATIC_CANVAS_MANAGER #include "slic3r/GUI/MeshUtils.hpp" #include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/PresetBundle.hpp" @@ -66,6 +64,19 @@ bool GLGizmoSlaSupports::on_init() void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const Selection& selection) { + if (! m_c->selection_info()) + return; + + ModelObject* mo = m_c->selection_info()->model_object(); + + if (mo != m_old_mo) { + disable_editing_mode(); + if (mo) + reload_cache(); + m_old_mo = mo; + } + + /* if (m_c->recent_update) { if (m_state == On) m_c->build_AABB_if_needed(); @@ -81,11 +92,11 @@ void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const S m_parent.toggle_model_objects_visibility(false); m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance); m_parent.toggle_sla_auxiliaries_visibility(! m_editing_mode, m_c->m_model_object, m_c->m_active_instance); - } + }*/ // If we triggered autogeneration before, check backend and fetch results if they are there - if (m_c->m_model_object) { - if (m_c->m_model_object->sla_points_status == sla::PointsStatus::Generating) + if (mo) { + if (mo->sla_points_status == sla::PointsStatus::Generating) get_data_from_backend(); } } @@ -94,13 +105,14 @@ void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const S void GLGizmoSlaSupports::on_render() const { + ModelObject* mo = m_c->selection_info()->model_object(); const Selection& selection = m_parent.get_selection(); // If current m_c->m_model_object does not match selection, ask GLCanvas3D to turn us off if (m_state == On - && (m_c->m_model_object != selection.get_model()->objects[selection.get_object_idx()] - || m_c->m_active_instance != selection.get_instance_idx() - || m_c->m_model_object_id != m_c->m_model_object->id())) { + && (mo != selection.get_model()->objects[selection.get_object_idx()] + || m_c->selection_info()->get_active_instance() != selection.get_instance_idx() + /*|| m_c->m_model_object_id != m_c->m_model_object->id()*/)) { m_parent.post_event(SimpleEvent(EVT_GLCANVAS_RESETGIZMOS)); return; } @@ -108,20 +120,22 @@ void GLGizmoSlaSupports::on_render() const glsafe(::glEnable(GL_BLEND)); glsafe(::glEnable(GL_DEPTH_TEST)); - m_z_shift = selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z(); +// m_z_shift = selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z(); if (m_quadric != nullptr && selection.is_from_single_instance()) render_points(selection, false); m_selection_rectangle.render(m_parent); - render_clipping_plane(selection); + m_c->object_clipper()->render_cut(); + m_c->supports_clipper()->render_cut(); + //render_clipping_plane(selection); glsafe(::glDisable(GL_BLEND)); } -void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const +/*void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const { if (m_c->m_clipping_plane_distance == 0.f || m_c->m_mesh->empty()) return; @@ -205,16 +219,17 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const ::glEnd(); ::glPopMatrix(); } -} +}*/ void GLGizmoSlaSupports::on_render_for_picking() const { const Selection& selection = m_parent.get_selection(); +/* #if ENABLE_RENDER_PICKING_PASS m_z_shift = selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z(); #endif - +*/ glsafe(::glEnable(GL_DEPTH_TEST)); render_points(selection, true); } @@ -227,9 +242,10 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin()); const Transform3d& instance_scaling_matrix_inverse = vol->get_instance_transformation().get_matrix(true, true, false, true).inverse(); const Transform3d& instance_matrix = vol->get_instance_transformation().get_matrix(); + float z_shift = m_c->selection_info()->get_sla_shift(); glsafe(::glPushMatrix()); - glsafe(::glTranslated(0.0, 0.0, m_z_shift)); + glsafe(::glTranslated(0.0, 0.0, z_shift)); glsafe(::glMultMatrixd(instance_matrix.data())); float render_color[4]; @@ -285,7 +301,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) if (m_editing_mode) { // in case the normal is not yet cached, find and cache it if (m_editing_cache[i].normal == Vec3f::Zero()) - m_c->m_mesh_raycaster->get_closest_point(m_editing_cache[i].support_point.pos, &m_editing_cache[i].normal); + m_c->raycaster()->raycaster()->get_closest_point(m_editing_cache[i].support_point.pos, &m_editing_cache[i].normal); Eigen::Quaterniond q; q.setFromTwoVectors(Vec3d{0., 0., 1.}, instance_scaling_matrix_inverse * m_editing_cache[i].normal.cast()); @@ -315,14 +331,15 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) } // Now render the drain holes: - if (! m_c->has_drilled_mesh()) { + //if (! m_c->has_drilled_mesh()) { + if (! m_c->hollowed_mesh()->get_hollowed_mesh()) { render_color[0] = 0.7f; render_color[1] = 0.7f; render_color[2] = 0.7f; render_color[3] = 0.7f; glsafe(::glColor4fv(render_color)); - for (const sla::DrainHole& drain_hole : m_c->m_model_object->sla_drain_holes) { - if (is_mesh_point_clipped((drain_hole.pos+m_c->HoleStickOutLength*drain_hole.normal).cast())) + for (const sla::DrainHole& drain_hole : m_c->selection_info()->model_object()->sla_drain_holes) { + if (is_mesh_point_clipped((drain_hole.pos+HoleStickOutLength*drain_hole.normal).cast())) continue; // Inverse matrix of the instance scaling is applied so that the mark does not scale with the object. @@ -365,12 +382,17 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) bool GLGizmoSlaSupports::is_mesh_point_clipped(const Vec3d& point) const { - if (m_c->m_clipping_plane_distance == 0.f) + if (m_c->object_clipper()->get_position() == 0.) return false; - Vec3d transformed_point = m_c->m_model_object->instances[m_c->m_active_instance]->get_transformation().get_matrix() * point; - transformed_point(2) += m_z_shift; - return m_c->m_clipping_plane->is_point_clipped(transformed_point); + auto sel_info = m_c->selection_info(); + int active_inst = m_c->selection_info()->get_active_instance(); + const ModelInstance* mi = sel_info->model_object()->instances[active_inst]; + const Transform3d& trafo = mi->get_transformation().get_matrix(); + + Vec3d transformed_point = trafo * point; + transformed_point(2) += sel_info->get_sla_shift(); + return m_c->object_clipper()->get_clipping_plane()->is_point_clipped(transformed_point); } @@ -379,7 +401,7 @@ bool GLGizmoSlaSupports::is_mesh_point_clipped(const Vec3d& point) const // Return false if no intersection was found, true otherwise. bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair& pos_and_normal) { - if (! m_c->m_mesh_raycaster) + if (! m_c->raycaster()->raycaster()) return false; #if ENABLE_NON_STATIC_CANVAS_MANAGER @@ -390,26 +412,30 @@ bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pairget_instance_transformation(); - trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_z_shift)); + trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_c->selection_info()->get_sla_shift())); + + double clp_dist = m_c->object_clipper()->get_position(); + const ClippingPlane* clp = m_c->object_clipper()->get_clipping_plane(); // The raycaster query Vec3f hit; Vec3f normal; - if (m_c->m_mesh_raycaster->unproject_on_mesh( + if (m_c->raycaster()->raycaster()->unproject_on_mesh( mouse_pos, trafo.get_matrix(), camera, hit, normal, - m_c->m_clipping_plane_distance != 0.f ? m_c->m_clipping_plane.get() : nullptr)) + clp_dist != 0. ? clp : nullptr)) { // Check whether the hit is in a hole bool in_hole = false; // In case the hollowed and drilled mesh is available, we can allow // placing points in holes, because they should never end up // on surface that's been drilled away. - if (! m_c->has_drilled_mesh()) { - for (const sla::DrainHole& hole : m_c->m_model_object->sla_drain_holes) { + if (! m_c->hollowed_mesh()->get_hollowed_mesh()) { + sla::DrainHoles drain_holes = m_c->selection_info()->model_object()->sla_drain_holes; + for (const sla::DrainHole& hole : drain_holes) { if (hole.is_inside(hit)) { in_hole = true; break; @@ -432,6 +458,9 @@ bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pairselection_info()->model_object(); + int active_inst = m_c->selection_info()->get_active_instance(); + if (m_editing_mode) { // left down with shift - show the selection rectangle: @@ -483,8 +512,8 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous GLSelectionRectangle::EState rectangle_status = m_selection_rectangle.get_state(); // First collect positions of all the points in world coordinates. - Geometry::Transformation trafo = m_c->m_model_object->instances[m_c->m_active_instance]->get_transformation(); - trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_z_shift)); + Geometry::Transformation trafo = mo->instances[active_inst]->get_transformation(); + trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_c->selection_info()->get_sla_shift())); std::vector points; for (unsigned int i=0; i()); @@ -496,11 +525,9 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous points_inside.push_back(points[idx].cast()); // Only select/deselect points that are actually visible -#if ENABLE_NON_STATIC_CANVAS_MANAGER - for (size_t idx : m_c->m_mesh_raycaster->get_unobscured_idxs(trafo, wxGetApp().plater()->get_camera(), points_inside, m_c->m_clipping_plane.get())) -#else - for (size_t idx : m_c->m_mesh_raycaster->get_unobscured_idxs(trafo, m_parent.get_camera(), points_inside, m_c->m_clipping_plane.get())) -#endif // ENABLE_NON_STATIC_CANVAS_MANAGER + for (size_t idx : m_c->raycaster()->raycaster()->get_unobscured_idxs( + trafo, wxGetApp().plater()->get_camera(), points_inside, + m_c->object_clipper()->get_clipping_plane())) { if (rectangle_status == GLSelectionRectangle::Deselect) unselect_point(points_idxs[idx]); @@ -577,20 +604,25 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous } if (action == SLAGizmoEventType::MouseWheelUp && control_down) { - m_c->m_clipping_plane_distance = std::min(1.f, m_c->m_clipping_plane_distance + 0.01f); - update_clipping_plane(m_c->m_clipping_plane_was_moved); - m_c->m_clipping_plane_was_moved = true; + double pos = m_c->object_clipper()->get_position(); + pos = std::min(1., pos + 0.01); + m_c->object_clipper()->set_position(pos, true); + //update_clipping_plane(/*m_c->m_clipping_plane_was_moved*/); + //m_c->m_clipping_plane_was_moved = true; return true; } if (action == SLAGizmoEventType::MouseWheelDown && control_down) { - m_c->m_clipping_plane_distance = std::max(0.f, m_c->m_clipping_plane_distance - 0.01f); - update_clipping_plane(true); + double pos = m_c->object_clipper()->get_position(); + pos = std::max(0., pos - 0.01); + m_c->object_clipper()->set_position(pos, true); + //update_clipping_plane(true); return true; } if (action == SLAGizmoEventType::ResetClippingPlane) { - update_clipping_plane(); + //update_clipping_plane(); + m_c->object_clipper()->set_position(-1., false); return true; } @@ -634,11 +666,12 @@ void GLGizmoSlaSupports::on_update(const UpdateData& data) std::vector GLGizmoSlaSupports::get_config_options(const std::vector& keys) const { std::vector out; + const ModelObject* mo = m_c->selection_info()->model_object(); - if (!m_c->m_model_object) + if (! mo) return out; - const DynamicPrintConfig& object_cfg = m_c->m_model_object->config; + const DynamicPrintConfig& object_cfg = mo->config; const DynamicPrintConfig& print_cfg = wxGetApp().preset_bundle->sla_prints.get_edited_preset().config; std::unique_ptr default_cfg = nullptr; @@ -661,10 +694,18 @@ std::vector GLGizmoSlaSupports::get_config_options(const st ClippingPlane GLGizmoSlaSupports::get_sla_clipping_plane() const { - if (!m_c->m_model_object || m_state == Off || m_c->m_clipping_plane_distance == 0.f) + //if (!m_c->m_model_object || m_state == Off || m_c->m_clipping_plane_distance == 0.f) + // return ClippingPlane::ClipsNothing(); + //else + // return ClippingPlane(-m_c->m_clipping_plane->get_normal(), m_c->m_clipping_plane->get_data()[3]); + if (! m_c->selection_info()->model_object() + || m_state == Off + || m_c->object_clipper()->get_position() == 0.) return ClippingPlane::ClipsNothing(); - else - return ClippingPlane(-m_c->m_clipping_plane->get_normal(), m_c->m_clipping_plane->get_data()[3]); + else { + const ClippingPlane& clp = *m_c->object_clipper()->get_clipping_plane(); + return ClippingPlane(-clp.get_normal(), clp.get_data()[3]); + } } @@ -714,7 +755,9 @@ void GLGizmoSlaSupports::on_render_input_window(float x, float y, float bottom_l static float last_y = 0.0f; static float last_h = 0.0f; - if (! m_c->m_model_object) + ModelObject* mo = m_c->selection_info()->model_object(); + + if (! mo) return; bool first_run = true; // This is a hack to redraw the button when all points are removed, @@ -851,15 +894,15 @@ RENDER_AGAIN: m_density_stash = density; } if (slider_edited) { - m_c->m_model_object->config.opt("support_points_minimal_distance", true)->value = minimal_point_distance; - m_c->m_model_object->config.opt("support_points_density_relative", true)->value = (int)density; + mo->config.opt("support_points_minimal_distance", true)->value = minimal_point_distance; + mo->config.opt("support_points_density_relative", true)->value = (int)density; } if (slider_released) { - m_c->m_model_object->config.opt("support_points_minimal_distance", true)->value = m_minimal_point_distance_stash; - m_c->m_model_object->config.opt("support_points_density_relative", true)->value = (int)m_density_stash; + mo->config.opt("support_points_minimal_distance", true)->value = m_minimal_point_distance_stash; + mo->config.opt("support_points_density_relative", true)->value = (int)m_density_stash; Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Support parameter change"))); - m_c->m_model_object->config.opt("support_points_minimal_distance", true)->value = minimal_point_distance; - m_c->m_model_object->config.opt("support_points_density_relative", true)->value = (int)density; + mo->config.opt("support_points_minimal_distance", true)->value = minimal_point_distance; + mo->config.opt("support_points_density_relative", true)->value = (int)density; wxGetApp().obj_list()->update_and_show_object_settings_item(); } @@ -886,7 +929,7 @@ RENDER_AGAIN: // Following is rendered in both editing and non-editing mode: ImGui::Separator(); - if (m_c->m_clipping_plane_distance == 0.f) + if (m_c->object_clipper()->get_position() == 0.f) { ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("clipping_of_view")); @@ -894,17 +937,17 @@ RENDER_AGAIN: else { if (m_imgui->button(m_desc.at("reset_direction"))) { wxGetApp().CallAfter([this](){ - update_clipping_plane(); + //update_clipping_plane(); + m_c->object_clipper()->set_position(-1., false); }); } } ImGui::SameLine(clipping_slider_left); ImGui::PushItemWidth(window_width - clipping_slider_left); - if (ImGui::SliderFloat(" ", &m_c->m_clipping_plane_distance, 0.f, 1.f, "%.2f")) { - update_clipping_plane(m_c->m_clipping_plane_was_moved); - m_c->m_clipping_plane_was_moved = true; - } + float clp_dist = m_c->object_clipper()->get_position(); + if (ImGui::SliderFloat(" ", &clp_dist, 0.f, 1.f, "%.2f")) + m_c->object_clipper()->set_position(clp_dist, true); if (m_imgui->button("?")) { @@ -969,18 +1012,31 @@ std::string GLGizmoSlaSupports::on_get_name() const } +CommonGizmosDataID GLGizmoSlaSupports::on_get_requirements() const +{ + return CommonGizmosDataID( + int(CommonGizmosDataID::SelectionInfo) + | int(CommonGizmosDataID::InstancesHider) + | int(CommonGizmosDataID::Raycaster) + | int(CommonGizmosDataID::HollowedMesh) + | int(CommonGizmosDataID::ObjectClipper) + | int(CommonGizmosDataID::SupportsClipper)); +} + + void GLGizmoSlaSupports::on_set_state() { + const ModelObject* mo = m_c->selection_info()->model_object(); // m_c->m_model_object pointer can be invalid (for instance because of undo/redo action), // we should recover it from the object id - m_c->m_model_object = nullptr; + /*m_c->m_model_object = nullptr; for (const auto mo : wxGetApp().model().objects) { if (mo->id() == m_c->m_model_object_id) { m_c->m_model_object = mo; break; } - } + }*/ if (m_state == m_old_state) return; @@ -988,28 +1044,28 @@ void GLGizmoSlaSupports::on_set_state() if (m_state == On && m_old_state != On) { // the gizmo was just turned on Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned on"))); - m_c->unstash_clipping_plane(); - update_clipping_plane(m_c->m_clipping_plane_was_moved); + //m_c->unstash_clipping_plane(); + //update_clipping_plane(m_c->m_clipping_plane_was_moved); - m_c->build_AABB_if_needed(); + //m_c->build_AABB_if_needed(); // we'll now reload support points: - if (m_c->m_model_object) + if (mo) reload_cache(); - m_parent.toggle_model_objects_visibility(false); + /*m_parent.toggle_model_objects_visibility(false); if (m_c->m_model_object) { m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance); m_parent.toggle_sla_auxiliaries_visibility(! m_editing_mode, m_c->m_model_object, m_c->m_active_instance); - } + }*/ // Set default head diameter from config. const DynamicPrintConfig& cfg = wxGetApp().preset_bundle->sla_prints.get_edited_preset().config; m_new_point_head_diameter = static_cast(cfg.option("support_head_front_diameter"))->value; } if (m_state == Off && m_old_state != Off) { // the gizmo was just turned Off - bool will_ask = m_c->m_model_object && m_editing_mode && unsaved_changes(); + bool will_ask = mo && m_editing_mode && unsaved_changes(); if (will_ask) { wxGetApp().CallAfter([this]() { // Following is called through CallAfter, because otherwise there was a problem @@ -1028,15 +1084,15 @@ void GLGizmoSlaSupports::on_set_state() // we are actually shutting down disable_editing_mode(); // so it is not active next time the gizmo opens Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned off"))); - m_parent.toggle_model_objects_visibility(true); + //m_parent.toggle_model_objects_visibility(true); m_normal_cache.clear(); - m_c->stash_clipping_plane(); - m_c->m_clipping_plane_distance = 0.f; - update_clipping_plane(true); + //m_c->stash_clipping_plane(); + //m_c->m_clipping_plane_distance = 0.f; + //update_clipping_plane(true); // Release clippers and the AABB raycaster. - m_its = nullptr; - m_c->m_object_clipper.reset(); - m_c->m_supports_clipper.reset(); + //m_its = nullptr; + //m_c->m_object_clipper.reset(); + //m_c->m_supports_clipper.reset(); //m_c->m_mesh_raycaster.reset(); } } @@ -1077,10 +1133,7 @@ void GLGizmoSlaSupports::on_stop_dragging() void GLGizmoSlaSupports::on_load(cereal::BinaryInputArchive& ar) { - ar(m_c->m_clipping_plane_distance, - *m_c->m_clipping_plane, - m_c->m_model_object_id, - m_new_point_head_diameter, + ar(m_new_point_head_diameter, m_normal_cache, m_editing_cache, m_selection_empty @@ -1091,10 +1144,7 @@ void GLGizmoSlaSupports::on_load(cereal::BinaryInputArchive& ar) void GLGizmoSlaSupports::on_save(cereal::BinaryOutputArchive& ar) const { - ar(m_c->m_clipping_plane_distance, - *m_c->m_clipping_plane, - m_c->m_model_object_id, - m_new_point_head_diameter, + ar(m_new_point_head_diameter, m_normal_cache, m_editing_cache, m_selection_empty @@ -1171,9 +1221,10 @@ void GLGizmoSlaSupports::editing_mode_apply_changes() for (const CacheEntry& ce : m_editing_cache) m_normal_cache.push_back(ce.support_point); - m_c->m_model_object->sla_points_status = sla::PointsStatus::UserModified; - m_c->m_model_object->sla_support_points.clear(); - m_c->m_model_object->sla_support_points = m_normal_cache; + ModelObject* mo = m_c->selection_info()->model_object(); + mo->sla_points_status = sla::PointsStatus::UserModified; + mo->sla_support_points.clear(); + mo->sla_support_points = m_normal_cache; reslice_SLA_supports(); } @@ -1183,23 +1234,25 @@ void GLGizmoSlaSupports::editing_mode_apply_changes() void GLGizmoSlaSupports::reload_cache() { + const ModelObject* mo = m_c->selection_info()->model_object(); m_normal_cache.clear(); - if (m_c->m_model_object->sla_points_status == sla::PointsStatus::AutoGenerated || m_c->m_model_object->sla_points_status == sla::PointsStatus::Generating) + if (mo->sla_points_status == sla::PointsStatus::AutoGenerated || mo->sla_points_status == sla::PointsStatus::Generating) get_data_from_backend(); else - for (const sla::SupportPoint& point : m_c->m_model_object->sla_support_points) + for (const sla::SupportPoint& point : mo->sla_support_points) m_normal_cache.emplace_back(point); } bool GLGizmoSlaSupports::has_backend_supports() const { - if (! m_c->m_model_object) + const ModelObject* mo = m_c->selection_info()->model_object(); + if (! mo) return false; // find SlaPrintObject with this ID for (const SLAPrintObject* po : m_parent.sla_print()->objects()) { - if (po->model_object()->id() == m_c->m_model_object->id()) + if (po->model_object()->id() == mo->id()) return po->is_step_done(slaposSupportPoints); } return false; @@ -1207,24 +1260,28 @@ bool GLGizmoSlaSupports::has_backend_supports() const void GLGizmoSlaSupports::reslice_SLA_supports(bool postpone_error_messages) const { - wxGetApp().CallAfter([this, postpone_error_messages]() { wxGetApp().plater()->reslice_SLA_supports(*m_c->m_model_object, postpone_error_messages); }); + wxGetApp().CallAfter([this, postpone_error_messages]() { + wxGetApp().plater()->reslice_SLA_supports( + *m_c->selection_info()->model_object(), postpone_error_messages); + }); } void GLGizmoSlaSupports::get_data_from_backend() { if (! has_backend_supports()) return; + ModelObject* mo = m_c->selection_info()->model_object(); // find the respective SLAPrintObject, we need a pointer to it for (const SLAPrintObject* po : m_parent.sla_print()->objects()) { - if (po->model_object()->id() == m_c->m_model_object->id()) { + if (po->model_object()->id() == mo->id()) { m_normal_cache.clear(); const std::vector& points = po->get_support_points(); auto mat = po->trafo().inverse().cast(); for (unsigned int i=0; im_model_object->sla_points_status = sla::PointsStatus::AutoGenerated; + mo->sla_points_status = sla::PointsStatus::AutoGenerated; break; } } @@ -1241,10 +1298,12 @@ void GLGizmoSlaSupports::auto_generate() _(L("Are you sure you want to do it?")) + "\n", _(L("Warning")), wxICON_WARNING | wxYES | wxNO); - if (m_c->m_model_object->sla_points_status != sla::PointsStatus::UserModified || m_normal_cache.empty() || dlg.ShowModal() == wxID_YES) { + ModelObject* mo = m_c->selection_info()->model_object(); + + if (mo->sla_points_status != sla::PointsStatus::UserModified || m_normal_cache.empty() || dlg.ShowModal() == wxID_YES) { Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Autogenerate support points"))); wxGetApp().CallAfter([this]() { reslice_SLA_supports(); }); - m_c->m_model_object->sla_points_status = sla::PointsStatus::Generating; + mo->sla_points_status = sla::PointsStatus::Generating; } } @@ -1259,7 +1318,8 @@ void GLGizmoSlaSupports::switch_to_editing_mode() m_editing_cache.emplace_back(sp); select_point(NoPoints); - m_parent.toggle_sla_auxiliaries_visibility(false, m_c->m_model_object, m_c->m_active_instance); + //m_parent.toggle_sla_auxiliaries_visibility(false, m_c->m_model_object, m_c->m_active_instance); + m_c->instances_hider()->show_supports(false); m_parent.set_as_dirty(); } @@ -1269,7 +1329,8 @@ void GLGizmoSlaSupports::disable_editing_mode() if (m_editing_mode) { m_editing_mode = false; wxGetApp().plater()->leave_gizmos_stack(); - m_parent.toggle_sla_auxiliaries_visibility(true, m_c->m_model_object, m_c->m_active_instance); + //m_parent.toggle_sla_auxiliaries_visibility(true, m_c->m_model_object, m_c->m_active_instance); + m_c->instances_hider()->show_supports(true); m_parent.set_as_dirty(); } } @@ -1288,7 +1349,7 @@ bool GLGizmoSlaSupports::unsaved_changes() const return false; } - +/* void GLGizmoSlaSupports::update_clipping_plane(bool keep_normal) const { if (! m_c->m_model_object) @@ -1306,7 +1367,7 @@ void GLGizmoSlaSupports::update_clipping_plane(bool keep_normal) const float dist = normal.dot(center); *m_c->m_clipping_plane = ClippingPlane(normal, (dist - (-m_c->m_active_instance_bb_radius) - m_c->m_clipping_plane_distance * 2*m_c->m_active_instance_bb_radius)); m_parent.set_as_dirty(); -} +}*/ SlaGizmoHelpDialog::SlaGizmoHelpDialog() : wxDialog(nullptr, wxID_ANY, _(L("SLA gizmo keyboard shortcuts")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index bd48ecd65..81b347204 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -16,7 +16,7 @@ namespace GUI { class ClippingPlane; class MeshClipper; class MeshRaycaster; -class CommonGizmosData; +//class CommonGizmosData; enum class SLAGizmoEventType : unsigned char; class GLGizmoSlaSupports : public GLGizmoBase @@ -26,7 +26,7 @@ private: //ObjectID m_model_object_id = 0; //int m_active_instance = -1; //float m_active_instance_bb_radius; // to cache the bb - mutable double m_z_shift = 0.f; + //mutable double m_z_shift = 0.f; bool unproject_on_mesh(const Vec2d& mouse_pos, std::pair& pos_and_normal); const float RenderPointScale = 1.f; @@ -81,8 +81,8 @@ public: bool is_selection_rectangle_dragging() const { return m_selection_rectangle.is_dragging(); } bool has_backend_supports() const; void reslice_SLA_supports(bool postpone_error_messages = false) const; - void update_clipping_plane(bool keep_normal = false) const; - void set_common_data_ptr(CommonGizmosData* ptr) { m_c = ptr; } + //void update_clipping_plane(bool keep_normal = false) const; + //void set_common_data_ptr(CommonGizmosData* ptr) { m_c = ptr; } private: bool on_init() override; @@ -92,7 +92,7 @@ private: //void render_selection_rectangle() const; void render_points(const Selection& selection, bool picking = false) const; - void render_clipping_plane(const Selection& selection) const; + //void render_clipping_plane(const Selection& selection) const; bool unsaved_changes() const; bool m_lock_unique_islands = false; @@ -104,6 +104,7 @@ private: float m_density_stash = 0.f; // and again mutable std::vector m_editing_cache; // a support point and whether it is currently selected std::vector m_normal_cache; // to restore after discarding changes or undo/redo + const ModelObject* m_old_mo = nullptr; //std::unique_ptr m_clipping_plane; @@ -117,7 +118,7 @@ private: bool m_selection_empty = true; EState m_old_state = Off; // to be able to see that the gizmo has just been closed (see on_set_state) - CommonGizmosData* m_c = nullptr; + //CommonGizmosData* m_c = nullptr; //mutable std::unique_ptr m_object_clipper; //mutable std::unique_ptr m_supports_clipper; @@ -159,6 +160,7 @@ protected: std::string on_get_name() const override; bool on_is_activable() const override; bool on_is_selectable() const override; + virtual CommonGizmosDataID on_get_requirements() const override; void on_load(cereal::BinaryInputArchive& ar) override; void on_save(cereal::BinaryOutputArchive& ar) const override; }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index 380aa4e7d..a8e1801d7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -196,16 +196,18 @@ void HollowedMesh::on_update() size_t timestamp = print_object->step_state_with_timestamp(slaposDrillHoles).timestamp; if (timestamp > m_old_hollowing_timestamp) { const TriangleMesh& backend_mesh = print_object->get_mesh_to_print(); - m_hollowed_mesh_transformed.reset(new TriangleMesh(backend_mesh)); - Transform3d trafo_inv = canvas->sla_print()->sla_trafo(*mo).inverse(); - m_hollowed_mesh_transformed->transform(trafo_inv); - m_old_hollowing_timestamp = timestamp; + if (! backend_mesh.empty()) { + m_hollowed_mesh_transformed.reset(new TriangleMesh(backend_mesh)); + Transform3d trafo_inv = canvas->sla_print()->sla_trafo(*mo).inverse(); + m_hollowed_mesh_transformed->transform(trafo_inv); + m_old_hollowing_timestamp = timestamp; + } + else + m_hollowed_mesh_transformed.reset(nullptr); } } - else { + else m_hollowed_mesh_transformed.reset(nullptr); - m_old_hollowing_timestamp = 0; - } } } @@ -417,7 +419,7 @@ void SupportsClipper::render_cut() const const SelectionInfo* sel_info = get_pool()->selection_info(); const ModelObject* mo = sel_info->model_object(); Geometry::Transformation inst_trafo = mo->instances[sel_info->get_active_instance()]->get_transformation(); - Geometry::Transformation vol_trafo = mo->volumes.front()->get_transformation(); + //Geometry::Transformation vol_trafo = mo->volumes.front()->get_transformation(); Geometry::Transformation trafo = inst_trafo;// * vol_trafo; trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., sel_info->get_sla_shift())); diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index ed9bd5de3..884d63b4c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -9,10 +9,10 @@ #include "slic3r/GUI/GUI_ObjectManipulation.hpp" #include "slic3r/GUI/PresetBundle.hpp" #include "slic3r/Utils/UndoRedo.hpp" -#include "libslic3r/SLAPrint.hpp" -#include "slic3r/GUI/MeshUtils.hpp" +//#include "libslic3r/SLAPrint.hpp" +//#include "slic3r/GUI/MeshUtils.hpp" #include "slic3r/GUI/Gizmos/GLGizmos.hpp" -#include "slic3r/GUI/Camera.hpp" +//#include "slic3r/GUI/Camera.hpp" #include @@ -96,7 +96,7 @@ bool GLGizmosManager::init() m_gizmos.emplace_back(new GLGizmoFlatten(m_parent, "place.svg", 3)); m_gizmos.emplace_back(new GLGizmoCut(m_parent, "cut.svg", 4)); m_gizmos.emplace_back(new GLGizmoHollow(m_parent, "hollow.svg", 5)); - //m_gizmos.emplace_back(new GLGizmoSlaSupports(m_parent, "sla_supports.svg", 6)); + m_gizmos.emplace_back(new GLGizmoSlaSupports(m_parent, "sla_supports.svg", 6)); //m_common_gizmos_data.reset(new CommonGizmosData()); //dynamic_cast(m_gizmos[Hollow].get())->set_common_data_ptr(m_common_gizmos_data.get()); @@ -375,7 +375,9 @@ void GLGizmosManager::set_sla_support_data(ModelObject* model_object) //gizmo_supports->set_sla_support_data(model_object, m_parent.get_selection()); */ auto* gizmo_hollow = dynamic_cast(m_gizmos[Hollow].get()); + auto* gizmo_supports = dynamic_cast(m_gizmos[SlaSupports].get()); gizmo_hollow->set_sla_support_data(model_object, m_parent.get_selection()); + gizmo_supports->set_sla_support_data(model_object, m_parent.get_selection()); } // Returns true if the gizmo used the event to do something, false otherwise. @@ -1217,7 +1219,7 @@ bool GLGizmosManager::grabber_contains_mouse() const } - +/* CommonGizmosData::CommonGizmosData() { m_clipping_plane.reset(new ClippingPlane(Vec3d::Zero(), 0.)); @@ -1344,7 +1346,7 @@ void CommonGizmosData::build_AABB_if_needed() m_supports_clipper.reset(); m_old_mesh = m_mesh; m_schedule_aabb_calculation = false; -} +}*/ } // namespace GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp index f01ecfd77..81fd991b7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp @@ -3,7 +3,7 @@ #include "slic3r/GUI/GLTexture.hpp" #include "slic3r/GUI/GLToolbar.hpp" -#include "libslic3r/ObjectID.hpp" +//#include "libslic3r/ObjectID.hpp" #include "slic3r/GUI/Gizmos/GLGizmoBase.hpp" #include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" @@ -20,7 +20,7 @@ namespace GUI { class GLCanvas3D; class ClippingPlane; enum class SLAGizmoEventType : unsigned char; -class CommonGizmosData; +//class CommonGizmosData; class CommonGizmosDataPool; class Rect @@ -234,13 +234,13 @@ private: -class MeshRaycaster; -class MeshClipper; +//class MeshRaycaster; +//class MeshClipper; // This class is only for sharing SLA related data between SLA gizmos // and its synchronization with backend data. It should not be misused // for anything else. -class CommonGizmosData { +/*class CommonGizmosData { public: CommonGizmosData(); const TriangleMesh* mesh() const { @@ -290,7 +290,7 @@ private: bool m_has_drilled_mesh = false; bool m_schedule_aabb_calculation = false; }; - +*/ } // namespace GUI } // namespace Slic3r From 535a27de65decbf0b16f85ff8004dc8935d86775 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 7 Apr 2020 15:55:54 +0200 Subject: [PATCH 21/28] Fixed crash related to ClippingPlane and incorrect handling of sla z shift in hollowing gizmo --- src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 8 ++++---- src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp | 4 ++-- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 4 ++-- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 13 +++++++++++-- 5 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index 46c570c19..3c82806ca 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -223,7 +223,7 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) cons const Transform3d& instance_matrix = vol->get_instance_transformation().get_matrix(); glsafe(::glPushMatrix()); - glsafe(::glTranslated(0.0, 0.0, m_z_shift)); + glsafe(::glTranslated(0.0, 0.0, m_c->selection_info()->get_sla_shift())); glsafe(::glMultMatrixd(instance_matrix.data())); float render_color[4]; @@ -444,7 +444,7 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos // First collect positions of all the points in world coordinates. Geometry::Transformation trafo = mo->instances[active_inst]->get_transformation(); - trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_z_shift)); + trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_c->selection_info()->get_sla_shift())); std::vector points; for (unsigned int i=0; isla_drain_holes.size(); ++i) points.push_back(trafo.get_matrix() * mo->sla_drain_holes[i].pos.cast()); @@ -607,7 +607,7 @@ GLGizmoHollow::get_config_options(const std::vector& keys) const return out; } - +/* ClippingPlane GLGizmoHollow::get_sla_clipping_plane() const { if (! m_c->selection_info()->model_object() @@ -619,7 +619,7 @@ ClippingPlane GLGizmoHollow::get_sla_clipping_plane() const return ClippingPlane(-clp.get_normal(), clp.get_data()[3]); } } - +*/ void GLGizmoHollow::on_render_input_window(float x, float y, float bottom_limit) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp index 178579ba1..73d26b2da 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp @@ -22,7 +22,7 @@ enum class SLAGizmoEventType : unsigned char; class GLGizmoHollow : public GLGizmoBase { private: - mutable double m_z_shift = 0.; + //mutable double m_z_shift = 0.; bool unproject_on_mesh(const Vec2d& mouse_pos, std::pair& pos_and_normal); GLUquadricObj* m_quadric; @@ -34,7 +34,7 @@ public: void set_sla_support_data(ModelObject* model_object, const Selection& selection); bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down); void delete_selected_points(); - ClippingPlane get_sla_clipping_plane() const; + //ClippingPlane get_sla_clipping_plane() const; bool is_selection_rectangle_dragging() const { return m_selection_rectangle.is_dragging(); } //void set_common_data_ptr(CommonGizmosData* ptr) { m_c = ptr; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index ac65d9313..16ac6ec3c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -691,7 +691,7 @@ std::vector GLGizmoSlaSupports::get_config_options(const st return out; } - +/* ClippingPlane GLGizmoSlaSupports::get_sla_clipping_plane() const { //if (!m_c->m_model_object || m_state == Off || m_c->m_clipping_plane_distance == 0.f) @@ -707,7 +707,7 @@ ClippingPlane GLGizmoSlaSupports::get_sla_clipping_plane() const return ClippingPlane(-clp.get_normal(), clp.get_data()[3]); } } - +*/ /* void GLGizmoSlaSupports::find_intersecting_facets(const igl::AABB* aabb, const Vec3f& normal, double offset, std::vector& idxs) const diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index 81b347204..2b7b1ae78 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -75,7 +75,7 @@ public: void set_sla_support_data(ModelObject* model_object, const Selection& selection); bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down); void delete_selected_points(bool force = false); - ClippingPlane get_sla_clipping_plane() const; + //ClippingPlane get_sla_clipping_plane() const; bool is_in_editing_mode() const { return m_editing_mode; } bool is_selection_rectangle_dragging() const { return m_selection_rectangle.is_dragging(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 884d63b4c..61d0bd5f4 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -395,13 +395,22 @@ bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_p ClippingPlane GLGizmosManager::get_sla_clipping_plane() const { - if (!m_enabled || (m_current != SlaSupports && m_current != Hollow) || m_gizmos.empty()) + if (! m_common_gizmos_data->object_clipper() + || m_common_gizmos_data->object_clipper()->get_position() == 0.) + return ClippingPlane::ClipsNothing(); + else { + const ClippingPlane& clp = *m_common_gizmos_data->object_clipper()->get_clipping_plane(); + return ClippingPlane(-clp.get_normal(), clp.get_data()[3]); + } + + + /*if (!m_enabled || (m_current != SlaSupports && m_current != Hollow) || m_gizmos.empty()) return ClippingPlane::ClipsNothing(); if (m_current == SlaSupports) return dynamic_cast(m_gizmos[SlaSupports].get())->get_sla_clipping_plane(); else - return dynamic_cast(m_gizmos[Hollow].get())->get_sla_clipping_plane(); + return dynamic_cast(m_gizmos[Hollow].get())->get_sla_clipping_plane();*/ } bool GLGizmosManager::wants_reslice_supports_on_undo() const From 1d65ce760b8b9a7fc401d873379c3f0bb1c89603 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 7 Apr 2020 16:19:53 +0200 Subject: [PATCH 22/28] Removed obsolete code Got rid of dummy header GLGizmos.hpp --- src/slic3r/CMakeLists.txt | 1 - src/slic3r/GUI/GLCanvas3D.cpp | 1 - src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 168 +--------------- src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp | 19 +- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 200 +------------------ src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp | 28 +-- src/slic3r/GUI/Gizmos/GLGizmos.hpp | 37 ---- src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 18 ++ src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 152 +------------- src/slic3r/GUI/Gizmos/GLGizmosManager.hpp | 59 ------ 10 files changed, 35 insertions(+), 648 deletions(-) delete mode 100644 src/slic3r/GUI/Gizmos/GLGizmos.hpp diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index f13c6084b..02275aeda 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -31,7 +31,6 @@ set(SLIC3R_GUI_SOURCES GUI/GLCanvas3DManager.cpp GUI/Selection.hpp GUI/Selection.cpp - GUI/Gizmos/GLGizmos.hpp GUI/Gizmos/GLGizmosManager.cpp GUI/Gizmos/GLGizmosManager.hpp GUI/Gizmos/GLGizmosCommon.cpp diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 74abbebdd..064f01cf2 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1,5 +1,4 @@ #include "libslic3r/libslic3r.h" -#include "slic3r/GUI/Gizmos/GLGizmos.hpp" #include "GLCanvas3D.hpp" #include "admesh/stl.h" diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index 3c82806ca..3c7e7a236 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -1,7 +1,6 @@ #include "GLGizmoHollow.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/Camera.hpp" -#include "slic3r/GUI/Gizmos/GLGizmos.hpp" #include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" #include @@ -63,34 +62,6 @@ void GLGizmoHollow::set_sla_support_data(ModelObject*, const Selection&) if (m_c->hollowed_mesh()->get_hollowed_mesh()) m_holes_in_drilled_mesh = mo->sla_drain_holes; } - - /*if (m_c->recent_update) { - - if (m_state == On) - m_c->build_AABB_if_needed(); - - update_clipping_plane(m_c->m_clipping_plane_was_moved); - - // This is a temporary and not very nice hack, to make sure that - // if the cp was moved by the data returned by backend, it will - // remember its direction. FIXME: Refactor this mess and make - // the clipping plane itself part of the shared data. - if (! m_c->m_clipping_plane_was_moved && m_c->m_clipping_plane_distance == 0.25f) - m_c->m_clipping_plane_was_moved = true; - - - if (m_c->m_model_object) { - reload_cache(); - if (m_c->has_drilled_mesh()) - m_holes_in_drilled_mesh = m_c->m_model_object->sla_drain_holes; - } - } - - if (m_state == On) { - m_parent.toggle_model_objects_visibility(false); - m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance); - m_parent.toggle_sla_auxiliaries_visibility(m_show_supports, m_c->m_model_object, m_c->m_active_instance); - }*/ } @@ -111,13 +82,10 @@ void GLGizmoHollow::on_render() const glsafe(::glEnable(GL_BLEND)); glsafe(::glEnable(GL_DEPTH_TEST)); - //m_z_shift = selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z(); - if (m_quadric != nullptr && selection.is_from_single_instance()) render_points(selection, false); m_selection_rectangle.render(m_parent); - //render_clipping_plane(selection); m_c->object_clipper()->render_cut(); m_c->supports_clipper()->render_cut(); @@ -125,83 +93,6 @@ void GLGizmoHollow::on_render() const } - -void GLGizmoHollow::render_clipping_plane(const Selection& selection) const -{ - return; -/* - if (m_c->m_clipping_plane_distance == 0.f) - return; - - // Get transformation of the instance - const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin()); - Geometry::Transformation trafo = vol->get_instance_transformation(); - trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_z_shift)); - - // Get transformation of supports - Geometry::Transformation supports_trafo; - supports_trafo.set_offset(Vec3d(trafo.get_offset()(0), trafo.get_offset()(1), vol->get_sla_shift_z())); - supports_trafo.set_rotation(Vec3d(0., 0., trafo.get_rotation()(2))); - // I don't know why, but following seems to be correct. - supports_trafo.set_mirror(Vec3d(trafo.get_mirror()(0) * trafo.get_mirror()(1) * trafo.get_mirror()(2), - 1, - 1.)); - - // Now initialize the TMS for the object, perform the cut and save the result. - if (! m_c->m_object_clipper) { - m_c->m_object_clipper.reset(new MeshClipper); - m_c->m_object_clipper->set_mesh(*m_c->mesh()); - } - m_c->m_object_clipper->set_plane(*m_c->m_clipping_plane); - m_c->m_object_clipper->set_transformation(trafo); - - if (m_c->m_print_object_idx >= 0) { - const SLAPrintObject* print_object = m_parent.sla_print()->objects()[m_c->m_print_object_idx]; - - if (print_object->is_step_done(slaposSupportTree) && !print_object->get_mesh(slaposSupportTree).empty()) { - // If the supports are already calculated, save the timestamp of the respective step - // so we can later tell they were recalculated. - size_t timestamp = print_object->step_state_with_timestamp(slaposSupportTree).timestamp; - - if (! m_c->m_supports_clipper || (int)timestamp != m_c->m_old_timestamp) { - // The timestamp has changed. - m_c->m_supports_clipper.reset(new MeshClipper); - // The mesh should already have the shared vertices calculated. - m_c->m_supports_clipper->set_mesh(print_object->support_mesh()); - m_c->m_old_timestamp = timestamp; - } - m_c->m_supports_clipper->set_plane(*m_c->m_clipping_plane); - m_c->m_supports_clipper->set_transformation(supports_trafo); - } - else - // The supports are not valid. We better dump the cached data. - m_c->m_supports_clipper.reset(); - } - - // At this point we have the triangulated cuts for both the object and supports - let's render. - if (! m_c->m_object_clipper->get_triangles().empty()) { - ::glPushMatrix(); - ::glColor3f(1.0f, 0.37f, 0.0f); - ::glBegin(GL_TRIANGLES); - for (const Vec3f& point : m_c->m_object_clipper->get_triangles()) - ::glVertex3f(point(0), point(1), point(2)); - ::glEnd(); - ::glPopMatrix(); - } - - if (m_show_supports && m_c->m_supports_clipper && ! m_c->m_supports_clipper->get_triangles().empty()) { - ::glPushMatrix(); - ::glColor3f(1.0f, 0.f, 0.37f); - ::glBegin(GL_TRIANGLES); - for (const Vec3f& point : m_c->m_supports_clipper->get_triangles()) - ::glVertex3f(point(0), point(1), point(2)); - ::glEnd(); - ::glPopMatrix(); - } -*/ -} - - void GLGizmoHollow::on_render_for_picking() const { const Selection& selection = m_parent.get_selection(); @@ -272,7 +163,6 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) cons glFrontFace(GL_CW); // Matrices set, we can render the point mark now. - Eigen::Quaterniond q; q.setFromTwoVectors(Vec3d{0., 0., 1.}, instance_scaling_matrix_inverse * (-drain_hole.normal).cast()); Eigen::AngleAxisd aa(q); @@ -456,13 +346,9 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos points_inside.push_back(points[idx].cast()); // Only select/deselect points that are actually visible -#if ENABLE_NON_STATIC_CANVAS_MANAGER for (size_t idx : m_c->raycaster()->raycaster()->get_unobscured_idxs( trafo, wxGetApp().plater()->get_camera(), points_inside, m_c->object_clipper()->get_clipping_plane())) -#else - for (size_t idx : m_c->m_mesh_raycaster->get_unobscured_idxs(trafo, m_parent.get_camera(), points_inside, m_c->m_clipping_plane.get())) -#endif // ENABLE_NON_STATIC_CANVAS_MANAGER { if (rectangle_status == GLSelectionRectangle::Deselect) unselect_point(points_idxs[idx]); @@ -519,8 +405,6 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos double pos = m_c->object_clipper()->get_position(); pos = std::min(1., pos + 0.01); m_c->object_clipper()->set_position(pos, true); - //update_clipping_plane(/*m_c->m_clipping_plane_was_moved*/); - //m_c->m_clipping_plane_was_moved = true; return true; } @@ -528,7 +412,6 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos double pos = m_c->object_clipper()->get_position(); pos = std::max(0., pos - 0.01); m_c->object_clipper()->set_position(pos, true); - //update_clipping_plane(true); return true; } @@ -607,19 +490,6 @@ GLGizmoHollow::get_config_options(const std::vector& keys) const return out; } -/* -ClippingPlane GLGizmoHollow::get_sla_clipping_plane() const -{ - if (! m_c->selection_info()->model_object() - || m_state == Off - || m_c->object_clipper()->get_position() == 0.) - return ClippingPlane::ClipsNothing(); - else { - const ClippingPlane& clp = *m_c->object_clipper()->get_clipping_plane(); - return ClippingPlane(-clp.get_normal(), clp.get_data()[3]); - } -} -*/ void GLGizmoHollow::on_render_input_window(float x, float y, float bottom_limit) { @@ -863,7 +733,6 @@ RENDER_AGAIN: // make sure supports are shown/hidden as appropriate bool show_sups = m_c->instances_hider()->are_supports_shown(); if (m_imgui->checkbox(m_desc["show_supports"], show_sups)) { - // m_parent.toggle_sla_auxiliaries_visibility(m_show_supports, mo, m_c->m_active_instance); m_c->instances_hider()->show_supports(show_sups); force_refresh = true; } @@ -937,51 +806,16 @@ CommonGizmosDataID GLGizmoHollow::on_get_requirements() const void GLGizmoHollow::on_set_state() { - // m_c->m_model_object pointer can be invalid (for instance because of undo/redo action), - // we should recover it from the object id - /*m_c->m_model_object = nullptr; - for (const auto mo : wxGetApp().model().objects) { - if (mo->id() == m_c->m_model_object_id) { - m_c->m_model_object = mo; - break; - } - }*/ - if (m_state == m_old_state) return; if (m_state == On && m_old_state != On) { // the gizmo was just turned on - //Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned on"))); - //m_c->update_from_backend(m_parent, m_c->m_model_object); - //m_c->unstash_clipping_plane(); - //update_clipping_plane(/*m_c->m_clipping_plane_was_moved*/); - - //m_c->build_AABB_if_needed(); - // we'll now reload support points: if (m_c->selection_info()->model_object()) reload_cache(); - - /*m_parent.toggle_model_objects_visibility(false); - if (m_c->m_model_object) { - m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance); - m_parent.toggle_sla_auxiliaries_visibility(m_show_supports, m_c->m_model_object, m_c->m_active_instance); - }*/ } - if (m_state == Off && m_old_state != Off) { // the gizmo was just turned Off - //Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned off"))); + if (m_state == Off && m_old_state != Off) // the gizmo was just turned Off m_parent.post_event(SimpleEvent(EVT_GLCANVAS_FORCE_UPDATE)); - //m_parent.toggle_model_objects_visibility(true); - //m_c->stash_clipping_plane(); - //m_c->m_clipping_plane_distance = 0.f; - //update_clipping_plane(true); - // Release clippers and the AABB raycaster. - //m_c->m_object_clipper.reset(); - //m_c->m_supports_clipper.reset(); - //m_c->m_mesh_raycaster.reset(); - //m_c->m_cavity_mesh.reset(); - //m_c->m_volume_with_cavity.reset(); - } m_old_state = m_state; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp index 73d26b2da..3ee83c345 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp @@ -13,16 +13,11 @@ namespace Slic3r { namespace GUI { -class ClippingPlane; -class MeshClipper; -class MeshRaycaster; -//class CommonGizmosData; enum class SLAGizmoEventType : unsigned char; class GLGizmoHollow : public GLGizmoBase { private: - //mutable double m_z_shift = 0.; bool unproject_on_mesh(const Vec2d& mouse_pos, std::pair& pos_and_normal); GLUquadricObj* m_quadric; @@ -33,11 +28,10 @@ public: ~GLGizmoHollow() override; void set_sla_support_data(ModelObject* model_object, const Selection& selection); bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down); - void delete_selected_points(); - //ClippingPlane get_sla_clipping_plane() const; - - bool is_selection_rectangle_dragging() const { return m_selection_rectangle.is_dragging(); } - //void set_common_data_ptr(CommonGizmosData* ptr) { m_c = ptr; } + void delete_selected_points(); + bool is_selection_rectangle_dragging() const { + return m_selection_rectangle.is_dragging(); + } private: bool on_init() override; @@ -46,7 +40,6 @@ private: void on_render_for_picking() const override; void render_points(const Selection& selection, bool picking = false) const; - void render_clipping_plane(const Selection& selection) const; void hollow_mesh(bool postpone_error_messages = false); bool unsaved_changes() const; @@ -66,10 +59,6 @@ private: sla::DrainHoles m_holes_in_drilled_mesh; sla::DrainHoles m_holes_stash; - - //CommonGizmosData* m_c = nullptr; - - //std::unique_ptr m_clipping_plane; // This map holds all translated description texts, so they can be easily referenced during layout calculations // etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect. diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 16ac6ec3c..496568d51 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -2,7 +2,6 @@ #include "GLGizmoSlaSupports.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/Camera.hpp" -#include "slic3r/GUI/Gizmos/GLGizmos.hpp" #include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" #include @@ -15,7 +14,6 @@ #include "slic3r/GUI/GUI.hpp" #include "slic3r/GUI/GUI_ObjectSettings.hpp" #include "slic3r/GUI/GUI_ObjectList.hpp" -#include "slic3r/GUI/MeshUtils.hpp" #include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/PresetBundle.hpp" #include "libslic3r/SLAPrint.hpp" @@ -27,7 +25,6 @@ namespace GUI { GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) , m_quadric(nullptr) - , m_its(nullptr) { m_quadric = ::gluNewQuadric(); if (m_quadric != nullptr) @@ -76,24 +73,6 @@ void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const S m_old_mo = mo; } - /* - if (m_c->recent_update) { - if (m_state == On) - m_c->build_AABB_if_needed(); - - update_clipping_plane(m_c->m_clipping_plane_was_moved); - - disable_editing_mode(); - if (m_c->m_model_object) - reload_cache(); - } - - if (m_state == On) { - m_parent.toggle_model_objects_visibility(false); - m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance); - m_parent.toggle_sla_auxiliaries_visibility(! m_editing_mode, m_c->m_model_object, m_c->m_active_instance); - }*/ - // If we triggered autogeneration before, check backend and fetch results if they are there if (mo) { if (mo->sla_points_status == sla::PointsStatus::Generating) @@ -111,8 +90,7 @@ void GLGizmoSlaSupports::on_render() const // If current m_c->m_model_object does not match selection, ask GLCanvas3D to turn us off if (m_state == On && (mo != selection.get_model()->objects[selection.get_object_idx()] - || m_c->selection_info()->get_active_instance() != selection.get_instance_idx() - /*|| m_c->m_model_object_id != m_c->m_model_object->id()*/)) { + || m_c->selection_info()->get_active_instance() != selection.get_instance_idx())) { m_parent.post_event(SimpleEvent(EVT_GLCANVAS_RESETGIZMOS)); return; } @@ -120,116 +98,20 @@ void GLGizmoSlaSupports::on_render() const glsafe(::glEnable(GL_BLEND)); glsafe(::glEnable(GL_DEPTH_TEST)); -// m_z_shift = selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z(); - if (m_quadric != nullptr && selection.is_from_single_instance()) render_points(selection, false); m_selection_rectangle.render(m_parent); m_c->object_clipper()->render_cut(); m_c->supports_clipper()->render_cut(); - //render_clipping_plane(selection); glsafe(::glDisable(GL_BLEND)); } - -/*void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const -{ - if (m_c->m_clipping_plane_distance == 0.f || m_c->m_mesh->empty()) - return; - - // Get transformation of the instance - const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin()); - Geometry::Transformation trafo = vol->get_instance_transformation(); - trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_z_shift)); - - // Get transformation of supports - Geometry::Transformation supports_trafo; - supports_trafo.set_offset(Vec3d(trafo.get_offset()(0), trafo.get_offset()(1), vol->get_sla_shift_z())); - supports_trafo.set_rotation(Vec3d(0., 0., trafo.get_rotation()(2))); - // I don't know why, but following seems to be correct. - supports_trafo.set_mirror(Vec3d(trafo.get_mirror()(0) * trafo.get_mirror()(1) * trafo.get_mirror()(2), - 1, - 1.)); - - // Now initialize the TMS for the object, perform the cut and save the result. - if (! m_c->m_object_clipper) { - m_c->m_object_clipper.reset(new MeshClipper); - m_c->m_object_clipper->set_mesh(*m_c->mesh()); - } - m_c->m_object_clipper->set_plane(*m_c->m_clipping_plane); - m_c->m_object_clipper->set_transformation(trafo); - - - // Next, ask the backend if supports are already calculated. If so, we are gonna cut them too. - // First we need a pointer to the respective SLAPrintObject. The index into objects vector is - // cached so we don't have todo it on each render. We only search for the po if needed: - if (m_c->m_print_object_idx < 0 || (int)m_parent.sla_print()->objects().size() != m_c->m_print_objects_count) { - m_c->m_print_objects_count = m_parent.sla_print()->objects().size(); - m_c->m_print_object_idx = -1; - for (const SLAPrintObject* po : m_parent.sla_print()->objects()) { - ++m_c->m_print_object_idx; - if (po->model_object()->id() == m_c->m_model_object->id()) - break; - } - } - if (m_c->m_print_object_idx >= 0) { - const SLAPrintObject* print_object = m_parent.sla_print()->objects()[m_c->m_print_object_idx]; - - if (print_object->is_step_done(slaposSupportTree) && !print_object->get_mesh(slaposSupportTree).empty()) { - // If the supports are already calculated, save the timestamp of the respective step - // so we can later tell they were recalculated. - size_t timestamp = print_object->step_state_with_timestamp(slaposSupportTree).timestamp; - - if (! m_c->m_supports_clipper || (int)timestamp != m_c->m_old_timestamp) { - // The timestamp has changed. - m_c->m_supports_clipper.reset(new MeshClipper); - // The mesh should already have the shared vertices calculated. - m_c->m_supports_clipper->set_mesh(print_object->support_mesh()); - m_c->m_old_timestamp = timestamp; - } - m_c->m_supports_clipper->set_plane(*m_c->m_clipping_plane); - m_c->m_supports_clipper->set_transformation(supports_trafo); - } - else - // The supports are not valid. We better dump the cached data. - m_c->m_supports_clipper.reset(); - } - - // At this point we have the triangulated cuts for both the object and supports - let's render. - if (! m_c->m_object_clipper->get_triangles().empty()) { - ::glPushMatrix(); - ::glColor3f(1.0f, 0.37f, 0.0f); - ::glBegin(GL_TRIANGLES); - for (const Vec3f& point : m_c->m_object_clipper->get_triangles()) - ::glVertex3f(point(0), point(1), point(2)); - ::glEnd(); - ::glPopMatrix(); - } - - if (m_c->m_supports_clipper && ! m_c->m_supports_clipper->get_triangles().empty() && !m_editing_mode) { - // The supports are hidden in the editing mode, so it makes no sense to render the cuts. - ::glPushMatrix(); - ::glColor3f(1.0f, 0.f, 0.37f); - ::glBegin(GL_TRIANGLES); - for (const Vec3f& point : m_c->m_supports_clipper->get_triangles()) - ::glVertex3f(point(0), point(1), point(2)); - ::glEnd(); - ::glPopMatrix(); - } -}*/ - - void GLGizmoSlaSupports::on_render_for_picking() const { const Selection& selection = m_parent.get_selection(); -/* -#if ENABLE_RENDER_PICKING_PASS - m_z_shift = selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z(); -#endif -*/ glsafe(::glEnable(GL_DEPTH_TEST)); render_points(selection, true); } @@ -404,11 +286,7 @@ bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pairraycaster()->raycaster()) return false; -#if ENABLE_NON_STATIC_CANVAS_MANAGER const Camera& camera = wxGetApp().plater()->get_camera(); -#else - const Camera& camera = m_parent.get_camera(); -#endif // ENABLE_NON_STATIC_CANVAS_MANAGER const Selection& selection = m_parent.get_selection(); const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); Geometry::Transformation trafo = volume->get_instance_transformation(); @@ -607,8 +485,6 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous double pos = m_c->object_clipper()->get_position(); pos = std::min(1., pos + 0.01); m_c->object_clipper()->set_position(pos, true); - //update_clipping_plane(/*m_c->m_clipping_plane_was_moved*/); - //m_c->m_clipping_plane_was_moved = true; return true; } @@ -616,12 +492,10 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous double pos = m_c->object_clipper()->get_position(); pos = std::max(0., pos - 0.01); m_c->object_clipper()->set_position(pos, true); - //update_clipping_plane(true); return true; } if (action == SLAGizmoEventType::ResetClippingPlane) { - //update_clipping_plane(); m_c->object_clipper()->set_position(-1., false); return true; } @@ -691,23 +565,7 @@ std::vector GLGizmoSlaSupports::get_config_options(const st return out; } -/* -ClippingPlane GLGizmoSlaSupports::get_sla_clipping_plane() const -{ - //if (!m_c->m_model_object || m_state == Off || m_c->m_clipping_plane_distance == 0.f) - // return ClippingPlane::ClipsNothing(); - //else - // return ClippingPlane(-m_c->m_clipping_plane->get_normal(), m_c->m_clipping_plane->get_data()[3]); - if (! m_c->selection_info()->model_object() - || m_state == Off - || m_c->object_clipper()->get_position() == 0.) - return ClippingPlane::ClipsNothing(); - else { - const ClippingPlane& clp = *m_c->object_clipper()->get_clipping_plane(); - return ClippingPlane(-clp.get_normal(), clp.get_data()[3]); - } -} -*/ + /* void GLGizmoSlaSupports::find_intersecting_facets(const igl::AABB* aabb, const Vec3f& normal, double offset, std::vector& idxs) const @@ -937,7 +795,6 @@ RENDER_AGAIN: else { if (m_imgui->button(m_desc.at("reset_direction"))) { wxGetApp().CallAfter([this](){ - //update_clipping_plane(); m_c->object_clipper()->set_position(-1., false); }); } @@ -1028,15 +885,6 @@ CommonGizmosDataID GLGizmoSlaSupports::on_get_requirements() const void GLGizmoSlaSupports::on_set_state() { const ModelObject* mo = m_c->selection_info()->model_object(); - // m_c->m_model_object pointer can be invalid (for instance because of undo/redo action), - // we should recover it from the object id - /*m_c->m_model_object = nullptr; - for (const auto mo : wxGetApp().model().objects) { - if (mo->id() == m_c->m_model_object_id) { - m_c->m_model_object = mo; - break; - } - }*/ if (m_state == m_old_state) return; @@ -1044,22 +892,10 @@ void GLGizmoSlaSupports::on_set_state() if (m_state == On && m_old_state != On) { // the gizmo was just turned on Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned on"))); - //m_c->unstash_clipping_plane(); - //update_clipping_plane(m_c->m_clipping_plane_was_moved); - - //m_c->build_AABB_if_needed(); - - // we'll now reload support points: if (mo) reload_cache(); - /*m_parent.toggle_model_objects_visibility(false); - if (m_c->m_model_object) { - m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance); - m_parent.toggle_sla_auxiliaries_visibility(! m_editing_mode, m_c->m_model_object, m_c->m_active_instance); - }*/ - // Set default head diameter from config. const DynamicPrintConfig& cfg = wxGetApp().preset_bundle->sla_prints.get_edited_preset().config; m_new_point_head_diameter = static_cast(cfg.option("support_head_front_diameter"))->value; @@ -1084,16 +920,8 @@ void GLGizmoSlaSupports::on_set_state() // we are actually shutting down disable_editing_mode(); // so it is not active next time the gizmo opens Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned off"))); - //m_parent.toggle_model_objects_visibility(true); m_normal_cache.clear(); - //m_c->stash_clipping_plane(); - //m_c->m_clipping_plane_distance = 0.f; - //update_clipping_plane(true); - // Release clippers and the AABB raycaster. - //m_its = nullptr; - //m_c->m_object_clipper.reset(); - //m_c->m_supports_clipper.reset(); - //m_c->m_mesh_raycaster.reset(); + } } m_old_state = m_state; @@ -1318,7 +1146,6 @@ void GLGizmoSlaSupports::switch_to_editing_mode() m_editing_cache.emplace_back(sp); select_point(NoPoints); - //m_parent.toggle_sla_auxiliaries_visibility(false, m_c->m_model_object, m_c->m_active_instance); m_c->instances_hider()->show_supports(false); m_parent.set_as_dirty(); } @@ -1329,7 +1156,6 @@ void GLGizmoSlaSupports::disable_editing_mode() if (m_editing_mode) { m_editing_mode = false; wxGetApp().plater()->leave_gizmos_stack(); - //m_parent.toggle_sla_auxiliaries_visibility(true, m_c->m_model_object, m_c->m_active_instance); m_c->instances_hider()->show_supports(true); m_parent.set_as_dirty(); } @@ -1349,26 +1175,6 @@ bool GLGizmoSlaSupports::unsaved_changes() const return false; } -/* -void GLGizmoSlaSupports::update_clipping_plane(bool keep_normal) const -{ - if (! m_c->m_model_object) - return; - -#if ENABLE_NON_STATIC_CANVAS_MANAGER - Vec3d normal = (keep_normal && m_c->m_clipping_plane->get_normal() != Vec3d::Zero() ? - m_c->m_clipping_plane->get_normal() : -wxGetApp().plater()->get_camera().get_dir_forward()); -#else - Vec3d normal = (keep_normal && m_c->m_clipping_plane->get_normal() != Vec3d::Zero() ? - m_c->m_clipping_plane->get_normal() : -m_parent.get_camera().get_dir_forward()); -#endif // ENABLE_NON_STATIC_CANVAS_MANAGER - - const Vec3d& center = m_c->m_model_object->instances[m_c->m_active_instance]->get_offset() + Vec3d(0., 0., m_z_shift); - float dist = normal.dot(center); - *m_c->m_clipping_plane = ClippingPlane(normal, (dist - (-m_c->m_active_instance_bb_radius) - m_c->m_clipping_plane_distance * 2*m_c->m_active_instance_bb_radius)); - m_parent.set_as_dirty(); -}*/ - SlaGizmoHelpDialog::SlaGizmoHelpDialog() : wxDialog(nullptr, wxID_ANY, _(L("SLA gizmo keyboard shortcuts")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index 2b7b1ae78..43454609a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -13,20 +13,12 @@ namespace Slic3r { namespace GUI { -class ClippingPlane; -class MeshClipper; -class MeshRaycaster; -//class CommonGizmosData; enum class SLAGizmoEventType : unsigned char; class GLGizmoSlaSupports : public GLGizmoBase { private: - //ModelObject* m_model_object = nullptr; - //ObjectID m_model_object_id = 0; - //int m_active_instance = -1; - //float m_active_instance_bb_radius; // to cache the bb - //mutable double m_z_shift = 0.f; + bool unproject_on_mesh(const Vec2d& mouse_pos, std::pair& pos_and_normal); const float RenderPointScale = 1.f; @@ -35,13 +27,6 @@ private: typedef Eigen::Map> MapMatrixXfUnaligned; typedef Eigen::Map> MapMatrixXiUnaligned; - //std::unique_ptr m_mesh_raycaster; - //const TriangleMesh* m_mesh; - const indexed_triangle_set* m_its; - //mutable int m_old_timestamp = -1; - //mutable int m_print_object_idx = -1; - //mutable int m_print_objects_count = -1; - class CacheEntry { public: CacheEntry() : @@ -81,8 +66,6 @@ public: bool is_selection_rectangle_dragging() const { return m_selection_rectangle.is_dragging(); } bool has_backend_supports() const; void reslice_SLA_supports(bool postpone_error_messages = false) const; - //void update_clipping_plane(bool keep_normal = false) const; - //void set_common_data_ptr(CommonGizmosData* ptr) { m_c = ptr; } private: bool on_init() override; @@ -90,9 +73,7 @@ private: void on_render() const override; void on_render_for_picking() const override; - //void render_selection_rectangle() const; void render_points(const Selection& selection, bool picking = false) const; - //void render_clipping_plane(const Selection& selection) const; bool unsaved_changes() const; bool m_lock_unique_islands = false; @@ -106,8 +87,6 @@ private: std::vector m_normal_cache; // to restore after discarding changes or undo/redo const ModelObject* m_old_mo = nullptr; - //std::unique_ptr m_clipping_plane; - // This map holds all translated description texts, so they can be easily referenced during layout calculations // etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect. std::map m_desc; @@ -118,11 +97,6 @@ private: bool m_selection_empty = true; EState m_old_state = Off; // to be able to see that the gizmo has just been closed (see on_set_state) - //CommonGizmosData* m_c = nullptr; - - //mutable std::unique_ptr m_object_clipper; - //mutable std::unique_ptr m_supports_clipper; - std::vector get_config_options(const std::vector& keys) const; bool is_mesh_point_clipped(const Vec3d& point) const; bool is_point_in_hole(const Vec3f& pt) const; diff --git a/src/slic3r/GUI/Gizmos/GLGizmos.hpp b/src/slic3r/GUI/Gizmos/GLGizmos.hpp deleted file mode 100644 index 9f97c42b4..000000000 --- a/src/slic3r/GUI/Gizmos/GLGizmos.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef slic3r_GLGizmos_hpp_ -#define slic3r_GLGizmos_hpp_ - -// this describes events being passed from GLCanvas3D to SlaSupport gizmo -namespace Slic3r { -namespace GUI { - -enum class SLAGizmoEventType : unsigned char { - LeftDown = 1, - LeftUp, - RightDown, - Dragging, - Delete, - SelectAll, - ShiftUp, - AltUp, - ApplyChanges, - DiscardChanges, - AutomaticGeneration, - ManualEditing, - MouseWheelUp, - MouseWheelDown, - ResetClippingPlane -}; - -} // namespace GUI -} // namespace Slic3r - -#include "slic3r/GUI/Gizmos/GLGizmoMove.hpp" -#include "slic3r/GUI/Gizmos/GLGizmoScale.hpp" -#include "slic3r/GUI/Gizmos/GLGizmoRotate.hpp" -#include "slic3r/GUI/Gizmos/GLGizmoFlatten.hpp" -#include "slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp" -#include "slic3r/GUI/Gizmos/GLGizmoCut.hpp" -#include "slic3r/GUI/Gizmos/GLGizmoHollow.hpp" - -#endif //slic3r_GLGizmos_hpp_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index 54e561f2f..ba0c310bf 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -17,6 +17,24 @@ class GLCanvas3D; static constexpr float HoleStickOutLength = 1.f; +enum class SLAGizmoEventType : unsigned char { + LeftDown = 1, + LeftUp, + RightDown, + Dragging, + Delete, + SelectAll, + ShiftUp, + AltUp, + ApplyChanges, + DiscardChanges, + AutomaticGeneration, + ManualEditing, + MouseWheelUp, + MouseWheelDown, + ResetClippingPlane +}; + class CommonGizmosDataBase; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 61d0bd5f4..f9d832bb1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -9,10 +9,14 @@ #include "slic3r/GUI/GUI_ObjectManipulation.hpp" #include "slic3r/GUI/PresetBundle.hpp" #include "slic3r/Utils/UndoRedo.hpp" -//#include "libslic3r/SLAPrint.hpp" -//#include "slic3r/GUI/MeshUtils.hpp" -#include "slic3r/GUI/Gizmos/GLGizmos.hpp" -//#include "slic3r/GUI/Camera.hpp" + +#include "slic3r/GUI/Gizmos/GLGizmoMove.hpp" +#include "slic3r/GUI/Gizmos/GLGizmoScale.hpp" +#include "slic3r/GUI/Gizmos/GLGizmoRotate.hpp" +#include "slic3r/GUI/Gizmos/GLGizmoFlatten.hpp" +#include "slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp" +#include "slic3r/GUI/Gizmos/GLGizmoCut.hpp" +#include "slic3r/GUI/Gizmos/GLGizmoHollow.hpp" #include @@ -402,15 +406,6 @@ ClippingPlane GLGizmosManager::get_sla_clipping_plane() const const ClippingPlane& clp = *m_common_gizmos_data->object_clipper()->get_clipping_plane(); return ClippingPlane(-clp.get_normal(), clp.get_data()[3]); } - - - /*if (!m_enabled || (m_current != SlaSupports && m_current != Hollow) || m_gizmos.empty()) - return ClippingPlane::ClipsNothing(); - - if (m_current == SlaSupports) - return dynamic_cast(m_gizmos[SlaSupports].get())->get_sla_clipping_plane(); - else - return dynamic_cast(m_gizmos[Hollow].get())->get_sla_clipping_plane();*/ } bool GLGizmosManager::wants_reslice_supports_on_undo() const @@ -1227,136 +1222,5 @@ bool GLGizmosManager::grabber_contains_mouse() const return (curr != nullptr) ? (curr->get_hover_id() != -1) : false; } - -/* -CommonGizmosData::CommonGizmosData() -{ - m_clipping_plane.reset(new ClippingPlane(Vec3d::Zero(), 0.)); -} - - - -bool CommonGizmosData::update_from_backend(GLCanvas3D& canvas, ModelObject* model_object) -{ - recent_update = false; - bool object_changed = false; - - if (m_model_object != model_object - || (model_object && m_model_object_id != model_object->id())) { - m_model_object = model_object; - m_print_object_idx = -1; - m_mesh_raycaster.reset(); - m_object_clipper.reset(); - m_supports_clipper.reset(); - m_old_mesh = nullptr; - m_mesh = nullptr; - m_backend_mesh_transformed.clear(); - - object_changed = true; - recent_update = true; - } - - if (m_model_object) { - int active_inst = canvas.get_selection().get_instance_idx(); - if (m_active_instance != active_inst) { - m_active_instance = active_inst; - m_active_instance_bb_radius = m_model_object->instance_bounding_box(m_active_instance).radius(); - recent_update = true; - } - } - - - if (! m_model_object || ! canvas.get_selection().is_from_single_instance()) - return false; - - int old_po_idx = m_print_object_idx; - - // First we need a pointer to the respective SLAPrintObject. The index into objects vector is - // cached so we don't have todo it on each render. We only search for the po if needed: - if (m_print_object_idx < 0 || (int)canvas.sla_print()->objects().size() != m_print_objects_count) { - m_print_objects_count = canvas.sla_print()->objects().size(); - m_print_object_idx = -1; - for (const SLAPrintObject* po : canvas.sla_print()->objects()) { - ++m_print_object_idx; - if (po->model_object()->id() == m_model_object->id()) - break; - } - } - - bool mesh_exchanged = false; - m_mesh = nullptr; - // Load either the model_object mesh, or one provided by the backend - // This mesh does not account for the possible Z up SLA offset. - // The backend mesh needs to be transformed and because a pointer to it is - // saved, a copy is stored as a member (FIXME) - if (m_print_object_idx >=0) { - const SLAPrintObject* po = canvas.sla_print()->objects()[m_print_object_idx]; - if (po->is_step_done(slaposDrillHoles)) { - m_backend_mesh_transformed = po->get_mesh_to_print(); - m_backend_mesh_transformed.transform(canvas.sla_print()->sla_trafo(*m_model_object).inverse()); - m_mesh = &m_backend_mesh_transformed; - m_has_drilled_mesh = true; - mesh_exchanged = true; - } - } - - if (! m_mesh) { - m_mesh = &m_model_object->volumes.front()->mesh(); - m_backend_mesh_transformed.clear(); - m_has_drilled_mesh = false; - } - - m_model_object_id = m_model_object->id(); - - if (m_mesh != m_old_mesh) { - // Update clipping plane position. - float new_clp_pos = m_clipping_plane_distance; - if (object_changed) { - new_clp_pos = 0.f; - m_clipping_plane_was_moved = false; - } else { - // After we got a drilled mesh, move the cp to 25%. This only applies when - // the hollowing gizmo is active and hollowing is enabled - if (m_clipping_plane_distance == 0.f && mesh_exchanged && m_has_drilled_mesh) { - const DynamicPrintConfig& cfg = - (m_model_object && m_model_object->config.has("hollowing_enable")) - ? m_model_object->config - : wxGetApp().preset_bundle->sla_prints.get_edited_preset().config; - - if (cfg.has("hollowing_enable") && cfg.opt_bool("hollowing_enable") - && canvas.get_gizmos_manager().get_current_type() == GLGizmosManager::Hollow) { - new_clp_pos = 0.25f; - m_clipping_plane_was_moved = false; // so it uses current camera direction - } - } - } - m_clipping_plane_distance = new_clp_pos; - m_clipping_plane_distance_stash = new_clp_pos; - - m_schedule_aabb_calculation = true; - recent_update = true; - return true; - } - if (! recent_update) - recent_update = m_print_object_idx < 0 && old_po_idx >= 0; - - return recent_update; -} - - -void CommonGizmosData::build_AABB_if_needed() -{ - if (! m_schedule_aabb_calculation) - return; - - wxBusyCursor wait; - m_mesh_raycaster.reset(new MeshRaycaster(*m_mesh)); - m_object_clipper.reset(); - m_supports_clipper.reset(); - m_old_mesh = m_mesh; - m_schedule_aabb_calculation = false; -}*/ - - } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp index 81fd991b7..a31a96a26 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp @@ -3,7 +3,6 @@ #include "slic3r/GUI/GLTexture.hpp" #include "slic3r/GUI/GLToolbar.hpp" -//#include "libslic3r/ObjectID.hpp" #include "slic3r/GUI/Gizmos/GLGizmoBase.hpp" #include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" @@ -20,7 +19,6 @@ namespace GUI { class GLCanvas3D; class ClippingPlane; enum class SLAGizmoEventType : unsigned char; -//class CommonGizmosData; class CommonGizmosDataPool; class Rect @@ -234,63 +232,6 @@ private: -//class MeshRaycaster; -//class MeshClipper; - -// This class is only for sharing SLA related data between SLA gizmos -// and its synchronization with backend data. It should not be misused -// for anything else. -/*class CommonGizmosData { -public: - CommonGizmosData(); - const TriangleMesh* mesh() const { - return (! m_mesh ? nullptr : m_mesh); //(m_cavity_mesh ? m_cavity_mesh.get() : m_mesh)); - } - - bool update_from_backend(GLCanvas3D& canvas, ModelObject* model_object); - bool recent_update = false; - static constexpr float HoleStickOutLength = 1.f; - - ModelObject* m_model_object = nullptr; - const TriangleMesh* m_mesh; - std::unique_ptr m_mesh_raycaster; - std::unique_ptr m_object_clipper; - std::unique_ptr m_supports_clipper; - - //std::unique_ptr m_cavity_mesh; - //std::unique_ptr m_volume_with_cavity; - - int m_active_instance = -1; - float m_active_instance_bb_radius = 0; - ObjectID m_model_object_id = 0; - int m_print_object_idx = -1; - int m_print_objects_count = -1; - int m_old_timestamp = -1; - - float m_clipping_plane_distance = 0.f; - std::unique_ptr m_clipping_plane; - bool m_clipping_plane_was_moved = false; - - void stash_clipping_plane() { - m_clipping_plane_distance_stash = m_clipping_plane_distance; - } - - void unstash_clipping_plane() { - m_clipping_plane_distance = m_clipping_plane_distance_stash; - } - - bool has_drilled_mesh() const { return m_has_drilled_mesh; } - - void build_AABB_if_needed(); - -private: - const TriangleMesh* m_old_mesh; - TriangleMesh m_backend_mesh_transformed; - float m_clipping_plane_distance_stash = 0.f; - bool m_has_drilled_mesh = false; - bool m_schedule_aabb_calculation = false; -}; -*/ } // namespace GUI } // namespace Slic3r From 17811598acda22542cf1fbfd99cd69cf40938654 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 7 Apr 2020 19:44:29 +0200 Subject: [PATCH 23/28] Fixed obvious merge conflicts FDM supports gizmo uses the new common data infrastructure --- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 223 +++++-------------- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp | 27 ++- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 6 +- 3 files changed, 70 insertions(+), 186 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index b578d6bdd..e9c419c61 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -1,12 +1,11 @@ // Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro. #include "GLGizmoFdmSupports.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" -#include "slic3r/GUI/Gizmos/GLGizmos.hpp" +#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" #include #include "slic3r/GUI/GUI_App.hpp" -#include "slic3r/GUI/MeshUtils.hpp" #include "slic3r/GUI/PresetBundle.hpp" #include "slic3r/GUI/Camera.hpp" @@ -55,32 +54,16 @@ bool GLGizmoFdmSupports::on_init() void GLGizmoFdmSupports::set_fdm_support_data(ModelObject* model_object, const Selection& selection) { - if (! model_object || selection.is_empty()) { - m_model_object = nullptr; + const ModelObject* mo = m_c->selection_info() ? m_c->selection_info()->model_object() : nullptr; + if (! mo) return; - } - if (m_model_object != model_object || m_model_object_id != model_object->id()) - m_model_object = model_object; - - m_active_instance = selection.get_instance_idx(); - - if (model_object && selection.is_from_single_instance()) + if (mo && selection.is_from_single_instance() + && (mo != m_old_mo || mo->volumes.size() != m_old_volumes_size)) { - // Cache the bb - it's needed for dealing with the clipping plane quite often - // It could be done inside update_mesh but one has to account for scaling of the instance. - //FIXME calling ModelObject::instance_bounding_box() is expensive! - m_active_instance_bb_radius = m_model_object->instance_bounding_box(m_active_instance).radius(); - - if (is_mesh_update_necessary()) - update_mesh(); - - if (m_state == On) { - m_parent.toggle_model_objects_visibility(false); - m_parent.toggle_model_objects_visibility(true, m_model_object, m_active_instance); - } - else - m_parent.toggle_model_objects_visibility(true, nullptr, -1); + update_mesh(); + m_old_mo = mo; + m_old_volumes_size = mo->volumes.size(); } } @@ -90,23 +73,11 @@ void GLGizmoFdmSupports::on_render() const { const Selection& selection = m_parent.get_selection(); - // If current m_model_object does not match selection, ask GLCanvas3D to turn us off - if (m_state == On - && (m_model_object != selection.get_model()->objects[selection.get_object_idx()] - || m_active_instance != selection.get_instance_idx() - || m_model_object_id != m_model_object->id())) { - m_parent.post_event(SimpleEvent(EVT_GLCANVAS_RESETGIZMOS)); - return; - } - - if (m_meshes.empty()) - const_cast(this)->update_mesh(); - glsafe(::glEnable(GL_BLEND)); glsafe(::glEnable(GL_DEPTH_TEST)); render_triangles(selection); - render_clipping_plane(selection); + m_c->object_clipper()->render_cut(); render_cursor_circle(); glsafe(::glDisable(GL_BLEND)); @@ -114,16 +85,14 @@ void GLGizmoFdmSupports::on_render() const void GLGizmoFdmSupports::render_triangles(const Selection& selection) const { -// if (m_meshes.empty()) -// return; + const ModelObject* mo = m_c->selection_info()->model_object(); - - for (size_t mesh_id=0; mesh_idvolumes.size(); ++mesh_id) { const Transform3d trafo_matrix = - m_model_object->instances[selection.get_instance_idx()]->get_transformation().get_matrix() * - m_model_object->volumes[mesh_id]->get_matrix(); - const TriangleMesh* mesh = m_meshes[mesh_id]; + mo->instances[selection.get_instance_idx()]->get_transformation().get_matrix() * + mo->volumes[mesh_id]->get_matrix(); + const TriangleMesh* mesh = &mo->volumes[mesh_id]->mesh(); @@ -147,39 +116,10 @@ void GLGizmoFdmSupports::render_triangles(const Selection& selection) const } } -void GLGizmoFdmSupports::render_clipping_plane(const Selection& selection) const -{ -// if (m_clipping_plane_distance == 0.f) -// return; - -// // Get transformation of the instance -// const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin()); -// Geometry::Transformation trafo = vol->get_instance_transformation(); - - -// // Now initialize the TMS for the object, perform the cut and save the result. -// if (! m_object_clipper) { -// m_object_clipper.reset(new MeshClipper); -// m_object_clipper->set_mesh(*m_mesh); -// } -// m_object_clipper->set_plane(*m_clipping_plane); -// m_object_clipper->set_transformation(trafo); - -// // At this point we have the triangulated cuts for both the object and supports - let's render. -// if (! m_object_clipper->get_triangles().empty()) { -// ::glPushMatrix(); -// ::glColor3f(1.0f, 0.37f, 0.0f); -// ::glBegin(GL_TRIANGLES); -// for (const Vec3f& point : m_object_clipper->get_triangles()) -// ::glVertex3f(point(0), point(1), point(2)); -// ::glEnd(); -// ::glPopMatrix(); -// } -} void GLGizmoFdmSupports::render_cursor_circle() const { - const Camera& camera = m_parent.get_camera(); + const Camera& camera = wxGetApp().plater()->get_camera(); float zoom = (float)camera.get_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; @@ -228,35 +168,19 @@ void GLGizmoFdmSupports::on_render_for_picking() const } -bool GLGizmoFdmSupports::is_mesh_update_necessary() const -{ - std::vector volumes_ids; - for (const ModelVolume* vol : m_model_object->volumes) - volumes_ids.push_back(vol->id()); - - return ((m_state == On) && (m_model_object != nullptr) && !m_model_object->instances.empty()) - && (m_model_object->id() != m_model_object_id || m_volumes_ids != volumes_ids); -} - - void GLGizmoFdmSupports::update_mesh() { - if (! m_model_object) - return; - wxBusyCursor wait; - size_t num_of_volumes = m_model_object->volumes.size(); - m_meshes.clear(); + const ModelObject* mo = m_c->selection_info()->model_object(); + size_t num_of_volumes = mo->volumes.size(); m_selected_facets.resize(num_of_volumes); m_neighbors.resize(num_of_volumes); - m_meshes_raycaster.clear(); for (size_t volume_id=0; volume_idvolumes[volume_id]->mesh(); - m_meshes.push_back(mesh); + const TriangleMesh* mesh = &mo->volumes[volume_id]->mesh(); m_selected_facets[volume_id].assign(mesh->its.indices.size(), false); m_neighbors[volume_id].resize(3 * mesh->its.indices.size()); @@ -269,12 +193,7 @@ void GLGizmoFdmSupports::update_mesh() m_neighbors[volume_id][3*i+2] = std::make_pair(ind(2), i); } std::sort(m_neighbors[volume_id].begin(), m_neighbors[volume_id].end()); - - // Recalculate raycaster. - m_meshes_raycaster.emplace_back(new MeshRaycaster(*mesh)); } - - m_model_object_id = m_model_object->id(); } @@ -292,34 +211,38 @@ bool operator<(const GLGizmoFdmSupports::NeighborData& a, const GLGizmoFdmSuppor bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down) { if (action == SLAGizmoEventType::MouseWheelUp && control_down) { - m_clipping_plane_distance = std::min(1.f, m_clipping_plane_distance + 0.01f); - update_clipping_plane(true); + double pos = m_c->object_clipper()->get_position(); + pos = std::min(1., pos + 0.01); + m_c->object_clipper()->set_position(pos, true); return true; } if (action == SLAGizmoEventType::MouseWheelDown && control_down) { - m_clipping_plane_distance = std::max(0.f, m_clipping_plane_distance - 0.01f); - update_clipping_plane(true); + double pos = m_c->object_clipper()->get_position(); + pos = std::max(0., pos - 0.01); + m_c->object_clipper()->set_position(pos, true); return true; } if (action == SLAGizmoEventType::ResetClippingPlane) { - update_clipping_plane(); + m_c->object_clipper()->set_position(-1., false); return true; } if (action == SLAGizmoEventType::LeftDown || (action == SLAGizmoEventType::Dragging && m_wait_for_up_event)) { bool select = ! shift_down; - const Camera& camera = m_parent.get_camera(); + const Camera& camera = wxGetApp().plater()->get_camera(); const Selection& selection = m_parent.get_selection(); - const Transform3d& instance_trafo = m_model_object->instances[selection.get_instance_idx()]->get_transformation().get_matrix(); + const ModelInstance* mi = m_c->selection_info()->model_object()->instances[selection.get_instance_idx()]; + const Transform3d& instance_trafo = mi->get_transformation().get_matrix(); // Precalculate transformations of individual meshes std::vector trafo_matrices; - for (const ModelVolume* mv : m_model_object->volumes) + const std::vector& volumes = m_c->selection_info()->model_object()->volumes; + for (const ModelVolume* mv : volumes) trafo_matrices.push_back(instance_trafo * mv->get_matrix()); - std::vector>> hit_positions_and_facet_ids(m_meshes.size()); + std::vector>> hit_positions_and_facet_ids(volumes.size()); bool some_mesh_was_hit = false; // Cast a ray on all meshes, pick the closest hit and save it for the respective mesh @@ -331,9 +254,9 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous size_t closest_facet = 0; size_t closest_hit_mesh_id = size_t(-1); - for (size_t mesh_id=0; mesh_idunproject_on_mesh( + if (m_c->raycaster()->raycasters()[mesh_id]->unproject_on_mesh( mouse_position, trafo_matrices[mesh_id], camera, @@ -358,11 +281,11 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous // Now propagate the hits - for (size_t mesh_id=0; mesh_id& hit_and_facet : hit_positions_and_facet_ids[mesh_id]) { some_mesh_was_hit = true; - const TriangleMesh* mesh = m_meshes[mesh_id]; + const TriangleMesh* mesh = &volumes[mesh_id]->mesh(); std::vector& neighbors = m_neighbors[mesh_id]; // Calculate direction from camera to the hit (in mesh coords): @@ -381,8 +304,8 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous }; // A lambda to determine whether this facet is potentionally visible (still can be obscured) - auto faces_camera = [&dir, this](const size_t& mesh_id, const size_t& facet) -> bool { - return (m_meshes[mesh_id]->stl.facet_start[facet].normal.dot(dir) > 0.); + auto faces_camera = [&dir, &volumes](const size_t& mesh_id, const size_t& facet) -> bool { + return (volumes[mesh_id]->mesh().stl.facet_start[facet].normal.dot(dir) > 0.); }; // Now start with the facet the pointer points to and check all adjacent facets. neighbors vector stores // pairs of vertex_idx - facet_idx and is sorted with respect to the former. Neighboring facet index can be @@ -439,18 +362,9 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous - -ClippingPlane GLGizmoFdmSupports::get_fdm_clipping_plane() const -{ - if (!m_model_object || m_state == Off || m_clipping_plane_distance == 0.f) - return ClippingPlane::ClipsNothing(); - else - return ClippingPlane(-m_clipping_plane->get_normal(), m_clipping_plane->get_data()[3]); -} - void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_limit) { - if (!m_model_object) + if (! m_c->selection_info()->model_object()) return; const float approx_height = m_imgui->scaled(18.0f); @@ -474,20 +388,21 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l // Following is rendered in both editing and non-editing mode: m_imgui->text(""); - if (m_clipping_plane_distance == 0.f) + if (m_c->object_clipper()->get_position() == 0.f) m_imgui->text(m_desc.at("clipping_of_view")); else { if (m_imgui->button(m_desc.at("reset_direction"))) { wxGetApp().CallAfter([this](){ - update_clipping_plane(); + m_c->object_clipper()->set_position(-1., false); }); } } ImGui::SameLine(clipping_slider_left); ImGui::PushItemWidth(window_width - clipping_slider_left); - if (ImGui::SliderFloat(" ", &m_clipping_plane_distance, 0.f, 1.f, "%.2f")) - update_clipping_plane(true); + float clp_dist = m_c->object_clipper()->get_position(); + if (ImGui::SliderFloat(" ", &clp_dist, 0.f, 1.f, "%.2f")) + m_c->object_clipper()->set_position(clp_dist, true); ImGui::SliderFloat(" ", &m_cursor_radius, 0.f, 8.f, "%.2f"); @@ -522,46 +437,29 @@ std::string GLGizmoFdmSupports::on_get_name() const } +CommonGizmosDataID GLGizmoFdmSupports::on_get_requirements() const +{ + return CommonGizmosDataID( + int(CommonGizmosDataID::SelectionInfo) + | int(CommonGizmosDataID::InstancesHider) + | int(CommonGizmosDataID::Raycaster) + | int(CommonGizmosDataID::HollowedMesh) + | int(CommonGizmosDataID::ObjectClipper) + | int(CommonGizmosDataID::SupportsClipper)); +} + void GLGizmoFdmSupports::on_set_state() { - // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - return; - - // m_model_object pointer can be invalid (for instance because of undo/redo action), - // we should recover it from the object id - m_model_object = nullptr; - for (const auto mo : wxGetApp().model().objects) { - if (mo->id() == m_model_object_id) { - m_model_object = mo; - break; - } - } - if (m_state == m_old_state) return; if (m_state == On && m_old_state != On) { // the gizmo was just turned on Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("FDM gizmo turned on"))); - if (is_mesh_update_necessary()) - update_mesh(); - - // we'll now reload support points: - if (m_model_object) - ;// !!!! reload_cache(); - - m_parent.toggle_model_objects_visibility(false); - if (m_model_object) - m_parent.toggle_model_objects_visibility(true, m_model_object, m_active_instance); } if (m_state == Off && m_old_state != Off) { // the gizmo was just turned Off // we are actually shutting down Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("FDM gizmo turned off"))); - m_parent.toggle_model_objects_visibility(true); - m_clipping_plane_distance = 0.f; - // Release clippers and the AABB raycaster. - m_meshes_clipper.clear(); - m_meshes_raycaster.clear(); } m_old_state = m_state; } @@ -594,19 +492,6 @@ void GLGizmoFdmSupports::on_save(cereal::BinaryOutputArchive& ar) const } -void GLGizmoFdmSupports::update_clipping_plane(bool keep_normal) const -{ - Vec3d normal = (keep_normal && m_clipping_plane->get_normal() != Vec3d::Zero() ? - m_clipping_plane->get_normal() : -m_parent.get_camera().get_dir_forward()); - - const Vec3d& center = m_model_object->instances[m_active_instance]->get_offset(); - float dist = normal.dot(center); - *m_clipping_plane = ClippingPlane(normal, (dist - (-m_active_instance_bb_radius) - m_clipping_plane_distance * 2*m_active_instance_bb_radius)); - m_parent.set_as_dirty(); -} - - - } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp index 2823299c5..50f4257da 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp @@ -9,25 +9,28 @@ namespace Slic3r { namespace GUI { -class ClippingPlane; +/*class ClippingPlane; class MeshClipper; -class MeshRaycaster; +class MeshRaycaster;*/ enum class SLAGizmoEventType : unsigned char; class GLGizmoFdmSupports : public GLGizmoBase { private: - ModelObject* m_model_object = nullptr; + /*ModelObject* m_model_object = nullptr; ObjectID m_model_object_id = 0; std::vector m_volumes_ids; int m_active_instance = -1; - float m_active_instance_bb_radius; // to cache the bb + float m_active_instance_bb_radius; // to cache the bb*/ + const ModelObject* m_old_mo = nullptr; + int m_old_volumes_size = 0; + GLUquadricObj* m_quadric; - std::vector> m_meshes_raycaster; - std::vector m_meshes; - mutable std::vector m_triangles; + //std::vector> m_meshes_raycaster; + //std::vector m_meshes; + //mutable std::vector m_triangles; float m_cursor_radius = 2.f; std::vector> m_selected_facets; @@ -37,7 +40,6 @@ public: ~GLGizmoFdmSupports() override; void set_fdm_support_data(ModelObject* model_object, const Selection& selection); bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down); - ClippingPlane get_fdm_clipping_plane() const; using NeighborData = std::pair; @@ -47,9 +49,9 @@ private: void on_render_for_picking() const override; void render_triangles(const Selection& selection) const; - void render_clipping_plane(const Selection& selection) const; + //void render_clipping_plane(const Selection& selection) const; void render_cursor_circle() const; - bool is_mesh_update_necessary() const; + //bool is_mesh_update_necessary() const; void update_mesh(); float m_clipping_plane_distance = 0.f; @@ -62,11 +64,11 @@ private: bool m_wait_for_up_event = false; EState m_old_state = Off; // to be able to see that the gizmo has just been closed (see on_set_state) - mutable std::vector> m_meshes_clipper; + //mutable std::vector> m_meshes_clipper; std::vector> m_neighbors; // pairs of vertex_index - facet_index for each mesh - void update_clipping_plane(bool keep_normal = false) const; + //void update_clipping_plane(bool keep_normal = false) const; protected: void on_set_state() override; @@ -78,6 +80,7 @@ protected: bool on_is_selectable() const override; void on_load(cereal::BinaryInputArchive& ar) override; void on_save(cereal::BinaryOutputArchive& ar) const override; + CommonGizmosDataID on_get_requirements() const override; }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 6f08f8eca..e71f617e4 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -15,6 +15,7 @@ #include "slic3r/GUI/Gizmos/GLGizmoRotate.hpp" #include "slic3r/GUI/Gizmos/GLGizmoFlatten.hpp" #include "slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp" +#include "slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp" #include "slic3r/GUI/Gizmos/GLGizmoCut.hpp" #include "slic3r/GUI/Gizmos/GLGizmoHollow.hpp" @@ -103,13 +104,8 @@ bool GLGizmosManager::init() m_gizmos.emplace_back(new GLGizmoSlaSupports(m_parent, "sla_supports.svg", 6)); m_gizmos.emplace_back(new GLGizmoFdmSupports(m_parent, "sla_supports.svg", 7)); - //m_common_gizmos_data.reset(new CommonGizmosData()); - //dynamic_cast(m_gizmos[Hollow].get())->set_common_data_ptr(m_common_gizmos_data.get()); - //dynamic_cast(m_gizmos[SlaSupports].get())->set_common_data_ptr(m_common_gizmos_data.get()); - m_common_gizmos_data.reset(new CommonGizmosDataPool(&m_parent)); - for (auto& gizmo : m_gizmos) { if (! gizmo->init()) { m_gizmos.clear(); From fe578266952a562053b1395e3790147c0d6c24cb Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 8 Apr 2020 00:34:05 +0200 Subject: [PATCH 24/28] Improved the FDM supports gizmo dialog Removed unused code Fixed a clipping-plane related crash Fixed a crash in hollowing gizmo when no hollowed mesh was provided Forbid opening the gizmo when a part of an object is selected --- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 79 ++++++++++++-------- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp | 22 +----- src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 1 + src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 2 +- 5 files changed, 53 insertions(+), 53 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index e9c419c61..fd4823cbc 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -36,18 +36,15 @@ bool GLGizmoFdmSupports::on_init() { m_shortcut_key = WXK_CONTROL_L; - m_desc["head_diameter"] = _(L("Head diameter")) + ": "; - m_desc["lock_supports"] = _(L("Lock supports under new islands")); - m_desc["remove_selected"] = _(L("Remove selected points")); - m_desc["remove_all"] = _(L("Remove all points")); - m_desc["apply_changes"] = _(L("Apply changes")); - m_desc["discard_changes"] = _(L("Discard changes")); - m_desc["minimal_distance"] = _(L("Minimal points distance")) + ": "; - m_desc["points_density"] = _(L("Support points density")) + ": "; - m_desc["auto_generate"] = _(L("Auto-generate points")); - m_desc["manual_editing"] = _(L("Manual editing")); - m_desc["clipping_of_view"] = _(L("Clipping of view"))+ ": "; - m_desc["reset_direction"] = _(L("Reset direction")); + m_desc["clipping_of_view"] = _L("Clipping of view") + ": "; + m_desc["reset_direction"] = _L("Reset direction"); + m_desc["cursor_size"] = _L("Cursor size") + ": "; + m_desc["enforce_caption"] = _L("Left mouse button") + ": "; + m_desc["enforce"] = _L("Enforce supports"); + m_desc["block_caption"] = _L("Alt + Left mouse button") + " "; + m_desc["block"] = _L("Block supports"); + m_desc["remove_caption"] = _L("Shift + Left mouse button") + ": "; + m_desc["remove"] = _L("Remove selection"); return true; } @@ -94,13 +91,12 @@ void GLGizmoFdmSupports::render_triangles(const Selection& selection) const mo->volumes[mesh_id]->get_matrix(); const TriangleMesh* mesh = &mo->volumes[mesh_id]->mesh(); - - - ::glColor3f(0.0f, 0.37f, 1.0f); - for (size_t facet_idx=0; facet_idxits, facet_idx); ::glPushMatrix(); ::glTranslatef(normal(0), normal(1), normal(2)); @@ -182,7 +178,7 @@ void GLGizmoFdmSupports::update_mesh() // This mesh does not account for the possible Z up SLA offset. const TriangleMesh* mesh = &mo->volumes[volume_id]->mesh(); - m_selected_facets[volume_id].assign(mesh->its.indices.size(), false); + m_selected_facets[volume_id].assign(mesh->its.indices.size(), 0); m_neighbors[volume_id].resize(3 * mesh->its.indices.size()); // Prepare vector of vertex_index - facet_index pairs to quickly find adjacent facets @@ -230,7 +226,7 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous } if (action == SLAGizmoEventType::LeftDown || (action == SLAGizmoEventType::Dragging && m_wait_for_up_event)) { - bool select = ! shift_down; + int8_t new_state = shift_down ? 0 : (alt_down ? -1 : 1); const Camera& camera = wxGetApp().plater()->get_camera(); const Selection& selection = m_parent.get_selection(); const ModelInstance* mi = m_c->selection_info()->model_object()->instances[selection.get_instance_idx()]; @@ -338,7 +334,7 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous } // Now just select all facets that passed for (size_t next_facet : facets_to_select) - m_selected_facets[mesh_id][next_facet] = select; + m_selected_facets[mesh_id][next_facet] = new_state; } } @@ -370,24 +366,45 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l const float approx_height = m_imgui->scaled(18.0f); y = std::min(y, bottom_limit - approx_height); m_imgui->set_next_window_pos(x, y, ImGuiCond_Always); - m_imgui->set_next_window_bg_alpha(0.5f); m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse); // First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that: - - const float settings_sliders_left = std::max(m_imgui->calc_text_size(m_desc.at("minimal_distance")).x, m_imgui->calc_text_size(m_desc.at("points_density")).x) + m_imgui->scaled(1.f); const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x, m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + m_imgui->scaled(1.5f); - const float diameter_slider_left = m_imgui->calc_text_size(m_desc.at("head_diameter")).x + m_imgui->scaled(1.f); + const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.f); const float minimal_slider_width = m_imgui->scaled(4.f); - const float buttons_width_approx = m_imgui->calc_text_size(m_desc.at("apply_changes")).x + m_imgui->calc_text_size(m_desc.at("discard_changes")).x + m_imgui->scaled(1.5f); - const float lock_supports_width_approx = m_imgui->calc_text_size(m_desc.at("lock_supports")).x + m_imgui->scaled(2.f); - float window_width = minimal_slider_width + std::max(std::max(settings_sliders_left, clipping_slider_left), diameter_slider_left); - window_width = std::max(std::max(window_width, buttons_width_approx), lock_supports_width_approx); + float caption_max = 0.f; + float total_text_max = 0.; + for (const std::string& t : {"enforce", "block", "remove"}) { + caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc.at(t+"_caption")).x); + total_text_max = std::max(total_text_max, caption_max + m_imgui->calc_text_size(m_desc.at(t)).x); + } + caption_max += m_imgui->scaled(1.f); + total_text_max += m_imgui->scaled(1.f); + float window_width = minimal_slider_width + std::max(cursor_slider_left, clipping_slider_left); + window_width = std::max(window_width, total_text_max); + + auto draw_text_with_caption = [this, &caption_max](const wxString& caption, const wxString& text) { + static const ImVec4 ORANGE(1.0f, 0.49f, 0.22f, 1.0f); + ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); + m_imgui->text(caption); + ImGui::PopStyleColor(); + ImGui::SameLine(caption_max); + m_imgui->text(text); + }; + + for (const std::string& t : {"enforce", "block", "remove"}) + draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t)); - // Following is rendered in both editing and non-editing mode: m_imgui->text(""); + + m_imgui->text(m_desc.at("cursor_size")); + ImGui::SameLine(clipping_slider_left); + ImGui::PushItemWidth(window_width - clipping_slider_left); + ImGui::SliderFloat(" ", &m_cursor_radius, 0.f, 8.f, "%.2f"); + + ImGui::Separator(); if (m_c->object_clipper()->get_position() == 0.f) m_imgui->text(m_desc.at("clipping_of_view")); else { @@ -404,7 +421,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l if (ImGui::SliderFloat(" ", &clp_dist, 0.f, 1.f, "%.2f")) m_c->object_clipper()->set_position(clp_dist, true); - ImGui::SliderFloat(" ", &m_cursor_radius, 0.f, 8.f, "%.2f"); + m_imgui->end(); } @@ -414,7 +431,7 @@ bool GLGizmoFdmSupports::on_is_activable() const const Selection& selection = m_parent.get_selection(); if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptFFF - || !selection.is_from_single_instance()) + || !selection.is_single_full_instance()) return false; // Check that none of the selected volumes is outside. Only SLA auxiliaries (supports) are allowed outside. diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp index 50f4257da..890e0bb2e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp @@ -9,31 +9,19 @@ namespace Slic3r { namespace GUI { -/*class ClippingPlane; -class MeshClipper; -class MeshRaycaster;*/ enum class SLAGizmoEventType : unsigned char; class GLGizmoFdmSupports : public GLGizmoBase { private: - /*ModelObject* m_model_object = nullptr; - ObjectID m_model_object_id = 0; - std::vector m_volumes_ids; - int m_active_instance = -1; - float m_active_instance_bb_radius; // to cache the bb*/ const ModelObject* m_old_mo = nullptr; - int m_old_volumes_size = 0; - + size_t m_old_volumes_size = 0; GLUquadricObj* m_quadric; - //std::vector> m_meshes_raycaster; - //std::vector m_meshes; - //mutable std::vector m_triangles; float m_cursor_radius = 2.f; - std::vector> m_selected_facets; + std::vector> m_selected_facets; public: GLGizmoFdmSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); @@ -49,9 +37,7 @@ private: void on_render_for_picking() const override; void render_triangles(const Selection& selection) const; - //void render_clipping_plane(const Selection& selection) const; void render_cursor_circle() const; - //bool is_mesh_update_necessary() const; void update_mesh(); float m_clipping_plane_distance = 0.f; @@ -64,12 +50,8 @@ private: bool m_wait_for_up_event = false; EState m_old_state = Off; // to be able to see that the gizmo has just been closed (see on_set_state) - //mutable std::vector> m_meshes_clipper; - std::vector> m_neighbors; // pairs of vertex_index - facet_index for each mesh - //void update_clipping_plane(bool keep_normal = false) const; - protected: void on_set_state() override; void on_start_dragging() override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index 3c7e7a236..d2f668dab 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -59,7 +59,7 @@ void GLGizmoHollow::set_sla_support_data(ModelObject*, const Selection&) const ModelObject* mo = m_c->selection_info()->model_object(); if (mo) { reload_cache(); - if (m_c->hollowed_mesh()->get_hollowed_mesh()) + if (m_c->hollowed_mesh() && m_c->hollowed_mesh()->get_hollowed_mesh()) m_holes_in_drilled_mesh = mo->sla_drain_holes; } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index a8e1801d7..822a602bd 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -306,6 +306,7 @@ void ObjectClipper::on_release() m_clipper.reset(); m_old_mesh = nullptr; m_clp.reset(); + m_clp_ratio = 0.; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index e71f617e4..d49537960 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -413,7 +413,7 @@ bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_p ClippingPlane GLGizmosManager::get_clipping_plane() const { if (! m_common_gizmos_data->object_clipper() - || m_common_gizmos_data->object_clipper()->get_position() == 0.) + || m_common_gizmos_data->object_clipper()->get_position() == 0.) return ClippingPlane::ClipsNothing(); else { const ClippingPlane& clp = *m_common_gizmos_data->object_clipper()->get_clipping_plane(); From c32fa67523848300d668295c93fdcf4d8508b762 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 8 Apr 2020 11:52:22 +0200 Subject: [PATCH 25/28] Clipping plane can now handle multiple-part objects --- src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 60 +++++++++++++++--------- src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 4 +- 2 files changed, 41 insertions(+), 23 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index 822a602bd..3ac1c3937 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -284,15 +284,24 @@ void ObjectClipper::on_update() return; // which mesh should be cut? - const TriangleMesh* mesh = &mo->volumes.front()->mesh(); + std::vector meshes; bool has_hollowed = get_pool()->hollowed_mesh() && get_pool()->hollowed_mesh()->get_hollowed_mesh(); if (has_hollowed) - mesh = get_pool()->hollowed_mesh()->get_hollowed_mesh(); + meshes.push_back(get_pool()->hollowed_mesh()->get_hollowed_mesh()); - if (mesh != m_old_mesh) { - m_clipper.reset(new MeshClipper); - m_clipper->set_mesh(*mesh); - m_old_mesh = mesh; + if (meshes.empty()) { + for (const ModelVolume* mv : mo->volumes) + if (mv->is_model_part()) + meshes.push_back(&mv->mesh()); + } + + if (meshes != m_old_meshes) { + m_clippers.clear(); + for (const TriangleMesh* mesh : meshes) { + m_clippers.emplace_back(new MeshClipper); + m_clippers.back()->set_mesh(*mesh); + } + m_old_meshes = meshes; m_active_inst_bb_radius = mo->instance_bounding_box(get_pool()->selection_info()->get_active_instance()).radius(); //if (has_hollowed && m_clp_ratio != 0.) @@ -303,8 +312,8 @@ void ObjectClipper::on_update() void ObjectClipper::on_release() { - m_clipper.reset(); - m_old_mesh = nullptr; + m_clippers.clear(); + m_old_meshes.clear(); m_clp.reset(); m_clp_ratio = 0.; @@ -317,21 +326,30 @@ void ObjectClipper::render_cut() const const SelectionInfo* sel_info = get_pool()->selection_info(); const ModelObject* mo = sel_info->model_object(); Geometry::Transformation inst_trafo = mo->instances[sel_info->get_active_instance()]->get_transformation(); - Geometry::Transformation vol_trafo = mo->volumes.front()->get_transformation(); - Geometry::Transformation trafo = inst_trafo * vol_trafo; - trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., sel_info->get_sla_shift())); - m_clipper->set_plane(*m_clp); - m_clipper->set_transformation(trafo); + size_t clipper_id = 0; + for (const ModelVolume* mv : mo->volumes) { + if (! mv->is_model_part()) + continue; - if (! m_clipper->get_triangles().empty()) { - ::glPushMatrix(); - ::glColor3f(1.0f, 0.37f, 0.0f); - ::glBegin(GL_TRIANGLES); - for (const Vec3f& point : m_clipper->get_triangles()) - ::glVertex3f(point(0), point(1), point(2)); - ::glEnd(); - ::glPopMatrix(); + Geometry::Transformation vol_trafo = mv->get_transformation(); + Geometry::Transformation trafo = inst_trafo * vol_trafo; + trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., sel_info->get_sla_shift())); + + auto& clipper = m_clippers[clipper_id]; + clipper->set_plane(*m_clp); + clipper->set_transformation(trafo); + + if (! clipper->get_triangles().empty()) { + ::glPushMatrix(); + ::glColor3f(1.0f, 0.37f, 0.0f); + ::glBegin(GL_TRIANGLES); + for (const Vec3f& point : clipper->get_triangles()) + ::glVertex3f(point(0), point(1), point(2)); + ::glEnd(); + ::glPopMatrix(); + } + ++clipper_id; } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index ba0c310bf..f2d35bc4e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -257,8 +257,8 @@ protected: void on_release() override; private: - const TriangleMesh* m_old_mesh = nullptr; - std::unique_ptr m_clipper; + std::vector m_old_meshes; + std::vector> m_clippers; std::unique_ptr m_clp; double m_clp_ratio = 0.; double m_active_inst_bb_radius = 0.; From 55c87886fa53c610f0cd04a54c4210de6df376af Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 8 Apr 2020 12:58:48 +0200 Subject: [PATCH 26/28] FDM supports gizmo now ignored modifiers and support enforcer/blockers --- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 70 ++++++++++++++------ 1 file changed, 49 insertions(+), 21 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index fd4823cbc..3db236a8e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -84,12 +84,17 @@ void GLGizmoFdmSupports::render_triangles(const Selection& selection) const { const ModelObject* mo = m_c->selection_info()->model_object(); - for (size_t mesh_id=0; mesh_idvolumes.size(); ++mesh_id) { + int mesh_id = -1; + for (const ModelVolume* mv : mo->volumes) { + if (! mv->is_model_part()) + continue; + + ++mesh_id; const Transform3d trafo_matrix = mo->instances[selection.get_instance_idx()]->get_transformation().get_matrix() * - mo->volumes[mesh_id]->get_matrix(); - const TriangleMesh* mesh = &mo->volumes[mesh_id]->mesh(); + mv->get_matrix(); + const TriangleMesh* mesh = &mv->mesh(); for (size_t facet_idx=0; facet_idxselection_info()->model_object(); - size_t num_of_volumes = mo->volumes.size(); + size_t num_of_volumes = 0; + for (const ModelVolume* mv : mo->volumes) + if (mv->is_model_part()) + ++num_of_volumes; + m_selected_facets.resize(num_of_volumes); m_neighbors.resize(num_of_volumes); - for (size_t volume_id=0; volume_idvolumes) { + if (! mv->is_model_part()) + continue; + + ++volume_id; + // This mesh does not account for the possible Z up SLA offset. - const TriangleMesh* mesh = &mo->volumes[volume_id]->mesh(); + const TriangleMesh* mesh = &mv->mesh(); m_selected_facets[volume_id].assign(mesh->its.indices.size(), 0); m_neighbors[volume_id].resize(3 * mesh->its.indices.size()); @@ -229,19 +244,13 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous int8_t new_state = shift_down ? 0 : (alt_down ? -1 : 1); const Camera& camera = wxGetApp().plater()->get_camera(); const Selection& selection = m_parent.get_selection(); - const ModelInstance* mi = m_c->selection_info()->model_object()->instances[selection.get_instance_idx()]; + const ModelObject* mo = m_c->selection_info()->model_object(); + const ModelInstance* mi = mo->instances[selection.get_instance_idx()]; const Transform3d& instance_trafo = mi->get_transformation().get_matrix(); - // Precalculate transformations of individual meshes - std::vector trafo_matrices; - const std::vector& volumes = m_c->selection_info()->model_object()->volumes; - for (const ModelVolume* mv : volumes) - trafo_matrices.push_back(instance_trafo * mv->get_matrix()); - - std::vector>> hit_positions_and_facet_ids(volumes.size()); + std::vector>> hit_positions_and_facet_ids; bool some_mesh_was_hit = false; - // Cast a ray on all meshes, pick the closest hit and save it for the respective mesh Vec3f normal = Vec3f::Zero(); Vec3f hit = Vec3f::Zero(); size_t facet = 0; @@ -250,7 +259,19 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous size_t closest_facet = 0; size_t closest_hit_mesh_id = size_t(-1); - for (size_t mesh_id=0; mesh_id trafo_matrices; + + int mesh_id = -1; + // Cast a ray on all meshes, pick the closest hit and save it for the respective mesh + for (const ModelVolume* mv : mo->volumes) { + if (! mv->is_model_part()) + continue; + + ++mesh_id; + + trafo_matrices.push_back(instance_trafo * mv->get_matrix()); + hit_positions_and_facet_ids.push_back(std::vector>()); if (m_c->raycaster()->raycasters()[mesh_id]->unproject_on_mesh( mouse_position, @@ -277,11 +298,18 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous // Now propagate the hits - for (size_t mesh_id=0; mesh_idvolumes) { + + if (! mv->is_model_part()) + continue; + + ++mesh_id; + // For all hits on this mesh... for (const std::pair& hit_and_facet : hit_positions_and_facet_ids[mesh_id]) { some_mesh_was_hit = true; - const TriangleMesh* mesh = &volumes[mesh_id]->mesh(); + const TriangleMesh* mesh = &mv->mesh(); std::vector& neighbors = m_neighbors[mesh_id]; // Calculate direction from camera to the hit (in mesh coords): @@ -300,8 +328,8 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous }; // A lambda to determine whether this facet is potentionally visible (still can be obscured) - auto faces_camera = [&dir, &volumes](const size_t& mesh_id, const size_t& facet) -> bool { - return (volumes[mesh_id]->mesh().stl.facet_start[facet].normal.dot(dir) > 0.); + auto faces_camera = [&dir](const ModelVolume* mv, const size_t& facet) -> bool { + return (mv->mesh().stl.facet_start[facet].normal.dot(dir) > 0.); }; // Now start with the facet the pointer points to and check all adjacent facets. neighbors vector stores // pairs of vertex_idx - facet_idx and is sorted with respect to the former. Neighboring facet index can be @@ -322,7 +350,7 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous if (dist < limit) { it = std::lower_bound(neighbors.begin(), neighbors.end(), vertex); while (it != neighbors.end() && it->first == vertex.first) { - if (it->second != facet && faces_camera(mesh_id, it->second)) + if (it->second != facet && faces_camera(mv, it->second)) facets_to_select.push_back(it->second); ++it; } From 4d8e6538e8b9fe8ac91a705456ebe7696a1c43f3 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 8 Apr 2020 14:59:53 +0200 Subject: [PATCH 27/28] FDM supports gizmo - use right mouse to place support blockers --- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 26 ++++++++++++++------ src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp | 8 +++++- src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 1 + src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 18 +++++++++++--- 4 files changed, 42 insertions(+), 11 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 3db236a8e..f423c0934 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -41,7 +41,7 @@ bool GLGizmoFdmSupports::on_init() m_desc["cursor_size"] = _L("Cursor size") + ": "; m_desc["enforce_caption"] = _L("Left mouse button") + ": "; m_desc["enforce"] = _L("Enforce supports"); - m_desc["block_caption"] = _L("Alt + Left mouse button") + " "; + m_desc["block_caption"] = _L("Right mouse button") + " "; m_desc["block"] = _L("Block supports"); m_desc["remove_caption"] = _L("Shift + Left mouse button") + ": "; m_desc["remove"] = _L("Remove selection"); @@ -240,8 +240,18 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous return true; } - if (action == SLAGizmoEventType::LeftDown || (action == SLAGizmoEventType::Dragging && m_wait_for_up_event)) { - int8_t new_state = shift_down ? 0 : (alt_down ? -1 : 1); + if (action == SLAGizmoEventType::LeftDown + || action == SLAGizmoEventType::RightDown + || (action == SLAGizmoEventType::Dragging && m_button_down != Button::None)) { + + int8_t new_state = 0; + if (! shift_down) { + if (action == SLAGizmoEventType::Dragging) + new_state = m_button_down == Button::Left ? 1 : -1; + else + new_state = action == SLAGizmoEventType::LeftDown ? 1 : -1; + } + const Camera& camera = wxGetApp().plater()->get_camera(); const Selection& selection = m_parent.get_selection(); const ModelObject* mo = m_c->selection_info()->model_object(); @@ -368,16 +378,18 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous if (some_mesh_was_hit) { - m_wait_for_up_event = true; + if (m_button_down == Button::None) + m_button_down = ((action == SLAGizmoEventType::LeftDown) ? Button::Left : Button::Right); m_parent.set_as_dirty(); return true; } - if (action == SLAGizmoEventType::Dragging && m_wait_for_up_event) + if (action == SLAGizmoEventType::Dragging && m_button_down != Button::None) return true; } - if (action == SLAGizmoEventType::LeftUp && m_wait_for_up_event) { - m_wait_for_up_event = false; + if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::RightUp) + && m_button_down != Button::None) { + m_button_down = Button::None; return true; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp index 890e0bb2e..e9e181c2c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp @@ -47,7 +47,13 @@ private: // etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect. std::map m_desc; - bool m_wait_for_up_event = false; + enum class Button { + None, + Left, + Right + }; + + Button m_button_down = Button::None; EState m_old_state = Off; // to be able to see that the gizmo has just been closed (see on_set_state) std::vector> m_neighbors; // pairs of vertex_index - facet_index for each mesh diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index f2d35bc4e..31c473bac 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -21,6 +21,7 @@ enum class SLAGizmoEventType : unsigned char { LeftDown = 1, LeftUp, RightDown, + RightUp, Dragging, Delete, SelectAll, diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index d49537960..ac7fe72e5 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -558,8 +558,8 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt) processed = true; m_mouse_capture.right = false; } - else - return false; +// else +// return false; } #if ENABLE_GIZMO_TOOLBAR_DRAGGING_FIX else if (evt.Dragging() && !is_dragging()) @@ -666,13 +666,20 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt) processed = true; } } - else if (evt.RightDown() && (selected_object_idx != -1) && (m_current == SlaSupports || m_current == Hollow) && gizmo_event(SLAGizmoEventType::RightDown)) + else if (evt.RightDown() && (selected_object_idx != -1) && (m_current == SlaSupports || m_current == Hollow) + && gizmo_event(SLAGizmoEventType::RightDown, mouse_pos)) { // we need to set the following right up as processed to avoid showing the context menu if the user release the mouse over the object pending_right_up = true; // event was taken care of by the SlaSupports gizmo processed = true; } + else if (evt.RightDown() && (selected_object_idx != -1) && m_current == FdmSupports + && gizmo_event(SLAGizmoEventType::RightDown, mouse_pos)) + { + // event was taken care of by the FdmSupports gizmo + processed = true; + } else if (evt.Dragging() && (m_parent.get_move_volume_id() != -1) && (m_current == SlaSupports || m_current == Hollow)) // don't allow dragging objects with the Sla gizmo on processed = true; @@ -766,6 +773,11 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt) // to avoid to loose the selection when user clicks an the white faces of a different object while the Flatten gizmo is active processed = true; } + else if (evt.RightUp() && m_current == FdmSupports && !m_parent.is_mouse_dragging()) + { + gizmo_event(SLAGizmoEventType::RightUp, mouse_pos, evt.ShiftDown(), evt.AltDown(), evt.ControlDown()); + processed = true; + } } else { From 23fbc2ff1a00afb7ecede7eefbdcccfccf455cbe Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 8 Apr 2020 15:21:41 +0200 Subject: [PATCH 28/28] Alt+mouse wheel adjusts cursor size in FDM supports gizmo --- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 24 +++++++++++++++----- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp | 3 +++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index f423c0934..668ab07df 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -221,11 +221,23 @@ bool operator<(const GLGizmoFdmSupports::NeighborData& a, const GLGizmoFdmSuppor // concludes that the event was not intended for it, it should return false. bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down) { - if (action == SLAGizmoEventType::MouseWheelUp && control_down) { - double pos = m_c->object_clipper()->get_position(); - pos = std::min(1., pos + 0.01); - m_c->object_clipper()->set_position(pos, true); - return true; + if (action == SLAGizmoEventType::MouseWheelUp + || action == SLAGizmoEventType::MouseWheelDown) { + if (control_down) { + double pos = m_c->object_clipper()->get_position(); + pos = action == SLAGizmoEventType::MouseWheelDown + ? std::max(0., pos - 0.01) + : std::min(1., pos + 0.01); + m_c->object_clipper()->set_position(pos, true); + return true; + } + else if (alt_down) { + m_cursor_radius = action == SLAGizmoEventType::MouseWheelDown + ? std::max(m_cursor_radius - CursorRadiusStep, CursorRadiusMin) + : std::min(m_cursor_radius + CursorRadiusStep, CursorRadiusMax); + m_parent.set_as_dirty(); + return true; + } } if (action == SLAGizmoEventType::MouseWheelDown && control_down) { @@ -442,7 +454,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l m_imgui->text(m_desc.at("cursor_size")); ImGui::SameLine(clipping_slider_left); ImGui::PushItemWidth(window_width - clipping_slider_left); - ImGui::SliderFloat(" ", &m_cursor_radius, 0.f, 8.f, "%.2f"); + ImGui::SliderFloat(" ", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f"); ImGui::Separator(); if (m_c->object_clipper()->get_position() == 0.f) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp index e9e181c2c..6c767db11 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp @@ -20,6 +20,9 @@ private: GLUquadricObj* m_quadric; float m_cursor_radius = 2.f; + static constexpr float CursorRadiusMin = 0.f; + static constexpr float CursorRadiusMax = 8.f; + static constexpr float CursorRadiusStep = 0.2f; std::vector> m_selected_facets;