diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index cbdadc4759..909907a88f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -290,21 +290,17 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) cons // Matrices set, we can render the point mark now. Eigen::Quaterniond q; - q.setFromTwoVectors(Vec3d{0., 0., 1.}, instance_scaling_matrix_inverse * drain_hole.m_normal.cast()); + q.setFromTwoVectors(Vec3d{0., 0., 1.}, instance_scaling_matrix_inverse * (-drain_hole.m_normal).cast()); Eigen::AngleAxisd aa(q); glsafe(::glRotated(aa.angle() * (180. / M_PI), aa.axis()(0), aa.axis()(1), aa.axis()(2))); - - const double cylinder_radius = double(drain_hole.m_radius) * RenderPointScale; //0.25; // mm - const double stick_out_length = 1.; - const double cone_height = m_new_hole_height + stick_out_length; glsafe(::glPushMatrix()); - glsafe(::glTranslated(0., 0., -cone_height+stick_out_length)); - ::gluCylinder(m_quadric, cylinder_radius, cylinder_radius, cone_height, 24, 1); - glsafe(::glTranslated(0., 0., cone_height)); - ::gluDisk(m_quadric, 0.0, cylinder_radius, 24, 1); - glsafe(::glTranslated(0., 0., -cone_height)); + glsafe(::glTranslated(0., 0., -drain_hole.m_height)); + ::gluCylinder(m_quadric, drain_hole.m_radius, drain_hole.m_radius, drain_hole.m_height, 24, 1); + glsafe(::glTranslated(0., 0., drain_hole.m_height)); + ::gluDisk(m_quadric, 0.0, drain_hole.m_radius, 24, 1); + glsafe(::glTranslated(0., 0., -drain_hole.m_height)); glsafe(::glRotatef(180.f, 1.f, 0.f, 0.f)); - ::gluDisk(m_quadric, 0.0, cylinder_radius, 24, 1); + ::gluDisk(m_quadric, 0.0, drain_hole.m_radius, 24, 1); glsafe(::glPopMatrix()); if (vol->is_left_handed()) @@ -434,7 +430,8 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos std::pair pos_and_normal; if (unproject_on_mesh(mouse_position, pos_and_normal)) { // we got an intersection Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Add drainage hole"))); - m_model_object->sla_drain_holes.emplace_back(pos_and_normal.first, pos_and_normal.second, m_new_hole_radius, m_new_hole_height); + m_model_object->sla_drain_holes.emplace_back(pos_and_normal.first + HoleStickOutLength * pos_and_normal.second, + -pos_and_normal.second, m_new_hole_radius, m_new_hole_height+HoleStickOutLength); m_selected.push_back(false); assert(m_selected.size == m_model_object->sla_drain_holes.size()); m_parent.set_as_dirty(); @@ -561,8 +558,8 @@ void GLGizmoHollow::on_update(const UpdateData& data) std::pair pos_and_normal; if (! unproject_on_mesh(data.mouse_pos.cast(), pos_and_normal)) return; - m_model_object->sla_drain_holes[m_hover_id].m_pos = pos_and_normal.first; - m_model_object->sla_drain_holes[m_hover_id].m_normal = pos_and_normal.second; + m_model_object->sla_drain_holes[m_hover_id].m_pos = pos_and_normal.first + HoleStickOutLength * pos_and_normal.second; + m_model_object->sla_drain_holes[m_hover_id].m_normal = -pos_and_normal.second; } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp index 290a793407..428a978c48 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp @@ -28,7 +28,7 @@ private: mutable double m_z_shift = 0.; bool unproject_on_mesh(const Vec2d& mouse_pos, std::pair& pos_and_normal); - const float RenderPointScale = 1.f; + const float HoleStickOutLength = 1.f; GLUquadricObj* m_quadric; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 000ddf8c95..a7ad02cd8d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -327,6 +327,43 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) glsafe(::glMaterialfv(GL_FRONT, GL_EMISSION, render_color_emissive)); } + // Now render the drain holes: + render_color[0] = 0.7f; + render_color[1] = 0.7f; + render_color[2] = 0.7f; + render_color[3] = 0.7f; + glsafe(::glColor4fv(render_color)); + for (const sla::DrainHole& drain_hole : m_model_object->sla_drain_holes) { + // Inverse matrix of the instance scaling is applied so that the mark does not scale with the object. + glsafe(::glPushMatrix()); + glsafe(::glTranslatef(drain_hole.m_pos(0), drain_hole.m_pos(1), drain_hole.m_pos(2))); + glsafe(::glMultMatrixd(instance_scaling_matrix_inverse.data())); + + if (vol->is_left_handed()) + glFrontFace(GL_CW); + + // Matrices set, we can render the point mark now. + + Eigen::Quaterniond q; + q.setFromTwoVectors(Vec3d{0., 0., 1.}, instance_scaling_matrix_inverse * (-drain_hole.m_normal).cast()); + Eigen::AngleAxisd aa(q); + glsafe(::glRotated(aa.angle() * (180. / M_PI), aa.axis()(0), aa.axis()(1), aa.axis()(2))); + glsafe(::glPushMatrix()); + glsafe(::glTranslated(0., 0., -drain_hole.m_height)); + ::gluCylinder(m_quadric, drain_hole.m_radius, drain_hole.m_radius, drain_hole.m_height, 24, 1); + glsafe(::glTranslated(0., 0., drain_hole.m_height)); + ::gluDisk(m_quadric, 0.0, drain_hole.m_radius, 24, 1); + glsafe(::glTranslated(0., 0., -drain_hole.m_height)); + glsafe(::glRotatef(180.f, 1.f, 0.f, 0.f)); + ::gluDisk(m_quadric, 0.0, drain_hole.m_radius, 24, 1); + glsafe(::glPopMatrix()); + + if (vol->is_left_handed()) + glFrontFace(GL_CCW); + glsafe(::glPopMatrix()); + + } + if (!picking) glsafe(::glDisable(GL_LIGHTING)); @@ -375,6 +412,24 @@ void GLGizmoSlaSupports::update_mesh() } +bool GLGizmoSlaSupports::is_point_in_hole(const Vec3f& pt) const +{ + auto squared_distance_from_line = [](const Vec3f pt, const Vec3f& line_pt, const Vec3f& dir) -> float { + Vec3f diff = line_pt - pt; + return (diff - diff.dot(dir) * dir).squaredNorm(); + }; + + + for (const sla::DrainHole& hole : m_model_object->sla_drain_holes) { + if ( hole.m_normal.dot(pt-hole.m_pos) < EPSILON + || hole.m_normal.dot(pt-(hole.m_pos+hole.m_height * hole.m_normal)) > 0.f) + continue; + if ( squared_distance_from_line(pt, hole.m_pos, hole.m_normal) < pow(hole.m_radius, 2.f)) + return true; + } + + return false; +} // Unprojects the mouse position on the mesh and saves hit point and normal of the facet into pos_and_normal // Return false if no intersection was found, true otherwise. @@ -393,7 +448,8 @@ bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pairunproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, hit, normal, m_clipping_plane.get())) { + if (m_mesh_raycaster->unproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, hit, normal, m_clipping_plane.get()) + && ! is_point_in_hole(hit)) { // Return both the point and the facet normal. pos_and_normal = std::make_pair(hit, normal); return true; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index 85835f9d0e..e536aab40f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -126,6 +126,7 @@ private: std::vector get_config_options(const std::vector& keys) const; bool is_mesh_point_clipped(const Vec3d& point) const; + bool is_point_in_hole(const Vec3f& pt) const; //void find_intersecting_facets(const igl::AABB* aabb, const Vec3f& normal, double offset, std::vector& out) const; // Methods that do the model_object and editing cache synchronization,