Christopher Olsson已经给出了一个好的答案,但是我想补充一些理论。
我一直觉得this webpage对这些公式很有用。
关于概念的简短说明
想象实际发生的几何形态。
现在,你只是在缩放输入。想象一下气球的经典例子。在气球上画出两条在底部和顶部相交的线段。它们代表经度线,因为它们向上和向下。当然要加引号,因为这些概念并不存在,但我们可以想象。现在,如果你看每条线段,就会发现随着你沿着它们的长度向上和向下移动,它们的距离是不同的。根据原始规格,它们在气球的顶部和底部相交,但在其他任何地方都不相交。经线也是如此。非欧几里得几何告诉我们,如果它们相交,则直线恰好相交两次,这可能很难想象。但由于这个原因,我们的线之间的距离在赤道处被有效地反射。
正如您所看到的,纬度极大地影响经线之间的距离。它们在南北极最近,在赤道最远。
纬线要简单一些。它们不会相交。如果您把我们的理论气球竖直地拿起来,将极点指向上下,也就是说,纬线将与地面平行。更一般地说,它们将垂直于经线极点形成的轴(欧几里得概念)。因此,无论您的经度如何,纬度之间的距离都是恒定的。
现在,您的实现依赖于这些线始终保持恒定距离的想法。如果是这样,您就可以采取简单的缩放方法,就像您所做的那样。如果它们实际上是欧几里得意义上的平行线,那么它与从英里每小时转换为公里每小时的概念并没有太大区别。然而,距离的差异使得这变得更加复杂。
北极的经线距离为零,在赤道上,正如你引用的维基百科页面所述,它是111.32公里。因此,要得到真正准确的结果,您必须考虑您所寻找的纬度。这就是为什么会变得更加复杂的原因。
获取实际结果
现在,根据您最近的编辑,您似乎希望融合纬度和经度进行评估的公式。根据您的代码示例,您似乎想要找到两个坐标之间的距离,并且希望它在短距离内运行良好。因此,我建议使用Haversine公式,就像我在本文开头指向的网站建议的那样。该网站提供了很多有关它的良好信息,但这就是公式本身。我直接从该网站复制它,包括符号,以确保我不犯任何愚蠢的打字错误。当然,这是JavaScript,但您可以基本上只更改一些情况,它将在C#中运行。
在其中,φ是纬度,λ是经度,θ是方位(以弧度表示,顺时针从北方),δ是角距离(以弧度表示)d / R; d是行驶距离,R是地球半径。
var R = 6371;
var φ1 = lat1.toRadians();
var φ2 = lat2.toRadians();
var Δφ = (lat2-lat1).toRadians();
var Δλ = (lon2-lon1).toRadians();
var a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
Math.cos(φ1) * Math.cos(φ2) *
Math.sin(Δλ/2) * Math.sin(Δλ/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c;
我认为需要注意的唯一一点是,正如第一行声明的那样,
R
是地球的半径。正如注释所建议的,我们已经在使用公里,因此您可能需要根据您的实现更改它。幸运的是,在线搜索可以轻松地找到您喜欢的单位下(平均)地球半径。
当然,您还需要注意,
toRadians
只是将输入乘以
Math.PI
,然后除以180。非常简单。
替代方案
这段内容可能与您的情况不太相关,但我会包含它。上述公式将给出准确的结果,但速度会受到影响。显然,在任何单个记录上都不是什么大问题,但随着您处理的数据越来越多,这可能会成为一个问题。如果确实存在这样的问题,并且您正在处理一个相当集中的地区,您可以利用我们星球的巨大性质,找到适合纬度和经度之间距离的数字,然后将星球视为“更或多或少欧几里得”(即平面),并使用勾股定理计算值。当然,离原始测试站点越远,这种方法就越不准确(我个人只需通过询问Google Earth或类似产品来查找这些数字)。但如果您正在处理一群密集的用户,那将比运行一堆公式到Math类更快得多。
另一种更抽象的替代方案
你可能还需要考虑逻辑处理的位置。在这里,我有点超出了我的能力范围,但是如果你恰好将数据存储在SQL Server中,则它已经内置了一些非常酷的地理功能,可以为你处理距离计算。只需查看
GEOGRAPHY
类型即可。
编辑
这是对评论的回应,建议所需结果实际上是表示边界的矩形。现在,我建议不要这样做,因为它并不是你的代码可能暗示的搜索“半径”。
但是,如果你确实想坚持使用该方法,你将需要查看两个单独的距离:一个用于纬度,一个用于经度。这也来自那个网页。
φ1
是
myLatitude
,而
λ1
是
myLongitude
。该公式接受方位和起始坐标,然后给出结果位置。
var φ2 = Math.asin( Math.sin(φ1)*Math.cos(d/R) + Math.cos(φ1)*Math.sin(d/R)*Math.cos(brng) );
var λ2 = λ1 + Math.atan2(Math.sin(brng)*Math.sin(d/R)*Math.cos(φ1), Math.cos(d/R)-Math.sin(φ1)*Math.sin(φ2));
你可以使用它来确定搜索矩形的边界。
double.Parse
更合理。 - Sayse