两点之间的方位角+地球曲率问题
Posted
技术标签:
【中文标题】两点之间的方位角+地球曲率问题【英文标题】:Location bearing between two points + earth curvature issue 【发布时间】:2014-05-07 01:35:08 【问题描述】:我想实现三件事:
1)基于位置传感器实现指南针+获取当前坐标
2) 设置方位到固定目的地
3) 设置好方位后,我想设置一个红色指南针,无论手机旋转如何,它都会继续指向该固定方位。
到目前为止,我已经完成了 1 + 2。关于 3 - 我设法将针指向正确的方向,但是随着手机旋转 - 针也旋转,失去了正确的方向。我已经尝试了很多事情,但我无法让它发挥作用。
还有一个问题:如果bearingTo() 方法计算两个位置之间的度数——它是否考虑了地球曲率?如果没有,这仅对近距离是准确的...希望是这样:-)
我将不胜感激。
这是我的代码 - 检查 cmets 以获得解释。提前致谢!
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
tvCurrAzim = (TextView) findViewById(R.id.tvaz);
tvCurrLat = (TextView) findViewById(R.id.tvlat);
tvCurrLng = (TextView) findViewById(R.id.tvlng);
tvBearing = (TextView) findViewById(R.id.tvbearing);
tvIndicator = (TextView) findViewById(R.id.tvindicator);
ivCompass = (ImageView) findViewById(R.id.imageView1); //compass ImageView
ivArrow = (ImageView) findViewById(R.id.imageView2); //Red Needle ImageView
// Get the location manager
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
// Define the criteria how to select the location provider -> use
// default
Criteria criteria = new Criteria();
provider = locationManager.getBestProvider(criteria, true);
location = locationManager.getLastKnownLocation(provider);
tvCurrLat.setText(String.valueOf(location.getLatitude()));
tvCurrLng.setText(String.valueOf(location.getLongitude()));
from = new Location(location); //creating new Location object
to = new Location(location); //creating new Location object
//setting lat,lng to destination Location
to.setLatitude(newLat);
to.setLongitude(newLng);
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
mCompass = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
// Compass Sensor Methods:
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy)
// TODO Auto-generated method stub
@Override
public void onSensorChanged(SensorEvent event)
// setting animation for compass
azimuth = Math.round(event.values[0]);
tvCurrAzim.setText(Float.toString(azimuth));
// get the angle around the z-axis rotated
// float degree = Math.round(event.values[0]);
// create a rotation animation (reverse turn degree degrees)
RotateAnimation ra = new RotateAnimation(currentDegree, -azimuth,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
// how long the animation will take place
ra.setDuration(210);
// set the animation after the end of the reservation status
ra.setFillAfter(true);
// Start the animation
ivCompass.startAnimation(ra);
currentDegree = -azimuth;
pointArrow();
// Location Manager Methods:
public void setBearing()
from.setLatitude(location.getLatitude()); //setting lat,lng to origin Location
from.setLongitude(location.getLongitude());
bearing = Math.round(from.bearingTo(to));
tvBearing.setText(String.valueOf(bearing));
hasBearing = true;
ivArrow.setVisibility(View.VISIBLE);
public void pointArrow()
if (hasBearing) //once bearing is set
// get the angle around the z-axis rotated
float degree1 = Math.round(azimuth) - (float) bearing;
// create a rotation animation (reverse turn degree degrees)
RotateAnimation ra1 = new RotateAnimation(currentDegree1, -degree1,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
// how long the animation will take place
ra1.setDuration(210);
// set the animation after the end of the reservation status
ra1.setFillAfter(true);
// Start the animation
ivArrow.startAnimation(ra1);
currentDegree1 = -degree1;
//THIS METHOD WORKS TO POINT THE NEEDLE IN CORRECT DIRECTION, BUT AS PHONE ROTATES THE NEEDLE ROTATES TOO.
//I WANT IT TO KEEP POINTING IN FIXED DIRECTION REGARDLESS OF PHONE ROTATION
@Override
public void onLocationChanged(Location location)
tvCurrLat.setText(String.valueOf(location.getLatitude()));
tvCurrLng.setText(String.valueOf(location.getLongitude()));
setBearing();
locationManager.removeUpdates(this);
@Override
public void onStatusChanged(String provider, int status, Bundle extras)
@Override
public void onProviderEnabled(String provider)
@Override
public void onProviderDisabled(String provider)
@Override
protected void onPause()
// Unregister the listener
super.onPause();
locationManager.removeUpdates(this);
mSensorManager.unregisterListener(this);
ivArrow.setVisibility(View.INVISIBLE);
@Override
protected void onResume()
super.onResume();
locationManager.requestLocationUpdates(provider, 1000, 1, this);
mSensorManager.registerListener(this, mCompass,
SensorManager.SENSOR_DELAY_GAME);
【问题讨论】:
【参考方案1】:android 文档说 bearingTo()
使用 WGS84 椭球,所以是的,它考虑了地球曲率。
要使您的指南针在设备旋转时使用位置传感器保持稳定是不够的,您还应该使用磁场传感器。大多数 Android 设备都有它们。
你需要SensorManager.getOrientation()
查看:http://developer.android.com/reference/android/hardware/SensorManager.html
【讨论】:
感谢您的回答。您知道如何完成我在问题中提到的第三部分吗?谢谢! @gilonm 在 textview tvCurrAzim 中,旋转设备时文本会改变吗? @gilonm 如果是这样,问题在于重绘指针,而不是获取设备方向... @gilonm 使您的代码更加清晰、易读和易于测试,将与指向箭头相关的所有方法和属性集中在一个单独的类中。它应该存储箭头的当前旋转、角度、动画资源 - 因此在接收到新方向后,您只需调用指向箭头对象的更新方法,它会自行完成所有其他工作。 @gilonm 我做了这样一个对象来处理方向更新,看看***.com/questions/22725606/…以上是关于两点之间的方位角+地球曲率问题的主要内容,如果未能解决你的问题,请参考以下文章