无论屏幕方向如何,如何获得正确的方位(磁方向)?
Posted
技术标签:
【中文标题】无论屏幕方向如何,如何获得正确的方位(磁方向)?【英文标题】:How do I get the correct bearing (magnetic orientation) regardless of screen orientation? 【发布时间】:2013-08-12 07:51:22 【问题描述】:无论当前屏幕方向(横向或纵向)如何,我都想获取当前的磁方向。
我找到了this 示例,但它与方向无关,对吧? this 也没有帮助我。我也读过http://android-developers.blogspot.de/2010/09/one-screen-turn-deserves-another.html。
这是我目前不推荐使用的方法,我不想使用(短):
mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
private SensorEventListener sensorEventListener = new SensorEventListener()
public void onSensorChanged(SensorEvent event)
/* Get measured value */
float current_measured_bearing = (float) event.values[0];
/* Compensate device orientation */
switch (((WindowManager) getSystemService(WINDOW_SERVICE))
.getDefaultDisplay().getRotation())
case Surface.ROTATION_90:
current_measured_bearing = current_measured_bearing + 90f;
break;
case Surface.ROTATION_180:
current_measured_bearing = current_measured_bearing - 180f;
break;
case Surface.ROTATION_270:
current_measured_bearing = current_measured_bearing - 90f;
break;
但最后一部分肯定是错的!在这种情况下,如何正确使用较新的方法getRotationMatrix()
? (与方向无关)或者我是否只需要使用基于旋转矩阵的 event.values[]
数组的其他值?还是我需要“重新映射坐标”?那么that 是实现这一目标的正确方法吗?
我正在为具有 360° 屏幕旋转和 API 级别 11+ 的设备进行开发。
我知道这些问题经常被问到,但我无法将他们的答案转移到我的问题中。
【问题讨论】:
我在这里发布了同样的问题:***.com/questions/11772923/… 但答案对我不起作用。也许你有更多的运气。 你还需要吗?因为也许我们“必须使用 event.values[] 数组的其他值?”基于屏幕旋转? 不,我取消了这个项目(一些 AR 的东西),因为事实证明大多数 Android 设备的旋转传感器都不够精确。 【参考方案1】:好的,我终于设法让代码工作了!
首先,我注册了Sensor.TYPE_MAGNETIC_FIELD
和Sensor.TYPE_GRAVITY
:(就像Hoan Nguyen 说的!)
/**
* Initialize the Sensors (Gravity and magnetic field, required as a compass
* sensor)
*/
private void initSensors()
LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
Sensor mSensorGravity = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);
Sensor mSensorMagneticField = sensorManager
.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
/* Initialize the gravity sensor */
if (mSensorGravity != null)
Log.i(TAG, "Gravity sensor available. (TYPE_GRAVITY)");
sensorManager.registerListener(mSensorEventListener,
mSensorGravity, SensorManager.SENSOR_DELAY_GAME);
else
Log.i(TAG, "Gravity sensor unavailable. (TYPE_GRAVITY)");
/* Initialize the magnetic field sensor */
if (mSensorMagneticField != null)
Log.i(TAG, "Magnetic field sensor available. (TYPE_MAGNETIC_FIELD)");
sensorManager.registerListener(mSensorEventListener,
mSensorMagneticField, SensorManager.SENSOR_DELAY_GAME);
else
Log.i(TAG,
"Magnetic field sensor unavailable. (TYPE_MAGNETIC_FIELD)");
我使用 SensorEventListner
进行计算:
private SensorEventListener mSensorEventListener = new SensorEventListener()
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy)
@Override
public void onSensorChanged(SensorEvent event)
if (event.sensor.getType() == Sensor.TYPE_GRAVITY)
mGravity = event.values.clone();
else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
mMagnetic = event.values.clone();
if (mGravity != null && mMagnetic != null)
/* Create rotation Matrix */
float[] rotationMatrix = new float[9];
if (SensorManager.getRotationMatrix(rotationMatrix, null,
mGravity, mMagnetic))
/* Compensate device orientation */
// http://android-developers.blogspot.de/2010/09/one-screen-turn-deserves-another.html
float[] remappedRotationMatrix = new float[9];
switch (getWindowManager().getDefaultDisplay()
.getRotation())
case Surface.ROTATION_0:
SensorManager.remapCoordinateSystem(rotationMatrix,
SensorManager.AXIS_X, SensorManager.AXIS_Y,
remappedRotationMatrix);
break;
case Surface.ROTATION_90:
SensorManager.remapCoordinateSystem(rotationMatrix,
SensorManager.AXIS_Y,
SensorManager.AXIS_MINUS_X,
remappedRotationMatrix);
break;
case Surface.ROTATION_180:
SensorManager.remapCoordinateSystem(rotationMatrix,
SensorManager.AXIS_MINUS_X,
SensorManager.AXIS_MINUS_Y,
remappedRotationMatrix);
break;
case Surface.ROTATION_270:
SensorManager.remapCoordinateSystem(rotationMatrix,
SensorManager.AXIS_MINUS_Y,
SensorManager.AXIS_X, remappedRotationMatrix);
break;
/* Calculate Orientation */
float results[] = new float[3];
SensorManager.getOrientation(remappedRotationMatrix,
results);
/* Get measured value */
float current_measured_bearing = (float) (results[0] * 180 / Math.PI);
if (current_measured_bearing < 0)
current_measured_bearing += 360;
/* Smooth values using a 'Low Pass Filter' */
current_measured_bearing = current_measured_bearing
+ SMOOTHING_FACTOR_COMPASS
* (current_measured_bearing - compass_last_measured_bearing);
/* Update normal output */
visual_compass_value.setText(String.valueOf(Math
.round(current_bearing))
+ getString(R.string.degrees));
/*
* Update variables for next use (Required for Low Pass
* Filter)
*/
compass_last_measured_bearing = current_measured_bearing;
;
【讨论】:
你想在这里实现什么?将您的设备保持在纵向模式,然后将设备旋转 15 度,current_measured_bearing 将相差 15 度。这是你想要的吗? 是的,例如。 嘿,SMOOTHING_FACTOR_COMPASS 的值是多少?? 你能添加所有的导入和常量吗?【参考方案2】:Sensor.TYPE_ORIENTATION
已折旧,仅在设备平坦时才有效。使用Sensor.TYPE_ORIENTATION
时,方位角(方位角)是设备Y-axis
指向的方向。因此,如果设备保持垂直,Y-axis
用作轴承的方向没有意义。只有计算后置摄像头指向的方向才有意义。要找到这个方向,您必须使用Sensor.TYPE_MAGNETIC_FIELD
和Sensor.TYPE_GRAVITY
或Sensor.TYPE_ACCELEROMETER
。如果使用Sensor.TYPE_ACCELEROMETER
,则必须过滤加速度计值。
使用这些传感器,您可以先调用getRotationMatrix
,然后再调用remapCoordinateSystem(inR, AXIS_X, AXIS_Z, outR)
,然后再调用getOrientation
。要获得稳定的方向,您应该保留方向的历史记录,然后计算平均值。对于使用 TYPE_GRAVITY 的实现,请检查 Android getOrientation Azimuth gets polluted when phone is tilted
【讨论】:
感谢您提供此解决方案。所以现在我要根据这个来写代码。【参考方案3】:我认为这段代码可以帮助你:
//get orientation
private int getScreenOrientation()
int rotation = getWindowManager().getDefaultDisplay().getRotation();
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int width = dm.widthPixels;
int height = dm.heightPixels;
int orientation;
// if the device's natural orientation is portrait:
if ((rotation == Surface.ROTATION_0
|| rotation == Surface.ROTATION_180) && height > width ||
(rotation == Surface.ROTATION_90
|| rotation == Surface.ROTATION_270) && width > height)
switch(rotation)
case Surface.ROTATION_0:
orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
break;
case Surface.ROTATION_90:
orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
break;
case Surface.ROTATION_180:
orientation =
ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
break;
case Surface.ROTATION_270:
orientation =
ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
break;
default:
Log.e(TAG, "Unknown screen orientation. Defaulting to " +
"portrait.");
orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
break;
// if the device's natural orientation is landscape or if the device
// is square:
else
switch(rotation)
case Surface.ROTATION_0:
orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
break;
case Surface.ROTATION_90:
orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
break;
case Surface.ROTATION_180:
orientation =
ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
break;
case Surface.ROTATION_270:
orientation =
ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
break;
default:
Log.e(TAG, "Unknown screen orientation. Defaulting to " +
"landscape.");
orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
break;
return orientation;
【讨论】:
感谢您的代码,并为这么晚的答案感到抱歉,但这只会将屏幕方向返回为 int(在ActivityInfo.SCREEN_ORIENTATION_XX
样式中)。这是一段非常有用的代码,但是你也知道如何使用旋转矩阵吗?
你能帮我解决这个question吗?以上是关于无论屏幕方向如何,如何获得正确的方位(磁方向)?的主要内容,如果未能解决你的问题,请参考以下文章