给定一个坐标和一个距离,查询数据库所有在这个范围的商店。
首先计算在这个范围的四个点,这四个点链接成一个正方形这个范围相切。
double minlat = 0;//定义经纬度四个极限值。 double maxlat = 0; double minlng = 0; double maxlng = 0; //我数据保存的经纬度是string,所以要转一下类型方便计算距离。 shopParam是传参。 double longitude = Double.parseDouble(shopParam.getLongitude()); double latitude = Double.parseDouble(shopParam.getLatitude()); // 先计算查询点的经纬度范围 double r = 6371;// 地球半径千米 double dis = 20;// 距离(单位:千米),查询范围 20km内的所有商铺 double dlng = 2 * Math.asin(Math.sin(dis / (2 * r)) / Math.cos(longitude * Math.PI / 180)); dlng = dlng * 180 / Math.PI;// 角度转为弧度 double dlat = dis / r; dlat = dlat * 180 / Math.PI; if (dlng < 0) { minlng = longitude + dlng;//拿到最大经度和最小经度 maxlng = longitude - dlng; } else { minlng = longitude - dlng; maxlng = longitude + dlng; } if (dlat < 0) { minlat = latitude + dlat;//拿到最大纬度和最小纬度 maxlat = latitude - dlat; } else { minlat = latitude - dlat; maxlat = latitude + dlat; } log.info("最大经度:{},最小经度:{}",maxlng,minlng); log.info("最大纬度:{},最小纬度:{}",maxlat,minlat); final List<Shop> shops = Lists.newArrayList();//定义一个空 list保存范围内的店铺 final List<Shop> shopList = shopMapper.selectNearShopList();//查询所有商铺 for (Shop shop:shopList) { double _long = Double.parseDouble(shop.getLongitude());//拿到店铺的坐标,判断是否在这个范围内 double _lat = Double.parseDouble(shop.getLatitude()); if (_long >= minlng && _long <= maxlng && _lat >= minlat && _lat <= maxlat){ shops.add(shop);//将在这个范围内的店铺添加到一个空list中。 } } Map<Shop,Double> map = new HashMap<Shop, Double>();//定义一个空的map存储店铺 //计算范围内每个店铺距离给定坐标的距离 for (Shop _shop:shops) { Double distance = LocationUtils.getDistance(Double.parseDouble(_shop.getLatitude()),Double.parseDouble(_shop.getLongitude()),latitude,longitude); log.info("店铺名称:{},经度:{},纬度:{},距离:{}",_shop.getShopName(),_shop.getLongitude(),_shop.getLatitude(),distance); map.put(_shop,distance);//将计算出来的距离作为value,该店铺作为key } final List<Shop> list = Lists.newArrayList();//存储排序之后的店铺 //这里使用Java8的map根据value排序,距离最近排序,按value排序,升序 Map<Shop,Double> doubleMap = map .entrySet() .stream() .sorted(comparingByValue()) .collect( toMap(e -> e.getKey(), e -> e.getValue(), (e1, e2) -> e2, LinkedHashMap::new)); for (Map.Entry<Shop, Double> entry:doubleMap.entrySet()) { list.add(entry.getKey());//循环map拿到key并保存到list中。 }
下面这个是上述代码中用到的LocationUtils工具类
public class LocationUtils { private static double EARTH_RADIUS = 6378.137; private static double rad(double d) { return d * Math.PI / 180.0; } /** * 通过经纬度获取距离(单位:米) * @param lat1 * @param lng1 * @param lat2 * @param lng2 * @return */ public static double getDistance(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 * 10000d) / 10000d; s = s*1000; return s; } }这个方法是用纯Java语言实现,只是方便用来学习的,真正的企业项目不建议使用,如果数据量较小可以使用。数据量过大可以使用sql语句实现,这里就不赘述了,不同公司使用的算法各不相同。如果有什么错误欢迎留言指正,也可私信给我,欢迎转载记得贴上出处 (。 ◕ ˇ ∀ ˇ ◕)。