diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 161e1a1ff..8587f01f2 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -85,6 +85,8 @@ set(SLIC3R_GUI_SOURCES GUI/GUI_ObjectLayers.hpp GUI/LambdaObjectDialog.cpp GUI/LambdaObjectDialog.hpp + GUI/MeshClipper.cpp + GUI/MeshClipper.hpp GUI/Tab.cpp GUI/Tab.hpp GUI/ConfigManipulation.cpp diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 404db33dd..ce86ffc55 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -12,6 +12,7 @@ #include "slic3r/GUI/GUI.hpp" #include "slic3r/GUI/GUI_ObjectSettings.hpp" #include "slic3r/GUI/GUI_ObjectList.hpp" +#include "slic3r/GUI/MeshClipper.hpp" #include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/PresetBundle.hpp" #include "libslic3r/SLAPrint.hpp" @@ -143,8 +144,9 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const // First cache instance transformation to be used later. const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin()); - Transform3f instance_matrix = vol->get_instance_transformation().get_matrix().cast<float>(); - Transform3f instance_matrix_no_translation_no_scaling = vol->get_instance_transformation().get_matrix(true,false,true).cast<float>(); + Geometry::Transformation trafo = vol->get_instance_transformation(); + Transform3f instance_matrix = trafo.get_matrix().cast<float>(); + Transform3f instance_matrix_no_translation_no_scaling = trafo.get_matrix(true,false,true).cast<float>(); Vec3f scaling = vol->get_instance_scaling_factor().cast<float>(); Vec3d instance_offset = vol->get_instance_offset(); // Calculate distance from mesh origin to the clipping plane (in mesh coordinates). @@ -152,6 +154,7 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const Vec3f up = Vec3f(up_noscale(0)*scaling(0), up_noscale(1)*scaling(1), up_noscale(2)*scaling(2)); float height_mesh = m_clipping_plane->distance(center) * (up_noscale.norm()/up.norm()); + // Get transformation of the supports and calculate how far from its origin the clipping plane is. Transform3d supports_trafo = Transform3d::Identity(); supports_trafo = supports_trafo.rotate(Eigen::AngleAxisd(vol->get_instance_rotation()(2), Vec3d::UnitZ())); @@ -167,15 +170,13 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const *m_old_clipping_plane = *m_clipping_plane; // Now initialize the TMS for the object, perform the cut and save the result. - if (! m_tms) { - m_tms.reset(new TriangleMeshSlicer); - m_tms->init(m_mesh, [](){}); + if (! m_object_clipper) { + m_object_clipper.reset(new MeshClipper); + m_object_clipper->set_mesh(*m_mesh); } - std::vector<ExPolygons> list_of_expolys; - m_tms->set_up_direction(up); - m_tms->slice(std::vector<float>{height_mesh}, 0.f, &list_of_expolys, [](){}); - m_triangles = triangulate_expolygons_2f(list_of_expolys[0]); - + m_object_clipper->set_plane(*m_clipping_plane); + trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_z_shift)); + m_object_clipper->set_transformation(trafo); // Next, ask the backend if supports are already calculated. If so, we are gonna cut them too. @@ -198,31 +199,27 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const // so we can later tell they were recalculated. size_t timestamp = print_object->step_state_with_timestamp(slaposSupportTree).timestamp; - if (!m_supports_tms || (int)timestamp != m_old_timestamp) { + if (! m_supports_clipper || (int)timestamp != m_old_timestamp) { // The timestamp has changed - stash the mesh and initialize the TMS. m_supports_mesh = &print_object->support_mesh(); - m_supports_tms.reset(new TriangleMeshSlicer); + m_supports_clipper.reset(new MeshClipper); // The mesh should already have the shared vertices calculated. - m_supports_tms->init(m_supports_mesh, [](){}); + m_supports_clipper->set_mesh(*m_supports_mesh); m_old_timestamp = timestamp; } // The TMS is initialized - let's do the cutting: - list_of_expolys.clear(); - m_supports_tms->set_up_direction(up_supports); - m_supports_tms->slice(std::vector<float>{height_supports}, 0.f, &list_of_expolys, [](){}); - m_supports_triangles = triangulate_expolygons_2f(list_of_expolys[0]); + m_supports_clipper->set_plane(*m_clipping_plane); + m_supports_clipper->set_transformation(Geometry::Transformation(supports_trafo)); } - else { + else // The supports are not valid. We better dump the cached data. - m_supports_tms.reset(); - m_supports_triangles.clear(); - } + m_supports_clipper.reset(); } } // At this point we have the triangulated cuts for both the object and supports - let's render. - if (! m_triangles.empty()) { + if (! m_object_clipper->get_triangles().empty()) { ::glPushMatrix(); ::glTranslated(0.0, 0.0, m_z_shift); ::glMultMatrixf(instance_matrix.data()); @@ -233,14 +230,14 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const ::glTranslatef(0.f, 0.f, 0.01f); // to make sure the cut does not intersect the structure itself ::glColor3f(1.0f, 0.37f, 0.0f); ::glBegin(GL_TRIANGLES); - for (const Vec2f& point : m_triangles) + for (const Vec2f& point : m_object_clipper->get_triangles()) ::glVertex3f(point(0), point(1), height_mesh); ::glEnd(); ::glPopMatrix(); } - if (! m_supports_triangles.empty() && !m_editing_mode) { + if (m_supports_clipper && ! 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(); ::glMultMatrixd(supports_trafo.data()); @@ -251,7 +248,7 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const ::glTranslatef(0.f, 0.f, 0.01f); ::glColor3f(1.0f, 0.f, 0.37f); ::glBegin(GL_TRIANGLES); - for (const Vec2f& point : m_supports_triangles) + for (const Vec2f& point : m_supports_clipper->get_triangles()) ::glVertex3f(point(0), point(1), height_supports); ::glEnd(); @@ -1142,8 +1139,8 @@ void GLGizmoSlaSupports::on_set_state() // Release triangle mesh slicer and the AABB spatial search structure. m_AABB.deinit(); m_its = nullptr; - m_tms.reset(); - m_supports_tms.reset(); + m_object_clipper.reset(); + m_supports_clipper.reset(); } } m_old_state = m_state; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index ee8e55218..130ac5202 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -21,6 +21,7 @@ namespace Slic3r { namespace GUI { class ClippingPlane; +class MeshClipper; class GLGizmoSlaSupports : public GLGizmoBase { @@ -126,8 +127,8 @@ 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) - mutable std::unique_ptr<TriangleMeshSlicer> m_tms; - mutable std::unique_ptr<TriangleMeshSlicer> m_supports_tms; + mutable std::unique_ptr<MeshClipper> m_object_clipper; + mutable std::unique_ptr<MeshClipper> m_supports_clipper; std::vector<const ConfigOption*> get_config_options(const std::vector<std::string>& keys) const; bool is_point_clipped(const Vec3d& point) const; diff --git a/src/slic3r/GUI/MeshClipper.cpp b/src/slic3r/GUI/MeshClipper.cpp new file mode 100644 index 000000000..c9648e7b6 --- /dev/null +++ b/src/slic3r/GUI/MeshClipper.cpp @@ -0,0 +1,83 @@ +#include "MeshClipper.hpp" +#include "GLCanvas3D.hpp" +#include "libslic3r/Tesselate.hpp" + +namespace Slic3r { +namespace GUI { + +void MeshClipper::set_plane(const ClippingPlane& plane) +{ + if (m_plane != plane) { + m_plane = plane; + m_triangles_valid = false; + } +} + +void MeshClipper::set_mesh(const TriangleMesh& mesh) +{ + if (m_mesh != &mesh) { + m_mesh = &mesh; + m_triangles_valid = false; + m_triangles.resize(0); + m_tms.reset(nullptr); + } +} + +void MeshClipper::set_transformation(const Geometry::Transformation& trafo) +{ + if (! m_trafo.get_matrix().isApprox(trafo.get_matrix())) { + m_trafo = trafo; + m_triangles_valid = false; + m_triangles.resize(0); + } +} + + +const std::vector<Vec2f>& MeshClipper::get_triangles() +{ + if (! m_triangles_valid) + recalculate_triangles(); + + return m_triangles; +} + +void MeshClipper::recalculate_triangles() +{ + if (! m_tms) { + m_tms.reset(new TriangleMeshSlicer); + m_tms->init(m_mesh, [](){}); + } + + + auto up_and_height = get_mesh_cut_normal(); + Vec3f up = up_and_height.first; + float height_mesh = up_and_height.second; + + std::vector<ExPolygons> list_of_expolys; + m_tms->set_up_direction(up); + m_tms->slice(std::vector<float>{height_mesh}, 0.f, &list_of_expolys, [](){}); + m_triangles = triangulate_expolygons_2f(list_of_expolys[0]); + + m_triangles_valid = true; +} + +std::pair<Vec3f, float> MeshClipper::get_mesh_cut_normal() const +{ + Transform3f instance_matrix_no_translation_no_scaling = m_trafo.get_matrix(true,false,true).cast<float>(); + Vec3f scaling = m_trafo.get_scaling_factor().cast<float>(); + + // Calculate distance from mesh origin to the clipping plane (in mesh coordinates). + Vec3f up_noscale = instance_matrix_no_translation_no_scaling.inverse() * m_plane.get_normal().cast<float>(); + Vec3f up (up_noscale(0)*scaling(0), up_noscale(1)*scaling(1), up_noscale(2)*scaling(2)); + + float height_mesh = m_plane.distance(m_trafo.get_offset()) * (up_noscale.norm()/up.norm()); + + + return std::make_pair(up, height_mesh); +} + + + + +} // namespace GUI +} // namespace Slic3r diff --git a/src/slic3r/GUI/MeshClipper.hpp b/src/slic3r/GUI/MeshClipper.hpp new file mode 100644 index 000000000..dbeef4408 --- /dev/null +++ b/src/slic3r/GUI/MeshClipper.hpp @@ -0,0 +1,37 @@ +#ifndef slic3r_MeshClipper_hpp_ +#define slic3r_MeshClipper_hpp_ + +#include "libslic3r/Point.hpp" +#include "slic3r/GUI/GLCanvas3D.hpp" + +namespace Slic3r { +namespace GUI { + +class MeshClipper { +public: + void set_plane(const ClippingPlane& plane); + void set_mesh(const TriangleMesh& mesh); + void set_transformation(const Geometry::Transformation& trafo); + + const std::vector<Vec2f>& get_triangles(); + +private: + void recalculate_triangles(); + std::pair<Vec3f, float> get_mesh_cut_normal() const; + + + Geometry::Transformation m_trafo; + const TriangleMesh* m_mesh = nullptr; + ClippingPlane m_plane; + std::vector<Vec2f> m_triangles; + bool m_triangles_valid = false; + std::unique_ptr<TriangleMeshSlicer> m_tms; +}; + + + +} // namespace GUI +} // namespace Slic3r + + +#endif // slic3r_MeshClipper_hpp_