How to rotate a set of points on z = 0 plane in 3-D, preserving pairwise distances?

Posted by cagirici on Game Development See other posts from Game Development or by cagirici
Published on 2014-05-25T14:12:15Z Indexed on 2014/05/29 22:05 UTC
Read the original article Hit count: 404

Filed under:
|
|

I have a set of points double n[] on the plane z = 0.
And I have another set of points double[] m on the plane ax + by + cz + d = 0.
Length of n is equal to length of m.
Also, euclidean distance between n[i] and n[j] is equal to euclidean distance between m[i] and m[j].

I want to rotate n[] in 3-D, such that for all i, n[i] = m[i] would be true.

In other words, I want to turn a plane into another plane, preserving the pairwise distances.

Here's my code in java. But it does not help so much:

double[] rotate(double[] point, double[] currentEquation, double[] targetEquation)
{

    double[] currentNormal = new double[]{currentEquation[0], currentEquation[1], currentEquation[2]};
    double[] targetNormal = new double[]{targetEquation[0], targetEquation[1], targetEquation[2]};
    targetNormal = normalize(targetNormal);
    double angle = angleBetween(currentNormal, targetNormal);
    double[] axis = cross(targetNormal, currentNormal);
    double[][] R = getRotationMatrix(axis, angle);
    return rotated; 
}

double[][] getRotationMatrix(double[] axis, double angle)
{
    axis = normalize(axis);

    double cA = (float)Math.cos(angle);
    double sA = (float)Math.sin(angle);
    Matrix I = Matrix.identity(3, 3);
    Matrix a = new Matrix(axis, 3);


    Matrix aT = a.transpose();

    Matrix a2 = a.times(aT);

    double[][] B = 
        {
            {0, axis[2], -1*axis[1]},
            {-1*axis[2], 0, axis[0]},
            {axis[1], -1*axis[0], 0}
        };
    Matrix A = new Matrix(B);

    Matrix R = I.minus(a2);


    R = R.times(cA);
    R = R.plus(a2);
    R = R.plus(A.times(sA));
    return R.getArray();
}

This is what I get. The point set on the right side is actually part of a point set on the left side. But they are on another plane.

Here's a 2-D representation of what I try to do:

enter image description here
There are two lines. The line on the bottom is the line I have. The line on the top is the target line. The distances are preserved (a, b and c). enter image description here

Edit:
I have tried both methods written in answers. They both fail (I guess).

Method of Martijn Courteaux

   public static double[][] getRotationMatrix(double[] v0, double[] v1, double[] v2, double[] u0, double[] u1, double[] u2)
        {

            RealMatrix M1 = new Array2DRowRealMatrix(new double[][]{
                    {1,0,0,-1*v0[0]},
                    {0,1,0,-1*v0[1]},
                    {0,0,1,0},
                    {0,0,0,1}
            });

            RealMatrix M2 = new Array2DRowRealMatrix(new double[][]{
                    {1,0,0,-1*u0[0]},
                    {0,1,0,-1*u0[1]},
                    {0,0,1,-1*u0[2]},
                    {0,0,0,1}
            });

            Vector3D imX = new Vector3D((v0[1] - v1[1])*(u2[0] - u0[0]) - (v0[1] - v2[1])*(u1[0] - u0[0]), 
                    (v0[1] - v1[1])*(u2[1] - u0[1]) - (v0[1] - v2[1])*(u1[1] - u0[1]),
                    (v0[1] - v1[1])*(u2[2] - u0[2]) - (v0[1] - v2[1])*(u1[2] - u0[2])
            ).scalarMultiply(1/((v0[0]*v1[1])-(v0[0]*v2[1])-(v1[0]*v0[1])+(v1[0]*v2[1])+(v2[0]*v0[1])-(v2[0]*v1[1])));

            Vector3D imZ = new Vector3D(findEquation(u0, u1, u2));
            Vector3D imY = Vector3D.crossProduct(imZ, imX);

            double[] imXn = imX.normalize().toArray();
            double[] imYn = imY.normalize().toArray();
            double[] imZn = imZ.normalize().toArray();
            RealMatrix M = new Array2DRowRealMatrix(new double[][]{
                    {imXn[0], imXn[1], imXn[2], 0},
                    {imYn[0], imYn[1], imYn[2], 0},
                    {imZn[0], imZn[1], imZn[2], 0},
                    {0, 0, 0, 1}
            });
            RealMatrix rotationMatrix = MatrixUtils.inverse(M2).multiply(M).multiply(M1);
            return rotationMatrix.getData(); 
        }

enter image description here

Method of Sam Hocevar

static double[][] makeMatrix(double[] p1, double[] p2, double[] p3)
    {
        double[] v1 = normalize(difference(p2,p1));
        double[] v2 = normalize(cross(difference(p3,p1), difference(p2,p1)));
        double[] v3 = cross(v1, v2);
        double[][] M = { { v1[0], v2[0], v3[0], p1[0] },
                         { v1[1], v2[1], v3[1], p1[1] },
                         { v1[2], v2[2], v3[2], p1[2] },
                         {   0.0,   0.0,   0.0,   1.0 } };
        return M;
    }

    static double[][] createTransform(double[] A, double[] B, double[] C,
                         double[] P, double[] Q, double[] R)
    {
        RealMatrix c = new Array2DRowRealMatrix(makeMatrix(A,B,C));
        RealMatrix t = new Array2DRowRealMatrix(makeMatrix(P,Q,R));
        return MatrixUtils.inverse(c).multiply(t).getData();
    }

enter image description here

The blue points are the calculated points. The black lines indicate the offset from the real position.

© Game Development or respective owner

Related posts about java

Related posts about rotation