Unified igl calls in MeshRaycaster and EigenMesh3D

MeshRaycaster is still aware of the clipping plane but it now uses EigenMesh3D internally
Public interface of both classes is unchanged
This commit is contained in:
Lukas Matena 2019-11-08 20:18:14 +01:00
parent 645f13a0ae
commit b4795e1292
4 changed files with 51 additions and 92 deletions

View File

@ -189,6 +189,9 @@ public:
// Casting a ray on the mesh, returns the distance where the hit occures.
hit_result query_ray_hit(const Vec3d &s, const Vec3d &dir) const;
// Casts a ray on the mesh and returns all hits
std::vector<hit_result> query_ray_hits(const Vec3d &s, const Vec3d &dir) const;
class si_result {
double m_value;
int m_fidx;

View File

@ -272,6 +272,31 @@ EigenMesh3D::query_ray_hit(const Vec3d &s, const Vec3d &dir) const
return ret;
}
std::vector<EigenMesh3D::hit_result>
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);
// The sort is necessary, the hits are not always sorted.
std::sort(hits.begin(), hits.end(),
[](const igl::Hit& a, const igl::Hit& b) { return a.t < b.t; });
// Convert the igl::Hit into hit_result
outs.reserve(hits.size());
for (const igl::Hit& hit : hits) {
outs.emplace_back(EigenMesh3D::hit_result(*this));
outs.back().m_t = double(hit.t);
outs.back().m_dir = dir;
outs.back().m_source = s;
if(!std::isinf(hit.t) && !std::isnan(hit.t))
outs.back().m_face_id = hit.id;
}
return outs;
}
#ifdef SLIC3R_SLA_NEEDS_WINDTREE
EigenMesh3D::si_result EigenMesh3D::signed_distance(const Vec3d &p) const {
double sign = 0; double sqdst = 0; int i = 0; Vec3d c;

View File

@ -5,10 +5,6 @@
#include "slic3r/GUI/Camera.hpp"
// There is an L function in igl that would be overridden by our localization macro.
#undef L
#include <igl/AABB.h>
#include <GL/glew.h>
@ -99,59 +95,6 @@ void MeshClipper::recalculate_triangles()
}
class MeshRaycaster::AABBWrapper {
public:
AABBWrapper(const TriangleMesh* mesh);
~AABBWrapper() { m_AABB.deinit(); }
typedef Eigen::Map<const Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>> MapMatrixXfUnaligned;
typedef Eigen::Map<const Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>> MapMatrixXiUnaligned;
igl::AABB<MapMatrixXfUnaligned, 3> m_AABB;
Vec3f get_hit_pos(const igl::Hit& hit) const;
Vec3f get_hit_normal(const igl::Hit& hit) const;
private:
const TriangleMesh* m_mesh;
};
MeshRaycaster::AABBWrapper::AABBWrapper(const TriangleMesh* mesh)
: m_mesh(mesh)
{
m_AABB.init(
MapMatrixXfUnaligned(m_mesh->its.vertices.front().data(), m_mesh->its.vertices.size(), 3),
MapMatrixXiUnaligned(m_mesh->its.indices.front().data(), m_mesh->its.indices.size(), 3));
}
MeshRaycaster::MeshRaycaster(const TriangleMesh& mesh)
: m_AABB_wrapper(new AABBWrapper(&mesh)), m_mesh(&mesh)
{
}
MeshRaycaster::~MeshRaycaster()
{
delete m_AABB_wrapper;
}
Vec3f MeshRaycaster::AABBWrapper::get_hit_pos(const igl::Hit& hit) const
{
const stl_triangle_vertex_indices& indices = m_mesh->its.indices[hit.id];
return Vec3f((1-hit.u-hit.v) * m_mesh->its.vertices[indices(0)]
+ hit.u * m_mesh->its.vertices[indices(1)]
+ hit.v * m_mesh->its.vertices[indices(2)]);
}
Vec3f MeshRaycaster::AABBWrapper::get_hit_normal(const igl::Hit& hit) const
{
const stl_triangle_vertex_indices& indices = m_mesh->its.indices[hit.id];
Vec3f a(m_mesh->its.vertices[indices(1)] - m_mesh->its.vertices[indices(0)]);
Vec3f b(m_mesh->its.vertices[indices(2)] - m_mesh->its.vertices[indices(0)]);
return Vec3f(a.cross(b));
}
bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
Vec3f& position, Vec3f& normal, const ClippingPlane* clipping_plane) const
{
@ -164,27 +107,20 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d&
::gluUnProject(mouse_pos(0), viewport[3] - mouse_pos(1), 0., model_mat.data(), proj_mat.data(), viewport.data(), &pt1(0), &pt1(1), &pt1(2));
::gluUnProject(mouse_pos(0), viewport[3] - mouse_pos(1), 1., model_mat.data(), proj_mat.data(), viewport.data(), &pt2(0), &pt2(1), &pt2(2));
std::vector<igl::Hit> hits;
Transform3d inv = trafo.inverse();
pt1 = inv * pt1;
pt2 = inv * pt2;
if (! m_AABB_wrapper->m_AABB.intersect_ray(
AABBWrapper::MapMatrixXfUnaligned(m_mesh->its.vertices.front().data(), m_mesh->its.vertices.size(), 3),
AABBWrapper::MapMatrixXiUnaligned(m_mesh->its.indices.front().data(), m_mesh->its.indices.size(), 3),
pt1.cast<float>(), (pt2-pt1).cast<float>(), hits))
std::vector<sla::EigenMesh3D::hit_result> hits = m_emesh.query_ray_hits(pt1, pt2-pt1);
if (hits.empty())
return false; // no intersection found
std::sort(hits.begin(), hits.end(), [](const igl::Hit& a, const igl::Hit& b) { return a.t < b.t; });
unsigned i = 0;
// Remove points that are obscured or cut by the clipping plane
if (clipping_plane) {
for (i=0; i<hits.size(); ++i)
if (! clipping_plane->is_point_clipped(trafo * m_AABB_wrapper->get_hit_pos(hits[i]).cast<double>()))
if (! clipping_plane->is_point_clipped(trafo * hits[i].position()))
break;
if (i==hits.size() || (hits.size()-i) % 2 != 0) {
@ -195,8 +131,8 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d&
}
// Now stuff the points in the provided vector and calculate normals if asked about them:
position = m_AABB_wrapper->get_hit_pos(hits[i]);
normal = m_AABB_wrapper->get_hit_normal(hits[i]);
position = hits[i].position().cast<float>();
normal = hits[i].normal().cast<float>();
return true;
}
@ -220,24 +156,21 @@ std::vector<unsigned> MeshRaycaster::get_unobscured_idxs(const Geometry::Transfo
bool is_obscured = false;
// Cast a ray in the direction of the camera and look for intersection with the mesh:
std::vector<igl::Hit> hits;
std::vector<sla::EigenMesh3D::hit_result> hits;
// Offset the start of the ray by EPSILON to account for numerical inaccuracies.
if (m_AABB_wrapper->m_AABB.intersect_ray(
AABBWrapper::MapMatrixXfUnaligned(m_mesh->its.vertices.front().data(), m_mesh->its.vertices.size(), 3),
AABBWrapper::MapMatrixXiUnaligned(m_mesh->its.indices.front().data(), m_mesh->its.indices.size(), 3),
inverse_trafo * pt + direction_to_camera_mesh * EPSILON, direction_to_camera_mesh, hits)) {
hits = m_emesh.query_ray_hits((inverse_trafo * pt + direction_to_camera_mesh * EPSILON).cast<double>(),
direction_to_camera.cast<double>());
std::sort(hits.begin(), hits.end(), [](const igl::Hit& h1, const igl::Hit& h2) { return h1.t < h2.t; });
if (! hits.empty()) {
// If the closest hit facet normal points in the same direction as the ray,
// we are looking through the mesh and should therefore discard the point:
if (m_AABB_wrapper->get_hit_normal(hits.front()).dot(direction_to_camera_mesh) > 0.f)
if (hits.front().normal().dot(direction_to_camera_mesh.cast<double>()) > 0)
is_obscured = true;
// Eradicate all hits that the caller wants to ignore
for (unsigned j=0; j<hits.size(); ++j) {
const igl::Hit& hit = hits[j];
if (clipping_plane && clipping_plane->is_point_clipped(trafo.get_matrix() * m_AABB_wrapper->get_hit_pos(hit).cast<double>())) {
if (clipping_plane && clipping_plane->is_point_clipped(trafo.get_matrix() * hits[j].position())) {
hits.erase(hits.begin()+j);
--j;
}
@ -258,17 +191,15 @@ std::vector<unsigned> MeshRaycaster::get_unobscured_idxs(const Geometry::Transfo
Vec3f MeshRaycaster::get_closest_point(const Vec3f& point, Vec3f* normal) const
{
int idx = 0;
Eigen::Matrix<float, 1, 3> closest_point;
m_AABB_wrapper->m_AABB.squared_distance(
AABBWrapper::MapMatrixXfUnaligned(m_mesh->its.vertices.front().data(), m_mesh->its.vertices.size(), 3),
AABBWrapper::MapMatrixXiUnaligned(m_mesh->its.indices.front().data(), m_mesh->its.indices.size(), 3),
point, idx, closest_point);
Vec3d closest_point;
m_emesh.squared_distance(point.cast<double>(), idx, closest_point);
if (normal) {
igl::Hit imag_hit;
imag_hit.id = idx;
*normal = m_AABB_wrapper->get_hit_normal(imag_hit);
const stl_triangle_vertex_indices& indices = m_mesh->its.indices[idx];
Vec3f a(m_mesh->its.vertices[indices(1)] - m_mesh->its.vertices[indices(0)]);
Vec3f b(m_mesh->its.vertices[indices(2)] - m_mesh->its.vertices[indices(0)]);
*normal = Vec3f(a.cross(b));
}
return closest_point;
return closest_point.cast<float>();
}

View File

@ -3,6 +3,7 @@
#include "libslic3r/Point.hpp"
#include "libslic3r/Geometry.hpp"
#include "libslic3r/SLA/SLACommon.hpp"
#include <cfloat>
@ -93,8 +94,9 @@ private:
class MeshRaycaster {
public:
MeshRaycaster(const TriangleMesh& mesh);
~MeshRaycaster();
MeshRaycaster(const TriangleMesh& mesh)
: m_mesh(&mesh), m_emesh(mesh)
{}
void set_transformation(const Geometry::Transformation& trafo);
void set_camera(const Camera& camera);
@ -107,9 +109,7 @@ public:
Vec3f get_closest_point(const Vec3f& point, Vec3f* normal = nullptr) const;
private:
// PIMPL wrapper around igl::AABB so I don't have to include the header-only IGL here
class AABBWrapper;
AABBWrapper* m_AABB_wrapper;
sla::EigenMesh3D m_emesh;
const TriangleMesh* m_mesh = nullptr;
};