Fixing many errors caused by the new changes.
This commit is contained in:
parent
450f817c09
commit
878ac7f1b0
3 changed files with 65 additions and 45 deletions
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue