remapCoordinateSystemの引数には何を指定する?|Android開発

      2016/11/15

方位角を取得する、android.hardware.SensorManagerのAPI
remapCoordinateSystemについて引数がイマイチ分からず、ネットの情報も色々異なっていたので自身が確認した内容を残しておきます。

書式
boolean remapCoordinateSystem(float[] inR, int X, int Y, float[] outR)

解説

XYにはワールド軸の値を設定する。
設定可能な値は以下。

  • SensorManager.AXIS_MINUS_X
  • SensorManager.AXIS_MINUS_Y
  • SensorManager.AXIS_MINUS_Z
  • SensorManager.AXIS_X
  • SensorManager.AXIS_Y
  • SensorManager.AXIS_Z

ワールド軸は自分が立った状態で考えると分かりやすいです。
上が+Z、正面が+Y、右が+X。(足元は-Z、後ろが-Y、左が-X)
この状態で端末を縦長(Portrait)で地面に水平にした状態が基準となります。そして、この状態で自分の正面が北であれば、方位角は0となります。

remapCoordinateSystemの引数XYはPortrait状態で見たディスプレイ右方向がX、ディスプレイ上方向がYとなります。
よって、

  • 端末をPortraitで正面に向けた場合、Xはワールド軸の+Z、Yはワールド軸の+Zとなります。
  • 端末をLandscapeで正面に向けた場合、Xはワールド軸の-X、Yはワールド軸の+Zとなります。

ワールド軸の図

ワールド軸

Portrait時の引数X,Y

Portrait

Landscape時の引数X,Y

Landscape

使い方

public class OrientationSensor implements SensorEventListener
{
    private static final int MATRIX_SIZE = 16;

    /* 回転行列 */
    private float[] mInR;
    private float[] mOutR;
    private float[] mI;
    private float[] mMagneticValues;
    private float[] mAccelerometerValues;

    private int mCurrentDegreeLandscape;
    private int mCurrentDegreePortrait;

    public OrientationSensor() {
        mInR = new float[MATRIX_SIZE];
        mOutR = new float[MATRIX_SIZE];
        mI = new float[MATRIX_SIZE];

        mMagneticValues = new float[0];
        mAccelerometerValues = new float[0];
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        switch (event.sensor.getType()) {
            case Sensor.TYPE_ACCELEROMETER:
                mAccelerometerValues = event.values.clone();
                break;
            case Sensor.TYPE_MAGNETIC_FIELD:
                mMagneticValues = event.values.clone();
                break;
            default:
                return;
        }

        if (mMagneticValues.length <= 0 || mAccelerometerValues.length <= 0) {
            return;
        }

        SensorManager.getRotationMatrix(mInR, mI, mAccelerometerValues, mMagneticValues);

        float[] orientationValues = new float[3];

        SensorManager.remapCoordinateSystem(mInR, SensorManager.AXIS_Z, SensorManager.AXIS_MINUS_X, mOutR);
        SensorManager.getOrientation(mOutR, orientationValues);
        int degreeLandscape = radianToDegree(orientationValues[0]);
        if (degreeLandscape < 0) {
            degreeLandscape += 360;
        }

        SensorManager.remapCoordinateSystem(mInR, SensorManager.AXIS_X, SensorManager.AXIS_Z, mOutR);
        SensorManager.getOrientation(mOutR, orientationValues);
        int degreePortrait = radianToDegree(orientationValues[0]);
        if (degreePortrait < 0) {
            degreePortrait += 360;
        }

        mCurrentDegreeLandscape = degreeLandscape;
        mCurrentDegreePortrait = degreePortrait;
        Log.v("OrientationSensor", String.format("DEGREE: land(%d), port(%d)", mCurrentDegreeLandscape, mCurrentDegreePortrait));
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        // NOP
    }

    private static int radianToDegree(float radian) {
        return (int) Math.floor(Math.toDegrees(radian));
    }
}

mCurrentDegreeLandscapemCurrentDegreePortraitは同じ値になるはずです。

 - Android