diff --git a/src/libslic3r/SLA/SLACommon.hpp b/src/libslic3r/SLA/SLACommon.hpp index 6e56b6de7..0a3ee311b 100644 --- a/src/libslic3r/SLA/SLACommon.hpp +++ b/src/libslic3r/SLA/SLACommon.hpp @@ -189,6 +189,9 @@ public: // Casting a ray on the mesh, returns the distance where the hit occures. hit_result query_ray_hit(const Vec3d &s, const Vec3d &dir) const; + // Casts a ray on the mesh and returns all hits + std::vector query_ray_hits(const Vec3d &s, const Vec3d &dir) const; + class si_result { double m_value; int m_fidx; diff --git a/src/libslic3r/SLA/SLASupportTreeIGL.cpp b/src/libslic3r/SLA/SLASupportTreeIGL.cpp index 03d4a563c..ea2be6be1 100644 --- a/src/libslic3r/SLA/SLASupportTreeIGL.cpp +++ b/src/libslic3r/SLA/SLASupportTreeIGL.cpp @@ -272,6 +272,31 @@ EigenMesh3D::query_ray_hit(const Vec3d &s, const Vec3d &dir) const return ret; } +std::vector +EigenMesh3D::query_ray_hits(const Vec3d &s, const Vec3d &dir) const +{ + std::vector outs; + std::vector hits; + m_aabb->intersect_ray(m_V, m_F, s, dir, hits); + + // The sort is necessary, the hits are not always sorted. + std::sort(hits.begin(), hits.end(), + [](const igl::Hit& a, const igl::Hit& b) { return a.t < b.t; }); + + // Convert the igl::Hit into hit_result + outs.reserve(hits.size()); + for (const igl::Hit& hit : hits) { + outs.emplace_back(EigenMesh3D::hit_result(*this)); + outs.back().m_t = double(hit.t); + outs.back().m_dir = dir; + outs.back().m_source = s; + if(!std::isinf(hit.t) && !std::isnan(hit.t)) + outs.back().m_face_id = hit.id; + } + + return outs; +} + #ifdef SLIC3R_SLA_NEEDS_WINDTREE EigenMesh3D::si_result EigenMesh3D::signed_distance(const Vec3d &p) const { double sign = 0; double sqdst = 0; int i = 0; Vec3d c; diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index 62a6813a6..8b37161e9 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -5,10 +5,6 @@ #include "slic3r/GUI/Camera.hpp" -// There is an L function in igl that would be overridden by our localization macro. -#undef L -#include - #include @@ -99,59 +95,6 @@ void MeshClipper::recalculate_triangles() } -class MeshRaycaster::AABBWrapper { -public: - AABBWrapper(const TriangleMesh* mesh); - ~AABBWrapper() { m_AABB.deinit(); } - - typedef Eigen::Map> MapMatrixXfUnaligned; - typedef Eigen::Map> MapMatrixXiUnaligned; - igl::AABB m_AABB; - - Vec3f get_hit_pos(const igl::Hit& hit) const; - Vec3f get_hit_normal(const igl::Hit& hit) const; - -private: - const TriangleMesh* m_mesh; -}; - -MeshRaycaster::AABBWrapper::AABBWrapper(const TriangleMesh* mesh) - : m_mesh(mesh) -{ - m_AABB.init( - MapMatrixXfUnaligned(m_mesh->its.vertices.front().data(), m_mesh->its.vertices.size(), 3), - MapMatrixXiUnaligned(m_mesh->its.indices.front().data(), m_mesh->its.indices.size(), 3)); -} - - -MeshRaycaster::MeshRaycaster(const TriangleMesh& mesh) - : m_AABB_wrapper(new AABBWrapper(&mesh)), m_mesh(&mesh) -{ -} - -MeshRaycaster::~MeshRaycaster() -{ - delete m_AABB_wrapper; -} - -Vec3f MeshRaycaster::AABBWrapper::get_hit_pos(const igl::Hit& hit) const -{ - const stl_triangle_vertex_indices& indices = m_mesh->its.indices[hit.id]; - return Vec3f((1-hit.u-hit.v) * m_mesh->its.vertices[indices(0)] - + hit.u * m_mesh->its.vertices[indices(1)] - + hit.v * m_mesh->its.vertices[indices(2)]); -} - - -Vec3f MeshRaycaster::AABBWrapper::get_hit_normal(const igl::Hit& hit) const -{ - const stl_triangle_vertex_indices& indices = m_mesh->its.indices[hit.id]; - Vec3f a(m_mesh->its.vertices[indices(1)] - m_mesh->its.vertices[indices(0)]); - Vec3f b(m_mesh->its.vertices[indices(2)] - m_mesh->its.vertices[indices(0)]); - return Vec3f(a.cross(b)); -} - - bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, Vec3f& position, Vec3f& normal, const ClippingPlane* clipping_plane) const { @@ -164,27 +107,20 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& ::gluUnProject(mouse_pos(0), viewport[3] - mouse_pos(1), 0., model_mat.data(), proj_mat.data(), viewport.data(), &pt1(0), &pt1(1), &pt1(2)); ::gluUnProject(mouse_pos(0), viewport[3] - mouse_pos(1), 1., model_mat.data(), proj_mat.data(), viewport.data(), &pt2(0), &pt2(1), &pt2(2)); - std::vector hits; - Transform3d inv = trafo.inverse(); - pt1 = inv * pt1; pt2 = inv * pt2; - 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), - pt1.cast(), (pt2-pt1).cast(), hits)) + std::vector hits = m_emesh.query_ray_hits(pt1, pt2-pt1); + if (hits.empty()) return false; // no intersection found - std::sort(hits.begin(), hits.end(), [](const igl::Hit& a, const igl::Hit& b) { return a.t < b.t; }); - unsigned i = 0; // Remove points that are obscured or cut by the clipping plane if (clipping_plane) { for (i=0; iis_point_clipped(trafo * m_AABB_wrapper->get_hit_pos(hits[i]).cast())) + if (! clipping_plane->is_point_clipped(trafo * hits[i].position())) break; if (i==hits.size() || (hits.size()-i) % 2 != 0) { @@ -195,8 +131,8 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& } // Now stuff the points in the provided vector and calculate normals if asked about them: - position = m_AABB_wrapper->get_hit_pos(hits[i]); - normal = m_AABB_wrapper->get_hit_normal(hits[i]); + position = hits[i].position().cast(); + normal = hits[i].normal().cast(); return true; } @@ -220,24 +156,21 @@ std::vector MeshRaycaster::get_unobscured_idxs(const Geometry::Transfo bool is_obscured = false; // Cast a ray in the direction of the camera and look for intersection with the mesh: - std::vector hits; + std::vector hits; // Offset the start of the ray by 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), - inverse_trafo * pt + direction_to_camera_mesh * EPSILON, direction_to_camera_mesh, hits)) { + hits = m_emesh.query_ray_hits((inverse_trafo * pt + direction_to_camera_mesh * EPSILON).cast(), + direction_to_camera.cast()); - std::sort(hits.begin(), hits.end(), [](const igl::Hit& h1, const igl::Hit& h2) { return h1.t < h2.t; }); + if (! hits.empty()) { // 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) + if (hits.front().normal().dot(direction_to_camera_mesh.cast()) > 0) is_obscured = true; // Eradicate all hits that the caller wants to ignore for (unsigned j=0; jis_point_clipped(trafo.get_matrix() * m_AABB_wrapper->get_hit_pos(hit).cast())) { + if (clipping_plane && clipping_plane->is_point_clipped(trafo.get_matrix() * hits[j].position())) { hits.erase(hits.begin()+j); --j; } @@ -258,17 +191,15 @@ std::vector MeshRaycaster::get_unobscured_idxs(const Geometry::Transfo Vec3f MeshRaycaster::get_closest_point(const Vec3f& point, Vec3f* normal) const { int idx = 0; - Eigen::Matrix closest_point; - m_AABB_wrapper->m_AABB.squared_distance( - 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), - point, idx, closest_point); + Vec3d closest_point; + m_emesh.squared_distance(point.cast(), idx, closest_point); if (normal) { - igl::Hit imag_hit; - imag_hit.id = idx; - *normal = m_AABB_wrapper->get_hit_normal(imag_hit); + const stl_triangle_vertex_indices& indices = m_mesh->its.indices[idx]; + Vec3f a(m_mesh->its.vertices[indices(1)] - m_mesh->its.vertices[indices(0)]); + Vec3f b(m_mesh->its.vertices[indices(2)] - m_mesh->its.vertices[indices(0)]); + *normal = Vec3f(a.cross(b)); } - return closest_point; + return closest_point.cast(); } diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp index e4c4c20d2..8dae2a2f0 100644 --- a/src/slic3r/GUI/MeshUtils.hpp +++ b/src/slic3r/GUI/MeshUtils.hpp @@ -3,6 +3,7 @@ #include "libslic3r/Point.hpp" #include "libslic3r/Geometry.hpp" +#include "libslic3r/SLA/SLACommon.hpp" #include @@ -93,8 +94,9 @@ private: class MeshRaycaster { public: - MeshRaycaster(const TriangleMesh& mesh); - ~MeshRaycaster(); + MeshRaycaster(const TriangleMesh& mesh) + : m_mesh(&mesh), m_emesh(mesh) + {} void set_transformation(const Geometry::Transformation& trafo); void set_camera(const Camera& camera); @@ -107,9 +109,7 @@ public: Vec3f get_closest_point(const Vec3f& point, Vec3f* normal = nullptr) const; private: - // PIMPL wrapper around igl::AABB so I don't have to include the header-only IGL here - class AABBWrapper; - AABBWrapper* m_AABB_wrapper; + sla::EigenMesh3D m_emesh; const TriangleMesh* m_mesh = nullptr; };