Android SensorManager奇怪如何重映射CoordinateSystem

18 android screen-orientation device-orientation sensormanager

API演示 - >图形 - > 指南针

它只能正常工作,直到您不更改设备的自然方向.在大多数手机中,肖像和大多数10英寸平板电脑是风景.如果你改变而不是需要旋转90度.我想看看该系统的3D修复.

100%肯定需要使用remapCoordinateSystem()方法.

我想看看如何(代码)如果我能看到如何计算那些轴映射(理论数学)的解释它会很好.

我试着理解,但我忘记了所有的线性代数.

这里说明为什么我们必须使用,但不告诉如何!

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);
Run Code Online (Sandbox Code Playgroud)

似乎那些坐标是这个位置: - 设备在表格中说(x,y轴在桌子上)

设备方向

只有,如果

getWindowManager().getDefaultDisplay().getRotation() == Surface.ROTATION_0
Run Code Online (Sandbox Code Playgroud)

问题是如何完成此代码: - 那些案例分支

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);
Run Code Online (Sandbox Code Playgroud)

编辑:我写了一个小测试应用程序,在屏幕上显示屏幕旋转:0,90,270度(现在不能180)

看来,如果Rotation 0不变(axisX = SensorManager.AXIS_X;axisY = SensorManager.AXIS_Y;),那么90度应该是:

axisX = SensorManager.AXIS_MINUS_Y;
axisY = SensorManager.AXIS_X;
Run Code Online (Sandbox Code Playgroud)

比谷歌文档说错误的值!问题在哪里?!

getRotationMatrix返回:

在此输入图像描述

X被定义为矢量积YZ(它在器件的当前位置与地面相切并且大致指向东).

Y在器件的当前位置与地面相切,并指向磁北极.

Z指向天空并垂直于地面.

看到上面的手机!我想从左到右,后置摄像头到地面.

getOrientation返回:

在此输入图像描述

X被定义为矢量积YZ(它在设备的当前位置与地面相切并且大致指向西).

Y在器件的当前位置与地面相切,并指向磁北极.

Z指向地球的中心并垂直于地面.

values[0]:方位角,绕Z轴旋转.

values[1]:俯仰,围绕X轴旋转.

values[2]:滚动,绕Y轴旋转.

怎么应该是手机?

最后我想拥有像飞机这样的角度值.我的电话(我)前往北方:(偏航是方位角)

在此输入图像描述

              if ScreenRotation = 0 degree
Pitch axis = -orientationAxisX  =  rotationAxisX
Roll axis  =  orientationAxisY  =  rotationAxisY 
Yaw axis   =  orientationAxisZ  = -rotationAxisZ
Run Code Online (Sandbox Code Playgroud)

kei*_*hzo 26

要完成切换分支,我只是尝试遵循remapCoordinateSystem方法javadoc:

X 定义了设备X轴映射到的世界轴和方向.
Y 定义设备的Y轴映射到的世界轴和方向.

因此,让您的设备从其自然方向(90度,180度或270度)旋转它并问自己:原始设备方向的X正轴与当前设备方向的轴对应?和Y轴相同.

因此,如果您的设备旋转90度,您将看到原始X正轴对应于当前正Y轴,而原始正Y轴对应于当前方向负X轴.

所以它应该是:

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;
}
Run Code Online (Sandbox Code Playgroud)

这对我有用,希望有所帮助.


小智 2

如果手机 UI 锁定到旋转 0,我将得到以下值,而无需 remapCoordinateSystem()

Pitch (phone) = -Pitch   (API)
Roll  (phone) =  Roll     (API)
Yaw   (phone) =  Azimuth  (API)
Run Code Online (Sandbox Code Playgroud)
  • 至少接近 0,0,0 值。

如果手机 UI 强制旋转 90

旧方向的偏航值为 -90 度 ( - PI/2 )!=> 现实中我会去东方而不是北方。

如果我将手机置于 0,0,0 位置:

Pitch (phone) = -Roll    (API)
Roll  (phone) = -Pitch   (API)
Yaw   (phone) =  Azimuth (API)
Run Code Online (Sandbox Code Playgroud)

如果手机 UI 强制旋转 180

旧方向的偏航值有 +/-180 度 (+/- PI)!=> 我会去现实中的南方而不是北方。

如果我将手机置于 0,0,0 位置:

Pitch (phone) =  Pitch   (API)
Roll  (phone) = -Roll    (API)
Yaw   (phone) =  Azimuth (API)
Run Code Online (Sandbox Code Playgroud)

如果手机 UI 强制旋转 270

旧方向的偏航值有 +90 度 (+ PI/2)!=> 我会去现实中的西方而不是北方。

如果我将手机置于 0,0,0 位置:

Pitch (phone) =  Roll    (API)
Roll  (phone) =  Pitch   (API)
Yaw   (phone) =  Azimuth (API)
Run Code Online (Sandbox Code Playgroud)

我写了一个小修复,并进行了测试:android:screenOrientation="fullSensor"

public static final void fixRotation0(float[] orientation) { //azimuth, pitch, roll
    orientation[1] = -orientation[1]; // pitch = -pitch
}

public static final void fixRotation90(float[] orientation) { //azimuth, pitch, roll
    orientation[0] += Math.PI / 2f; // offset
    float tmpOldPitch = orientation[1];
    orientation[1] = -orientation[2]; //pitch = -roll
    orientation[2] = -tmpOldPitch; // roll  = -pitch    
}

public static final void fixRotation180(float[] orientation) { //azimuth, pitch, roll
    orientation[0] = (float)(orientation[0] > 0f ? (orientation[0] - Math.PI) : (orientation[0] + Math.PI)); // offset
    orientation[2] = -orientation[2]; // roll = -roll
}

public static final void fixRotation270(float[] orientation) { //azimuth, pitch, roll
    orientation[0] -= Math.PI / 2; // offset
    float tmpOldPitch = orientation[1];
    orientation[1] = orientation[2]; //pitch = roll
    orientation[2] = tmpOldPitch; // roll  = pitch  
}
Run Code Online (Sandbox Code Playgroud)

大多数情况下是有效的。当您绕 1 轴快速旋转 180 度时,系统将被拧紧!

完整代码可在 Github 上获取