Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix 5088. Voronoi On Mesh. Append input socket for mask #5097

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -507,7 +507,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
Loading