在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
是带有箭头图片的ImageView
和postRotate
中的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中计算罗盘方位/前往位置的主要内容,如果未能解决你的问题,请参考以下文章