2017-02-13 34 views
12

我的要求正确航向像Google maps apps罗盘模式轴承(你可以看到演示时点击current location button twice):计算真正在Android的

  • 在这个compass模式下,地图总是一个角度,使旋转bluedot arrow始终指向顶部屏幕。

但我不知道如何从azimuth, pitch, roll值计算正确的bearing

public void onSensorChanged(SensorEvent sensorEvent) { 
     switch (sensorEvent.sensor.getType()) { 
      case Sensor.TYPE_ACCELEROMETER: 
       System.arraycopy(sensorEvent.values, 0, mAccelerometers, 0, 3); 
       break; 
      case Sensor.TYPE_MAGNETIC_FIELD: 
       System.arraycopy(sensorEvent.values, 0, mMagnetometers, 0, 3); 
       break; 
      default: 
       break; 
     } 
     float[] rotationMatrix = new float[9]; 
     boolean success = 
        SensorManager.getRotationMatrix(rotationMatrix, null, mAccelerometers, mMagnetometers); 
     if (success) { 
      SensorManager.getOrientation(rotationMatrix, mOrientation); 
      float azimuth = Math.toDegrees(mOrientation[0]); 
      float pitch = Math.toDegrees(mOrientation[1]); 
      float roll = Math.toDegrees(mOrientation[2]); 
     } 
     // cal to updateBearing(); 
    } 

在iOS中,CLHeading可以返回准确真实headingandroid中是否有一个班级具有相同的功能?我该如何计算它?

+0

这有帮助吗? http://stackoverflow.com/q/7355679/7292819 – Gary99

+0

@加里99,没有人。 – NamNH

+0

您是否检查过[this](http://stackoverflow.com/a/4316717/5993410) –

回答

3

检查下面的链接为您的问题轴承例子也回答以下

bearing-example

是similor您的问题。

How do I get the correct bearing?

package ymc.ch.bearingexample; 
import android.content.Context; 
import android.hardware.GeomagneticField; 
import android.hardware.Sensor; 
import android.hardware.SensorEvent; 
import android.hardware.SensorEventListener; 
import android.hardware.SensorManager; 
import android.location.Location; 
import android.location.LocationListener; 
import android.location.LocationManager; 
import android.os.Bundle; 
import android.util.Log; 

/** 
* Utility class that provides bearing values to true north. 
*/ 
public class BearingToNorthProvider implements SensorEventListener, LocationListener 
{ 
    public static final String TAG = "BearingToNorthProvider"; 

    /** 
    * Interface definition for a callback to be invoked when the bearing changes. 
    */ 
    public static interface ChangeEventListener { 
     /** 
     * Callback method to be invoked when the bearing changes. 
     * @param bearing the new bearing value 
     */ 
     void onBearingChanged(double bearing); 
    } 

    private final SensorManager mSensorManager; 
    private final LocationManager mLocationManager; 
    private final Sensor mSensorAccelerometer; 
    private final Sensor mSensorMagneticField; 

    // some arrays holding intermediate values read from the sensors, used to calculate our azimuth 
    // value 

    private float[] mValuesAccelerometer; 
    private float[] mValuesMagneticField; 
    private float[] mMatrixR; 
    private float[] mMatrixI; 
    private float[] mMatrixValues; 

    /** 
    * minimum change of bearing (degrees) to notify the change listener 
    */ 
    private final double mMinDiffForEvent; 

    /** 
    * minimum delay (millis) between notifications for the change listener 
    */ 
    private final double mThrottleTime; 

    /** 
    * the change event listener 
    */ 
    private ChangeEventListener mChangeEventListener; 

    /** 
    * angle to magnetic north 
    */ 
    private AverageAngle mAzimuthRadians; 

    /** 
    * smoothed angle to magnetic north 
    */ 
    private double mAzimuth = Double.NaN; 

    /** 
    * angle to true north 
    */ 
    private double mBearing = Double.NaN; 

    /** 
    * last notified angle to true north 
    */ 
    private double mLastBearing = Double.NaN; 

    /** 
    * Current GPS/WiFi location 
    */ 
    private Location mLocation; 

    /** 
    * when we last dispatched the change event 
    */ 
    private long mLastChangeDispatchedAt = -1; 

    /** 
    * Default constructor. 
    * 
    * @param context Application Context 
    */ 
    public BearingToNorthProvider(Context context) { 
     this(context, 10, 0.5, 50); 
    } 

    /** 
    * @param context Application Context 
    * @param smoothing the number of measurements used to calculate a mean for the azimuth. Set 
    *      this to 1 for the smallest delay. Setting it to 5-10 to prevents the 
    *      needle from going crazy 
    * @param minDiffForEvent minimum change of bearing (degrees) to notify the change listener 
    * @param throttleTime minimum delay (millis) between notifications for the change listener 
    */ 
    public BearingToNorthProvider(Context context, int smoothing, double minDiffForEvent, int throttleTime) 
    { 
     mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); 
     mSensorAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); 
     mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); 
     mSensorMagneticField = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); 

     mValuesAccelerometer = new float[3]; 
     mValuesMagneticField = new float[3]; 

     mMatrixR = new float[9]; 
     mMatrixI = new float[9]; 
     mMatrixValues = new float[3]; 

     mMinDiffForEvent = minDiffForEvent; 
     mThrottleTime = throttleTime; 

     mAzimuthRadians = new AverageAngle(smoothing); 
    } 

    //============================================================================================== 
    // Public API 
    //============================================================================================== 

    /** 
    * Call this method to start bearing updates. 
    */ 
    public void start() 
    { 
     mSensorManager.registerListener(this, mSensorAccelerometer, SensorManager.SENSOR_DELAY_UI); 
     mSensorManager.registerListener(this, mSensorMagneticField, SensorManager.SENSOR_DELAY_UI); 

     for (final String provider : mLocationManager.getProviders(true)) { 
      if (LocationManager.GPS_PROVIDER.equals(provider) 
        || LocationManager.PASSIVE_PROVIDER.equals(provider) 
        || LocationManager.NETWORK_PROVIDER.equals(provider)) { 
       if (mLocation == null) { 
        mLocation = mLocationManager.getLastKnownLocation(provider); 
       } 
       mLocationManager.requestLocationUpdates(provider, 0, 100.0f, this); 
      } 
     } 
    } 

    /** 
    * call this method to stop bearing updates. 
    */ 
    public void stop() 
    { 
     mSensorManager.unregisterListener(this, mSensorAccelerometer); 
     mSensorManager.unregisterListener(this, mSensorMagneticField); 
     mLocationManager.removeUpdates(this); 
    } 

    /** 
    * @return current bearing 
    */ 
    public double getBearing() 
    { 
     return mBearing; 
    } 

    /** 
    * Returns the bearing event listener to which bearing events must be sent. 
    * @return the bearing event listener 
    */ 
    public ChangeEventListener getChangeEventListener() 
    { 
     return mChangeEventListener; 
    } 

    /** 
    * Specifies the bearing event listener to which bearing events must be sent. 
    * @param changeEventListener the bearing event listener 
    */ 
    public void setChangeEventListener(ChangeEventListener changeEventListener) 
    { 
     this.mChangeEventListener = changeEventListener; 
    } 

    //============================================================================================== 
    // SensorEventListener implementation 
    //============================================================================================== 

    @Override 
    public void onSensorChanged(SensorEvent event) 
    { 
     switch (event.sensor.getType()) { 
      case Sensor.TYPE_ACCELEROMETER: 
       System.arraycopy(event.values, 0, mValuesAccelerometer, 0, 3); 
       break; 
      case Sensor.TYPE_MAGNETIC_FIELD: 
       System.arraycopy(event.values, 0, mValuesMagneticField, 0, 3); 
       break; 
     } 

     boolean success = SensorManager.getRotationMatrix(mMatrixR, mMatrixI, 
       mValuesAccelerometer, 
       mValuesMagneticField); 

     // calculate a new smoothed azimuth value and store to mAzimuth 
     if (success) { 
      SensorManager.getOrientation(mMatrixR, mMatrixValues); 
      mAzimuthRadians.putValue(mMatrixValues[0]); 
      mAzimuth = Math.toDegrees(mAzimuthRadians.getAverage()); 
     } 

     // update mBearing 
     updateBearing(); 
    } 

    @Override 
    public void onAccuracyChanged(Sensor sensor, int i) { } 

    //============================================================================================== 
    // LocationListener implementation 
    //============================================================================================== 

    @Override 
    public void onLocationChanged(Location location) 
    { 
     // set the new location 
     this.mLocation = location; 

     // update mBearing 
     updateBearing(); 
    } 

    @Override 
    public void onStatusChanged(String s, int i, Bundle bundle) { } 

    @Override 
    public void onProviderEnabled(String s) { } 

    @Override 
    public void onProviderDisabled(String s) { } 

    //============================================================================================== 
    // Private Utilities 
    //============================================================================================== 

    private void updateBearing() 
    { 
     if (!Double.isNaN(this.mAzimuth)) { 
      if(this.mLocation == null) { 
       Log.w(TAG, "Location is NULL bearing is not true north!"); 
       mBearing = mAzimuth; 
      } else { 
       mBearing = getBearingForLocation(this.mLocation); 
      } 

      // Throttle dispatching based on mThrottleTime and minDiffForEvent 
      if(System.currentTimeMillis() - mLastChangeDispatchedAt > mThrottleTime && 
       (Double.isNaN(mLastBearing) || Math.abs(mLastBearing - mBearing) >= mMinDiffForEvent)) { 
       mLastBearing = mBearing; 
       if(mChangeEventListener != null) { 
        mChangeEventListener.onBearingChanged(mBearing); 
       } 
       mLastChangeDispatchedAt = System.currentTimeMillis(); 
      } 
     } 
    } 

    private double getBearingForLocation(Location location) 
    { 
     return mAzimuth + getGeomagneticField(location).getDeclination(); 
    } 

    private GeomagneticField getGeomagneticField(Location location) 
    { 
     GeomagneticField geomagneticField = new GeomagneticField(
       (float)location.getLatitude(), 
       (float)location.getLongitude(), 
       (float)location.getAltitude(), 
       System.currentTimeMillis()); 
     return geomagneticField; 
    } 
} 
+0

谢谢!我读了这个样本。这很好,但我无法证实这是一个正确的答案。为什么'azimuth'是唯一一个用来计算'heading'的值,'pitch'和'roll'值如何。另外,在某个地方,我对'remapCoordinateSystem'方法感到困惑。 – NamNH

3
方位角

和位置来计算标题唯一需要的参数。

的角度进行计算和转换的约定是按以下顺序使用它们:
1)方位角
2)间距
3)辊

+1

对不起,我不得不张贴我的评论作为答案,因为我的代表是低于50. –

+0

经过许多引用的网站,现在我可以同意你的说法,azimuth和位置的偏差是我们需要计算的标题。 – NamNH

3

要计算一个标题,你只需要方位。正如你已经证明,它是values[0]从调用返回到SensorManager.getOrientation

然后,从弧度转换为度,并确保它的积极意义:

float current_measured_bearing = (float) (results[0] * 180/Math.PI); 
if (current_measured_bearing < 0) current_measured_bearing += 360; 

更多细节this answer,其中还考虑了effect of device orientation