mirror of
https://git.mirrors.martin98.com/https://github.com/bambulab/BambuStudio.git
synced 2025-09-21 05:43:11 +08:00
NEW: add "render non_manifold_edges" function
jira: none Change-Id: I620e095740c60a8c9d4ceb33d6b3a44ab3d17f05 (cherry picked from commit f71b0fdeee18e3fb1482fa3e5f1121d33724b1a7)
This commit is contained in:
parent
498face4d6
commit
53d7c755a7
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
@ -365,16 +411,16 @@ 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;
|
||||||
@ -961,6 +1007,7 @@ void GLGizmoMmuSegmentation::on_set_state()
|
|||||||
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();
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user