当前位置: 首页 > 工具软件 > Spatial4J > 使用案例 >

JAVA经纬度距离计算并排序-Spatial4j+ForkJoin

扈昀
2023-12-01

Spatial4j+ForkJoin 实现经纬度距离计算并排序

maven

<dependency>
	<groupId>com.spatial4j</groupId>
	<artifactId>spatial4j</artifactId>
	<version>0.5</version>
</dependency>

Spatial4j工具类

import com.spatial4j.core.context.SpatialContext;
import com.spatial4j.core.distance.DistanceUtils;
import com.spatial4j.core.shape.Rectangle;

/**
 * java类简单作用描述
 *
 * @Package: cn.fulong.bjwalk.findhome.util
 * @Author: yu_du_chen
 * @CreateDate: 2020/8/29 10:43
 * @Version: 1.0
 */
public class spatial {
    // 移动设备经纬度
    private double lon;
    private double lat;
    //千米
    final private static int radius = 16;

    public spatial() {
        this(116.311777,40.035986);
    }

    public spatial(double lon, double lat) {
        this.lon = lon;
        this.lat = lat;
        System.out.println("配置加载");
    }

    /**根据设置的范围 检索*/
    public void xyRange(){
        System.out.println(lon);
        System.out.println(lat);
        SpatialContext geo = SpatialContext.GEO;
        Rectangle rectangle = geo.getDistCalc().calcBoxByDistFromPt(
                geo.makePoint(lon, lat), radius * DistanceUtils.KM_TO_DEG, geo, null);
        System.out.println(rectangle.getMinX() + "-" + rectangle.getMaxX());// 经度范围
        System.out.println(rectangle.getMinY() + "-" + rectangle.getMaxY());// 纬度范围
    }

    /**商户经纬度和当前经纬度距离,传入商户经纬度*/
    public double xyDistance(double lon2,double lat2){
        SpatialContext geo = SpatialContext.GEO;
        double distance = geo.calcDistance(geo.makePoint(lon, lat), geo.makePoint(lon2, lat2))
                * DistanceUtils.DEG_TO_KM;
        return distance;
    }

    public static void main(String[] args) {
        spatial A = new spatial();
        A.xyRange();
        A.xyDistance(116.426612,39.905184);//北京站地铁站-A口
    }
}

ForkJoin工具类

ForkJoin的用法可参考 : ForkJoin

import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.RecursiveTask;

/**
 * ForkJoin 多任务
 * @ProjectName: utils
 * @Package: cn.fulong.web.forkjoin
 * @Author: yu_du_chen
 * @CreateDate: 2019/9/10 16:26
 * @Version: 1.0
 */
@Component
public class ForkJoin{
    /**
     * 单个排序的子任务
     */
    public static class MyTask  extends RecursiveTask<CopyOnWriteArrayList> {

        private CopyOnWriteArrayList<Map<String, Object>> maps;
        private spatial A;
        public MyTask(List<Map<String, Object>> maps,spatial A) {
            this.maps = new CopyOnWriteArrayList(maps);
            this.A = A;
        }

        /* (non-Javadoc)
         * @see java.util.concurrent.RecursiveTask#compute()
         */
        @Override
        protected CopyOnWriteArrayList compute() {
            int sourceLen = maps.size();

            if(sourceLen > 1) {
                int midIndex = sourceLen / 2;
                // 拆分成两个子任务
                MyTask task1 = new MyTask(maps.subList(0, midIndex),A);
                task1.fork();
                MyTask task2 = new MyTask(maps.subList(midIndex, sourceLen),A);
                task2.fork();
                // 结果集合并
                CopyOnWriteArrayList list1 = task1.join();
                CopyOnWriteArrayList list2 = task2.join();
                list1.addAll(list2);
                return list1;
            }else {
                double a = A.xyDistance(Double.parseDouble(maps.get(0).get("position_x").toString()),Double.parseDouble(maps.get(0).get("position_y").toString()));
                //计算出的距离反存入 list
                maps.get(0).put("distance",a);
                return maps;
            }
        }
    }

}

实际用法(impl)

 /*per 分页、school查询参数、x/y移动设备当前经纬度、sortFlag升序/降序*/
 @Override
    public Map<String, Object> getCloudClassList(Integer per, School school, Double x, Double y, boolean sortFlag) {
        //MyBatis-Plus的查询用法
        IPage<School> iPage = new Page<>(Optional.ofNullable(per).orElse(0), FindConstants.SchollList);
        IPage<Map<String, Object>> list = schoolMapper.selectMapsPage(iPage,Wrappers.<School>lambdaQuery()
                .like(IsNotNull.get(school.getSchoolName()),School::getSchoolName, school.getSchoolName())
                .eq(IsNotNull.get(school.getId()),School::getId, school.getId())
                .eq(true,School::getFlag, "1"));

        System.out.println("总页数:" + list.getPages());
        System.out.println("总数:" + list.getTotal());
        System.out.println("页数:" + list.getSize());
        System.out.println("页码:" + list.getCurrent());

		//业务需求 前端需要这些参数 放入map中
		//list.getRecords() 查询出的所有学校数据
        Map<String, Object> map = new LinkedHashMap();
        map.put("pages",list.getPages());
        map.put("total",list.getTotal());
        map.put("size",list.getSize());
        map.put("current",list.getCurrent());
		
		//IsNotNull 自封装的判空方法 后面会给出文章链接
        if(IsNotNull.get(list.getRecords())){
             /*开启任务*/
             /*方法实现的是:通过spatial4j计算出 list每条数据距离当前移动设备的距离(distance)反存入list,
             并且按照distance排序*/
            ForkJoinPool pool = new ForkJoinPool();
            ForkJoin.MyTask task = new ForkJoin.MyTask(list.getRecords(),new spatial(x,y));
            ForkJoinTask<CopyOnWriteArrayList> index = pool.submit(task);
            try {
                CopyOnWriteArrayList<Map<String, Object>> m = index.get();
                //通过distance排序  具体用法 参考java1.8 stream().sorted 这里不做过多解释
                List<Map<String, Object>> nameList = m.stream().sorted((a,b)  -> getCollect(sortFlag,a,b)).collect(Collectors.toList());
                Map<String, Object> map1 = new LinkedHashMap();
                map1.put("data",nameList);
                map1.put("ipage",map);
                return map1;
            } catch (Exception  e) {
                e.printStackTrace(System.out);
            }
        }
        return null;
    }
    
	private int getCollect(boolean sortFlag, Map<String, Object> a, Map<String, Object> b){
        if(sortFlag){
            if (b.get("distance").toString().equals(a.get("distance").toString())) {
                return b.get("id").toString().compareTo(a.get("id").toString());
            }else {
                return new BigDecimal(b.get("distance").toString()).compareTo(new BigDecimal(a.get("distance").toString()));
            }
        }else{
            if (a.get("distance").toString().equals(b.get("distance").toString())) {
                return a.get("id").toString().compareTo(b.get("id").toString());
            }else {
                return new BigDecimal(a.get("distance").toString()).compareTo(new BigDecimal(b.get("distance").toString()));
            }
        }
    }
 类似资料: