Problems with MItSelectionList Filters

One of the most common tools in the Maya API for custom commands is the MItSelectionList class. Part of the reason why it is so valuable is because it allows for an optional filter in its constructor using the MFn::Type enum. Applying a filter allows us to effectively ignore certain types of objects in which we are not interested, and conceivably to code with some amount of impunity since we know what the objects inside the iterator will be. Conceivably…

While working on some custom commands for the book over the weekend, I discovered some cases in which the filters do not work as expected, so be on the lookout!

Specifically, you might presume that using the MFn.kDagNode or the MFn.kTransform filter should limit the iterator to objects of type kDagSelection. In the former case, this could still include shape nodes, while the latter case properly excludes them. The problem, however, is that the iterator will still include objects of type kPlugSelection, presumably because plugs are technically part of a dependency node. As such, while a transform or any other DAG object could be captured using MItSelectionList.getDagPath(), you can get a difficult-to-find error if a plug has snuck into your selection somehow.

Although you can handle this problem in a variety of ways (such as including a check against the selection item type), I recommend instead using the getDependNode() function to get the node on which the plug exists, and then use a function set to get a a DAG path to this node. I have made a simple Python script so you can see the problem as well as a possible solution:

import maya.OpenMaya as OM
import maya.cmds as cmds

locator1 = cmds.spaceLocator()
mathNode = cmds.createNode('multMatrix')
locator2 = cmds.spaceLocator()

sList = OM.MSelectionList()
sList.add(locator1[0])
sList.add('%s%s'%(locator1[0],'.rotateX'))
sList.add(mathNode)
sList.add(locator2[0])
sList.add('locatorShape%s'%locator2[0].lstrip('locator'))

sListAsStrings = []
sList.getSelectionStrings(sListAsStrings)
print 'List: %s'%sListAsStrings

iter = OM.MItSelectionList(sList, OM.MFn.kDagNode)
node = OM.MObject()
path = OM.MDagPath()
items = {0:'kDagSelectionItem',
    1:'kAnimSelectionItem',
    2:'kDNselectionItem',
    3:'kPlugSelectionItem'}

while not iter.isDone():
    iter.getDependNode(node)
    OM.MFnDagNode(node).getPath(path)
    print '------------'
    print 'Item Type: %s'%(items[iter.itemType()])
    print 'Dependency Node: %s'%OM.MFnDependencyNode(node).name()
    print 'DAG Path: %s'%path.partialPathName()
    iter.next()

You should end up with something like:

List: [u'locator1', u'locator1.rotateX', u'multMatrix4', u'locator2', u'locatorShape2']
------------
Item Type: kDagSelectionItem
Dependency Node: locator1
DAG Path: locator1
------------
Item Type: kPlugSelectionItem
Dependency Node: locator1
DAG Path: locator1
------------
Item Type: kDagSelectionItem
Dependency Node: locator2
DAG Path: locator2
------------
Item Type: kDagSelectionItem
Dependency Node: locatorShape2
DAG Path: locatorShape2

Tags: , , ,

Leave a Reply