package com.xiaopeng.map.utils;
|
|
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSONArray;
|
import com.alibaba.fastjson2.JSONObject;
|
import com.xiaopeng.api.dto.map.HistoryPointDto;
|
import com.xiaopeng.api.dto.operation.LonLatDto;
|
import com.xiaopeng.api.vo.operation.RouteVo;
|
import com.xiaopeng.common.core.utils.HttpUtils;
|
import com.xiaopeng.map.config.MapApiProperties;
|
import com.xiaopeng.map.mangodb.service.XpGeoFencingPolygonService;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.context.annotation.Lazy;
|
import org.springframework.stereotype.Component;
|
|
import java.util.ArrayList;
|
import java.util.HashMap;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.concurrent.ForkJoinPool;
|
import java.util.concurrent.RecursiveTask;
|
|
/**
|
* 高德地图的地理编码工具类
|
*/
|
@Slf4j
|
@Component
|
@Lazy
|
public class GDMapGeocodingUtil {
|
|
|
@Autowired
|
private XpGeoFencingPolygonService xpGeoFencingPolygonService;
|
|
@Autowired
|
private MapApiProperties mapApiProperties;
|
|
|
/**
|
* 根据起始点获取驾车距离 和 时间 以及避让区域
|
*
|
* @param start 起点
|
* @param end 终点
|
* @param avoidRoads 避让点
|
* @param fenceId mango id
|
* @param routePlanRule 线路规划规则
|
* @return
|
* @throws Exception
|
*/
|
public RouteVo getDistanceAndTime(LonLatDto start, LonLatDto end,ArrayList<JSONObject> avoidRoads,String fenceId,Integer routePlanRule, List<HistoryPointDto> history) {
|
RouteVo routeVo = new RouteVo();
|
|
String url = mapApiProperties.getUrls().getRoutePrice() + "?key=" + mapApiProperties.getApiKey() + "&extensions=all&start=" + start.getLongitude() + "," + start.getLatitude();
|
HashMap<String, Object> params = new HashMap<>();
|
params.put("extensions", "all");
|
params.put("start", start.getLongitude() + "," + start.getLatitude());
|
params.put("end", end.getLongitude() + "," + end.getLatitude());
|
params.put("routeUserType", 2);
|
if (avoidRoads != null && !avoidRoads.isEmpty()) {
|
params.put("avoidPolygons", avoidRoads);
|
}
|
if (routePlanRule != null) {
|
params.put("strategy", routePlanRule);
|
}
|
if(null != history && !history.isEmpty()){
|
params.put("history", history);
|
}
|
log.info("高德地图接口:{}", url);
|
log.info("高德地图参数:{}", JSON.toJSONString(params));
|
String post = HttpUtils.post(url, JSON.toJSONString(params));
|
log.info("高德地图返回结果:" + post);
|
JSONObject jsonObject = JSON.parseObject(post);
|
String data = jsonObject.getString("data");
|
|
JSONObject jsonObject1 = JSON.parseObject(data);
|
JSONArray path = jsonObject1.getJSONArray("paths");
|
log.info("开始判断导航路径是否在运营区域范围内 {}", fenceId);
|
log.info("先判断是否有大众常选的线路,优先选择大众常选的路线");
|
for (Object o : path) {
|
JSONObject jsonObject2 = (JSONObject) o;
|
String routeID = jsonObject2.getString("routeID");
|
String points = jsonObject2.getString("points");
|
String label = jsonObject2.getString("label");
|
if(label.contains("大众常选")){
|
String[] split = points.split(";");
|
List<LonLatDto> pointsArray = new ArrayList<>();
|
for (int i = 0; i < split.length; i++) {
|
if((i % 2) == 0){
|
String[] split1 = split[i].split(",");
|
LonLatDto lonLatDto = new LonLatDto(Double.parseDouble(split1[0]), Double.parseDouble(split1[1]));
|
pointsArray.add(lonLatDto);
|
}
|
}
|
ForkJoinPool pool = new ForkJoinPool(); // 创建ForkJoinPool对象(默认使用处理器的核心数作为线程池大小)
|
ArrayPointsTask arrayPointsTask = new ArrayPointsTask(pointsArray, fenceId); // 创建求和任务对象并传入数组作为参数(这里也可以传入数组的一部分作为参数来实现更细粒度的拆分)
|
Long temp = pool.invoke(arrayPointsTask); // 提交任务并等待处理完成(也可以使用submit方法提交任务并获取一个Future对象来异步获取结果)
|
pool.shutdown(); // 关闭ForkJoinPool(释放资源)
|
if(temp==0){
|
Integer costTime = jsonObject2.getInteger("costTime");
|
Integer distance = jsonObject2.getInteger("distance");
|
routeVo.setDistance(distance);
|
routeVo.setDuration(costTime);
|
ArrayList<LonLatDto> lonLatDtos = new ArrayList<>(split.length);
|
for (String s : split) {
|
String[] split1 = s.split(",");
|
LonLatDto lonLatDto = new LonLatDto(Double.parseDouble(split1[0]), Double.parseDouble(split1[1]));
|
lonLatDtos.add(lonLatDto);
|
}
|
routeVo.setPolyline(lonLatDtos);
|
routeVo.setRouteID(routeID);
|
log.info("导航 {} 在 {} 运营区域内", routeVo.getRouteID(), fenceId);
|
return routeVo;
|
}
|
}
|
|
}
|
|
for (Object o : path) {
|
JSONObject jsonObject2 = (JSONObject) o;
|
String routeID = jsonObject2.getString("routeID");
|
String points = jsonObject2.getString("points");
|
String[] split = points.split(";");
|
List<LonLatDto> pointsArray = new ArrayList<>();
|
for (int i = 0; i < split.length; i++) {
|
if((i % 2) == 0){
|
String[] split1 = split[i].split(",");
|
LonLatDto lonLatDto = new LonLatDto(Double.parseDouble(split1[0]), Double.parseDouble(split1[1]));
|
pointsArray.add(lonLatDto);
|
}
|
}
|
ForkJoinPool pool = new ForkJoinPool(); // 创建ForkJoinPool对象(默认使用处理器的核心数作为线程池大小)
|
ArrayPointsTask arrayPointsTask = new ArrayPointsTask(pointsArray, fenceId); // 创建求和任务对象并传入数组作为参数(这里也可以传入数组的一部分作为参数来实现更细粒度的拆分)
|
Long temp = pool.invoke(arrayPointsTask); // 提交任务并等待处理完成(也可以使用submit方法提交任务并获取一个Future对象来异步获取结果)
|
pool.shutdown(); // 关闭ForkJoinPool(释放资源)
|
if (temp == 0) {
|
Integer costTime = jsonObject2.getInteger("costTime");
|
Integer distance = jsonObject2.getInteger("distance");
|
routeVo.setDistance(distance);
|
routeVo.setDuration(costTime);
|
ArrayList<LonLatDto> lonLatDtos = new ArrayList<>(split.length);
|
for (String s : split) {
|
String[] split1 = s.split(",");
|
LonLatDto lonLatDto = new LonLatDto(Double.parseDouble(split1[0]), Double.parseDouble(split1[1]));
|
lonLatDtos.add(lonLatDto);
|
}
|
routeVo.setPolyline(lonLatDtos);
|
routeVo.setRouteID(routeID);
|
log.info("导航 {} 在 {} 运营区域内", routeVo.getRouteID(), fenceId);
|
return routeVo;
|
}
|
}
|
return null;
|
|
}
|
|
|
/**
|
* 根据起始点获取驾车距离 和 时间 以及避让区域
|
*
|
* @param start 起点
|
* @param end 终点
|
* @param avoidRoads 避让点
|
* @param fenceId mango id
|
* @param routePlanRule 线路规划规则
|
* @return
|
* @throws Exception
|
*/
|
public List<RouteVo> getDistanceAndTimeList(LonLatDto start, LonLatDto end,ArrayList<JSONObject> avoidRoads,String fenceId,Integer routePlanRule, List<HistoryPointDto> history) {
|
String url = mapApiProperties.getUrls().getRoutePrice() + "?key=" + mapApiProperties.getApiKey() + "&extensions=all&start=" + start.getLongitude() + "," + start.getLatitude();
|
HashMap<String, Object> params = new HashMap<>();
|
params.put("extensions", "all");
|
params.put("start", start.getLongitude() + "," + start.getLatitude());
|
params.put("end", end.getLongitude() + "," + end.getLatitude());
|
params.put("routeUserType", 2);
|
if (avoidRoads != null && !avoidRoads.isEmpty()) {
|
params.put("avoidPolygons", avoidRoads);
|
}
|
if (routePlanRule != null) {
|
params.put("strategy", routePlanRule);
|
}
|
if(null != history && !history.isEmpty()){
|
params.put("history", history);
|
}
|
log.info("高德地图接口:{}", url);
|
log.info("高德地图参数:{}", JSON.toJSONString(params));
|
String post = HttpUtils.post(url, JSON.toJSONString(params));
|
log.info("高德地图返回结果:" + post);
|
JSONObject jsonObject = JSON.parseObject(post);
|
String data = jsonObject.getString("data");
|
|
JSONObject jsonObject1 = JSON.parseObject(data);
|
JSONArray path = jsonObject1.getJSONArray("paths");
|
log.info("开始判断导航路径是否在运营区域范围内 {}", fenceId);
|
List<RouteVo> list = new ArrayList<>();
|
for (Object o : path) {
|
RouteVo routeVo = new RouteVo();
|
JSONObject jsonObject2 = (JSONObject) o;
|
String routeID = jsonObject2.getString("routeID");
|
String points = jsonObject2.getString("points");
|
String[] split = points.split(";");
|
List<LonLatDto> pointsArray = new ArrayList<>();
|
for (int i = 0; i < split.length; i++) {
|
if((i % 2) == 0){
|
String[] split1 = split[i].split(",");
|
LonLatDto lonLatDto = new LonLatDto(Double.parseDouble(split1[0]), Double.parseDouble(split1[1]));
|
pointsArray.add(lonLatDto);
|
}
|
}
|
ForkJoinPool pool = new ForkJoinPool(); // 创建ForkJoinPool对象(默认使用处理器的核心数作为线程池大小)
|
ArrayPointsTask arrayPointsTask = new ArrayPointsTask(pointsArray, fenceId); // 创建求和任务对象并传入数组作为参数(这里也可以传入数组的一部分作为参数来实现更细粒度的拆分)
|
Long temp = pool.invoke(arrayPointsTask); // 提交任务并等待处理完成(也可以使用submit方法提交任务并获取一个Future对象来异步获取结果)
|
pool.shutdown(); // 关闭ForkJoinPool(释放资源)
|
if (temp == 0) {
|
Integer costTime = jsonObject2.getInteger("costTime");
|
Integer distance = jsonObject2.getInteger("distance");
|
routeVo.setDistance(distance);
|
routeVo.setDuration(costTime);
|
ArrayList<LonLatDto> lonLatDtos = new ArrayList<>(split.length);
|
for (String s : split) {
|
String[] split1 = s.split(",");
|
LonLatDto lonLatDto = new LonLatDto(Double.parseDouble(split1[0]), Double.parseDouble(split1[1]));
|
lonLatDtos.add(lonLatDto);
|
}
|
routeVo.setPolyline(lonLatDtos);
|
routeVo.setRouteID(routeID);
|
log.info("导航 {} 在 {} 运营区域内", routeVo.getRouteID(), fenceId);
|
list.add(routeVo);
|
}
|
}
|
return list;
|
|
}
|
|
|
class ArrayPointsTask extends RecursiveTask<Long> {
|
//最大定位集合阈值
|
private final int THRESHOLD = 10;
|
//围栏ID
|
String fenceId;
|
//定位点集合
|
List<LonLatDto> pointsArray;
|
|
|
public ArrayPointsTask(List<LonLatDto> pointsArray, String fenceId) {
|
this.pointsArray = pointsArray;
|
this.fenceId = fenceId;
|
}
|
|
@Override
|
protected Long compute() {
|
if (this.pointsArray.size() > THRESHOLD) {
|
int num = this.pointsArray.size() / 2;
|
ArrayPointsTask task1 = new ArrayPointsTask(this.pointsArray.subList(0, num), fenceId);
|
ArrayPointsTask task2 = new ArrayPointsTask(this.pointsArray.subList(num, this.pointsArray.size()), fenceId);
|
task1.fork();
|
task2.fork();
|
return task1.join() + task2.join();
|
} else {
|
long temp = 0;
|
for (LonLatDto lonLatDto : this.pointsArray) {
|
if (!xpGeoFencingPolygonService.isInFence(lonLatDto.getLongitude(), lonLatDto.getLatitude(), fenceId, "operating_area")) {
|
temp++;
|
break;
|
}
|
}
|
return temp;
|
}
|
}
|
}
|
|
|
/**
|
* 线路还原接口
|
* 车端使用的数据
|
*
|
* @param routeID
|
* @return
|
*/
|
public String routed(String routeID) {
|
String url = mapApiProperties.getUrls().getRouteQuery() + "?key=" + mapApiProperties.getApiKey();
|
HashMap<String, Object> params = new HashMap<>();
|
params.put("routeID", routeID);
|
params.put("sdkVersion", "9.850.152.3.532");
|
params.put("encoderVersion", "5.1");
|
params.put("pushDataNaviVersion", "1.0");
|
String post = HttpUtils.post(url, JSON.toJSONString(params));
|
log.info("高德地图: routeId:{} 结果: {}", routeID, post);
|
return post;
|
}
|
|
|
/**
|
* 根据经纬度获取行政区域信息
|
*
|
* @param lon
|
* @param lan
|
* @return
|
* @throws Exception
|
*/
|
public Map<String, String> geocode(String lon, String lan) {
|
String url = mapApiProperties.getUrls().getReverseGeocode() + "?key=" + mapApiProperties.getApiKey() + "&location=" + lon + "," + lan;
|
String forObject = HttpUtils.sendGet(url);
|
JSONObject jsonObject = JSON.parseObject(forObject);
|
Map<String, String> map = new HashMap<>();
|
if (jsonObject.getString("status").equals("1")) {
|
JSONObject regeocode = jsonObject.getJSONObject("regeocode");
|
JSONObject addressComponent = regeocode.getJSONObject("addressComponent");
|
String address = regeocode.getString("formatted_address");
|
map.put("address", address);
|
String code = addressComponent.getString("adcode");
|
String province = addressComponent.getString("province");
|
String city = addressComponent.getString("city");
|
String district = addressComponent.getString("district");
|
map.put("province", province);
|
map.put("provinceCode", code.substring(0, 2) + "0000");
|
map.put("city", city);
|
map.put("cityCode", code.substring(0, 4) + "00");
|
map.put("district", district);
|
map.put("districtCode", code);
|
}
|
return map;
|
}
|
|
}
|