1 #ifndef slic3r_MeshUtils_hpp_ 2 #define slic3r_MeshUtils_hpp_ 3 4 #include "libslic3r/Point.hpp" 5 #include "libslic3r/Geometry.hpp" 6 #include "libslic3r/SLA/IndexedMesh.hpp" 7 #include "admesh/stl.h" 8 9 #include "slic3r/GUI/3DScene.hpp" 10 11 #include <cfloat> 12 13 namespace Slic3r { 14 15 class TriangleMesh; 16 class TriangleMeshSlicer; 17 18 namespace GUI { 19 20 struct Camera; 21 22 23 // lm_FIXME: Following class might possibly be replaced by Eigen::Hyperplane 24 class ClippingPlane 25 { 26 double m_data[4]; 27 28 public: ClippingPlane()29 ClippingPlane() 30 { 31 *this = ClipsNothing(); 32 } 33 ClippingPlane(const Vec3d & direction,double offset)34 ClippingPlane(const Vec3d& direction, double offset) 35 { 36 Vec3d norm_dir = direction.normalized(); 37 m_data[0] = norm_dir(0); 38 m_data[1] = norm_dir(1); 39 m_data[2] = norm_dir(2); 40 m_data[3] = offset; 41 } 42 operator ==(const ClippingPlane & cp) const43 bool operator==(const ClippingPlane& cp) const { 44 return m_data[0]==cp.m_data[0] && m_data[1]==cp.m_data[1] && m_data[2]==cp.m_data[2] && m_data[3]==cp.m_data[3]; 45 } operator !=(const ClippingPlane & cp) const46 bool operator!=(const ClippingPlane& cp) const { return ! (*this==cp); } 47 distance(const Vec3d & pt) const48 double distance(const Vec3d& pt) const { 49 // FIXME: this fails: assert(is_approx(get_normal().norm(), 1.)); 50 return (-get_normal().dot(pt) + m_data[3]); 51 } 52 is_point_clipped(const Vec3d & point) const53 bool is_point_clipped(const Vec3d& point) const { return distance(point) < 0.; } set_normal(const Vec3d & normal)54 void set_normal(const Vec3d& normal) { for (size_t i=0; i<3; ++i) m_data[i] = normal(i); } set_offset(double offset)55 void set_offset(double offset) { m_data[3] = offset; } get_normal() const56 Vec3d get_normal() const { return Vec3d(m_data[0], m_data[1], m_data[2]); } is_active() const57 bool is_active() const { return m_data[3] != DBL_MAX; } ClipsNothing()58 static ClippingPlane ClipsNothing() { return ClippingPlane(Vec3d(0., 0., 1.), DBL_MAX); } get_data() const59 const double* get_data() const { return m_data; } 60 61 // Serialization through cereal library 62 template <class Archive> serialize(Archive & ar)63 void serialize( Archive & ar ) 64 { 65 ar( m_data[0], m_data[1], m_data[2], m_data[3] ); 66 } 67 }; 68 69 70 // MeshClipper class cuts a mesh and is able to return a triangulated cut. 71 class MeshClipper { 72 public: 73 // Inform MeshClipper about which plane we want to use to cut the mesh 74 // This is supposed to be in world coordinates. 75 void set_plane(const ClippingPlane& plane); 76 77 // Which mesh to cut. MeshClipper remembers const * to it, caller 78 // must make sure that it stays valid. 79 void set_mesh(const TriangleMesh& mesh); 80 81 // Inform the MeshClipper about the transformation that transforms the mesh 82 // into world coordinates. 83 void set_transformation(const Geometry::Transformation& trafo); 84 85 // Render the triangulated cut. Transformation matrices should 86 // be set in world coords. 87 void render_cut(); 88 89 private: 90 void recalculate_triangles(); 91 92 Geometry::Transformation m_trafo; 93 const TriangleMesh* m_mesh = nullptr; 94 ClippingPlane m_plane; 95 std::vector<Vec2f> m_triangles2d; 96 GLIndexedVertexArray m_vertex_array; 97 bool m_triangles_valid = false; 98 std::unique_ptr<TriangleMeshSlicer> m_tms; 99 }; 100 101 102 103 // MeshRaycaster class answers queries such as where on the mesh someone clicked, 104 // whether certain points are visible or obscured by the mesh etc. 105 class MeshRaycaster { 106 public: 107 // The class references extern TriangleMesh, which must stay alive 108 // during MeshRaycaster existence. MeshRaycaster(const TriangleMesh & mesh)109 MeshRaycaster(const TriangleMesh& mesh) 110 : m_emesh(mesh) 111 { 112 m_normals.reserve(mesh.stl.facet_start.size()); 113 for (const stl_facet& facet : mesh.stl.facet_start) 114 m_normals.push_back(facet.normal); 115 } 116 117 void line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, 118 Vec3d& point, Vec3d& direction) const; 119 120 // Given a mouse position, this returns true in case it is on the mesh. 121 bool unproject_on_mesh( 122 const Vec2d& mouse_pos, 123 const Transform3d& trafo, // how to get the mesh into world coords 124 const Camera& camera, // current camera position 125 Vec3f& position, // where to save the positibon of the hit (mesh coords) 126 Vec3f& normal, // normal of the triangle that was hit 127 const ClippingPlane* clipping_plane = nullptr, // clipping plane (if active) 128 size_t* facet_idx = nullptr // index of the facet hit 129 ) const; 130 131 // Given a vector of points in woorld coordinates, this returns vector 132 // of indices of points that are visible (i.e. not cut by clipping plane 133 // or obscured by part of the mesh. 134 std::vector<unsigned> get_unobscured_idxs( 135 const Geometry::Transformation& trafo, // how to get the mesh into world coords 136 const Camera& camera, // current camera position 137 const std::vector<Vec3f>& points, // points in world coords 138 const ClippingPlane* clipping_plane = nullptr // clipping plane (if active) 139 ) const; 140 141 // Given a point in world coords, the method returns closest point on the mesh. 142 // The output is in mesh coords. 143 // normal* can be used to also get normal of the respective triangle. 144 145 Vec3f get_closest_point(const Vec3f& point, Vec3f* normal = nullptr) const; 146 147 Vec3f get_triangle_normal(size_t facet_idx) const; 148 149 private: 150 sla::IndexedMesh m_emesh; 151 std::vector<stl_normal> m_normals; 152 }; 153 154 155 } // namespace GUI 156 } // namespace Slic3r 157 158 159 #endif // slic3r_MeshUtils_hpp_ 160