Skip to content

Commit

Permalink
Merge pull request #5097 from nortikin/fix_5088_Voronoi_On_Mesh_Appen…
Browse files Browse the repository at this point in the history
…d_input_socket_for_mask

fix 5088. Voronoi On Mesh. Appended input socket to mask sites
  • Loading branch information
satabol committed Apr 6, 2024
2 parents 86fb2ee + cd3a298 commit 8c254b4
Show file tree
Hide file tree
Showing 7 changed files with 355 additions and 50 deletions.
10 changes: 8 additions & 2 deletions docs/nodes/spatial/voronoi_on_mesh_mk2.rst
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
Voronoi on Mesh
===============

.. image:: https://github.com/nortikin/sverchok/assets/14288520/3782710e-2a14-4bea-a835-37ac6ff715b4
:target: https://github.com/nortikin/sverchok/assets/14288520/3782710e-2a14-4bea-a835-37ac6ff715b4
.. image:: https://github.com/nortikin/sverchok/assets/14288520/c907cc2d-7493-4117-a20f-b5e760a47d28
:target: https://github.com/nortikin/sverchok/assets/14288520/c907cc2d-7493-4117-a20f-b5e760a47d28

Dependencies
------------
Expand All @@ -29,6 +29,12 @@ This node has the following inputs:

* **Vertices**. Vertices of the mesh to generate Voronoi diagram on. This input is mandatory.
* **Faces**. Faces of the mesh to generate Voronoi diagram on. This input is mandatory.
* **Mask**. List of True/False. What Sites will visible.

.. image:: https://github.com/nortikin/sverchok/assets/14288520/cc788894-acc7-4b1f-a1c0-fb5756e42eb2
:target: https://github.com/nortikin/sverchok/assets/14288520/cc788894-acc7-4b1f-a1c0-fb5756e42eb2


* **Sites**. The points to generate Voronoi diagram for. Usually you want for
this points to lie either inside the mesh or on it's surface, but this is not
necessary. This input is mandatory.
Expand Down
2 changes: 1 addition & 1 deletion index.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@
- SvExVoronoi3DNode
- SvExVoronoiSphereNode
- SvVoronoiOnSurfaceNode
- SvVoronoiOnMeshNodeMK2
- SvVoronoiOnMeshNodeMK3
- SvVoronoiOnSolidNodeMK2
- ---
- SvLloyd2dNode
Expand Down
2 changes: 1 addition & 1 deletion menus/full_by_data_type.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@
- SvExVoronoi3DNode
- SvExVoronoiSphereNode
- SvVoronoiOnSurfaceNode
- SvVoronoiOnMeshNodeMK2
- SvVoronoiOnMeshNodeMK3
- SvVoronoiOnSolidNodeMK2
- ---
- SvLloyd2dNode
Expand Down
2 changes: 1 addition & 1 deletion menus/full_nortikin.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@
- SvExVoronoi3DNode
- SvExVoronoiSphereNode
- SvVoronoiOnSurfaceNode
- SvVoronoiOnMeshNodeMK2
- SvVoronoiOnMeshNodeMK3
- SvVoronoiOnSolidNodeMK2
- ---
- SvLloyd2dNode
Expand Down
109 changes: 90 additions & 19 deletions nodes/spatial/voronoi_on_mesh_mk2.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,15 @@
from sverchok.utils.sv_bmesh_utils import recalc_normals
from sverchok.utils.sv_mesh_utils import mesh_join
from sverchok.utils.voronoi3d import voronoi_on_mesh
import numpy as np


class SvVoronoiOnMeshNodeMK2(SverchCustomTreeNode, bpy.types.Node):
class SvVoronoiOnMeshNodeMK3(SverchCustomTreeNode, bpy.types.Node):
"""
Triggers: Voronoi Mesh
Tooltip: Generate Voronoi diagram on the surface of a mesh object
"""
bl_idname = 'SvVoronoiOnMeshNodeMK2'
bl_idname = 'SvVoronoiOnMeshNodeMK3'
bl_label = 'Voronoi on Mesh'
bl_icon = 'OUTLINER_OB_EMPTY'
sv_icon = 'SV_VORONOI'
Expand Down Expand Up @@ -80,6 +81,30 @@ def update_sockets(self, context):
default = 'FLAT',
update = updateNode)

def updateMaskMode(self, context):
if self.mask_mode=='MASK':
self.inputs["Mask"].label = "Mask of Sites"
elif self.mask_mode=='INDEXES':
self.inputs["Mask"].label = "Indexes of Sites"
updateNode(self, context)

mask_modes = [
('MASK', "Mask of sites", "Boolean value (0/1) to mask of sites", 0),
('INDEXES', "Index of sites", "Indexes of sites to mask", 1),
]
mask_mode : EnumProperty(
name = "Mask mode",
items = mask_modes,
default = 'MASK',
update = updateMaskMode)

mask_inversion : BoolProperty(
name = "Inversion",
default = False,
description="Invert mask of sites",
update = updateNode)


accuracy : IntProperty(
name = "Accuracy",
description = "Accuracy for mesh bisecting procedure",
Expand All @@ -92,16 +117,21 @@ def sv_init(self, context):
self.inputs.new('SvStringsSocket', 'Faces')
self.inputs.new('SvVerticesSocket', "Sites")
# self.inputs.new('SvStringsSocket', 'Thickness').prop_name = 'thickness'
self.inputs.new('SvStringsSocket', "Mask").label = "Mask of Sites"
self.inputs.new('SvStringsSocket', 'Spacing').prop_name = 'spacing'
self.outputs.new('SvVerticesSocket', "Vertices")
self.outputs.new('SvStringsSocket', "Edges")
self.outputs.new('SvStringsSocket', "Faces")
self.outputs.new('SvStringsSocket', "Sites_idx")
self.outputs.new('SvStringsSocket', "Sites_verts")
self.update_sockets(context)

def draw_buttons(self, context, layout):
layout.label(text="Mode:")
layout.prop(self, "mode", text='')
split = layout.column().split(factor=0.6)
split.column().prop(self, "mask_mode", text='')
split.column().prop(self, "mask_inversion", text='Invert')
if self.mode == 'VOLUME':
layout.prop(self, 'normals')
layout.label(text='Output nesting:')
Expand All @@ -119,6 +149,13 @@ def process(self):
verts_in = self.inputs['Vertices'].sv_get(deepcopy=False)
faces_in = self.inputs['Faces'].sv_get(deepcopy=False)
sites_in = self.inputs['Sites'].sv_get(deepcopy=False)

mask_in = self.inputs['Mask'] #.sv_get(deepcopy=False)
if mask_in.is_linked==False:
mask_in = [[[]]]
else:
mask_in = mask_in.sv_get(deepcopy=False)

#thickness_in = self.inputs['Thickness'].sv_get()
spacing_in = self.inputs['Spacing'].sv_get(deepcopy=False)

Expand All @@ -128,6 +165,7 @@ def process(self):
faces_in = ensure_nesting_level(faces_in, 4)
#thickness_in = ensure_nesting_level(thickness_in, 2)
spacing_in = ensure_min_nesting(spacing_in, 2)
mask_in = ensure_min_nesting(mask_in, 3)

nested_output = input_level > 3

Expand All @@ -137,57 +175,90 @@ def process(self):
edges_out = []
faces_out = []
sites_idx_out = []
for params in zip_long_repeat(verts_in, faces_in, sites_in, spacing_in):
sites_verts_out = []
for params in zip_long_repeat(verts_in, faces_in, sites_in, spacing_in, mask_in):
new_verts = []
new_edges = []
new_faces = []
new_sites = []
for verts, faces, sites, spacing in zip_long_repeat(*params):
verts, edges, faces, used_sites_idx = voronoi_on_mesh(verts, faces, sites, thickness=0,
new_sites_idx = []
new_sites_verts = []
for verts, faces, sites, spacing, mask in zip_long_repeat(*params):
# if mask is zero or not connected then do not mask any. Except of inversion,
if not mask:
np_mask = np.ones(len(sites), dtype=bool)
if self.mask_inversion==True:
np_mask = np.invert(np_mask)
mask = np_mask.tolist()
else:
if self.mask_mode=='MASK':
if self.mask_inversion==True:
mask = list( map( lambda v: False if v==0 else True, mask) )
mask = mask[:len(sites)]
np_mask = np.zeros(len(sites), dtype=bool)
np_mask[0:len(mask)]=mask
np_mask = np.invert(np_mask)
mask = np_mask.tolist()
pass
elif self.mask_mode=='INDEXES':
mask_len = len(sites)
mask_range = []
for x in mask:
if -mask_len<x<mask_len:
mask_range.append(x)
np_mask = np.ones(len(sites), dtype=bool)
np_mask[mask_range] = False
if self.mask_inversion==True:
np_mask = np.invert(np_mask)
mask = np_mask.tolist()

verts, edges, faces, used_sites_idx, used_sites_verts = voronoi_on_mesh(verts, faces, sites, thickness=0,
spacing = spacing,
#clip_inner = self.clip_inner, clip_outer = self.clip_outer,
do_clip=True, clipping=None,
mode = self.mode,
normal_update = self.normals,
precision = precision)
precision = precision,
mask = mask
)

if self.join_mode == 'FLAT':
new_verts.extend(verts)
new_edges.extend(edges)
new_faces.extend(faces)
new_sites.extend([[idx] for idx in used_sites_idx])
new_sites_idx.extend([[idx] for idx in used_sites_idx])
new_sites_verts.extend([[idx] for idx in used_sites_verts])
elif self.join_mode == 'SEPARATE':
new_verts.append(verts)
new_edges.append(edges)
new_faces.append(faces)
new_sites.append(used_sites_idx)
new_sites_idx.append(used_sites_idx)
new_sites_verts.append(used_sites_verts)
else: # JOIN
verts, edges, faces = mesh_join(verts, edges, faces)
new_verts.append(verts)
new_edges.append(edges)
new_faces.append(faces)
new_sites.append(used_sites_idx)
new_sites_idx.append(used_sites_idx)
new_sites_verts.append(used_sites_verts)

if nested_output:
verts_out.append(new_verts)
edges_out.append(new_edges)
faces_out.append(new_faces)
sites_idx_out.append(new_sites)
sites_idx_out.append(new_sites_idx)
sites_verts_out.append(new_sites_verts)
else:
verts_out.extend(new_verts)
edges_out.extend(new_edges)
faces_out.extend(new_faces)
sites_idx_out.extend(new_sites)
sites_idx_out.extend(new_sites_idx)
sites_verts_out.extend(new_sites_verts)

self.outputs['Vertices'].sv_set(verts_out)
self.outputs['Edges'].sv_set(edges_out)
self.outputs['Faces'].sv_set(faces_out)
self.outputs['Sites_idx'].sv_set(sites_idx_out)
self.outputs['Sites_verts'].sv_set(sites_verts_out)


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


def unregister():
bpy.utils.unregister_class(SvVoronoiOnMeshNodeMK2)
classes = [SvVoronoiOnMeshNodeMK3]
register, unregister = bpy.utils.register_classes_factory(classes)
Loading

0 comments on commit 8c254b4

Please sign in to comment.