diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 04ad8a4601..f15bc806bf 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -479,76 +479,28 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous GLSelectionRectangle::EState rectangle_status = m_selection_rectangle.get_state(); // First collect positions of all the points in world coordinates. - const Transform3d& instance_matrix = m_model_object->instances[m_active_instance]->get_transformation().get_matrix(); + Geometry::Transformation trafo = m_model_object->instances[m_active_instance]->get_transformation(); + trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_z_shift)); std::vector points; - for (unsigned int i=0; i()); - points.back()(2) += m_z_shift; - } + for (unsigned int i=0; i()); + // Now ask the rectangle which of the points are inside. - const Camera& camera = m_parent.get_camera(); - std::vector selected_idxs = m_selection_rectangle.stop_dragging(m_parent, points); + std::vector points_inside; + std::vector points_idxs = m_selection_rectangle.stop_dragging(m_parent, points); + for (size_t idx : points_idxs) + points_inside.push_back((trafo.get_matrix() * points[idx]).cast()); - // we'll recover current look direction (in world coords) and transform it to model coords. - const Selection& selection = m_parent.get_selection(); - const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); - const Transform3d& instance_matrix_no_translation_no_scaling = volume->get_instance_transformation().get_matrix(true,false,true); - Vec3f direction_to_camera = -camera.get_dir_forward().cast(); - Vec3f direction_to_camera_mesh = (instance_matrix_no_translation_no_scaling.inverse().cast() * direction_to_camera).normalized().eval(); - Vec3f scaling = volume->get_instance_scaling_factor().cast(); - direction_to_camera_mesh = Vec3f(direction_to_camera_mesh(0)*scaling(0), direction_to_camera_mesh(1)*scaling(1), direction_to_camera_mesh(2)*scaling(2)); - - // Iterate over all points in the rectangle and check that they are neither clipped by the - // clipping plane nor obscured by the mesh. - for (const unsigned int i : selected_idxs) { - const sla::SupportPoint &support_point = m_editing_cache[i].support_point; + // Only select/deselect points that are actually visible + for (size_t idx : m_mesh_raycaster->get_unobscured_idxs(trafo, m_parent.get_camera(), points_inside, + [this](const Vec3f& pt) { return is_point_clipped(pt.cast()); })) + { + const sla::SupportPoint &support_point = m_editing_cache[points_idxs[idx]].support_point; if (! is_point_clipped(support_point.pos.cast())) { - bool is_obscured = false; - // Cast a ray in the direction of the camera and look for intersection with the mesh: - std::vector hits; - // Offset the start of the ray to the front of the ball + EPSILON to account for numerical inaccuracies. - if (m_AABB.intersect_ray( - MapMatrixXfUnaligned(m_its->vertices.front().data(), m_its->vertices.size(), 3), - MapMatrixXiUnaligned(m_its->indices.front().data(), m_its->indices.size(), 3), - support_point.pos + direction_to_camera_mesh * (support_point.head_front_radius + EPSILON), direction_to_camera_mesh, hits)) { - std::sort(hits.begin(), hits.end(), [](const igl::Hit& h1, const igl::Hit& h2) { return h1.t < h2.t; }); - - if (m_clipping_plane_distance != 0.f) { - // If the closest hit facet normal points in the same direction as the ray, - // we are looking through the mesh and should therefore discard the point: - int fid = hits.front().id; // facet id - Vec3f a = (m_its->vertices[m_its->indices[fid](1)] - m_its->vertices[m_its->indices[fid](0)]); - Vec3f b = (m_its->vertices[m_its->indices[fid](2)] - m_its->vertices[m_its->indices[fid](0)]); - if ((a.cross(b)).dot(direction_to_camera_mesh) > 0.f) - is_obscured = true; - - // Eradicate all hits that are on clipped surfaces: - for (unsigned int j=0; jvertices[m_its->indices[fid](0)] + bc(1) * m_its->vertices[m_its->indices[fid](1)] + bc(2)*m_its->vertices[m_its->indices[fid](2)]; - if (is_point_clipped(hit_pos.cast())) { - hits.erase(hits.begin()+j); - --j; - } - } - } - - // FIXME: the intersection could in theory be behind the camera, but as of now we only have camera direction. - // Also, the threshold is in mesh coordinates, not in actual dimensions. - if (!hits.empty()) - is_obscured = true; - } - - if (!is_obscured) { - if (rectangle_status == GLSelectionRectangle::Deselect) - unselect_point(i); - else - select_point(i); - } + if (rectangle_status == GLSelectionRectangle::Deselect) + unselect_point(points_idxs[idx]); + else + select_point(points_idxs[idx]); } } return true; diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index 26697acc57..2c00890538 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -196,11 +196,52 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& } -std::vector MeshRaycaster::get_unobscured_idxs(const Transform3d& trafo, const Camera& camera, const std::vector& points) const +std::vector MeshRaycaster::get_unobscured_idxs(const Geometry::Transformation& trafo, const Camera& camera, const std::vector& points, + std::function fn_ignore_hit) const { + std::vector out; + const Transform3d& instance_matrix_no_translation_no_scaling = trafo.get_matrix(true,false,true); + Vec3f direction_to_camera = -camera.get_dir_forward().cast(); + Vec3f direction_to_camera_mesh = (instance_matrix_no_translation_no_scaling.inverse().cast() * direction_to_camera).normalized().eval(); + Vec3f scaling = trafo.get_scaling_factor().cast(); + direction_to_camera_mesh = Vec3f(direction_to_camera_mesh(0)*scaling(0), direction_to_camera_mesh(1)*scaling(1), direction_to_camera_mesh(2)*scaling(2)); - return std::vector(); + for (size_t i=0; i hits; + // Offset the start of the ray to the front of the ball + EPSILON to account for numerical inaccuracies. + if (m_AABB_wrapper->m_AABB.intersect_ray( + AABBWrapper::MapMatrixXfUnaligned(m_mesh->its.vertices.front().data(), m_mesh->its.vertices.size(), 3), + AABBWrapper::MapMatrixXiUnaligned(m_mesh->its.indices.front().data(), m_mesh->its.indices.size(), 3), + pt + direction_to_camera_mesh * EPSILON, direction_to_camera_mesh, hits)) { + + std::sort(hits.begin(), hits.end(), [](const igl::Hit& h1, const igl::Hit& h2) { return h1.t < h2.t; }); + // If the closest hit facet normal points in the same direction as the ray, + // we are looking through the mesh and should therefore discard the point: + if (m_AABB_wrapper->get_hit_normal(hits.front()).dot(direction_to_camera_mesh) > 0.f) + is_obscured = true; + + // Eradicate all hits that the caller wants to ignore + for (unsigned j=0; jget_hit_pos(hit))) { + hits.erase(hits.begin()+j); + --j; + } + } + // FIXME: the intersection could in theory be behind the camera, but as of now we only have camera direction. + // Also, the threshold is in mesh coordinates, not in actual dimensions. + if (! hits.empty()) + is_obscured = true; + } + if (! is_obscured) + out.push_back(i); + } + + return out; } diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp index 5c11053abb..2573b4b894 100644 --- a/src/slic3r/GUI/MeshUtils.hpp +++ b/src/slic3r/GUI/MeshUtils.hpp @@ -100,8 +100,8 @@ public: bool unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, std::vector* positions = nullptr, std::vector* normals = nullptr) const; - std::vector get_unobscured_idxs(const Transform3d& trafo, const Camera& camera, - const std::vector& points) const; + std::vector get_unobscured_idxs(const Geometry::Transformation& trafo, const Camera& camera, + const std::vector& points, std::function fn_ignore_hit) const; private: // PIMPL wrapper around igl::AABB so I don't have to include the header-only IGL here