Cmds.curve periodic - maya command error

Hi!

I’m trying to create a curve from code. I get existing curve’s data like CVs, knots, periodic or not and degree and feed it into a cmds.curve command.

Here’s an example using data I got from a standard circle curve:

pts = [[0.7836116248912245, 4.798237340988473e-17, -0.7836116248912246], [6.785732323110912e-17, 6.785732323110912e-17, -1.1081941875543877], [-0.7836116248912245, 4.798237340988472e-17, -0.7836116248912244], [-1.1081941875543881, 3.517735619006027e-33, -5.74489823752483e-17], [-0.7836116248912245, -4.7982373409884725e-17, 0.7836116248912245], [-1.1100856969603225e-16, -6.785732323110917e-17, 1.1081941875543884], [0.7836116248912245, -4.798237340988472e-17, 0.7836116248912244], [1.1081941875543881, -9.253679210110099e-33, 1.511240500779959e-16], [1.1081941875543881, -9.253679210110099e-33, 1.511240500779959e-16], [1.1081941875543881, -9.253679210110099e-33, 1.511240500779959e-16], [1.1081941875543881, -9.253679210110099e-33, 1.511240500779959e-16]]

cmds.curve(p=pts, 
d=3.0,
per=True,
k=(-2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0))

However it gives me a “maya command error”. If I remove periodic and knots flags then it creates the curve, but it’s obviously open and not a closed circle.

I’m at a loss, there’s no explanation, just a generic error, and I assume that data should be correct as it’s grabbed from an existing curve.

What is my mistake here?

I honestly don’t know. I’d have to re-figure out how I handled this.

But looking back in my code for creating curves, I kept a separate command after the curve was created. Create the points first, without using the per flag. And then close it afterwards. This seems to work for me, except in your example, you no longer seem to need to repeat the points, or else it creates a sharp point where multiple points get placed.

controlCurve = cmds.curve(p=pts, d=3.0, k=(-2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0))
cmds.closeCurve(controlCurve, ch=False, ps=True, rpo=True)

According to the documentation:

when the “-per” flag is used. Notice that the first “degree” points are the same as the last “degree” points (ie. the first three points are the same as the last three points)’

So looking at your list I noticed the last 4 points are identical.

pts = [
[0.7836116248912245, 4.798237340988473e-17, -0.7836116248912246], 
[6.785732323110912e-17, 6.785732323110912e-17, -1.1081941875543877], 
[-0.7836116248912245, 4.798237340988472e-17, -0.7836116248912244], 
[-1.1081941875543881, 3.517735619006027e-33, -5.74489823752483e-17], 
[-0.7836116248912245, -4.7982373409884725e-17, 0.7836116248912245], 
[-1.1100856969603225e-16, -6.785732323110917e-17, 1.1081941875543884], 
[0.7836116248912245, -4.798237340988472e-17, 0.7836116248912244], 
[1.1081941875543881, -9.253679210110099e-33, 1.511240500779959e-16], 
[1.1081941875543881, -9.253679210110099e-33, 1.511240500779959e-16], 
[1.1081941875543881, -9.253679210110099e-33, 1.511240500779959e-16], 
[1.1081941875543881, -9.253679210110099e-33, 1.511240500779959e-16] ]

After replacing the last 3 with the first 3 I managed to get a circle out of the command.

pts = [
[0.7836116248912245, 4.798237340988473e-17, -0.7836116248912246], 
[6.785732323110912e-17, 6.785732323110912e-17, -1.1081941875543877], 
[-0.7836116248912245, 4.798237340988472e-17, -0.7836116248912244], 
[-1.1081941875543881, 3.517735619006027e-33, -5.74489823752483e-17], 
[-0.7836116248912245, -4.7982373409884725e-17, 0.7836116248912245], 
[-1.1100856969603225e-16, -6.785732323110917e-17, 1.1081941875543884], 
[0.7836116248912245, -4.798237340988472e-17, 0.7836116248912244], 
[1.1081941875543881, -9.253679210110099e-33, 1.511240500779959e-16], 
[0.7836116248912245, 4.798237340988473e-17, -0.7836116248912246], 
[6.785732323110912e-17, 6.785732323110912e-17, -1.1081941875543877], 
[-0.7836116248912245, 4.798237340988472e-17, -0.7836116248912244] ] 

(personally though I find this too much hassle and I’d go with @clesage’s solution )

Thanks guys!

I tried the first suggested approach and it does close the curve, but as you said, it has repeating points in the end. I suppose there’s a mistake in my function that grabs points from existing curve? Here’s what I’m doing:


Is there a mistake somewhere, or should I just check if point is similar to previous one and ignore it if it is? Like filter it out either while grabbing or while building the curve?

def get_cv_points(*args, **kwargs):
    '''
    Print number of points on selected CV into console.
    '''
    from BroTools.core.nodes import BroNode

    c = BroNode(cmds.ls(sl=True, long=True)[0])

    degs = c.degree
    spans = c.spans
    form = c.form

    cvs = degs + spans

    curveInfo = BroNode.create('curveInfo')
    curveInfo.connect(c, 'worldSpace[0]', 'inputCurve')
    knots = curveInfo.knots
    if knots:
        knots = knots[0]

    points = [degs, form, knots]
    for cv in range(0, cvs):
        points.append(cmds.pointPosition('{}.cv[{}]'.format(c, cv)))

    print ""
    print points
    print ""

    curveInfo.delete()

I’m not certain since I can’t check what your BroNode does.
But the following does a decent job of listing all cv positions for me.

sel = cmds.ls(sl=1)[0]
shp = cmds.listRelatives(sel, shapes=True)[0]
cvs = cmds.getAttr('{}.cv[*]'.format(shp))

pprint.pprint(cvs)
1 Like

It’s a wrapper around maya’s nodes, sort of like Theodox’s Nodule. Just an easier way to handle Maya’s nodes, create, get and set attributes in a more pythonic way and connect nodes. Makes the code more readable and shorter.

Thanks, I’ll try your code.

Tried it out, interesting. Whlie it works for curves that I draw myself, for the standard circle (cmds.circle) it shows all zeros.

from pprint import PrettyPrinter

pprint = PrettyPrinter()

circle = cmds.circle()


#sel = cmds.ls(sl=1)[0]
shp = cmds.listRelatives(circle, shapes=True)[0]
cvs = cmds.getAttr('{}.cv[*]'.format(shp))

pprint.pprint(cvs)

Outputs:

[(0.0, 0.0, 0.0),
 (0.0, 0.0, 0.0),
 (0.0, 0.0, 0.0),
 (0.0, 0.0, 0.0),
 (0.0, 0.0, 0.0),
 (0.0, 0.0, 0.0),
 (0.0, 0.0, 0.0),
 (0.0, 0.0, 0.0)]

But at least it gives the correct amount of points, so I can use length of the array to feed into pointPosition

But now it says knot vector is too long, apparently those extra points are needed for something. Sigh

Ah yes, I noticed the same thing when the circle has construction history. You want to make sure the shape you are feeding to the getAttr is the actual nurbs shape.

They are, There must be (numberOfPoints + degree - 1) knots, so if you want to use the periodic flag, you’d need to copy the first 3 points to the end of your point list. Which would give you the same amount of knots and points.

But! If you are not using ’ periodic, and are closing the curve instead, you do not need knots at all.

circle = cmds.circle(constructionHistory=False)

# List curve points
shp = cmds.listRelatives(circle, shapes=True)[0]
cvs = cmds.getAttr('{}.cv[*]'.format(shp))

# Build curve from point list
new_curve = cmds.curve(point=cvs, degree=3, n='newCurve')
cmds.closeCurve(new_curve, preserveShape=False, replaceOriginal=True)

Aaah, thanks, this certainly makes it a lot easier :slight_smile: I don’t think I’ll be losing much if anything if I ignore knots I guess?

EDIT:
Tried it and adapted to my code, was finally able to make a clean circle, thanks!