获取地球上两个坐标之间的距离
Get distance between 2 coordinates on globe
我尝试使用 here
中的公式计算两个坐标之间的距离
坐标为1.5378236000、110.3372347000和1.5395056000、110.3373156000。
不知何故,结果大不相同。我相信 "dist1" 在 KM 中,但不确定 "dist2"。
select 6371 * acos( cos( radians(1.5378236000) ) * cos( radians( 1.5395056000 ) ) *
cos( radians( 1.5378236000 ) - radians(110.3373156000) )
+ sin( radians(1.5378236000) ) * sin( radians( 1.5395056000 ) ) ) AS dis1,
GetDistance(1.5378236000, 110.3372347000, 1.5395056000, 110.3373156000) as dis2
结果
dist1: 12091.536526805385
dist2: 0.11190
获取距离函数
CREATE DEFINER=`root`@`localhost` FUNCTION `GetDistance`(
lat1 numeric (9,6),
lon1 numeric (9,6),
lat2 numeric (9,6),
lon2 numeric (9,6)
) RETURNS decimal(10,5)
READS SQL DATA
BEGIN
/* http://www.codecodex.com/wiki/Calculate_distance_between_two_points_on_a_globe#MySQL */
DECLARE x decimal (20,10);
DECLARE pi decimal (21,20);
SET pi = 3.14159265358979323846;
SET x = sin( lat1 * pi/180 ) * sin( lat2 * pi/180 ) + cos(
lat1 *pi/180 ) * cos( lat2 * pi/180 ) * cos( abs( (lon2 * pi/180) -
(lon1 *pi/180) ) );
SET x = acos( x );
RETURN ( 1.852 * 60.0 * ((x/pi)*180) ) / 1.609344;
END
第一个函数获取长距离(如果你绕地球走很远的距离)
第二个是抄近路的距离。
看那两个点,离的很近。这就像环游世界只是为了过马路。 :D
第二个距离仍然以公里为单位,只是很短。地球的周长刚刚超过 12,000 公里。
这是准确的方法
public static double elongation(double longitude1, double latitude1,
double longitude2, double latitude2)
{
return Math.Acos(1 - 2 * (hav(latitude1 - latitude2)
+ Math.Cos(RAD * latitude1) * math.Cos(RAD * latitude2)
* hav(longitude1 - longitude2))) / RAD;
}
当函数 "hav" 为
static public double hav(double x)
{
return 0.5 - 0.5 * Math.Cos(RAD * x);
}
你的第一个表达式有错误。您正在计算纬度和经度之间差异的余弦值。在那个术语中,您应该计算起始经度和结束经度之间的差异。
用于计算纬度和经度点对之间距离的余弦定律(或半正弦)公式是这样的:
DEGREES(ACOS(COS(RADIANS(lat1)) * COS(RADIANS(lat2)) *
COS(RADIANS(long1) - RADIANS(long2)) +
SIN(RADIANS(lat1)) * SIN(RADIANS(lat2))))
这会产生以度为单位的结果。
你问题中的第一个表达式采用这种形式。如您所见,您的公式正确,但您插入的参数不正确。
6371 * acos( cos( radians(lat1)) * cos( radians( long1 )) * /*should be lat1, lat 2*/
cos( radians( lat1) - radians(long1 )) /*should be long1,long2*/
sin( radians(lat1) ) * sin( radians(long2 ))) /*should be lat1, lat2 */
您的第一个点似乎位于马来西亚古晋,就在 Green 街和 Ahmad Zaidi 街交界处的南边。第二点是那里以北的一个街区。 (根据你的第二个结果,它在北边大约 112m)。请注意,我编写的距离公式以弧度为单位。你给它 lat/long 度数点,它 returns 度数距离。为了将度数转换为千米(一种更有用的测量方法),您需要知道每度有多少千米。
请注意,您的公式版本包含幻数 6371。这会将 ACOS()
函数产生的弧度转换为度数,然后转换为千米,使用常数 111.195 公里/度。这是一个可接受的值;地球在赤道处有点凸起。
此外,您的存储函数在同一术语中有一个不必要的 ABS。由于十进制运算,它的效率也非常低。 MySQL 使用 DOUBLE(ieee 64 位浮点数)算法进行所有计算,但它的编码方式需要大量浪费且可能会丢失精度的来回十进制转换。
如果您使用的是商业级 GPS 坐标,32 位 FLOAT 算法就足够精确了。
这是对此 material 的详尽解释。 http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc/
我尝试使用 here
中的公式计算两个坐标之间的距离坐标为1.5378236000、110.3372347000和1.5395056000、110.3373156000。
不知何故,结果大不相同。我相信 "dist1" 在 KM 中,但不确定 "dist2"。
select 6371 * acos( cos( radians(1.5378236000) ) * cos( radians( 1.5395056000 ) ) *
cos( radians( 1.5378236000 ) - radians(110.3373156000) )
+ sin( radians(1.5378236000) ) * sin( radians( 1.5395056000 ) ) ) AS dis1,
GetDistance(1.5378236000, 110.3372347000, 1.5395056000, 110.3373156000) as dis2
结果
dist1: 12091.536526805385
dist2: 0.11190
获取距离函数
CREATE DEFINER=`root`@`localhost` FUNCTION `GetDistance`(
lat1 numeric (9,6),
lon1 numeric (9,6),
lat2 numeric (9,6),
lon2 numeric (9,6)
) RETURNS decimal(10,5)
READS SQL DATA
BEGIN
/* http://www.codecodex.com/wiki/Calculate_distance_between_two_points_on_a_globe#MySQL */
DECLARE x decimal (20,10);
DECLARE pi decimal (21,20);
SET pi = 3.14159265358979323846;
SET x = sin( lat1 * pi/180 ) * sin( lat2 * pi/180 ) + cos(
lat1 *pi/180 ) * cos( lat2 * pi/180 ) * cos( abs( (lon2 * pi/180) -
(lon1 *pi/180) ) );
SET x = acos( x );
RETURN ( 1.852 * 60.0 * ((x/pi)*180) ) / 1.609344;
END
第一个函数获取长距离(如果你绕地球走很远的距离)
第二个是抄近路的距离。
看那两个点,离的很近。这就像环游世界只是为了过马路。 :D
第二个距离仍然以公里为单位,只是很短。地球的周长刚刚超过 12,000 公里。
这是准确的方法
public static double elongation(double longitude1, double latitude1,
double longitude2, double latitude2)
{
return Math.Acos(1 - 2 * (hav(latitude1 - latitude2)
+ Math.Cos(RAD * latitude1) * math.Cos(RAD * latitude2)
* hav(longitude1 - longitude2))) / RAD;
}
当函数 "hav" 为
static public double hav(double x)
{
return 0.5 - 0.5 * Math.Cos(RAD * x);
}
你的第一个表达式有错误。您正在计算纬度和经度之间差异的余弦值。在那个术语中,您应该计算起始经度和结束经度之间的差异。
用于计算纬度和经度点对之间距离的余弦定律(或半正弦)公式是这样的:
DEGREES(ACOS(COS(RADIANS(lat1)) * COS(RADIANS(lat2)) *
COS(RADIANS(long1) - RADIANS(long2)) +
SIN(RADIANS(lat1)) * SIN(RADIANS(lat2))))
这会产生以度为单位的结果。
你问题中的第一个表达式采用这种形式。如您所见,您的公式正确,但您插入的参数不正确。
6371 * acos( cos( radians(lat1)) * cos( radians( long1 )) * /*should be lat1, lat 2*/
cos( radians( lat1) - radians(long1 )) /*should be long1,long2*/
sin( radians(lat1) ) * sin( radians(long2 ))) /*should be lat1, lat2 */
您的第一个点似乎位于马来西亚古晋,就在 Green 街和 Ahmad Zaidi 街交界处的南边。第二点是那里以北的一个街区。 (根据你的第二个结果,它在北边大约 112m)。请注意,我编写的距离公式以弧度为单位。你给它 lat/long 度数点,它 returns 度数距离。为了将度数转换为千米(一种更有用的测量方法),您需要知道每度有多少千米。
请注意,您的公式版本包含幻数 6371。这会将 ACOS()
函数产生的弧度转换为度数,然后转换为千米,使用常数 111.195 公里/度。这是一个可接受的值;地球在赤道处有点凸起。
此外,您的存储函数在同一术语中有一个不必要的 ABS。由于十进制运算,它的效率也非常低。 MySQL 使用 DOUBLE(ieee 64 位浮点数)算法进行所有计算,但它的编码方式需要大量浪费且可能会丢失精度的来回十进制转换。
如果您使用的是商业级 GPS 坐标,32 位 FLOAT 算法就足够精确了。
这是对此 material 的详尽解释。 http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc/