Search code examples
pythonmaya

if object exists add a new object name in Maya Python


Trying to make a script I created be able to run multiple times. If I run it once it works, but the second time I get:

Error: setAttr: Not enough data was provided. The last 0 items will be skipped.
 Traceback (most recent call last):
   File "<maya console>", line 8, in <module>

Here is my script

import maya.cmds as mc

#Create and place Spiral DNA elements
for x in range (0,20):
    strandLName = "strandL" +str(x)
    nucleoName = "nucleo" +str(x)
    strandRName = "strandR" +str(x)
    strandL,strandHistory = mc.polySphere(name=strandLName, ch=1)
    nucleo,nucleoHistory = mc.polyCylinder(name=nucleoName, ch=1)
    mc.setAttr(nucleoName + '.translateX', 5)
    mc.setAttr(nucleoName + '.rotateZ', -90)
    mc.setAttr(nucleoName + '.scaleX', 0.5)
    mc.setAttr(nucleoName + '.scaleY', 5)
    mc.setAttr(nucleoName + '.scaleZ', 0.5)
    strandR,strandHistory = mc.polySphere(name=strandRName, ch=1)
    mc.setAttr(strandRName + '.translateX', 10)
    mc.select(deselect=1)

    #create empty group
    grp = mc.group(n=strandLName + 'NULL', em=1)
    mc.select(deselect=1)

    #Parent Elements to Group
    nucleotide = mc.parent(strandL, nucleo, strandR, grp)[0]

    #Move and rotate groups
    mc.setAttr(grp + '.translateX', -5.5)
    mc.xform(grp, cp=1)
    mc.setAttr(grp + ".translateY", x * 2)
    mc.setAttr(grp + ".ry", 15 * x)
    mc.select(deselect=1)

I have 3 objects that have been grouped and that group is then iterated another 19 times to create a spiral DNA strand. I would like to make the names relative so that if the object exists it will create a new object based on what already exists (example strandLName 20 ++). It would be great if I could do the same with the position so that the strand continuously grows each time the script is run.


Solution

  • When you create an object in maya, appending # to the name will automatically increment the name :

    examples = [cmds.createNode('transform', n='example_#') for x in range(10)]
    print examples
    [u'example_1', u'example_2', u'example_3', u'example_4', u'example_5', u'example_6', u'example_7', u'example_8', u'example_9', u'example_10']
    

    However maya won't let you have two items at the same level of the hierarchy with the same name, so it may decide to change your numbering scheme to avoid name clashes. Running the above code twice would generate more transforms named example_11 through example_20.

    To avoid name clashes you can use a namespace or a top level group:

    topnode = cmds.createNode('transform', n= 'top_node_#')
    # calling createNode with 'p=' makes the new items as children
    for n in range(10):
         cmds.createNode('transform', n= 'child%i' % n, p=topnode)
    

    Running this twice will produce top_node_1 and top_node_2 but they'll both have children named child1 through child10. I've manually incremented the names because I'm certain there will be no clashes under top_node_# but that's only reliable if you know for sure that nothing at the same hierarchy level will have the same name stem.

    So, for your example you'll want to create your top-level groups with the # suffix so they can predictably get suffixes, and then manually increment the names of the children as you create them. In your case you won't have the option of creating the nodes directly under your top-level group -- you'll have to rename them after creation and parenting. You can also simplify the code a lot by using the xform command instead of directly setting attributes

    import maya.cmds as cmds
    
    def dna_strand(number_of_pairs):
    
        top_level = cmds.createNode('transform', n='dna_#')
    
        for n in range(number_of_pairs):
            left, _ = cmds.polySphere()
            cmds.xform(t = (-5, 0,0 ))
            right,_  = cmds.polySphere()
            cmds.xform(t = (5, 0,0 ))
            nucleo,_ = cmds.polyCylinder(h = 10, r=.5)
            cmds.xform(nucleo, ro=(0,0,90))
            group = cmds.group(left, right, nucleo)
    
            # now these are under the group, naming is deterministic
            cmds.rename(left, 'strandL%i' % n)
            cmds.rename(right, 'strandR%i' % n)
            cmds.rename(nucleo, 'nucleo%i' % n)
            cmds.xform(group, t=(0,n * 2,0), ro = (0, 15 * n, 0))
            cmds.parent(group, top_level, r=True)
    
            # group is under `dna_x` so again you can manually rename
            cmds.rename(group, "basepair%i" % n)