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