Dashboard_avatar
Jan 23, 2011
Post id: 306898 Report Item

I'm trying to come up with a script that moves one object apart from another. For this I am experimenting with locators. I have a loctor that acts like the origin (p1) and another acts as the object that will move apart (p2). I got the script working fine for one plane. But the problem is when I try to do it for all 3 axis, I just cant figure out the maths (I am not really a math guy). In the 2d plane I used basic pythagorus formula. Is there a formula to determine 3d point on a streight line in 3d space? Please do help me figure out the third point (p3) I would be ever so gratful!

Avatar2
Jan 23, 2011
Post id: 306899 Report Item

whats about using vector algebra? Its totally simple stuff. If you have point p1 with coordinates <<x1,y1,z1>> and point p2 with <<x2,y2,z2>> then the vector X from p1 TO p2 equals X = p2 - p1 because p1 + X = p2 (simple, isnt it :D)
means: X = <<(x2-x1),(y2-y1),(z2-z1)>>
now the resulting X is your direction vector, the point p1 is the position vector. if you add the direction vector X to your position vector p1 you reach p2. Just as the equation above, only in words. Now you can take the direction vector and extend him by simply multiply it with some values to reach point p3.
Looks like p3 = p1 + aX  (a here is the value to extend the direction vector between p1 and p2)
If we want to have p3 located at the double distance of p1 to p2 we would calculate
p3 = <<x1,y1,z1>> + 2 * <<(x2-x1),(y2-y1),(z2-z1)>>
or longer:
 p3 = <<x1,y1,z1>> + <<((x2-x1) * 2),((y2-y1) * 2),((z2-z1) * 2)>>
or
p3 = <<(x1 + (x2-x1) * 2),(y1 + (y2-y1) * 2),(z1 + (z2-z1) * 2)>>

a practical example:

//create a locator and assign some random translation values
string $loc1[] = `spaceLocator`;
float $px = rand(-5,5);
float $py = rand(-5,5);
float $pz = rand(-5,5);
move $px $py $pz $loc1[0];

//create another one and move him randomly
string $loc2[] = `spaceLocator`;
$px = rand(-5,5);
$py = rand(-5,5);
$pz = rand(-5,5);
move $px $py $pz $loc2[0];

//now get the translation values of both locators and put them into vector variables
vector $p1 = `getAttr ($loc1[0] + ".translate")`;
//or: vector $p1 = `xform -query -worldSpace -translation $loc1[0]`;
//or: vector $p1 = `pointPosition -world $loc1[0]`; (applies only to point objects)
vector $p2 = `getAttr ($loc2[0] + ".translate")`;

//get the direction vector from p1 to p2
vector $directionVector = $p2 - $p1;

//create third locator for p3
string $loc3[] = `spaceLocator`;

//get and set the final position
vector $p3 = $p1 + $directionVector * 2;

move ($p3.x) ($p3.y) ($p3.z) $loc3[0];

Dashboard_avatar
Jan 24, 2011
Post id: 306900 Report Item

I thought I'd give this problem a try aswell. Since I am not good with math either I thought I'd give it my own approach.
I think that the idea from nowayfra is the official solution.
But this works just as well.

Basically what I did is get the position from p1 and p2 and blend these together.

So 0,5 % from p1 + 0,5% from p2 gives you eactly the center between the two.
But you can also overshoot ofcourse.

If you want to enter a value manually just change both entries of self.mySlider.getValue() to any value.
Any value between 0 and 1 will give you a position within the "range" of the two original objects.
Any value above or below that will make it overshoot in either direction.

Since an answer is already given in mel I descided to just leave this in python. If anyone wants I can rewrite this to mel :)
 (i hope noboddy minds)













1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43


# select 3 objects else you get a nice warning
if len(selected())!= 3:
warning ('please select exactly 3 objects. The last object wil move between the first 2 objects')
else:
# put all objects in their variables
originObjA = selected()[0]
originObjB = selected()[1]
moveObj = selected()[2]
 
# just used a simple class to create a window ^^
class buildUI:
def __init__(self):
self.mySlider = ''
self.curentPos = ''
self.buildWind()
self.i = 0
self.blendC = [0,0,0]
 
def buildWind(self):
cmds.window( width=300, height = 100 )
cmds.columnLayout( adjustableColumn=True )
# create our slider that we can use to blend the 3'rd object, it calls changeBlend when it gets dragged
self.mySlider = floatSlider( minValue = -5, maxValue = 5, dragCommand = self.changeBlend)
cmds.showWindow()
 
# here is our changeBlend proc.
def changeBlend(self, *args):
# first get the position of the 2 objects to blend between
matrix1 = xform (originObjA, query = True, translation = True, worldSpace = True)
matrix2 = xform (originObjB, query = True, translation = True, worldSpace = True)
 
# calculate the blending. (the slider goes from 0 to 5 in positive and negative directions.
# so we can use this as positive and negative percentage. ofcourse we can overshoot this :).
blendA = [x * (1-self.mySlider.getValue()) for x in matrix1]
blendB = [x * self.mySlider.getValue() for x in matrix2]
for x in blendA:
self.blendC[self.i] = blendA[self.i]+blendB[self.i]
self.i = self.i +1
self.i = 0
# set the position of the object now that we know the correct blending.
xform (moveObj, translation = self.blendC, worldSpace = True)
# build our interface.
buildUI()




 



self.mySlider.getValue()

Dashboard_avatar
Jan 24, 2011
Post id: 306906 Report Item

Jan, if you carefully expand the solutions in vector form you will notice that they yeald the same equation!

the % signs makes your explanation wrong but yeah.

Dashboard_avatar
Jan 24, 2011
Post id: 306907 Report Item

@nowayfra: WOW thanks man! That was really a huge help. Cant thank you enough. That works perfectly.

Thanks to others too for replying.

Dashboard_avatar
Jan 24, 2011
Post id: 306908 Report Item

@nowayfra: I have another extention to this problem. What if I wanted to move the p3 by a specific distence. For example I want to move the p3 exactly 1 unit away from p2. How would the math be for that?

Avatar2
Jan 24, 2011
Post id: 306909 Report Item

Its almost the same as above. If you have your direction vector figured out you now need to know how long it is to get the right multiplier to expand or truncate the direction vector to the unit vector (vector with a certain direction but a length of 1). Getting the length of a vector is as easy as calculating the hypotenuse of two given sides of a rectangle, you only add the third dimension to the equation: vector length = Squareroot of  (x² + y² + z²). You now have the length and with it the divisor for your direction vector to get the unit vector which you would add to your position vector p2 to get p3.

MEL has some usefull functions to let you handle such things easy without much typing:
mag <<x,y,z>> returns the length of a vector
unit <<x,y,z>> returns the unit vector of the given vector.

You should have a look into your Docs for "MEL and Expressions / functions", there is a section dedicated to vector functions.

Dashboard_avatar
Jan 28, 2011
Post id: 306943 Report Item

Thanks for all the help. I figured it all out and the script is running fine. Thanks again!