FDM supports gizmo: slight code refactoring

This commit is contained in:
Lukas Matena 2020-05-15 18:31:55 +02:00
parent ed55ebba55
commit 1a38d39f82
2 changed files with 80 additions and 84 deletions

View file

@ -233,8 +233,8 @@ void GLGizmoFdmSupports::update_from_model_object()
for (int i : list) for (int i : list)
m_selected_facets[volume_id][i] = type; m_selected_facets[volume_id][i] = type;
} }
update_vertex_buffers(mv, volume_id, FacetSupportType::ENFORCER); update_vertex_buffers(mesh, volume_id, FacetSupportType::ENFORCER);
update_vertex_buffers(mv, volume_id, FacetSupportType::BLOCKER); update_vertex_buffers(mesh, volume_id, FacetSupportType::BLOCKER);
m_neighbors[volume_id].resize(3 * mesh->its.indices.size()); m_neighbors[volume_id].resize(3 * mesh->its.indices.size());
@ -333,7 +333,7 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
Vec3f closest_hit = Vec3f::Zero(); Vec3f closest_hit = Vec3f::Zero();
double closest_hit_squared_distance = std::numeric_limits<double>::max(); double closest_hit_squared_distance = std::numeric_limits<double>::max();
size_t closest_facet = 0; size_t closest_facet = 0;
size_t closest_hit_mesh_id = size_t(-1); int closest_hit_mesh_id = -1;
// Transformations of individual meshes // Transformations of individual meshes
std::vector<Transform3d> trafo_matrices; std::vector<Transform3d> trafo_matrices;
@ -376,17 +376,22 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
} }
// We now know where the ray hit, let's save it and cast another ray // 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 if (closest_hit_mesh_id != size_t(-1)) // only if there is at least one hit
hit_positions_and_facet_ids[closest_hit_mesh_id].emplace_back(closest_hit, closest_facet); 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;
}
}
// Now propagate the hits
mesh_id = -1;
for (const ModelVolume* mv : mo->volumes) {
if (! mv->is_model_part())
continue;
++mesh_id;
bool update_both = false; bool update_both = false;
const Transform3d& trafo_matrix = trafo_matrices[mesh_id]; const Transform3d& trafo_matrix = trafo_matrices[mesh_id];
@ -397,98 +402,90 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
const float avg_scaling = (sf(0) + sf(1) + sf(2))/3.; const float avg_scaling = (sf(0) + sf(1) + sf(2))/3.;
const float limit = pow(m_cursor_radius/avg_scaling , 2.f); const float limit = pow(m_cursor_radius/avg_scaling , 2.f);
std::vector<size_t> new_facets; const std::pair<Vec3f, size_t>& hit_and_facet = { closest_hit, closest_facet };
// For all hits on this mesh... const std::vector<NeighborData>& neighbors = m_neighbors[mesh_id];
for (const std::pair<Vec3f, size_t>& hit_and_facet : hit_positions_and_facet_ids[mesh_id]) {
some_mesh_was_hit = true;
const TriangleMesh* mesh = &mv->mesh();
const std::vector<NeighborData>& neighbors = m_neighbors[mesh_id];
// Calculate direction from camera to the hit (in mesh coords): // 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(); Vec3f dir = ((trafo_matrix.inverse() * camera.get_position()).cast<float>() - hit_and_facet.first).normalized();
// A lambda to calculate distance from the centerline: // A lambda to calculate distance from the centerline:
auto squared_distance_from_line = [&hit_and_facet, &dir](const Vec3f& point) -> float { auto squared_distance_from_line = [&hit_and_facet, &dir](const Vec3f& point) -> float {
Vec3f diff = hit_and_facet.first - point; Vec3f diff = hit_and_facet.first - point;
return (diff - diff.dot(dir) * dir).squaredNorm(); return (diff - diff.dot(dir) * dir).squaredNorm();
}; };
// A lambda to determine whether this facet is potentionally visible (still can be obscured) // A lambda to determine whether this facet is potentionally visible (still can be obscured)
auto faces_camera = [&dir](const ModelVolume* mv, const size_t& facet) -> bool { auto faces_camera = [&dir, &mesh](const size_t& facet) -> bool {
return (mv->mesh().stl.facet_start[facet].normal.dot(dir) > 0.); return (mesh->stl.facet_start[facet].normal.dot(dir) > 0.);
}; };
// Now start with the facet the pointer points to and check all adjacent facets. neighbors vector stores // Now start with the facet the pointer points to and check all adjacent facets. neighbors vector stores
// pairs of vertex_idx - facet_idx and is sorted with respect to the former. Neighboring facet index can be // pairs of vertex_idx - facet_idx and is sorted with respect to the former. Neighboring facet index can be
// quickly found by finding a vertex in the list and read the respective facet ids. // quickly found by finding a vertex in the list and read the respective facet ids.
std::vector<size_t> facets_to_select{hit_and_facet.second}; std::vector<size_t> facets_to_select{hit_and_facet.second};
NeighborData vertex = std::make_pair(0, 0); NeighborData vertex = std::make_pair(0, 0);
std::vector<bool> visited(m_selected_facets[mesh_id].size(), false); // keep track of facets we already processed 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 size_t facet_idx = 0; // index into facets_to_select
auto it = neighbors.end(); auto it = neighbors.end();
while (facet_idx < facets_to_select.size()) { while (facet_idx < facets_to_select.size()) {
size_t facet = facets_to_select[facet_idx]; size_t facet = facets_to_select[facet_idx];
if (! visited[facet]) { if (! visited[facet]) {
// check all three vertices and in case they're close enough, find the remaining facets // check all three vertices and in case they're close enough, find the remaining facets
// and add them to the list to be proccessed later // and add them to the list to be proccessed later
for (size_t i=0; i<3; ++i) { for (size_t i=0; i<3; ++i) {
vertex.first = mesh->its.indices[facet](i); // vertex index vertex.first = mesh->its.indices[facet](i); // vertex index
float dist = squared_distance_from_line(mesh->its.vertices[vertex.first]); float dist = squared_distance_from_line(mesh->its.vertices[vertex.first]);
if (dist < limit) { if (dist < limit) {
it = std::lower_bound(neighbors.begin(), neighbors.end(), vertex); it = std::lower_bound(neighbors.begin(), neighbors.end(), vertex);
while (it != neighbors.end() && it->first == vertex.first) { while (it != neighbors.end() && it->first == vertex.first) {
if (it->second != facet && faces_camera(mv, it->second)) if (it->second != facet && faces_camera(it->second))
facets_to_select.push_back(it->second); facets_to_select.push_back(it->second);
++it; ++it;
}
} }
} }
visited[facet] = true;
} }
++facet_idx; visited[facet] = true;
} }
++facet_idx;
}
//std::vector<size_t> new_facets; std::vector<size_t> new_facets;
//new_facets.clear(); new_facets.reserve(facets_to_select.size());
new_facets.reserve(facets_to_select.size());
// Now just select all facets that passed and remember which // Now just select all facets that passed and remember which
// ones have really changed state. // ones have really changed state.
for (size_t next_facet : facets_to_select) { for (size_t next_facet : facets_to_select) {
FacetSupportType& facet = m_selected_facets[mesh_id][next_facet]; FacetSupportType& facet = m_selected_facets[mesh_id][next_facet];
if (facet != new_state) { if (facet != new_state) {
if (facet != FacetSupportType::NONE) { if (facet != FacetSupportType::NONE) {
// this triangle is currently in the other VBA. // this triangle is currently in the other VBA.
// Both VBAs need to be refreshed. // Both VBAs need to be refreshed.
update_both = true; update_both = true;
}
facet = new_state;
new_facets.push_back(next_facet);
} }
facet = new_state;
new_facets.push_back(next_facet);
} }
} }
if (! new_facets.empty()) { if (! new_facets.empty()) {
if (new_state != FacetSupportType::NONE) { if (new_state != FacetSupportType::NONE) {
// append triangles into the respective VBA // append triangles into the respective VBA
update_vertex_buffers(mv, mesh_id, new_state, &new_facets); update_vertex_buffers(mesh, mesh_id, new_state, &new_facets);
if (update_both) { if (update_both) {
auto other = new_state == FacetSupportType::ENFORCER auto other = new_state == FacetSupportType::ENFORCER
? FacetSupportType::BLOCKER ? FacetSupportType::BLOCKER
: FacetSupportType::ENFORCER; : FacetSupportType::ENFORCER;
update_vertex_buffers(mv, mesh_id, other); // regenerate the other VBA update_vertex_buffers(mesh, mesh_id, other); // regenerate the other VBA
} }
} }
else { else {
update_vertex_buffers(mv, mesh_id, FacetSupportType::ENFORCER); update_vertex_buffers(mesh, mesh_id, FacetSupportType::ENFORCER);
update_vertex_buffers(mv, mesh_id, FacetSupportType::BLOCKER); update_vertex_buffers(mesh, mesh_id, FacetSupportType::BLOCKER);
} }
} }
}
if (some_mesh_was_hit)
{
if (m_button_down == Button::None) if (m_button_down == Button::None)
m_button_down = ((action == SLAGizmoEventType::LeftDown) ? Button::Left : Button::Right); m_button_down = ((action == SLAGizmoEventType::LeftDown) ? Button::Left : Button::Right);
return true; return true;
@ -516,13 +513,11 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
} }
void GLGizmoFdmSupports::update_vertex_buffers(const ModelVolume* mv, void GLGizmoFdmSupports::update_vertex_buffers(const TriangleMesh* mesh,
int mesh_id, int mesh_id,
FacetSupportType type, FacetSupportType type,
const std::vector<size_t>* new_facets) const std::vector<size_t>* new_facets)
{ {
const TriangleMesh* mesh = &mv->mesh();
std::vector<GLIndexedVertexArray>& ivas = m_ivas[mesh_id][type == FacetSupportType::ENFORCER ? 0 : 1]; std::vector<GLIndexedVertexArray>& ivas = m_ivas[mesh_id][type == FacetSupportType::ENFORCER ? 0 : 1];
// lambda to push facet into vertex buffer // lambda to push facet into vertex buffer
@ -598,8 +593,8 @@ void GLGizmoFdmSupports::select_facets_by_angle(float threshold_deg, bool overwr
? FacetSupportType::BLOCKER ? FacetSupportType::BLOCKER
: FacetSupportType::ENFORCER; : FacetSupportType::ENFORCER;
} }
update_vertex_buffers(mv, mesh_id, FacetSupportType::ENFORCER); update_vertex_buffers(&mv->mesh(), mesh_id, FacetSupportType::ENFORCER);
update_vertex_buffers(mv, mesh_id, FacetSupportType::BLOCKER); update_vertex_buffers(&mv->mesh(), mesh_id, FacetSupportType::BLOCKER);
} }
Plater::TakeSnapshot(wxGetApp().plater(), block ? _L("Block supports by angle") Plater::TakeSnapshot(wxGetApp().plater(), block ? _L("Block supports by angle")
@ -669,8 +664,8 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
if (mv->is_model_part()) { if (mv->is_model_part()) {
m_selected_facets[idx].assign(m_selected_facets[idx].size(), FacetSupportType::NONE); m_selected_facets[idx].assign(m_selected_facets[idx].size(), FacetSupportType::NONE);
mv->m_supported_facets.clear(); mv->m_supported_facets.clear();
update_vertex_buffers(mv, idx, FacetSupportType::ENFORCER); update_vertex_buffers(&mv->mesh(), idx, FacetSupportType::ENFORCER);
update_vertex_buffers(mv, idx, FacetSupportType::BLOCKER); update_vertex_buffers(&mv->mesh(), idx, FacetSupportType::BLOCKER);
m_parent.set_as_dirty(); m_parent.set_as_dirty();
} }
} }

View file

@ -38,11 +38,12 @@ private:
// other triangles. Enforcers and blockers are of course separate. // other triangles. Enforcers and blockers are of course separate.
std::vector<std::array<std::vector<GLIndexedVertexArray>, 2>> m_ivas; std::vector<std::array<std::vector<GLIndexedVertexArray>, 2>> m_ivas;
void update_vertex_buffers(const ModelVolume* mv, void update_vertex_buffers(const TriangleMesh* mesh,
int mesh_id, int mesh_id,
FacetSupportType type, // enforcers / blockers FacetSupportType type, // enforcers / blockers
const std::vector<size_t>* new_facets = nullptr); // nullptr -> regenerate all const std::vector<size_t>* new_facets = nullptr); // nullptr -> regenerate all
public: public:
GLGizmoFdmSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); GLGizmoFdmSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
~GLGizmoFdmSupports() override; ~GLGizmoFdmSupports() override;