得到当前点,距离和方位的纬度/长度

时间:2011-08-28 16:56:14

标签: python gis distance latitude-longitude

给定lat / long中的现有点,(以KM表示)和方位(以度数转换为弧度)的距离,我想计算新的纬度/经度。 This网站反复出现,但我无法让公式为我工作。

以上链接的公式为:

lat2 = asin(sin(lat1)*cos(d/R) + cos(lat1)*sin(d/R)*cos(θ))

lon2 = lon1 + atan2(sin(θ)*sin(d/R)*cos(lat1), cos(d/R)−sin(lat1)*sin(lat2))

以上公式适用于MSExcel where-

asin          = arc sin()   
d             = distance (in any unit)   
R             = Radius of the earth (in the same unit as above)  
and hence d/r = is the angular distance (in radians)  
atan2(a,b)    = arc tan(b/a)  
θ is the bearing (in radians, clockwise from north);  

这是我在Python中获得的代码。

import math

R = 6378.1 #Radius of the Earth
brng = 1.57 #Bearing is 90 degrees converted to radians.
d = 15 #Distance in km

#lat2  52.20444 - the lat result I'm hoping for
#lon2  0.36056 - the long result I'm hoping for.

lat1 = 52.20472 * (math.pi * 180) #Current lat point converted to radians
lon1 = 0.14056 * (math.pi * 180) #Current long point converted to radians

lat2 = math.asin( math.sin(lat1)*math.cos(d/R) +
             math.cos(lat1)*math.sin(d/R)*math.cos(brng))

lon2 = lon1 + math.atan2(math.sin(brng)*math.sin(d/R)*math.cos(lat1),
                     math.cos(d/R)-math.sin(lat1)*math.sin(lat2))

print(lat2)
print(lon2)

我得到了

lat2 = 0.472492248844 
lon2 = 79.4821662373

13 个答案:

答案 0 :(得分:61)

需要将弧度的答案转换回度数。下面的工作代码:

import math

R = 6378.1 #Radius of the Earth
brng = 1.57 #Bearing is 90 degrees converted to radians.
d = 15 #Distance in km

#lat2  52.20444 - the lat result I'm hoping for
#lon2  0.36056 - the long result I'm hoping for.

lat1 = math.radians(52.20472) #Current lat point converted to radians
lon1 = math.radians(0.14056) #Current long point converted to radians

lat2 = math.asin( math.sin(lat1)*math.cos(d/R) +
     math.cos(lat1)*math.sin(d/R)*math.cos(brng))

lon2 = lon1 + math.atan2(math.sin(brng)*math.sin(d/R)*math.cos(lat1),
             math.cos(d/R)-math.sin(lat1)*math.sin(lat2))

lat2 = math.degrees(lat2)
lon2 = math.degrees(lon2)

print(lat2)
print(lon2)

答案 1 :(得分:23)

geopy库支持:

import geopy
from geopy.distance import VincentyDistance

# given: lat1, lon1, b = bearing in degrees, d = distance in kilometers

origin = geopy.Point(lat1, lon1)
destination = VincentyDistance(kilometers=d).destination(origin, b)

lat2, lon2 = destination.latitude, destination.longitude

通过https://stackoverflow.com/a/4531227/37610

找到

答案 2 :(得分:9)

回答可能有点迟,但在测试了其他答案之后,它们似乎无法正常工作。这是我们用于系统的PHP代码。在各个方向工作。

PHP代码:

  

lat1 =以度为单位的起点纬度

     

long1 =以度为单位的起点经度

     

d = KM的距离

     

angle =以度为单位

function get_gps_distance($lat1,$long1,$d,$angle)
{
    # Earth Radious in KM
    $R = 6378.14;

    # Degree to Radian
    $latitude1 = $lat1 * (M_PI/180);
    $longitude1 = $long1 * (M_PI/180);
    $brng = $angle * (M_PI/180);

    $latitude2 = asin(sin($latitude1)*cos($d/$R) + cos($latitude1)*sin($d/$R)*cos($brng));
    $longitude2 = $longitude1 + atan2(sin($brng)*sin($d/$R)*cos($latitude1),cos($d/$R)-sin($latitude1)*sin($latitude2));

    # back to degrees
    $latitude2 = $latitude2 * (180/M_PI);
    $longitude2 = $longitude2 * (180/M_PI);

    # 6 decimal for Leaflet and other system compatibility
   $lat2 = round ($latitude2,6);
   $long2 = round ($longitude2,6);

   // Push in array and get back
   $tab[0] = $lat2;
   $tab[1] = $long2;
   return $tab;
 }

答案 3 :(得分:8)

此问题在geodesy的研究中被称为直接问题

这确实是一个非常受欢迎的问题,也是导致混淆的常见问题。原因是大多数人都在寻找一个简单而直截了当的答案。但没有,因为大多数人提出这个问题并没有提供足够的信息,只是因为他们不知道:

  1. 地球不是一个完美的球体,因为它被它的杆子弄平/压缩
  2. 由于(1)地球没有恒定的半径,R。见here
  3. 地球不是非常光滑(高度变化)等。
  4. 由于构造板移动,地理点的纬度/经度位置每年可能会改变几毫米(至少)。
  5. 因此,根据您所需的精度,在各种几何模型中使用的许多不同的假设会有不同的应用。因此,要回答这个问题,您需要考虑一下准确度您希望得到的结果。

    一些例子:

    • 我只是在latitudes N之间的0-70 deg小距离(< 100 km)找到距离最近几公里的大致位置| S 即可。 (地球是平面模型。)
    • 我想要一个在全球任何地方都很好的答案,但只能精确到几米
    • 我想要一个超精确的定位,有效的原子尺度为nanometers [nm]。
    • 我想要的答案非常快速且易于计算,而且计算量不大。

    因此,您可以选择使用哪种算法。此外,每种编程语言都有自己的实现或“包”乘以模型数量和模型开发人员的特定需求。出于所有实际目的,忽略javascript之外的任何其他语言是值得的,因为它本质上非常类似于伪代码。因此,它可以很容易地转换为任何其他语言,只需要很小的改动。

    然后主要模型是:

    • Euclidian/Flat earth model:适用于~10 km以下的极短距离
    • Spherical model:适用于较大的纵向距离,但纬度差异较小。热门型号:
      • Haversine米精度[km]刻度,代码非常简单。
    • Ellipsoidal models:在任何纬度/经度和距离上最准确,但仍然是一个数值近似值,取决于您需要的准确度。一些流行的模型是:

    <强>参考文献:

答案 4 :(得分:3)

lon1和lat1(度)

brng =以弧度为单位

d =以km为单位的距离

R =以千米为单位的地球半径

lat2 = math.degrees((d/R) * math.cos(brng)) + lat1
long2 = math.degrees((d/(R*math.sin(math.radians(lat2)))) * math.sin(brng)) + long1

我在PHP中实现了您的算法并对其进行了基准测试。该版本在大约50%的时间内运行。生成的结果是相同的,因此它似乎在数学上是等价的。

我没有测试上面的python代码,因此可能存在语法错误。

答案 5 :(得分:2)

使用geopy的快速方法

from geopy import distance
#distance.distance(unit=15).destination((lat,lon),bering) 
#Exemples
distance.distance(nautical=15).destination((-24,-42),90) 
distance.distance(miles=15).destination((-24,-42),90)
distance.distance(kilometers=15).destination((-24,-42),90) 

答案 6 :(得分:1)

也很晚,但对于那些可能会发现这一点的人,您将使用geographiclib库获得更准确的结果。查看测地线问题描述和JavaScript示例,以便简单介绍如何使用回答主题问题以及许多其他问题。包括Python在内的各种语言的实现。如果你关心准确性,那就远比编码你自己更好;比早期的VincentyDistance更好&#34;使用库&#34;建议。正如文档所说:&#34;重点是返回准确的结果,误差接近四舍五入(约5-15纳米)。&#34;

答案 7 :(得分:1)

只需交换atan2(y,x)函数中的值即可。不是atan2(x,y)!

答案 8 :(得分:1)

我将Brad的答案移植到了香草JS答案,没有Bing映射的依赖项

https://jsfiddle.net/kodisha/8a3hcjtd/

// ----------------------------------------
// Calculate new Lat/Lng from original points
// on a distance and bearing (angle)
// ----------------------------------------
let llFromDistance = function(latitude, longitude, distance, bearing) {
  // taken from: https://stackoverflow.com/a/46410871/13549 
  // distance in KM, bearing in degrees

  const R = 6378.1; // Radius of the Earth
  const brng = bearing * Math.PI / 180; // Convert bearing to radian
  let lat = latitude * Math.PI / 180; // Current coords to radians
  let lon = longitude * Math.PI / 180;

  // Do the math magic
  lat = Math.asin(Math.sin(lat) * Math.cos(distance / R) + Math.cos(lat) * Math.sin(distance / R) * Math.cos(brng));
  lon += Math.atan2(Math.sin(brng) * Math.sin(distance / R) * Math.cos(lat), Math.cos(distance / R) - Math.sin(lat) * Math.sin(lat));

  // Coords back to degrees and return
  return [(lat * 180 / Math.PI), (lon * 180 / Math.PI)];

}

let pointsOnMapCircle = function(latitude, longitude, distance, numPoints) {
  const points = [];
  for (let i = 0; i <= numPoints - 1; i++) {
    const bearing = Math.round((360 / numPoints) * i);
    console.log(bearing, i);
    const newPoints = llFromDistance(latitude, longitude, distance, bearing);
    points.push(newPoints);
  }
  return points;
}


const points = pointsOnMapCircle(41.890242042122836, 12.492358982563019, 0.2, 8);


let geoJSON = {
  "type": "FeatureCollection",
  "features": []
};
points.forEach((p) => {
  geoJSON.features.push({
    "type": "Feature",
    "properties": {},
    "geometry": {
      "type": "Point",
      "coordinates": [
        p[1],
        p[0]
      ]
    }
  });
});



document.getElementById('res').innerHTML = JSON.stringify(geoJSON, true, 2);

此外,我添加了geoJSON导出,因此您只需将生成的geoJSON粘贴到 http://geojson.io/#map=17/41.89017/12.49171并立即查看结果。

结果: geoJSON Screenshot

答案 9 :(得分:0)

我将Python移植到Javascript。这将返回Bing Maps Location对象,您可以更改为您喜欢的任何内容。

getLocationXDistanceFromLocation: function(latitude, longitude, distance, bearing) {
    // distance in KM, bearing in degrees

    var R = 6378.1,                         // Radius of the Earth
        brng = Math.radians(bearing)       // Convert bearing to radian
        lat = Math.radians(latitude),       // Current coords to radians
        lon = Math.radians(longitude);

    // Do the math magic
    lat = Math.asin(Math.sin(lat) * Math.cos(distance / R) + Math.cos(lat) * Math.sin(distance / R) * Math.cos(brng));
    lon += Math.atan2(Math.sin(brng) * Math.sin(distance / R) * Math.cos(lat), Math.cos(distance/R)-Math.sin(lat)*Math.sin(lat));

    // Coords back to degrees and return
    return new Microsoft.Maps.Location(Math.degrees(lat), Math.degrees(lon));

},

答案 10 :(得分:0)

这是基于Ed Williams Aviation Formulary的PHP版本。在PHP中,模数处理稍有不同。这对我有用。

function get_new_waypoint ( $lat, $lon, $radial, $magvar, $range )
{

   // $range in nm.
   // $radial is heading to or bearing from    
   // $magvar for local area.

   $range = $range * pi() /(180*60);
   $radial = $radial - $magvar ;

   if ( $radial < 1 )
     {
        $radial = 360 + $radial - $magvar; 
     }
   $radial =  deg2rad($radial);
   $tmp_lat = deg2rad($lat);
   $tmp_lon = deg2rad($lon);
   $new_lat = asin(sin($tmp_lat)* cos($range) + cos($tmp_lat) * sin($range) * cos($radial));
   $new_lat = rad2deg($new_lat);
   $new_lon = $tmp_lon - asin(sin($radial) * sin($range)/cos($new_lat))+ pi() % 2 * pi() -  pi();
   $new_lon = rad2deg($new_lon);

   return $new_lat." ".$new_lon;

}

答案 11 :(得分:0)

如果有人需要,我将答案从@David M移植到java ...我得到的结果与52.20462299620793,0.360433887489931略有不同

    double R = 6378.1;  //Radius of the Earth
    double brng = 1.57;  //Bearing is 90 degrees converted to radians.
    double d = 15;  //Distance in km

    double lat2 = 52.20444; // - the lat result I'm hoping for
    double lon2 = 0.36056; // - the long result I'm hoping for.

    double lat1 = Math.toRadians(52.20472); //Current lat point converted to radians
    double lon1 = Math.toRadians(0.14056); //Current long point converted to radians

    lat2 = Math.asin( Math.sin(lat1)*Math.cos(d/R) +
            Math.cos(lat1)*Math.sin(d/R)*Math.cos(brng));

    lon2 = lon1 + Math.atan2(Math.sin(brng)*Math.sin(d/R)*Math.cos(lat1),
            Math.cos(d/R)-Math.sin(lat1)*Math.sin(lat2));

    lat2 = Math.toDegrees(lat2);
    lon2 = Math.toDegrees(lon2);

    System.out.println(lat2 + ", " + lon2);

答案 12 :(得分:0)

感谢@kodisha,这是一个 Swift 版本,但对地球半径进行了改进和更精确的计算:

extension CLLocationCoordinate2D {
  
  func earthRadius() -> CLLocationDistance {
    let earthRadiusInMetersAtSeaLevel = 6378137.0
    let earthRadiusInMetersAtPole = 6356752.314
    
    let r1 = earthRadiusInMetersAtSeaLevel
    let r2 = earthRadiusInMetersAtPole
    let beta = latitude
    
    let earthRadiuseAtGivenLatitude = (
      ( pow(pow(r1, 2) * cos(beta), 2) + pow(pow(r2, 2) * sin(beta), 2) ) /
        ( pow(r1 * cos(beta), 2) + pow(r2 * sin(beta), 2) )
    )
    .squareRoot()
    
    return earthRadiuseAtGivenLatitude
  }
  
  func locationByAdding(
    distance: CLLocationDistance,
    bearing: CLLocationDegrees
  ) -> CLLocationCoordinate2D {
    let latitude = self.latitude
    let longitude = self.longitude
    
    let earthRadiusInMeters = self.earthRadius()
    let brng = bearing.degreesToRadians
    var lat = latitude.degreesToRadians
    var lon = longitude.degreesToRadians
    
    lat = asin(
      sin(lat) * cos(distance / earthRadiusInMeters) +
        cos(lat) * sin(distance / earthRadiusInMeters) * cos(brng)
    )
    lon += atan2(
      sin(brng) * sin(distance / earthRadiusInMeters) * cos(lat),
      cos(distance / earthRadiusInMeters) - sin(lat) * sin(lat)
    )
    
    let newCoordinate = CLLocationCoordinate2D(
      latitude: lat.radiansToDegrees,
      longitude: lon.radiansToDegrees
    )
    
    return newCoordinate
  }
}

extension FloatingPoint {
  var degreesToRadians: Self { self * .pi / 180 }
  var radiansToDegrees: Self { self * 180 / .pi }
}