FDM supports gizmo: fixed a crash when trying to paint on the clipping plane
This commit is contained in:
parent
9c365da828
commit
feb591782f
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user