mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-28 11:21:30 +00:00
BBS Port: Mesh Subdivision (#12150)
Ported from BBS You can now right-click a part and choose Subdivide Part to apply Loop subdivision with multiple iterations. This is useful for models with low original mesh resolution. > [!NOTE] > 1. Only meshes without non-manifold edges are supported. > 2. Color attributes will be lost after subdivision. We recommend subdividing first, then painting and applying colors. Not perfect and it can break some features but a nice to have and we can improve it. https://github.com/user-attachments/assets/33f10e49-f6dc-44d3-8c21-9e12e1fe23dc Best case scenario a sphere: Each picture is a Mesh subdivision step over the other <img width="541" height="495" alt="260202_164257_orca-slicer" src="https://github.com/user-attachments/assets/e62b3f4d-ee6b-4451-95a4-40a154d3a405" /> <img width="541" height="495" alt="260202_164302_%pn" src="https://github.com/user-attachments/assets/f7399457-be8d-45e7-b93f-f42064dadd64" /> <img width="541" height="495" alt="260202_164306_%pn" src="https://github.com/user-attachments/assets/55370035-219f-4b7f-94f4-9b31733820d6" /> <img width="541" height="495" alt="260202_164310_%pn" src="https://github.com/user-attachments/assets/3be8c904-cc6f-4efe-b4f8-f390b50d310c" />
This commit is contained in:
@@ -18,7 +18,7 @@ template <
|
|||||||
typename DerivedF,
|
typename DerivedF,
|
||||||
typename SType,
|
typename SType,
|
||||||
typename DerivedNF>
|
typename DerivedNF>
|
||||||
IGL_INLINE void igl::loop(
|
IGL_INLINE bool igl::loop(
|
||||||
const int n_verts,
|
const int n_verts,
|
||||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||||
Eigen::SparseMatrix<SType>& S,
|
Eigen::SparseMatrix<SType>& S,
|
||||||
@@ -51,8 +51,14 @@ IGL_INLINE void igl::loop(
|
|||||||
if (FF(i,j) != -1)
|
if (FF(i,j) != -1)
|
||||||
{
|
{
|
||||||
//If it is not a boundary
|
//If it is not a boundary
|
||||||
NI(FF(i,j), FFi(i,j)) = counter;
|
int adj_triangle = FF(i, j);
|
||||||
NIdoubles(i,j) = 1;
|
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
|
} else
|
||||||
{
|
{
|
||||||
//Mark boundary vertices for later
|
//Mark boundary vertices for later
|
||||||
@@ -142,6 +148,7 @@ IGL_INLINE void igl::loop(
|
|||||||
NF.row((i*4)+2) = f2;
|
NF.row((i*4)+2) = f2;
|
||||||
NF.row((i*4)+3) = f3;
|
NF.row((i*4)+3) = f3;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <
|
template <
|
||||||
@@ -149,7 +156,7 @@ template <
|
|||||||
typename DerivedF,
|
typename DerivedF,
|
||||||
typename DerivedNV,
|
typename DerivedNV,
|
||||||
typename DerivedNF>
|
typename DerivedNF>
|
||||||
IGL_INLINE void igl::loop(
|
IGL_INLINE bool igl::loop(
|
||||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||||
Eigen::PlainObjectBase<DerivedNV>& NV,
|
Eigen::PlainObjectBase<DerivedNV>& NV,
|
||||||
@@ -162,10 +169,13 @@ IGL_INLINE void igl::loop(
|
|||||||
{
|
{
|
||||||
DerivedNF tempF = NF;
|
DerivedNF tempF = NF;
|
||||||
Eigen::SparseMatrix<typename DerivedV::Scalar> S;
|
Eigen::SparseMatrix<typename DerivedV::Scalar> S;
|
||||||
loop(NV.rows(), tempF, S, NF);
|
if (!loop(NV.rows(), tempF, S, NF)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// This .eval is super important
|
// This .eval is super important
|
||||||
NV = (S*NV).eval();
|
NV = (S*NV).eval();
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef IGL_STATIC_LIBRARY
|
#ifdef IGL_STATIC_LIBRARY
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ namespace igl
|
|||||||
typename DerivedF,
|
typename DerivedF,
|
||||||
typename SType,
|
typename SType,
|
||||||
typename DerivedNF>
|
typename DerivedNF>
|
||||||
IGL_INLINE void loop(
|
IGL_INLINE bool loop(
|
||||||
const int n_verts,
|
const int n_verts,
|
||||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||||
Eigen::SparseMatrix<SType>& S,
|
Eigen::SparseMatrix<SType>& S,
|
||||||
@@ -48,7 +48,7 @@ namespace igl
|
|||||||
typename DerivedF,
|
typename DerivedF,
|
||||||
typename DerivedNV,
|
typename DerivedNV,
|
||||||
typename DerivedNF>
|
typename DerivedNF>
|
||||||
IGL_INLINE void loop(
|
IGL_INLINE bool loop(
|
||||||
const Eigen::PlainObjectBase<DerivedV>& V,
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
||||||
const Eigen::PlainObjectBase<DerivedF>& F,
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
||||||
Eigen::PlainObjectBase<DerivedNV>& NV,
|
Eigen::PlainObjectBase<DerivedNV>& NV,
|
||||||
|
|||||||
@@ -449,6 +449,8 @@ set(lisbslic3r_sources
|
|||||||
Timer.hpp
|
Timer.hpp
|
||||||
TriangleMesh.cpp
|
TriangleMesh.cpp
|
||||||
TriangleMesh.hpp
|
TriangleMesh.hpp
|
||||||
|
TriangleMeshDeal.cpp
|
||||||
|
TriangleMeshDeal.hpp
|
||||||
TriangleMeshSlicer.cpp
|
TriangleMeshSlicer.cpp
|
||||||
TriangleMeshSlicer.hpp
|
TriangleMeshSlicer.hpp
|
||||||
TriangleSelector.cpp
|
TriangleSelector.cpp
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
#include "TriangleMeshDeal.hpp"
|
||||||
|
|
||||||
|
#include <igl/read_triangle_mesh.h>
|
||||||
|
#include <igl/loop.h>
|
||||||
|
#include <igl/upsample.h>
|
||||||
|
#include <igl/false_barycentric_subdivision.h>
|
||||||
|
|
||||||
|
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<float>();
|
||||||
|
}
|
||||||
|
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
|
||||||
@@ -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_
|
||||||
@@ -1349,6 +1349,8 @@ void MenuFactory::create_extra_object_menu()
|
|||||||
append_menu_item_fix_through_netfabb(&m_object_menu);
|
append_menu_item_fix_through_netfabb(&m_object_menu);
|
||||||
// Object Simplify
|
// Object Simplify
|
||||||
append_menu_item_simplify(&m_object_menu);
|
append_menu_item_simplify(&m_object_menu);
|
||||||
|
// Object Mesh Subdivision
|
||||||
|
append_menu_item_smooth_mesh(&m_object_menu);
|
||||||
// merge to single part
|
// merge to single part
|
||||||
append_menu_item_merge_parts_to_single_part(&m_object_menu);
|
append_menu_item_merge_parts_to_single_part(&m_object_menu);
|
||||||
// Object Center
|
// Object Center
|
||||||
@@ -1400,6 +1402,8 @@ void MenuFactory::create_bbl_assemble_object_menu()
|
|||||||
append_menu_item_fix_through_netfabb(&m_assemble_object_menu);
|
append_menu_item_fix_through_netfabb(&m_assemble_object_menu);
|
||||||
// Object Simplify
|
// Object Simplify
|
||||||
append_menu_item_simplify(&m_assemble_object_menu);
|
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();
|
m_assemble_object_menu.AppendSeparator();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1483,6 +1487,7 @@ void MenuFactory::create_bbl_part_menu()
|
|||||||
append_menu_item_edit_text(menu);
|
append_menu_item_edit_text(menu);
|
||||||
append_menu_item_fix_through_netfabb(menu);
|
append_menu_item_fix_through_netfabb(menu);
|
||||||
append_menu_item_simplify(menu);
|
append_menu_item_simplify(menu);
|
||||||
|
append_menu_item_smooth_mesh(menu);
|
||||||
append_menu_item_center(menu);
|
append_menu_item_center(menu);
|
||||||
append_menu_item_drop(menu);
|
append_menu_item_drop(menu);
|
||||||
append_menu_items_mirror(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_delete(menu);
|
||||||
append_menu_item_simplify(menu);
|
append_menu_item_simplify(menu);
|
||||||
|
append_menu_item_smooth_mesh(menu);
|
||||||
menu->AppendSeparator();
|
menu->AppendSeparator();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1949,6 +1955,13 @@ void MenuFactory::append_menu_item_simplify(wxMenu* menu)
|
|||||||
[]() {return plater()->can_simplify(); }, m_parent);
|
[]() {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)
|
void MenuFactory::append_menu_item_center(wxMenu* menu)
|
||||||
{
|
{
|
||||||
append_menu_item(menu, wxID_ANY, _L("Center") , "",
|
append_menu_item(menu, wxID_ANY, _L("Center") , "",
|
||||||
|
|||||||
@@ -164,6 +164,7 @@ private:
|
|||||||
//BBS add bbl menu item
|
//BBS add bbl menu item
|
||||||
void append_menu_item_clone(wxMenu* menu);
|
void append_menu_item_clone(wxMenu* menu);
|
||||||
void append_menu_item_simplify(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_center(wxMenu* menu);
|
||||||
void append_menu_item_drop(wxMenu* menu);
|
void append_menu_item_drop(wxMenu* menu);
|
||||||
void append_menu_item_per_object_process(wxMenu* menu);
|
void append_menu_item_per_object_process(wxMenu* menu);
|
||||||
|
|||||||
@@ -44,6 +44,7 @@
|
|||||||
#endif /* __WXMSW__ */
|
#endif /* __WXMSW__ */
|
||||||
#include "Gizmos/GLGizmoScale.hpp"
|
#include "Gizmos/GLGizmoScale.hpp"
|
||||||
|
|
||||||
|
#include "libslic3r/TriangleMeshDeal.hpp"
|
||||||
namespace Slic3r
|
namespace Slic3r
|
||||||
{
|
{
|
||||||
namespace GUI
|
namespace GUI
|
||||||
@@ -5931,6 +5932,92 @@ void ObjectList::simplify()
|
|||||||
gizmos_mgr.open_gizmo(GLGizmosManager::EType::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<int> 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<wxWindow *>(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<wxWindow *>(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<int>(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<int>(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
|
void ObjectList::update_item_error_icon(const int obj_idx, const int vol_idx) const
|
||||||
{
|
{
|
||||||
auto obj = object(obj_idx);
|
auto obj = object(obj_idx);
|
||||||
|
|||||||
@@ -428,6 +428,7 @@ public:
|
|||||||
void rename_item();
|
void rename_item();
|
||||||
void fix_through_netfabb();
|
void fix_through_netfabb();
|
||||||
void simplify();
|
void simplify();
|
||||||
|
void smooth_mesh();
|
||||||
void update_item_error_icon(const int obj_idx, int vol_idx) const ;
|
void update_item_error_icon(const int obj_idx, int vol_idx) const ;
|
||||||
|
|
||||||
void copy_layers_to_clipboard();
|
void copy_layers_to_clipboard();
|
||||||
|
|||||||
@@ -4640,6 +4640,7 @@ struct Plater::priv
|
|||||||
bool can_layers_editing() const;
|
bool can_layers_editing() const;
|
||||||
bool can_fix_through_netfabb() const;
|
bool can_fix_through_netfabb() const;
|
||||||
bool can_simplify() const;
|
bool can_simplify() const;
|
||||||
|
bool can_smooth_mesh() const;
|
||||||
bool can_set_instance_to_object() const;
|
bool can_set_instance_to_object() const;
|
||||||
bool can_mirror() const;
|
bool can_mirror() const;
|
||||||
bool can_reload_from_disk() const;
|
bool can_reload_from_disk() const;
|
||||||
@@ -11035,6 +11036,24 @@ bool Plater::priv::can_simplify() const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Plater::priv::can_smooth_mesh() const
|
||||||
|
{
|
||||||
|
std::vector<int> 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
|
bool Plater::priv::can_increase_instances() const
|
||||||
{
|
{
|
||||||
if (!m_worker.is_idle()
|
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_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_fix_through_netfabb() const { return p->can_fix_through_netfabb(); }
|
||||||
bool Plater::can_simplify() const { return p->can_simplify(); }
|
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_objects() const { return p->can_split_to_objects(); }
|
||||||
bool Plater::can_split_to_volumes() const { return p->can_split_to_volumes(); }
|
bool Plater::can_split_to_volumes() const { return p->can_split_to_volumes(); }
|
||||||
bool Plater::can_arrange() const { return p->can_arrange(); }
|
bool Plater::can_arrange() const { return p->can_arrange(); }
|
||||||
|
|||||||
@@ -662,6 +662,7 @@ public:
|
|||||||
bool can_set_instance_to_object() const;
|
bool can_set_instance_to_object() const;
|
||||||
bool can_fix_through_netfabb() const;
|
bool can_fix_through_netfabb() const;
|
||||||
bool can_simplify() const;
|
bool can_simplify() const;
|
||||||
|
bool can_smooth_mesh() const;
|
||||||
bool can_split_to_objects() const;
|
bool can_split_to_objects() const;
|
||||||
bool can_split_to_volumes() const;
|
bool can_split_to_volumes() const;
|
||||||
bool can_arrange() const;
|
bool can_arrange() const;
|
||||||
|
|||||||
Reference in New Issue
Block a user