2013-08-10 3 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()을 어떻게 사용합니까? (Orientation independent) 아니면 Rotation Matrix를 기반으로 다른 배열의 event.values[] 배열을 사용해야할까요? 아니면 좌표를 다시 매핑해야합니까? 그렇다면 that이 올바른 방법입니까?

화면 회전이 360 °이고 API 레벨 11 이상인 기기 용으로 개발 중입니다.

나는 이러한 질문들이 매우 자주 제기되지만 나는 그들의 질문에 대답을 전달할 수 없다는 것을 알고있다.

+0

: http://stackoverflow.com/questions/11772923/how-can-i-get-the-magnetic-field-vector-independent-of-the-device-rotation하지만 대답은 나를 위해 작동하지 않았다. 아마도 당신에게는 더 많은 행운이있을 것입니다. – Ridcully

+0

아직도 필요합니까? 아마 우리는 event.values ​​[] 배열의 다른 값을 사용해야 만 할 것입니다. ' 화면 회전에 따라? – felixd

+0

아니요, 대부분의 Android 기기의 회전 센서가 내가 염두에두고있는 것만 큼 정확하지 않은 것으로 밝혀짐에 따라 프로젝트를 취소했습니다 (일부 AR 항목). – Ridcully

답변

6

확인 드디어 코드가 작동 얻을 수 있었다! 먼저

, 나는 Sensor.TYPE_MAGNETIC_FIELDSensor.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이 가리키는 방향입니다. 따라서 장치가 수직으로 유지되면 베어링으로 ​​사용하는 방향은 의미가 없습니다. 뒷쪽 카메라가 가리키는 방향을 계산하는 것이 의미가 있습니다. 이 방향을 찾으려면 Sensor.TYPE_MAGNETIC_FIELDSensor.TYPE_GRAVITY 또는 Sensor.TYPE_ACCELEROMETER을 사용해야합니다. Sensor.TYPE_ACCELEROMETER을 사용하는 경우 가속도계 값을 필터링해야합니다.
getOrientation에 전화하기 전에이 센서를 사용하여 getRotationMatrixremapCoordinateSystem(inR, AXIS_X, AXIS_Z, outR)으로 전화하십시오. 안정된 방향을 얻으려면 방향의 역사를 유지하고 평균을 계산해야합니다. 구현을 위해이 코드 당신을 도울 수있다 생각 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)에서 나를 도울 수 있습니까? –

관련 문제