Shannon Hochkins
Shannon Hochkins

Reputation: 12175

Maya Variable Concatenation

Having a few problems basically inserting a bunch of flags generated by a loop:

def drawHelix(radius, length, coils): 
    numPoints = int(8)
    degrees = float((360 / numPoints))
    centerX = float(0)
    centerZ = float(0)
    xLoc = float(0)
    zLoc  = float(0)
    yLoc  = float(0)
    yOffset = float(((length / coils) / numPoints))
    vectorIndex = int(0)
    pointStr = ""
    knotStr = ""
    for i in range(1, (360 * coils), 20):
        t = i + degrees
        xLoc = centerX + (math.cos(t) * radius)
        zLoc = centerZ - (math.sin(t) * radius)
        pointStr = (pointStr + " p=(" + str(xLoc) + "," +  str(yLoc) + "," +  str(zLoc) + "),")
        knotStr = (knotStr + "k=(" + str(vectorIndex) + ")")
        vectorIndex = i + 1
        yLoc = yLoc + yOffset
    print pointStr        
    spiral = cmds.curve(d=float(1.0), pointStr, knotStr)
    cmds.rebuildCurve (spiral, ch=1, rpo=1, rt=0, end=1, kr=1, kcp=0, kep=0, kt=0, s=0, d=3, tol=0.001)
    return spiral

Which I then run with: drawHelix (2.00, 3.00, 5.00)

The problem is that Maya doesn't recognise the "pointStr" as a flag for the curve command, when I print pointStr it does give me exactly what I want, but struggling on how to actually make this work!

Upvotes: 0

Views: 1103

Answers (2)

joojaa
joojaa

Reputation: 4434

I assume this is what you had in mind:

from maya import cmds
import math
def drawHelix(radius, length, coils): 
    numPoints = int(8)
    degrees = float((360 / numPoints))
    centerX = float(0)
    centerZ = float(0)
    xLoc = float(0)
    zLoc  = float(0)
    yLoc  = float(0)
    yOffset = float(((length / float(coils)) / float(numPoints)))
    vectorIndex = int(0)
    pointStr = []
    knotStr = []
    yLoc = 0
    for i in range(1, (360 * coils), 20):
        t = i + degrees
        xLoc = centerX + (math.cos(t) * radius)
        zLoc = centerZ - (math.sin(t) * radius)
        pointStr.append((xLoc, yLoc,zLoc))
        knotStr.append(vectorIndex)
        vectorIndex = i + 1
        yLoc = yLoc + yOffset
    print pointStr        
    spiral = cmds.curve(p= pointStr, k=knotStr,d=float(1.0))
    cmds.rebuildCurve (spiral, ch=1, rpo=1, 
                       rt=0, end=1, kr=1, kcp=0, kep=0, 
                       kt=0, s=0, d=3, tol=0.001)
    return spiral

There is just a way much better way to do this. This is how your supposed to use Maya, use nodes to build your stuff. So here goes, a unnecessarily commented and verbose version:

from maya import cmds

def getHistoryShape(name):
    history = cmds.listHistory(name)
    filteredShape = cmds.ls(history, shapes=1)[0]
    return filteredShape 

def drawHelix(radius, length, coils): 
    cyl = cmds.cylinder( ch=True, radius=radius, ax=(0,1,0),
                         hr=float(length)/float(radius) )

    # build a curve on the cylinders surface
    crv = cmds.curveOnSurface(cyl[0], d=1, 
                              uv=[(0,0),(length, coils*4)],
                              k=[0,1]) 
    # make a duplicate that is visible 
    crv = cmds.duplicateCurve(ch=1, rn=0, local=1)

    # tell maya to ignore the cylinder as a piece of geometry
    shape = getHistoryShape(cyl[0])
    cmds.setAttr(shape+'.intermediateObject', 1)

    cmds.rename(cyl[0],'helix1')
    return crv  

Now you can change the helixes parameters later, live. You could expose the parameters radius, length and coils for the user, so they can be animated. See Maya factory scripts for example.

Upvotes: 1

tzelleke
tzelleke

Reputation: 15345

The Python interpreter will not expand your strings before calling the function (you could achieve this using eval but this is generally considered bad practice -- see this post on SO).

It should work when passing the arguments as a dict of keywords. Look it up here:

So instead of:

pointStr = (pointStr + " p=(" + str(xLoc) + "," +  str(yLoc) + "," +  str(zLoc) + "),")
knotStr = (knotStr + "k=(" + str(vectorIndex) + ")")

You should do

kwargs['d'] = 1.0
kwargs['p'] = []
for i in range(1, (360 * coils), 20):
    ...
    kwargs['p'].append((xloc, yloc, zloc))
    kwargs['k'].append(vectorIndex)

spiral = cmds.curve(**kwargs) 

Apart from that there are a few other issues in your code:

float((360 / numPoints)) will evaluate differently in Python2.x and Python3.x. This is what happens in 2.x:

In [5]: float(7 / 6)
Out[5]: 1.0

In [6]: 7. / 6
Out[6]: 1.1666666666666667

In If you wanted to ensure that floating point division is performed in your case use degrees = 360. / numPoints. The potential implications are worse in this line of your code: yOffset = float(((length / coils) / numPoints)).

You declare float and int constants just by writing them either with or without a decimal point. No need to wrap them in a call to float() or int()

Upvotes: 2

Related Questions