无论屏幕方向如何,如何获得正确的方位(磁方向)?

无论当前的屏幕方向(横向或纵向),我都希望获得当前的磁性方向。

我找到了这个例子,但它不是独立的方向,对吧? 这对我也没有帮助。 我也读过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[]数组的其他值? 或者我需要’重新映射坐标’? 这是实现这一目标的正确方法吗?

我正在为具有360°屏幕旋转和API Level 11+的设备开发。

我知道这些问题经常被问到,但我不能将他们的答案转移到我的问题上。

好的,我终于设法让代码工作了!

首先,我注册了一个Sensor.TYPE_MAGNETIC_FIELDSensor.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; } } } }; 

Sensor.TYPE_ORIENTATION是折旧的,只有在设备持平时才有效。 使用Sensor.TYPE_ORIENTATION ,轴承(方位角)是设备Y-axis指向Y-axis 。 因此,如果设备保持垂直,则Y-axis指向的方向作为轴承没有意义。 只计算后置摄像头指向的方向才有意义。 要找到此方向,您必须使用Sensor.TYPE_MAGNETIC_FIELDSensor.TYPE_GRAVITYSensor.TYPE_ACCELEROMETER 。 如果使用Sensor.TYPE_ACCELEROMETER ,则必须过滤加速度计值。
使用这些传感器,在调用getOrientation之前调用getOrientation然后重新remapCoordinateSystem(inR, AXIS_X, AXIS_Z, outR) 。 要获得稳定的方向,您应该保留方向的历史记录,然后计算平均值。 对于使用TYPE_GRAVITY的实现,请检查Android getOrientation方法在手机倾斜时受到污染

我认为这段代码可以帮助您:

  //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; }