两点之间的方位角+地球曲率问题

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/…

以上是关于两点之间的方位角+地球曲率问题的主要内容,如果未能解决你的问题,请参考以下文章

T-SQL:这个地理距离算法是不是没有考虑地球曲率

如何用 lng 和 lat 获得地球上两点之间的距离或弧度?

地球表面两点距离计算

数据分析系列 之根据经纬度计算两点之间的距离

计算两个经纬度之间的距离

c# 计算地球上两点间距离