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

时间:2010-10-14 11:09:15

标签: math google-maps

有没有办法计算两个纬度/经度点之间的角度?

我想要实现的是知道用户的前进方向。例如,用户正在前往北,南,......东南等地

但我只有两点(Lng / Ltd)

THX

17 个答案:

答案 0 :(得分:39)

使用this引用来计算角度:

private double angleFromCoordinate(double lat1, double long1, double lat2,
        double long2) {

    double dLon = (long2 - long1);

    double y = Math.sin(dLon) * Math.cos(lat2);
    double x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1)
            * Math.cos(lat2) * Math.cos(dLon);

    double brng = Math.atan2(y, x);

    brng = Math.toDegrees(brng);
    brng = (brng + 360) % 360;
    brng = 360 - brng; // count degrees counter-clockwise - remove to make clockwise

    return brng;
}

答案 1 :(得分:21)

你可以使用谷歌地图computeHeading:

var point1 = new google.maps.LatLng(lat1, lng1);
var point2 = new google.maps.LatLng(lat2, lng2);
var heading = google.maps.geometry.spherical.computeHeading(point1,point2);

答案 2 :(得分:9)

计算两点之间的角度(方位)的通用公式如下:

θ = atan2(sin(Δlong)*cos(lat2), cos(lat1)*sin(lat2) − sin(lat1)*cos(lat2)*cos(Δlong))

请注意,在使用此公式之前,应将角度(θ)转换为弧度 Δlong= long2 - long1。

atan2是几乎所有编程语言中常见的函数(主要在Math包/库中)。通常还有在度和弧度之间进行转换的函数(也在Math包/库中)。

请记住,atan2返回-π... +π范围内的值,要将结果转换为罗盘方位,需要将θ乘以180 /π然后使用(θ+ 360)%360,其中%是模数除法运算返回除法的其余部分。

以下链接是涉及纬度和经度的公式的良好资源。他们还提供其公式的Javascript实现。实际上,这个答案是基于这个页面的信息:

http://www.yourhomenow.com/house/haversine.html

答案 3 :(得分:4)

根据Nayanesh Gupte的回答,如果有人需要,这是一个Python实现:

def angleFromCoordinate(lat1, long1, lat2, long2):
    dLon = (long2 - long1)

    y = math.sin(dLon) * math.cos(lat2)
    x = math.cos(lat1) * math.sin(lat2) - math.sin(lat1) * math.cos(lat2) * math.cos(dLon)

    brng = math.atan2(y, x)

    brng = math.degrees(brng)
    brng = (brng + 360) % 360
    brng = 360 - brng # count degrees clockwise - remove to make counter-clockwise

    return brng

0度角表示向北的标题。

答案 4 :(得分:3)

在Javascript中,我创建一个函数名称angleFromCoordinate,在其中我传递了两个lat / lng。此函数将在两个lat / lng

之间返回angel
function angleFromCoordinate(lat1,lon1,lat2,lon2) {
    var p1 = {
        x: lat1,
        y: lon1
    };

    var p2 = {
        x: lat2,
        y: lon2
    };
    // angle in radians
    var angleRadians = Math.atan2(p2.y - p1.y, p2.x - p1.x);
    // angle in degrees
    var angleDeg = Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180 / Math.PI;
    console.log(angleDeg);
    return angleDeg;
}

工作代码段

function angleFromCoordinate(lat1,lon1,lat2,lon2) {
    var p1 = {
        x: lat1,
        y: lon1
    };

    var p2 = {
        x: lat2,
        y: lon2
    };
    // angle in radians
    var angleRadians = Math.atan2(p2.y - p1.y, p2.x - p1.x);
    // angle in degrees
    var angleDeg = Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180 / Math.PI;

    document.getElementById('rotation').innerHTML ="Rotation : "+ angleDeg;
    return angleDeg;
    
}
     angleFromCoordinate(37.330604,-122.028947,37.3322109,-122.0329665);
<html>
<p id="rotation">Rotation : </p>
</html>

答案 5 :(得分:3)

如果点之间的距离较小,请使用示例javascript代码 -

brng = Math.atan2(newLat - oldLat, newLong - oldLong);
brng = brng * (180 / Math.PI);
brng = (brng + 360) % 360;
brng = 360 - brng;

答案 6 :(得分:2)

我认为你想要Great Circle bearing的计算。

答案 7 :(得分:2)

如果您使用的是Google Maps(Android),有一种简单的方法-使用SphericalUtil

double angle = SphericalUtil.computeHeading(fromLatLng, toLatLng);

考虑到我们有2点及其经度和纬度 然后创建其Latlng对象

LatLng latlng = new LatLng(latValue, lngValue);

获得2点Latlng后,使用sperical util获取角度

//import com.google.maps.android.SphericalUtil;
double sphericalValue = SphericalUtil.computeHeading(latLng1, latLng2);

SpericalValue是角度。 考虑您有一个汽车图标,并将其相应地转向行驶方向。从latLng1到latLng2然后

Bitmap vehiclePin = rotateIconBitmap(sphericalValue);
mMap.addMarker(new MarkerOptions().anchor(0.5f, 0.5f).position(latLng2))
               .setIcon(BitmapDescriptorFactory.fromBitmap(vehiclePin));

使用以下方法旋转

    Bitmap rotateIconBitmap(double angle) {
       Bitmap source = BitmapFactory.decodeResource(getResources(), 
                                          R.drawable.ic_vehicle_say_car);
       Matrix matrix = new Matrix();
       matrix.postRotate((float) angle);
       return Bitmap.createBitmap(source, 0, 0, 
                    source.getWidth(), source.getHeight(), matrix, true);
    }

enter image description here

轻松实现超级旋转图标的方式

注意:-如果标记图标未指向零度,则可能需要添加90度的偏移量

androidsphereutil是开源的,如果您使用的是Java,请参考它,您可以使用它。

https://github.com/googlemaps/android-maps-utils/blob/master/library/src/com/google/maps/android/SphericalUtil.java

答案 8 :(得分:2)

function calculateAngle(lat, lng) {
    var checkLengthInterval = 2;

    // Calculate Angle
    //If ObjFeed == [] add first object.
    if (ObjFeed.length == 0) {
        ObjFeed.push({ 'lat': lat, 'lng': lng });
    } else {
        // Get last object from list to calculate angle betwn last and latest.
        var tempNode = ObjFeed[ObjFeed.length - 1];
        // If last lat and lng is same as current it will always return 0 angle.so only push lat lng in obj which is diff than last one.
        if (!(tempNode.lat == lat && tempNode.lng == lng)) {
            ObjFeed.push({ 'lat': lat, 'lng': lng });
        } else {
            console.log('exact match for lat lng');
        }
    }
     // this is for to keep only few objects in the list and remove other
    if (ObjFeed.length >= checkLengthInterval) {
        // calculating angle only if previous data point is available
        ObjFeed = ObjFeed.slice(-1 * checkLengthInterval); // remove all items in array except last two
        var point1 = ObjFeed[ObjFeed.length - checkLengthInterval];
        var point2 = ObjFeed[ObjFeed.length - 1];

        console.log('previous point1', point1);
        console.log('next point2', point2);

        var dLng = (point2.lng - point1.lng);
        var dLat = (point2.lat - point1.lat);

        dLng = dLng * 10000;
        dLat = dLat * 10000;

        var dlat_by_dlan = 0;

        try {
            dlat_by_dlan = dLng / dLat;
        } catch (err) {
            dlat_by_dlan = NaN;
            console.log('Exception: dLat == 0');
        }

        var angleDegreeBearing = 0, angleBearingRad = 0;
        angleBearingRad = Math.atan(dlat_by_dlan);
        angleDegreeBearing = angleBearingRad * 180 / Math.PI;

        if (dLat < 0 && dLng < 0) {
            angleDegreeBearing = angleDegreeBearing + 180;
        } else if (dLat < 0 && dLng > 0) {
            angleDegreeBearing = angleDegreeBearing + 180;
        } else if (dLat == 0 && dLng == 0) {
            angleDegreeBearing = prevVechicleAngle;
        } else if (dlat_by_dlan == NaN) {
            angleDegreeBearing = prevVechicleAngle;
        }

        console.log('angleDegreeBearing', angleDegreeBearing);

    } else {
        // setting up default angle to 0 if previous data point is not available to calculate actual anglle
        console.log('feedArray default angle 0');
        angleDegreeBearing = 0;
    }
    prevVechicleAngle = angleDegreeBearing;
    return angleDegreeBearing;

}

答案 9 :(得分:1)

也许这就是你想要的:

cos(say) = (cosd(90-lat(1))) * (cos(90-lat(2)))
         + (sin(90-lat(1))) * (sind(90-lat(2)) * (cosd(abs(Landa(2)-landa(1)))));

答案 10 :(得分:1)

如果您需要精确的旋转椭球方法(即WGS 84),则algorithms会变得很沉重。您可能会受益于GeographicLib,它已经在C / C ++,Java,JavaScript,Python,Matlab / Octave和其他版本中实现。

对于这个问题,在第一点和第二点之间有一个geodesicrhumb line

大地测量

测地线是曲面上两点之间的最短路径。这是“用户前往”位置的最常见解释(来自问题),因为它是最短和最直接的。可以使用GeodSolve来解决反测地线计算问题。您也可以使用online interface。该工具具有输入/输出:

  

lat1 lon1 lat2 lon2 azi1 azi2 s12

其中 lat1 lon1 是第一个点的坐标对,而 lat2 lon2 是第二个点的坐标对。所有单位均为度(不是弧度)。结果 azi1 或α 1 是从起点开始的方位角(又称方位角),从北向顺时针方向给出。第二个方位角在第二个点,因为沿着测地线的两个点之间的角度不是恒定的。 s12 是两点之间的距离,以米为单位,精度为15 nm。

大黄线

一条横线连接两个坐标点,它们具有恒定的方位角(或方位角)。 可以使用RhumbSolve来解决反摆线计算问题。您也可以使用online interface。该工具具有输入/输出:

  

lat1 lon1 lat2 lon2 azi12 s12

这些参数与GeodSolve相同,除了 azi12 是两点之间的恒定角度。

答案 11 :(得分:1)

要提供标题,您必须计算方位。

了解方位读数this article

根据这个article (section bearing),公式为:

θ = atan2( sin Δλ ⋅ cos φ2 , cos φ1 ⋅ sin φ2 − sin φ1 ⋅ cos φ2 ⋅ cos Δλ )
where φ1, λ1 is the start point, 
      φ2, λ2 the end point,
      Δλ is the difference in longitude`

以下是关于如何计算以Lat / Lon表示的两点之间的角度(以度为单位)的示例。 (用C#完成)

让我们说Point是一个简单的类,有两个double属性X(经度)和Y(持纬度)。

public double ComputeBearing(Point start,Point end)
{
     var φ1 = start.Y; //latitude 1
     var λ1 = start.X; //longitude 1
     var φ2 = end.Y; //latitude 2
     var λ2 = end.X; //longitude 2

     var y = Math.Sin(this.degreeToRadian(λ2 - λ1)) * Math.Cos(this.degreeToRadian(φ2));
     var x = Math.Cos(this.degreeToRadian(φ1)) * Math.Sin(this.degreeToRadian(φ2)) - Math.Sin(this.degreeToRadian(φ1)) * Math.Cos(this.degreeToRadian(φ2)) * Math.Cos(this.degreeToRadian(λ2 - λ1));

     var θ = Math.Atan2(y, x);
     θ = this.radianToDegree(θ);

     return θ;
}

使用以下方法:

public double degreeToRadian(double angle)
{
    return Math.PI * angle / 180.0;
}

public double radianToDegree(double angle)
{
    return angle * (180.0 / Math.PI);
}

通过使用ComputeBearing,您可以轻松获得以度数表示的角度,可以轻松地用作标题

答案 12 :(得分:1)

如果有人需要PHP代码来实现此功能:

/**
 * Calculate angle between 2 given latLng
 * @param  float $lat1
 * @param  float $lat2
 * @param  float $lng1
 * @param  float $lng2
 * @return integer
 */
function angle($lat1, $lat2, $lng1, $lng2) {
    $dLon = $lng2 - $lng1;
    $y = sin($dLon) * cos($lat2);
    $x = cos($lat1) * sin($lat2) - sin($lat1) * cos($lat2) * cos($dLon);
    return 360 - ((rad2deg(atan2($y, $x)) + 360) % 360);
}

答案 13 :(得分:1)

对于那些使用C / C ++的人,下面是经过测试的代码:

static const auto PI = 3.14159265358979323846, diameterOfEarthMeters = 6371.0 * 2 * 1000;

double degreeToRadian (double degree) { return (degree * PI / 180); };
double radianToDegree (double radian) { return (radian * 180 / PI); };

double CoordinatesToAngle (const double latitude1,
                           const double longitude1,
                           const double latitude2,
                           const double longitude2)
{
  const auto longitudeDifferenceRadians = degreeToRadian(longitude2 - longitude1);
  auto latitude1Radian = degreeToRadian(latitude1),
       latitude2Radian = degreeToRadian(latitude2);

  const auto x = std::cos(latitude1Radian) * std::sin(latitude2Radian) -
                 std::sin(latitude1Radian) * std::cos(latitude2Radian) *
                 std::cos(longitudeDifferenceRadians);
  const auto y = std::sin(longitudeDifferenceRadians) * std::cos(latitude2Radian);

  return radianToDegree(std::atan2(y, x));
}

double CoordinatesToMeters (const double latitude1,
                            const double longitude1,
                            const double latitude2,
                            const double longitude2)
{
  auto latitude1Radian = degreeToRadian(latitude1),
       longitude1Radian = degreeToRadian(longitude1),
       latitude2Radian = degreeToRadian(latitude2),
       longitude2Radian = degreeToRadian(longitude2);
  auto x = std::sin((latitude2Radian - latitude1Radian) / 2),
       y = std::sin((longitude2Radian - longitude1Radian) / 2);

  return diameterOfEarthMeters *
         std::asin(std::sqrt((x * x) +
                             (std::cos(latitude1Radian) * std::cos(latitude2Radian) * y * y)));
}

答案 14 :(得分:0)

考虑 Nayanesh Gupte 的回答及其评论。我已经更改了部分代码并在$('#addDataset').click(function() { var background = randomColor(0.5); var nextCompanyLabel = 6; var newDataset = { label: label[nextCompanyLabel++], borderColor: background, backgroundColor: background, pointBorderColor: background, pointBackgroundColor: background, pointBorderWidth: 1, fill: false, data: [], }; for (var index = 0; index < config.data.labels.length; ++index) { newDataset.data.push(randomScalingFactor()); } config.data.datasets.push(newDataset); window.myLine.update(); }); 中编写了它。

  • 纬度经度已在函数内转换为弧度

这是功能:

PHP

答案 15 :(得分:0)

  

确保它的竖线不是一个很大的圆形轴承   初始轴承根据距离变化

 double angle= Math.min((pbearingf-tbearingf) < 0 ? pbearingf-tbearingf+360:pbearingf-tbearingf, (tbearingf-pbearingf)<0?tbearingf-pbearingf+360:tbearingf-pbearingf);

答案 16 :(得分:0)

使用javascript,只需使用Turf

var point1 = turf.point([-75.343, 39.984]);
var point2 = turf.point([-75.534, 39.123]);

var bearing = turf.bearing(point1, point2);
相关问题