Nesting¶
Come back to this document when you get confused about how data is stored in sockets.
Sverchok sockets can contain the elements of any number of objects. The number of objects is shown by the number beside the socket name. If you look at all the previous images, you’ll notice most sockets have been outputting socketname. 1
(a collection, containing one thing
).
Broadly speaking: each collection is a List
of objects and these objects are themselves made from lists down to the most basic level which is the list of coordinates of each vertex.
A vertex is also a list of coordinates (X, Y, Z):
v0 = (1.0, 3.8, 2.5)
v1 = (0.0, 0.0, 0.0)
v2 = (2.1, 3.1, 4.1)
A list of vertices is made of several lists of coordinates per vertex:
vertices = [v0, v1, v2]
# or written in full
vertices = [(1.0, 3.8, 2.5), (0.0, 0.0, 0.0), (2.1, 3.1, 4.1)]
Each List element has an index
, the first element of a list has index 0
and the last element of that list is n-1
(where n
is the number of elements in the list).
In the above vertices list the indices for each vertex are:
# this is a vertex list
vertices = [(1.0, 3.8, 2.5), (0.0, 0.0, 0.0), (2.1, 3.1, 4.1)]
# index = 0 index = 1 index = 2
If, for example, you want to generate edges between vertices, you reference the vertex indices of the two vertices that you want to connect. If we want to generate “edge 0” based on vertices v1 and v2 we will reference them using index 1 and index 2 from that list, we will be creating an edge like this:
edge = (1, 2)
If we want to generate an object composed of 3 edges from the above vertex list
we would end up with an edge list similar to this:
edges_list = [(0, 1), (1, 2), (2, 0)]
At a fundamental level sverchok works by using nodes to create lists of values, then using other nodes to evaluate those lists and generate new lists. Eventually the results of the final list will be used to generate the output that will be passed to the viewport with a viewer node.
This is why the nesting concept is fundamental in order to use Sverchok.
Let’s look at some examples, not necessarily outputting just one thing, f.ex: multiple sets of vertices, or multiple edge index lists:
The image represents a set of nodes and the leftmost node output reads Vertices. 2
Here the number 2
means that the Vertices
socket contains two lists (the vertex lists of two objects). You’ll see the Edges
also has a 2 beside it, it also contains the edge_index
lists of two objects.
the
Vertices
socket contains 2 collections (The first line has 4 vertices, the next line has 6)the
Edges
socket contains 2 collections (The first line has 3 edges, the next line has 5 edges)
To know how many elements are in each socket’s sublist, we can attach a List Length
node. Each sublist represents a Level and it’s values depends on how nested the level is. The default Level
param of 1 will be sufficient for now.
Two Parallel Lines¶
verts¶
Let’s entertain the scenario above where a Node outputs two parallel “PolyLines”, each with a different vertex and edge count. The data in that vertex-socket looks like.
A
. (abstract top level)vertices. 2
is alist
with 2 itemsB
. zoom in, what’s inside the “vertex_lists” data?:[vertex_list_1, vertex_list_2]
C
. one level down, you can count the number of verts per object:[[v1, v2, v3, v4], [v1, v2, v3, v4, v5, v6]]
D
the literal data, you can see the coordinates:[ [(0,0,0),(1,0,0),(2,0,0),(3,0,0)], [(0,-1,0),(0.6,-1,0),(1.2,-1,0),(1.8,-1,0),(2.4,-1,0),(3,-1,0)] ]
A, B, C and D
are all different ways of thinking about the same data in the socket
this is the same as D, with different formatting, and a comment:
[
[(0, 0, 0), (1, 0, 0), (2, 0, 0), (3, 0, 0)], # the vertices for object 1
[(0, -1, 0), (0.6, -1, 0), (1.2, -1, 0), (1.8, -1, 0), (2.4, -1, 0), (3, -1, 0)] # the vertices for object 2
]
here with some highlighting of the syntax
The (orange)
comma
is what syntactically separates the objects.The inner (green)
Square Brackets
are what encapsulate the vertices associated with one object.The outer most (blue)
Square Brackets
are what collect all sublists into something that we can pass through a socketThe parentheses enclose coordinates of each Vertex. In sverchok can also use square brackets to enclose a Vertex. The following are functionally equivalent in sverchok:
vertex_1 = [x, y ,z] vertex_2 = (x, y, z)
Note: We will use parentheses
()
and brackets[]
interchangeably in these lessons. There are real differences between[]
and()
, and we’ll ignore those for now.
edges¶
Then here are the data associated with the Edges
socket in the example
A
. (abstract top level)edges. 2
is alist
with 2 itemsB
zoom in, what’s inside the “edge_index_lists”?:[edge_indices_1, edge_indices_2]
C
one level down:[[edge_1, edge_2, edge_3], [edge_1, edge_2, edge_3, edge_4, edge_5]]
D
literal data, there are a lot of brackets, i’ll space them out a bit:[ [[0, 1], [1, 2], [2, 3]], [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5]] ]
same as D but with some formatting and a comment:
[
[ [0, 1], [1, 2], [2, 3] ], # the edge indices of object 1
[ [0, 1], [1, 2], [2, 3], [3, 4], [4, 5] ] # the edge indices of object 2
]
And that’s structurally the same as what the stethoschope will show us
Notice above that the edges are wrapped by outer parentheses, this isn’t common, but it’s not incorrect.
A Circle and a Cube¶
- Let’s say we have two mesh objects that we’ll be receiving from a node with
Vertices
andEdges
sockets. a crude circle with 6 verts and 1 face, and
a Cube (with 8 verts and 6 faces)
Notice that each object is visually transformed away from the world origin, I will be using the untransformed coordinates.
let’s describe them formally in psuedo-code:
verts = [vertex_list_circle, vertex_list_cube] # two vertex lists
faces = [face_index_list_circle, face_index_list_cube] # two face_index lists
zoomed in a level:
verts = [
[v1, v2, v3, v4, v5, v6], # the circle
[v1, v2, v3, v4, v5, v6, v7, v8] # the cube
]
faces = [
[face_1], # object 1: the circle's face, only one face!
[face_1, face_2, face_3, face_4, face_5, face_6] # object 2: a cube has 6 faces
]
This is what the literal data would look like:
verts = [
# circle verts
[(0, 1, 0), (0.866, 0.5, 0), (0.866, -0.5, 0), (0, -1, 0), (-0.866, -0.5, 0), (-0.8660, 0.5, 0)],
# cube verts, there are all 0.5, but because the zero is not considered significant we can omit it.
[[-.5, -.5, -.5], [-.5, .5, -.5], [.5, .5, -.5], [.5, -.5, -.5], [-.5, -.5, .5], [-.5, .5, .5], [.5, .5, .5], [.5, -.5, .5]]
]
faces = [
# the face index list for a circle of 6 vertices
[[0, 1, 2, 3, 4, 5]],
# cube of 8 verts has 6 quad faces.
[[4, 5, 1, 0], [5, 6, 2, 1], [6, 7, 3, 2], [7, 4, 0, 3], [7, 6, 5, 4], [0, 1, 2, 3]]
]
The final nail¶
Let’s say we have a node, and it outputs the Face of a single object (a polygon, a quad). so the socket will read something like:
Faces. 1
.
What do you expect the output to look like if the only face is described by 4 vertex indices 0, 1, 2, 3
, and why?:
# the face
face_1 = [0, 1, 2, 3]
# the object has no more faces, but we wrap the face anyway
faces_of_obj_1 = [face_1]
# and we wrap all the objects, here it's just one object
faces = [faces_of_obj_1]
# so 0, 1, 2 ,3 becomes
[[[0, 1, 2, 3]]]
This is going to look weird (and arguably redundant) in the scenario where the socket only describes one object. You’ll almost never see sockets outputting a single face, except for the most primitive of geometry nodes.
Note
It’s possible that none of this makes sense to you. In that case I encourage you to hook a stethoscope into any node that isn’t outputting what you expect. More about debugging in a later Note.