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 {
|
class hit_result {
|
||||||
double m_t = std::nan("");
|
double m_t = std::nan("");
|
||||||
int m_face_id = -1;
|
int m_face_id = -1;
|
||||||
std::reference_wrapper<const EigenMesh3D> m_mesh;
|
const EigenMesh3D *m_mesh = nullptr;
|
||||||
Vec3d m_dir;
|
Vec3d m_dir;
|
||||||
Vec3d m_source;
|
Vec3d m_source;
|
||||||
friend class EigenMesh3D;
|
friend class EigenMesh3D;
|
||||||
public:
|
|
||||||
|
|
||||||
// A valid object of this class can only be obtained from
|
// A valid object of this class can only be obtained from
|
||||||
// EigenMesh3D::query_ray_hit method.
|
// 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 double distance() const { return m_t; }
|
||||||
inline const Vec3d& direction() const { return m_dir; }
|
inline const Vec3d& direction() const { return m_dir; }
|
||||||
inline Vec3d position() const { return m_source + m_dir * m_t; }
|
inline Vec3d position() const { return m_source + m_dir * m_t; }
|
||||||
inline int face() const { return m_face_id; }
|
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.
|
// Hit_result can decay into a double as the hit distance.
|
||||||
inline operator double() const { return distance(); }
|
inline operator double() const { return distance(); }
|
||||||
|
|
||||||
inline Vec3d normal() const {
|
inline Vec3d normal() const {
|
||||||
if(m_face_id < 0) return {};
|
if(m_face_id < 0 || !is_valid()) return {};
|
||||||
auto trindex = m_mesh.get().m_F.row(m_face_id);
|
auto trindex = m_mesh->m_F.row(m_face_id);
|
||||||
const Vec3d& p1 = m_mesh.get().V().row(trindex(0));
|
const Vec3d& p1 = m_mesh->V().row(trindex(0));
|
||||||
const Vec3d& p2 = m_mesh.get().V().row(trindex(1));
|
const Vec3d& p2 = m_mesh->V().row(trindex(1));
|
||||||
const Vec3d& p3 = m_mesh.get().V().row(trindex(2));
|
const Vec3d& p3 = m_mesh->V().row(trindex(2));
|
||||||
Eigen::Vector3d U = p2 - p1;
|
Eigen::Vector3d U = p2 - p1;
|
||||||
Eigen::Vector3d V = p3 - p1;
|
Eigen::Vector3d V = p3 - p1;
|
||||||
return U.cross(V).normalized();
|
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
|
// 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
|
// 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
|
// is the full width from the pin center to the back center m: The object
|
||||||
// mesh
|
// mesh.
|
||||||
//
|
// The return value is the hit result from the ray casting. If the starting
|
||||||
// Optional:
|
// point was inside the model, an "invalid" hit_result will be returned
|
||||||
// samples: how many rays will be shot
|
// with a zero distance value instead of a NAN. This way the result can
|
||||||
// safety distance: This will be added to the radiuses to have a safety
|
// be used safely for comparison with other distances.
|
||||||
// distance from the mesh.
|
|
||||||
EigenMesh3D::hit_result pinhead_mesh_intersect(
|
EigenMesh3D::hit_result pinhead_mesh_intersect(
|
||||||
const Vec3d& s,
|
const Vec3d& s,
|
||||||
const Vec3d& dir,
|
const Vec3d& dir,
|
||||||
double r_pin,
|
double r_pin,
|
||||||
double r_back,
|
double r_back,
|
||||||
double width,
|
double width)
|
||||||
unsigned samples = 8)
|
|
||||||
{
|
{
|
||||||
|
static const size_t SAMPLES = 8;
|
||||||
|
|
||||||
// method based on:
|
// method based on:
|
||||||
// https://math.stackexchange.com/questions/73237/parametric-equation-of-a-circle-in-3d-space
|
// 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
|
// The portions of the circle (the head-back circle) for which we will
|
||||||
// shoot rays.
|
// 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();
|
for(size_t i = 0; i < phis.size(); ++i) phis[i] = i*2*PI/phis.size();
|
||||||
|
|
||||||
auto& m = m_mesh;
|
auto& m = m_mesh;
|
||||||
using HitResult = EigenMesh3D::hit_result;
|
using HitResult = EigenMesh3D::hit_result;
|
||||||
|
|
||||||
// Hit results
|
// 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
|
// 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
|
// 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);
|
auto q = m.query_ray_hit(ps + sd*n, n);
|
||||||
|
|
||||||
if(q.is_inside()) { // the hit is inside the model
|
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 {
|
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);
|
auto q2 = m.query_ray_hit(ps + (q.distance() + 2*sd)*n, n);
|
||||||
hits[i] = q2;
|
hits[i] = q2;
|
||||||
}
|
}
|
||||||
} else hits[i] = q;
|
} else hits[i] = q;
|
||||||
});
|
});
|
||||||
|
|
||||||
auto mit = std::min_element(hits.begin(), hits.end(),
|
auto mit = std::min_element(hits.begin(), hits.end());
|
||||||
[](const HitResult& hr1,
|
|
||||||
const HitResult& hr2)
|
|
||||||
{
|
|
||||||
return hr1.distance() < hr2.distance();
|
|
||||||
});
|
|
||||||
|
|
||||||
return *mit;
|
return *mit;
|
||||||
}
|
}
|
||||||
|
@ -1132,13 +1138,18 @@ class SLASupportTree::Algorithm {
|
||||||
// If the function is used for headless sticks, the ins_check parameter
|
// 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
|
// have to be true as the beginning of the stick might be inside the model
|
||||||
// geometry.
|
// 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(
|
EigenMesh3D::hit_result bridge_mesh_intersect(
|
||||||
const Vec3d& s,
|
const Vec3d& s,
|
||||||
const Vec3d& dir,
|
const Vec3d& dir,
|
||||||
double r,
|
double r,
|
||||||
bool ins_check = false,
|
bool ins_check = false)
|
||||||
unsigned samples = 4)
|
|
||||||
{
|
{
|
||||||
|
static const size_t SAMPLES = 8;
|
||||||
|
|
||||||
// helper vector calculations
|
// helper vector calculations
|
||||||
Vec3d a(0, 1, 0), b;
|
Vec3d a(0, 1, 0), b;
|
||||||
const double& sd = m_cfg.safety_distance_mm;
|
const double& sd = m_cfg.safety_distance_mm;
|
||||||
|
@ -1160,14 +1171,14 @@ class SLASupportTree::Algorithm {
|
||||||
}
|
}
|
||||||
|
|
||||||
// circle portions
|
// 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();
|
for(size_t i = 0; i < phis.size(); ++i) phis[i] = i*2*PI/phis.size();
|
||||||
|
|
||||||
auto& m = m_mesh;
|
auto& m = m_mesh;
|
||||||
using HitResult = EigenMesh3D::hit_result;
|
using HitResult = EigenMesh3D::hit_result;
|
||||||
|
|
||||||
// Hit results
|
// Hit results
|
||||||
std::vector<HitResult> hits(samples, HitResult(m));
|
std::array<HitResult, SAMPLES> hits;
|
||||||
|
|
||||||
tbb::parallel_for(size_t(0), phis.size(),
|
tbb::parallel_for(size_t(0), phis.size(),
|
||||||
[&m, &phis, a, b, sd, dir, r, s, ins_check, &hits]
|
[&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);
|
auto hr = m.query_ray_hit(p + sd*dir, dir);
|
||||||
|
|
||||||
if(ins_check && hr.is_inside()) {
|
if(ins_check && hr.is_inside()) {
|
||||||
if(hr.distance() > 2*r) phi = 0;
|
if(hr.distance() > 2*r) hits[i] = HitResult(0.0);
|
||||||
else {
|
else {
|
||||||
// re-cast the ray from the outside of the object
|
// re-cast the ray from the outside of the object
|
||||||
auto hr2 =
|
auto hr2 =
|
||||||
|
@ -1200,12 +1211,7 @@ class SLASupportTree::Algorithm {
|
||||||
} else hits[i] = hr;
|
} else hits[i] = hr;
|
||||||
});
|
});
|
||||||
|
|
||||||
auto mit = std::min_element(hits.begin(), hits.end(),
|
auto mit = std::min_element(hits.begin(), hits.end());
|
||||||
[](const HitResult& hr1,
|
|
||||||
const HitResult& hr2)
|
|
||||||
{
|
|
||||||
return hr1.distance() < hr2.distance();
|
|
||||||
});
|
|
||||||
|
|
||||||
return *mit;
|
return *mit;
|
||||||
}
|
}
|
||||||
|
@ -1442,7 +1448,7 @@ public:
|
||||||
polar = std::max(polar, 3*PI / 4);
|
polar = std::max(polar, 3*PI / 4);
|
||||||
|
|
||||||
// save the head (pinpoint) position
|
// save the head (pinpoint) position
|
||||||
Vec3d hp = m_points.row(i);
|
Vec3d hp = m_points.row(fidx);
|
||||||
|
|
||||||
double w = m_cfg.head_width_mm +
|
double w = m_cfg.head_width_mm +
|
||||||
m_cfg.head_back_radius_mm +
|
m_cfg.head_back_radius_mm +
|
||||||
|
@ -1492,12 +1498,14 @@ public:
|
||||||
bound(-PI, PI) // azimuth can be a full search
|
bound(-PI, PI) // azimuth can be a full search
|
||||||
);
|
);
|
||||||
|
|
||||||
t = oresult.score;
|
if(oresult.score > w) {
|
||||||
polar = std::get<0>(oresult.optimum);
|
polar = std::get<0>(oresult.optimum);
|
||||||
azimuth = std::get<1>(oresult.optimum);
|
azimuth = std::get<1>(oresult.optimum);
|
||||||
nn = Vec3d(std::cos(azimuth) * std::sin(polar),
|
nn = Vec3d(std::cos(azimuth) * std::sin(polar),
|
||||||
std::sin(azimuth) * std::sin(polar),
|
std::sin(azimuth) * std::sin(polar),
|
||||||
std::cos(polar)).normalized();
|
std::cos(polar)).normalized();
|
||||||
|
t = oresult.score;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// save the verified and corrected normal
|
// save the verified and corrected normal
|
||||||
|
@ -1829,6 +1837,8 @@ public:
|
||||||
double d = 0, tdown = 0;
|
double d = 0, tdown = 0;
|
||||||
Vec3d dirdown(0.0, 0.0, -1.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(
|
while(d < t && !std::isinf(tdown = bridge_mesh_intersect(
|
||||||
hjp + d*head.dir,
|
hjp + d*head.dir,
|
||||||
dirdown, head.r_back_mm))) {
|
dirdown, head.r_back_mm))) {
|
||||||
|
@ -1881,12 +1891,16 @@ public:
|
||||||
);
|
);
|
||||||
|
|
||||||
d = 0; t = oresult.score;
|
d = 0; t = oresult.score;
|
||||||
|
|
||||||
|
|
||||||
polar = std::get<0>(oresult.optimum);
|
polar = std::get<0>(oresult.optimum);
|
||||||
azimuth = std::get<1>(oresult.optimum);
|
azimuth = std::get<1>(oresult.optimum);
|
||||||
Vec3d bridgedir = Vec3d(std::cos(azimuth) * std::sin(polar),
|
Vec3d bridgedir = Vec3d(std::cos(azimuth) * std::sin(polar),
|
||||||
std::sin(azimuth) * std::sin(polar),
|
std::sin(azimuth) * std::sin(polar),
|
||||||
std::cos(polar)).normalized();
|
std::cos(polar)).normalized();
|
||||||
|
|
||||||
|
t = std::min(t, m_cfg.max_bridge_length_mm);
|
||||||
|
|
||||||
while(d < t && !std::isinf(tdown = bridge_mesh_intersect(
|
while(d < t && !std::isinf(tdown = bridge_mesh_intersect(
|
||||||
hjp + d*bridgedir,
|
hjp + d*bridgedir,
|
||||||
dirdown,
|
dirdown,
|
||||||
|
|
|
@ -82,7 +82,7 @@ struct SupportConfig {
|
||||||
double normal_cutoff_angle = 150.0 * M_PI / 180.0;
|
double normal_cutoff_angle = 150.0 * M_PI / 180.0;
|
||||||
|
|
||||||
// The shortest distance of any support structure from the model surface
|
// 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;
|
struct PoolConfig;
|
||||||
|
|
Loading…
Add table
Reference in a new issue