点和线之间的最短距离(Google Maps API 问题?)

Posted

技术标签:

【中文标题】点和线之间的最短距离(Google Maps API 问题?)【英文标题】:Shortest distance between a point and a line (Google Maps API issue?) 【发布时间】:2018-11-21 19:43:56 【问题描述】:

我试图找到从 C 点到海滩的直线距离。海滩线由 A 点和 B 点定义,使用 Haversine 公式,我得到从 C(我在谷歌地图中的标记)到 AB 海滩线中垂直于 C 的点 D 的距离。

一切正常,但 D 点不是正确的。我用这段代码找到D:

function get_perp(C)
        var A =  lat:33.345678, lng:-117.518921 ;
        var B =  lat:33.100678, lng:-117.318492 ;

        t = ((C.lat-A.lat)*(B.lat-A.lat)+(C.lng-A.lng)*(B.lng-A.lng))/((B.lat-A.lat)*(B.lat-A.lat)+(B.lng-A.lng)*(B.lng-A.lng));

        var D =  lat:0,lng:0;
        D.lat = A.lat + t*(B.lat-A.lat);
        D.lng = A.lng + t*(B.lng-A.lng);

        return D;

返回的D点确实是直线上的一个点,但它不垂直于C。是AB线水平或垂直的时候,但是AB和CD的夹角不对的时候。

我已经尝试了我在这里找到的其他功能,但它们都导致相同的结果。

在这个小提琴中,它是整个过程,如果你放大到足够大,你可以看到 AB 和 CD 线不垂直:Shortest distance from AB to C

编辑:在 geogebra 中使用它我可以看到该功能可以找到点。当 google maps api 表示该点时,就会发生错误。 Geogebra

【问题讨论】:

这很有趣。绝对是某种精度误差或舍入误差。或者可能与三角函数有关。 我尝试了四种不同的方法,它们都返回相同的点坐标,始终在线但不是最近/垂直于 C。 如果我猜的话,我会说精度错误发生在这里的某个地方:t = ((C.lat-A.lat)*(B.lat-A.lat)+(C.lng-A.lng)*(B.lng-A.lng))/((B.lat-A.lat)*(B.lat-A.lat)+(B.lng-A.lng)*(B.lng-A.lng)); 我一直在使用 geogebra 中的函数,它是正确的!它总是返回精确的垂直点,所以错误是当谷歌地图 api 将该点放在线上时。老实说,我不知道为什么。我已经编辑并放置了 geogebra 链接。 看这个answer,很容易移植到javascript 【参考方案1】:

据我所知,您的 D 公式是正确的,并且线性近似值在如此小的范围内是合理的(增量约为四分之一度;由于非线性引起的相对误差应该在10^-5)。

您看到的可能是由于地图投影不一致(不保留角度),因此角度未显示为正确的。但这点是正确的。

你知道他们使用哪种投影吗?


Bingo,角度对了,只是投影造成的显示神器。

【讨论】:

我用谷歌搜索了它,谷歌地图似乎改变了 3 个月前使用的投影。现在他们使用方位角透视投影(又名垂直透视投影)。之前的投影是Web Mercator。但我真的不知道 GMaps API 是否仍然使用墨卡托,因为如果你使用 API 一直放大,你就看不到地球的球体,就像现在在谷歌地图中发生的那样。 @Alvaro:如果你能把经络和纬线显示出来,你很快就会知道。 IMO,地球曲率的校正是不必要的。 刚刚看到您的编辑...所以,这意味着垂直距离比水平距离长吗?如果是这样,像街道环岛这样的物体不应该是椭圆形的吗? @Alvaro:红色矩形是经纬度 0.1°。【参考方案2】:

您使用平面几何方法进行计算,但对于球面几何,它们是错误的。 (C.f.:请注意,您使用 Haversine 公式而不是毕达哥拉斯公式找到距离)。

在this page,你可以找到算法和JS代码来找到跨轨道距离和沿轨道距离(可能用于使用从第一点的方位和这个距离来找到D点)

Cross-track distance
Here’s a new one: I’ve sometimes been asked about distance of a
point from a great-circle path (sometimes called cross track
error).

Formula:    dxt = asin( sin(δ13) ⋅ sin(θ13−θ12) ) ⋅ R
where   δ13 is (angular) distance from start point to third point
θ13 is (initial) bearing from start point to third point
θ12 is (initial) bearing from start point to end point
R is the earth’s radius
JavaScript: 
var δ13 = d13 / R;
var dXt = Math.asin(Math.sin(δ13)*Math.sin(θ13-θ12)) * R;
Here, the great-circle path is identified by a start point and 
an end point – depending on what initial data you’re working from,
you can use the formulæ above to obtain the relevant distance 
and bearings. The sign of dxt tells you which side of the path
the third point is on.

The along-track distance, from the start point to the closest 
point on the path to the third point, is

Formula:    dat = acos( cos(δ13) / cos(δxt) ) ⋅ R
where   δ13 is (angular) distance from start point to third point
δxt is (angular) cross-track distance
R is the earth’s radius
JavaScript: 
var δ13 = d13 / R;
var dAt = Math.acos(Math.cos(δ13)/Math.cos(dXt/R)) * R;

【讨论】:

感谢@MBo,但问题出在我使用 Haversine 之前。在fiddle 我什至不使用它。我使用 get_perp() 函数计算点,它的坐标是 euclideanly 正确的,但是在地图 api 中表示它时,它不是应该的位置。 看到那把小提琴了。再次 - 将平面方法应用于球坐标是完全错误的。 get_perp() 在这里无效。另请注意,地球上点之间的最短路径不是地图上的直线(不包括等经度的情况) 我知道你一定是对的,问题只能是平面/球面差异。但我不明白为什么谷歌然后将任何 AB 线绘制为直线,它不应该是弯曲的吗?为什么如果我把 AB 点放在一条笔直的街道上,然后在一条垂直的街道上选择一个 C 点,即使在非常短的距离内,它也不正确,我认为地球曲率并不重要@ 987654323@. @MBo:IMO 点之间的距离不足以解释 OP 显示的异常。我们在一个小于 1° 的正方形内。 最短路径是大圆弧,远点应该弯曲。但是 gmap 在地图上直接绘制连接线(不是测地线/loxodrome/smth 其他)-我检查了 9000 公里的飞机路线

以上是关于点和线之间的最短距离(Google Maps API 问题?)的主要内容,如果未能解决你的问题,请参考以下文章

在 Google Maps v2 上计算当前位置和标记之间的距离

获取两个位置 android google maps 之间的距离并画线

在 Google Maps for Ionic 2 中计算两点之间的距离

使用 Google Maps API 查找两个位置之间的路线和距离并将其呈现在表格中

最近邻和点与线之间的距离

如何使用带有 Google Maps Roads API 的坐标列表计算距离