2013-08-10 2 views
3

Я хочу получить текущую магнитную ориентацию независимо от текущей ориентации экрана (пейзаж или портрет).Как получить правильный подшипник (магнитная ориентация) независимо от ориентации экрана?

Я нашел 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+.

Я знаю, что эти вопросы задаются очень часто, но я просто не могу передать их ответы на мой вопрос.

+0

У меня была та же проблема размещена здесь: http://stackoverflow.com/questions/11772923/how-can-i-get-the-magnetic-field-vector-independent-the-device-rotation, но ответ не сработал для меня. Возможно, вам повезло больше. – Ridcully

+0

Вам все еще нужно? Потому что, может быть, нам придется использовать другие значения массива event.values ​​[]? основанный на вращении экрана? – felixd

+0

Нет, я отменил проект (некоторые вещи AR), поскольку оказалось, что датчики вращения большинства устройств Android недостаточно точны для того, что я имел в виду. – Ridcully

ответ

6

Хорошо, я наконец-то удалось получить код работает!

Во-первых, я зарегистрировать Sensor.TYPE_MAGNETIC_FIELD и Sensor.TYPE_GRAVITY: (! Как сказал Хоан Нгуен)

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

      } 
     } 
    } 
}; 
+0

Что вы пытаетесь достичь здесь? Держите устройство в портретном режиме, а затем поверните устройство на 15 градусов, а current_measured_bearing будет отличаться на 15 градусов. Это то, что вы хотите? –

+0

Да, это так, например. – felixd

+0

эй какая ценность для SMOOTHING_FACTOR_COMPASS ?? –

3

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

+0

Благодарим вас за это решение. Итак, теперь я собираюсь написать код на основе этого. – felixd

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; 
} 
+0

Thamk вы за свой код и жалеете о таком позднем ответе, но это только возвращает ориентацию экрана как int (в 'ActivityInfo.SCREEN_ORIENTATION_XX'-стиле).Это очень полезная часть кода, но знаете ли вы также, как использовать матрицу вращения? – felixd

+0

Можете ли вы мне помочь на этом [вопрос] (http://stackoverflow.com/questions/34997669/android-acceleration-down-smash), пожалуйста? –

Смежные вопросы