4

現在の画面の向き(横または縦)に関係なく、現在の磁気の向きを取得したい。

この例を見つけましたが、方向に依存しませんよね? そして、これも私を助けませんでした。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 レベル 11+ を備えたデバイス向けに開発しています。

これらの質問が非常に頻繁に寄せられることは知っていますが、それらの回答を私の質問に移すことはできませんでした.

4

3 に答える 3

8

OK、ようやくコードを機能させることができました!

まず、a Sensor.TYPE_MAGNETIC_FIELDandを登録し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;

            }
        }
    }
};
于 2013-08-18T12:57:17.803 に答える
4

Sensor.TYPE_ORIENTATION減価償却され、デバイスが平らな場合にのみ有効です。を使用する場合Sensor.TYPE_ORIENTATION、方位 (方位角) はデバイスがY-axis指す方向です。したがって、デバイスが垂直に保持されている場合Y-axis、ベアリングとして使用するポイントの方向は意味がありません。バックカメラが向いている方向を計算することだけが理にかなっています。この方向を見つけるにはSensor.TYPE_MAGNETIC_FIELD、 andSensor.TYPE_GRAVITYまたはを使用する必要がありますSensor.TYPE_ACCELEROMETER。を使用Sensor.TYPE_ACCELEROMETERする場合は、加速度計の値をフィルタリングする必要があります。
これらのセンサーを使用して、 を呼び出しgetRotationMatrix、次にremapCoordinateSystem(inR, AXIS_X, AXIS_Z, outR)を呼び出しgetOrientationます。安定した方向を取得するには、方向の履歴を保持してから平均を計算する必要があります。TYPE_GRAVITY チェックを使用した実装の場合Android getOrientation Azimuth は、電話を傾けると汚染されます

于 2013-08-11T05:14:51.907 に答える
0

このコードが役立つと思います:

    //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;
}
于 2013-08-11T08:31:43.750 に答える