Maya python - Place Node Along Vector

Is this the best way to go about placing an object along the vector created by two other objects in the scene? I hope you guys can help me make this more efficient as it seems very redundant and long for such a simple concept. Thanks



import maya.cmds as cmds
import random

cmds.select(all=True)   
cmds.delete()

#------------------------------TEST SCENE SETUP

def genPos():
    x = random.uniform(-5,5)
    y = random.uniform(0,5)
    z = random.uniform(-5,5)
    return (x, y, z)

a = cmds.spaceLocator(n='ctrl_00')
b = cmds.spaceLocator(n='ctrl_00')

cmds.xform(a, t=(genPos()) )
cmds.xform(b, t=(genPos()) )

cmds.createDisplayLayer(name="Ctrls")
cmds.editDisplayLayerMembers('Ctrls', a, b)
cmds.setAttr('Ctrls.color' ,14)

cmds.select(clear=True)


#-----------------------THE SCRIPT
def normlizedVector(vecA,vecB,offset):

    nX = vecB[0] - vecA[0]
    nY = vecB[1] - vecA[1]
    nZ = vecB[2] - vecA[2]

    #vectorLength = distance vecA vecB
    # find the distance between the two supplied point3 values
    distX = pow( (vecA[0] - vecB[0] ) , 2.0 ) 
    distY = pow( (vecA[1] - vecB[1] ) , 2.0 ) 
    distZ = pow( (vecA[2] - vecB[2] ) , 2.0 )

    vecLength = sqrt(distX + distY + distZ)

    # the normalized vector is calculated by dividing the X, Y and Z coordinates by the length
    calcX = nX / vecLength
    calcY = nY / vecLength
    calcZ = nZ / vecLength

    # project point along vector, offset by a given value
    ptX = vecB[0] + (calcX * offset)
    ptY = vecB[1] + (calcY * offset)
    ptZ = vecB[2] + (calcZ * offset)

    return (ptX, ptY, ptZ)


posA = cmds.xform(a,q=1,ws=1,rp=1)  
posB = cmds.xform(b,q=1,ws=1,rp=1)  

pt = normlizedVector(posA,posB,10)

c = cmds.spaceLocator(n='main')
cmds.xform(c, t=(pt) )
posC = cmds.xform(c,q=1,ws=1,rp=1) 

cmds.distanceDimension( sp=posB, ep=posC )

I use PyMel and it has a great vector class for doing that stuff. Or you could use the maya API vector class. They are basically the same.

# To get the vector between the two points you just need their positions in world space and you subtract one from the other
vector = b-a #This gives you a vector that points from a to b

# If you want to make it a unit vector you can use this (PyMel version)
vector.normalize()

# You now only need to add this new vector to the starting position, which would be point a and multiply it by your offset
c = a + (vector * offset)
# And you position your third object at c

Hope this helps.

[QUOTE=raziel;24256]I use PyMel and it has a great vector class for doing that stuff. Or you could use the maya API vector class. They are basically the same.

# To get the vector between the two points you just need their positions in world space and you subtract one from the other
vector = b-a #This gives you a vector that points from a to b

# If you want to make it a unit vector you can use this (PyMel version)
vector.normalize()

# You now only need to add this new vector to the starting position, which would be point a and multiply it by your offset
c = a + (vector * offset)
# And you position your third object at c

Hope this helps.[/QUOTE]

Would you be able to show me how to get this working exactly?
Thank you

doing

vecB = (0,2,5)
vecA = (3,7,10)

vecB - vecA errors out. How can this be written?

Is this the proper way to create the same function? Any extras i should remove or get rid of. I want to make sure I’m writing things correctly and/or efficiently.

Thank you again guys for the help.


from pymel.all import *
import pymel.core.datatypes as dt
import maya.cmds as cmds
import random

cmds.select(all=True)   
cmds.delete()

#------------------------------TEST SCENE SETUP

def genPos():
	x = random.uniform(-10,10)
	y = random.uniform(0,10)
	z = random.uniform(-10,10)
	return (x, y, z)
	
a = cmds.spaceLocator(n='pipeCtrl_00')
b = cmds.spaceLocator(n='pipeCtrl_00')

cmds.xform(a, t=(genPos()) )
cmds.xform(b, t=(genPos()) )


#-----------------------THE SCRIPT
def normlizedVector(vecA,vecB,offset):
	
	# To get the vector between the two points you just need their positions in world space and you subtract one from the other
	vX = vecB[0] - vecA[0]
	vY = vecB[1] - vecA[1]
	vZ = vecB[2] - vecA[2]
	
	# the normalized vector
	vector = dt.Vector(vX, vY, vZ)
	vector.normalize()
	
	# project point along vector, offset by a given value
	ptX = vecB[0] + (vector[0] * offset)
	ptY = vecB[1] + (vector[1] * offset)
	ptZ = vecB[2] + (vector[2] * offset)
	
	return (ptX, ptY, ptZ)
	
#---------------------------------	
posA = cmds.xform(a,q=1,ws=1,rp=1)  
posB = cmds.xform(b,q=1,ws=1,rp=1)  

pt = normlizedVector(posA,posB,5.5)

c = cmds.spaceLocator(n='pipeCtrl_00')
cmds.xform(c, t=pt )

posC = cmds.xform(c,q=1,ws=1,rp=1) 
cmds.distanceDimension( sp=posB, ep=posC )

I will give you some pointers on how you can handle it yourself and get started with pymel, if you are interested.
I usually import pymel.core as pm. Pymel doesn’t handle objects as strings as MEL or standard cmds python does. It contains a pointer to the node object in the memory. And for every Maya node type it has a class with the same. So if you use pymel to create a locator it will return the class of the created object. In this example a = pm.spaceLocator() would give you an instance of the Transform class, since a locator is basically just a transform node. You can check the node type by typing a.nodeType and the class name with a.class. The class name will be written with a capital letter. With that information you go to pymel.core.nodetypes — PyMEL 1.0.5 documentation and find your class. In this case: pymel.core.nodetypes.Transform — PyMEL 1.0.5 documentation
Now you can use the classes methods to get your positions. For a you would write posA = a.getTranslation(space = “world”). And that will return you an instance of the Vector class containing the nodes position in world space. The Vector class has its own methods that allow you to subtract the two vectors and normalize the result. And you can set the last nodes location with c.setTranslation( location, space = “world”).

Go through the introduction pages in the documentation to find out more about pymel and things will probably become clearer. Or if you prefer video tutorials you can check this out http://www.cgcircuit.com/course/intro-to-pymel-part-1. Geordie covers many topics and the tutorial is definitely worth the money.
Good luck with your project.

Hey JokerMartini,

There are several ways you can approach this, and what you’ve outlined may work, however what Raziel is saying, is that if you write this yourself in python (create your own functions/class and math) it will be less efficient or as quick as using some of the SDK function/classes that are tailored to do these calculations.

Note that in some cases you may need to do the math yourself in python, but in most cases it’s best to use the functions and classes supplied by the 3d software to do this kind of stuff.

Here’s a quick example, using OpenMaya’s MVector Class…

import maya.cmds as mc
import maya.OpenMaya as om

def placeNodeAtOffset(pt1, pt2, offset, node):
	V1 = om.MVector(*pt1)
	V2 = om.MVector(*pt2)
	
	V3 = (V1 - V2).normal()
	V4 = V1 + V3 * offset
	
	mc.move(V4.x,V4.y,V4.z,node) 
	

	
pt1,pt2 = (1,2,3),(4,5,6)
offset = 5.0
node = 'locator3'

placeNodeAtOffset(pt1, pt2, offset, node)