在Android中计算罗盘方位/前往位置

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在Android中计算罗盘方位/前往位置相关的知识,希望对你有一定的参考价值。

我想在谷歌地图视图上的我的位置显示一个箭头,显示我相对于目的地位置(而不是北方)的方向。

a)我使用磁力计和加速度计的传感器值计算了北方。我知道这是正确的,因为它与谷歌地图视图中使用的指南针对齐。

b)我使用myLocation.bearingTo(destLocation)计算了从我的位置到目的地位置的初始方位;

我错过了最后一步;从这两个值(a和b)我用什么公式来得出手机相对于目的地位置的方向?

感谢任何有关心灵的帮助!

答案

好的,我想出来了。对于其他试图这样做的人,你需要:

a)航向:从硬件指南针前进。这是磁北以东的度数

b)轴承:轴承从您的位置到目的地。这是在真北的东边。

myLocation.bearingTo(destLocation);

c)赤纬:真北和磁北之间的差异

从磁力计+加速度计返回的航向是真(磁)北(-180到+180)以东的度数,所以你需要得到北和磁北的区别。这种差异是可变的,取决于你在地球上的位置。您可以使用GeomagneticField类获取。

GeomagneticField geoField;

private final LocationListener locationListener = new LocationListener() {
   public void onLocationChanged(Location location) {
      geoField = new GeomagneticField(
         Double.valueOf(location.getLatitude()).floatValue(),
         Double.valueOf(location.getLongitude()).floatValue(),
         Double.valueOf(location.getAltitude()).floatValue(),
         System.currentTimeMillis()
      );
      ...
   }
}

有了这些,您可以计算在地图上绘制的箭头的角度,以显示您相对于目标对象所面对的位置,而不是真正的北方。

首先用赤纬调整你的标题:

heading += geoField.getDeclination();

其次,您需要从目标目的地而不是真北偏移手机朝向(航向)的方向。这是我被困住的部分。从罗盘返回的航向值为您提供一个值,该值描述磁北向(相对于手机指向的位置的真北的度数)。所以例如如果值为-10,则表示磁北向左侧10度。轴承为您提供目的地的角度,以真北为东。因此,在您补偿了赤纬后,您可以使用下面的公式来获得所需的结果:

heading = myBearing - (myBearing + heading); 

然后,您将要从真北(-180到+180)以东的度数转换为正常度数(0到360):

Math.round(-heading / 360 + 180)
另一答案

这是在Google地图上检测来自位置对象的方位的最佳方法: - >

 float targetBearing=90;

      Location endingLocation=new Location("ending point"); 

      Location
       startingLocation=new Location("starting point");
       startingLocation.setLatitude(mGoogleMap.getCameraPosition().target.latitude);
       startingLocation.setLongitude(mGoogleMap.getCameraPosition().target.longitude);
       endingLocation.setLatitude(mLatLng.latitude);
       endingLocation.setLongitude(mLatLng.longitude);
      targetBearing =
       startingLocation.bearingTo(endingLocation);

另一答案

以下是计算两点之间轴承角度的代码:

public float CalculateBearingAngle(double lat1,double lon1, double lat2, double lon2){
    double Phi1 = Math.toRadians(lat1);
    double Phi2 = Math.toRadians(lat2);
    double DeltaLambda = Math.toRadians(lon2 - lon1);
    double Theta = atan2((sin(DeltaLambda)*cos(Phi2)),
        (cos(Phi1)*sin(Phi2) - sin(Phi1)*cos(Phi2)*cos(DeltaLambda)));
    return (float)Math.toDegrees(Theta);
}

征集功能:

float angle = CalculateBearingAngle(lat1, lon1, lat2, lon2);
另一答案

公式将使用起点坐标到终点see给出方位

以下代码将为您提供轴承(角度在0-360之间)

private double bearing(Location startPoint, Location endPoint) {
    double longitude1 = startPoint.getLongitude();
    double latitude1 = Math.toRadians(startPoint.getLatitude());

    double longitude2 = endPoint.getLongitude();        
    double latitude2 = Math.toRadians(endPoint.getLatitude());

    double longDiff = Math.toRadians(longitude2 - longitude1);

    double y = Math.sin(longDiff) * Math.cos(latitude2);
    double x = Math.cos(latitude1) * Math.sin(latitude2) - Math.sin(latitude1) * Math.cos(latitude2) * Math.cos(longDiff);

    return Math.toDegrees(Math.atan2(y, x));

}

这对我有用,希望它也会对其他人有用

另一答案

@Damian - 这个想法非常好,我同意答案,但是当我使用你的代码时我的错误值,所以我自己写了这个(有人在你的评论中说了同样的话)。我想,计算带有赤纬的标题是好的,但后来我使用了类似的东西:

heading = (bearing - heading) * -1;

而不是达米安的代码:

heading = myBearing - (myBearing + heading); 

并将-180更改为180表示0到360:

      private float normalizeDegree(float value){
          if(value >= 0.0f && value <= 180.0f){
              return value;
          }else{
              return 180 + (180 + value);
          }

然后当你想旋转你的箭头时你可以使用这样的代码:

      private void rotateArrow(float angle){

            Matrix matrix = new Matrix();
            arrowView.setScaleType(ScaleType.MATRIX);
            matrix.postRotate(angle, 100f, 100f);
            arrowView.setImageMatrix(matrix);
      }

其中arrowView是带有箭头图片的ImageViewpostRotate中的100f参数是枢轴和旋转)。

我希望我会帮助别人。

另一答案

在此指南针上的箭头显示从您的位置到Kaaba的方向(目的地位置)

你可以通过这种方式简单地使用bearing.bearing将给你从你的位置到目的地的直接角度

  Location userLoc=new Location("service Provider");
    //get longitudeM Latitude and altitude of current location with gps class and  set in userLoc
    userLoc.setLongitude(longitude); 
    userLoc.setLatitude(latitude);
    userLoc.setAltitude(altitude);

   Location destinationLoc = new Location("service Provider");
  destinationLoc.setLatitude(21.422487); //kaaba latitude setting
  destinationLoc.setLongitude(39.826206); //kaaba longitude setting
  float bearTo=userLoc.bearingTo(destinationLoc);

bearingTo会给你-180到180的范围,这会让事情有点混乱。我们需要将此值转换为0到360的范围才能获得正确的旋转。

这是我们真正想要的表格,与轴承给我们的内容相比较

+-----------+--------------+
| bearingTo | Real bearing |
+-----------+--------------+
| 0         | 0            |
+-----------+--------------+
| 90        | 90           |
+-----------+--------------+
| 180       | 180          |
+-----------+--------------+
| -90       | 270          |
+-----------+--------------+
| -135      | 225          |
+-----------+--------------+
| -180      | 180          |
+-----------+--------------+

所以我们必须在bearTo之后添加这段代码

// If the bearTo is smaller than 0, add 360 to get the rotation clockwise.

  if (bearTo < 0) {
    bearTo = bearTo + 360;
    //bearTo = -100 + 360  = 260;
}

你需要实现SensorEventListener及其函数(onSensorChanged,onAcurracyChabge)并写入onSensorChanged中的所有代码

完整的代码在这里为Qibla指南针方向

 public class QiblaDirectionCompass extends Service implements SensorEventListener{
 public static ImageView image,arrow;

// record the compass picture angle turned
private float currentDegree = 0f;
private float currentDegreeNeedle = 0f;
Context context;
Location userLoc=new Location("service Provider");
// device sensor manager
private static SensorManager mSensorManager ;
private Sensor sensor;
public static TextView tvHeading;
   public QiblaDirectionCompass(Context context, ImageView compass, ImageView needle,TextView heading, double longi,double lati,double alti ) {

    image = compass;
    arrow = needle;


    // TextView that will tell the user what degree is he heading
    tvHeading = heading;
    userLoc.setLongitude(longi);
    userLoc.setLatitude(lati);
    userLoc.setAltitude(alti);

  mSensorManager =  (SensorManager) context.getSystemService(SENSOR_SERVICE);
    sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
    if(sensor!=null) {
        // for the system's orientation sensor registered listeners
        mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_GAME);//SensorManager.SENSOR_DELAY_Fastest
    }else{
        Toast.makeText(context,"Not Supported", Toast.LENGTH_SHORT).show();
    }
    // initialize your android device sensor capabilities
this.context =context;
@Override
public void onCreate() {
    // TODO Auto-generated method stub
    Toast.makeText(context, "Started", Toast.LENGTH_SHORT).show();
    mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_GAME); //SensorManager.SENSOR_DELAY_Fastest
    super.onCreate();
}

@Override
public void onDestroy() {
    mSensorManager.unregisterListener(this);
Toast.makeText(context, "Destroy", Toast.LENGTH_SHORT).show();

    super.onDestroy();

}
@Override
public void onSensorChanged(SensorEvent sensorEvent) {


Location destinationLoc = new Location("service Provider");

destinationLoc.setLatitude(21.422487); //kaaba latitude setting
destinationLoc.setLongitude(39.826206); //kaaba longitude s

以上是关于在Android中计算罗盘方位/前往位置的主要内容,如果未能解决你的问题,请参考以下文章

iOS SDK中当前位置的方位

计算两个位置之间的方位角

(译)计算距离方位和更多经纬度之间的点

计算两个纬度/经度点之间的角度

android - 如何获得两个位置之间的方位度?

Android 使用两个不同的代码片段获取当前位置 NULL