Skip to content

Commit

Permalink
Performance some generators:
Browse files Browse the repository at this point in the history
- generator/circle.py
- generator/ngon.py
- generator/sphere.py
- generator/torus_mk2.py
- generators_extended/ellipse_mk3.py
- generators_extended/hilbert3d.py
- generators_extended/ring_mk2.py
- generators_extended/spiral_mk2.py
- generators_extended/super_ellipsoid.py
- generators_extended/torus_knot_mk2.py
  • Loading branch information
satabol committed Oct 10, 2023
1 parent 3b6878b commit ff2d546
Show file tree
Hide file tree
Showing 10 changed files with 644 additions and 533 deletions.
23 changes: 11 additions & 12 deletions nodes/generator/circle.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import (fullList, match_long_repeat, updateNode)
import numpy as np
from datetime import datetime


class SvCircleNode(SverchCustomTreeNode, bpy.types.Node):
Expand Down Expand Up @@ -62,8 +61,8 @@ def make_verts(self, Angle, Vertices, Radius):
else:
theta = Angle/Vertices

steps = np.arange(Vertices, dtype=np.int32)
_theta = steps*theta
_n1 = np.arange(Vertices, dtype=np.int32)
_theta = _n1*theta
_x = Radius * np.cos(np.radians(_theta))
_y = Radius * np.sin(np.radians(_theta))

Expand All @@ -82,19 +81,19 @@ def make_verts(self, Angle, Vertices, Radius):

def make_edges(self, Angle, Vertices):

steps = np.arange(Vertices, dtype=np.int32)
arr_edges = np.zeros((Vertices-1, 2), 'i' )
arr_edges[:,0] = steps[:-1]
arr_edges[:,1] = steps[1:]
_n = np.arange(Vertices, dtype=np.int32)
_edges = np.column_stack( (_n[:-1], _n[1:]) )

if Angle < 360 and self.mode_ == 1:
arr_edges = np.vstack( (arr_edges, (Vertices-1, Vertices)) )
arr_edges = np.vstack( (arr_edges, (Vertices, 0 )) )
# Close circle like Packman (throw center of circle)
_edges = np.vstack( (_edges, (Vertices-1, Vertices) ))
_edges = np.vstack( (_edges, (Vertices , 0) ))
else:
arr_edges = np.vstack( (arr_edges, (Vertices-1, 0)) )
# Close circle from last point to first point
_edges = np.vstack( (_edges, (Vertices-1, 0)))

_listEdg = arr_edges.tolist()
return _listEdg
_list_edges = _edges.tolist()
return _list_edges

def make_faces(self, Angle, Vertices):

Expand Down
94 changes: 51 additions & 43 deletions nodes/generator/ngon.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,62 +21,70 @@

import bpy
from bpy.props import BoolProperty, IntProperty, FloatProperty, EnumProperty
import numpy as np

from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import (updateNode, rotate_list, list_match_modes, list_match_func)

def make_verts(nsides, radius, rand_r, rand_phi, rand_seed, divs):
if rand_r or rand_phi:
random.seed(rand_seed)

vertices = []
dphi = (2*pi)/nsides
prev_vertex = None
first_vertex = None
for i in range(nsides):
phi = dphi * i
# randomize radius if necessary
if not rand_r:
rr = radius
else:
rr = random.uniform(radius - rand_r, radius + rand_r)
# randomize angle if necessary
if rand_phi:
phi = random.uniform(phi - rand_phi, phi + rand_phi)
x = rr*cos(phi)
y = rr*sin(phi)
next_vertex = (x, y, 0)
if prev_vertex is not None and divs > 1:
prev_x, prev_y, prev_z = prev_vertex
alphas = [float(i)/divs for i in range(1, divs)]
mid_vertices = [((1-alpha)*prev_x + alpha*x, (1-alpha)*prev_y + alpha*y, 0) for alpha in alphas]
vertices.extend(mid_vertices)
vertices.append(next_vertex)
prev_vertex = next_vertex
if first_vertex is None:
first_vertex = next_vertex

if divs > 1 and first_vertex is not None and prev_vertex is not None:
x, y, z = first_vertex
prev_x, prev_y, prev_z = prev_vertex
alphas = [float(i)/divs for i in range(1, divs)]
mid_vertices = [((1-alpha)*prev_x + alpha*x, (1-alpha)*prev_y + alpha*y, 0) for alpha in alphas]
vertices.extend(mid_vertices)
return vertices

_phi = np.arange(nsides)*dphi
if rand_phi:
np.random.seed( int(rand_seed*1000) )
_phi = _phi + np.array( np.random.uniform(-rand_phi, +rand_phi, nsides) )

_rr = np.ones( nsides )*radius
if rand_r:
np.random.seed( int(rand_seed*1000) )
_rr = _rr + np.array( np.random.uniform(-rand_r, +rand_r, nsides) )

_x = _rr*np.cos(_phi)
_y = _rr*np.sin(_phi)

if divs>1:
# divs stright lines, not arcs
_x0 = _x
_y0 = _y
_x1 = np.roll(_x0, -1)
_y1 = np.roll(_y0, -1)
_dx = (_x1-_x0)/divs
_dy = (_y1-_y0)/divs
_x_divs = np.repeat( _x0, divs)
_y_divs = np.repeat( _y0, divs)
_dx = np.repeat( _dx, divs)
_dy = np.repeat( _dy, divs)
_id = np.meshgrid( np.arange(divs), np.arange(nsides), indexing = 'xy')[0].flatten()
_xd = _x_divs+_id*_dx
_yd = _y_divs+_id*_dy
_verts = np.column_stack( (_xd, _yd, np.zeros_like(_xd) ) )
pass
else:
_verts = np.column_stack( (_x, _y, np.zeros_like(_x) ))

_list_verts = _verts.tolist()
return _list_verts

def make_edges(nsides, shift, divs):
vs = range(nsides*divs)
edges = list( zip( vs, rotate_list(vs, shift+1) ) )
return edges

def make_faces(nsides, shift, divs):
_n = np.arange(nsides*divs)
_edges = np.column_stack( (_n, np.roll(_n, -1-shift )) )
_list_edges = _edges.tolist()
return _list_edges

def make_faces(nsides, shift, divs, r, dr, dphi):
# for now, do not return faces if star factor
# is not zero - the face obviously would be degraded.
# This actual for random phi too and some cases of random r
# to the future version of node
# if not shift or dphi or dr and (r-dr)<0:
if shift:
return []
vs = range(nsides*divs)
face = list(vs)
return [face]
_faces = np.arange(nsides*divs)
_list_faces = _faces.tolist()
return [_list_faces]

class SvNGonNode(SverchCustomTreeNode, bpy.types.Node):
''' NGon. [default]
Expand All @@ -99,7 +107,7 @@ class SvNGonNode(SverchCustomTreeNode, bpy.types.Node):
sides_: IntProperty(name='N Sides', description='Number of polygon sides',
default=5, min=3,
update=updateNode)
divisions : IntProperty(name='Divisions', description = "Number of divisions to divide each side to",
divisions : IntProperty(name='Divisions', description = "Number of divisions to divide each side to (lines not arcs)",
default=1, min=1,
update=updateNode)
rand_seed_: FloatProperty(name='Seed', description='Random seed',
Expand Down Expand Up @@ -167,7 +175,7 @@ def process(self):
self.outputs['Edges'].sv_set(edges)

if self.outputs['Polygons'].is_linked:
faces = [make_faces(n, shift, divs) for r, n, s, dr, dphi, shift, divs in zip(*parameters)]
faces = [make_faces(n, shift, divs, r, dr, dphi) for r, n, s, dr, dphi, shift, divs in zip(*parameters)]
self.outputs['Polygons'].sv_set(faces)


Expand Down
111 changes: 73 additions & 38 deletions nodes/generator/sphere.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,37 @@
from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import updateNode, list_match_modes, list_match_func
from sverchok.utils.decorators_compilation import jit, njit
import numpy as np

# from numba.typed import List
# @njit(cache=True)
def make_sphere_verts_combined(U, V, Radius):

N1 = U # X
N2 = V # Y
n1_i = np.arange(N1, dtype=np.int16)
_n1 = np.repeat( [np.array(n1_i)], N2-2, axis = 0) # index n1
n2_i = np.arange(1, N2-1, dtype=np.int16)
_n2 = np.repeat( [np.array(n2_i)], N1, axis = 0).T # index n2

theta = radians(360 / U)
phi = radians(180 / (V-1))

pts = []
pts = [[0, 0, Radius]]
for i in range(1, V-1):
pts_u = []
sin_phi_i = sin(phi * i)
for j in range(U):
X = Radius * cos(theta * j) * sin_phi_i
Y = Radius * sin(theta * j) * sin_phi_i
Z = Radius * cos(phi * i)
pts_u.append([X, Y, Z])
pts.extend(pts_u)

pts.append([0, 0, -Radius])
return pts
_theta = theta*_n1
_phi = phi*_n2
_X = Radius * np.cos(_theta) * np.sin(_phi)
_Y = Radius * np.sin(_theta) * np.sin(_phi)
_Z = Radius * np.cos(_phi)
_verts = np.dstack((_X, _Y, _Z))
_verts = _verts.reshape(-1, 3)
list_verts = [[0,0,Radius]]
list_verts.extend(_verts.tolist())
list_verts.append([0,0,-Radius])
return list_verts

def make_sphere_verts_separate(U, V, Radius):
theta = radians(360/U)
phi = radians(180/(V-1))
theta = radians(360 / U)
phi = radians(180 / (V-1))

pts = []
pts = [[[0, 0, Radius] for i in range(U)]]
Expand Down Expand Up @@ -66,32 +72,61 @@ def sphere_verts(U, V, Radius, Separate):

# @njit(cache=True)
def sphere_edges(U, V):
nr_pts = U*V-(U-1)*2
listEdg = []
for i in range(V-2):
listEdg.extend([[j+1+U*i, j+2+U*i] for j in range(U-1)])
listEdg.append([U*(i+1), U*(i+1)-U+1])
listEdg.extend([[i+1, i+1+U] for i in range(U*(V-3))])
listEdg.extend([[0, i+1] for i in range(U)])
listEdg.extend([[nr_pts-1, i+nr_pts-U-1] for i in range(U)])
listEdg.reverse()
return listEdg

N1 = U # X
N2 = V # Y
steps = np.arange(N1*(N2-2) ) + 1 # skip first verts at [0,0,Radius] and finish before [0,0,-Radius]


arr_verts = np.array ( np.split(steps, (N2-2) ) ) # split array vertically
arr_verts = np.hstack( (arr_verts, np.array([arr_verts[:,0]]).T ) ) # append first row to bottom to horizontal circle

_arr_h_edges = np.zeros((N2-2, N1, 2), 'i' )
_arr_h_edges[:, :, 0] = arr_verts[ : , :-1 ] # hor_edges
_arr_h_edges[:, :, 1] = arr_verts[ : , 1: ] # hor_edges
_arr_h_edges = _arr_h_edges.reshape(-1,2)

_arr_v_edges = np.zeros((N2-2-1, N1, 2), 'i' ) # -1: vert edges except top and bottom point and less than 1 than exists vertcal points
_arr_v_edges[:, :, 0] = arr_verts[ :-1, :-1] # hor_edges
_arr_v_edges[:, :, 1] = arr_verts[1: , :-1] # hor_edges
_arr_v_edges = _arr_v_edges.reshape(-1,2)

_edges = np.concatenate(
(
_arr_h_edges,
_arr_v_edges,
np.dstack( ( arr_verts[0:1, :-1]-arr_verts[0:1, :-1] , arr_verts[ 0: 1, :-1]) ).reshape(-1,2), # self subtract to get array of 0 appropriate length
np.dstack( ( arr_verts[0:1, :-1]-arr_verts[0:1, :-1] + N1*(N2-2)+1, arr_verts[-1: , :-1]) ).reshape(-1,2),
) )
_list_edges = _edges.tolist()
return _list_edges

# @njit(cache=True)
def sphere_faces(U, V):
nr_pts = U*V-(U-1)*2
listPln = []
for i in range(V-3):
listPln.append([U*i+2*U, 1+U*i+U, 1+U*i, U*i+U])
listPln.extend([[1+U*i+j+U, 2+U*i+j+U, 2+U*i+j, 1+U*i+j] for j in range(U-1)])

for i in range(U-1):
listPln.append([1+i, 2+i, 0])
listPln.append([i+nr_pts-U, i+nr_pts-1-U, nr_pts-1])
listPln.append([U, 1, 0])
listPln.append([nr_pts-1-U, nr_pts-2, nr_pts-1])
return listPln

N1 = U # X
N2 = V # Y
steps = np.arange(N1*(N2-2) ) + 1 # skip first verts at [0,0,Radius] and finish before [0,0,-Radius]
_arr_middle_verts = np.array ( np.split(steps, (N2-2) ) ) # split array vertically
_arr_middle_verts = np.hstack( (_arr_middle_verts, np.array([_arr_middle_verts[:,0]]).T ) ) # append first row to bottom to horizontal circle

_arr_middle_faces = np.zeros((N2-3, N1, 4), 'i' )
_arr_middle_faces[:, :, 0] = _arr_middle_verts[1: , :-1 ]
_arr_middle_faces[:, :, 1] = _arr_middle_verts[1: , 1: ]
_arr_middle_faces[:, :, 2] = _arr_middle_verts[ :-1, 1: ]
_arr_middle_faces[:, :, 3] = _arr_middle_verts[ :-1, :-1 ]
_arr_middle_faces = _arr_middle_faces.reshape(-1,4)

_arr_faces_top_bottom = np.concatenate(
(
np.dstack( ( _arr_middle_verts[ 0:1, :-1], _arr_middle_verts[ :1, 1: ], np.zeros_like(_arr_middle_verts[0,:-1]) + 0) ).reshape(-1,3), # top triangled faces
np.dstack( ( np.zeros_like(_arr_middle_verts[-1,:-1]) + N1*(N2-2)+1, _arr_middle_verts[ -1: ,1: ], _arr_middle_verts[ -1:, :-1]) ).reshape(-1,3), # bottom triangled faces
)
)
_arr_faces_top_bottom = _arr_faces_top_bottom.reshape(-1,3)
_list_faces = _arr_middle_faces.tolist()
_list_faces.extend( _arr_faces_top_bottom )
return _list_faces

class SphereNode(SverchCustomTreeNode, bpy.types.Node):
'''UV Sphere. [default]
Expand Down
Loading

0 comments on commit ff2d546

Please sign in to comment.