计算PHP中两个X,Y坐标之间的距离

时间:2011-01-02 11:04:56

标签: php mysql algorithm math coordinate-systems

我正在为游戏编写一个工具,它涉及计算500个单位的环形平面上两个坐标之间的距离。也就是说,[0,0]到[499,499]是有效坐标,[0,0]和[499,499]也是相邻的。

目前,在我的应用程序中,我正在比较一个城市与[X,Y]位置之间的距离,该距离分别与用户自己的[X,Y]位置相对应,而这些位置是他们事先配置的。

为此,我找到了这种算法,哪种方法有效:

Math.sqrt ( dx * dx + dy * dy );

因为按距离对页面列表进行排序是一件很有用的事情,所以我在MySQL查询中实现了这个算法,并使用SELECT语句的以下部分将它提供给我的应用程序:

SQRT( POW( ( ".strval($sourceX)." - cityX ) , 2 ) + POW( ( ".strval($sourceY)." - cityY ) , 2 ) ) AS distance

这适用于许多计算,但没有考虑[0,0]和[499,499]相互之间的小角落这一事实。

有没有办法我可以调整这个算法来生成一个准确的距离,假设0和499是相邻的?

7 个答案:

答案 0 :(得分:7)

我认为你的意思是包裹坐标而没有球形。就像一张平坦的纸片,其末端神奇地相互连接。

这意味着对于尺寸为500x500的地图,x(或y)方向的距离最多为250.(如果超过250步,我们最好向后走500-x步。)

解决此问题的一种简单方法是

dx = Math.abs(dx);
dy = Math.abs(dy);
if (dx > 250)
  dx = 500 - dx;
if (dy > 250)
  dy = 500 - dy;
distance = Math.sqrt ( dx * dx + dy * dy );

答案 1 :(得分:5)

更新(圆环):

好的,从你自己的评论来看,似乎你意味着圆环 - 圆环的表面 - 而不是球体。 (这是一个很大的区别,你应该编辑你的问题:称它为球体是错误。)

为此,答案相当简单 - 您给出的笛卡尔公式或多或少是正确的。但是,您需要包围距离,以便大于或等于250 = 500/2的任何内容都可以转换为0到250之间。

所以答案是这样的(我根本不懂PHP,因此可能需要修改语法)

dx1 = min(dx, 500-dx)
dy1 = min(dy, 500-dy);
distance = Math.sqrt(dx1*dx1 + dy1*dy1);

(这假设您已将dx和dy定义为差异的绝对值。)

刚刚找到this routine,它在一个包装精美的函数中实现了相同的计算。

原始答案(球体):

你还没有解释你的(x,y)坐标如何映射到球体上的点!

(字面上)有无数个选项,每个选项对应不同的map projection,并且每个选项的公式都不同。请注意,无论您做出何种选择,两个坐标的含义都是非常不同的。

如果您的(x,y)确实是经度和纬度,例如,有很多罐装公式(即,半身),但您必须先将0-> 499转换为0-> 360度经度为-90-> 90度为纬度。 (请注意,lon和lat在球体上的表现非常不同!)

但我强调,你做出的任何选择都会扭曲你在(x,y)中绘制的平面几何形状与它在球体上看起来的方式之间的扭曲。

(最后,如果你的意思是上边缘与底部相同,而右边与左边相同,那么你可能有圆环而不是球体!)

答案 2 :(得分:1)

如果您知道两点的纬度和经度 - 您可以使用haversine formula计算球体上两点之间的距离。

但据我所知,你想要的公式对于几乎对映点来说是准确的。 Haversine配方在这里失败了。在这种情况下,您需要Vincenty's formula,即使在对映情况下也是如此。

http://en.wikipedia.org/wiki/Great-circle_distance#Formulae

答案 3 :(得分:1)

听起来你只是在使用“平铺”的特殊有限笛卡尔空间。在这种情况下,每个对象都没有唯一的位置。对于所有可能的整数值i和j,它代替(x,y)(x + i * w,y + j * h),其中w和h分别是“窗口”的宽度和高度。

显然,距离不是唯一的,但最小距离就是所有i,j的最小距离(d(p1,p2))。

如果您的坐标被包裹,那么您只需要为i = -1,0,1和j = -1,0,1计算它,然后选择最小的坐标。

答案 4 :(得分:0)

这种通用算法适用于直角坐标系或球面坐标中的非常大的距离,但它不适合球面坐标系。

我认为更好的方法是基于纬度和经度,如下所示:

http://jan.ucc.nau.edu/~cvm/latlongdist.html

MySQL内置了地理编码。为什么不使用它?

http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL

答案 5 :(得分:0)

虽然这里的一些答案非常接近,但问题终于通过这个SELECT段解决了:

SQRT( POW( LEAST( ABS($sourceXstr-cityX), ( 500 +LEAST($sourceXstr,cityX)-GREATEST($sourceXstr,cityX))) , 2 ) + POW( LEAST( ABS($sourceYstr-cityY), ( 500 +LEAST($sourceYstr,cityY)-GREATEST($sourceYstr,cityY))) , 2 ) ) AS distance

答案 6 :(得分:0)

如果两个坐标位于二维平面中,我在写答案,其中两端没有相遇,OP没有询问。但它可能在将来帮助某人。

如果您的点位于二维平面中,则点(x1,y1)和(x2,y2)之间的距离由毕达哥拉斯定理给出:

Pythagoras formula

d = squareroot( square(x2 - x1) + square(y2 - y1) )

在PHP中,

$x1 = $y1 = 2;
$x2 = $y2 = 5;
$distance = sqrt( pow(($x2-$x1),2) + pow(($y2-$y1),2) );
echo $distance;              // 4.2426406871193