How can I remove rotations from points defining a plane?

I have coordinates for 4 vertices/points that define a plane and the normal/perpendicular. The plane has an arbitrary rotation applied to it.

How can I 'un-rotate'/translate the points so that the plane has rotation 0 on x,y,z ?

I've tried to get the plane rotation from the plane's normal:

rotationX = atan2(normal.z,normal.y);
rotationY = atan2(normal.z,normal.x);
rotationZ = atan2(normal.y,normal.x);


Is this correct ?

How do I apply the inverse rotation to the position vectors ?

I've tried to create a matrix with those rotations and multiply it with the vertices, but it doesn't look right.

At the moment, I've wrote a simple test using Processing and can be seen here:

float s = 50.0f;//scale/unit
PVector[] face = {new PVector(1.08335042,0.351914703846,0.839020013809),
new PVector(-0.886264681816,0.69921118021,0.839020371437),
new PVector(-1.05991327763,-0.285596489906,-0.893030643463),
new PVector(0.909702301025,-0.63289296627,-0.893030762672)};
PVector n = new PVector(0.150384, -0.500000, 0.852869);
PVector[] clone;

void setup(){
size(400,400,P3D);
smooth();
clone = unRotate(face,n,true);
}

void draw(){
background(255);
translate(width*.5,height*.5);
if(mousePressed){
rotateX(map(mouseY,0,height,0,TWO_PI));
rotateY(map(mouseX,0,width,0,TWO_PI));
}
stroke(128,0,0);
for(int i = 0 ; i < 4; i++) vertex(face[i].x*s,face[i].y*s,face[i].z*s);
endShape();
stroke(0,128,0);
for(int i = 0 ; i < 4; i++) vertex(clone[i].x*s,clone[i].y*s,clone[i].z*s);
endShape();
}
//get rotation from normal
loc.normalize();
float rz = asRadians ? atan2(loc.y,loc.x) : degrees(atan2(loc.y,loc.x));
float ry = asRadians ? atan2(loc.z,loc.x) : degrees(atan2(loc.z,loc.x));
float rx = asRadians ? atan2(loc.z,loc.y) : degrees(atan2(loc.z,loc.y));
return new PVector(rx,ry,rz);
}
//translate vertices
PVector[] unRotate(PVector[] verts,PVector no,Boolean doClone){
int vl = verts.length;
PVector[] clone;
if(doClone) {
clone = new PVector[vl];
for(int i = 0; i<vl;i++) clone[i] = PVector.add(verts[i],new PVector());
}else clone = verts;
PVector rot = getRot(no,false);

PMatrix3D rMat = new PMatrix3D();
rMat.rotateX(-rot.x);rMat.rotateY(-rot.y);rMat.rotateZ(-rot.z);
for(int i = 0; i<vl;i++) rMat.mult(clone[i],clone[i]);
return clone;
}


Any syntax/pseudo code or explanation is useful.

What trying to achieve is this: If I have a rotated plane:

How can move the vertices to have something that would have no rotation:

Thanks!

UPDATE:

I'm not sure I understand. I thought I was using matrices for rotations. PMatrix3D's rotateX,rotateY,rotateZ calls should done the rotations for me. Doing it manually would be declaring 3d matrices and multiplying them. Here's a little snippet to illustrate this:

 PMatrix3D rx = new PMatrix3D(1,          0,          0,  0,
0, cos(rot.x),-sin(rot.x),  0,
0, sin(rot.x),cos(rot.x) ,  0,
0,          0,          0,  1);
PMatrix3D ry = new PMatrix3D(cos(rot.y), 0,sin(rot.y),  0,
0, 1,0         ,  0,
-sin(rot.y), 0,cos(rot.y),  0,
0, 0,0         ,  1);
PMatrix3D rz = new PMatrix3D(cos(rot.z),-sin(rot.z), 0, 0,
sin(rot.z), cos(rot.z), 0, 0,
0         ,          0, 1, 0,
0         ,          0, 0, 1);
PMatrix3D r = new PMatrix3D();
r.apply(rx);r.apply(ry);r.apply(rz);

//test
PMatrix rmat = new PMatrix3D();rmat.rotateX(rot.x);rmat.rotateY(rot.y);rmat.rotateZ(rot.z);
float[] frmat = new float[16];rmat.get(frmat);
float[] fr    = new float[16];r.get(fr);
println(frmat);println(fr);

/*
Outputs:
[0] 0.059300933
[1] 0.09312407
[2] -0.99388695
[3] 0.0
[4] 0.90466285
[5] 0.41586864
[6] 0.09294289
[7] 0.0
[8] 0.42198166
[9] -0.9046442
[10] -0.059584484
[11] 0.0
[12] 0.0
[13] 0.0
[14] 0.0
[15] 1.0
[0] 0.059300933
[1] 0.09312407
[2] -0.99388695
[3] 0.0
[4] 0.90466285
[5] 0.41586864
[6] 0.09294289
[7] 0.0
[8] 0.42198166
[9] -0.9046442
[10] -0.059584484
[11] 0.0
[12] 0.0
[13] 0.0
[14] 0.0
[15] 1.0

*/

• Is it OK if the points end up on the xy plane but in an arbitrary orientation, or do you want them to also line up with the x and y axes? The answer will be different in the two cases. – Rahul Sep 22 '10 at 19:16
• @Rahul The end goal is to get the rotation of the plane, then get the 3d coordinates as if they were on a 2d plane(one dimension can be dropped, as it should be 0). If the points end up on xy,xz,yz, it shouldn't matter. – George Profenza Sep 22 '10 at 22:16
• I think you didn't get my meaning. Let's say your quadrilateral is the red one in this crudely-drawn diagram: imgur.com/wwDx2.png . The smallest rotation that brings them into the xy plane gets you the blue quadrilateral. Is that what you want, or do you want the rotation that gets you the axis-aligned green quadrilateral instead? – Rahul Sep 23 '10 at 5:14
• @Rahul Thank you for the explanation. The axis-aligned green quadrilateral is what I want. – George Profenza Sep 23 '10 at 8:04

From your comments, what I understand of your problem is that you have the coordinates of an arbitrarily oriented rectangle centred on the origin, and you want to find the rotation that will bring it to an axis-aligned rectangle on the $xy$ plane.

Let $u$ and $v$ be the unit vectors that should be mapped to the axis-oriented unit vectors $e_x$ and $e_y$ respectively. You can get these by subtracting adjacent points of the rectangle and normalizing. Then you want a rotation $R$ which satisfies $Ru = e_x$, $Rv = e_y$, and $Rn = e_z$.

You can express this as $R[u\;v\;n] = [e_x\;e_y\;e_z] = I$. Then $R$ equals $[u\;v\;n]^{-1}$, which is simply $[u\;v\;n]^T$ since $u$, $v$, and $n$ are an orthonormal set. To be more explicit, the rotation matrix you want is: $$R = \begin{bmatrix}u_x & u_y & u_z \\ v_x & v_y & v_z \\ n_x & n_y & n_z\end{bmatrix}.$$ If you really like Euler angles (rotateX, rotateY, rotateZ), there are ways to convert a rotation matrix like above to Euler angles, but they're ugly. You're best off using the rotation matrix explicitly.

By the way, if your rectangle is not centred on the origin, and you want to perform the rotation keeping its centre (say $c$) fixed, you'll have to get the rotated coordinates of a point $p$ not simply as $Rp$ but as $R(p-c) + c$.

• Unfortunately I can barely 'read' math, so here's what I do and do not understand: 'coordinates of an arbitrarily oriented rectangle centred on the origin' - it is an arbitrarily oriented plane centred on the origin. it can be any shape(parallelogram for instance, not just rectangle). Yes, I want to find the rotation that will bring it to an axis aligned rectangle on the xy plane. – George Profenza Oct 5 '10 at 21:13
• ex and ey describe the xy plane, and u v describe the unit vectors of my plane, right ? shouldn't there be a w(a third dimension) ? 'subtracting adjacent points of the rectangle and normalizing' - I didn't understand. do I subtract a value from u so it matches with ex, and similarly for v ? This would probably take care of 2 axes, not 3. Then I would create R which uses ex,ey and ez as the rotations. Rn ? is this linked to the normal ? – George Profenza Oct 5 '10 at 21:19
• Once I know R, I invert/transpose it and multiple it to the original vectors and should get the vectors in the xy plane now, correct ? Related to the last note, the plane will always be centred on it's origin/centre – George Profenza Oct 5 '10 at 21:21
• @George Profenza: I think by "plane" you mean "quadrilateral"; the word "plane" is usually used to refer to an infinite plane, while a planar shape connecting four points is called a quadrilateral. But I'm still not sure I understand, as it's not possible to simply rotate a parallelogram and turn it into a rectangle -- you would also need to shear it in some way. And if you have an arbitrary quadrilateral then the problem becomes much more complicated. – Rahul Oct 5 '10 at 21:31
• @George Profenza: Sorry, I didn't see your other two comments when I replied. The third dimension is $n$, the normal to the plane, so you have a set of three vectors ($u$, $v$, and $n$) in space which are all perpendicular to each other. The rotation matrix is $R$, while the notation $Rx$ for some vector $x$ denotes multiplying $R$ with the vector $x$. You don't have to invert or transpose it; what I have written above is the actual value of $R$. – Rahul Oct 5 '10 at 21:38

Try to represent rotations using matrices instead of angles - then finding the inverse is easy.

• PMatrix3D rMat = new PMatrix3D(); rMat.rotateX(-rot.x);rMat.rotateY(-rot.y);rMat.rotateZ(-rot.z); should create a matrix and set rotation X,Y and Z for the matrix. If I multiply it to the position vertices, the result looks wrong(distorted). I also looked at Spherical Coordinates(en.wikipedia.org/wiki/…), but I didn't understand what theta and phi would be in my case, and what would I do with the 3rd rotation. – George Profenza Sep 22 '10 at 20:07
• I am suggesting that you use rotation matrices instead of angles. – anon Sep 22 '10 at 20:08
• @George: To make muad's comment explicit: Euler angles is what you need here. The actual rotation matrix is decomposable as a product of three orthogonals; inverting is as easy as transposing all three and multiplying in the reverse order. – J. M. is a poor mathematician Sep 22 '10 at 22:22
• @J. M. I thought I was using Euler angles. I've added an update. – George Profenza Sep 22 '10 at 23:13
• No I am not suggesting to use Euler angles. – anon Oct 3 '10 at 20:11

At the moment, I went with a somewhat simple solution that allows me to draw a plane/face with 4 vertices with arbitrary rotations, in 2D:

Here's how it works:

PVector[] unRotateVerts(PVector[] verts,PVector n){
//get the angle between the face4 normal and Y
angle = PVector.angleBetween(n,y);//acos(n.dot(y));
//get the axis of rotation, by getting the perpendicular
axis = n.cross(y);
axis.normalize();
//clone vertices
int vl = verts.length;
PVector[] clone = new PVector[vl];
for(int i = 0; i<vl;i++) clone[i] = verts[i].get();
//make a rotation matrix and rotate it
PMatrix3D rMat = new PMatrix3D();
rMat.rotate(angle,axis.x,axis.y,axis.z);
//multiply each vertex with the rotation matrix
PVector[] dst = new PVector[vl];
for(int i = 0; i<vl;i++) {
dst[i] = new PVector();
rMat.mult(clone[i],dst[i]);
}
return dst;
}


This works perfectly for aligning with XZ, but rotations on the Z axis are still there. Any hints on how to remove that would be handy.