what axis your function does align?

# Align an axis to a plane, using other axis?

**3ak**#31

You wrote that my func returns different results. i created box, plane, rotated them randomly, run my script. it aligned box to plane (let’s say rotate box around Y to align X to XY plane of Plane). then i just run script second time and box didn’t rotate. So i can’t understand what error did you mention?

if it possible could you share matrix3 values for 2 objects and what axis align to what plane. and i’ll try it out.

**denisT**#34

i don’t see any axis aligned:

```
(
delete objects
s = point name:"s" axistripod:on constantscreensize:on isselected:on
t = plane name:"t"
rotate s (eulerangles 33 25 17)
tm1 = s.transform
tm2 = t.transform
rotAxis = normalize tm1.row2
rotdAxis = normalize tm1.row1
axis3 = cross (normalize tm1.row2) (normalize tm2.row3)
rot = acos (dot rotdAxis (normalize axis3))
if rot>90 then rot-=180
rQuat = quat (rotAxis.x * (sin(rot / 2))) (rotAxis.y * (sin(rot / 2))) (rotAxis.z * (sin(rot / 2))) (cos (rot / 2))
if (normalize(cross rotdAxis axis3)) == rotAxis then rQuat = inverse rQuat else rQuat
rotate s rQuat
)
```

it’s why I’ve asked about that…

**denisT**#35

here is how to align an axis to a direction and a plane:

```
fn alignAxisToDir node axis:#z dir:[0,0,1] =
(
vec = case axis of
(
#x: node.transform[1]
#y: node.transform[2]
#z: node.transform[3]
)
tm = node.transform
vec = normalize vec
dir = normalize dir
rtm = angleaxis (acos (dot vec dir)) (normalize (cross dir vec))
node.transform = translate (rotate (scalematrix tm.scale) (tm.rotation*rtm)) tm.pos
)
fn alignAxisToPlane node axis:#x normal:[0,0,1] =
(
vec = case axis of
(
#x: node.transform[1]
#y: node.transform[2]
#z: node.transform[3]
)
vec = normalize vec
normal = normalize normal
front = normalize (cross vec normal)
alignAxisToDir node axis:axis dir:(cross normal front)
)
```

**3ak**#36

Malkalypse. this should work without dot prod check:

```
fn rotateToAlign obj rotatedAxis rotationAxis planeNormal =
(
if rotatedAxis != rotationAxis then
(
proj = cross (normalize rotationAxis) (normalize planeNormal)
rot = acos (dot rotatedAxis (normalize proj))
if rot>90.0 then abs (rot-=180)
rotationAxis = normalize(cross rotatedAxis proj)
rQuat = quat (rotationAxis.x * (sin(rot / 2))) (rotationAxis.y * (sin(rot / 2))) (rotationAxis.z * (sin(rot / 2))) (cos (rot / 2))
rotate obj rQuat
)
)
rotateToAlign $box001 $box001.transform.row1 $box001.transform.row2 $plane001.transform.row3
```

**eek**#37

From playing with a beet mat this might work - basically if your aligning to the XY plane its direction is going to be Z ([0,0,1]) - if its the identity. So lets keep it simple and rotate object A’s Y axis about its X so that it lies flat on the XY world plane.

proj = cross a.transform.row1 [0,0,1] – project onto the XY plane

ang = acos (dot a.transform.row2 proj) – get the angle of the Y axis relative to the projection

a.rotation.controller[1].value += ang

or

a.rotation.controller[1].value += degToRad ang

That should be it roughly, if you get the cross of the projection and the Y axis you can check its sign to rotate it in the correct direction.

If you wanted to use the axis of the plane in any direction you could use plane.dir to give you its normal. This maybe all wrong as im not next to max.

**denisT**#38

still not working right… check:

```
s = point name:"s" axistripod:on constantscreensize:on isselected:on
rotate s (eulerangles 33 25 17)
rotateToAlign s s.transform[1] s.transform[3] [0,0,1]
rotateToAlign s s.transform[3] s.transform[1] [0,0,1]
-- repeat next line several times
rotateToAlign s s.transform[3] s.transform[2] [0,0,1]
```

**3ak**#39

and whts wrong there?)

it alignes to plane perfectly. The reason it rotates is cause planeNormal and axis of rotation are the same and cross prod = [0,0,0]. thx. I should add check.

```
fn rotateToAlign obj rotatedAxis rotationAxis planeNormal =
(
if rotatedAxis != rotationAxis then
(
if rotationAxis != planeNormal then
(
format "rotationAxis = %
" rotationAxis
format "planeNormal = %
" planeNormal
proj = cross (normalize rotationAxis) (normalize planeNormal)
rot = acos (dot rotatedAxis (normalize proj))
) else rot = 0.0
if rot>90.0 then abs (rot-=180)
rotationAxis = normalize(cross rotatedAxis proj)
rQuat = quat (rotationAxis.x * (sin(rot / 2))) (rotationAxis.y * (sin(rot / 2))) (rotationAxis.z * (sin(rot / 2))) (cos (rot / 2))
rotate obj rQuat
)
)
```

But new problem arises - it prints out [0,0,1] [0,0,1] for both axises and dot prod gives us 90 angle for zero vector. But it shouldn’t be cause “if” condition should execute else part in this case.

I just can’t get why 3ds max behave like this.

and where can i choose axis of rotation in your fn?

**denisT**#40

my method doesn’t need a axis of rotation. it aligns using the shortest way. I calculate the axis of rotation inside the function…

**3ak**#41

but task is to align to plane rotating around given axis. you can align X axis to plane XY of second object rotating around both of the remaining axises of the first object. and you leave no choice.

**denisT**#42

the task was set incorrectly. there are two things - align and rotate. doing both at the same time doesn’t make sense. but just for practicing in math it’s easy to change my function to support the pole-vector to rotate about…

**3ak**#43

Why incorrectly? Rotating X around Z to align X to plane results in different vector than rotating X around Y to align with the same plane:

and TS asked for possibility to choose axis of rotation.

**denisT**#44

the nice picture by the way…

well… you see a sense of the aligning using a pole-vector. fine!

how is about to move an object to some place using rotations only? it’s doable, but does it make sense?

**3ak**#45

thx)

i don’t know how TS will use it so maybe it has sense)

a bit offtopic: do you know why sometimes the only way to compare values is as strings? I had two vectors which are the same and checking this in if-then-else block executes the code which should run only if vectors differ (i printed out values and they are the same)? so i had to do as string comparison.

**denisT**#46

Malkalypse has a gift…

his questions keep me in fighting trim all the time

that’s the best one http://forums.cgsociety.org/showthread.php?f=98&t=893959

solving the task i’ve made one of my coolest tools. thanks a lot!

**Malkalypse**#47

Denis: Thanks, that had me laughing quite hard… it really made my day

I think a useful guideline for most things is “If it’s easy, do it yourself. If it’s hard, find an expert.”

3ak: In general terms it’s good for anything that requires aligning an edge to a surface. And being able to choose the “pole vector” is definitely helpful. (Also, I agree with what Denis said, that is an awesome picture… how did you happen to make it?)

As for your question… I’m guessing the values you are trying to compare are array or matrix elements? Let me quote Bobo himself on this one:

Matrices [and] Arrays, are compound values where the comparison only looks to see if the two variables point at the same memory (in other words, if they are instances) … you cannot compare the CONTENT of the value as it does not do a component by component comparison, only a top-level test.

If your values are something else… then no clue!

**denisT**#48

well… here is a version where you can optionally choose the “pole-vector”:

```
fn alignAxisToPlane node axis:#x pole: normal:[0,0,1] =
(
tm = node.transform
vec = case axis of
(
#x: tm[1]
#y: tm[2]
#z: tm[3]
)
vec = normalize vec
normal = normalize normal
if abs (dot vec normal) > 0.0 do
(
rot = if iskindof pole Point3 and abs (dot vec pole) < 1.0 then
(
pole = normalize pole
normalize (cross pole normal)
) else vec
front = normalize (cross rot normal)
side = normalize (cross normal front)
if (dot vec side) < 0.0 do side = -side
rtm = angleaxis (acos (dot vec side)) (normalize (cross side vec))
node.transform = tm = translate (rotate (scalematrix tm.scale) (tm.rotation*rtm)) tm.pos
)
tm
)
```

the function aligns always using the shortest way.

This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.