29

我正在制作一个地图应用程序,包括向您显示您面对的方向的位置箭头,如下所示:

带有蓝色箭头的地图

我直接从 获取方向SensorManager.getOrientation(),使用第一个返回值:方位角。当握住手机使屏幕指向地平线上方并且纵向时,箭头可以正常工作。然而:

  • 当手持手机使屏幕指向地平线以下时,箭头指向的方向与用户所面对的方向相差 180 度。
  • 当手机被握在屏幕的朝向与地平线齐平时,箭头不知道它指向哪个方向。Azimuth 根本不会返回有意义的结果。
  • 当手机向左或向右倾斜(或以横向模式握住)时,箭头向左或向右倾斜。

下面精心构建的科学图像显示了我的意思(其中蓝色是用户面向,红色是箭头方向,屏幕大致面向用户的面部,Google Maps 正是我想要的):

发生了什么与我想要什么的图表

(请注意,使用谷歌地图,如果自动旋转关闭,它不会成功执行列表中的最后两个操作。但我什至还没有到那个阶段。一次一件事。)

看起来好像它只是使用 Y 轴指向方向,如下所示:http: //developer.android.com/reference/android/hardware/SensorEvent.html,当我希望它使用 Z 轴指向方向的反向时,大多数时候,和手机平放时的 Y。但是,考虑到getOrientation()返回的值,我必须编写复杂的案例来解决一些问题,而面向手机的地平线用例是无法解决的。我敢肯定有一个更简单的方法。

这是我的代码(lastAcceleration 和 lastMagneticField 都来自内部传感器):

float[] rotationMatrix = new float[9];
if(SensorManager.getRotationMatrix(rotationMatrix, null, lastAcceleration, lastMagneticField)){
    float[] orientMatrix = new float[3];
    SensorManager.getOrientation(rotationMatrix, orientMatrix);

    orientation = orientMat[0]*180/(float)Math.PI;
}

我究竟做错了什么?有没有更简单的方法来做到这一点?

编辑:为了澄清,我假设用户将设备放在他们面前,并且屏幕指向他们。除此之外,我显然无法判断它们是否只有一个旋转。另外,我使用的是用户移动时的动作,但这是针对他们静止时的。

4

5 回答 5

6

你打电话给 remapCoordinateSystem 了吗?否则,您只能在垂直握住手机时获得正确的面值。对于这种情况,当手机被握住时,屏幕的朝向与地平线齐平,你无法获得用户的朝向。因为要获得朝向,您必须将传感器读数的 z 值投影到世界坐标中的 xy 平面中,并且当设备水平放置时它为零。

更准确地说,如果你想让手机面向,那么手机必须从水平方向倾斜至少 25 度,你必须调用 remapCoordinateSystem。以下代码将为您提供上面最后两张图片所需的内容。
代码

float[] rotationMatrix = new float[9];  

if(SensorManager.getRotationMatrix(rotationMatrix, null, lastAcceleration, lastMagneticField)){
    float[] orientMatrix = new float[3];
    float remapMatrix = new float[9];
    SensorManager.remapCoordinateSystem(rotationMatrix, SensorManager.AXIS_X, SensorManager.AXIS_Z, remapMatrix);
    SensorManager.getOrientation(remapMatrix, orientMatrix);

    orientation = orientMat[0]*180/(float)Math.PI;
}  

假设手机平放,getOrientation 会为您提供正确的值。因此,如果手机垂直握持,则必须重新映射坐标才能获得平坦位置。在几何上,您将手机 -z 轴向下投影到世界 xy 平面,然后计算此投影向量与世界 y 轴之间的角度。

于 2012-05-18T10:08:01.260 回答
0

当用户垂直握住手机时,获得方位的适当方法似乎是使用以下方法:

// after calling getRotationMatrix pass the rotationMatix below:
SensorManager.remapCoordinateSystem(inR, AXIS_X, AXIS_Z, outR);

如果您想同时处理两种方式(垂直和平面),您可能需要检测到这一点,然后仅在垂直时执行此重新映射。

请参阅此处的 API 文档。

于 2014-01-28T23:20:11.017 回答
0

这看起来很棘手。我正在为 Android 开发 PNS,并且面临着一个类似的问题,我仍然需要光:如何获得加速度计轴和运动矢量之间的旋转?

问题是,在我看来,如果用户不移动,则绝对不可能找到用户面向的方向(而不是设备)。那就是人的身体上没有传感器,那么如果设备保持在绝对相同的位置但用户旋转了 90° 怎么办?我看不出有什么办法找到这个。

我可以建议(实际上适合我的问题)是您可以(我不知道您在代码中实际做了什么)使用用户的动作来确定他的标题。让我解释。假设您有第一个位置 A。用户前往 B。然后您可以构建 AB 向量并在用户停在 B 时获取用户的航向。然后您必须将代码限制为他所面临的方向到达目的地。

我知道这不如谷歌地图得到的那么好,但你知道谷歌为此使用了什么吗?我的意思是他们只使用加速和磁场传感器吗?

于 2012-04-20T07:46:07.793 回答
0

您应该进行推销并确定用户是否接近将手机垂直向上举起。

我选择了从桌面向上或向下倾斜 45 度后,应重新映射坐标系。

if (Math.round(Math.toDegrees(-orientation[1])) < 45 && Math.round(Math.toDegrees(-orientation[1])) > -45) {
//do something while the phone is horizontal
}else{
//R below is the original rotation matrix
float remapOut[] = new float[9];
SensorManager.remapCoordinateSystem(R, SensorManager.AXIS_X, SensorManager.AXIS_Z, remapOut);
//get the orientation with remapOut
float remapOrientation[] = new float[3];
SensorManager.getOrientation(remapOut, remapOrientation);

效果很好。让我知道是否有人可以建议对此进行改进。谢谢。

于 2015-10-18T01:21:21.727 回答
0

我建议应用以下重映射。就我而言,它适用于前三个场景: SensorManager.remapCoordinateSystem(rMat, SensorManager.AXIS_Z, SensorManager.AXIS_Y, rMatRemapped);

于 2021-03-10T12:48:36.600 回答