获取距离某坐标附近一定范围内的点的两种方式
场景:数据库中有一些点坐标,需要查找出距离当前位置2千米范围内的坐标
方式1:根据两个经纬度计算距离,Oracle/MySql计算地表两点之间的距离:
Oracle:
- 创建获取弧度的函数:
CREATE OR REPLACe FUNCTION RAD(d number) RETURN NUMBER
is
PI number :=3.141592625;
begin
return d* PI/180.0;
end ;
- 创建根据两个坐标计算距离的函数
CREATE OR REPLACE FUNCTION GetDistance(LngBegin number,
LatBegin number,
LngEnd number,
LatEnd number) RETURN NUMBER is
earth_padius number := 6378.137;
radLat1 number := rad(LngBegin);
radLat2 number := rad(LngEnd);
a number := radLat1 - radLat2;
b number := rad(LatBegin) - rad(LatEnd);
s number := 0;
begin
s := 2 *
Asin(Sqrt(power(sin(a / 2), 2) +
cos(radLat1) * cos(radLat2) * power(sin(b / 2), 2)));
s := s * earth_padius;
s := Round(s * 10000)/10;
return s;
end;
- 查询距离
SELECT
GetDistance(#{lon},#{lat},SHOP_LON,SHOP_LAT) AS Mdistance
FROM Shop
MySql:
查询距离sql:
SELECt
ROUND( 6378.138 * 2 * ASIN( SQRT( POW( SIN(( #{lat} * PI() / 180 - SHOP_LAT * PI() / 180) / 2 ),
2 ) + COS(#{lat} * PI() / 180) * COS(SHOP_LAT * PI() / 180) * POW( SIN( ( #{lon} * PI() / 180 - SHOP_LON * PI() / 180 ) / 2 ),
2 ) ) ) * 1000 ) AS Mdistance
FROM Shop
当然,也可将计算方法封装为函数
拿到距离后根据条件取值,因为是sql查询,若数据量大时,效率是一个问题
方式2:根据经纬度和距离计算出矩形范围,取范围内的值:
- 提供工具类如下:
public class GeoUtil
{
private static double EARTH_RADIUS = 6378.137;
public static double[] getRectangle(double lng, double lat, long distance)
{
float delta = 111000;
if (lng != 0 && lat != 0)
{
double lng1 = lng - distance / Math.abs(Math.cos(Math.toRadians(lat)) * delta);
double lng2 = lng + distance / Math.abs(Math.cos(Math.toRadians(lat)) * delta);
double lat1 = lat - (distance / delta);
double lat2 = lat + (distance / delta);
return new double[] {lng1, lat1, lng2, lat2};
}
else
{
double lng1 = lng - distance / delta;
double lng2 = lng + distance / delta;
double lat1 = lat - (distance / delta);
double lat2 = lat + (distance / delta);
return new double[] {lng1, lat1, lng2, lat2};
}
}
public static double getDistanceOfMeter(double lat1, double lng1, double lat2, double lng2)
{
double radLat1 = rad(lat1);
double radLat2 = rad(lat2);
double a = radLat1 - radLat2;
double b = rad(lng1) - rad(lng2);
double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
s = s * EARTH_RADIUS;
s = Math.round(s * 10000) / 10;
return s;
}
private static double rad(double d)
{
return d * Math.PI / 180.0;
}
}