array issue

80 views
Skip to first unread message

Serena Xu

unread,
Jun 12, 2012, 12:11:15 PM6/12/12
to python_inside_maya
I'm having an issue updating the information in a class array
variable. I have a few variables storing point info on a plane. when I
delete that plane and make a new one the same name it still has info
from the first plane even after i run the method to get the info from
the second plane. here's my script

#move vertices as rod goes over it
import maya.OpenMaya as om
import maya.cmds as cmds
import math as m

class vertexInfo(object):
def __init__(self):
self.verX = []
self.verY = []
self.verZ = []
self.verIn = []

def saveDefaultPos(self):
del self.verX[0:len(self.verX)]
del self.verY[0:len(self.verY)]
del self.verZ[0:len(self.verZ)]
del self.verIn[0:len(self.verIn)]

om.MGlobal.clearSelectionList()
om.MGlobal.selectByName('pPlane1')
sList = om.MSelectionList()
om.MGlobal.getActiveSelectionList(sList)
iter1 = om.MItSelectionList ( sList, om.MFn.kGeometric )

while not iter1.isDone():
dagPath = om.MDagPath()
components = om.MObject()
sList.getDagPath( 0 ,dagPath, components)
iter2 = om.MItMeshVertex(dagPath, components)
while not iter2.isDone():
pt = iter2.position()
ind = iter2.index()
self.verX.append(pt.x)
self.verY.append(pt.y)
self.verZ.append(pt.z)
self.verIn.append(ind)
iter2.next()
iter1.next()
def check(self):
'''if #variable are not empty check to match
self.match(yesNo)
if yesNo == 0: #no match then run clear
self.clear()
self.saveDefaultPos()
if yesNo == 1: #yes match then keep going

'''

doubleArray = om.MScriptUtil()
spc = om.MSpace.kWorld

#check current position
##save cylinder as a selection
om.MGlobal.clearSelectionList()
om.MGlobal.selectByName('cyl')
sCyl = om.MSelectionList()
om.MGlobal.getActiveSelectionList(sCyl)
item = om.MDagPath()
sCyl.getDagPath(0, item)
item.extendToShape()
fnMesh = om.MFnMesh(item)
dagPath = om.MDagPath()
components = om.MObject()
sCyl.getDagPath( 0 ,dagPath, components)
cylPts = om.MItMeshVertex(dagPath, components)

##save plane as selection
om.MGlobal.clearSelectionList()
om.MGlobal.selectByName('pPlane1')
sList = om.MSelectionList()
om.MGlobal.getActiveSelectionList(sList)
iter1 = om.MItSelectionList ( sList, om.MFn.kGeometric )

while not iter1.isDone():
dagPath = om.MDagPath()
components = om.MObject()
sList.getDagPath( 0 ,dagPath, components)
iter2 = om.MItMeshVertex(dagPath, components)
while not iter2.isDone():
thisPt = iter2.position()
ind = iter2.index()
inPoint = om.MPoint(thisPt.x, thisPt.y, thisPt.z)
outPoint = om.MPoint(0.0, 0.0, 0.0)
fnMesh.getClosestPoint(inPoint, outPoint, spc)
x = (outPoint[0] - thisPt.x)
y = (outPoint[1] - thisPt.y)
z = (outPoint[2] - thisPt.z)
dist = m.sqrt(m.pow(x, 2) + m.pow(y, 2) + m.pow(z, 2))

# if current position is default position then run
check to move down
if thisPt.x == self.verX[ind] and thisPt.y ==
self.verY[ind] and thisPt.z == self.verZ[ind]:
#find the normal of the closest point on the
cylinder
doubleArray.createFromList([1, 1, 1], 1)
cylNor = om.MVector(doubleArray.asDoublePtr())
cylPts.getNormal(cylNor, spc)
#print cylNor.x
dist = m.sqrt(m.pow(x, 2) + m.pow(y, 2) + m.pow(z,
2))
if dist < 2:
#find that remaining distance cylNor is
magnitude 1
nX = -cylNor.x * (2 - dist)
nY = -cylNor.y * (2 - dist)
nZ = -cylNor.z * (2 - dist)
doubleArray.createFromList([nX, nY, nZ], 1)
moveVec =
om.MVector(doubleArray.asDoublePtr())
#move down the remaining distance
iter2.translateBy(moveVec, spc)
iter2.next()

#if current position is not default then run check to
move it back in place
else:
if dist > 2:
dx = verX[ind] - thisPt.x
dy = verY[ind] - thisPt.y
dz = verZ[ind] - thisPt.z
doubleArray.createFromList([dx, dy, dz], 1)
vec = om.MVector(doubleArray.asDoublePtr())
iter2.translateBy(vec, spc)

iter2.next()

iter1.next()

##save cylinder as a selection
om.MGlobal.clearSelectionList()
om.MGlobal.selectByName('cyl')
sCyl = om.MSelectionList()
om.MGlobal.getActiveSelectionList(sCyl)
item = om.MDagPath()
sCyl.getDagPath(0, item)
item.extendToShape()
fnMesh = om.MFnMesh(item)
dagPath = om.MDagPath()
components = om.MObject()
sCyl.getDagPath( 0 ,dagPath, components)
cylPts = om.MItMeshVertex(dagPath, components)

##save plane as selection
om.MGlobal.clearSelectionList()
om.MGlobal.selectByName('pPlane1')
sList = om.MSelectionList()
om.MGlobal.getActiveSelectionList(sList)
iter1 = om.MItSelectionList ( sList, om.MFn.kGeometric )

while not iter1.isDone():
dagPath = om.MDagPath()
components = om.MObject()
sList.getDagPath( 0 ,dagPath, components)
iter2 = om.MItMeshVertex(dagPath, components)
while not iter2.isDone():
thisPt = iter2.position()
ind = iter2.index()
inPoint = om.MPoint(thisPt.x, thisPt.y, thisPt.z)
outPoint = om.MPoint(0.0, 0.0, 0.0)
fnMesh.getClosestPoint(inPoint, outPoint, spc)
x = (outPoint[0] - thisPt.x)
y = (outPoint[1] - thisPt.y)
z = (outPoint[2] - thisPt.z)
dist = m.sqrt(m.pow(x, 2) + m.pow(y, 2) + m.pow(z, 2))

# if current position is default position then run
check to move down
if thisPt.x == self.verX[ind] and thisPt.y ==
self.verY[ind] and thisPt.z == self.verZ[ind]:
#find the normal of the closest point on the
cylinder
doubleArray.createFromList([1, 1, 1], 1)
cylNor = om.MVector(doubleArray.asDoublePtr())
cylPts.getNormal(cylNor, spc)
#print cylNor.x
dist = m.sqrt(m.pow(x, 2) + m.pow(y, 2) + m.pow(z,
2))
if dist < 2:
#find that remaining distance cylNor is
magnitude 1
nX = -cylNor.x * (2 - dist)
nY = -cylNor.y * (2 - dist)
nZ = -cylNor.z * (2 - dist)
doubleArray.createFromList([nX, nY, nZ], 1)
moveVec =
om.MVector(doubleArray.asDoublePtr())
#move down the remaining distance
iter2.translateBy(moveVec, spc)
iter2.next()

#if current position is not default then run check to
move it back in place
else:
if dist > 2:
dx = verX[ind] - thisPt.x
dy = verY[ind] - thisPt.y
dz = verZ[ind] - thisPt.z
doubleArray.createFromList([dx, dy, dz], 1)
vec = om.MVector(doubleArray.asDoublePtr())
iter2.translateBy(vec, spc)

iter2.next()
iter1.next()

i'm using this to run the methods

v = vertexInfo()
v.saveDefaultPos()
jobNum = cmds.scriptJob(event=('timeChanged', v.check))


Please help! Thanks!!

Justin Israel

unread,
Jun 12, 2012, 1:35:41 PM6/12/12
to python_in...@googlegroups.com
Hey Serena,

Make sure you use some form of external code view tool for this much code. Small snippets are fine, but the messages can't handle the formatting of this size and it makes it hard for others to read it. The wrapping breaks the lines, and indentations, etc.

I reformatted it into a gist for ya:  https://gist.github.com/2918740
(pastebin.com works too, but I like gist because of how you can edit and version it up, and see a diff)

It was crashing because of a naming error here (line 113):
dx = verX[ind] - thisPt.x  # self.verX
dy = verY[ind] - thisPt.y  # self.verY
dz = verZ[ind] - thisPt.z  # self.verZ

Could you maybe explain a little more specifically how to reproduce the problem? This is a lot of code and its hard to understand what is going on (a lot of repetition of similar operations). 

If you are trying to clear those instance attribute lists (not class attributes), you can either just assign them new lists, or if you are trying to not break a reference that some other variable may have to that same attribute, you can clear the contents with:
    del self.verX[:]   # or self.verX = [] if you don't care about references to the same list

Which specific area is not working as expected?

From the looks of the code, I don't see really why you would need 4 different lists with so many appends, just to look them up by index again later. I don't see the self.verIn even being used... You could probably just store them in a dictionary and have much faster access and less multi-appends:

self.ver = {}
self.ver[ind] = (x,y,z)
x,y,z = self.ver[ind]
self.ver.clear()




Serena Xu

unread,
Jun 12, 2012, 2:11:26 PM6/12/12
to python_inside_maya
What i had intended to do was to move a cylinder over a plane and
leave an indentation as the cylinder goes over. I wanted the plane to
be elastic so when the cylinder leaves the immediate region the plane
returns to its initial state. so I have the saveDefaultPos() to save
the vertex information and the check() to displace the vertices of
the plane when the cylinder moves close to it. The first time i run it
the result will be as I expect but when I delete the old pPlane1 and
make a new one with the same name I run the saveDefaultPos() to save
the vertex info of the new plane. When i run check() now the results
are not what I expect because the vertices move to the positions of
the old pPlane1 instead of the second one I created.

I had thought of using a matrix to store info instead of so many
arrays but i ran into some syntax errors (still having trouble with
the language) so I thought i'd do a small cheat for now. I'll go fix
that now that you've helped me out so my code can be less redundant.

Justin Israel

unread,
Jun 12, 2012, 2:44:13 PM6/12/12
to python_in...@googlegroups.com
Hmm, well this is what I did...

1. Using this version with the fixed attribute names: https://gist.github.com/2918740/2e9054947f2c22696d472de968c81f03e4a0330b
2. Create a plane
3. New class instance, set defaults, start scriptJob:
    v = vertexInfo()
    v.saveDefaultPos()
    jobNum = cmds.scriptJob(event=('timeChanged', v.check))
4. go through time range and observe deformation, then go back to frame 1 (zero deform)
5. delete plane, create new one with same name but clearly different size and subdivs
6. v.saveDefaultPos()
7. step through timeline again, and deformation seems to work as expected for me?

Serena Xu

unread,
Jun 12, 2012, 3:21:36 PM6/12/12
to python_inside_maya
Oh that did work as I expected. Thanks!
Could it be that with the mixed up names from my script before maya
didnt complain because the values did exist (even though they were
wrong values)?

How do make this script work as I scrub the timeline?
cmds.scriptJob(event=('timeChanged', v.check)) only runs it when i
click through the timeline. It doesnt show up when I playblast.
> ...
>
> read more »

Justin Israel

unread,
Jun 12, 2012, 4:40:06 PM6/12/12
to python_in...@googlegroups.com
Unfortunately the scripJob doesn't work if its not an interactive process:

This triggering happens very frequently so for speed considerations no events are forwarded during playback. This means that you cannot use scriptJob -tc tcCallback; to alter animation behaviour. Use an expression instead, or the rendering callbacks "preRenderMel" and "postRenderMel".

But what you could do to make this start working right away is use a scriptNode instead. You can tell the scriptNode to update on frame change:

n = cmds.scriptNode(name="vertexDeformer", sourceType="python", scriptType=7, bs="v.check()")

This will work in a playblast

 

Serena Xu

unread,
Jun 12, 2012, 6:15:29 PM6/12/12
to python_inside_maya
oh that works! Thanks!

On Jun 12, 4:40 pm, Justin Israel <justinisr...@gmail.com> wrote:
> Unfortunately the scripJob doesn't work if its not an interactive process:
>
> http://download.autodesk.com/global/docs/maya2012/en_us/CommandsPytho...
> ...
>
> read more »

cedric bazillou

unread,
Jun 13, 2012, 8:33:06 AM6/13/12
to python_in...@googlegroups.com
Hello , just an idea: wouldn't it be easier to write a deformer?
@Justin on your code you already use the maya API, do you have to compute vector length/distance by hand?
the MVector class has already a length method and you can also query the distance between 2 MPoint: PointA.distanceTo (PointB).

you can also store and update vectorArray/ pointArray attribute on regular node attribute: Just a personal preference, I just see lots of code floating around where a lot of thing present in maya is ditched just for the sake of playing with python( people are free to do that , if they are comfortable with something its better to stick with it )

Serena Xu

unread,
Jun 13, 2012, 10:23:39 AM6/13/12
to python_inside_maya
@cedric
I wasnt aware of the distanceTo. thanks!
i'm still getting use to use the API and i'm still learning what's
available to use
> ...
>
> read more »

Justin Israel

unread,
Jun 13, 2012, 11:08:09 AM6/13/12
to python_in...@googlegroups.com
I didn't write the code. Serena did. I just helped her out by pasting into a readable gist. She is still learning and I assume she has not yet delved into writing a scripted plugin node. 


--

cedric bazillou

unread,
Jun 13, 2012, 11:26:29 AM6/13/12
to python_in...@googlegroups.com
That makes sense, sorry for the confusion: @deformer : I write node, so when something comes up I am found guilty on relying sometimes too much on them... But in this case this is what seems to me the most logical.
Reply all
Reply to author
Forward
0 new messages