查指定范围内的街道(基于经纬度)

来源:互联网 发布:淘宝电脑版 编辑:程序博客网 时间:2024/05/01 12:07

一、表结构:

CREATE TABLE `district` (  `id` bigint(20) NOT NULL AUTO_INCREMENT,  `p_id` bigint(20) NOT NULL COMMENT '父ID',  `zipcode` varchar(4) DEFAULT NULL COMMENT '城市编码',  `adcode` varchar(6) NOT NULL DEFAULT '' COMMENT '区域编码',  `name` varchar(64) NOT NULL DEFAULT '' COMMENT '行政区名称',  `center` varchar(30) NOT NULL DEFAULT '' COMMENT '城市中心点',  `lon` double(9,6) NOT NULL COMMENT '经度',  `lat` double(8,6) NOT NULL COMMENT '维度',  `geo_code` varchar(12) DEFAULT NULL COMMENT 'geohash编码',  `level` varchar(10) NOT NULL DEFAULT '' COMMENT '取值:province省份,city市,district区县,street街道',  `area` text COMMENT '街道覆盖域',  PRIMARY KEY (`id`),  KEY `p_id` (`p_id`) USING BTREE,  KEY `zipcode` (`zipcode`) USING BTREE,  KEY `adcode` (`adcode`) USING BTREE,  KEY `name` (`name`) USING BTREE,  KEY `level` (`level`) USING BTREE,  KEY `lon` (`lon`) USING BTREE,  KEY `lat` (`lat`) USING BTREE,  KEY `geo_code` (`geo_code`) USING BTREE) ENGINE=InnoDB AUTO_INCREMENT=51264 DEFAULT CHARSET=utf8mb4 COMMENT='行政区域';


二、引入jar包

<dependency><groupId>com.spatial4j</groupId><artifactId>spatial4j</artifactId><version>0.5</version></dependency><dependency><groupId>ch.hsr</groupId><artifactId>geohash</artifactId><version>1.3.0</version></dependency>
三、Java代码

    /**     * 方法一,查询指定范围内的所有街道(区间查找)     * @return     */    public List<District> findNearbyDistrictByRadius(Double lon, Double lat, int radius){        SpatialContext geo = SpatialContext.GEO;        Rectangle rectangle = geo.getDistCalc().calcBoxByDistFromPt(geo.makePoint(lon, lat), radius * DistanceUtils.KM_TO_DEG, geo, null);        double minX = rectangle.getMinX();        double maxX = rectangle.getMaxX();        double minY = rectangle.getMinY();        double maxY = rectangle.getMaxY();        LOGGER.info(minX + " - " + maxX);   // 经度范围        LOGGER.info(minY + " - " + maxY);   // 纬度范围        String sql = "select * from district where (lon BETWEEN ? AND ?) AND (lat BETWEEN ? AND ?) and level = 'street' ";        List<District> districtList = dao.find(sql, minX, maxX, minY, maxY);        LOGGER.info("districtList1={}", JSON.toJSONString(districtList));        //按照距离排序        Collections.sort(districtList, new DistrictComparator(lon, lat));        return districtList;    }    /**     * 方法二,查询指定范围内的所有街道(geohash查找)     * @param lon     * @param lat     * @return     */    public List<District> findNearbyDistrictByRadius2(Double lon, Double lat, int geohashLength){        String geoCode = GeohashUtils.encodeLatLon(lat, lon, geohashLength);    //1公里        LOGGER.info("geoCode={}", geoCode);        StringBuilder sql = new StringBuilder("select * from district where ");        GeoHash geoHash = GeoHash.withCharacterPrecision(lat, lon, geohashLength);        // 当前        sql.append(" geo_code LIKE CONCAT('" + geoHash.toBase32() + "', '%') ");        // N, NE, E, SE, S, SW, W, NW        GeoHash[] adjacent = geoHash.getAdjacent();        for (GeoHash hash : adjacent) {            sql.append("or geo_code LIKE CONCAT('" + hash.toBase32() +"', '%') ");        }        LOGGER.info("sql={}", sql.toString());        List<District> districtList = dao.find(sql.toString());        LOGGER.info("districtList2={}", JSON.toJSONString(districtList));        //按照距离排序        Collections.sort(districtList, new DistrictComparator(lon, lat));        return districtList;    }
    /**     * 按照距离远近排序     */    class DistrictComparator implements Comparator<District>{        private SpatialContext geo = SpatialContext.GEO;        private Double centerLon;   //中心点经度        private Double centerLat;   //中心点纬度        public DistrictComparator(Double centerLon, Double centerLat) {            this.centerLon = centerLon;            this.centerLat = centerLat;        }        @Override        public int compare(District o1, District o2) {            double o1Distance = geo.calcDistance(geo.makePoint(o1.getDouble("lon"), o1.getDouble("lat")), geo.makePoint(centerLon, centerLat)) * DistanceUtils.DEG_TO_KM;            o1.put("distance", o1Distance);            double o2Distance = geo.calcDistance(geo.makePoint(o2.getDouble("lon"), o2.getDouble("lat")), geo.makePoint(centerLon, centerLat)) * DistanceUtils.DEG_TO_KM;            o2.put("distance", o2Distance);            if(o1Distance < o2Distance){                return -1;            }else if(o1Distance > o2Distance){                return 1;            }else{                return 0;            }        }    }




原创粉丝点击