Adding vertices to a selection list in Maya API

I’m currently on Maya 2020 and am trying to add vertices into a selection list and it doesn’t seem to be working. I’m also new to Maya API so trying to learn. Here’s what I have

import maya.OpenMaya as om
import maya.cmds as cmds

def selVertices():
    selectedObj = cmds.ls(selection=True, flatten=True)
    selectedObj = [str(obj) for obj in selectedObj]
    return(selectedObj)
remVts = selVertices()
print(remVts)  
    
vertList = om.MSelectionList()
for vertex in remVts:
    vertList.add(vertex)
print(vertList.length())

I think it is working. It’s just that MSelectionList.length() isn’t returning what you expect.
For proof, add this to the end of your script. You can see it’ll print out all of the components

a = []
vertList.getSelectionStrings(a)
print(a)

So then how to access those components?
Well, I did a quick google, and found a reply on this forum that might have what you’re looking for. The rest of that thread has some really good info as well, and you should be able to get a lot out of it.
And it also shows how to get the selection using om instead of cmds (if that’s applicable to your use-case)


Finally, some python cleanup on this section of your code

def selVertices():
    selectedObj = cmds.ls(selection=True, flatten=True)
    selectedObj = [str(obj) for obj in selectedObj]
    return(selectedObj)

You don’t need to cast everything to str, because it will already be a list of strings. If you’re worried about what happens if there’s no selection, then (depending on your use-case) you can check if selectedObj is None and do what you need from there. (There are fancier ways to do this, but I’m keeping it simple for now)
There should be a space after the word return, and you don’t need the parentheses
So I think the function would be better like this:

def selVertices():
    selectedObj = cmds.ls(selection=True, flatten=True)
    if selectedObj is None:
        return []  # or you may want to raise an error here, depending on what you're doing
    return selectedObj

Ahhh, ok this makes sense. I didn’t realize that. TYSM! So, how would you iterate through a MSelectionList of vertices?

The post I linked to shows exactly how to iterate over the vertices in the MSelectionList using MItMeshVertex

That’s a great resource…didn’t see the link at first thanks for pointing that out. Awesome feedback much appreciated.

Playing around with the iteration…Little stuck on it. Seeing if I could iterate and get positions for the vertices and store in . Getting: # Error: TypeError: file line 19: in method ‘MFloatPointArray_append’, argument 2 of type ‘MFloatPoint const &’ #

import maya.OpenMaya as om

def create_ray_dir_array():
    sel = om.MSelectionList()
    om.MGlobal.getActiveSelectionList(sel)
    
    dag = om.MDagPath()
    component = om.MObject()
    sel.getDagPath(0, dag, component)
    if not component.isNull():
        # There were components selected
        vert_itr = om.MItMeshVertex(dag, component)
        posArray = om.MFloatPointArray()
        while not vert_itr.isDone():
            # Do stuff
            position = vert_itr.position(om.MSpace.kWorld)
            vectorPos = om.MFloatVector(position.x, position.y, position.z)
            print(position.x)
            posArray.append(vectorPos)
            vert_itr.next()
    return posArray
    
test = create_ray_dir_array()

Vectors and Points are different things.
What is the type of posArray?
What is the type of vectorPos?
What is the type of position?

Another separate issue … what error will you get if component.isNull() returns True?

Great Prompting questions…Tysm…Don’t have the solution in yet if component.isNull() is True…But used some traditional approaches too and I’m getting point positions.

import maya.OpenMaya as om

def create_ray_dir_array():
    sel = om.MSelectionList()
    om.MGlobal.getActiveSelectionList(sel)
    
    dag = om.MDagPath()
    component = om.MObject()
    sel.getDagPath(0, dag, component)
    if not component.isNull():
        # There were components selected
        vert_itr = om.MItMeshVertex(dag, component)
        #posArray = om.MFloatPointArray()
        #posArray = om.MVectorArray() 
        posArray = []
        while not vert_itr.isDone():
            # Do stuff
            position = vert_itr.position(om.MSpace.kWorld)
            #vectorPos = om.MFloatVector(position.x, position.y, position.z)
            vectorPos = (position.x, position.y, position.z)
            print(position.x)
            posArray.append(vectorPos)
            print(posArray)
            vert_itr.next()
    return posArray
    
test = create_ray_dir_array()

Good attempt! But lets simplify a bit.
vert_itr.position(om.MSpace.kWorld) returns an MPoint object, so if posArray was an MPointArray, you could just append it! So the chunk in the if block could look like this

        vert_itr = om.MItMeshVertex(dag, component)
        posArray = om.MPointArray()
        while not vert_itr.isDone():
            pos = vert_itr.position(om.MSpace.kWorld)
            posArray.append(pos)
            vert_itr.next()

Now for the component.isNull() being True, lets look at JUST the code that would get run if that was the case:

def create_ray_dir_array():
    sel = om.MSelectionList()
    om.MGlobal.getActiveSelectionList(sel)
    
    dag = om.MDagPath()
    component = om.MObject()
    sel.getDagPath(0, dag, component)
    # if not component.isNull(): Nothing in this block would get run
    #     so I just removed it from the code as an example

    return posArray  # Where does this variable get defined???
    
test = create_ray_dir_array()

If you don’t have any specific goals, then make your life easier by using maya.api.OpenMaya instead of maya.OpenMaya.

A simple way to work with selected vertices:

import maya.api.OpenMaya as om2

# Get the current selection of elements in the scene.
selection = om2.MGlobal.getActiveSelectionList()
# We get the shape and the components selected on it.
node, component = selection.getComponent(0)
# We will use an iterator specifically designed to effectively work with vertices.
it = om2.MItMeshVertex(node, component)
# We will place the results (vertex positions) in a special array designed to store the positions of points (vertices).
# Essentially, the array value contains a tuple of four float values ​​(x, y, z, w).
vertices_pos_array = om2.MFloatPointArray()
# Loop through the selected vertices for a given shape until we have iterated through them all:
while not it.isDone():
    # Get the vertex position in the space we need, for example in World Space.
    position = it.position(om2.MSpace.kWorld) # or it.position(4)
    # Add the result to the array:
    vertices_pos_array.append(position)
    # For clarity, let's print the name of the shape with the index of the current vertex and its position:
    print('{}.vtx[{}]: {}'.format(node.fullPathName(), it.index(), position))    # or node.partialPathName()
    # move to the next vertex in the current iteration:
    it.next()

BUT! This will work correctly if you have only vertices selected and only on one shape!
If the selection contains different components, or non-DAG nodes, or components are selected on different shapes, then you will get strange, incorrect and incomplete results.
Or you will even get errors.
That is, this only works for the first element in the list.
We specify this ourselves explicitly using index ‘0’:
getComponent(0)

Let’s try a more reasonable approach.

import maya.api.OpenMaya as om2

selection = om2.MGlobal.getActiveSelectionList()
# Let's find out the number of elements in the select list and process them all:
for i in range(selection.length()):
    # If the element is not a DAG node, then when we try to request a node with components for the current selection element, we will receive an error.
    # Handle the error using the `try/except` construct
    node, component = None, None
    try:
        node, component = selection.getComponent(i)
    except:
        pass
   # If the node contains the selected components, then process the result
    if component:
        # Check that the selected components are vertices:
        if component.apiTypeStr == 'kMeshVertComponent':
            # Use an iterator as in the previous example:
            it = om2.MItMeshVertex(node, component)
            vertices_pos_array = om2.MFloatPointArray()
            while not it.isDone():
                position = it.position(om2.MSpace.kWorld) # or it.position(4)
                vertices_pos_array.append(position)
                print('{}.vtx[{}]: {}'.format(node.fullPathName(), it.index(), position))    # or node.partialPathName()
                it.next()

BUT! The method proposed above is not effective and is a clumsy crutch.
There is a special iterator to work effectively with Selection List!

import maya.api.OpenMaya as om2

selection = om2.MGlobal.getActiveSelectionList()
# Create an iterator to process the `Selection List`:
it_sel = om2.MItSelectionList(selection)
while not it_sel.isDone():
    # Check that the current element is a DAG node:
    if not it_sel.itemType():    # int kDagSelectionItem = 0
        # Check that the selection contains the components of the current element:
        if(it_sel.hasComponents()):
            # Now we can get a DAG node with the components selected on it:
            node, component = it_sel.getComponent()
            # Check that the selected components are vertices:
            if component.apiTypeStr == 'kMeshVertComponent':    # or component.apiType() == 554
               # Use an iterator as in the previous example:
                it = om2.MItMeshVertex(node, component)
                vertices_pos_array = om2.MFloatPointArray()
                while not it.isDone():
                    position = it.position(om2.MSpace.kWorld) # or it.position(4)
                    vertices_pos_array.append(position)
                    print('{}.vtx[{}]: {}'.format(node.fullPathName(), it.index(), position))    # or node.partialPathName()
                    it.next()
    it_sel.next()

OpenMaya.MItMeshVertex Class Reference

OpenMaya.MItSelectionList Class Reference

OpenMaya.MFloatPointArray Class Reference

This is great stuff TYSM. Going to pour over this.