10

I'm doing something where I have a plane in a coord sys A with a set of points already on it. I also have a normal vector in space N. How can I rotate the points on coord sys A so that the underlying plane will have the same normal direction as N?

Wondering if any one has a good idea on how to do this. Thanks

bendervader
  • 2,619
  • 2
  • 19
  • 22

3 Answers3

24

If you have, or can easily compute, the normal vector to the plane that your points are currently in, I think the easiest way to do this will be to rotate around the axis common to the two planes. Here's how I'd go about it:

  1. Let M be the vector normal to your current plane, and N be the vector normal to the plane you want to rotate into. If M == N you can stop now and leave the original points unchanged.
  2. Calculate the rotation angle as

    costheta = dot(M,N)/(norm(M)*norm(N))
    
  3. Calculate the rotation axis as

    axis = unitcross(M, N)
    

    where unitcross is a function that performs the cross product and normalizes it to a unit vector, i.e. unitcross(a, b) = cross(a, b) / norm(cross(a, b)). As user1318499 pointed out in a comment, this step can cause an error if M == N, unless your implementation of unitcross returns (0,0,0) when a == b.

  4. Compute the rotation matrix from the axis and angle as

    c = costheta
    s = sqrt(1-c*c)
    C = 1-c
    rmat = matrix([ x*x*C+c    x*y*C-z*s  x*z*C+y*s ],
                  [ y*x*C+z*s  y*y*C+c    y*z*C-x*s ]
                  [ z*x*C-y*s  z*y*C+x*s  z*z*C+c   ])
    

    where x, y, and z are the components of axis. This formula is described on Wikipedia.

  5. For each point, compute its corresponding point on the new plane as

    newpoint = dot(rmat, point)
    

    where the function dot performs matrix multiplication.

This is not unique, of course; as mentioned in peterk's answer, there are an infinite number of possible rotations you could make that would transform the plane normal to M into the plane normal to N. This corresponds to the fact that, after you take the steps described above, you can then rotate the plane around N, and your points will be in different places while staying in the same plane. (In other words, each rotation you can make that satisfies your conditions corresponds to doing the procedure described above followed by another rotation around N.) But if you don't care where in the plane your points wind up, I think this rotation around the common axis is the simplest way to just get the points into the plane you want them in.


If you don't have M, but you do have the coordinates of the points in your starting plane relative to an origin in that plane, you can compute the starting normal vector from two points' positions x1 and x2 as

M = cross(x1, x2)

(you can also use unitcross here but it doesn't make any difference). If you have the points' coordinates relative to an origin that is not in the plane, you can still do it, but you'll need three points' positions:

M = cross(x3-x1, x3-x2)
David Z
  • 128,184
  • 27
  • 255
  • 279
  • 1
    +1 Good answer. The only gripe (to the extent it rises to the level of a gripe, which is questionable) I have is you didn't mention Quaternion Rotation as a possible alternative to steps 4 and 5. They are somewhat more efficient. – andand Feb 24 '12 at 03:26
  • @andand: usually I'm doing this sort of thing analytically, so I'm not completely familiar with quaternions. But if I have time I'll edit that in. – David Z Feb 24 '12 at 06:22
  • where do you use axis? – padawan May 12 '14 at 18:28
  • 1
    @cagirici the components of `axis` are the `x`, `y`, and `z` that appear in the formula for the rotation matrix. – David Z May 12 '14 at 18:30
  • 1
    @DavidZ one more question: What do I do if I want to shift the plane with respect to the `d` component? – padawan May 12 '14 at 18:31
  • This will have a divide-by-zero if the two planes are parallel. You should test for `norm(cross(a,b))` ~= 0 and then just return the input vector (no rotation needed). Depending on the language and performance, you could also allow it to happen then test for +/-infinity in each component of `axis`. – user1318499 Jun 23 '14 at 12:36
  • @user1318499 presumably that would be part of the implementation of `unitcross`, but let me edit in a note about that. – David Z Jul 08 '15 at 08:22
  • @cagirici I think that goes beyond the scope of this answer. – David Z Jul 08 '15 at 08:22
2

A single vector (your normal - N) will not be enough. You will need another two vectors for the other two dimensions. (Imagine that your 3D space could still rotate/spin around the normal vector, and you need another 2 vectors to nail it down). Once you have the normal and another one on the plane, the 3rd one should be easy to find (left- or right-handed depending on your system).

Make sure all three are normalized (length of 1) and put them in a matrix; use that matrix to transform any point in your 3D space (use matrix multiplication). This should give you the new coordinates.

PeterK
  • 51
  • 6
0

I'm thinking make a unit vector [0,0,1] and use the dot-product along two planes to find the angle of difference, and shift all your points by those angles. This is assuming you want the z-axis to align with the normal vector, else just use [1,0,0] or [0,1,0] for x and y respectively.