How do I get the correct bearing (magnetic orientation) regardless of screen orientation?

后端 未结 3 695
栀梦
栀梦 2020-12-09 07:01

I want to get the current magnetic orientation regardless of the current screen orientation (landscape or portrait).

I found this example, but it\'s not orientation

相关标签:
3条回答
  • 2020-12-09 07:31

    OK I finally managed to get the code working!

    First, I register a Sensor.TYPE_MAGNETIC_FIELD and Sensor.TYPE_GRAVITY: (like Hoan Nguyen said!)

    /**
     * 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)");
        }
    }
    

    And I use that SensorEventListner for the computation:

    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;
    
                }
            }
        }
    };
    
    0 讨论(0)
  • 2020-12-09 07:35

    I think this code may help you:

        //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;
    }
    
    0 讨论(0)
  • 2020-12-09 07:45

    Sensor.TYPE_ORIENTATION is depreciated and only good if the device is flat. When using Sensor.TYPE_ORIENTATION, the bearing (azimuth) is the direction where the device Y-axis points. So if the device is held vertical, the direction where the Y-axis points using as the bearing does not make sense. It only make sense to calculate the direction where the back camera points. To find this direction you have to use Sensor.TYPE_MAGNETIC_FIELD and Sensor.TYPE_GRAVITY or Sensor.TYPE_ACCELEROMETER. If using Sensor.TYPE_ACCELEROMETER, you have to filter the accelerometer values.
    Using these sensors, you call getRotationMatrix and then remapCoordinateSystem(inR, AXIS_X, AXIS_Z, outR) before calling getOrientation. To get a stable direction you should keep a history of the direction and then calculate the average. For an implementation using TYPE_GRAVITY check Android getOrientation Azimuth gets polluted when phone is tilted

    0 讨论(0)
提交回复
热议问题