Getting around signed_distance in pinhead_mesh_intersect

This commit is contained in:
tamasmeszaros 2019-01-30 17:35:39 +01:00
parent 4e82e32a27
commit 3f10b2f7f8
3 changed files with 72 additions and 18 deletions

View File

@ -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 ||

View File

@ -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<double>::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;

View File

@ -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<float>::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 {