Selecting poles

In order to select vertices with a certain number of steps we may perform the following steps:

  1. Check whether the active object is a Mesh.
  2. Check whether we are in object mode.
  3. Show a pop-up menu to input the minimum number of edges.
  4. For every vertex:
    • Iterate over all edges, counting occurrences of the vertex
    • If count is larger or equal to the minimum, select the vertex

This approach is straightforward and simple. The function that is responsible for the actual work is shown below (the full script is called poleselect1.py). It follows our outline closely. The actual selection of a vertex is effected by assigning to the sel attribute of the vertex. Note also that the v1 and v2 attributes of an edge object are not indices into the verts attribute of our mesh but refer to MVert objects. That is why we need to retrieve the index attributes to compare.

def poleselect1(me,n=5):
for v in me.verts:
n_edges=0
for e in me.edges:
if e.v1.index == v.index or e.v2.index == v.index:
n_edges+=1
if n_edges >= n:
v.sel = 1
break

Selecting poles, again

You probably noticed that we iterated over the list of edges for each and every vertex (highlighted in the previous code). This might be costly in terms of performance and this cost is even compounded by the need to compare indices which have to be retrieved again and again. Is it possible to write more efficient code that stays readable nonetheless? It is if we follow this strategy:

  1. Check whether the active object is a Mesh.
  2. Check whether we are in object mode.
  3. Show a pop-up menu to input the minimum number of edges.
  4. Initialize a dictionary, indexed by vertex index that will contain edge counts.
  5. Iterate over all edges (update the count for both referred vertices).
  6. Iterate over the items in the dictionary (if count is larger or equal to the minimum, select the vertex).

By using this strategy we perform just two possibly lengthy iterations at the cost of needing the memory to store the dictionary (nothing is free). The speed increase is negligible for small meshes but might be considerable (I clocked a 1,000-fold speed boost on a smallish mesh of 3,000 vertices) for large meshes, and those are just the kind of meshes where someone might need a tool like this.

Our revised selection function is shown below (the full script is called poleselect.py). First note the import statement. The dictionary that we will be using is called a default dictionary and is provided by Python's collections module. A default dictionary is a dictionary that initializes missing items the first time they are referred to. As we want to increment the count for every vertex that is referred to by an edge, we should either initialize our dictionary with a zero value for every vertex in the mesh beforehand or check if a vertex is already indexed every time we want to increment the count and, if not, initialize it. A default dictionary does away with the need to initialize everything in advance and allows for a very readable idiom.

We create our dictionary by calling the defaultdictionary() function (a function returning a new object whose behavior is configured by some argument to the function is called a factory in object-oriented circles) with an int argument. The argument should be a function taking no arguments. The built-in function int() that we use here will return an integer value of zero when called without arguments. Every time we access our dictionary with a non-existing key, a new item is created and its value will be the return value of our int() function, that is, zero. The essential lines are the two where we increment the edgecount (highlighted part of the following code). We could have written that expression in a slightly different way to illustrate why we need a default dictionary:

edgecount[edge.v1.index] = edgecount[edge.v1.index] + 1

The dictionary item we refer to on the right-hand side of the expression might not yet exist every time we refer to a vertex index that we encounter for the first time. Of course, we could check beforehand but that would render the code a whole lot less readable.

from collections import defaultdict
def poleselect(me,n=5):
n_edges = defaultdict(int)
for e in me.edges:
n_edges[e.v1.index]+=1
n_edges[e.v2.index]+=1
for v in (v for v,c in n_edges.items() if c>=n ):
me.verts[v].sel=1
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.116.21.152