Android SensorManager strange how to remapCoordinateSystem

user529543 picture user529543 · Sep 13, 2013 · Viewed 14.8k times · Source

API Demos -> Graphics -> Compass

It works properly only, until you don't change the device natural orientation. In most phones is the portrait and most 10 inch tablets are the landscape. If you change than need to rotate this with 90 degree. I would like to see a 3D fix for that system.

100% sure need to use remapCoordinateSystem() method.

I would like to see how ( code ) if I could see an explanation with how is calculated those axes mapping ( theoretical math ) it would be nice.

I have tryed to understand, but I forgot all linear algebra.

Here it says why must we use, but doesn't telling how!

float R[] = new float[9];
// X  (product of Y and Z) and roughly points East
// Y: points to Magnetic NORTH and tangential to ground
// Z: points to SKY and perpendicular to ground
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(R, I, mGravity, mGeomagnetic);

It seems those coordinates are to this position: - the device say in a table (x, and y axes are on table)

device orientation

Only and only if

getWindowManager().getDefaultDisplay().getRotation() == Surface.ROTATION_0

The question is how to complete this code: - those case branches

switch (mScreenRotation) {
    case Surface.ROTATION_0:
    Log.v("SurfaceRemap", "0 degree");
    axisX = SensorManager.AXIS_X;// is this valid?
    axisY = SensorManager.AXIS_Y;// is this valid?
    break;

    case Surface.ROTATION_90:
    Log.v("SurfaceRemap", "90 degree");
    // examples says remapCoordinateSystem(inR, AXIS_Y, AXIS_MINUS_X, outR);
    axisX = SensorManager.AXIS_Y;
    axisY = SensorManager.AXIS_MINUS_X;
    break;

    case Surface.ROTATION_180:
    Log.v("SurfaceRemap", "180 degree");
    break;

    case Surface.ROTATION_270:
    Log.v("SurfaceRemap", "270 degree");
    break;

    default:
    Log.v("SurfaceRemap", "don't know the mScreenRotation value: "+mScreenRotation+" you should never seen this message!");
    break;
}


boolean remapped = SensorManager.remapCoordinateSystem(R, axisX, axisY, R);

float orientation[] = new float[3];

SensorManager.getOrientation(R, orientation);// All three angles above are in radians and positive in the counter-clockwise direction.
inclination = SensorManager.getInclination(I);

Edit: I wrote a little test application, where on the screen it display the screen rotation: 0, 90, 270 degrees ( can't make 180 now)

It seems, if Rotation 0 is unchanged (axisX = SensorManager.AXIS_X;axisY = SensorManager.AXIS_Y;) than the 90 degree should be:

axisX = SensorManager.AXIS_MINUS_Y;
axisY = SensorManager.AXIS_X;

than the Google documentation says somewhere wrong values! Question is where?!

getRotationMatrix return this:

enter image description here

X is defined as the vector product Y.Z (It is tangential to the ground at the device's current location and roughly points East).

Y is tangential to the ground at the device's current location and points towards the magnetic North Pole.

Z points towards the sky and is perpendicular to the ground.

See the phone above! I want to to to right from left, with back camera to ground.

getOrientation return this:

enter image description here

X is defined as the vector product Y.Z (It is tangential to the ground at the device's current location and roughly points West).

Y is tangential to the ground at the device's current location and points towards the magnetic North Pole.

Z points towards the center of the Earth and is perpendicular to the ground.

values[0]: azimuth, rotation around the Z axis.

values[1]: pitch, rotation around the X axis.

values[2]: roll, rotation around the Y axis.

How should be the phone?

Finally I would like to have values of angles like aircrafts. My phone (me) heading to North: (yaw is azimuth)

enter image description here

              if ScreenRotation = 0 degree
Pitch axis = -orientationAxisX  =  rotationAxisX
Roll axis  =  orientationAxisY  =  rotationAxisY 
Yaw axis   =  orientationAxisZ  = -rotationAxisZ

Answer

keianhzo picture keianhzo · Dec 24, 2013

To complete the switch branches I just try to think following the remapCoordinateSystem method javadoc:

X defines on which world axis and direction the X axis of the device is mapped.
Y defines on which world axis and direction the Y axis of the device is mapped.

So take your device rotate it from its natural orientation (90, 180 or 270 degrees) and ask yourself: The X positive axis in the original device orientation to which axis corresponds in the current device orientation?. And same for the Y axis.

So in case your device is rotated 90 degrees you will see that the original X positive axis corresponds to the current positive Y axis and the original positive Y axis corresponds to the current orientation negative X axis.

So It should be:

switch (mScreenRotation) {
    case Surface.ROTATION_0:
        axisX = SensorManager.AXIS_X;
    axisY = SensorManager.AXIS_Y;
        break;

    case Surface.ROTATION_90:
        axisX = SensorManager.AXIS_Y;
    axisY = SensorManager.AXIS_MINUS_X;
        break;

    case Surface.ROTATION_180:
        axisX = SensorManager.AXIS_MINUS_X;
    axisY = SensorManager.AXIS_MINUS_Y;
        break;

    case Surface.ROTATION_270:
        axisX = SensorManager.AXIS_MINUS_Y;
    axisY = SensorManager.AXIS_X;
        break;

    default:
        break;
}

That worked for me, hope that helps.