Fixing many errors caused by the new changes.

This commit is contained in:
tamasmeszaros 2019-03-01 17:45:29 +01:00
parent 450f817c09
commit 878ac7f1b0
3 changed files with 65 additions and 45 deletions

View file

@ -72,30 +72,36 @@ public:
class hit_result {
double m_t = std::nan("");
int m_face_id = -1;
std::reference_wrapper<const EigenMesh3D> m_mesh;
const EigenMesh3D *m_mesh = nullptr;
Vec3d m_dir;
Vec3d m_source;
friend class EigenMesh3D;
public:
// A valid object of this class can only be obtained from
// EigenMesh3D::query_ray_hit method.
explicit inline hit_result(const EigenMesh3D& em): m_mesh(em) {}
explicit inline hit_result(const EigenMesh3D& em): m_mesh(&em) {}
public:
// This can create a placeholder object which is invalid (not created
// by a query_ray_hit call) but the distance can be preset to
// a specific value for distinguishing the placeholder.
inline hit_result(double val = std::nan("")): m_t(val) {}
inline double distance() const { return m_t; }
inline const Vec3d& direction() const { return m_dir; }
inline Vec3d position() const { return m_source + m_dir * m_t; }
inline int face() const { return m_face_id; }
inline bool is_valid() const { return m_mesh != nullptr; }
// Hit_result can decay into a double as the hit distance.
inline operator double() const { return distance(); }
inline Vec3d normal() const {
if(m_face_id < 0) return {};
auto trindex = m_mesh.get().m_F.row(m_face_id);
const Vec3d& p1 = m_mesh.get().V().row(trindex(0));
const Vec3d& p2 = m_mesh.get().V().row(trindex(1));
const Vec3d& p3 = m_mesh.get().V().row(trindex(2));
if(m_face_id < 0 || !is_valid()) 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();

View file

@ -1011,20 +1011,20 @@ class SLASupportTree::Algorithm {
// surface. dir: This is the direction of the head from the pin to the back
// r_pin, r_back: the radiuses of the pin and the back sphere width: This
// is the full width from the pin center to the back center m: The object
// mesh
//
// Optional:
// samples: how many rays will be shot
// safety distance: This will be added to the radiuses to have a safety
// distance from the mesh.
// mesh.
// The return value is the hit result from the ray casting. If the starting
// point was inside the model, an "invalid" hit_result will be returned
// with a zero distance value instead of a NAN. This way the result can
// be used safely for comparison with other distances.
EigenMesh3D::hit_result pinhead_mesh_intersect(
const Vec3d& s,
const Vec3d& dir,
double r_pin,
double r_back,
double width,
unsigned samples = 8)
double width)
{
static const size_t SAMPLES = 8;
// method based on:
// https://math.stackexchange.com/questions/73237/parametric-equation-of-a-circle-in-3d-space
@ -1045,14 +1045,14 @@ class SLASupportTree::Algorithm {
// The portions of the circle (the head-back circle) for which we will
// shoot rays.
std::vector<double> phis(samples);
std::array<double, SAMPLES> phis;
for(size_t i = 0; i < phis.size(); ++i) phis[i] = i*2*PI/phis.size();
auto& m = m_mesh;
using HitResult = EigenMesh3D::hit_result;
// Hit results
std::vector<HitResult> hits(samples, HitResult(m));
std::array<HitResult, SAMPLES> hits;
// We have to address the case when the direction vector v (same as
// dir) is coincident with one of the world axes. In this case two of
@ -1109,21 +1109,27 @@ class SLASupportTree::Algorithm {
auto q = m.query_ray_hit(ps + sd*n, n);
if(q.is_inside()) { // the hit is inside the model
if(q.distance() > 2*r_pin) phi = 0;
if(q.distance() > 2*r_pin) {
// If we are inside the model and the hit distance is bigger
// than our pin circle diameter, it probably indicates that
// the support point was already inside the model, or there
// is really no space around the point. We will assign a
// zero hit distance to these cases which will enforce the
// function return value to be an invalid ray with zero hit
// distance. (see min_element at the end)
hits[i] = HitResult(0.0);
}
else {
// re-cast the ray from the outside of the object
// re-cast the ray from the outside of the object.
// The starting point has an offset of 2*safety_distance
// because the original ray has also had an offset
auto q2 = m.query_ray_hit(ps + (q.distance() + 2*sd)*n, n);
hits[i] = q2;
}
} else hits[i] = q;
});
auto mit = std::min_element(hits.begin(), hits.end(),
[](const HitResult& hr1,
const HitResult& hr2)
{
return hr1.distance() < hr2.distance();
});
auto mit = std::min_element(hits.begin(), hits.end());
return *mit;
}
@ -1132,13 +1138,18 @@ class SLASupportTree::Algorithm {
// 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.
// The return value is the hit result from the ray casting. If the starting
// point was inside the model, an "invalid" hit_result will be returned
// with a zero distance value instead of a NAN. This way the result can
// be used safely for comparison with other distances.
EigenMesh3D::hit_result bridge_mesh_intersect(
const Vec3d& s,
const Vec3d& dir,
double r,
bool ins_check = false,
unsigned samples = 4)
bool ins_check = false)
{
static const size_t SAMPLES = 8;
// helper vector calculations
Vec3d a(0, 1, 0), b;
const double& sd = m_cfg.safety_distance_mm;
@ -1160,14 +1171,14 @@ class SLASupportTree::Algorithm {
}
// circle portions
std::vector<double> phis(samples);
std::array<double, SAMPLES> phis;
for(size_t i = 0; i < phis.size(); ++i) phis[i] = i*2*PI/phis.size();
auto& m = m_mesh;
using HitResult = EigenMesh3D::hit_result;
// Hit results
std::vector<HitResult> hits(samples, HitResult(m));
std::array<HitResult, SAMPLES> hits;
tbb::parallel_for(size_t(0), phis.size(),
[&m, &phis, a, b, sd, dir, r, s, ins_check, &hits]
@ -1189,7 +1200,7 @@ class SLASupportTree::Algorithm {
auto hr = m.query_ray_hit(p + sd*dir, dir);
if(ins_check && hr.is_inside()) {
if(hr.distance() > 2*r) phi = 0;
if(hr.distance() > 2*r) hits[i] = HitResult(0.0);
else {
// re-cast the ray from the outside of the object
auto hr2 =
@ -1200,12 +1211,7 @@ class SLASupportTree::Algorithm {
} else hits[i] = hr;
});
auto mit = std::min_element(hits.begin(), hits.end(),
[](const HitResult& hr1,
const HitResult& hr2)
{
return hr1.distance() < hr2.distance();
});
auto mit = std::min_element(hits.begin(), hits.end());
return *mit;
}
@ -1442,7 +1448,7 @@ public:
polar = std::max(polar, 3*PI / 4);
// save the head (pinpoint) position
Vec3d hp = m_points.row(i);
Vec3d hp = m_points.row(fidx);
double w = m_cfg.head_width_mm +
m_cfg.head_back_radius_mm +
@ -1492,12 +1498,14 @@ public:
bound(-PI, PI) // azimuth can be a full search
);
t = oresult.score;
if(oresult.score > w) {
polar = std::get<0>(oresult.optimum);
azimuth = std::get<1>(oresult.optimum);
nn = Vec3d(std::cos(azimuth) * std::sin(polar),
std::sin(azimuth) * std::sin(polar),
std::cos(polar)).normalized();
t = oresult.score;
}
}
// save the verified and corrected normal
@ -1829,6 +1837,8 @@ public:
double d = 0, tdown = 0;
Vec3d dirdown(0.0, 0.0, -1.0);
t = std::min(t, m_cfg.max_bridge_length_mm);
while(d < t && !std::isinf(tdown = bridge_mesh_intersect(
hjp + d*head.dir,
dirdown, head.r_back_mm))) {
@ -1881,12 +1891,16 @@ public:
);
d = 0; t = oresult.score;
polar = std::get<0>(oresult.optimum);
azimuth = std::get<1>(oresult.optimum);
Vec3d bridgedir = Vec3d(std::cos(azimuth) * std::sin(polar),
std::sin(azimuth) * std::sin(polar),
std::cos(polar)).normalized();
t = std::min(t, m_cfg.max_bridge_length_mm);
while(d < t && !std::isinf(tdown = bridge_mesh_intersect(
hjp + d*bridgedir,
dirdown,

View file

@ -82,7 +82,7 @@ struct SupportConfig {
double normal_cutoff_angle = 150.0 * M_PI / 180.0;
// The shortest distance of any support structure from the model surface
double safety_distance_mm = 0.001;
double safety_distance_mm = 0.1;
};
struct PoolConfig;