javascript 计算两个 GPS 坐标之间的罗盘方位的问题

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11415106/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 13:07:39  来源:igfitidea点击:

Issue with calculating compass bearing between two GPS coordinates

javascriptgeolocation

提问by Jason

In my webapp, have a JSON data response from a database query that includes the lat/long coordinates of 1 to n locations. I want to calculate the bearing from the data[i]location to the current position.

在我的 web 应用程序中,有一个来自数据库查询的 JSON 数据响应,其中包括 1 到 n 个位置的经纬度坐标。我想计算从该data[i]位置到当前位置的方位角。

I've been adapting the code here, but the bearing returned is incorrect.

我一直在调整这里的代码,但返回的轴承不正确。

//starting lat/long along with converting lat to rads
var endLat = toRad(location.lat());        
var endLong = location.lng();

//loop over response, calculate new headings for links and add link to array
for(var i=0; i<data.length; i++){

  //this link's lat/long coordinates, convert lat to rads
  var startLat = toRad(data[i].lat);
  var startLong = data[i].lon;

  //get the delta values between start and end coordinates in rads
  var dLong = toRad(endLong - startLong);

  //calculate 
  var y = Math.sin(dLong)*Math.cos(endLong);
  var x = Math.cos(startLat)*Math.sin(endLat)-Math.sin(startLat)*Math.cos(endLat)*Math.cos(dLong);
  var bearing = Math.atan(y, x);
  bearing = (toDeg(bearing) + 360) % 360;

  panoLinks.push({'heading': bearing, 'description': data[i].description, 'pano': data[i].description});
}

//radian/degree conversions
function toRad(convert){
  return convert * Math.PI/180;
}

function toDeg(convert){
  return convert * 180/Math.PI;
}

Using the functions above and the values

使用上面的函数和值

startLat= 43.6822, converts to 0.7623982145146669 radians
startLong= -70.450769

endLat= 43.682211, converts to 0.7623984065008848 radians
endLong= -70.45070

dLong = startLong - endLong, converts to 0.0000011170107216805305 radians

results in a compass degree of

导致罗盘度数

bearing= 0.000014910023935499339

which is definitely off. Where have I gone wrong?

这绝对是关闭的。我哪里错了?

回答by Manatok

Give this a try, I can't for the life of me remember where I got it though...

试试这个,我一辈子都记不起我是从哪里得到它的……

    /**
     * Calculate the bearing between two positions as a value from 0-360
     *
     * @param lat1 - The latitude of the first position
     * @param lng1 - The longitude of the first position
     * @param lat2 - The latitude of the second position
     * @param lng2 - The longitude of the second position
     *
     * @return int - The bearing between 0 and 360
     */
    bearing : function (lat1,lng1,lat2,lng2) {
        var dLon = (lng2-lng1);
        var y = Math.sin(dLon) * Math.cos(lat2);
        var x = Math.cos(lat1)*Math.sin(lat2) - Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
        var brng = this._toDeg(Math.atan2(y, x));
        return 360 - ((brng + 360) % 360);
    },

   /**
     * Since not all browsers implement this we have our own utility that will
     * convert from degrees into radians
     *
     * @param deg - The degrees to be converted into radians
     * @return radians
     */
    _toRad : function(deg) {
         return deg * Math.PI / 180;
    },

    /**
     * Since not all browsers implement this we have our own utility that will
     * convert from radians into degrees
     *
     * @param rad - The radians to be converted into degrees
     * @return degrees
     */
    _toDeg : function(rad) {
        return rad * 180 / Math.PI;
    },

回答by Chaudhry Junaid

This is an edit of the accepted answer with some modifications which made it work for me (mainly the use of toRad function on lat,lng values).

这是对已接受答案的编辑,并进行了一些修改,使其对我有用(主要是在 lat,lng 值上使用 toRad 函数)。

    var geo = {
        /**
         * Calculate the bearing between two positions as a value from 0-360
         *
         * @param lat1 - The latitude of the first position
         * @param lng1 - The longitude of the first position
         * @param lat2 - The latitude of the second position
         * @param lng2 - The longitude of the second position
         *
         * @return int - The bearing between 0 and 360
         */
        bearing : function (lat1,lng1,lat2,lng2) {
            var dLon = this._toRad(lng2-lng1);
            var y = Math.sin(dLon) * Math.cos(this._toRad(lat2));
            var x = Math.cos(this._toRad(lat1))*Math.sin(this._toRad(lat2)) - Math.sin(this._toRad(lat1))*Math.cos(this._toRad(lat2))*Math.cos(dLon);
            var brng = this._toDeg(Math.atan2(y, x));
            return ((brng + 360) % 360);
        },

       /**
         * Since not all browsers implement this we have our own utility that will
         * convert from degrees into radians
         *
         * @param deg - The degrees to be converted into radians
         * @return radians
         */
        _toRad : function(deg) {
             return deg * Math.PI / 180;
        },

        /**
         * Since not all browsers implement this we have our own utility that will
         * convert from radians into degrees
         *
         * @param rad - The radians to be converted into degrees
         * @return degrees
         */
        _toDeg : function(rad) {
            return rad * 180 / Math.PI;
        },
    };

    /** Usage **/
    var myInitialBearing = geo.bearing(0,0,45,45);

Find theory and online calculator at: http://www.movable-type.co.uk/scripts/latlong.html

查找理论和在线计算器:http: //www.movable-type.co.uk/scripts/latlong.html

回答by RobG

If you want a very rough method for short distances, you can use an Earth radius of 6,378,137m (the length of the semi-major axis of the WGS84 spheroid) to calculate the sides of the triangle based on the difference in latitude and longitude. Then calculate the appropriate bearing. It will be a true bearing, but likely close enough over short distances.

如果你想要一个非常粗略的短距离方法,你可以使用地球半径 6,378,137m(WGS84 椭球体的半长轴的长度),根据经纬度差计算三角形的边。然后计算合适的轴承。这将是一个真正的方位,但可能在短距离内足够接近。

You'll need to leave it up to users to work out the local magnetic declination.

您需要让用户自行计算当地的磁偏角。

e.g. for your example:

例如,对于您的示例:

startLat  = 43.6822
startLong = -70.450769

endLat  = 43.682211
endLong = -70.45070

diff lat  = 0.000011 = 1.22m
diff long = 0.000069 = 7.68m

The end point is north and east of the start, so the bearing can be found by:

终点位于起点的北侧和东侧,因此可以通过以下方式找到方位:

tan a = 7.68 / 1.22
    a = 81°

So the direction is about East by North.

所以方向大约是东偏北

This should probably be in a mapping and surveying thread. Once you've got the maths worked out, come here for the solution.

这可能应该在测绘和测量线程中。一旦你解决了数学问题,就来这里寻找解决方案。

Edit

编辑

To convert degrees of latitude to metres, first calculate the Earth circumference at the equator (or any great circle):

要将纬度转换为米,首先计算赤道(或任何大圆)的地球周长:

c = 2πR where r = 6378137m
  = 40,075,000 (approx)

Then get the ratio of the circumference out of 360°:

然后得到圆周与360°的比例:

dist = c * deg / 360
     = 40,075,000m * 0.000011° / 360°
     = 1.223m

For longitude, the distance narrows as the latitude approaches the pole, so the same formula is used and the result multiplied by the cosine of the latitude:

对于经度,距离随着纬度接近极点而变窄,因此使用相同的公式并将结果乘以纬度的余弦:

     = 40,075,000m * 0.000069° / 360° * cos(0.000011°)
     = 7.681m

The value for the Earth radius is not necessarily accurate, the Earth isn't a perfect sphere (it's an oblate spheroid, sort of pear shaped). Different approximations are used in different places for greater accuracy, but the one I've used should be good enough.

地球半径的值不一定准确,地球不是一个完美的球体(它是一个扁球体,有点像梨形)。在不同的地方使用了不同的近似值以获得更高的精度,但我使用的那个应该足够好。