diff --git a/deps_src/libigl/igl/loop.cpp b/deps_src/libigl/igl/loop.cpp index b4233ca679..d377c72d22 100644 --- a/deps_src/libigl/igl/loop.cpp +++ b/deps_src/libigl/igl/loop.cpp @@ -18,7 +18,7 @@ template < typename DerivedF, typename SType, typename DerivedNF> -IGL_INLINE void igl::loop( +IGL_INLINE bool igl::loop( const int n_verts, const Eigen::PlainObjectBase & F, Eigen::SparseMatrix& S, @@ -26,15 +26,15 @@ IGL_INLINE void igl::loop( { typedef Eigen::SparseMatrix SparseMat; typedef Eigen::Triplet Triplet_t; - + //Ref. https://graphics.stanford.edu/~mdfisher/subdivision.html //Heavily borrowing from igl::upsample - + DerivedF FF, FFi; triangle_triangle_adjacency(F, FF, FFi); std::vector> adjacencyList; adjacency_list(F, adjacencyList, true); - + //Compute the number and positions of the vertices to insert (on edges) Eigen::MatrixXi NI = Eigen::MatrixXi::Constant(FF.rows(), FF.cols(), -1); Eigen::MatrixXi NIdoubles = Eigen::MatrixXi::Zero(FF.rows(), FF.cols()); @@ -48,12 +48,18 @@ IGL_INLINE void igl::loop( { NI(i,j) = counter; NIdoubles(i,j) = 0; - if (FF(i,j) != -1) + if (FF(i,j) != -1) { //If it is not a boundary - NI(FF(i,j), FFi(i,j)) = counter; - NIdoubles(i,j) = 1; - } else + int adj_triangle = FF(i, j); + int adj_edge = FFi(i, j); + if (adj_triangle >= 0 && adj_triangle < NI.rows() && adj_edge >= 0 && adj_edge < NI.cols()) { + NI(adj_triangle, adj_edge) = counter; + NIdoubles(i, j) = 1; + } else { + return false; + } + } else { //Mark boundary vertices for later vertIsOnBdry(F(i,j)) = 1; @@ -63,24 +69,24 @@ IGL_INLINE void igl::loop( } } } - + const int& n_odd = n_verts; const int& n_even = counter; const int n_newverts = n_odd + n_even; - + //Construct vertex positions std::vector tripletList; - for(int i=0; i& localAdjList = adjacencyList[i]; - if(vertIsOnBdry(i)==1) + if(vertIsOnBdry(i)==1) { //Boundary vertex tripletList.emplace_back(i, localAdjList.front(), 1./8.); tripletList.emplace_back(i, localAdjList.back(), 1./8.); tripletList.emplace_back(i, i, 3./4.); - } else + } else { const int n = localAdjList.size(); const SType dn = n; @@ -99,19 +105,19 @@ IGL_INLINE void igl::loop( tripletList.emplace_back(i, i, 1.-dn*beta); } } - for(int i=0; i -IGL_INLINE void igl::loop( +IGL_INLINE bool igl::loop( const Eigen::PlainObjectBase& V, const Eigen::PlainObjectBase& F, Eigen::PlainObjectBase& NV, @@ -158,16 +165,19 @@ IGL_INLINE void igl::loop( { NV = V; NF = F; - for(int i=0; i S; - loop(NV.rows(), tempF, S, NF); + if (!loop(NV.rows(), tempF, S, NF)) { + return false; + } // This .eval is super important NV = (S*NV).eval(); } + return true; } #ifdef IGL_STATIC_LIBRARY template void igl::loop, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, int); -#endif +#endif \ No newline at end of file diff --git a/deps_src/libigl/igl/loop.h b/deps_src/libigl/igl/loop.h index bc1616891a..6cf3741612 100644 --- a/deps_src/libigl/igl/loop.h +++ b/deps_src/libigl/igl/loop.h @@ -29,7 +29,7 @@ namespace igl typename DerivedF, typename SType, typename DerivedNF> - IGL_INLINE void loop( + IGL_INLINE bool loop( const int n_verts, const Eigen::PlainObjectBase & F, Eigen::SparseMatrix& S, @@ -44,11 +44,11 @@ namespace igl // NV a matrix containing the new vertices // NF a matrix containing the new faces template < - typename DerivedV, + typename DerivedV, typename DerivedF, typename DerivedNV, typename DerivedNF> - IGL_INLINE void loop( + IGL_INLINE bool loop( const Eigen::PlainObjectBase& V, const Eigen::PlainObjectBase& F, Eigen::PlainObjectBase& NV, diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 4ab335879d..5f9591452f 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -449,6 +449,8 @@ set(lisbslic3r_sources Timer.hpp TriangleMesh.cpp TriangleMesh.hpp + TriangleMeshDeal.cpp + TriangleMeshDeal.hpp TriangleMeshSlicer.cpp TriangleMeshSlicer.hpp TriangleSelector.cpp diff --git a/src/libslic3r/TriangleMeshDeal.cpp b/src/libslic3r/TriangleMeshDeal.cpp new file mode 100644 index 0000000000..046be9d5b0 --- /dev/null +++ b/src/libslic3r/TriangleMeshDeal.cpp @@ -0,0 +1,55 @@ +#include "TriangleMeshDeal.hpp" + +#include +#include +#include +#include + +namespace Slic3r { +TriangleMesh TriangleMeshDeal::smooth_triangle_mesh(const TriangleMesh &mesh, bool &ok) +{ + { + using namespace std; + using namespace igl; + Eigen::MatrixXi OF, F; + Eigen::MatrixXd OV, V; + auto vertices_count = mesh.its.vertices.size(); + OV = Eigen::MatrixXd(vertices_count, 3); + for (int i = 0; i < vertices_count; i++) { + auto v = mesh.its.vertices[i]; + OV.row(i) << v[0], v[1], v[2]; + } + auto indices_count = mesh.its.indices.size(); + OF = Eigen::MatrixXi(indices_count, 3); + for (int i = 0; i < indices_count; i++) { + auto face = mesh.its.indices[i]; + OF.row(i) << face[0], face[1], face[2]; + } + //igl:: read_triangle_mesh( "E:/Download/libigl-2.6.0/out/build/x64-Debug/_deps/libigl_tutorial_data-src/decimated-knight.off", OV, OF); + V = OV; + F = OF; + + //igl::upsample(Eigen::MatrixXd(V), Eigen::MatrixXi(F), V, F); + ok = true; + if (!igl::loop(Eigen::MatrixXd(V), Eigen::MatrixXi(F), V, F)) { + ok = false; + return TriangleMesh(); + } + //igl::false_barycentric_subdivision(Eigen::MatrixXd(V), Eigen::MatrixXi(F), V, F); + indexed_triangle_set its; + int vertex_count = V.rows(); + its.vertices.resize(vertex_count); + for (int i = 0; i < vertex_count; i++) { + its.vertices[i] = V.row(i).cast(); + } + int indice_count = F.rows(); + its.indices.resize(indice_count); + for (int i = 0; i < indice_count; i++) { + auto cur = F.row(i); + its.indices[i] = Slic3r::Vec3i32(cur[0], cur[1], cur[2]); + } + TriangleMesh result_mesh(its); + return result_mesh; + } + } +} // namespace Slic3r diff --git a/src/libslic3r/TriangleMeshDeal.hpp b/src/libslic3r/TriangleMeshDeal.hpp new file mode 100644 index 0000000000..b1da431229 --- /dev/null +++ b/src/libslic3r/TriangleMeshDeal.hpp @@ -0,0 +1,14 @@ +#ifndef libslic3r_Timer_hpp_ +#define libslic3r_Timer_hpp_ + +#include "TriangleMesh.hpp" + +namespace Slic3r { +class TriangleMeshDeal +{ +public: + static TriangleMesh smooth_triangle_mesh(const TriangleMesh &mesh,bool& ok); +}; +} // namespace Slic3r + +#endif // libslic3r_Timer_hpp_ diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index acc53d35b8..3d429e6e0b 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -1349,6 +1349,8 @@ void MenuFactory::create_extra_object_menu() append_menu_item_fix_through_netfabb(&m_object_menu); // Object Simplify append_menu_item_simplify(&m_object_menu); + // Object Mesh Subdivision + append_menu_item_smooth_mesh(&m_object_menu); // merge to single part append_menu_item_merge_parts_to_single_part(&m_object_menu); // Object Center @@ -1400,6 +1402,8 @@ void MenuFactory::create_bbl_assemble_object_menu() append_menu_item_fix_through_netfabb(&m_assemble_object_menu); // Object Simplify append_menu_item_simplify(&m_assemble_object_menu); + // Object Mesh Subdivision + append_menu_item_smooth_mesh(&m_assemble_object_menu); m_assemble_object_menu.AppendSeparator(); } @@ -1483,6 +1487,7 @@ void MenuFactory::create_bbl_part_menu() append_menu_item_edit_text(menu); append_menu_item_fix_through_netfabb(menu); append_menu_item_simplify(menu); + append_menu_item_smooth_mesh(menu); append_menu_item_center(menu); append_menu_item_drop(menu); append_menu_items_mirror(menu); @@ -1514,6 +1519,7 @@ void MenuFactory::create_bbl_assemble_part_menu() append_menu_item_delete(menu); append_menu_item_simplify(menu); + append_menu_item_smooth_mesh(menu); menu->AppendSeparator(); } @@ -1949,6 +1955,13 @@ void MenuFactory::append_menu_item_simplify(wxMenu* menu) []() {return plater()->can_simplify(); }, m_parent); } +void MenuFactory::append_menu_item_smooth_mesh(wxMenu *menu) +{ + wxMenuItem *menu_item = append_menu_item( + menu, wxID_ANY, _L("Subdivision mesh") + _L("(Lost color)"), "", [](wxCommandEvent &) { obj_list()->smooth_mesh(); }, "", menu, []() { return plater()->can_smooth_mesh(); }, + m_parent); +} + void MenuFactory::append_menu_item_center(wxMenu* menu) { append_menu_item(menu, wxID_ANY, _L("Center") , "", diff --git a/src/slic3r/GUI/GUI_Factories.hpp b/src/slic3r/GUI/GUI_Factories.hpp index 7f1947814d..0ae0e96a73 100644 --- a/src/slic3r/GUI/GUI_Factories.hpp +++ b/src/slic3r/GUI/GUI_Factories.hpp @@ -164,6 +164,7 @@ private: //BBS add bbl menu item void append_menu_item_clone(wxMenu* menu); void append_menu_item_simplify(wxMenu* menu); + void append_menu_item_smooth_mesh(wxMenu *menu); void append_menu_item_center(wxMenu* menu); void append_menu_item_drop(wxMenu* menu); void append_menu_item_per_object_process(wxMenu* menu); diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 4429faf1f5..58e058cc0c 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -44,6 +44,7 @@ #endif /* __WXMSW__ */ #include "Gizmos/GLGizmoScale.hpp" +#include "libslic3r/TriangleMeshDeal.hpp" namespace Slic3r { namespace GUI @@ -5931,6 +5932,92 @@ void ObjectList::simplify() gizmos_mgr.open_gizmo(GLGizmosManager::EType::Simplify); } +void GUI::ObjectList::smooth_mesh() +{ + wxBusyCursor cursor; + auto plater = wxGetApp().plater(); + if (!plater) { return; } + plater->take_snapshot("smooth_mesh"); + std::vector obj_idxs, vol_idxs; + get_selection_indexes(obj_idxs, vol_idxs); + auto object_idx = obj_idxs.front(); + ModelObject *obj{nullptr}; + auto show_warning_dlg = [this](int cur_face_count,std::string name,bool is_part) { + int limit_face_count = 1000000; + if (cur_face_count > limit_face_count) { + auto name_str = wxString::FromUTF8(name); + auto content = wxString::Format(_L("\"%s\" will exceed 1 million faces after this subdivision, which may increase slicing time. Do you want to continue?"), name_str); + WarningDialog dlg(static_cast(wxGetApp().mainframe), (is_part ? _L("Part") : _L("Object")) + " " + content, _L("BambuStudio warning"), wxYES_NO); + if (dlg.ShowModal() == wxID_NO) { + return true; + } + return false; + } + return false; + }; + auto show_smooth_mesh_error_dlg = [this](std::string name) { + auto name_str = wxString::FromUTF8(name); + auto content = wxString::Format(_L("\"%s\" part's mesh contains errors. Please repair it first."), name_str); + WarningDialog dlg(static_cast(wxGetApp().mainframe), content, _L("BambuStudio warning"), wxOK); + dlg.ShowModal(); + }; + bool has_show_smooth_mesh_error_dlg = false; + if (vol_idxs.empty()) { + obj = object(object_idx); + auto future_face_count = static_cast(obj->facets_count()) * 4; + if (show_warning_dlg(future_face_count, obj->name,false)) { + return; + } + for (auto mv : obj->volumes) { + bool ok; + auto result_mesh = TriangleMeshDeal::smooth_triangle_mesh(mv->mesh(), ok); + if (ok) { + mv->set_mesh(result_mesh); + mv->reset_extra_facets(); // reset paint color + mv->calculate_convex_hull(); + mv->invalidate_convex_hull_2d(); + mv->set_new_unique_id(); + } else { + if (!has_show_smooth_mesh_error_dlg) { + show_smooth_mesh_error_dlg(mv->name); + has_show_smooth_mesh_error_dlg = true; + } + } + } + obj->invalidate_bounding_box(); + obj->ensure_on_bed(); + plater->changed_mesh(object_idx); + } else { + obj = object(obj_idxs.front()); + for (int vol_idx : vol_idxs) { + auto mv = obj->volumes[vol_idx]; + auto future_face_count = static_cast(mv->mesh().facets_count()) * 4; + if (show_warning_dlg(future_face_count, mv->name,true)) { + return; + } + bool ok; + auto result_mesh = TriangleMeshDeal::smooth_triangle_mesh(mv->mesh(),ok); + if (ok) { + mv->set_mesh(result_mesh); + mv->reset_extra_facets(); // reset paint color + mv->calculate_convex_hull(); + mv->invalidate_convex_hull_2d(); + mv->set_new_unique_id(); + } else { + if (!has_show_smooth_mesh_error_dlg) { + show_smooth_mesh_error_dlg(mv->name); + has_show_smooth_mesh_error_dlg = true; + } + } + } + } + if (obj) { + obj->invalidate_bounding_box(); + obj->ensure_on_bed(); + plater->changed_mesh(object_idx); + } +} + void ObjectList::update_item_error_icon(const int obj_idx, const int vol_idx) const { auto obj = object(obj_idx); diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index 5824316385..1f84fff5d3 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -428,6 +428,7 @@ public: void rename_item(); void fix_through_netfabb(); void simplify(); + void smooth_mesh(); void update_item_error_icon(const int obj_idx, int vol_idx) const ; void copy_layers_to_clipboard(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 2b955dc412..c1b042a34e 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4640,6 +4640,7 @@ struct Plater::priv bool can_layers_editing() const; bool can_fix_through_netfabb() const; bool can_simplify() const; + bool can_smooth_mesh() const; bool can_set_instance_to_object() const; bool can_mirror() const; bool can_reload_from_disk() const; @@ -11035,6 +11036,24 @@ bool Plater::priv::can_simplify() const return true; } +bool Plater::priv::can_smooth_mesh() const +{ + std::vector obj_idxs, vol_idxs; + sidebar->obj_list()->get_selection_indexes(obj_idxs, vol_idxs); + if (vol_idxs.empty()) { + for (auto obj_idx : obj_idxs) + if (model.objects[obj_idx]->get_object_stl_stats().open_edges > 0) + return false; + return true; + } + + int obj_idx = obj_idxs.front(); + for (auto vol_idx : vol_idxs) + if (model.objects[obj_idx]->get_object_stl_stats().open_edges > 0) + return false; + return true; +} + bool Plater::priv::can_increase_instances() const { if (!m_worker.is_idle() @@ -17927,6 +17946,7 @@ bool Plater::can_decrease_instances() const { return p->can_decrease_instances() bool Plater::can_set_instance_to_object() const { return p->can_set_instance_to_object(); } bool Plater::can_fix_through_netfabb() const { return p->can_fix_through_netfabb(); } bool Plater::can_simplify() const { return p->can_simplify(); } +bool Plater::can_smooth_mesh() const { return p->can_smooth_mesh(); } bool Plater::can_split_to_objects() const { return p->can_split_to_objects(); } bool Plater::can_split_to_volumes() const { return p->can_split_to_volumes(); } bool Plater::can_arrange() const { return p->can_arrange(); } diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 6dccc59b2b..89b9f560c4 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -662,6 +662,7 @@ public: bool can_set_instance_to_object() const; bool can_fix_through_netfabb() const; bool can_simplify() const; + bool can_smooth_mesh() const; bool can_split_to_objects() const; bool can_split_to_volumes() const; bool can_arrange() const;