定位当前位置(坐标点)到 附近多个位置(坐标点)最短路径动态规划(汉密尔顿回路算法整合百度地图API)

      最近项目中需要实现这样一个功能:从当前位置,规划一条最优线路到附近多个工厂的最优线路。必须要有详细的路径坐标点信息。

     思路:1.首先 使用汉密尔顿回路算法,求解出当前位置坐标点到附近工厂最短线路的路径。2.借助百度地图API,实现2点间坐标点的详细路径。话不多说,直接整代码:

项目使用的框架是springboot: 参数path格式为:40.465,116.314|40.232,116.352|40.121,116.453|41.121,118.453  经纬度直接用“,”隔开,2个坐标点之间用"|"隔开。这样做的目的是方便前端传值与后台取值。

@GetMapping("/dynamicProgramming")
public AjaxResult dynamicProgramming(HttpServletRequest request,
                                     @RequestParam("path") String path) throws Exception{
    //所有经纬度数组
    String[] strings = path.split("\\|");

    double  [] x = new double[strings.length];
    double [] y = new double[strings.length];
    for (int i = 0; i < strings.length; i++) {
        String str = strings[i];
        String latitude = str.substring(0, str.indexOf(","));
        String longitude = str.substring(str.lastIndexOf(",") + 1);
        x[i] = Double.parseDouble(latitude);
        y[i] = Double.parseDouble(longitude);

    }
    //汉密尔顿回路算法求解最短路线的最优路线
    List<Integer> sort = DynamicProgramming.sort(x, y, strings.length);;

    List<Map> list = new ArrayList<>();

    //将返回的规划路线分段调用百度地图api,获取详细坐标
    for (int i = 0; i < sort.size()-1; i++) {
        Map<String, Object> steps = new HashMap<>();
        int qidian = sort.get(i);
        int zongdian = sort.get(i+1);
        //出发地
        String origin = strings[qidian-1];
        //目的地
        String destination = strings[zongdian-1];
        //调用百度地图驾车路线api生成具体路径

        String url = " http://api.map.baidu.com/directionlite/v1/driving?" +
                "origin="+origin+"&destination="+destination+
                "&ak="+baiduAk;

        String result = BaiduHttpUtils.httpGet(url);
        List<Map> maps = BaiduHttpUtils.getResult(result);
        steps.put("step",maps);
        list.add(steps);

    }


    return success(list);
}

算法工具类:DynamicProgramming

package com.chaosting.kiwifruit.web.utils.weixin;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author: zhangweixia
 * @Description:  汉密尔顿回路算法最短路径动态规划
 * @Date:Created in 10:35 2020/4/3
 * @Modified:
 */
public class DynamicProgramming {

    private int citynumbers;//城市数目
    double s = 0;//总距离
    int path[];//存放路径,方便计算距离
    private double[][] distance;
    private double[][] optimalvalue;//阶段最短路径值矩阵
    private int[][] optimalchoice;//阶段最优策略矩阵

    public DynamicProgramming(int citynumbers) {
        this.citynumbers = citynumbers;
    }

    public void readData(double [] x,double [] y) throws IOException {

        //  int [] x = {2066,935,1270,1389,984,2253};

        // int [] y = {2333,1304,200,700,2810,478};
        distance = new double[citynumbers][citynumbers];//距离矩阵

        //计算距离矩阵
        for (int i = 0; i < citynumbers; i++) {
            for (int j = 0; j < citynumbers; j++) {
                distance[i][j] = Math.sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]));//计算欧式距离
            }
        }
        int h = (int) Math.pow(2, citynumbers - 1);
        optimalvalue = new double[citynumbers][h];
        optimalchoice = new int[citynumbers][h];
    }

    public List solve() {
        double min = Double.MAX_VALUE;//确保会更新
        int mink = 0;
        //计算第一列地值
        for (int i = 0; i < citynumbers; i++) {
            optimalvalue[i][0] = distance[i][0];
        }
        for (int i = 1; i < (Math.pow(2, citynumbers - 1)); i++) {
            for (int j = 1; j < citynumbers; j++) {
                int k = 0;
                if (judge(i, j) == 0) {//确定j不包含在i代表的集合中
                    String a = com.chaosting.fireStation.service.util.DynamicProgramming.binary(i, citynumbers - 1);
                    for (int w = a.length(); w > 0; w--) {
                        k = a.charAt(a.length() - w) - 48;//k为0或者1
                        if (k == 1) {
                            k = k * w;//此时的k为选择的集合中的某个值
                            double y = (distance[j][k] + optimalvalue[k][(int) (i - Math.pow(2, k - 1))]);
                            if (y < min) {
                                min = (distance[j][k] + optimalvalue[k][(int) (i - Math.pow(2, k - 1))]);
                                mink = k;
                            }
                        }
                    }
                    if (min < Double.MAX_VALUE) {//确定min是否变化,有变化再写入矩阵
                        optimalvalue[j][i] = min;
                        optimalchoice[j][i] = mink;
                        min = Double.MAX_VALUE;
                    }
                }
            }
        }
        min = Double.MAX_VALUE;//更新min
        int i = (int) (Math.pow(2, citynumbers - 1) - 1);//更新最后一列
        for (int k = citynumbers - 1; k > 0; k--) {
            double x = (distance[0][k] + optimalvalue[k][(int) (i - Math.pow(2, k - 1))]);
            if (x < min) {
                min = x;
                mink = k;
            }
        }
        optimalvalue[0][i] = min;
        optimalchoice[0][i] = mink;
        path = new int[citynumbers + 1];
        path[0] = 1;
        int c = 1;
        for (int j = 0; i > 0; ) {
            j = optimalchoice[j][i];
            i = (int) (i - Math.pow(2, j - 1));
            path[c++] = j + 1;
        }
        path[c++] = 1;
        List<Integer> list = new ArrayList<>();
        for (i = 0; i < citynumbers; i++) {
            //System.out.print(path[i] + "->");
            list.add(path[i]);
            s = s + distance[path[i] - 1][path[i + 1] - 1];
        }

        return list;
    }

    //判断j是否在i表示的集合中
    public int judge(int i, int j) {
        String a = com.chaosting.fireStation.service.util.DynamicProgramming.binary(i, citynumbers - 1);
        int b = a.charAt(a.length() - j) - 48;
        return b;
    }

    //给定一个十进制数,输出一个指定位数的二进制形式字符串
    public static String binary(int decNum, int digit) {
        String binStr = "";
        for (int i = digit - 1; i >= 0; i--) {
            binStr += (decNum >> i) & 1;
        }
        return binStr;
    }

    public static void main(String[] args) throws Exception {

        double [] x = {0,93.568};

        double [] y = {0,13.865};

        List sort = sort(x, y, 2);
        System.out.println(sort);


    }

    public static List<Integer> sort(double [] x,double [] y,int number) throws Exception{
        com.chaosting.fireStation.service.util.DynamicProgramming tsp = new com.chaosting.fireStation.service.util.DynamicProgramming(number);//建立对象
        tsp.readData(x,y);
        List<Integer> list = tsp.solve();

        return list;
    }
}

百度工具类:BaiduHttpUtils

package com.chaosting.kiwifruit.web.utils.weixin;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.springframework.util.StringUtils;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;

/**
 * @Author: zhangweixia
 * @Description:  请求百度开发接口工具类
 * @Date:Created in 14:34 2020/2/26
 * @Modified:
 */
public class BaiduHttpUtils {
    /**
     * GET请求
     */
    public static String httpGet(String httpUrl) throws Exception {
        //创建一个url对象
        URL url = new URL(httpUrl);
        //打开链接,强转为httpUrlConnection
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        //设置链接方式
        connection.setRequestMethod("GET");
        //设置超时时间
        connection.setConnectTimeout(3000);
        //设置读取超时时间
        connection.setReadTimeout(5000);
        //发送请求
        connection.connect();
        //获取输入流
        InputStream inputStream = connection.getInputStream();
        //封装输入流
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
        //接收返回的数据
        StringBuffer stringBuffer = new StringBuffer();
        String line = null;
        while ((line = bufferedReader.readLine()) != null){
            stringBuffer.append(line);

        }
        //关流
        bufferedReader.close();
        inputStream.close();
        //关闭链接
        connection.disconnect();
        return stringBuffer.toString();
    }
    /**
     * 百度驾车路径解析
     */
    public static List<Map> getResult(String baiduResult){
        JSONObject jsonObject = JSON.parseObject(baiduResult);
        //0.获得结果集json对象
        Object result = jsonObject.get("result");
        JSONObject resultJsonObject = JSON.parseObject(result.toString());
        //4.获得第一页路线routes
        String routes = resultJsonObject.getString("routes");
        JSONArray routesArray = JSON.parseArray(routes);
        System.out.println("routes总共有="+routesArray.size());
        //默认取第一条路线
        JSONObject routeJsonObject = JSON.parseObject(routesArray.get(0).toString());
        //本条路线有几个step 步骤
        String steps = routeJsonObject.getString("steps");

        JSONArray stepsArray = JSON.parseArray(steps);

        System.out.println("steps总共有="+stepsArray.size());

        List<Map> maps = new ArrayList<>();

        for (int i = 0; i < stepsArray.size(); i++) {
            Map map1 = new HashMap();

            JSONObject jsonStep = JSON.parseObject(stepsArray.get(i).toString());

            String start_location = jsonStep.getString("start_location");

            JSONObject startObject = JSON.parseObject(start_location);
            String longitude = startObject.getString("lng");
            String latitude = startObject.getString("lat");
            map1.put("latitude",latitude);
            map1.put("longitude",longitude);


            maps.add(map1);

        }
        return maps;
    }
    /**
     * 百度地址解析
     */
    public static Map getJson(String baiduResult) {


        JSONObject jsonObject = JSON.parseObject(baiduResult);
        String status = jsonObject.getString("status");//0
        String message = jsonObject.getString("message");//成功
        Map<Object, Object> hashMap = new HashMap<>();
        hashMap.put("status", status);
        hashMap.put("message", message);
        if (!"0".equals(status)) return hashMap;
        //0.获得结果集json对象
        Object result = jsonObject.get("result");
        JSONObject resultJsonObject = JSON.parseObject(result.toString());
        //1.获得出发地城市名称
        Object origin = resultJsonObject.get("origin");
        JSONObject originJsonObject = JSON.parseObject(origin.toString());
        String origin_city_name = originJsonObject.get("city_name").toString();
        //2.获得目的地城市名称
        Object destination = resultJsonObject.get("destination");
        JSONObject destinationJsonObject = JSON.parseObject(destination.toString());
        String destination_city_name = destinationJsonObject.getString("city_name");
        //3.获得所有路线的总数
        String total = resultJsonObject.getString("total");
        //计算总页数
        int totalInt = Integer.parseInt(total);

        //4.获得第一页路线routes
        String routes = resultJsonObject.getString("routes");
        JSONArray routesArray = JSON.parseArray(routes);

        Map<String, Object> map = new LinkedHashMap<>();
        Map<String, Object> dataMap = new LinkedHashMap<>();

        dataMap.put("total", totalInt);
        //当前页数量
        dataMap.put("pageSize", routesArray.size());
        dataMap.put("origin", origin_city_name);
        dataMap.put("destination", destination_city_name);

        map.put("status", status);
        map.put("message", message);
        //5.解析第一页的所有路线
        List<Map> routeList = new ArrayList<>();
        for (int i = 0; i < routesArray.size(); i++) {
            int m = 1;
            //Map<String, String> sunMap = new HashMap<>();
            Map<String, Object> routeMap = new LinkedHashMap<>();
            Map sunMap = new LinkedHashMap<String, String>();
            List<Map> sunMapList = new ArrayList<>();
            JSONObject routeJsonObject = JSON.parseObject(routesArray.get(i).toString());
            //本条路线的总距离(米)
            String distanceType = routeJsonObject.getString("distance");
            //将米转换成公里,保留小数点后一位,四舍五入
            String distance = getKM(distanceType);
            //本条路线的总耗时(秒)
            String duration = routeJsonObject.getString("duration");
            //将秒转换成时分秒
            duration = DateUtil.getDuratiom(duration);
            routeMap.put("distance", distance);
            routeMap.put("duration", duration);
            //6.本条路线的总票价
            String price = routeJsonObject.getString("price");
            routeMap.put("price", price);
            //本条路线有几个step 步骤
            String steps = routeJsonObject.getString("steps");
            JSONArray stepsArray = JSON.parseArray(steps);
            //System.out.println("第"+i+"条路线:"+"总距离="+distance+"。总耗时="+duration+"。步骤="+steps);
            //每个子步骤的具体方案
            for (int j = 0; j < stepsArray.size(); j++) {

                //每个子步骤 schemes
                String schemes = stepsArray.get(j).toString();

                //解析每个子步骤下面的孙子步骤
                JSONArray schemesArray = JSON.parseArray(schemes);

                for (int k = 0; k < schemesArray.size(); k++) {

                    String sun = schemesArray.get(k).toString();
                    JSONObject sunJsonObject = JSON.parseObject(sun);
                    //1.获取孙子步骤的描述信息
                    String instructions = sunJsonObject.getString("instructions");
                    //2.孙子步骤的距离
                    String sunDistanceType = sunJsonObject.getString("distance");
                    String sunDistance = getKM(sunDistanceType);
                    //3.孙子步骤的耗时
                    String sunDuration = sunJsonObject.getString("duration");
                    sunDuration = DateUtil.getDuratiom(sunDuration);
                    //.交通方式
                    String vehicle_info = sunJsonObject.getString("vehicle_info");
                    JSONObject vehicleJsonObject = JSON.parseObject(vehicle_info);
                    String type = vehicleJsonObject.getString("type");
                    //存入步骤信息,因机场有些描述信息没有,但还是有步骤,当没描述信息就不存了,跳出此次循环
                    if (StringUtils.isEmpty(instructions)) {
                        break;
                    }
                    //type为1是火车,type为2是飞机
                    if (Integer.parseInt(type) == 1 || Integer.parseInt(type) == 2) {
                        String detail = vehicleJsonObject.getString("detail");
                        JSONObject detailJsonObject = JSON.parseObject(detail);
                        //火车车次
                        String name = detailJsonObject.getString("name");
                        //总票价
                        String detailPrice = detailJsonObject.getString("price");
                        //上车火车站名
                        String departureStation = detailJsonObject.getString("departure_station");
                        //下火车站名
                        String arriveStation = detailJsonObject.getString("arrive_station");
                        //发车时间
                        String departureTime = detailJsonObject.getString("departure_time");
                        //到站时间
                        String arriveTime = detailJsonObject.getString("arrive_time");
                        sunMap.put("第" + m + "步", instructions + "|距离=" + sunDistance + "|耗时=" + sunDuration + "|班次" + name + "|出发时间=" + departureTime + "|到达时间=" + arriveTime);
                    } else {
                        sunMap.put("第" + m + "步", instructions + "|距离=" + sunDistance + "|耗时=" + sunDuration);
                    }

                    System.out.println("第" + (i + 1) + "条路线:" + "第" + m + "步=" + instructions);

                    m++;
                }


            }
            sunMapList.add(sunMap);

            routeMap.put("route", sunMapList);

            routeList.add(routeMap);

        }

        dataMap.put("routes", routeList);
        map.put("result", dataMap);

        return map;
    }

    /**
     * 米转换成公里,保留小数点后一位
     */
    public static String getKM(String distance) {
        //换算成公里,保留小数点后一位,四舍五入
        double distanceDouble = Double.parseDouble(distance);
        double b = Math.rint(distanceDouble / 100) / 10;
        distance = b + "公里";

        return distance;

    }

}

返回给前端的路径格式:

 "code": 0,

    "data": [

    

 {

            "step": [

扫描二维码关注公众号,回复: 10984430 查看本文章

                {

                    "latitude": "40.479965606385",

                    "longitude": "116.31932607972"

                },

                {

                    "latitude": "40.479900370146",

                    "longitude": "116.32667969845"

                } 

            ]

        },

 {

            "step": [

              

 {

                    "latitude": "41.129388293691",

                    "longitude": "118.447649255"

                },

                {

                    "latitude": "41.122830549249",

                    "longitude": "118.43334984823"

                }

            ]

        },

 {

            "step": [

               

 {

                    "latitude": "40.120992095059",

                    "longitude": "116.45298917858"

                },

                {

                    "latitude": "40.124614014625",

                    "longitude": "116.45278705984"

                }

            ]

        }

   ]

 
发布了42 篇原创文章 · 获赞 14 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/a116385895/article/details/105379885
今日推荐