FDM supports gizmo: fixed a crash when trying to paint on the clipping plane

This commit is contained in:
Lukas Matena 2020-05-20 12:33:49 +02:00
parent 9c365da828
commit feb591782f

View File

@ -308,7 +308,7 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
const Transform3d& instance_trafo = mi->get_transformation().get_matrix();
std::vector<std::vector<std::pair<Vec3f, size_t>>> hit_positions_and_facet_ids;
bool some_mesh_was_hit = false;
bool clipped_mesh_was_hit = false;
Vec3f normal = Vec3f::Zero();
Vec3f hit = Vec3f::Zero();
@ -343,7 +343,7 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
{
// In case this hit is clipped, skip it.
if (is_mesh_point_clipped(hit.cast<double>())) {
some_mesh_was_hit = true;
clipped_mesh_was_hit = true;
continue;
}
@ -357,116 +357,119 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
}
}
}
// We now know where the ray hit, let's save it and cast another ray
if (closest_hit_mesh_id != size_t(-1)) // only if there is at least one hit
some_mesh_was_hit = true;
if (some_mesh_was_hit) {
// Now propagate the hits
mesh_id = -1;
const TriangleMesh* mesh = nullptr;
for (const ModelVolume* mv : mo->volumes) {
if (! mv->is_model_part())
continue;
++mesh_id;
if (mesh_id == closest_hit_mesh_id) {
mesh = &mv->mesh();
break;
}
if (closest_hit_mesh_id == -1) {
// In case we have no valid hit, we can return. The event will
// be stopped in following two cases:
// 1. clicking the clipping plane
// 2. dragging while painting (to prevent scene rotations and moving the object)
return clipped_mesh_was_hit
|| (action == SLAGizmoEventType::Dragging && m_button_down != Button::None);
}
// Now propagate the hits
mesh_id = -1;
const TriangleMesh* mesh = nullptr;
for (const ModelVolume* mv : mo->volumes) {
if (! mv->is_model_part())
continue;
++mesh_id;
if (mesh_id == closest_hit_mesh_id) {
mesh = &mv->mesh();
break;
}
}
bool update_both = false;
bool update_both = false;
const Transform3d& trafo_matrix = trafo_matrices[mesh_id];
const Transform3d& trafo_matrix = trafo_matrices[mesh_id];
// Calculate how far can a point be from the line (in mesh coords).
// FIXME: The scaling of the mesh can be non-uniform.
const Vec3d sf = Geometry::Transformation(trafo_matrix).get_scaling_factor();
const float avg_scaling = (sf(0) + sf(1) + sf(2))/3.;
const float limit = pow(m_cursor_radius/avg_scaling , 2.f);
// Calculate how far can a point be from the line (in mesh coords).
// FIXME: The scaling of the mesh can be non-uniform.
const Vec3d sf = Geometry::Transformation(trafo_matrix).get_scaling_factor();
const float avg_scaling = (sf(0) + sf(1) + sf(2))/3.;
const float limit = pow(m_cursor_radius/avg_scaling , 2.f);
const std::pair<Vec3f, size_t>& hit_and_facet = { closest_hit, closest_facet };
const std::pair<Vec3f, size_t>& hit_and_facet = { closest_hit, closest_facet };
// Calculate direction from camera to the hit (in mesh coords):
Vec3f dir = ((trafo_matrix.inverse() * camera.get_position()).cast<float>() - hit_and_facet.first).normalized();
// Calculate direction from camera to the hit (in mesh coords):
Vec3f dir = ((trafo_matrix.inverse() * camera.get_position()).cast<float>() - hit_and_facet.first).normalized();
// A lambda to calculate distance from the centerline:
auto squared_distance_from_line = [&hit_and_facet, &dir](const Vec3f& point) -> float {
Vec3f diff = hit_and_facet.first - point;
return (diff - diff.dot(dir) * dir).squaredNorm();
};
// A lambda to calculate distance from the centerline:
auto squared_distance_from_line = [&hit_and_facet, &dir](const Vec3f& point) -> float {
Vec3f diff = hit_and_facet.first - point;
return (diff - diff.dot(dir) * dir).squaredNorm();
};
// A lambda to determine whether this facet is potentionally visible (still can be obscured)
auto faces_camera = [&dir, &mesh](const size_t& facet) -> bool {
return (mesh->stl.facet_start[facet].normal.dot(dir) > 0.);
};
// Now start with the facet the pointer points to and check all adjacent facets.
std::vector<size_t> facets_to_select{hit_and_facet.second};
std::vector<bool> visited(m_selected_facets[mesh_id].size(), false); // keep track of facets we already processed
size_t facet_idx = 0; // index into facets_to_select
while (facet_idx < facets_to_select.size()) {
size_t facet = facets_to_select[facet_idx];
if (! visited[facet]) {
// check all three vertices and in case they're close enough,
// add neighboring facets to be proccessed later
for (size_t i=0; i<3; ++i) {
float dist = squared_distance_from_line(
mesh->its.vertices[mesh->its.indices[facet](i)]);
if (dist < limit) {
for (int n=0; n<3; ++n) {
if (faces_camera(mesh->stl.neighbors_start[facet].neighbor[n]))
facets_to_select.push_back(mesh->stl.neighbors_start[facet].neighbor[n]);
}
// A lambda to determine whether this facet is potentionally visible (still can be obscured)
auto faces_camera = [&dir, &mesh](const size_t& facet) -> bool {
return (mesh->stl.facet_start[facet].normal.dot(dir) > 0.);
};
// Now start with the facet the pointer points to and check all adjacent facets.
std::vector<size_t> facets_to_select{hit_and_facet.second};
std::vector<bool> visited(m_selected_facets[mesh_id].size(), false); // keep track of facets we already processed
size_t facet_idx = 0; // index into facets_to_select
while (facet_idx < facets_to_select.size()) {
size_t facet = facets_to_select[facet_idx];
if (! visited[facet]) {
// check all three vertices and in case they're close enough,
// add neighboring facets to be proccessed later
for (size_t i=0; i<3; ++i) {
float dist = squared_distance_from_line(
mesh->its.vertices[mesh->its.indices[facet](i)]);
if (dist < limit) {
for (int n=0; n<3; ++n) {
if (faces_camera(mesh->stl.neighbors_start[facet].neighbor[n]))
facets_to_select.push_back(mesh->stl.neighbors_start[facet].neighbor[n]);
}
}
visited[facet] = true;
}
++facet_idx;
visited[facet] = true;
}
std::vector<size_t> new_facets;
new_facets.reserve(facets_to_select.size());
// Now just select all facets that passed and remember which
// ones have really changed state.
for (size_t next_facet : facets_to_select) {
FacetSupportType& facet = m_selected_facets[mesh_id][next_facet];
if (facet != new_state) {
if (facet != FacetSupportType::NONE) {
// this triangle is currently in the other VBA.
// Both VBAs need to be refreshed.
update_both = true;
}
facet = new_state;
new_facets.push_back(next_facet);
}
}
if (! new_facets.empty()) {
if (new_state != FacetSupportType::NONE) {
// append triangles into the respective VBA
update_vertex_buffers(mesh, mesh_id, new_state, &new_facets);
if (update_both) {
auto other = new_state == FacetSupportType::ENFORCER
? FacetSupportType::BLOCKER
: FacetSupportType::ENFORCER;
update_vertex_buffers(mesh, mesh_id, other); // regenerate the other VBA
}
}
else {
update_vertex_buffers(mesh, mesh_id, FacetSupportType::ENFORCER);
update_vertex_buffers(mesh, mesh_id, FacetSupportType::BLOCKER);
}
}
if (m_button_down == Button::None)
m_button_down = ((action == SLAGizmoEventType::LeftDown) ? Button::Left : Button::Right);
return true;
++facet_idx;
}
if (action == SLAGizmoEventType::Dragging && m_button_down != Button::None)
return true;
std::vector<size_t> new_facets;
new_facets.reserve(facets_to_select.size());
// Now just select all facets that passed and remember which
// ones have really changed state.
for (size_t next_facet : facets_to_select) {
FacetSupportType& facet = m_selected_facets[mesh_id][next_facet];
if (facet != new_state) {
if (facet != FacetSupportType::NONE) {
// this triangle is currently in the other VBA.
// Both VBAs need to be refreshed.
update_both = true;
}
facet = new_state;
new_facets.push_back(next_facet);
}
}
if (! new_facets.empty()) {
if (new_state != FacetSupportType::NONE) {
// append triangles into the respective VBA
update_vertex_buffers(mesh, mesh_id, new_state, &new_facets);
if (update_both) {
auto other = new_state == FacetSupportType::ENFORCER
? FacetSupportType::BLOCKER
: FacetSupportType::ENFORCER;
update_vertex_buffers(mesh, mesh_id, other); // regenerate the other VBA
}
}
else {
update_vertex_buffers(mesh, mesh_id, FacetSupportType::ENFORCER);
update_vertex_buffers(mesh, mesh_id, FacetSupportType::BLOCKER);
}
}
if (m_button_down == Button::None)
m_button_down = ((action == SLAGizmoEventType::LeftDown) ? Button::Left : Button::Right);
return true;
}
if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::RightUp)