EigenMesh3D now stores TriangleMesh inside, not a mesh in Eigen format

Rotfinder was apparently building the AABB tree needlessly
This commit is contained in:
Lukas Matena 2020-05-22 18:21:52 +02:00
parent 9224a6a3e6
commit d85fa8e9ab
4 changed files with 62 additions and 69 deletions

View file

@ -184,42 +184,39 @@ void BoxIndex::foreach(std::function<void (const BoxIndexEl &)> fn)
class EigenMesh3D::AABBImpl {
private:
AABBTreeIndirect::Tree3f m_tree;
TriangleMesh m_triangle_mesh; // FIXME: There should be no extra copy
// maybe even the m_V and m_F are extra. This is just to see the new
// AABB tree in action
public:
void init(const TriangleMesh& tmesh)
void init(const TriangleMesh& tm)
{
m_triangle_mesh = tmesh;
m_tree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set(
m_triangle_mesh.its.vertices, m_triangle_mesh.its.indices);
tm.its.vertices, tm.its.indices);
}
void intersect_ray(const Eigen::MatrixXd&, const Eigen::MatrixXi&,
void intersect_ray(const TriangleMesh& tm,
const Vec3d& s, const Vec3d& dir, igl::Hit& hit)
{
AABBTreeIndirect::intersect_ray_first_hit(m_triangle_mesh.its.vertices,
m_triangle_mesh.its.indices,
AABBTreeIndirect::intersect_ray_first_hit(tm.its.vertices,
tm.its.indices,
m_tree,
s, dir, hit);
}
void intersect_ray(const Eigen::MatrixXd&, const Eigen::MatrixXi&,
void intersect_ray(const TriangleMesh& tm,
const Vec3d& s, const Vec3d& dir, std::vector<igl::Hit>& hits)
{
AABBTreeIndirect::intersect_ray_all_hits(m_triangle_mesh.its.vertices,
m_triangle_mesh.its.indices,
AABBTreeIndirect::intersect_ray_all_hits(tm.its.vertices,
tm.its.indices,
m_tree,
s, dir, hits);
}
double squared_distance(const Eigen::MatrixXd&, const Eigen::MatrixXi&,
double squared_distance(const TriangleMesh& tm,
const Vec3d& point, int& i, Eigen::Matrix<double, 1, 3>& closest) {
size_t idx_unsigned = 0;
Vec3d closest_vec3d(closest);
double dist = AABBTreeIndirect::squared_distance_to_indexed_triangle_set(
m_triangle_mesh.its.vertices,
m_triangle_mesh.its.indices,
tm.its.vertices,
tm.its.indices,
m_tree, point, idx_unsigned, closest_vec3d);
i = int(idx_unsigned);
closest = closest_vec3d;
@ -276,12 +273,12 @@ trigger linking error when attempting to use it.
}
#endif
EigenMesh3D::EigenMesh3D(const TriangleMesh& tmesh): m_aabb(new AABBImpl()) {
EigenMesh3D::EigenMesh3D(const TriangleMesh& tmesh)
: m_aabb(new AABBImpl()), m_tm(tmesh)
{
auto&& bb = tmesh.bounding_box();
m_ground_level += bb.min(Z);
to_eigen_mesh(tmesh, m_V, m_F);
// Build the AABB accelaration tree
m_aabb->init(tmesh);
}
@ -289,10 +286,10 @@ EigenMesh3D::EigenMesh3D(const TriangleMesh& tmesh): m_aabb(new AABBImpl()) {
EigenMesh3D::~EigenMesh3D() {}
EigenMesh3D::EigenMesh3D(const EigenMesh3D &other):
m_V(other.m_V), m_F(other.m_F), m_ground_level(other.m_ground_level),
m_tm(other.m_tm), m_ground_level(other.m_ground_level),
m_aabb( new AABBImpl(*other.m_aabb) ) {}
EigenMesh3D::EigenMesh3D(const Contour3D &other)
/*EigenMesh3D::EigenMesh3D(const Contour3D &other)
{
m_V.resize(Eigen::Index(other.points.size()), 3);
m_F.resize(Eigen::Index(other.faces3.size() + 2 * other.faces4.size()), 3);
@ -310,12 +307,11 @@ EigenMesh3D::EigenMesh3D(const Contour3D &other)
m_F.row(Eigen::Index(i)) = Vec3i{quad(0), quad(1), quad(2)};
m_F.row(Eigen::Index(i + 1)) = Vec3i{quad(2), quad(3), quad(0)};
}
}
}*/
EigenMesh3D &EigenMesh3D::operator=(const EigenMesh3D &other)
{
m_V = other.m_V;
m_F = other.m_F;
m_tm = other.m_tm;
m_ground_level = other.m_ground_level;
m_aabb.reset(new AABBImpl(*other.m_aabb)); return *this;
}
@ -333,13 +329,14 @@ EigenMesh3D::query_ray_hit(const Vec3d &s, const Vec3d &dir) const
#ifdef SLIC3R_HOLE_RAYCASTER
if (! m_holes.empty()) {
// If there are holes, the hit_results will be made by
// query_ray_hits (object) and filter_hits (holes):
return filter_hits(query_ray_hits(s, dir));
}
#endif
m_aabb->intersect_ray(m_V, m_F, s, dir, hit);
m_aabb->intersect_ray(m_tm, s, dir, hit);
hit_result ret(*this);
ret.m_t = double(hit.t);
ret.m_dir = dir;
@ -357,7 +354,7 @@ EigenMesh3D::query_ray_hits(const Vec3d &s, const Vec3d &dir) const
{
std::vector<EigenMesh3D::hit_result> outs;
std::vector<igl::Hit> hits;
m_aabb->intersect_ray(m_V, m_F, s, dir, hits);
m_aabb->intersect_ray(m_tm, s, dir, hits);
// The sort is necessary, the hits are not always sorted.
std::sort(hits.begin(), hits.end(),
@ -489,7 +486,7 @@ double EigenMesh3D::squared_distance(const Vec3d &p, int& i, Vec3d& c) const {
double sqdst = 0;
Eigen::Matrix<double, 1, 3> pp = p;
Eigen::Matrix<double, 1, 3> cc;
sqdst = m_aabb->squared_distance(m_V, m_F, pp, i, cc);
sqdst = m_aabb->squared_distance(m_tm, pp, i, cc);
c = cc;
return sqdst;
}
@ -523,7 +520,7 @@ PointSet normals(const PointSet& points,
std::function<void()> thr, // throw on cancel
const std::vector<unsigned>& pt_indices)
{
if (points.rows() == 0 || mesh.V().rows() == 0 || mesh.F().rows() == 0)
if (points.rows() == 0 || mesh.vertices().empty() || mesh.indices().empty())
return {};
std::vector<unsigned> range = pt_indices;
@ -545,11 +542,11 @@ PointSet normals(const PointSet& points,
mesh.squared_distance(points.row(eidx), faceid, p);
auto trindex = mesh.F().row(faceid);
auto trindex = mesh.indices(faceid);
const Vec3d &p1 = mesh.V().row(trindex(0));
const Vec3d &p2 = mesh.V().row(trindex(1));
const Vec3d &p3 = mesh.V().row(trindex(2));
const Vec3d &p1 = mesh.vertices(trindex(0)).cast<double>();
const Vec3d &p2 = mesh.vertices(trindex(1)).cast<double>();
const Vec3d &p3 = mesh.vertices(trindex(2)).cast<double>();
// We should check if the point lies on an edge of the hosting
// triangle. If it does then all the other triangles using the
@ -584,17 +581,17 @@ PointSet normals(const PointSet& points,
// vector for the neigboring triangles including the detected one.
std::vector<Vec3i> neigh;
if (ic >= 0) { // The point is right on a vertex of the triangle
for (int n = 0; n < mesh.F().rows(); ++n) {
for (size_t n = 0; n < mesh.indices().size(); ++n) {
thr();
Vec3i ni = mesh.F().row(n);
Vec3i ni = mesh.indices(n);
if ((ni(X) == ic || ni(Y) == ic || ni(Z) == ic))
neigh.emplace_back(ni);
}
} else if (ia >= 0 && ib >= 0) { // the point is on and edge
// now get all the neigboring triangles
for (int n = 0; n < mesh.F().rows(); ++n) {
for (size_t n = 0; n < mesh.indices().size(); ++n) {
thr();
Vec3i ni = mesh.F().row(n);
Vec3i ni = mesh.indices(n);
if ((ni(X) == ia || ni(Y) == ia || ni(Z) == ia) &&
(ni(X) == ib || ni(Y) == ib || ni(Z) == ib))
neigh.emplace_back(ni);
@ -605,9 +602,9 @@ PointSet normals(const PointSet& points,
std::vector<Vec3d> neighnorms;
neighnorms.reserve(neigh.size());
for (const Vec3i &tri : neigh) {
const Vec3d & pt1 = mesh.V().row(tri(0));
const Vec3d & pt2 = mesh.V().row(tri(1));
const Vec3d & pt3 = mesh.V().row(tri(2));
const Vec3d & pt1 = mesh.vertices(tri(0)).cast<double>();
const Vec3d & pt2 = mesh.vertices(tri(1)).cast<double>();
const Vec3d & pt3 = mesh.vertices(tri(2)).cast<double>();
Eigen::Vector3d U = pt2 - pt1;
Eigen::Vector3d V = pt3 - pt1;
neighnorms.emplace_back(U.cross(V).normalized());

View file

@ -28,14 +28,14 @@ Contour3D::Contour3D(TriangleMesh &&trmesh)
}
Contour3D::Contour3D(const EigenMesh3D &emesh) {
points.reserve(size_t(emesh.V().rows()));
faces3.reserve(size_t(emesh.F().rows()));
points.reserve(emesh.vertices().size());
faces3.reserve(emesh.indices().size());
for (int r = 0; r < emesh.V().rows(); r++)
points.emplace_back(emesh.V().row(r).cast<double>());
for (const Vec3f& vert : emesh.vertices())
points.emplace_back(vert.cast<double>());
for (int i = 0; i < emesh.F().rows(); i++)
faces3.emplace_back(emesh.F().row(i));
for (const auto& ind : emesh.indices())
faces3.emplace_back(ind);
}
Contour3D &Contour3D::merge(const Contour3D &ctr)

View file

@ -2,6 +2,7 @@
#define SLA_EIGENMESH3D_H
#include <libslic3r/SLA/Common.hpp>
#include <libslic3r/TriangleMesh.hpp>
// There is an implementation of a hole-aware raycaster that was eventually
@ -15,8 +16,6 @@
namespace Slic3r {
class TriangleMesh;
namespace sla {
struct Contour3D;
@ -30,8 +29,7 @@ void to_triangle_mesh(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F, Triang
class EigenMesh3D {
class AABBImpl;
Eigen::MatrixXd m_V;
Eigen::MatrixXi m_F;
TriangleMesh m_tm;
double m_ground_level = 0, m_gnd_offset = 0;
std::unique_ptr<AABBImpl> m_aabb;
@ -59,8 +57,14 @@ public:
inline void ground_level_offset(double o) { m_gnd_offset = o; }
inline double ground_level_offset() const { return m_gnd_offset; }
inline const Eigen::MatrixXd& V() const { return m_V; }
inline const Eigen::MatrixXi& F() const { return m_F; }
const std::vector<stl_vertex>& vertices() const { return m_tm.its.vertices; }
const std::vector<stl_triangle_vertex_indices>& indices() const { return m_tm.its.indices; }
const stl_vertex& vertices(size_t idx) const {
return m_tm.its.vertices[idx];
}
const stl_triangle_vertex_indices& indices(size_t idx) const {
return m_tm.its.indices[idx];
}
// Result of a raycast
class hit_result {
@ -148,10 +152,12 @@ public:
}
Vec3d normal_by_face_id(int face_id) const {
auto trindex = F().row(face_id);
const Vec3d& p1 = V().row(trindex(0));
const Vec3d& p2 = V().row(trindex(1));
const Vec3d& p3 = V().row(trindex(2));
// FIXME: normals should be cached in TriangleMesh, there should be
// no need to recalculate them.
auto trindex = this->indices(face_id);
const Vec3d& p1 = this->vertices(trindex(0)).cast<double>();
const Vec3d& p2 = this->vertices(trindex(1)).cast<double>();
const Vec3d& p3 = this->vertices(trindex(2)).cast<double>();
Eigen::Vector3d U = p2 - p1;
Eigen::Vector3d V = p3 - p1;
return U.cross(V).normalized();

View file

@ -28,7 +28,7 @@ std::array<double, 3> find_best_rotation(const ModelObject& modelobj,
// We will use only one instance of this converted mesh to examine different
// rotations
EigenMesh3D emesh(modelobj.raw_mesh());
const TriangleMesh& mesh = modelobj.raw_mesh();
// For current iteration number
unsigned status = 0;
@ -44,10 +44,10 @@ std::array<double, 3> find_best_rotation(const ModelObject& modelobj,
// call the status callback in each iteration but the actual value may be
// the same for subsequent iterations (status goes from 0 to 100 but
// iterations can be many more)
auto objfunc = [&emesh, &status, &statuscb, &stopcond, max_tries]
auto objfunc = [&mesh, &status, &statuscb, &stopcond, max_tries]
(double rx, double ry, double rz)
{
EigenMesh3D& m = emesh;
const TriangleMesh& m = mesh;
// prepare the rotation transformation
Transform3d rt = Transform3d::Identity();
@ -68,18 +68,8 @@ std::array<double, 3> find_best_rotation(const ModelObject& modelobj,
// area. The current function is only an example of how to optimize.
// Later we can add more criteria like the number of overhangs, etc...
for(int i = 0; i < m.F().rows(); i++) {
auto idx = m.F().row(i);
Vec3d p1 = m.V().row(idx(0));
Vec3d p2 = m.V().row(idx(1));
Vec3d p3 = m.V().row(idx(2));
Eigen::Vector3d U = p2 - p1;
Eigen::Vector3d V = p3 - p1;
// So this is the normal
auto n = U.cross(V).normalized();
for(size_t i = 0; i < m.stl.facet_start.size(); i++) {
Vec3d n = m.stl.facet_start[i].normal.cast<double>();
// rotate the normal with the current rotation given by the solver
n = rt * n;