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

Calculation of used sites for node "Voronoi on Mesh". #4980

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
2 changes: 1 addition & 1 deletion docs/nodes/pulga_physics/pulga_springs_force.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Example in description:

* Generator-> :doc:`Cylinder </nodes/generator/cylinder_mk2>`
* Spatial-> :doc:`Populate Mesh </nodes/spatial/random_points_on_mesh>`
* Spatial-> :doc:`Voronoi on Mesh </nodes/spatial/voronoi_on_mesh>`
* Spatial-> :doc:`Voronoi on Mesh </nodes/spatial/voronoi_on_mesh_mk2>`
* Modifiers->Modifier Change-> :doc:`Mesh Join </nodes/modifier_change/mesh_join_mk2>`
* Modifiers->Modifier Change-> :doc:`Merge by Distance </nodes/modifier_change/merge_by_distance>`
* Analyzers->Component Analyzer **Vertices->Sharpness**: :ref:`Vertices Sharpness<VERTICES_SHARPNESS>`
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
- SvVoronoiOnMeshNode
- SvVoronoiOnMeshNodeMK2
- 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 @@ -506,7 +506,7 @@
- SvExVoronoi3DNode
- SvExVoronoiSphereNode
- SvVoronoiOnSurfaceNode
- SvVoronoiOnMeshNode
- SvVoronoiOnMeshNodeMK2
- 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
- SvVoronoiOnMeshNode
- SvVoronoiOnMeshNodeMK2
- SvVoronoiOnSolidNodeMK2
- ---
- SvLloyd2dNode
Expand Down
193 changes: 193 additions & 0 deletions nodes/spatial/voronoi_on_mesh_mk2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
# ##### 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 FloatProperty, EnumProperty, BoolProperty, IntProperty

from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import updateNode, zip_long_repeat, ensure_nesting_level, get_data_nesting_level,\
ensure_min_nesting
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


class SvVoronoiOnMeshNodeMK2(SverchCustomTreeNode, bpy.types.Node):
"""
Triggers: Voronoi Mesh
Tooltip: Generate Voronoi diagram on the surface of a mesh object
"""
bl_idname = 'SvVoronoiOnMeshNodeMK2'
bl_label = 'Voronoi on Mesh'
bl_icon = 'OUTLINER_OB_EMPTY'
sv_icon = 'SV_VORONOI'
sv_dependencies = {'scipy'}

modes = [
('VOLUME', "Split Volume", "Split volume of the mesh into regions of Voronoi diagram", 0),
('SURFACE', "Split Surface", "Split the surface of the mesh into regions of Vornoi diagram", 1),
#('RIDGES', "Ridges near Surface", "Generate ridges of 3D Voronoi diagram near the surface of the mesh", 2),
#('REGIONS', "Regions near Surface", "Generate regions of 3D Voronoi diagram near the surface of the mesh", 3)
]

spacing : FloatProperty(
name = "Spacing",
default = 0.0,
min = 0.0,
description="Percent of space to leave between generated fragment meshes",
update=updateNode)

normals : BoolProperty(
name = "Correct normals",
default = True,
description="Make sure that all normals of generated meshes point outside",
update = updateNode)

def update_sockets(self, context):
self.inputs['Spacing'].hide_safe = self.mode not in {'VOLUME', 'SURFACE'}
updateNode(self, context)

mode : EnumProperty(
name = "Mode",
items = modes,
default = 'VOLUME',
update = update_sockets)

join_modes = [
('FLAT', "Flat list", "Output a single flat list of mesh objects (Voronoi diagram ridges / regions) for all input meshes", 0),
('SEPARATE', "Separate lists", "Output a separate list of mesh objects (Voronoi diagram ridges / regions) for each input mesh", 1),
('JOIN', "Join meshes", "Output one mesh, joined from ridges / edges of Voronoi diagram, for each input mesh", 2)
]

join_mode : EnumProperty(
name = "Output mode",
items = join_modes,
default = 'FLAT',
update = updateNode)

accuracy : IntProperty(
name = "Accuracy",
description = "Accuracy for mesh bisecting procedure",
default = 6,
min = 1,
update = updateNode)

def sv_init(self, context):
self.inputs.new('SvVerticesSocket', 'Vertices')
self.inputs.new('SvStringsSocket', 'Faces')
self.inputs.new('SvVerticesSocket', "Sites")
# self.inputs.new('SvStringsSocket', 'Thickness').prop_name = 'thickness'
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.update_sockets(context)

def draw_buttons(self, context, layout):
layout.label(text="Mode:")
layout.prop(self, "mode", text='')
if self.mode == 'VOLUME':
layout.prop(self, 'normals')
layout.label(text='Output nesting:')
layout.prop(self, 'join_mode', text='')

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

def process(self):

if not any(socket.is_linked for socket in self.outputs):
return

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)
#thickness_in = self.inputs['Thickness'].sv_get()
spacing_in = self.inputs['Spacing'].sv_get(deepcopy=False)

verts_in = ensure_nesting_level(verts_in, 4)
input_level = get_data_nesting_level(sites_in)
sites_in = ensure_nesting_level(sites_in, 4)
faces_in = ensure_nesting_level(faces_in, 4)
#thickness_in = ensure_nesting_level(thickness_in, 2)
spacing_in = ensure_min_nesting(spacing_in, 2)

nested_output = input_level > 3

precision = 10 ** (-self.accuracy)

verts_out = []
edges_out = []
faces_out = []
sites_idx_out = []
for params in zip_long_repeat(verts_in, faces_in, sites_in, spacing_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,
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)

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])
elif self.join_mode == 'SEPARATE':
new_verts.append(verts)
new_edges.append(edges)
new_faces.append(faces)
new_sites.append(used_sites_idx)
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)

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

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)


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


def unregister():
bpy.utils.unregister_class(SvVoronoiOnMeshNodeMK2)
2 changes: 1 addition & 1 deletion nodes/spatial/voronoi_on_solid_mk2.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def process(self):
z_min, z_max = box.ZMin - clipping, box.ZMax + clipping
bounds = list(itertools.product([x_min,x_max], [y_min, y_max], [z_min, z_max]))
bounds_box_faces = [ [0,1,3,2], [2,3,7,6], [6,7,5,4], [4,5,1,0], [2,6,4,0], [7,3,1,5] ] # cube's faces
verts, edges, faces = voronoi_on_mesh_bmesh(bounds, bounds_box_faces, len(sites), sites, spacing=inset, mode='VOLUME' )
verts, edges, faces, used_sites_idx = voronoi_on_mesh_bmesh(bounds, bounds_box_faces, len(sites), sites, spacing=inset, mode='VOLUME' )

if isinstance(inset, list):
inset = repeat_last_for_length(inset, len(sites))
Expand Down
2 changes: 1 addition & 1 deletion nodes/spatial/voronoi_on_surface.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ def process(self):
uvverts, verts, edges, faces = self.voronoi_uv(surface, uvpoints, maxsides)
new_uvverts.append(uvverts)
else:
verts, edges, faces = voronoi_on_surface(surface, uvpoints, thickness, self.do_clip, clipping, self.mode == 'REGIONS')
verts, edges, faces, used_sites = voronoi_on_surface(surface, uvpoints, thickness, self.do_clip, clipping, self.mode == 'REGIONS')

if (self.mode in {'RIDGES', 'REGIONS'} or self.make_faces) and self.normals:
verts, edges, faces = recalc_normals(verts, edges, faces, loop = (self.mode in {'REGIONS', 'RIDGES'}))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,4 +190,4 @@ def register():


def unregister():
bpy.utils.unregister_class(SvVoronoiOnMeshNode)
bpy.utils.unregister_class(SvVoronoiOnMeshNode)
10 changes: 6 additions & 4 deletions utils/voronoi3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ def voronoi3d_layer(n_src_sites, all_sites, make_regions, do_clip, clipping, ski
faces_n.append(faces_i)
verts, edges, faces = verts_n, edges_n, faces_n

return verts, edges, faces
return verts, edges, faces, all_sites

def voronoi_on_surface(surface, uvpoints, thickness, do_clip, clipping, make_regions):
u_min, u_max, v_min, v_max = surface.get_domain()
Expand Down Expand Up @@ -418,6 +418,7 @@ def cut_cell(start_mesh, sites_delaunay_params, site_idx, spacing, center_of_mas
bbox_aligned = bounding_box_aligned(verts)[0]

start_mesh = bmesh_from_pydata(verts, [], faces, normal_update=False)
used_sites_idx = []
for site_idx in range(len(sites)):
cell = cut_cell(start_mesh, sites_delaunay_params, site_idx, spacing[site_idx], center_of_mass, bbox_aligned)
if cell is not None:
Expand All @@ -426,6 +427,7 @@ def cut_cell(start_mesh, sites_delaunay_params, site_idx, spacing, center_of_mas
verts_out.append(new_verts)
edges_out.append(new_edges)
faces_out.append(new_faces)
used_sites_idx.append( site_idx )
start_mesh.clear() # remember to clear empty geometry
start_mesh.free()

Expand All @@ -435,7 +437,7 @@ def cut_cell(start_mesh, sites_delaunay_params, site_idx, spacing, center_of_mas
# unb - unpredicted erased mesh (bbox_aligned cannot make predicted results)
# sites - count of sites in process
# print( f"bisects: {num_bisect: 4d}, unb={num_unpredicted_erased: 4d}, sites={len(sites)}")
return verts_out, edges_out, faces_out
return verts_out, edges_out, faces_out, used_sites_idx

def voronoi_on_mesh(verts, faces, sites, thickness,
spacing = 0.0,
Expand Down Expand Up @@ -469,10 +471,10 @@ def voronoi_on_mesh(verts, faces, sites, thickness,

else: # VOLUME, SURFACE
all_points = sites[:]
verts, edges, faces = voronoi_on_mesh_bmesh(verts, faces, len(sites), all_points,
verts, edges, faces, used_sites_idx = voronoi_on_mesh_bmesh(verts, faces, len(sites), all_points,
spacing = spacing, mode = mode, normal_update = normal_update,
precision = precision)
return verts, edges, faces, all_points
return verts, edges, faces, used_sites_idx

def project_solid_normals(shell, pts, thickness, add_plus=True, add_minus=True, predicate_plus=None, predicate_minus=None):
k = 0.5*thickness
Expand Down
Loading