发布于 

根据一个经纬度查询附近的楼盘信息

最近做一个项目,需要查询一个门店3公里范围内的所有楼盘信息

实现原理

先算出该点周围的矩形的四个点,然后使用经纬度去直接匹配数据库中的记录。

java代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/**
* 根据传入的经纬度和半径范围确定附近的经纬度范围
*
* @param longitude 经度
* @param latitude 纬度
* @param distance 距离 多少千米
* @return
*/
public static Location getNearbyLocation(double longitude, double latitude, double distance) {

boolean b = LocationUtil.checkItude(longitude + "", latitude + "");

if (!b) {
return null;
}

//先计算查询点的经纬度范围
double r = 6371;//地球半径千米
double dlng = 2 * Math.asin(Math.sin(distance / (2 * r)) / Math.cos(latitude * Math.PI / 180));
dlng = dlng * 180 / Math.PI;//角度转为弧度
double dlat = distance / r;
dlat = dlat * 180 / Math.PI;
double minlat = latitude - dlat;
double maxlat = latitude + dlat;
double minlng = longitude - dlng;
double maxlng = longitude + dlng;

Location location = new Location();
location.setLatitude(latitude);
location.setLongitude(longitude);
location.setMaxLatitude(maxlat + "");
location.setMinLatitude(minlat + "");
location.setMaxLongitude(maxlng + "");
location.setMinLongitude(minlng + "");
return location;
}

经纬度格式校验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 经纬度校验
* 经度longitude: (?:[0-9]|[1-9][0-9]|1[0-7][0-9]|180)\\.([0-9]{6})
* 纬度latitude: (?:[0-9]|[1-8][0-9]|90)\\.([0-9]{6})
*
* @return
*/
public static boolean checkItude(String longitude, String latitude) {
String reglo = "((?:[0-9]|[1-9][0-9]|1[0-7][0-9])\\.([0-9]{0,6}))|((?:180)\\.([0]{0,6}))";
String regla = "((?:[0-9]|[1-8][0-9])\\.([0-9]{0,6}))|((?:90)\\.([0]{0,6}))";
longitude = longitude.trim();
latitude = latitude.trim();
return longitude.matches(reglo) == true ? latitude.matches(regla) : false;
}

求两点之间的距离

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* 求两点之间的距离
* @param lng1 A点经度
* @param lat1 A点纬度
* @param lng2 B点经度
* @param lat2 B点纬度
* @return 两点距离
*/
public static double getDistance(double lng1, double lat1, double lng2, double lat2) {
double EARTH_RADIUS = 6371;
double radiansAX = Math.toRadians(lng1); // A经弧度
double radiansAY = Math.toRadians(lat1); // A纬弧度
double radiansBX = Math.toRadians(lng2); // B经弧度
double radiansBY = Math.toRadians(lat2); // B纬弧度

// 公式中“cosβ1cosβ2cos(α1-α2)+sinβ1sinβ2”的部分,得到∠AOB的cos值
double cos = Math.cos(radiansAY) * Math.cos(radiansBY) * Math.cos(radiansAX - radiansBX)
+ Math.sin(radiansAY) * Math.sin(radiansBY);
double acos = Math.acos(cos); // 反余弦值
return EARTH_RADIUS * acos; // 最终结果
}

拿到4个确定范围的经纬度就可以去数据库查询了,由于数据库经纬度存的是一个字段需要切割下字段(使用的是Mysql),在 原本的条件下拼接上范围条件就完成!

条件sql

1
2
3
4
substring( location, 1, LOCATE ( ',', location ) - 1 ) >= #{minLongitude}
AND substring( location, 1, LOCATE ( ',', location ) - 1 ) <= #{maxLongitude}
AND substring( location, LOCATE ( ',', location ) + 1, LENGTH ( a.location ) - 1 ) >= #{minLatitude}
AND substring( location, LOCATE ( ',', location ) + 1, LENGTH ( a.location ) - 1 ) <= #{maxLatitude}

得到的结果进行比较删除

因为得到的结果是个正方形方位内的数据,想要在地图上显示,会发现超过了地图上圆圈外也有数据,这时候就需要再做一下处理。

1
2
3
4
5
6
7
8
9
//判断两点之间的距离是否大于半径,大于的删除
for (int i = 0; i < 之前查询结果的len; i++) {
double distance = LocationUtil.getDistance(longitude, latitude, longitude1, latitude1);
if (distance > kilometer) {
list.remove(i);
i--;
len--;
}
}

处理之后不不会出现全外面数据显示的情况了!


本站由 @binvv 使用 Stellar 主题创建。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。