根据百分比计算两个坐标点之间的中间点

9
我正在寻找一个功能,它返回两个点之间(我也指定了它们的纬度和经度)的一个点(纬度,经度),该点基于距离百分比。因此,我在函数中指定Lat1、Lon1、Lat2、Lon2和一个百分比,并返回一个点,例如从第一个点到第二个点距离的20%。

1
如果您正在使用Google Maps API,请查看插值函数,它可以在两个点之间以某个分数(0-1)计算出一个点。 - Christiaan Westerbeek
3个回答

13

假设坐标是十进制数。您可以使用此方程式。

function midpoint(lat1, long1, lat2, long2, per) {
     return [lat1 + (lat2 - lat1) * per, long1 + (long2 - long1) * per];
}

根据百分比(例如per=0.2表示20%),返回一个新的[lat, long]坐标。


6
一般来说,经纬度的中点不是通过这个公式计算出来的中点,因为它们是球面坐标而不是平面坐标。 - spirographer
2
Iguiel,我也考虑过这个问题,但它并不像那样工作。例如,对于P1(37.740675,-25.661043)和P2(37.738096,-25.669267),20%返回P3(7.5478771,-5,133031)。这将把我放在非洲而不是P1和P2之间的亚速尔群岛。 - mignz
1
嗨,Swift-R,我看到了,我想我的方程式有误,应该是: [lat1+(lat2-lat1)*per, long1+(long2-long1)*per] 我会编辑我的答案。希望这对你有用。 - lguiel
1
除了地图之外,这实际上是其他创意JavaScript相关事物的非常好的功能 - 我在这个笔记本http://codepen.io/headwinds/pen/BLVXwa?editors=0010中进行了测试。 - headwinds
1
这个方程在数学上是不正确的。线性插值经纬度不是适当的球面数学方法。 - Meekohi

4

这里有一个非常有用的参考资料(请查看底部链接)

http://www.movable-type.co.uk/scripts/latlong.html

中间点

可以计算两点间大圆路径上任何分数位置的中间点。

公式:

a = sin((1−f)⋅δ) / sin δ
b = sin(f⋅δ) / sin δ
x = a ⋅ cos φ1 ⋅ cos λ1 + b ⋅ cos φ2 ⋅ cos λ2
y = a ⋅ cos φ1 ⋅ sin λ1 + b ⋅ cos φ2 ⋅ sin λ2
z = a ⋅ sin φ1 + b ⋅ sin φ2
φi = atan2(z, √x² + y²)
λi = atan2(y, x)

其中f表示大圆航线上的分数(f=0代表点1,f=1代表点2),δ是两点间的角距离d/R


我不明白百分比是怎么出现的。 - mignz
1
f 是从点1到点2的分数。百分比是分母为100的分数。例如,如果你的百分比是39%,那么分数f=39/100 - spirographer

4

两个答案对于特定用户可能都有用,但我想指出一些问题。

lguiel的解决方案对于游戏或短距离是正确的,但不适用于地球作为球体进行几何计算。

spirographer的答案是正确的,但由于它非常理论化,可能太难以编程。

我将第二个答案翻译成了实用的编程语言,这样你就可以在自己的项目中使用它。

完整代码 | 在线运行

// Original calculation from https://www.movable-type.co.uk/scripts/latlong.html
LatLng calculateIntermediatePoint(LatLng point1, LatLng point2, double perc) {
  //const φ1 = this.lat.toRadians(), λ1 = this.lon.toRadians();
  //const φ2 = point.lat.toRadians(), λ2 = point.lon.toRadians();
  double lat1 = degreesToRadians(point1.latitude);
  double lng1 = degreesToRadians(point1.longitude);
  double lat2 = degreesToRadians(point2.latitude);
  double lng2 = degreesToRadians(point2.longitude);

  //const Δφ = φ2 - φ1;
  //const Δλ = λ2 - λ1;
  double deltaLat = lat2 - lat1;
  double deltaLng = lng2 - lng1;

  //const a = Math.sin(Δφ/2) * Math.sin(Δφ/2) + Math.cos(φ1) * Math.cos(φ2) * Math.sin(Δλ/2) * Math.sin(Δλ/2);
  //const δ = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
  double calcA = sin(deltaLat / 2) * sin(deltaLat / 2) +
      cos(lat1) * cos(lat2) * sin(deltaLng / 2) * sin(deltaLng / 2);
  double calcB = 2 * atan2(sqrt(calcA), sqrt(1 - calcA));

  //const A = Math.sin((1-fraction)*δ) / Math.sin(δ);
  //const B = Math.sin(fraction*δ) / Math.sin(δ);
  double A = sin((1 - perc) * calcB) / sin(calcB);
  double B = sin(perc * calcB) / sin(calcB);

  //const x = A * Math.cos(φ1) * Math.cos(λ1) + B * Math.cos(φ2) * Math.cos(λ2);
  //const y = A * Math.cos(φ1) * Math.sin(λ1) + B * Math.cos(φ2) * Math.sin(λ2);
  //const z = A * Math.sin(φ1) + B * Math.sin(φ2);
  double x = A * cos(lat1) * cos(lng1) + B * cos(lat2) * cos(lng2);
  double y = A * cos(lat1) * sin(lng1) + B * cos(lat2) * sin(lng2);
  double z = A * sin(lat1) + B * sin(lat2);

  //const φ3 = Math.atan2(z, Math.sqrt(x*x + y*y));
  //const λ3 = Math.atan2(y, x);
  double lat3 = atan2(z, sqrt(x * x + y * y));
  double lng3 = atan2(y, x);

  //const lat = φ3.toDegrees();
  //const lon = λ3.toDegrees();
  return LatLng(radiansToDegrees(lat3), radiansToDegrees(lng3));
}

谢谢。可以确认,这是正确的答案。运行得非常好! - awaik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接