diff --git a/src/libslic3r/SLA/SLASupportTree.cpp b/src/libslic3r/SLA/SLASupportTree.cpp index e753a947a..4640037bb 100644 --- a/src/libslic3r/SLA/SLASupportTree.cpp +++ b/src/libslic3r/SLA/SLASupportTree.cpp @@ -565,7 +565,7 @@ inline double ray_mesh_intersect(const Vec3d& s, const Vec3d& dir, const EigenMesh3D& m) { - return m.query_ray_hit(s, dir); + return m.query_ray_hit(s, dir).distance(); } // This function will test if a future pinhead would not collide with the model @@ -588,7 +588,7 @@ double pinhead_mesh_intersect(const Vec3d& s, double r_back, double width, const EigenMesh3D& m, - unsigned samples = 4, + unsigned samples = 8, double safety_distance = 0.001) { // method based on: @@ -643,15 +643,26 @@ double pinhead_mesh_intersect(const Vec3d& s, // Point ps is not on mesh but can be inside or outside as well. This // would cause many problems with ray-casting. So we query the closest // point on the mesh to this. - auto psq = m.signed_distance(ps); +// auto psq = m.signed_distance(ps); // This is the point on the circle on the back sphere Vec3d p(c(X) + rpbcos * a(X) + rpbsin * b(X), c(Y) + rpbcos * a(Y) + rpbsin * b(Y), c(Z) + rpbcos * a(Z) + rpbsin * b(Z)); - Vec3d n = (p - psq.point_on_mesh()).normalized(); - phi = m.query_ray_hit(psq.point_on_mesh() + sd*n, n); +// Vec3d n = (p - psq.point_on_mesh()).normalized(); +// phi = m.query_ray_hit(psq.point_on_mesh() + sd*n, n); + + Vec3d n = (p - ps).normalized(); + auto hr = m.query_ray_hit(ps + sd*n, n); + + if(hr.is_inside()) { // the hit is inside the model + if(hr.distance() > 2*r_pin) phi = 0; + else { + auto hr2 = m.query_ray_hit(ps + (hr.distance() + 2*sd)*n, n); + phi = hr2.distance(); + } + } else phi = hr.distance(); }); auto mit = std::min_element(phis.begin(), phis.end()); @@ -659,10 +670,14 @@ double pinhead_mesh_intersect(const Vec3d& s, return *mit; } +// Checking bridge (pillar and stick as well) intersection with the model. If +// the function is used for headless sticks, the ins_check parameter have to be +// true as the beginning of the stick might be inside the model geometry. double bridge_mesh_intersect(const Vec3d& s, const Vec3d& dir, double r, const EigenMesh3D& m, + bool ins_check = false, unsigned samples = 4, double safety_distance = 0.001) { @@ -678,7 +693,7 @@ double bridge_mesh_intersect(const Vec3d& s, for(size_t i = 0; i < phis.size(); ++i) phis[i] = i*2*PI/phis.size(); tbb::parallel_for(size_t(0), phis.size(), - [&phis, &m, a, b, sd, dir, r, s](size_t i) + [&phis, &m, a, b, sd, dir, r, s, ins_check](size_t i) { double& phi = phis[i]; double sinphi = std::sin(phi); @@ -693,11 +708,13 @@ double bridge_mesh_intersect(const Vec3d& s, s(Y) + rcos * a(Y) + rsin * b(Y), s(Z) + rcos * a(Z) + rsin * b(Z)); - auto result = m.signed_distance(p); + Vec3d sp; + if(ins_check) { + auto result = m.signed_distance(p); + sp = result.value() < 0 ? result.point_on_mesh() : p; + } else sp = p; - Vec3d sp = result.value() < 0 ? result.point_on_mesh() : p; - - phi = m.query_ray_hit(sp + sd*dir, dir); + phi = m.query_ray_hit(sp + sd*dir, dir).distance(); }); auto mit = std::min_element(phis.begin(), phis.end()); @@ -1538,12 +1555,12 @@ bool SLASupportTree::generate(const PointSet &points, // is distributed more effectively on the pillar. auto search_nearest = - [&cfg, &result, &emesh, maxbridgelen, gndlvl, pradius] + [&tifcl, &cfg, &result, &emesh, maxbridgelen, gndlvl, pradius] (SpatIndex& spindex, const Vec3d& jsh) { long nearest_id = -1; const double max_len = maxbridgelen / 2; - while(nearest_id < 0 && !spindex.empty()) { + while(nearest_id < 0 && !spindex.empty()) { tifcl(); // loop until a suitable head is not found // if there is a pillar closer than the cluster center // (this may happen as the clustering is not perfect) @@ -1660,7 +1677,7 @@ bool SLASupportTree::generate(const PointSet &points, if(!ring.empty()) { // inner ring is now in 'newring' and outer ring is in 'ring' SpatIndex innerring; - for(unsigned i : newring) { + for(unsigned i : newring) { tifcl(); const Pillar& pill = result.head_pillar(gndidx[i]); assert(pill.id >= 0); innerring.insert(pill.endpoint, unsigned(pill.id)); @@ -1669,7 +1686,7 @@ bool SLASupportTree::generate(const PointSet &points, // For all pillars in the outer ring find the closest in the // inner ring and connect them. This will create the spider web // fashioned connections between pillars - for(unsigned i : ring) { + for(unsigned i : ring) { tifcl(); const Pillar& outerpill = result.head_pillar(gndidx[i]); auto res = innerring.nearest(outerpill.endpoint, 1); if(res.empty()) continue; @@ -1695,6 +1712,7 @@ bool SLASupportTree::generate(const PointSet &points, next != ring.end(); ++it, ++next) { + tifcl(); const Pillar& pillar = result.head_pillar(gndidx[*it]); const Pillar& nextpillar = result.head_pillar(gndidx[*next]); interconnect(pillar, nextpillar, emesh, result); @@ -1802,7 +1820,7 @@ bool SLASupportTree::generate(const PointSet &points, Vec3d sj = sp + R * n; // stick start point // This is only for checking - double idist = bridge_mesh_intersect(sph, dir, R, emesh); + double idist = bridge_mesh_intersect(sph, dir, R, emesh, true); double dist = ray_mesh_intersect(sj, dir, emesh); if(std::isinf(idist) || std::isnan(idist) || idist < 2*R || diff --git a/src/libslic3r/SLA/SLASupportTree.hpp b/src/libslic3r/SLA/SLASupportTree.hpp index d6e128da0..b1e77b056 100644 --- a/src/libslic3r/SLA/SLASupportTree.hpp +++ b/src/libslic3r/SLA/SLASupportTree.hpp @@ -125,8 +125,38 @@ public: inline const Eigen::MatrixXd& V() const { return m_V; } inline const Eigen::MatrixXi& F() const { return m_F; } + // Result of a raycast + class hit_result { + double m_t = std::numeric_limits::infinity(); + int m_face_id = -1; + const EigenMesh3D& m_mesh; + Vec3d m_dir; + inline hit_result(const EigenMesh3D& em): m_mesh(em) {} + friend class EigenMesh3D; + public: + + inline double distance() const { return m_t; } + + inline int face() const { return m_face_id; } + + inline Vec3d normal() const { + if(m_face_id < 0) return {}; + auto trindex = m_mesh.m_F.row(m_face_id); + const Vec3d& p1 = m_mesh.V().row(trindex(0)); + const Vec3d& p2 = m_mesh.V().row(trindex(1)); + const Vec3d& p3 = m_mesh.V().row(trindex(2)); + Eigen::Vector3d U = p2 - p1; + Eigen::Vector3d V = p3 - p1; + return U.cross(V).normalized(); + } + + inline bool is_inside() { + return m_face_id >= 0 && normal().dot(m_dir) > 0; + } + }; + // Casting a ray on the mesh, returns the distance where the hit occures. - double query_ray_hit(const Vec3d &s, const Vec3d &dir) const; + hit_result query_ray_hit(const Vec3d &s, const Vec3d &dir) const; class si_result { double m_value; diff --git a/src/libslic3r/SLA/SLASupportTreeIGL.cpp b/src/libslic3r/SLA/SLASupportTreeIGL.cpp index b41c56acc..d3af1eac8 100644 --- a/src/libslic3r/SLA/SLASupportTreeIGL.cpp +++ b/src/libslic3r/SLA/SLASupportTreeIGL.cpp @@ -153,13 +153,19 @@ EigenMesh3D &EigenMesh3D::operator=(const EigenMesh3D &other) m_aabb.reset(new AABBImpl(*other.m_aabb)); return *this; } -double EigenMesh3D::query_ray_hit(const Vec3d &s, const Vec3d &dir) const +EigenMesh3D::hit_result +EigenMesh3D::query_ray_hit(const Vec3d &s, const Vec3d &dir) const { igl::Hit hit; hit.t = std::numeric_limits::infinity(); m_aabb->intersect_ray(m_V, m_F, s, dir, hit); - return double(hit.t); + hit_result ret(*this); + ret.m_t = double(hit.t); + ret.m_dir = dir; + if(!std::isinf(hit.t) && !std::isnan(hit.t)) ret.m_face_id = hit.id; + + return ret; } EigenMesh3D::si_result EigenMesh3D::signed_distance(const Vec3d &p) const {