-
Notifications
You must be signed in to change notification settings - Fork 235
/
Copy pathmesh_separate_mk2.py
140 lines (119 loc) · 5.36 KB
/
mesh_separate_mk2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# ##### 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 collections
import bpy
from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import updateNode, zip_long_repeat
from sverchok.utils.nodes_mixins.sockets_config import ModifierLiteNode
class SvSeparateMeshNodeMK2(ModifierLiteNode, SverchCustomTreeNode, bpy.types.Node):
'''Separate Loose mesh parts'''
bl_idname = 'SvSeparateMeshNodeMK2'
bl_label = 'Separate Loose Parts MK2'
bl_icon = 'OUTLINER_OB_EMPTY'
sv_icon = 'SV_SEPARATE_LOOSE_PARTS'
join : bpy.props.BoolProperty(
name = "Flat output",
description = "If checked, generate one flat list of loose parts for all input meshes; otherwise, generate separate list of loose parts for each input mesh",
default = True,
update = updateNode)
def draw_buttons(self, context, layout):
layout.prop(self, 'join')
def sv_init(self, context):
self.inputs.new('SvVerticesSocket', 'Vertices')
self.inputs.new('SvStringsSocket', 'Poly Egde')
self.outputs.new('SvVerticesSocket', 'Vertices')
self.outputs.new('SvStringsSocket', 'Poly Egde')
self.outputs.new('SvStringsSocket', 'Vert idx')
self.outputs.new('SvStringsSocket', 'Poly Egde idx')
def process(self):
if not any(s.is_linked for s in self.outputs):
return
verts = self.inputs['Vertices'].sv_get(deepcopy=False)
poly = self.inputs['Poly Egde'].sv_get(deepcopy=False)
verts_out = []
poly_edge_out = []
vert_index = []
poly_edge_index = []
for ve, pe in zip_long_repeat(verts, poly):
new_verts = []
new_polys = []
new_vert_indexes = []
new_poly_indexes = []
# build links
node_links = collections.defaultdict(set)
for edge_face in pe:
for i in edge_face:
node_links[i].update(edge_face)
nodes = set(node_links.keys())
n = nodes.pop()
node_set_list = [set([n])]
node_stack = collections.deque()
node_stack_append = node_stack.append
node_stack_pop = node_stack.pop
node_set = node_set_list[-1]
# find separate sets
while nodes:
for node in node_links[n]:
if node not in node_set:
node_stack_append(node)
if not node_stack: # new mesh part
n = nodes.pop()
node_set_list.append(set([n]))
node_set = node_set_list[-1]
else:
while node_stack and n in node_set:
n = node_stack_pop()
nodes.discard(n)
node_set.add(n)
# create new meshes from sets, new_pe is the slow line.
if len(node_set_list) > 1:
node_set_list.sort(key=lambda x: min(x))
for idx, node_set in enumerate(node_set_list):
mesh_index = sorted(node_set)
vert_dict = {j: i for i, j in enumerate(mesh_index)}
new_vert = [ve[i] for i in mesh_index]
new_pe = [[vert_dict[n] for n in fe]
for fe in pe
if fe[0] in node_set]
new_verts.append(new_vert)
new_polys.append(new_pe)
new_vert_indexes.append([idx for i in range(len(new_vert))])
new_poly_indexes.append([idx for face in new_pe])
elif node_set_list: # no reprocessing needed
new_verts.append(ve)
new_polys.append(pe)
new_vert_indexes.append([0 for i in range(len(ve))])
new_poly_indexes.append([0 for face in pe])
if self.join:
verts_out.extend(new_verts)
poly_edge_out.extend(new_polys)
vert_index.extend(new_vert_indexes)
poly_edge_index.extend(new_poly_indexes)
else:
verts_out.append(new_verts)
poly_edge_out.append(new_polys)
vert_index.append(new_vert_indexes)
poly_edge_index.append(new_poly_indexes)
self.outputs['Vertices'].sv_set(verts_out)
self.outputs['Poly Egde'].sv_set(poly_edge_out)
self.outputs['Vert idx'].sv_set(vert_index)
self.outputs['Poly Egde idx'].sv_set(poly_edge_index)
def register():
bpy.utils.register_class(SvSeparateMeshNodeMK2)
def unregister():
bpy.utils.unregister_class(SvSeparateMeshNodeMK2)