diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index a0eef72fe..e9cdf1527 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -141,8 +141,9 @@ sub new { # callback to react to gizmo rotate my $on_gizmo_rotate = sub { - my ($angle_z) = @_; + my ($angle_z, $angle_y) = @_; $self->rotate(rad2deg($angle_z), Z, 'absolute'); + $self->rotate(rad2deg($angle_y), Y, 'absolute'); }; # callback to update object's geometry info while using gizmos diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index ab4095e6f..f1bbba934 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -1,5 +1,6 @@ #include "GLCanvas3D.hpp" +#include "../../admesh/stl.h" #include "../../libslic3r/libslic3r.h" #include "../../slic3r/GUI/3DScene.hpp" #include "../../slic3r/GUI/GLShader.hpp" @@ -1154,6 +1155,18 @@ bool GLCanvas3D::Gizmos::init() m_gizmos.insert(GizmosMap::value_type(Rotate, gizmo)); + gizmo = new GLGizmoFlatten; + if (gizmo == nullptr) + return false; + + if (!gizmo->init()) { + _reset(); + return false; + } + + m_gizmos.insert(GizmosMap::value_type(Flatten, gizmo)); + + return true; } @@ -1387,6 +1400,25 @@ void GLCanvas3D::Gizmos::set_angle_z(float angle_z) reinterpret_cast(it->second)->set_angle_z(angle_z); } +Pointf3 GLCanvas3D::Gizmos::get_flattening_normal() const +{ + if (!m_enabled) + return Pointf3(0.f, 0.f, 0.f); + + GizmosMap::const_iterator it = m_gizmos.find(Flatten); + return (it != m_gizmos.end()) ? reinterpret_cast(it->second)->get_flattening_normal() : Pointf3(0.f, 0.f, 0.f); +} + +void GLCanvas3D::Gizmos::set_flattening_data(std::vector vertices_list) +{ + if (!m_enabled) + return; + + GizmosMap::const_iterator it = m_gizmos.find(Flatten); + if (it != m_gizmos.end()) + reinterpret_cast(it->second)->set_flattening_data(vertices_list); +} + void GLCanvas3D::Gizmos::render(const GLCanvas3D& canvas, const BoundingBoxf3& box) const { if (!m_enabled) @@ -2170,6 +2202,27 @@ void GLCanvas3D::update_gizmos_data() { m_gizmos.set_scale(model_instance->scaling_factor); m_gizmos.set_angle_z(model_instance->rotation); + + ///////////////////////////////////////////////////////////////////////// + // Following block provides convex hull data to the Flatten gizmo + // It is temporary, it should be optimized and moved elsewhere later + TriangleMesh ch = model_object->mesh().convex_hull3d(); + stl_facet* facet_ptr = ch.stl.facet_start; + std::vector points; + while (facet_ptr < ch.stl.facet_start+ch.stl.stats.number_of_facets) { + Pointf3 a = Pointf3(facet_ptr->vertex[1].x - facet_ptr->vertex[0].x, facet_ptr->vertex[1].y - facet_ptr->vertex[0].y, facet_ptr->vertex[1].z - facet_ptr->vertex[0].z); + Pointf3 b = Pointf3(facet_ptr->vertex[2].x - facet_ptr->vertex[0].x, facet_ptr->vertex[2].y - facet_ptr->vertex[0].y, facet_ptr->vertex[2].z - facet_ptr->vertex[0].z); + + if (0.5 * sqrt(dot(cross(a, b), cross(a,b))) > 50.f) { + points.emplace_back(Pointf3s()); + for (unsigned int j=0; j<3; ++j) + points.back().emplace_back(Pointf3(facet_ptr->vertex[j].x, facet_ptr->vertex[j].y, facet_ptr->vertex[j].z)); + points.back().emplace_back(Pointf3(facet_ptr->normal.x, facet_ptr->normal.y, facet_ptr->normal.z)); + } + facet_ptr+=1; + } + m_gizmos.set_flattening_data(points); + //////////////////////////////////////////////////////////////////////// } } } @@ -2177,6 +2230,7 @@ void GLCanvas3D::update_gizmos_data() { m_gizmos.set_scale(1.0f); m_gizmos.set_angle_z(0.0f); + m_gizmos.set_flattening_data(std::vector()); } } @@ -2760,6 +2814,16 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_gizmos.start_dragging(); m_mouse.drag.gizmo_volume_idx = _get_first_selected_volume_id(selected_object_idx); m_dirty = true; + + if (m_gizmos.get_current_type() == Gizmos::Flatten) { + // Rotate the object so the normal points downward: + Pointf3 normal = m_gizmos.get_flattening_normal(); + if (normal.x != 0.f || normal.y != 0.f || normal.z != 0.f) { + float angle_z = -atan2(normal.y, normal.x); + float angle_y = M_PI - atan2(normal.x*cos(angle_z)-normal.y*sin(angle_z), normal.z); + m_on_gizmo_rotate_callback.call((double)angle_z, (double)angle_y); + } + } } else { @@ -3039,7 +3103,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) } case Gizmos::Rotate: { - m_on_gizmo_rotate_callback.call((double)m_gizmos.get_angle_z()); + m_on_gizmo_rotate_callback.call((double)m_gizmos.get_angle_z(), 0.); break; } default: diff --git a/xs/src/slic3r/GUI/GLCanvas3D.hpp b/xs/src/slic3r/GUI/GLCanvas3D.hpp index ae20882fc..09a7de823 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.hpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.hpp @@ -338,6 +338,7 @@ public: Undefined, Scale, Rotate, + Flatten, Num_Types }; @@ -382,6 +383,9 @@ public: float get_angle_z() const; void set_angle_z(float angle_z); + void set_flattening_data(std::vector vertices_list); + Pointf3 get_flattening_normal() const; + void render(const GLCanvas3D& canvas, const BoundingBoxf3& box) const; void render_current_gizmo_for_picking_pass(const BoundingBoxf3& box) const; diff --git a/xs/src/slic3r/GUI/GLGizmo.cpp b/xs/src/slic3r/GUI/GLGizmo.cpp index 47b01e8a2..5a0944758 100644 --- a/xs/src/slic3r/GUI/GLGizmo.cpp +++ b/xs/src/slic3r/GUI/GLGizmo.cpp @@ -110,7 +110,7 @@ int GLGizmoBase::get_hover_id() const void GLGizmoBase::set_hover_id(int id) { - if (id < (int)m_grabbers.size()) + //if (id < (int)m_grabbers.size()) m_hover_id = id; } @@ -502,5 +502,112 @@ void GLGizmoScale::on_render_for_picking(const BoundingBoxf3& box) const render_grabbers(); } + +GLGizmoFlatten::GLGizmoFlatten() + : GLGizmoBase(), + m_normal(Pointf3(0.f, 0.f, 0.f)) +{} + + +bool GLGizmoFlatten::on_init() +{ + std::string path = resources_dir() + "/icons/overlay/"; + + std::string filename = path + "scale_off.png"; + if (!m_textures[Off].load_from_file(filename, false)) + return false; + + filename = path + "scale_hover.png"; + if (!m_textures[Hover].load_from_file(filename, false)) + return false; + + filename = path + "scale_on.png"; + if (!m_textures[On].load_from_file(filename, false)) + return false; + + return true; +} + +void GLGizmoFlatten::on_start_dragging() +{ + if (m_hover_id != -1) + m_normal = m_planes[m_hover_id].normal; +} + +void GLGizmoFlatten::on_update(const Pointf& mouse_pos) +{ + /*Pointf center(0.5 * (m_grabbers[1].center.x + m_grabbers[0].center.x), 0.5 * (m_grabbers[3].center.y + m_grabbers[0].center.y)); + + coordf_t orig_len = length(m_starting_drag_position - center); + coordf_t new_len = length(mouse_pos - center); + coordf_t ratio = (orig_len != 0.0) ? new_len / orig_len : 1.0; + + m_scale = m_starting_scale * (float)ratio;*/ +} + +void GLGizmoFlatten::on_render(const BoundingBoxf3& box) const +{ + bool blending_was_enabled = ::glIsEnabled(GL_BLEND); + ::glEnable(GL_BLEND); + ::glDisable(GL_DEPTH_TEST); + + for (int i=0; i<(int)m_planes.size(); ++i) { + if (i == m_hover_id) + ::glColor4f(0.9f, 0.9f, 0.9f, 0.75f); + else + ::glColor4f(0.9f, 0.9f, 0.9f, 0.5f); + + ::glBegin(GL_POLYGON); + for (const auto& vertex : m_planes[i].vertices) + ::glVertex3f((GLfloat)vertex.x, (GLfloat)vertex.y, (GLfloat)vertex.z); + ::glEnd(); + } + + if (!blending_was_enabled) + ::glDisable(GL_BLEND); +} + +void GLGizmoFlatten::on_render_for_picking(const BoundingBoxf3& box) const +{ + static const GLfloat INV_255 = 1.0f / 255.0f; + + ::glDisable(GL_DEPTH_TEST); + + for (unsigned int i = 0; i < m_planes.size(); ++i) + { + ::glColor3f(1.f, 1.f, (254.0f - (float)i) * INV_255); + ::glBegin(GL_POLYGON); + for (const auto& vertex : m_planes[i].vertices) + ::glVertex3f((GLfloat)vertex.x, (GLfloat)vertex.y, (GLfloat)vertex.z); + ::glEnd(); + } +} + +void GLGizmoFlatten::set_flattening_data(std::vector vertices_list) +{ + // Each entry in vertices_list describe one polygon that can be laid flat. + // All points but the last one are vertices of the polygon, the last "point" is the outer normal vector. + + m_planes.clear(); + m_planes.reserve(vertices_list.size()); + + for (const auto& plane_data : vertices_list) { + m_planes.emplace_back(PlaneData()); + for (unsigned int i=0; i vertices; + Pointf3 normal; + float color[3]; + }; + + std::vector m_planes; + +public: + GLGizmoFlatten(); + + void set_flattening_data(std::vector vertices_list); + Pointf3 get_flattening_normal() const; + +protected: + virtual bool on_init(); + virtual void on_start_dragging(); + virtual void on_update(const Pointf& mouse_pos); + virtual void on_render(const BoundingBoxf3& box) const; + virtual void on_render_for_picking(const BoundingBoxf3& box) const; +}; + + + } // namespace GUI } // namespace Slic3r