From bc644d8e41e1d387f83fc4ffff7baf130b6f5bc9 Mon Sep 17 00:00:00 2001 From: satabol Date: Thu, 21 Sep 2023 23:07:03 +0300 Subject: [PATCH] - fix #3288 - Create library function separate_loose_mesh.py --- nodes/modifier_change/extrude_region.py | 26 +++++++ nodes/modifier_change/mesh_separate.py | 90 +++++++++++++------------ utils/mesh/separate_loose_mesh.py | 81 ++++++++++++++++++++++ 3 files changed, 155 insertions(+), 42 deletions(-) create mode 100644 utils/mesh/separate_loose_mesh.py diff --git a/nodes/modifier_change/extrude_region.py b/nodes/modifier_change/extrude_region.py index bd7a50aa0a..08497fb869 100644 --- a/nodes/modifier_change/extrude_region.py +++ b/nodes/modifier_change/extrude_region.py @@ -27,6 +27,8 @@ from sverchok.data_structure import updateNode, match_long_repeat, repeat_last_for_length from sverchok.utils.sv_bmesh_utils import bmesh_from_pydata, pydata_from_bmesh from sverchok.utils.nodes_mixins.sockets_config import ModifierNode +from sverchok.utils.mesh.separate_loose_mesh import separate_loose_mesh +import numpy as np is_290 = bpy.app.version >= (2, 90, 0) @@ -217,6 +219,16 @@ def process(self): if face_data: face_data_matched = repeat_last_for_length(face_data, len(faces)) + need_fake_face = True + loops = [[faces]] + if need_fake_face: + _, _, loops = separate_loose_mesh(vertices, faces) + + for loop in loops: + vertices.append( vertices[loop[0][0]] ) + faces.append( [loop[0][0], loop[0][1], len(vertices)-1] ) # face area is zero but this is not important. It will not extrude. + mask_matched.append(False) + bm = bmesh_from_pydata(vertices, edges, faces, normal_update=True, markup_face_data=True) mask_layer = bm.faces.layers.int.new('mask') bm.faces.ensure_lookup_table() @@ -295,6 +307,20 @@ def process(self): extrude_geom = new_geom + if need_fake_face: + for loop in loops: + bm.verts.ensure_lookup_table() + bm.verts.remove(bm.verts[len(vertices)-1]) + vertices.pop() + faces.pop() + mask_matched.pop() + + bm.verts.index_update() + bm.edges.index_update() + bm.faces.index_update() + bm.verts.ensure_lookup_table() + bm.faces.ensure_lookup_table() + if face_data: new_vertices, new_edges, new_faces, new_face_data = pydata_from_bmesh(bm, face_data_matched) else: diff --git a/nodes/modifier_change/mesh_separate.py b/nodes/modifier_change/mesh_separate.py index 0b1af6921a..e756bee198 100644 --- a/nodes/modifier_change/mesh_separate.py +++ b/nodes/modifier_change/mesh_separate.py @@ -23,6 +23,7 @@ from sverchok.node_tree import SverchCustomTreeNode from sverchok.data_structure import zip_long_repeat from sverchok.utils.nodes_mixins.sockets_config import ModifierLiteNode +from sverchok.utils.mesh.separate_loose_mesh import separate_loose_mesh class SvSeparateMeshNode(ModifierLiteNode, SverchCustomTreeNode, bpy.types.Node): @@ -47,49 +48,54 @@ def process(self): verts_out = [] poly_edge_out = [] for ve, pe in zip_long_repeat(verts, poly): - # build links - node_links = {} - for edge_face in pe: - for i in edge_face: - if i not in node_links: - node_links[i] = set() - node_links[i].update(edge_face) + # # build links + # node_links = {} + # for edge_face in pe: + # for i in edge_face: + # if i not in node_links: + # node_links[i] = set() + # 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: - for node_set in 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] - verts_out.append(new_vert) - poly_edge_out.append(new_pe) - elif node_set_list: # no reprocessing needed - verts_out.append(ve) - poly_edge_out.append(pe) + # 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: + # for node_set in 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] + # verts_out.append(new_vert) + # poly_edge_out.append(new_pe) + # elif node_set_list: # no reprocessing needed + # verts_out.append(ve) + # poly_edge_out.append(pe) + + vo, po, _ = separate_loose_mesh(ve, pe) + verts_out.extend(vo) + poly_edge_out.extend(po) + self.outputs['Vertices'].sv_set(verts_out) self.outputs['Poly Egde'].sv_set(poly_edge_out) diff --git a/utils/mesh/separate_loose_mesh.py b/utils/mesh/separate_loose_mesh.py new file mode 100644 index 0000000000..1c7527170c --- /dev/null +++ b/utils/mesh/separate_loose_mesh.py @@ -0,0 +1,81 @@ +# ##### 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 zip_long_repeat +from sverchok.utils.nodes_mixins.sockets_config import ModifierLiteNode + +def separate_loose_mesh(verts_in, poly_edge_in): + verts_out = [] + poly_edge_out = [] + poly_edge_old_indexes_out = [] # faces with old indices + + # build links + node_links = {} + for edge_face in poly_edge_in: + for i in edge_face: + if i not in node_links: + node_links[i] = set() + 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: + for node_set in node_set_list: + mesh_index = sorted(node_set) + vert_dict = {j: i for i, j in enumerate(mesh_index)} + new_vert = [verts_in[i] for i in mesh_index] + new_pe = [[vert_dict[n] for n in fe] + for fe in poly_edge_in + if fe[0] in node_set] + old_pe = [fe for fe in poly_edge_in + if fe[0] in node_set] + verts_out.append(new_vert) + poly_edge_out.append(new_pe) + poly_edge_old_indexes_out.append(old_pe) + elif node_set_list: # no reprocessing needed + verts_out.append(verts_in) + poly_edge_out.append(poly_edge_in) + poly_edge_old_indexes_out.append(poly_edge_in) + + return verts_out, poly_edge_out, poly_edge_old_indexes_out + \ No newline at end of file