NEW: add "render non_manifold_edges" function

jira: none
Change-Id: I620e095740c60a8c9d4ceb33d6b3a44ab3d17f05
(cherry picked from commit f71b0fdeee18e3fb1482fa3e5f1121d33724b1a7)
This commit is contained in:
zhou.xu 2024-08-26 11:58:04 +08:00 committed by Lane.Wei
parent 498face4d6
commit 53d7c755a7
9 changed files with 111 additions and 14 deletions

View File

@ -258,6 +258,23 @@ public:
using Scalar = Vec3d::Scalar; using Scalar = Vec3d::Scalar;
}; };
class Line3float
{
public:
Line3float() : a(Vec3f::Zero()), b(Vec3f::Zero()) {}
Line3float(const Vec3f &_a, const Vec3f &_b) : a(_a), b(_b) {}
Vec3f vector() const { return this->b - this->a; }
Vec3f unit_vector() const { return (length() == 0.0) ? Vec3f::Zero() : vector().normalized(); }
double length() const { return vector().norm(); }
Vec3f a;
Vec3f b;
static const constexpr int Dim = 3;
using Scalar = Vec3f::Scalar;
};
typedef std::vector<Line3float> Line3floats;
BoundingBox get_extents(const Lines &lines); BoundingBox get_extents(const Lines &lines);
} // namespace Slic3r } // namespace Slic3r
@ -272,7 +289,7 @@ namespace boost { namespace polygon {
struct segment_traits<Slic3r::Line> { struct segment_traits<Slic3r::Line> {
typedef coord_t coordinate_type; typedef coord_t coordinate_type;
typedef Slic3r::Point point_type; typedef Slic3r::Point point_type;
static inline point_type get(const Slic3r::Line& line, direction_1d dir) { static inline point_type get(const Slic3r::Line& line, direction_1d dir) {
return dir.to_int() ? line.b : line.a; return dir.to_int() ? line.b : line.a;
} }

View File

@ -218,7 +218,10 @@ public:
// Create new object on a TriangleMesh. The referenced mesh must // Create new object on a TriangleMesh. The referenced mesh must
// stay valid, a ptr to it is saved and used. // stay valid, a ptr to it is saved and used.
explicit TriangleSelector(const TriangleMesh& mesh, float edge_limit = 0.6f); explicit TriangleSelector(const TriangleMesh& mesh, float edge_limit = 0.6f);
int get_orig_size_vertices() { return m_orig_size_vertices; }
const std::vector<Triangle> &get_triangles() { return m_triangles; }
const std::vector<Vertex>& get_vertices() { return m_vertices; }
const std::vector<Vec3i>& get_neighbors() { return m_neighbors; }
// Returns the facet_idx of the unsplit triangle containing the "hit". Returns -1 if the triangle isn't found. // Returns the facet_idx of the unsplit triangle containing the "hit". Returns -1 if the triangle isn't found.
[[nodiscard]] int select_unsplit_triangle(const Vec3f &hit, int facet_idx) const; [[nodiscard]] int select_unsplit_triangle(const Vec3f &hit, int facet_idx) const;
[[nodiscard]] int select_unsplit_triangle(const Vec3f &hit, int facet_idx, const Vec3i &neighbors) const; [[nodiscard]] int select_unsplit_triangle(const Vec3f &hit, int facet_idx, const Vec3i &neighbors) const;

View File

@ -3501,6 +3501,9 @@ void GLCanvas3D::on_key(wxKeyEvent& evt)
evt.ShiftDown() && evt.AltDown() && keyCode == WXK_RETURN) { evt.ShiftDown() && evt.AltDown() && keyCode == WXK_RETURN) {
wxGetApp().plater()->toggle_show_wireframe(); wxGetApp().plater()->toggle_show_wireframe();
m_dirty = true; m_dirty = true;
} else if ((evt.ShiftDown() && evt.ControlDown() && keyCode == 'L')) {
wxGetApp().plater()->toggle_non_manifold_edges();
m_dirty = true;
} }
else if (m_tab_down && keyCode == WXK_TAB && !evt.HasAnyModifiers()) { else if (m_tab_down && keyCode == WXK_TAB && !evt.HasAnyModifiers()) {
// Enable switching between 3D and Preview with Tab // Enable switching between 3D and Preview with Tab

View File

@ -696,6 +696,23 @@ bool GLModel::init_model_from_lines(const Lines3 &lines, bool generate_mesh)
return true; return true;
} }
bool GLModel::init_model_from_lines(const Line3floats &lines, bool generate_mesh)
{
GLModel::Geometry init_data;
init_data.format = {GLModel::PrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3};
init_data.reserve_vertices(2 * lines.size());
init_data.reserve_indices(2 * lines.size());
for (const auto &l : lines) {
init_data.add_vertex(l.a);
init_data.add_vertex(l.b);
const unsigned int vertices_counter = (unsigned int) init_data.vertices_count();
init_data.add_line(vertices_counter - 2, vertices_counter - 1);
}
init_from(std::move(init_data), generate_mesh);
return true;
}
void GLModel::set_color(int entity_id, const std::array<float, 4>& color) void GLModel::set_color(int entity_id, const std::array<float, 4>& color)
{ {
for (size_t i = 0; i < m_render_data.size(); ++i) { for (size_t i = 0; i < m_render_data.size(); ++i) {

View File

@ -187,6 +187,7 @@ namespace GUI {
bool init_model_from_poly(const std::vector<Vec2f> &triangles, float z, bool generate_mesh = false); bool init_model_from_poly(const std::vector<Vec2f> &triangles, float z, bool generate_mesh = false);
bool init_model_from_lines(const Lines &lines, float z, bool generate_mesh = false); bool init_model_from_lines(const Lines &lines, float z, bool generate_mesh = false);
bool init_model_from_lines(const Lines3 &lines, bool generate_mesh = false); bool init_model_from_lines(const Lines3 &lines, bool generate_mesh = false);
bool init_model_from_lines(const Line3floats &lines, bool generate_mesh = false);
// if entity_id == -1 set the color of all entities // if entity_id == -1 set the color of all entities
void set_color(int entity_id, const std::array<float, 4>& color); void set_color(int entity_id, const std::array<float, 4>& color);
void set_color(const ColorRGBA &color); void set_color(const ColorRGBA &color);

View File

@ -143,7 +143,9 @@ bool GLGizmoMmuSegmentation::on_init()
//add toggle wire frame hint //add toggle wire frame hint
m_desc["toggle_wireframe_caption"] = alt + _L("Shift + Enter"); m_desc["toggle_wireframe_caption"] = alt + _L("Shift + Enter");
m_desc["toggle_wireframe"] = _L("Toggle Wireframe"); m_desc["toggle_wireframe"] = _L("Toggle Wireframe");//"show_wireframe" in shader
m_desc["toggle_non_manifold_edges_caption"] = ctrl + _L("Shift + L");
m_desc["toggle_non_manifold_edges"] = _L("Toggle non-manifold edges");
init_extruders_data(); init_extruders_data();
@ -167,10 +169,54 @@ void GLGizmoMmuSegmentation::render_painter_gizmo() const
m_c->object_clipper()->render_cut(); m_c->object_clipper()->render_cut();
m_c->instances_hider()->render_cut(); m_c->instances_hider()->render_cut();
render_cursor(); render_cursor();
render_non_manifold_edges();
glsafe(::glDisable(GL_BLEND)); glsafe(::glDisable(GL_BLEND));
} }
void GLGizmoMmuSegmentation::render_non_manifold_edges() const {
if (wxGetApp().plater()->is_show_non_manifold_edges()) {
if (!m_non_manifold_edges_model.is_initialized()) {
const Selection & selection = m_parent.get_selection();
const ModelObject *mo = m_c->selection_info()->model_object();
Line3floats non_manifold_edges;
int idx = -1;
for (ModelVolume *mv : mo->volumes) {
if (mv->is_model_part()) {
++idx;
auto &triangle_selector = m_triangle_selectors[idx];
int max_orig_size_vertices = triangle_selector->get_orig_size_vertices();
auto neighbors = triangle_selector->get_neighbors();
auto vertices = triangle_selector->get_vertices();
auto triangles = triangle_selector->get_triangles();
auto world_tran = (mo->instances[selection.get_instance_idx()]->get_transformation().get_matrix() * mv->get_matrix()).cast<float>();
for (size_t i = 0; i < neighbors.size(); i++) {
auto nei = neighbors[i];
for (int j = 0; j < 3; j++) {
if (nei[j] < 0) {
auto jj = next_idx_modulo(j, 3);
auto v = world_tran * vertices[triangles[i].verts_idxs[j]].v;
auto next_v = world_tran * vertices[triangles[i].verts_idxs[jj]].v;
non_manifold_edges.emplace_back(Line3float(v, next_v));
}
}
}
}
}
m_non_manifold_edges_model.init_model_from_lines(non_manifold_edges);
m_non_manifold_edges_model.set_color(ColorRGBA::RED());
}
const Camera & camera = wxGetApp().plater()->get_camera();
auto view_mat = camera.get_view_matrix();
auto proj_mat = camera.get_projection_matrix();
GLShaderProgram *shader = wxGetApp().get_shader("flat");
shader->start_using();
shader->set_uniform("view_model_matrix", view_mat);
shader->set_uniform("projection_matrix", proj_mat);
m_non_manifold_edges_model.render_geometry();
shader->stop_using();
}
}
void GLGizmoMmuSegmentation::set_painter_gizmo_data(const Selection &selection) void GLGizmoMmuSegmentation::set_painter_gizmo_data(const Selection &selection)
{ {
GLGizmoPainterBase::set_painter_gizmo_data(selection); GLGizmoPainterBase::set_painter_gizmo_data(selection);
@ -364,17 +410,17 @@ void GLGizmoMmuSegmentation::show_tooltip_information(float caption_max, float x
std::vector<std::string> tip_items; std::vector<std::string> tip_items;
switch (m_tool_type) { switch (m_tool_type) {
case ToolType::BRUSH: case ToolType::BRUSH:
tip_items = {"paint", "erase", "cursor_size", "clipping_of_view", "toggle_wireframe"}; tip_items = {"paint", "erase", "cursor_size", "clipping_of_view", "toggle_wireframe", "toggle_non_manifold_edges"};
break; break;
case ToolType::BUCKET_FILL: case ToolType::BUCKET_FILL:
tip_items = {"paint", "erase", "smart_fill_angle", "clipping_of_view", "toggle_wireframe"}; tip_items = {"paint", "erase", "smart_fill_angle", "clipping_of_view", "toggle_wireframe", "toggle_non_manifold_edges"};
break; break;
case ToolType::SMART_FILL: case ToolType::SMART_FILL:
// TODO: // TODO:
break; break;
case ToolType::GAP_FILL: case ToolType::GAP_FILL:
tip_items = {"gap_area", "toggle_wireframe"}; tip_items = {"gap_area", "toggle_wireframe", "toggle_non_manifold_edges"};
break; break;
default: default:
break; break;
@ -958,9 +1004,10 @@ void GLGizmoMmuSegmentation::on_set_state()
GLGizmoPainterBase::on_set_state(); GLGizmoPainterBase::on_set_state();
if (get_state() == On) { if (get_state() == On) {
size_t n_extruder_colors = std::min((size_t) EnforcerBlockerType::ExtruderMax, m_extruders_colors.size()); size_t n_extruder_colors = std::min((size_t) EnforcerBlockerType::ExtruderMax, m_extruders_colors.size());
if (n_extruder_colors>=2) { if (n_extruder_colors>=2) {
m_selected_extruder_idx = 1; m_selected_extruder_idx = 1;
} }
m_non_manifold_edges_model.reset();
} }
else if (get_state() == Off) { else if (get_state() == Off) {
ModelObject* mo = m_c->selection_info()->model_object(); ModelObject* mo = m_c->selection_info()->model_object();

View File

@ -68,7 +68,7 @@ public:
~GLGizmoMmuSegmentation() override = default; ~GLGizmoMmuSegmentation() override = default;
void render_painter_gizmo() const override; void render_painter_gizmo() const override;
void render_non_manifold_edges() const;
void set_painter_gizmo_data(const Selection& selection) override; void set_painter_gizmo_data(const Selection& selection) override;
void render_triangles(const Selection& selection) const override; void render_triangles(const Selection& selection) const override;
@ -139,6 +139,7 @@ private:
// This map holds all translated description texts, so they can be easily referenced during layout calculations // This map holds all translated description texts, so they can be easily referenced during layout calculations
// etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect. // etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect.
std::map<std::string, wxString> m_desc; std::map<std::string, wxString> m_desc;
mutable GLModel m_non_manifold_edges_model;
}; };
} // namespace Slic3r } // namespace Slic3r

View File

@ -2296,7 +2296,7 @@ struct Plater::priv
bool show_render_statistic_dialog{ false }; bool show_render_statistic_dialog{ false };
bool show_wireframe{ false }; bool show_wireframe{ false };
bool wireframe_enabled{ true }; bool wireframe_enabled{ true };
bool show_non_manifold_edges{false};
static const std::regex pattern_bundle; static const std::regex pattern_bundle;
static const std::regex pattern_3mf; static const std::regex pattern_3mf;
static const std::regex pattern_zip_amf; static const std::regex pattern_zip_amf;
@ -13965,8 +13965,14 @@ bool Plater::is_render_statistic_dialog_visible() const
return p->show_render_statistic_dialog; return p->show_render_statistic_dialog;
} }
void Plater::toggle_show_wireframe() void Plater::toggle_non_manifold_edges() {
{ p->show_non_manifold_edges = !p->show_non_manifold_edges; }
bool Plater::is_show_non_manifold_edges() {
return p->show_non_manifold_edges;
}
void Plater::toggle_show_wireframe() {
p->show_wireframe = !p->show_wireframe; p->show_wireframe = !p->show_wireframe;
} }

View File

@ -699,6 +699,8 @@ public:
void toggle_render_statistic_dialog(); void toggle_render_statistic_dialog();
bool is_render_statistic_dialog_visible() const; bool is_render_statistic_dialog_visible() const;
void toggle_non_manifold_edges();
bool is_show_non_manifold_edges();
void toggle_show_wireframe(); void toggle_show_wireframe();
bool is_show_wireframe() const; bool is_show_wireframe() const;
void enable_wireframe(bool status); void enable_wireframe(bool status);