|  |  |  | 
|---|
|  |  |  | package com.zy.asrs.wcs.core.utils; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | import com.alibaba.fastjson.JSON; | 
|---|
|  |  |  | import com.alibaba.fastjson.JSONArray; | 
|---|
|  |  |  | import com.zy.asrs.framework.common.SpringUtils; | 
|---|
|  |  |  | import com.zy.asrs.wcs.core.model.MapNode; | 
|---|
|  |  |  | import com.zy.asrs.wcs.core.model.NavigateNode; | 
|---|
|  |  |  | import com.zy.asrs.wcs.core.model.PythonSimilarityResult; | 
|---|
|  |  |  | import com.zy.asrs.wcs.core.model.enums.MapNodeType; | 
|---|
|  |  |  | import com.zy.asrs.wcs.core.model.enums.NavigationMapType; | 
|---|
|  |  |  | import com.zy.asrs.wcs.rcs.News; | 
|---|
|  |  |  | import org.springframework.beans.factory.annotation.Value; | 
|---|
|  |  |  | import org.springframework.stereotype.Component; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | import java.io.BufferedReader; | 
|---|
|  |  |  | import java.io.InputStreamReader; | 
|---|
|  |  |  | import java.util.ArrayList; | 
|---|
|  |  |  | import java.util.Collections; | 
|---|
|  |  |  | import java.util.HashMap; | 
|---|
|  |  |  | import java.util.List; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * A*算法使用工具 | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | @Component | 
|---|
|  |  |  | public class NavigateUtils { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public static List<NavigateNode> calc(String startPoint, String endPoint, Integer mapType, List<int[]> shuttlePoints) { | 
|---|
|  |  |  | @Value("${pythonCalcPath}") | 
|---|
|  |  |  | private String pythonCalcPath; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | @Value("${pythonCalcSimilarity}") | 
|---|
|  |  |  | private String pythonCalcSimilarity; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public List<NavigateNode> calc(String startPoint, String endPoint, Integer mapType, List<int[]> shuttlePoints) { | 
|---|
|  |  |  | //通过开始编号和结束编号获取对应的xy轴坐标 | 
|---|
|  |  |  | int[] startArr = NavigatePositionConvert.positionToXY(startPoint);//开始节点 | 
|---|
|  |  |  | int[] endArr = NavigatePositionConvert.positionToXY(endPoint);//结束节点 | 
|---|
|  |  |  | 
|---|
|  |  |  | NavigateSolution solution = new NavigateSolution(mapType, lev, whiteList, shuttlePoints); | 
|---|
|  |  |  | //开始节点,不纳入禁用节点内计算 | 
|---|
|  |  |  |  | 
|---|
|  |  |  | NavigateNode res_node = solution.astarSearch(start, end); | 
|---|
|  |  |  | if (res_node == null) { | 
|---|
|  |  |  | System.err.println("未找到路径"); | 
|---|
|  |  |  | String pathStr = solution.astarSearch(start, end, pythonCalcPath); | 
|---|
|  |  |  | if (pathStr == null) { | 
|---|
|  |  |  | News.error("{} dash {} can't find navigate path!", startPoint, endPoint); | 
|---|
|  |  |  | return null; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | ArrayList<NavigateNode> list = new ArrayList<>(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | //渲染 | 
|---|
|  |  |  | List<NavigateNode> list = new ArrayList<>(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | NavigateNode fatherNode = null;//当前循环上一节点,用于拐点计算 | 
|---|
|  |  |  | while (res_node != null) { | 
|---|
|  |  |  | res_node.setDirection(null); | 
|---|
|  |  |  | res_node.setIsInflectionPoint(false); | 
|---|
|  |  |  | res_node.setZ(lev);//设置层高 | 
|---|
|  |  |  | JSONArray rows = JSON.parseArray(pathStr); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | for (int i = 0; i < rows.size(); i++) { | 
|---|
|  |  |  | Object currentObj = rows.get(i); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | NavigateNode nextNode = null; | 
|---|
|  |  |  | if ((i + 1) < rows.size()) { | 
|---|
|  |  |  | Object object = rows.get(i + 1); | 
|---|
|  |  |  | nextNode = pythonObjTransferNode(object, lev); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | NavigateNode node = pythonObjTransferNode(currentObj, lev); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | //寻找拐点 | 
|---|
|  |  |  | HashMap<String, Object> result = searchInflectionPoint(res_node, fatherNode, res_node.getFather());//分别传入当前节点、父节点、下一节点 | 
|---|
|  |  |  | HashMap<String, Object> result = searchInflectionPoint(node, fatherNode, nextNode);//分别传入当前节点、父节点、下一节点 | 
|---|
|  |  |  | //判断当前节点是否为拐点 | 
|---|
|  |  |  | if (Boolean.parseBoolean(result.get("result").toString())) { | 
|---|
|  |  |  | //当前为拐点 | 
|---|
|  |  |  | res_node.setIsInflectionPoint(true); | 
|---|
|  |  |  | node.setIsInflectionPoint(true); | 
|---|
|  |  |  | //拐点方向 | 
|---|
|  |  |  | res_node.setDirection(result.get("direction").toString()); | 
|---|
|  |  |  | node.setDirection(result.get("direction").toString()); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | list.add(res_node); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | fatherNode = res_node;//把当前节点保存成一个父节点 | 
|---|
|  |  |  | res_node = res_node.getFather();//迭代操作 | 
|---|
|  |  |  | list.add(node); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | fatherNode = node;//把当前节点保存成一个父节点 | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | Collections.reverse(list); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | //将每个节点里面的fatherNode至为null(方便后续计算时父节点过多导致显示的节点太多) | 
|---|
|  |  |  | for (NavigateNode navigateNode : list) { | 
|---|
|  |  |  | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | //判断当前节点到下一个节点是否为拐点 | 
|---|
|  |  |  | public static HashMap<String,Object> searchInflectionPoint(NavigateNode currentNode, NavigateNode fatherNode, NavigateNode nextNode) { | 
|---|
|  |  |  | public HashMap<String,Object> searchInflectionPoint(NavigateNode currentNode, NavigateNode fatherNode, NavigateNode nextNode) { | 
|---|
|  |  |  | HashMap<String, Object> map = new HashMap<>(); | 
|---|
|  |  |  | map.put("result", false);//是否为拐点,true:拐点,false:直线 | 
|---|
|  |  |  | // 第一个点或直线点 | 
|---|
|  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * 计算方向 | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | public static String calcDirection(NavigateNode currentNode, NavigateNode fatherNode) { | 
|---|
|  |  |  | public String calcDirection(NavigateNode currentNode, NavigateNode fatherNode) { | 
|---|
|  |  |  | //拐点方向 | 
|---|
|  |  |  | String direction = ""; | 
|---|
|  |  |  | // 普通拐点 | 
|---|
|  |  |  | 
|---|
|  |  |  | * 加转弯节点 | 
|---|
|  |  |  | * 获取分段路径,每当有一个拐点则进行一次分段,最终返回总分段数据 | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | public static ArrayList<ArrayList<NavigateNode>> getSectionPath(List<NavigateNode> mapList) { | 
|---|
|  |  |  | public ArrayList<ArrayList<NavigateNode>> getSectionPath(List<NavigateNode> mapList) { | 
|---|
|  |  |  | ArrayList<ArrayList<NavigateNode>> list = new ArrayList<>(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | ArrayList<NavigateNode> data = new ArrayList<>(); | 
|---|
|  |  |  | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | //获取从x点到下一点的行走距离 | 
|---|
|  |  |  | public static Integer getXToNextDistance(NavigateNode xNode) { | 
|---|
|  |  |  | public Integer getXToNextDistance(NavigateNode xNode) { | 
|---|
|  |  |  | NavigateMapData mapData = SpringUtils.getBean(NavigateMapData.class); | 
|---|
|  |  |  | mapData.setLev(xNode.getZ()); | 
|---|
|  |  |  | List<List<MapNode>> lists = mapData.getJsonData(NavigationMapType.NONE.id, null, null); | 
|---|
|  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * 根据原始节点结果,计算总行走距离 | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | public static Integer getOriginPathAllDistance(List<NavigateNode> path) { | 
|---|
|  |  |  | ArrayList<ArrayList<NavigateNode>> sectionPath = NavigateUtils.getSectionPath(path); | 
|---|
|  |  |  | public Integer getOriginPathAllDistance(List<NavigateNode> path) { | 
|---|
|  |  |  | ArrayList<ArrayList<NavigateNode>> sectionPath = getSectionPath(path); | 
|---|
|  |  |  | Integer allDistance = 0; | 
|---|
|  |  |  | for (ArrayList<NavigateNode> navigateNodes : sectionPath) { | 
|---|
|  |  |  | Integer distance = NavigateUtils.getCurrentPathAllDistance(navigateNodes); | 
|---|
|  |  |  | Integer distance = getCurrentPathAllDistance(navigateNodes); | 
|---|
|  |  |  | allDistance += distance; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | return allDistance; | 
|---|
|  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * 获取当前路径总行走距离 | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | public static Integer getCurrentPathAllDistance(List<NavigateNode> path) { | 
|---|
|  |  |  | public Integer getCurrentPathAllDistance(List<NavigateNode> path) { | 
|---|
|  |  |  | if (path.size() == 1) { | 
|---|
|  |  |  | //路径只有一条数据,则直接返回行走距离 | 
|---|
|  |  |  | return path.get(0).getMoveDistance(); | 
|---|
|  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * 获取中间点到目标点行走距离 | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | public static Integer getMiddleToDistDistance(List<NavigateNode> path, NavigateNode middlePath) { | 
|---|
|  |  |  | public Integer getMiddleToDistDistance(List<NavigateNode> path, NavigateNode middlePath) { | 
|---|
|  |  |  | //最后一条节点不计算进行走距离 | 
|---|
|  |  |  | NavigateNode lastPath = path.get(path.size() - 1); | 
|---|
|  |  |  | //总距离 | 
|---|
|  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * 检测路径是否可用(可走) | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | public static boolean checkPathIsAvailable(List<NavigateNode> path, Integer shuttleNo, Integer lev) { | 
|---|
|  |  |  | public boolean checkPathIsAvailable(List<NavigateNode> path, Integer shuttleNo, Integer lev) { | 
|---|
|  |  |  | NavigateSolution solution = new NavigateSolution(NavigationMapType.DFX.id, lev, null, Utils.getShuttlePoints(shuttleNo, lev));//获取无白名单地图(该地图包含小车坐标) | 
|---|
|  |  |  | int[][] map = solution.map; | 
|---|
|  |  |  | for (NavigateNode node : path) { | 
|---|
|  |  |  | 
|---|
|  |  |  | return true; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public static void main(String[] args) { | 
|---|
|  |  |  | //计算路径 | 
|---|
|  |  |  | List<NavigateNode> calc = calc("1000901", "1800201", NavigationMapType.NONE.id, null); | 
|---|
|  |  |  | System.out.println(calc); | 
|---|
|  |  |  | System.out.println("------------------------"); | 
|---|
|  |  |  | //        List<NavigateNode> calc = calc("0501401", "0201801", "out"); | 
|---|
|  |  |  | //将路径分割成多段 | 
|---|
|  |  |  | ArrayList<ArrayList<NavigateNode>> data = getSectionPath(calc); | 
|---|
|  |  |  | for (ArrayList<NavigateNode> list : data) { | 
|---|
|  |  |  | Integer currentPathAllDistance = getCurrentPathAllDistance(list);//计算当前路径总距离 | 
|---|
|  |  |  | System.out.println(currentPathAllDistance); | 
|---|
|  |  |  | System.out.println(list); | 
|---|
|  |  |  | private NavigateNode pythonObjTransferNode(Object obj, Integer z) { | 
|---|
|  |  |  | List<Integer> pathData = JSON.parseArray(obj.toString(), Integer.class); | 
|---|
|  |  |  | Integer x = pathData.get(0); | 
|---|
|  |  |  | Integer y = pathData.get(1); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | NavigateNode node = new NavigateNode(x, y); | 
|---|
|  |  |  | node.setDirection(null); | 
|---|
|  |  |  | node.setIsInflectionPoint(false); | 
|---|
|  |  |  | node.setZ(z); | 
|---|
|  |  |  | return node; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public Double similarityPath(List<NavigateNode> firstPath, List<NavigateNode> secondPath) { | 
|---|
|  |  |  | try { | 
|---|
|  |  |  | List<int[]> first = new ArrayList<>(); | 
|---|
|  |  |  | for (NavigateNode node : firstPath) { | 
|---|
|  |  |  | first.add(new int[]{node.getX(), node.getY()}); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | List<int[]> second = new ArrayList<>(); | 
|---|
|  |  |  | for (NavigateNode node : secondPath) { | 
|---|
|  |  |  | second.add(new int[]{node.getX(), node.getY()}); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | ProcessBuilder processBuilder = new ProcessBuilder("python", pythonCalcSimilarity, JSON.toJSONString(first), JSON.toJSONString(second)); | 
|---|
|  |  |  | processBuilder.redirectErrorStream(true); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | Process process = processBuilder.start(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 读取Python脚本的输出 | 
|---|
|  |  |  | BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); | 
|---|
|  |  |  | String line; | 
|---|
|  |  |  | StringBuilder builder = new StringBuilder(); | 
|---|
|  |  |  | while ((line = reader.readLine()) != null) { | 
|---|
|  |  |  | builder.append(line); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 等待Python脚本执行完成 | 
|---|
|  |  |  | int exitCode = process.waitFor(); | 
|---|
|  |  |  | if (exitCode != 0) { | 
|---|
|  |  |  | System.out.println("Python script exited with error code: " + exitCode); | 
|---|
|  |  |  | return null; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | reader.close(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (builder.length() <= 0) { | 
|---|
|  |  |  | return null; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | PythonSimilarityResult result = JSON.parseObject(builder.toString(), PythonSimilarityResult.class); | 
|---|
|  |  |  | if (result.getCalcResult() != 200) { | 
|---|
|  |  |  | return 0D; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | Double similarity = result.getSimilarity(); | 
|---|
|  |  |  | return similarity; | 
|---|
|  |  |  | } catch (Exception e) { | 
|---|
|  |  |  | e.printStackTrace(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | return 0D; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public static void main(String[] args) { | 
|---|
|  |  |  | //        //计算路径 | 
|---|
|  |  |  | //        List<NavigateNode> calc = calc("1000901", "1800201", NavigationMapType.NONE.id, null); | 
|---|
|  |  |  | //        System.out.println(calc); | 
|---|
|  |  |  | //        System.out.println("------------------------"); | 
|---|
|  |  |  | ////        List<NavigateNode> calc = calc("0501401", "0201801", "out"); | 
|---|
|  |  |  | //        //将路径分割成多段 | 
|---|
|  |  |  | //        ArrayList<ArrayList<NavigateNode>> data = getSectionPath(calc); | 
|---|
|  |  |  | //        for (ArrayList<NavigateNode> list : data) { | 
|---|
|  |  |  | //            Integer currentPathAllDistance = getCurrentPathAllDistance(list);//计算当前路径总距离 | 
|---|
|  |  |  | //            System.out.println(currentPathAllDistance); | 
|---|
|  |  |  | //            System.out.println(list); | 
|---|
|  |  |  | //        } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | System.loadLibrary("example"); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|