mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	WIP: First working implementation of the triangle selector for the FDM support gizmo
This commit is contained in:
		
							parent
							
								
									7afe7326b6
								
							
						
					
					
						commit
						08daddb5de
					
				
					 7 changed files with 108 additions and 28 deletions
				
			
		|  | @ -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<Vec3f, Vec3f>& 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::pair<Vec | |||
|     // 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); | ||||
|     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(); | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,9 +3,6 @@ | |||
| 
 | ||||
| #include "GLGizmoBase.hpp" | ||||
| 
 | ||||
| //#include "libslic3r/SLA/SLACommon.hpp"
 | ||||
| //#include <wx/dialog.h>
 | ||||
| 
 | ||||
| #include <cereal/types/vector.hpp> | ||||
| 
 | ||||
| 
 | ||||
|  | @ -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<Vec3f, Vec3f>& 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<Vec2f> m_triangles; | ||||
| 
 | ||||
|     std::vector<size_t> 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(); | ||||
|  |  | |||
|  | @ -388,9 +388,12 @@ bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_p | |||
| 
 | ||||
|     if (m_current == SlaSupports) | ||||
|         return dynamic_cast<GLGizmoSlaSupports*>(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<GLGizmoHollow*>(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<GLGizmoFdmSupports*>(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; | ||||
|  |  | |||
|  | @ -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<int, 4>& 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<sla::EigenMesh3D::hit_result> 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<sla::EigenMesh3D::hit_result> 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<float>(); | ||||
|     normal = hits[i].normal().cast<float>(); | ||||
| 
 | ||||
|     if (facet_idx) | ||||
|         *facet_idx = hits[i].face(); | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -4,6 +4,8 @@ | |||
| #include "libslic3r/Point.hpp" | ||||
| #include "libslic3r/Geometry.hpp" | ||||
| #include "libslic3r/SLA/EigenMesh3D.hpp" | ||||
| #include "admesh/stl.h" | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| #include <cfloat> | ||||
|  | @ -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; | ||||
| }; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Lukas Matena
						Lukas Matena