From 724cc19ae500f6d292e2251b156348cba69711ce Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 12 Sep 2019 10:44:38 +0200 Subject: [PATCH 1/6] Fixed object position after reload from disk --- src/slic3r/GUI/Plater.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 803510f80..a2443a522 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3127,11 +3127,14 @@ void Plater::priv::reload_from_disk() object->add_volume(*v); } + Vec3d offset = object_orig->origin_translation - object->origin_translation; + if (object->volumes.size() == object_orig->volumes.size()) { for (size_t i = 0; i < object->volumes.size(); i++) { object->volumes[i]->config.apply(object_orig->volumes[i]->config); + object->volumes[i]->translate(offset); } } From 177a96a768b7fb9abd37b39d47b9a3a1c9e976af Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Fri, 13 Sep 2019 11:01:02 +0200 Subject: [PATCH 2/6] Fix arrange crash with ASAN --- .../libnest2d/selections/selection_boilerplate.hpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/libnest2d/include/libnest2d/selections/selection_boilerplate.hpp b/src/libnest2d/include/libnest2d/selections/selection_boilerplate.hpp index 4bb2e72af..2df9a26c3 100644 --- a/src/libnest2d/include/libnest2d/selections/selection_boilerplate.hpp +++ b/src/libnest2d/include/libnest2d/selections/selection_boilerplate.hpp @@ -33,10 +33,16 @@ protected: // then it should be removed from the list auto it = c.begin(); while (it != c.end() && !stopcond_()) { - Placer p{bin}; - p.configure(pcfg); + + // WARNING: The copy of itm needs to be created before Placer. + // Placer is working with references and its destructor still + // manipulates the item this is why the order of stack creation + // matters here. const Item& itm = *it; Item cpy{itm}; + + Placer p{bin}; + p.configure(pcfg); if (!p.pack(cpy)) it = c.erase(it); else it++; } From cf23146ee3fa6e6038396d85796d497f9edfd8ab Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 12 Sep 2019 13:18:02 +0200 Subject: [PATCH 3/6] Refactoring the SLA clipping plane The plane is now internally stored as a plane in world coordinates --- src/slic3r/GUI/GLCanvas3D.hpp | 22 +++++- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 70 ++++++++------------ src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp | 9 ++- 3 files changed, 53 insertions(+), 48 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 202d3ef77..1b998c67e 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -89,11 +89,29 @@ public: m_data[3] = offset; } + bool operator==(const ClippingPlane& cp) const { + 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]; + } + bool operator!=(const ClippingPlane& cp) const { return ! (*this==cp); } + + double distance(const Vec3d& pt) const { + assert(is_approx(get_normal().norm(), 1.)); + return (-get_normal().dot(pt) + m_data[3]); + } + + void set_normal(const Vec3d& normal) { for (size_t i=0; i<3; ++i) m_data[i] = normal(i); } + void set_offset(double offset) { m_data[3] = offset; } + Vec3d get_normal() const { return Vec3d(m_data[0], m_data[1], m_data[2]); } bool is_active() const { return m_data[3] != DBL_MAX; } - static ClippingPlane ClipsNothing() { return ClippingPlane(Vec3d(0., 0., 1.), DBL_MAX); } - const double* get_data() const { return m_data; } + + // Serialization through cereal library + template + void serialize( Archive & ar ) + { + ar( m_data[0], m_data[1], m_data[2], m_data[3] ); + } }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 0a5c21cce..404db33dd 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -26,6 +26,8 @@ GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& ic , m_quadric(nullptr) , m_its(nullptr) { + m_clipping_plane.reset(new ClippingPlane(Vec3d::Zero(), 0.)); + m_old_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 @@ -137,10 +139,7 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const if (m_clipping_plane_distance == 0.f) return; - if (m_clipping_plane_normal == Vec3d::Zero()) - reset_clipping_plane_normal(); - - const Vec3d& direction_to_camera = m_clipping_plane_normal; + const Vec3d& center = m_model_object->instances[m_active_instance]->get_offset() + Vec3d(0., 0., m_z_shift); // First cache instance transformation to be used later. const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin()); @@ -148,27 +147,24 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const Transform3f instance_matrix_no_translation_no_scaling = vol->get_instance_transformation().get_matrix(true,false,true).cast(); Vec3f scaling = vol->get_instance_scaling_factor().cast(); Vec3d instance_offset = vol->get_instance_offset(); - // Calculate distance from mesh origin to the clipping plane (in mesh coordinates). - Vec3f up_noscale = instance_matrix_no_translation_no_scaling.inverse() * direction_to_camera.cast(); + Vec3f up_noscale = instance_matrix_no_translation_no_scaling.inverse() * m_clipping_plane->get_normal().cast(); Vec3f up = Vec3f(up_noscale(0)*scaling(0), up_noscale(1)*scaling(1), up_noscale(2)*scaling(2)); - float height_mesh = (m_active_instance_bb_radius - m_clipping_plane_distance * 2*m_active_instance_bb_radius) * (up_noscale.norm()/up.norm()); + 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())); - Vec3f up_supports = (supports_trafo.inverse() * direction_to_camera).cast(); + Vec3f up_supports = (supports_trafo.inverse() * m_clipping_plane->get_normal()).cast(); supports_trafo = supports_trafo.pretranslate(Vec3d(instance_offset(0), instance_offset(1), vol->get_sla_shift_z())); // Instance and supports origin do not coincide, so the following is quite messy: - float height_supports = height_mesh * (up.norm() / up_supports.norm()) + instance_offset(2) * (direction_to_camera(2) / direction_to_camera.norm()); + float height_supports = height_mesh * (up.norm() / up_supports.norm()) + instance_offset(2) * (m_clipping_plane->get_normal()(2)); // In case either of these was recently changed, the cached triangulated ExPolygons are invalid now. // We are gonna recalculate them both for the object and for the support structures. - if (m_clipping_plane_distance != m_old_clipping_plane_distance - || m_old_clipping_plane_normal != direction_to_camera) { + if (*m_old_clipping_plane != *m_clipping_plane) { - m_old_clipping_plane_normal = direction_to_camera; - m_old_clipping_plane_distance = m_clipping_plane_distance; + *m_old_clipping_plane = *m_clipping_plane; // Now initialize the TMS for the object, perform the cut and save the result. if (! m_tms) { @@ -379,15 +375,12 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) bool GLGizmoSlaSupports::is_point_clipped(const Vec3d& point) const { - const Vec3d& direction_to_camera = m_clipping_plane_normal; - if (m_clipping_plane_distance == 0.f) return false; Vec3d transformed_point = m_model_object->instances.front()->get_transformation().get_matrix() * point; transformed_point(2) += m_z_shift; - return direction_to_camera.dot(m_model_object->instances[m_active_instance]->get_offset() + Vec3d(0., 0., m_z_shift)) + m_active_instance_bb_radius - - m_clipping_plane_distance * 2*m_active_instance_bb_radius < direction_to_camera.dot(transformed_point); + return m_clipping_plane->distance(transformed_point) < 0.; } @@ -693,18 +686,18 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous if (action == SLAGizmoEventType::MouseWheelUp && control_down) { m_clipping_plane_distance = std::min(1.f, m_clipping_plane_distance + 0.01f); - m_parent.set_as_dirty(); + 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); - m_parent.set_as_dirty(); + update_clipping_plane(true); return true; } if (action == SLAGizmoEventType::ResetClippingPlane) { - reset_clipping_plane_normal(); + update_clipping_plane(); return true; } @@ -796,18 +789,10 @@ void GLGizmoSlaSupports::update_cache_entry_normal(size_t i) const ClippingPlane GLGizmoSlaSupports::get_sla_clipping_plane() const { - if (!m_model_object || m_state == Off) + if (!m_model_object || m_state == Off || m_clipping_plane_distance == 0.f) return ClippingPlane::ClipsNothing(); - - //Eigen::Matrix modelview_matrix; - //::glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix.data()); - // we'll recover current look direction from the modelview matrix (in world coords): - //Vec3d direction_to_camera(modelview_matrix.data()[2], modelview_matrix.data()[6], modelview_matrix.data()[10]); - - const Vec3d& direction_to_camera = m_clipping_plane_normal; - float dist = direction_to_camera.dot(m_model_object->instances[m_active_instance]->get_offset() + Vec3d(0., 0., m_z_shift)); - - return ClippingPlane(-direction_to_camera.normalized(),(dist - (-m_active_instance_bb_radius) - m_clipping_plane_distance * 2*m_active_instance_bb_radius)); + else + return ClippingPlane(-m_clipping_plane->get_normal(), m_clipping_plane->get_data()[3]); } @@ -1019,14 +1004,15 @@ RENDER_AGAIN: else { if (m_imgui->button(m_desc.at("reset_direction"))) { wxGetApp().CallAfter([this](){ - reset_clipping_plane_normal(); + update_clipping_plane(); }); } } ImGui::SameLine(clipping_slider_left); ImGui::PushItemWidth(window_width - clipping_slider_left); - ImGui::SliderFloat(" ", &m_clipping_plane_distance, 0.f, 1.f, "%.2f"); + if (ImGui::SliderFloat(" ", &m_clipping_plane_distance, 0.f, 1.f, "%.2f")) + update_clipping_plane(true); if (m_imgui->button("?")) { @@ -1198,7 +1184,7 @@ void GLGizmoSlaSupports::on_stop_dragging() void GLGizmoSlaSupports::on_load(cereal::BinaryInputArchive& ar) { ar(m_clipping_plane_distance, - m_clipping_plane_normal, + *m_clipping_plane, m_model_object_id, m_new_point_head_diameter, m_normal_cache, @@ -1212,7 +1198,7 @@ void GLGizmoSlaSupports::on_load(cereal::BinaryInputArchive& ar) void GLGizmoSlaSupports::on_save(cereal::BinaryOutputArchive& ar) const { ar(m_clipping_plane_distance, - m_clipping_plane_normal, + *m_clipping_plane, m_model_object_id, m_new_point_head_diameter, m_normal_cache, @@ -1401,17 +1387,19 @@ bool GLGizmoSlaSupports::unsaved_changes() const } -void GLGizmoSlaSupports::reset_clipping_plane_normal() const +void GLGizmoSlaSupports::update_clipping_plane(bool keep_normal) const { - Eigen::Matrix modelview_matrix; - ::glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix.data()); - m_clipping_plane_normal = Vec3d(modelview_matrix.data()[2], modelview_matrix.data()[6], modelview_matrix.data()[10]); + 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() + Vec3d(0., 0., m_z_shift); + 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(); } - SlaGizmoHelpDialog::SlaGizmoHelpDialog() -: wxDialog(NULL, wxID_ANY, _(L("SLA gizmo keyboard shortcuts")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER) +: wxDialog(nullptr, wxID_ANY, _(L("SLA gizmo keyboard shortcuts")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER) { SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); const wxString ctrl = GUI::shortkey_ctrl_prefix(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index d2451f64e..ee8e55218 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -4,6 +4,7 @@ #include "GLGizmoBase.hpp" #include "GLGizmos.hpp" #include "slic3r/GUI/GLSelectionRectangle.hpp" +#include "slic3r/GUI/GLSelectionRectangle.hpp" // There is an L function in igl that would be overridden by our localization macro - let's undefine it... #undef L @@ -19,10 +20,8 @@ namespace Slic3r { namespace GUI { - class ClippingPlane; - class GLGizmoSlaSupports : public GLGizmoBase { private: @@ -114,9 +113,8 @@ private: std::vector m_normal_cache; // to restore after discarding changes or undo/redo float m_clipping_plane_distance = 0.f; - mutable float m_old_clipping_plane_distance = 0.f; - mutable Vec3d m_old_clipping_plane_normal; - mutable Vec3d m_clipping_plane_normal = Vec3d::Zero(); + std::unique_ptr m_clipping_plane; + std::unique_ptr m_old_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. @@ -151,6 +149,7 @@ private: void switch_to_editing_mode(); void disable_editing_mode(); void reset_clipping_plane_normal() const; + void update_clipping_plane(bool keep_normal = false) const; protected: void on_set_state() override; From 546917830bb1f96615ee5841518c717fc348b9a0 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 12 Sep 2019 14:58:03 +0200 Subject: [PATCH 4/6] Initial implementation of MeshClipper class So far the work is shared between the old code in GLGizmoSlaSupports.cpp and the new class --- src/slic3r/CMakeLists.txt | 2 + src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 51 ++++++------ src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp | 5 +- src/slic3r/GUI/MeshClipper.cpp | 83 ++++++++++++++++++++ src/slic3r/GUI/MeshClipper.hpp | 37 +++++++++ 5 files changed, 149 insertions(+), 29 deletions(-) create mode 100644 src/slic3r/GUI/MeshClipper.cpp create mode 100644 src/slic3r/GUI/MeshClipper.hpp 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(); - Transform3f instance_matrix_no_translation_no_scaling = vol->get_instance_transformation().get_matrix(true,false,true).cast(); + Geometry::Transformation trafo = vol->get_instance_transformation(); + Transform3f instance_matrix = trafo.get_matrix().cast(); + Transform3f instance_matrix_no_translation_no_scaling = trafo.get_matrix(true,false,true).cast(); Vec3f scaling = vol->get_instance_scaling_factor().cast(); 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 list_of_expolys; - m_tms->set_up_direction(up); - m_tms->slice(std::vector{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{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 m_tms; - mutable std::unique_ptr m_supports_tms; + 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_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& 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 list_of_expolys; + m_tms->set_up_direction(up); + m_tms->slice(std::vector{height_mesh}, 0.f, &list_of_expolys, [](){}); + m_triangles = triangulate_expolygons_2f(list_of_expolys[0]); + + m_triangles_valid = true; +} + +std::pair MeshClipper::get_mesh_cut_normal() const +{ + Transform3f instance_matrix_no_translation_no_scaling = m_trafo.get_matrix(true,false,true).cast(); + Vec3f scaling = m_trafo.get_scaling_factor().cast(); + + // 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(); + 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& get_triangles(); + +private: + void recalculate_triangles(); + std::pair get_mesh_cut_normal() const; + + + Geometry::Transformation m_trafo; + const TriangleMesh* m_mesh = nullptr; + ClippingPlane m_plane; + std::vector m_triangles; + bool m_triangles_valid = false; + std::unique_ptr m_tms; +}; + + + +} // namespace GUI +} // namespace Slic3r + + +#endif // slic3r_MeshClipper_hpp_ From 9782701dd4f3fe8b13c6ab0c4ed1c55f0bfdac73 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 12 Sep 2019 16:57:30 +0200 Subject: [PATCH 5/6] Calculating the transformations is now only performed by the MeshClipper Attempted to get mirroring right (that never worked correctly with the clipping plane in the sla gizmo) The transformation of the support mesh is kind of a mystery to me, hopefully it is right Also cleaned the code a bit (removed commented-out code, unused variables, etc) --- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 140 +++++++------------ src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp | 1 - src/slic3r/GUI/MeshClipper.cpp | 54 +++---- src/slic3r/GUI/MeshClipper.hpp | 7 +- 4 files changed, 85 insertions(+), 117 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index ce86ffc55..99c4612ce 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -28,7 +28,6 @@ GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& ic , m_its(nullptr) { m_clipping_plane.reset(new ClippingPlane(Vec3d::Zero(), 0.)); - m_old_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 @@ -140,117 +139,82 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const if (m_clipping_plane_distance == 0.f) return; - const Vec3d& center = m_model_object->instances[m_active_instance]->get_offset() + Vec3d(0., 0., m_z_shift); - - // First cache instance transformation to be used later. + // Get transformation of the instance const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin()); Geometry::Transformation trafo = vol->get_instance_transformation(); - Transform3f instance_matrix = trafo.get_matrix().cast(); - Transform3f instance_matrix_no_translation_no_scaling = trafo.get_matrix(true,false,true).cast(); - Vec3f scaling = vol->get_instance_scaling_factor().cast(); - Vec3d instance_offset = vol->get_instance_offset(); - // Calculate distance from mesh origin to the clipping plane (in mesh coordinates). - Vec3f up_noscale = instance_matrix_no_translation_no_scaling.inverse() * m_clipping_plane->get_normal().cast(); - 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()); + 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_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); - // 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())); - Vec3f up_supports = (supports_trafo.inverse() * m_clipping_plane->get_normal()).cast(); - supports_trafo = supports_trafo.pretranslate(Vec3d(instance_offset(0), instance_offset(1), vol->get_sla_shift_z())); - // Instance and supports origin do not coincide, so the following is quite messy: - float height_supports = height_mesh * (up.norm() / up_supports.norm()) + instance_offset(2) * (m_clipping_plane->get_normal()(2)); - - // In case either of these was recently changed, the cached triangulated ExPolygons are invalid now. - // We are gonna recalculate them both for the object and for the support structures. - if (*m_old_clipping_plane != *m_clipping_plane) { - - *m_old_clipping_plane = *m_clipping_plane; - - // 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); + // 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_print_object_idx < 0 || (int)m_parent.sla_print()->objects().size() != m_print_objects_count) { + m_print_objects_count = m_parent.sla_print()->objects().size(); + m_print_object_idx = -1; + for (const SLAPrintObject* po : m_parent.sla_print()->objects()) { + ++m_print_object_idx; + if (po->model_object()->id() == m_model_object->id()) + break; } - 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); + } + if (m_print_object_idx >= 0) { + const SLAPrintObject* print_object = m_parent.sla_print()->objects()[m_print_object_idx]; + if (print_object->is_step_done(slaposSupportTree)) { + // 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; - // 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_print_object_idx < 0 || (int)m_parent.sla_print()->objects().size() != m_print_objects_count) { - m_print_objects_count = m_parent.sla_print()->objects().size(); - m_print_object_idx = -1; - for (const SLAPrintObject* po : m_parent.sla_print()->objects()) { - ++m_print_object_idx; - if (po->model_object()->id() == m_model_object->id()) - break; + if (! m_supports_clipper || (int)timestamp != m_old_timestamp) { + // The timestamp has changed. + m_supports_clipper.reset(new MeshClipper); + // The mesh should already have the shared vertices calculated. + m_supports_clipper->set_mesh(print_object->support_mesh()); + m_old_timestamp = timestamp; } + m_supports_clipper->set_plane(*m_clipping_plane); + m_supports_clipper->set_transformation(supports_trafo); } - if (m_print_object_idx >= 0) { - const SLAPrintObject* print_object = m_parent.sla_print()->objects()[m_print_object_idx]; - - if (print_object->is_step_done(slaposSupportTree)) { - // 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_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_clipper.reset(new MeshClipper); - // The mesh should already have the shared vertices calculated. - m_supports_clipper->set_mesh(*m_supports_mesh); - m_old_timestamp = timestamp; - } - - // The TMS is initialized - let's do the cutting: - m_supports_clipper->set_plane(*m_clipping_plane); - m_supports_clipper->set_transformation(Geometry::Transformation(supports_trafo)); - } - else - // The supports are not valid. We better dump the cached data. - m_supports_clipper.reset(); - } + else + // The supports are not valid. We better dump the cached data. + m_supports_clipper.reset(); } // 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(); - ::glTranslated(0.0, 0.0, m_z_shift); - ::glMultMatrixf(instance_matrix.data()); - Eigen::Quaternionf q; - q.setFromTwoVectors(Vec3f::UnitZ(), up); - Eigen::AngleAxisf aa(q); - ::glRotatef(aa.angle() * (180./M_PI), aa.axis()(0), aa.axis()(1), aa.axis()(2)); - ::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_object_clipper->get_triangles()) - ::glVertex3f(point(0), point(1), height_mesh); - + for (const Vec3f& point : m_object_clipper->get_triangles()) + ::glVertex3f(point(0), point(1), point(2)); ::glEnd(); ::glPopMatrix(); } 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()); - Eigen::Quaternionf q; - q.setFromTwoVectors(Vec3f::UnitZ(), up_supports); - Eigen::AngleAxisf aa(q); - ::glRotatef(aa.angle() * (180./M_PI), aa.axis()(0), aa.axis()(1), aa.axis()(2)); - ::glTranslatef(0.f, 0.f, 0.01f); + ::glPushMatrix(); ::glColor3f(1.0f, 0.f, 0.37f); ::glBegin(GL_TRIANGLES); - for (const Vec2f& point : m_supports_clipper->get_triangles()) - ::glVertex3f(point(0), point(1), height_supports); - + for (const Vec3f& point : m_supports_clipper->get_triangles()) + ::glVertex3f(point(0), point(1), point(2)); ::glEnd(); ::glPopMatrix(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index 130ac5202..515783d98 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -115,7 +115,6 @@ private: float m_clipping_plane_distance = 0.f; std::unique_ptr m_clipping_plane; - std::unique_ptr m_old_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/MeshClipper.cpp b/src/slic3r/GUI/MeshClipper.cpp index c9648e7b6..21ddf52bc 100644 --- a/src/slic3r/GUI/MeshClipper.cpp +++ b/src/slic3r/GUI/MeshClipper.cpp @@ -18,7 +18,8 @@ void MeshClipper::set_mesh(const TriangleMesh& mesh) if (m_mesh != &mesh) { m_mesh = &mesh; m_triangles_valid = false; - m_triangles.resize(0); + m_triangles2d.resize(0); + m_triangles3d.resize(0); m_tms.reset(nullptr); } } @@ -28,17 +29,19 @@ 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); + m_triangles2d.resize(0); + m_triangles3d.resize(0); } } -const std::vector& MeshClipper::get_triangles() + +const std::vector& MeshClipper::get_triangles() { if (! m_triangles_valid) recalculate_triangles(); - return m_triangles; + return m_triangles3d; } void MeshClipper::recalculate_triangles() @@ -49,34 +52,37 @@ void MeshClipper::recalculate_triangles() } - auto up_and_height = get_mesh_cut_normal(); - Vec3f up = up_and_height.first; - float height_mesh = up_and_height.second; + const Transform3f& instance_matrix_no_translation_no_scaling = m_trafo.get_matrix(true,false,true).cast(); + const Vec3f& scaling = m_trafo.get_scaling_factor().cast(); + // Calculate clipping plane normal in mesh coordinates. + Vec3f up_noscale = instance_matrix_no_translation_no_scaling.inverse() * m_plane.get_normal().cast(); + Vec3f up (up_noscale(0)*scaling(0), up_noscale(1)*scaling(1), up_noscale(2)*scaling(2)); + // Calculate distance from mesh origin to the clipping plane (in mesh coordinates). + float height_mesh = m_plane.distance(m_trafo.get_offset()) * (up_noscale.norm()/up.norm()); + // Now do the cutting std::vector list_of_expolys; m_tms->set_up_direction(up); m_tms->slice(std::vector{height_mesh}, 0.f, &list_of_expolys, [](){}); - m_triangles = triangulate_expolygons_2f(list_of_expolys[0]); + m_triangles2d = triangulate_expolygons_2f(list_of_expolys[0], m_trafo.get_matrix().matrix().determinant() < 0.); + + // Rotate the cut into world coords: + Eigen::Quaternionf q; + q.setFromTwoVectors(Vec3f::UnitZ(), up); + Transform3f tr = Transform3f::Identity(); + tr.rotate(q); + 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_triangles_valid = true; } -std::pair MeshClipper::get_mesh_cut_normal() const -{ - Transform3f instance_matrix_no_translation_no_scaling = m_trafo.get_matrix(true,false,true).cast(); - Vec3f scaling = m_trafo.get_scaling_factor().cast(); - - // 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(); - 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 diff --git a/src/slic3r/GUI/MeshClipper.hpp b/src/slic3r/GUI/MeshClipper.hpp index dbeef4408..18b60761e 100644 --- a/src/slic3r/GUI/MeshClipper.hpp +++ b/src/slic3r/GUI/MeshClipper.hpp @@ -13,17 +13,16 @@ public: void set_mesh(const TriangleMesh& mesh); void set_transformation(const Geometry::Transformation& trafo); - const std::vector& get_triangles(); + const std::vector& get_triangles(); private: void recalculate_triangles(); - std::pair get_mesh_cut_normal() const; - Geometry::Transformation m_trafo; const TriangleMesh* m_mesh = nullptr; ClippingPlane m_plane; - std::vector m_triangles; + std::vector m_triangles2d; + std::vector m_triangles3d; bool m_triangles_valid = false; std::unique_ptr m_tms; }; From 70c0c8759805472d1c72bf9d2254900fff44a01e Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 13 Sep 2019 11:30:50 +0200 Subject: [PATCH 6/6] Renamed MeshClipper.cpp/.hpp to MeshUtils.cpp/.hpp More helper classes like the MeshClipper could live here Moved ClippingPlane class in here to start --- src/slic3r/CMakeLists.txt | 4 +- src/slic3r/GUI/GLCanvas3D.hpp | 49 +--------- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp | 3 +- src/slic3r/GUI/Gizmos/GLGizmos.hpp | 8 +- src/slic3r/GUI/MeshClipper.hpp | 36 ------- .../GUI/{MeshClipper.cpp => MeshUtils.cpp} | 12 ++- src/slic3r/GUI/MeshUtils.hpp | 94 +++++++++++++++++++ 8 files changed, 116 insertions(+), 94 deletions(-) delete mode 100644 src/slic3r/GUI/MeshClipper.hpp rename src/slic3r/GUI/{MeshClipper.cpp => MeshUtils.cpp} (97%) create mode 100644 src/slic3r/GUI/MeshUtils.hpp diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 8587f01f2..17b76e629 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -85,8 +85,8 @@ set(SLIC3R_GUI_SOURCES GUI/GUI_ObjectLayers.hpp GUI/LambdaObjectDialog.cpp GUI/LambdaObjectDialog.hpp - GUI/MeshClipper.cpp - GUI/MeshClipper.hpp + GUI/MeshUtils.cpp + GUI/MeshUtils.hpp GUI/Tab.cpp GUI/Tab.hpp GUI/ConfigManipulation.cpp diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 1b998c67e..b15402a52 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -12,6 +12,7 @@ #include "Selection.hpp" #include "Gizmos/GLGizmosManager.hpp" #include "GUI_ObjectLayers.hpp" +#include "MeshUtils.hpp" #include @@ -67,54 +68,6 @@ public: }; -class ClippingPlane -{ - double m_data[4]; - -public: - ClippingPlane() - { - m_data[0] = 0.0; - m_data[1] = 0.0; - m_data[2] = 1.0; - m_data[3] = 0.0; - } - - ClippingPlane(const Vec3d& direction, double offset) - { - Vec3d norm_dir = direction.normalized(); - m_data[0] = norm_dir(0); - m_data[1] = norm_dir(1); - m_data[2] = norm_dir(2); - m_data[3] = offset; - } - - bool operator==(const ClippingPlane& cp) const { - 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]; - } - bool operator!=(const ClippingPlane& cp) const { return ! (*this==cp); } - - double distance(const Vec3d& pt) const { - assert(is_approx(get_normal().norm(), 1.)); - return (-get_normal().dot(pt) + m_data[3]); - } - - void set_normal(const Vec3d& normal) { for (size_t i=0; i<3; ++i) m_data[i] = normal(i); } - void set_offset(double offset) { m_data[3] = offset; } - Vec3d get_normal() const { return Vec3d(m_data[0], m_data[1], m_data[2]); } - bool is_active() const { return m_data[3] != DBL_MAX; } - static ClippingPlane ClipsNothing() { return ClippingPlane(Vec3d(0., 0., 1.), DBL_MAX); } - const double* get_data() const { return m_data; } - - // Serialization through cereal library - template - void serialize( Archive & ar ) - { - ar( m_data[0], m_data[1], m_data[2], m_data[3] ); - } -}; - - wxDECLARE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent); using Vec2dEvent = Event; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 99c4612ce..80afb29b1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -1,6 +1,7 @@ // Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro. #include "GLGizmoSlaSupports.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" +#include "slic3r/GUI/Gizmos/GLGizmos.hpp" #include @@ -12,11 +13,10 @@ #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/MeshUtils.hpp" #include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/PresetBundle.hpp" #include "libslic3r/SLAPrint.hpp" -#include "libslic3r/Tesselate.hpp" namespace Slic3r { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index 515783d98..7bef33e1b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -2,8 +2,6 @@ #define slic3r_GLGizmoSlaSupports_hpp_ #include "GLGizmoBase.hpp" -#include "GLGizmos.hpp" -#include "slic3r/GUI/GLSelectionRectangle.hpp" #include "slic3r/GUI/GLSelectionRectangle.hpp" // There is an L function in igl that would be overridden by our localization macro - let's undefine it... @@ -22,6 +20,7 @@ namespace GUI { class ClippingPlane; class MeshClipper; +enum class SLAGizmoEventType : unsigned char; class GLGizmoSlaSupports : public GLGizmoBase { diff --git a/src/slic3r/GUI/Gizmos/GLGizmos.hpp b/src/slic3r/GUI/Gizmos/GLGizmos.hpp index 2e98899be..272fa098a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmos.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmos.hpp @@ -2,7 +2,10 @@ #define slic3r_GLGizmos_hpp_ // this describes events being passed from GLCanvas3D to SlaSupport gizmo -enum class SLAGizmoEventType { +namespace Slic3r { +namespace GUI { + +enum class SLAGizmoEventType : unsigned char { LeftDown = 1, LeftUp, RightDown, @@ -20,6 +23,9 @@ enum class SLAGizmoEventType { ResetClippingPlane }; +} // namespace GUI +} // namespace Slic3r + #include "slic3r/GUI/Gizmos/GLGizmoMove.hpp" #include "slic3r/GUI/Gizmos/GLGizmoScale.hpp" #include "slic3r/GUI/Gizmos/GLGizmoRotate.hpp" diff --git a/src/slic3r/GUI/MeshClipper.hpp b/src/slic3r/GUI/MeshClipper.hpp deleted file mode 100644 index 18b60761e..000000000 --- a/src/slic3r/GUI/MeshClipper.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#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& get_triangles(); - -private: - void recalculate_triangles(); - - Geometry::Transformation m_trafo; - const TriangleMesh* m_mesh = nullptr; - ClippingPlane m_plane; - std::vector m_triangles2d; - std::vector m_triangles3d; - bool m_triangles_valid = false; - std::unique_ptr m_tms; -}; - - - -} // namespace GUI -} // namespace Slic3r - - -#endif // slic3r_MeshClipper_hpp_ diff --git a/src/slic3r/GUI/MeshClipper.cpp b/src/slic3r/GUI/MeshUtils.cpp similarity index 97% rename from src/slic3r/GUI/MeshClipper.cpp rename to src/slic3r/GUI/MeshUtils.cpp index 21ddf52bc..9542f0b1f 100644 --- a/src/slic3r/GUI/MeshClipper.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -1,6 +1,7 @@ -#include "MeshClipper.hpp" -#include "GLCanvas3D.hpp" +#include "MeshUtils.hpp" + #include "libslic3r/Tesselate.hpp" +#include "libslic3r/TriangleMesh.hpp" namespace Slic3r { namespace GUI { @@ -13,6 +14,8 @@ void MeshClipper::set_plane(const ClippingPlane& plane) } } + + void MeshClipper::set_mesh(const TriangleMesh& mesh) { if (m_mesh != &mesh) { @@ -24,6 +27,8 @@ void MeshClipper::set_mesh(const TriangleMesh& mesh) } } + + void MeshClipper::set_transformation(const Geometry::Transformation& trafo) { if (! m_trafo.get_matrix().isApprox(trafo.get_matrix())) { @@ -44,6 +49,8 @@ const std::vector& MeshClipper::get_triangles() return m_triangles3d; } + + void MeshClipper::recalculate_triangles() { if (! m_tms) { @@ -51,7 +58,6 @@ void MeshClipper::recalculate_triangles() m_tms->init(m_mesh, [](){}); } - const Transform3f& instance_matrix_no_translation_no_scaling = m_trafo.get_matrix(true,false,true).cast(); const Vec3f& scaling = m_trafo.get_scaling_factor().cast(); // Calculate clipping plane normal in mesh coordinates. diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp new file mode 100644 index 000000000..f97003a91 --- /dev/null +++ b/src/slic3r/GUI/MeshUtils.hpp @@ -0,0 +1,94 @@ +#ifndef slic3r_MeshUtils_hpp_ +#define slic3r_MeshUtils_hpp_ + +#include "libslic3r/Point.hpp" +#include "libslic3r/Geometry.hpp" + + +#include + +namespace Slic3r { + +class TriangleMesh; +class TriangleMeshSlicer; + +namespace GUI { + + + +class ClippingPlane +{ + double m_data[4]; + +public: + ClippingPlane() + { + m_data[0] = 0.0; + m_data[1] = 0.0; + m_data[2] = 1.0; + m_data[3] = 0.0; + } + + ClippingPlane(const Vec3d& direction, double offset) + { + Vec3d norm_dir = direction.normalized(); + m_data[0] = norm_dir(0); + m_data[1] = norm_dir(1); + m_data[2] = norm_dir(2); + m_data[3] = offset; + } + + bool operator==(const ClippingPlane& cp) const { + 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]; + } + bool operator!=(const ClippingPlane& cp) const { return ! (*this==cp); } + + double distance(const Vec3d& pt) const { + assert(is_approx(get_normal().norm(), 1.)); + return (-get_normal().dot(pt) + m_data[3]); + } + + void set_normal(const Vec3d& normal) { for (size_t i=0; i<3; ++i) m_data[i] = normal(i); } + void set_offset(double offset) { m_data[3] = offset; } + Vec3d get_normal() const { return Vec3d(m_data[0], m_data[1], m_data[2]); } + bool is_active() const { return m_data[3] != DBL_MAX; } + static ClippingPlane ClipsNothing() { return ClippingPlane(Vec3d(0., 0., 1.), DBL_MAX); } + const double* get_data() const { return m_data; } + + // Serialization through cereal library + template + void serialize( Archive & ar ) + { + ar( m_data[0], m_data[1], m_data[2], m_data[3] ); + } +}; + + + +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& get_triangles(); + +private: + void recalculate_triangles(); + + Geometry::Transformation m_trafo; + const TriangleMesh* m_mesh = nullptr; + ClippingPlane m_plane; + std::vector m_triangles2d; + std::vector m_triangles3d; + bool m_triangles_valid = false; + std::unique_ptr m_tms; +}; + + + +} // namespace GUI +} // namespace Slic3r + + +#endif // slic3r_MeshUtils_hpp_