Skip to content

Commit

Permalink
New Mesh Clean Node (#4012)
Browse files Browse the repository at this point in the history
* Mesh Clean Node

* docs example
  • Loading branch information
vicdoval authored Apr 3, 2021
1 parent 899cf54 commit abadcd6
Show file tree
Hide file tree
Showing 8 changed files with 416 additions and 23 deletions.
13 changes: 13 additions & 0 deletions data_structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
array as np_array,
newaxis as np_newaxis,
ndarray,
ones as np_ones,
arange as np_arange,
repeat as np_repeat,
concatenate as np_concatenate,
tile as np_tile,
Expand Down Expand Up @@ -814,6 +816,17 @@ def apply_mask(mask, lst):
bad.append(item)
return good, bad

def invert_index_list(indexes, length):
'''
Inverts indexes list
indexes: List[Int] of Ndarray flat numpy array
length: Int. Length of the base list
'''
mask = np_ones(length, dtype='bool')
mask[indexes] = False
inverted_indexes = np_arange(length)[mask]
return inverted_indexes

def rotate_list(l, y=1):
"""
"Rotate" list by shifting it's items towards the end and putting last items to the beginning.
Expand Down
46 changes: 46 additions & 0 deletions docs/nodes/modifier_change/mesh_clean.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
Mesh Clean
==========

Functionality
-------------

Cleans input mesh by removing doubled, unreferenced or bad formed elements.

Options
-------

**Unreferenced Edges**: Remove the edges that point to un-existing vertices.

**Unreferenced Faces**: Remove the faces that point to un-existing vertices.

**Duplicated Edges**: Remove duplicated edges. Note that edges as (0,1) and (1,0) will be considered identical.

**Duplicated Faces**: Remove duplicated faces. Note that faces as (0,1,2,3) and (1,0,3,2) will be considered identical.

**Degenerated Edges**: Check for edges with repeated indices and remove them.

**Degenerated Faces**: Check for repeated indices on every face and remove them, if it has less than 3 vertices then the face will be removed

**Unused Vertices**: Removes the vertices not used to create any edge or face.


Inputs
------

Vertices, Edges and Faces

Outputs
-------

Vertices, Edges and Faces: Cleaned Mesh Data

Removed Vertices Idx: the index of the removed vertices

Removed Edges Idx: the index of the removed edges

Removed Faces Idx: the index of the removed faces

Examples
--------

.. image:: https://user-images.githubusercontent.com/10011941/113458705-739eab80-9413-11eb-8605-03d4be6b33a9.png
1 change: 1 addition & 0 deletions docs/nodes/modifier_change/modifier_change_index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Modifier Change
smooth
relax_mesh
delete_loose
mesh_clean
edges_intersect_mk2
poke
extrude_edges_mk2
Expand Down
1 change: 1 addition & 0 deletions index.md
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@
## Modifier Change
SvDeleteLooseNode
SvMergeByDistanceNode
SvMeshCleanNode
SvSeparateMeshNode
SvSeparatePartsToIndexes
SvEdgenetToPathsNode
Expand Down
2 changes: 0 additions & 2 deletions nodes/modifier_change/limited_dissolve.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import updateNode, match_long_repeat
from sverchok.utils.sv_bmesh_utils import bmesh_from_pydata, pydata_from_bmesh
from sverchok.utils.sv_mesh_utils import get_unique_faces


class SvLimitedDissolve(bpy.types.Node, SverchCustomTreeNode):
Expand Down Expand Up @@ -68,7 +67,6 @@ def process(self):
use_dissolve_boundaries=self.use_dissolve_boundaries,
verts=bm.verts, edges=bm.edges)
new_verts, new_edges, new_faces = pydata_from_bmesh(bm)
new_faces = get_unique_faces(new_faces)
bm.free()

r_verts.append(new_verts)
Expand Down
132 changes: 132 additions & 0 deletions nodes/modifier_change/mesh_clean.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####




import bpy
from bpy.props import BoolProperty

from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import updateNode
from sverchok.utils.nodes_mixins.recursive_nodes import SvRecursiveNode
from sverchok.utils.sv_mesh_utils import clean_meshes


class SvMeshCleanNode(bpy.types.Node, SverchCustomTreeNode, SvRecursiveNode):
'''
Triggers: Duplicated + unreferenced
Tooltip: Cleans input mesh by removing doubled, unreferenced or bad formed elements
'''
bl_idname = 'SvMeshCleanNode'
bl_label = 'Mesh Clean'
bl_icon = 'SHADING_RENDERED'

remove_unreferenced_edges: BoolProperty(
name='Unreferenced Edges',
description='Remove the edges that point to un-existing vertices',
default=False,
update=updateNode)
remove_unreferenced_faces: BoolProperty(
name='Unreferenced Faces',
description='Remove the faces that point to un-existing vertices',
default=False,
update=updateNode)

remove_loose_verts: BoolProperty(
name='Unused Vertices',
description='Removes the vertices not used to create any edge or face',
default=False,
update=updateNode)


remove_duplicated_edges: BoolProperty(
name='Duplicated Edges',
description='Remove duplicated edges. Note that (0,1) and (1,0) will be considered identical.',
default=False,
update=updateNode)
remove_duplicated_faces: BoolProperty(
name='Duplicated Faces',
description='Remove duplicated faces. Note that faces as (0,1,2,3) and (1,0,3,2) will be considered identical.',
default=False,
update=updateNode)

remove_degenerated_edges: BoolProperty(
name='Degenerated Edges',
description='Check for edges with repeated indices and remove them',
default=False,
update=updateNode)
remove_degenerated_faces: BoolProperty(
name='Degenerated Faces',
description='Check for repeated indices on every face and remove them, if it has less than 3 vertices then the face will be removed',
default=False,
update=updateNode)

def sv_init(self, context):
self.inputs.new('SvVerticesSocket', "Vertices").is_mandatory = True
self.inputs.new('SvStringsSocket', "Edges").nesting_level = 3
self.inputs.new('SvStringsSocket', "Faces").nesting_level = 3

self.outputs.new('SvVerticesSocket', "Vertices")
self.outputs.new('SvStringsSocket', "Edges")
self.outputs.new('SvStringsSocket', "Faces")

self.outputs.new('SvStringsSocket', "Removed Vertices Idx")
self.outputs.new('SvStringsSocket', "Removed Edges Idx")
self.outputs.new('SvStringsSocket', "Removed Faces Idx")

def draw_buttons(self, context, layout):
col = layout.column(align=True)
col.label(text='Remove:')
col.prop(self, 'remove_unreferenced_edges', toggle=True)
col.prop(self, 'remove_unreferenced_faces', toggle=True)
col.prop(self, 'remove_duplicated_edges', toggle=True)
col.prop(self, 'remove_duplicated_faces', toggle=True)
col.prop(self, 'remove_degenerated_edges', toggle=True)
col.prop(self, 'remove_degenerated_faces', toggle=True)
col.prop(self, 'remove_loose_verts', toggle=True)

def draw_buttons_ext(self, context, layout):
layout.prop(self, 'list_match')

def rclick_menu(self, context, layout):
layout.prop_menu_enum(self, "list_match", text="List Match")


def process_data(self, params):
vertices, edges, faces = params
calc_verts_idx, calc_edges_idx, calc_faces_idx = [s.is_linked for s in self.outputs[3:]]
return clean_meshes(
vertices, edges, faces,
remove_unreferenced_edges=self.remove_unreferenced_edges,
remove_unreferenced_faces=self.remove_unreferenced_faces,
remove_duplicated_edges=self.remove_duplicated_edges,
remove_duplicated_faces=self.remove_duplicated_faces,
remove_degenerated_edges=self.remove_degenerated_edges,
remove_degenerated_faces=self.remove_degenerated_faces,
remove_loose_verts=self.remove_loose_verts,
calc_verts_idx=calc_verts_idx,
calc_edges_idx=calc_edges_idx,
calc_faces_idx=calc_faces_idx)

def register():
bpy.utils.register_class(SvMeshCleanNode)


def unregister():
bpy.utils.unregister_class(SvMeshCleanNode)
3 changes: 0 additions & 3 deletions nodes/modifier_change/triangulate.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@

from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import updateNode, match_long_repeat, repeat_last_for_length
from sverchok.utils.sv_mesh_utils import get_unique_faces
from sverchok.utils.sv_bmesh_utils import bmesh_from_pydata, pydata_from_bmesh


Expand Down Expand Up @@ -126,8 +125,6 @@ def process(self):
new_face_data = []
bm.free()

new_faces = get_unique_faces(new_faces)

result_vertices.append(new_vertices)
result_edges.append(new_edges)
result_faces.append(new_faces)
Expand Down
Loading

0 comments on commit abadcd6

Please sign in to comment.