Search code examples
androidmatrixrotationquaternions

Using Rotation Matrix to rotate points in space


I'm using android's rotation matrix to rotate multiple points in space.

Work so far

I start by reading the matrix from the SensorManager.getRotationMatrix function. Next I transform the rotation matrix into a quaternion using the explanation given in this link. I'm doing this because I read that Euler angles can lead to Gimbal lock issue and that operations with a 3x3 matrix can be exhaustive. source

Problem

Now what I want to do is: Imagine the phone is the origin of the referential and given a set of points (projected lat/lng coordinates into a xyz coordinate system see method bellow) I want to rotate them so I can check which ones are on my line of sight. For that I'm using this SO question which returns a X and Y (left and top respectively) to display the point on screen. It's working fine but only works when facing North (because it doesn't take orientation into account and my projected vector uses North/South as X and East/West as Z). So my thought was to rotate all objects. Also even though the initial altitude (Y) is 0 I want to be able to position the point up/down according to phone's orientation.

I think part of the solution may be on this post. But since this uses Euler angles I don't think that's the best method.

Conclusion

So, if it's really better to rotate each point's position how can I archive that using the rotation quaternion? Otherwise which is the better way?

I'm sorry if I said anything wrong in this post. I'm not good at physics.

Code

//this functions returns a 3d vector (0 for Y since I'm discarding altitude) using 2 coordinates
public static float[] convLocToVec(LatLng source, LatLng destination)
{
    float[] z = new float[1];
    z[0] = 0;
    Location.distanceBetween(source.latitude, source.longitude, destination
            .latitude, source.longitude, z);
    float[] x = new float[1];
    Location.distanceBetween(source.latitude, source.longitude, source
            .latitude, destination.longitude, x);
    if (source.latitude < destination.latitude)
        z[0] *= -1;
    if (source.longitude > destination.longitude)
        x[0] *= -1;

    return new float[]{x[0], (float) 0, z[0]};
}

Thanks for your help and have a nice day.


UPDATE 1

According to Wikipedia:

Compute the matrix product of a 3 × 3 rotation matrix R and the original 3 × 1 column matrix representing v→. This requires 3 × (3 multiplications + 2 additions) = 9 multiplications and 6 additions, the most efficient method for rotating a vector.

Should I really just use the rotation matrix to rotate a vector?


Solution

  • Since no one answered I'm here to answer myself.

    After some research (a lot actually) I came to the conclusion that yes it is possible to rotate a vector using a quaternion but it's better for you that you transform it into a rotation matrix.

    • Rotation matrix - 9 multiplications and 6 additions
    • Quartenion - 15 multiplications and 15 additions

    Source: Performance comparisons

    It's better to use the rotation matrix provided by Android. Also if you are going to use quaternion somehow (Sensor.TYPE_ROTATION_VECTOR + SensorManager.getQuaternionFromVector for example) you can (and should) transform it into a rotation matrix. You can use the method SensorManager.getRotationMatrixFromVector to convert the rotation vector to a matrix. After you get the rotation matrix you just have to multiply it for the projected vector you want. You can use this function for that:

     public float[] multiplyByVector(float[][] A, float[] x) {
            int m = A.length;
            int n = A[0].length;
            if (x.length != n) throw new RuntimeException("Illegal matrix dimensions.");
            float[] y = new float[m];
            for (int i = 0; i < m; i++)
                for (int j = 0; j < n; j++)
                    y[i] += (A[i][j] * x[j]);
            return y;
      }
    

    Although I'm still not able to get this running correctly I will mark this as answer.