Mysql 经纬度范围查询
Mysql 经纬度范围查询
给定经纬度与半径(距离)查询范围内的数据?
方案一:Mysql + 外接正方形
实现思路:
以当前经纬度为圆心,以给定距离为半径画圆,那么在这个圆内的所有用户信息就是符合结果的信息,直接检索圆内的用户坐标难以实现,我们可以通过获取这个圆的外接正方形。
通过外接正方形,获取经度和纬度的最大最小值,根据最大最小值可以将坐标在正方形内的用户信息搜索出来。
此时在外接正方形中不属于圆形区域的部分就属于多余的部分,这部分用户信息距离当前用户(圆心)的距离必定是大于给定半径的,故可以将其剔除,最终获得指定范围内的附近的人。

工具类:
public class GeoUtils {
//地球半径(米)
private static final double EARTH_RADIUS = 6371000d;
//弧度
public static final double RADIANS_TO_DEGREES = 180 / Math.PI;
public static final double DEGREES_TO_RADIANS = Math.PI / 180;
/**
* 根据中心点经纬度,计算半径范围内的最大、最小经纬度范围
*
* @param centerLon 中心点经度
* @param centerLat 中心点纬度
* @param dist 半径范围(米)
* @return
*/
public static Map<String, Double> findPosition(double centerLon, double centerLat, double dist) {
//先计算查询点的经纬度范围
double lonRad = 2 * Math.asin(Math.sin(dist / (2 * EARTH_RADIUS)) / Math.cos(centerLat * Math.PI / 180));
//角度转为弧度
lonRad = lonRad * RADIANS_TO_DEGREES;
double latRad = dist / EARTH_RADIUS;
latRad = latRad * 180 / Math.PI;
//经度最小值
double minLon = centerLon - lonRad;
//经度最大值
double maxLon = centerLon + lonRad;
//纬度最小值
double minLat = centerLat - latRad;
//纬度最大值
double maxLat = centerLat + latRad;
HashMap<String, Double> geoMap = new HashMap<>();
geoMap.put("minLat", minLat);
geoMap.put("maxLat", maxLat);
geoMap.put("minLon", minLon);
geoMap.put("maxLon", maxLon);
return geoMap;
}
/**
* 求地球表面两点间的距离
*
* @param centerLon 中心点经度
* @param centerLat 中心点纬度
* @param targetLon 目标经度
* @param targetLat 目标纬度
* @return
*/
public static double getDistance(double centerLon, double centerLat, double targetLon, double targetLat) {
//计算中心点经纬度弧度
double centerLonRad = centerLon * DEGREES_TO_RADIANS;
double centerLatRad = centerLat * DEGREES_TO_RADIANS;
//计算目标点经纬度弧度
double targetLonRad = targetLon * DEGREES_TO_RADIANS;
double targetLatRad = targetLat * DEGREES_TO_RADIANS;
//计算经纬度的差
double diffX = Math.abs(centerLonRad - targetLonRad);
double diffY = Math.abs(centerLatRad - targetLatRad);
//计算正弦
double hsinX = Math.sin(diffX / 2);
double hsinY = Math.sin(diffY / 2);
//计算余弦
double centerLatRad_cos = Math.cos(centerLatRad);
double targetLatRad_cos = Math.cos(targetLatRad);
double h = power(hsinY, 2) + (centerLatRad_cos * targetLatRad_cos * power(hsinX, 2));
//两点的距离
double dist = EARTH_RADIUS * 2 * Math.atan2(Math.sqrt(h), Math.sqrt(1 - h));
return dist;
}
/**
* 经纬度剔除小数点(直接剔除不舍入),保留6位
*
* @param number 经度/纬度
* @return
*/
public static Double geoRound6Pla(Double number) {
BigDecimal numDigd = new BigDecimal(number);
number = numDigd.setScale(6, BigDecimal.ROUND_DOWN).doubleValue();
return number;
}
public static void main(String[] args) {
//中心点经纬度
double x1 = 102.604646;
double y1 = 24.239485;
//目标点经纬度
double x2 = 103.634895;
double y2 = 24.778173;
Map<String, Double> position = GeoUtils.findPosition(x1, y1, 130000 );
double distance = GeoUtils.getDistance(x1, y1, x2, y2);
System.out.println(position);
System.out.println(distance);
}
}
方案二:mysql自带函数st_distance()查询两个经纬度点的距离。 st_distance 为mysql5.6+版本中开始自带的经纬度计算函数。
st_distance 计算的结果单位是度,需要乘111195(地球半径6371000*3.1415926/180)是将值转化为米。
SELECT
u.user_name,
u.position_lng,
u.position_lat,
(st_distance (point (u.position_lng, u.position_lat), point(113.210411, 23.122771) ) * 111195) AS distance
FROM
user AS u
HAVING distance < 5000
ORDER BY distance

浙公网安备 33010602011771号