# Rotating planes so that one rotationaxis is set to zero

Hello everybody,

I'm fairly new to maxscript but I have some experience with c and java.

My Problem:

Within my scenes there are planes that are placed and rotated by hand. The person who placed them now needs two values from those planes: heading and the pitch

To be more precise: The Values for pitch (or drop as it's an tectonically problem) need to be between 0-90 degrees
The Values for heading need to be between 0-360 degrees. (both eulerangles)

I don't actually need to rotate those planes in the end but I really need those values.

My solution so far:
I don't know if there is an easier way to do this in maxscript. So please point out any stupid stuff I'm doing.

1. collect all planes in the scene and convert them to poly with only one face

2. get normal vector for each plane (normalvector = polyOp.getFaceNormal 1)

3. get the "horizontal" vector for that plane (horizontalVector = normalize (cross [0,0,1] normalvector))

4. get the "vertical" vector (verticalVector = normalize (cross horizontalVector normalvector ))

5. get the vector facing to the front (frontVector = normalize ([normalvector , normalvector , 0]))

6. after all that I calculate the angle between the vertical vector and the front vector with (theAngle = acos(dot (normalize frontVector ) (normalize verticalVector )))

All the results till now were really strange. In some cases I looked like it worked correctly and in others it really wasn't right at all.

Am I missing something here? Am I using the right approach to this problem?

I can't provide any working code right now because of some strange bug in maxscript. Nevertheless would I be very thankful if anyone has an idea how this could be solved?

If you need any more code I will happily post any "non-working" snippets ;-)

Cheers,
Per

## Comment viewing options That's exactly what my snippet finds. Did you try it?
Make a plane, rotate it randomly and run the code. Then check the result.
Note that the angle follows the usual convention, i.e. 0° points towards positive X and positive angles are CCW. ### I tried your code but my

I tried your code but my results weren't right.

Nevertheless I found a solution my self. Thank you anyway.

Here is my final code:

```	out_name = ((GetDir #export)+"/tectdata.txt")
out_file = createfile out_name

north = [0,1,0]

for obje in Shapes  where classOf obje == Section do
(
sectionrotation  = quatToEuler2(obje.transform.rotation)
p = Plane pos: [obje.pos.x, obje.pos.y, obje.pos.z] width:10 length:10 widthsegments:1 lengthsegments:1 isSelected:off
gSHsetObjectRotation p sectionrotation.x sectionrotation.y sectionrotation.z
obj_poly = convertToPoly(p)

local nv = polyOp.getFaceNormal obj_poly 1
if (nv.z < 0) then
(
local nv = polyOp.getFaceNormal obj_poly 1
local fv = [nv.x, nv.y, 0]
local hv = normalize (cross [0,0,1] nv)
local vv = normalize (cross hv nv)
--local heading = acos (dot nv y_axis)
local heading = acos((nv.x * north.x +nv.y*north.y) / (sqrt(nv.x^2 + nv.y^2) * sqrt(north.x^2+north.y^2)))

local drop = acos (dot nv z_axis)
if (drop > 90) then
( drop = 180-drop)
format "%; %; %\n" obje.name drop heading nv fv to:out_file
) else
(
local fv = [nv.x, nv.y, 0]
local hv = normalize (cross [0,0,1] nv)
local vv = normalize (cross hv nv)
--local heading = acos (dot nv y_axis)
local heading = acos((nv.x * north.x +nv.y*north.y) / (sqrt(nv.x^2 + nv.y^2) * sqrt(north.x^2+north.y^2)))

local drop = acos (dot nv z_axis)
if (drop > 90) then
( drop = 180-drop)
format "%; %; %\n" obje.name drop heading nv fv to:out_file
)

delete p
)
close out_file

fn gSHsetObjectRotation obj rx ry rz =
(
-- Reset the object's transformation matrix so that
-- it only includes position and scale information.
-- Doing this clears out any previous object rotation.
local translateMat = transMatrix obj.transform.pos
local scaleMat = scaleMatrix obj.transform.scale
obj.transform = scaleMat * translateMat

-- Perform each axis rotation individually
rotate obj (angleaxis rx [1,0,0])
rotate obj (angleaxis ry [0,1,0])
rotate obj (angleaxis rz [0,0,1])
)``` ### and one more thing...

I'm not looking for the actual object heading (the sections(planes) are randomly placed by hand). I just need the heading of the drop. hopefully that helps a little understanding the problem. ### Hi,

this is what i've got so far:

```	out_name = ((GetDir #export)+"/tectdata.txt")
out_file = createfile out_name

north = [0,1,0]

for obje in Shapes  where classOf obje == Section do
(
sectionrotation  = quatToEuler2(obje.transform.rotation)
p = Plane pos: [obje.pos.x, obje.pos.y, obje.pos.z] width:10 length:10 widthsegments:1 lengthsegments:1 isSelected:off
gSHsetObjectRotation p sectionrotation.x sectionrotation.y sectionrotation.z
obj_poly = convertToPoly(p)

local nv = polyOp.getFaceNormal obj_poly 1
if (nv.z < 0) then
(
local nv = polyOp.getFaceNormal obj_poly 1
local fv = [nv.x, nv.y, 0]
local hv = normalize (cross [0,0,1] nv)
local vv = normalize (cross hv nv)
local heading = acos (dot nv y_axis)
--local heading = atan2 nv.y nv.x

local drop = acos (dot nv z_axis)
if (drop > 90) then
( drop = 180-drop)
format "name:%, drop:%, heading:%, nv:% fv:%\n" obje.name drop heading nv fv to:out_file
) else
(
local fv = [nv.x, nv.y, 0]
local hv = normalize (cross [0,0,1] nv)
local vv = normalize (cross hv nv)
local heading = acos (dot nv y_axis)
--local heading = atan2 nv.y nv.x

local drop = acos (dot nv z_axis)
if (drop > 90) then
( drop = 180-drop)
format "name:%, drop:%, heading:%, nv:% fv:%\n" obje.name drop heading nv fv to:out_file
)

)
close out_file

fn gSHsetObjectRotation obj rx ry rz =
(
-- Reset the object's transformation matrix so that
-- it only includes position and scale information.
-- Doing this clears out any previous object rotation.
local translateMat = transMatrix obj.transform.pos
local scaleMat = scaleMatrix obj.transform.scale
obj.transform = scaleMat * translateMat

-- Perform each axis rotation individually
rotate obj (angleaxis rx [1,0,0])
rotate obj (angleaxis ry [0,1,0])
rotate obj (angleaxis rz [0,0,1])
)```

and I'm using the following script to generate my test enviroment:

```for xr = 0 to 360 by 30 do
(
for yr = 0 to 360 by 30 do
(

p = section pos: [xr,yr,0]
gSHsetObjectRotation p xr yr 0

)
)

fn gSHsetObjectRotation obj rx ry rz =
(
-- Reset the object's transformation matrix so that
-- it only includes position and scale information.
-- Doing this clears out any previous object rotation.
local translateMat = transMatrix obj.transform.pos
local scaleMat = scaleMatrix obj.transform.scale
obj.transform = scaleMat * translateMat

-- Perform each axis rotation individually
rotate obj (angleaxis rx [1,0,0])
rotate obj (angleaxis ry [0,1,0])
rotate obj (angleaxis rz [0,0,1])
)```

As you can see I implemented your samples and now all my drop angles are correct. Thank you very much for that! But ;-) ...my heading is still messed up. It seems if it is giving me less than half the time correct results and the rest is just screwed up.

What am I missing here guys?

Both the atan2 and the acos(dot v1 v2) solutions aren't working correctly. ### hi

hi fexed , the garp 's solution is right and
work with face normal as well ( just have to convert negative angle in positive value )

i just want to give you a small advice
when you work with maxscript, dont hesitate to create small interface to check

quick new script a couple of output field
a timer then you could see really well what s happen in your test case
cut and paste when everithing s fine

sorry

example :

north = [0,1,0]
rollout unnamedRollout "Untitled" width:388 height:265
(
Timer tmr1 "Timer" pos:[328,220] width:24 height:24 interval:100
edittext drop "" pos:[72,30] width:125 height:22
edittext dir "" pos:[72,75] width:125 height:22

on tmr1 tick do
(
if \$ == undefined do return false
nv = polyOp.getFaceNormal \$ 1
heading = (atan2 nv.y nv.x )
dropt = acos ( dot nv z_axis )
drop.text = ( dropt as string )
dir.text= ( heading as string )
)
)

createdialog unnamedRollout

shanghalf ### If I understand correctly...

```theFile = createFile "C:\\testdata.txt"
for obj in geometry do
(
local nv = obj.dir
local drop = acos (dot nv z_axis)
local heading = atan2 nv.y nv.x
)
close theFile```

You don't need to convert to anything.
These angles correspond to the pivot, not the geometry. If the pivot has been rotated independently of the object, you need a face normal. ### Hi again, two things that

Hi again,

two things that I've come up with so far.

First I simplified my code a lot:

```	out_name = ((GetDir #export)+"/testdata.txt")
out_file = createfile out_name

north = [0,1,0]
--only editable Poly in the Scene
for obj in Geometry do
(
--NormalVector
break()
nv = polyOp.getFaceNormal obj 1
--HorizontalVector
break()
hv = normalize (cross north nv)
--VerticalVector
break()
vv = normalize (cross hv nv)
--FrontVector
break()
fv = normalize ([nv, nv, 0])
drop = acos(dot vv fv)
break()
break()
break()
)
close out_file```

And second I created a testing setup here:

```for xr = 0 to 360 by 45 do
(
for yr = 0 to 360 by 45 do
(

p = plane pos: [xr,yr,0] lengthsegments:1 widthsegments:1
gSHsetObjectRotation p xr yr 0
p = convertToPoly(p)

)
)

fn gSHsetObjectRotation obj rx ry rz =
(
-- Reset the object's transformation matrix so that
-- it only includes position and scale information.
-- Doing this clears out any previous object rotation.
local translateMat = transMatrix obj.transform.pos
local scaleMat = scaleMatrix obj.transform.scale
obj.transform = scaleMat * translateMat

-- Perform each axis rotation individually
rotate obj (angleaxis rx [1,0,0])
rotate obj (angleaxis ry [0,1,0])
rotate obj (angleaxis rz [0,0,1])
)```

So what I need now are drop angles between 0-90 degrees and heading angles between 0 and 360 degrees. But what I get are angles between 0 and 180 degrees that are obviously not correct.

Could anybody help me with that? I'm really stuck right now.