|
|
|
|
@@ -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>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|