From 59782d1d8abc7a98111459349b4fddf45d286866 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E7=8E=89=E4=B8=9C?= <129883742+liyudong2018@users.noreply.github.com> Date: Thu, 18 Sep 2025 23:33:24 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E7=9B=B8=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/demo.html | 131 +++++++-------- src/main/java/com/hivekion/Test.java | 18 +- .../common/MultiPointGeoPosition.java | 18 ++ .../com/hivekion/enums/WsCmdTypeEnum.java | 24 +++ .../com/hivekion/room/bean/MoveRootTask.java | 158 +++++++++++++++--- .../java/com/hivekion/room/bean/Room.java | 2 +- .../service/impl/ScenarioTaskServiceImpl.java | 2 +- .../service/impl/StatisticServiceImpl.java | 17 +- src/main/java/com/hivekion/ws/WsServer.java | 4 +- .../resources/application-rule.properties | 0 10 files changed, 268 insertions(+), 106 deletions(-) create mode 100644 src/main/java/com/hivekion/enums/WsCmdTypeEnum.java create mode 100644 src/main/resources/application-rule.properties diff --git a/src/main/demo.html b/src/main/demo.html index 4552271..d4dcd15 100644 --- a/src/main/demo.html +++ b/src/main/demo.html @@ -1,89 +1,86 @@ - + - - Google Map 绘制路线 - + + WS实时推送轨迹 - Google Map +
- + + \ No newline at end of file diff --git a/src/main/java/com/hivekion/Test.java b/src/main/java/com/hivekion/Test.java index e990746..3dfaf84 100644 --- a/src/main/java/com/hivekion/Test.java +++ b/src/main/java/com/hivekion/Test.java @@ -1,5 +1,8 @@ package com.hivekion; +import java.util.NavigableMap; +import java.util.TreeMap; + /** * [类的简要说明] *

@@ -12,13 +15,12 @@ package com.hivekion; public class Test { public static void main(String[] args) { - String test = "id\n" - + "general_time\n" - + "from_resource_id\n" - + "supplier_type\n" - + "supplier_num\n" - + "lat\n" - + "lng"; - System.out.println(test.toUpperCase()); + TreeMap treeMap = new TreeMap(); + treeMap.put(new Double("1"), "1"); + treeMap.put(new Double("5"), "1"); + treeMap.put(new Double("9"), "1"); + treeMap.put(new Double("20"), "1"); + treeMap.put(new Double("21"), "1"); + System.out.println(treeMap.ceilingKey(new Double("22"))); ; } } diff --git a/src/main/java/com/hivekion/common/MultiPointGeoPosition.java b/src/main/java/com/hivekion/common/MultiPointGeoPosition.java index de99522..3ab572d 100644 --- a/src/main/java/com/hivekion/common/MultiPointGeoPosition.java +++ b/src/main/java/com/hivekion/common/MultiPointGeoPosition.java @@ -40,6 +40,7 @@ public class MultiPointGeoPosition { } public static double[] interpolate(double lat1, double lon1, double lat2, double lon2, double f) { + lat1 = toRadians(lat1); lon1 = toRadians(lon1); lat2 = toRadians(lat2); @@ -118,4 +119,21 @@ public class MultiPointGeoPosition { PositionResult pos = getPosition(points, speed, time); System.out.printf("当前位置:纬度 %.6f, 经度 %.6f, 是否到达:%s\n", pos.latitude, pos.longitude, pos.reached ? "是" : "否"); } + /** + * 沿球面大圆,从起点(lat1, lon1)出发,沿着到终点(lat2, lon2)方向,距离为d(米)的位置点 + * 若d >= 起点到终点距离,则返回终点 + * @param lat1 起点纬度 + * @param lon1 起点经度 + * @param lat2 终点纬度 + * @param lon2 终点经度 + * @param d 距起点的距离(米) + * @return double[]{纬度, 经度} + */ + public static double[] pointAlong(double lat1, double lon1, double lat2, double lon2, double d) { + double L = haversine(lat1, lon1, lat2, lon2); + if (d <= 0) return new double[] {lat1, lon1}; + if (d >= L) return new double[] {lat2, lon2}; + double f = d / L; + return interpolate(lat1, lon1, lat2, lon2, f); + } } \ No newline at end of file diff --git a/src/main/java/com/hivekion/enums/WsCmdTypeEnum.java b/src/main/java/com/hivekion/enums/WsCmdTypeEnum.java new file mode 100644 index 0000000..1b00d81 --- /dev/null +++ b/src/main/java/com/hivekion/enums/WsCmdTypeEnum.java @@ -0,0 +1,24 @@ +package com.hivekion.enums; + +import lombok.Getter; + +/** + * [类的简要说明] + *

+ * [详细描述,可选] + *

+ * + * @author LiDongYU + * @since 2025/7/22 + */ +public enum WsCmdTypeEnum { + PATH_UPDATE("path_update"), + PATH_FINISHED("path_finished"), + PATH_INIT("path_init"); + @Getter + private final String code; + + WsCmdTypeEnum(String code) { + this.code = code; + } +} diff --git a/src/main/java/com/hivekion/room/bean/MoveRootTask.java b/src/main/java/com/hivekion/room/bean/MoveRootTask.java index 3a1ebce..052bf82 100644 --- a/src/main/java/com/hivekion/room/bean/MoveRootTask.java +++ b/src/main/java/com/hivekion/room/bean/MoveRootTask.java @@ -7,13 +7,21 @@ import com.alibaba.fastjson2.JSONObject; import com.hivekion.Global; import com.hivekion.common.MultiPointGeoPosition; import com.hivekion.common.entity.ResponseCmdInfo; +import com.hivekion.enums.WsCmdTypeEnum; import com.hivekion.room.func.TaskAction; import com.hivekion.scenario.entity.ScenarioTask; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import java.util.NavigableMap; import java.util.TreeMap; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.springframework.core.env.Environment; @@ -29,12 +37,19 @@ import org.springframework.core.env.Environment; @Slf4j public class MoveRootTask extends AbtParentTask implements TaskAction { + /** + * 速度 换算为100Km/小时 + */ + private final double SPEED = 27; + /** + * 距离和坐标的对应关系 + */ + private final TreeMap distanceInfoMap = new TreeMap<>(); + /** + * 开始点坐标 + */ + private final AtomicReference startPoint = new AtomicReference<>(); - private final double SPEED = 170;//速度 - private double accumulatedDistance = 0;//累计距离 - private final Map distanceInfoMap = new TreeMap();//距离和坐标点对应关系 - private Double beforeLng = null;//上一次经度 - private Double beforeLat = null; //上一次纬度 public MoveRootTask(ScenarioTask scenarioTask, String roomId) { super(scenarioTask, roomId); @@ -53,9 +68,7 @@ public class MoveRootTask extends AbtParentTask implements TaskAction { */ private void initPath() { try { - beforeLng = Double.parseDouble(scenarioTask.getFromLng()); - beforeLat = Double.parseDouble(scenarioTask.getFromLat()); - //累计距离 + String url = SpringUtil.getBean(Environment.class).getProperty("path.planning.url"); String params = url + "?" + "profile=car" @@ -65,35 +78,56 @@ public class MoveRootTask extends AbtParentTask implements TaskAction { + scenarioTask.getToLng() + "&points_encoded=false" + "&algorithm=alternative_route&alternative_route.max_paths=3"; - log.info("params::{}", params); + //获取路线信息 String result = webClient.get().uri(params) .retrieve() .bodyToMono(String.class) .block(); - log.info("result:{}", result); + JSONObject pointJson = JSON.parseObject(result); //获取路径点 if (pointJson != null) { JSONObject pointsObj = pointJson.getJSONArray("paths").getJSONObject(0) .getJSONObject("points"); - + JSONArray coordinates = pointsObj.getJSONArray("coordinates"); + //组装信息 + Map dataMap = new HashMap<>(); + dataMap.put("resourceId", scenarioTask.getResourceId()); + dataMap.put("points", coordinates); //推送路径任务 Global.sendCmdInfoQueue.add( - ResponseCmdInfo.create("path_init", roomId, scenarioTask.getScenarioId(), pointsObj)); - - JSONArray coordinates = pointsObj.getJSONArray("coordinates"); - + ResponseCmdInfo.create(WsCmdTypeEnum.PATH_INIT.getCode(), roomId, + scenarioTask.getScenarioId(), dataMap)); + log.info("init::{}", JSON.toJSONString(coordinates)); + //计算各个点的累计距离和坐标的对应关系 + double beforeLng = Double.parseDouble(scenarioTask.getFromLng()); + double beforeLat = Double.parseDouble(scenarioTask.getFromLat()); + double total = 0; for (int i = 0; i < coordinates.size(); i++) { JSONArray coordinate = coordinates.getJSONArray(i); Double lng = coordinate.getDouble(0); + Double lat = coordinate.getDouble(1); - double distance = MultiPointGeoPosition.haversine(beforeLat, beforeLng, lng, lat); - distanceInfoMap.put(distance, lng + "," + lat); + + double distance = MultiPointGeoPosition.haversine(beforeLat, beforeLng, lat, lng); + //当前总距离 + total = total + distance; + //定义坐标对象 + Coordinate coordinateInfo = new Coordinate(); + coordinateInfo.setLat(lat); + coordinateInfo.setLng(lng); + + //记录距离和数组列表直接的索引关系 + distanceInfoMap.put(total, coordinateInfo); + beforeLng = lng; beforeLat = lat; } + //设置第一个开始位置 + startPoint.set(distanceInfoMap.firstKey()); } + } catch (Exception e) { log.error("error::", e); } @@ -104,14 +138,96 @@ public class MoveRootTask extends AbtParentTask implements TaskAction { ScheduledExecutorService schedule = Executors.newScheduledThreadPool( 1); schedule.scheduleWithFixedDelay(() -> { - long duringTime = getDuringTime(); - // - double distance = duringTime * SPEED; - + + try { + if (this.getRoomStatus()) { + + long duringTime = getDuringTime(); + log.info("duringTime::{}", duringTime); + //跑动距离 + double distance = duringTime * SPEED; + //获取大与此距离的第一个路线点key + Entry endPoint = distanceInfoMap.ceilingEntry(distance); + //ws数据 + List dataList = new ArrayList<>(); + HashMap dataMap = new HashMap<>(); + dataMap.put("resourceId", scenarioTask.getResourceId()); + dataMap.put("points", dataList); + + if (Double.compare(distance, endPoint.getKey()) < 0) { + //获取小于最大值的第一个key + Double lowerKey = distanceInfoMap.lowerKey(endPoint.getKey()); + // log.info("distance::{},lowerKey::{},endPoint{}",distance,lowerKey,endPoint.getKey()); + //获取从上一个开始节点到lowKey的数据 + NavigableMap subPathMap = distanceInfoMap.subMap(startPoint.get(), + true, lowerKey, true); + for (Double key : subPathMap.keySet()) { + Coordinate coordinate = subPathMap.get(key); + dataList.add(new double[]{coordinate.getLng(), coordinate.getLat()}); + } + double diff =distance - lowerKey ; + + //插入值 + double[] insertPoints = MultiPointGeoPosition.pointAlong( + distanceInfoMap.get(lowerKey).getLat(), distanceInfoMap.get(lowerKey).getLng(), + endPoint.getValue().getLat(), endPoint.getValue().getLng(), diff); + + + + dataList.add(new double[]{insertPoints[1], insertPoints[0]}); + + Coordinate coordinate = new Coordinate(); + coordinate.setLat(insertPoints[0]); + coordinate.setLng(insertPoints[1]); + distanceInfoMap.put(distance, coordinate); + startPoint.set(distance); + + + Global.sendCmdInfoQueue.add( + ResponseCmdInfo.create(WsCmdTypeEnum.PATH_UPDATE.getCode(), roomId, + scenarioTask.getScenarioId(), dataMap)); + + } else if (Double.compare(distance, endPoint.getKey()) == 0) { + NavigableMap subPathMap = distanceInfoMap.subMap(startPoint.get(), + true, endPoint.getKey(), true); + for (Double key : subPathMap.keySet()) { + Coordinate coordinate = subPathMap.get(key); + dataList.add(new double[]{coordinate.getLng(), coordinate.getLat()}); + } + + startPoint.set(endPoint.getKey()); + Global.sendCmdInfoQueue.add( + ResponseCmdInfo.create(WsCmdTypeEnum.PATH_UPDATE.getCode(), roomId, + scenarioTask.getScenarioId(), dataMap)); + + } else { + //完成路径 + Global.sendCmdInfoQueue.add( + ResponseCmdInfo.create(WsCmdTypeEnum.PATH_FINISHED.getCode(), roomId, + scenarioTask.getScenarioId(), dataMap)); + } + + + + } + } catch (Exception e) { + log.error("error::", e); + } + }, 0, 1, TimeUnit.SECONDS); //房间统一管理定时器;房间关闭后,定时器销毁 addScheduledExecutorServiceRefenceToRoom(schedule); } + + +} + +@Data +class Coordinate { + + double lng; + double lat; + } diff --git a/src/main/java/com/hivekion/room/bean/Room.java b/src/main/java/com/hivekion/room/bean/Room.java index d336568..5ac43d9 100644 --- a/src/main/java/com/hivekion/room/bean/Room.java +++ b/src/main/java/com/hivekion/room/bean/Room.java @@ -132,7 +132,7 @@ public class Room implements AutoCloseable { if (magValue != null) { this.mag = magValue.getMag(); } - + log.info("mag:{}", mag); long curTime = duringTime.addAndGet(this.mag); sendRemainTime((totalTime.get() - curTime)); diff --git a/src/main/java/com/hivekion/scenario/service/impl/ScenarioTaskServiceImpl.java b/src/main/java/com/hivekion/scenario/service/impl/ScenarioTaskServiceImpl.java index cd9524c..8c9814c 100644 --- a/src/main/java/com/hivekion/scenario/service/impl/ScenarioTaskServiceImpl.java +++ b/src/main/java/com/hivekion/scenario/service/impl/ScenarioTaskServiceImpl.java @@ -148,7 +148,7 @@ public class ScenarioTaskServiceImpl extends try { long diff = Duration.between(scenario.getStartTime(),task.getStartTime()) .getSeconds(); - log.info("diff::{},taskType::{}",diff,task.getTaskType()); + switch (task.getTaskType()) { //移动任务 case "1": diff --git a/src/main/java/com/hivekion/statistic/service/impl/StatisticServiceImpl.java b/src/main/java/com/hivekion/statistic/service/impl/StatisticServiceImpl.java index f296fbf..63373de 100644 --- a/src/main/java/com/hivekion/statistic/service/impl/StatisticServiceImpl.java +++ b/src/main/java/com/hivekion/statistic/service/impl/StatisticServiceImpl.java @@ -62,12 +62,17 @@ public class StatisticServiceImpl implements StatisticService { List orgList = orgPostList.stream().map(ScenarioOrgPost::getOrgId) .collect(Collectors.toList()); //获取人员信息 - List staffList = fightpowerstaffService.queryByOrgIds(orgList); - int sum = staffList.stream() - .mapToInt(Fightpowerstaff::getNumber) - .sum(); - statisticBean.getPerson().setCurrent(sum); - statisticBean.getPerson().setTotal(sum); + if(!orgList.isEmpty()){ + List staffList = fightpowerstaffService.queryByOrgIds(orgList); + int sum = staffList.stream() + .mapToInt(Fightpowerstaff::getNumber) + .sum(); + statisticBean.getPerson().setCurrent(sum); + statisticBean.getPerson().setTotal(sum); + }else{ + return statisticBean; + } + //获取物资信息 List suppliers = orgSupplierService.selectByOrgIds(orgList); diff --git a/src/main/java/com/hivekion/ws/WsServer.java b/src/main/java/com/hivekion/ws/WsServer.java index 0d4ab97..d8d1222 100644 --- a/src/main/java/com/hivekion/ws/WsServer.java +++ b/src/main/java/com/hivekion/ws/WsServer.java @@ -111,11 +111,11 @@ public class WsServer { } public static void sendMessage(Integer scenarioId, String room, String message) { - // log.info("send {},{},{}", message, scenarioId, room); + Object lock = lockMap.computeIfAbsent(scenarioId, k -> new Object()); synchronized (lock) { Map> roomMap = SESSION_MAP.get(String.valueOf(scenarioId)); - // log.info("roomMap:{}", roomMap); + if (roomMap != null) { if (roomMap.containsKey(room)) { Map singleRoomMap = roomMap.get(room); diff --git a/src/main/resources/application-rule.properties b/src/main/resources/application-rule.properties new file mode 100644 index 0000000..e69de29