如何在已知两点之间生成坐标

9

背景:

我正在处理交通路线,并且谷歌提供了足够远的路线点来创建“形状”。这些是您在谷歌地图上看到的公交/火车路线。

我的要求:

谷歌的点足够远,可以创建直线。但是,我想每隔5米就有一个点。

问题:

因此,假设我有两个点[纬度,经度]:

[-33.8824219918503,151.206686052582]和[-33.8815434600467,151.206556440037]

给定这两个点,我可以计算它们之间的距离。为了方便起见,假设距离为1公里。

因此,我们可以想象在这两个点之间存在一条虚拟的直线。

如何为该虚拟线生成坐标,例如每隔5米?


2
对于短距离来说可能不是很重要,但沿着地球表面的一条直线并不是直的。 - Stefan
http://en.wikipedia.org/wiki/Great-circle_distance and http://en.wikipedia.org/wiki/Great-circle_navigation - Marek Lipka
3个回答

14

起始点到目的地点的距离和方位角后的目的地点可应用于您的问题:

class Numeric
  def to_rad
    self * Math::PI / 180
  end
  def to_deg
    self * 180 / Math::PI
  end
end

include Math

R = 6371.0

def waypoint(φ1, λ1, θ, d)
  φ2 = asin( sin(φ1) * cos(d/R) + cos(φ1) * sin(d/R) * cos(θ) )
  λ2 = λ1 + atan2( sin(θ) * sin(d/R) * cos(φ1), cos(d/R) - sin(φ1) * sin(φ2) )
  λ2 = (λ2 + 3 * Math::PI) % (2 * Math::PI) - Math::PI # normalise to -180..+180°2, λ2]
end

φ1, λ1 = -33.to_rad, -71.6.to_rad   # Valparaíso
φ2, λ2 = 31.4.to_rad, 121.8.to_rad  # Shanghai

d = R * acos( sin(φ1) * sin(φ2) + cos(φ1) * cos(φ2) * cos(λ2 - λ1) )
θ = atan2( sin(λ2 - λ1) * cos(φ2), cos(φ1) * sin(φ2) - sin(φ1) * cos(φ2) * cos(λ2 - λ1) )

waypoints = (0..d).step(2000).map { |d| waypoint(φ1, λ1, θ, d) }

markers = waypoints.map { |φ, λ| "#{φ.to_deg},#{λ.to_deg}" }.join("|")

puts "http://maps.googleapis.com/maps/api/staticmap?size=640x320&sensor=false&markers=#{markers}"

生成一条Google静态地图链接,其路线为从瓦尔帕莱索到上海,每隔2,000公里设置一个途经点:

http://maps.googleapis.com/maps/api/staticmap?size=640x320&sensor=false&markers=-33.0,-71.60000000000002|-32.54414813683714,-93.02142653011552|-28.59922979115139,-113.43958859125276|-21.877555679819015,-131.91586675556778|-13.305784544363858,-148.5297601858932|-3.7370081151180683,-163.94988578467394|6.094273692291354,-179.03345538133888|15.493534924596633,165.33401731030006|23.70233917422386,148.3186618914762|29.83806632244171,129.34766276764626


这很棒,@stefan。我知道这超出了问题的范围,但您介意解释一些数学知识或指导我方向吗?我理解三角学部分(在理论上),但我不明白距离单位。似乎无论使用哪个单位都没有关系? - andy
哦,为什么所有东西都要转换成弧度? - andy
1
只需使用相同的单位。在一个直径为6,000公里的球体上行驶1公里,就相当于在一个直径为6,000毫米的球体上行驶1毫米。这种转换是必要的,因为Math三角函数需要使用弧度作为单位。 - Stefan

3

步骤1 - 获取总距离

这里可以找到全面的答案:http://www.movable-type.co.uk/scripts/latlong.html

简略版:

使用‘haversine’公式计算两点之间的大圆距离,即在地球表面上最短的距离 - 给出两点之间的‘直线距离’(当然会忽略任何山丘!)。

var R = 6371; // km
var dLat = (lat2-lat1).toRad();
var dLon = (lon2-lon1).toRad();
var lat1 = lat1.toRad();
var lat2 = lat2.toRad();

var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
        Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2); 
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
var distance = R * c;

第二步 - 获取行驶百分比。

现在您已经有了这条直线的距离,您可以计算出每五米的总距离的百分比。

第三步 - 将行驶百分比应用于纬度和经度之间的差异

找出起始纬度和最终纬度之间的差异。使用此数字,将其乘以行驶百分比(作为小数)。然后可以将其添加回起始纬度,以查找此点的当前纬度。对经度重复此操作。


这是JavaScript,但我相信你也可以用Ruby做同样的事情。 - benjaminjosephw
谢谢@benjaminjosephw。但是等一下,这给我两点之间的距离对吧?但我想知道如何沿着一条线每5米生成一个点。你明白我的意思吗? - andy
抱歉,更新已添加。这对我来说很有意义,看起来很合理,但是我必须承认我不是数学家。请先检查一下这是否有效! - benjaminjosephw
@benjaminjosephw,您能详细说明第2步和第3步的具体内容吗? - Alan

1
以下解决方案可能不完全符合您的要求,但可能足以满足您的目的...
请查看官方文档(https://developers.google.com/maps/documentation/javascript/reference)中的interpolate方法。从文档中可以了解到:“返回在起点LatLng和终点LatLng之间给定的分数处的LatLng。”
因此,如果您知道您的原始点相距100米,并且将0.05指定为分数,则该方法将为每5米返回沿该线的lat/lng。

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