zhanghaijun лет назад: 2
Родитель
Сommit
29a5e9c950

+ 1 - 1
train-common/train-common-core/src/main/java/top/haijunit/common/config/AsyncConfig.java

@@ -41,7 +41,7 @@ public class AsyncConfig implements AsyncConfigurer {
     public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
         return (Throwable ex, Method method, Object... params) -> {
             log.error("glob async exception: {},method: {}, params: {}", ex.getMessage(), method.getName(), params);
-            ErrorUtil.errorInfoToString(ex);
+            log.error(ErrorUtil.errorInfoToString(ex));
         };
     }
 }

+ 0 - 8
train-server/src/main/java/top/haijunit/train/domain/entity/RouteEntity.java

@@ -110,14 +110,6 @@ public class RouteEntity implements Serializable {
         return map;
     }
 
-    /** 是否触发进路 */
-    public boolean isTrigger(BigDecimal kilometer, DirectionEnum direction) {
-        return switch (direction) {
-            case UP -> NumberUtil.isLessOrEqual(kilometer, this.getTrigPosition());
-            case DOWN -> NumberUtil.isGreaterOrEqual(kilometer, this.getTrigPosition());
-        };
-    }
-
     // 进路中是否包括该区段
     public boolean isContain(Long selectionId) {
         return this.getSelectionList().contains(selectionId);

+ 4 - 4
train-server/src/main/java/top/haijunit/train/domain/entity/SelectionEntity.java

@@ -74,10 +74,10 @@ public class SelectionEntity implements Serializable {
             return false;
         }
         return switch (direction) {
-            // 上行 车尾 <= 区段的开始里程
-            case UP -> NumberUtil.isLessOrEqual(tailKilometer, this.getStartKilometer());
-            // 下行 车位 > 区段的结束里程
-            case DOWN -> NumberUtil.isGreater(tailKilometer, this.getEndKilometer());
+            // 上行 车尾 < 区段的开始里程
+            case UP -> NumberUtil.isLess(tailKilometer, this.getStartKilometer());
+            // 下行 车位 >= 区段的结束里程
+            case DOWN -> NumberUtil.isGreaterOrEqual(tailKilometer, this.getEndKilometer());
         };
     }
 

+ 4 - 5
train-server/src/main/java/top/haijunit/train/listener/ReportTimeHandle.java

@@ -34,7 +34,7 @@ public class ReportTimeHandle {
 
     /** 定时发送列车位置数据 */
     @Async
-    @Scheduled(fixedDelay = 500)
+    @Scheduled(fixedDelay = 1000)
     public void sendTrainPositionList() {
         for (TrainItem trainItem : TrainSimulationHolder.getTrainItem()) {
             TrainWebSocketUtils.sendMessage(CommandEnum.TRAIN, trainItem);
@@ -43,14 +43,14 @@ public class ReportTimeHandle {
 
     /** 定时发送进路占用数据 */
     @Async
-    @Scheduled(fixedDelay  = 500)
+    @Scheduled(fixedDelay = 1000)
     public void sendRouterStatus() {
         Map<Long, LinkedList<RouteItem>> routeMap = TrainSimulationHolder.getRouteMap();
         TrainWebSocketUtils.sendMessage(CommandEnum.ROUTE_STATUS, new HashMap<>(routeMap));
         log.info("------------");
         for (Map.Entry<Long, LinkedList<RouteItem>> entry : routeMap.entrySet()) {
             log.info("进路资源, 列车:{},进路:{}", entry.getKey(), entry.getValue().stream().map(item -> {
-                return item.getName() + "--" + item.getRouteStatus().getDescribe();
+                return item.getId() + "--" + item.getRouteStatus().getDescribe();
             }).collect(Collectors.joining(",")));
         }
         log.info("------------");
@@ -58,7 +58,7 @@ public class ReportTimeHandle {
 
     /** 定时计算进路 */
     @Async
-    @Scheduled(fixedRate = 500)
+    @Scheduled(fixedDelay = 1000)
     public void runRouteCompute() {
         for (TrainItem trainItem : TrainSimulationHolder.getTrainItem()) {
             routeComputerService.run(trainItem);
@@ -66,7 +66,6 @@ public class ReportTimeHandle {
     }
 
     @Async
-    @Scheduled(fixedRate = 500)
     public void runTrainCompute() {
         for (TrainItem trainItem : TrainSimulationHolder.getTrainItem()) {
             trainComputerService.run(trainItem);

+ 5 - 1
train-server/src/main/java/top/haijunit/train/listener/TrainApplication.java

@@ -12,6 +12,7 @@ import top.haijunit.train.service.SelectionService;
 import top.haijunit.train.simulation.domain.TrainItem;
 import top.haijunit.train.simulation.train.TrainSimulationHolder;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -29,7 +30,10 @@ public class TrainApplication implements ApplicationRunner {
 
     @Override
     public void run(ApplicationArguments args) {
-        List<TrainEntity> list = trainRepository.findAll();
+        // List<TrainEntity> list = trainRepository.findAll();
+        List<TrainEntity> list = trainRepository.findAllById(new ArrayList<>() {{
+            add(110004L);
+        }});
         for (TrainEntity train : list) {
             SelectionEntity selection = selectionService.getSelection(train.getInitKilometer(), train.getInitDirection());
             if (selection == null) {

+ 54 - 15
train-server/src/main/java/top/haijunit/train/service/RouteService.java

@@ -1,8 +1,11 @@
 package top.haijunit.train.service;
 
+import cn.hutool.core.collection.CollUtil;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
+import top.haijunit.common.utils.StreamUtils;
+import top.haijunit.train.domain.constant.RouteStatusEnum;
 import top.haijunit.train.domain.entity.RouteEntity;
 import top.haijunit.train.domain.entity.SelectionEntity;
 import top.haijunit.train.domain.entity.SignalEntity;
@@ -12,8 +15,8 @@ import top.haijunit.train.domain.repository.SignalRepository;
 import top.haijunit.train.simulation.domain.RouteItem;
 import top.haijunit.train.simulation.domain.TrainItem;
 
-import java.util.LinkedList;
-import java.util.List;
+import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * @author zhanghaijun
@@ -28,6 +31,7 @@ public class RouteService {
     private final RouteRepository routeRepository;
     private final SelectionRepository selectionRepository;
     private final SignalRepository signalRepository;
+    private final SelectionService selectionService;
 
     public RouteItem toBuildRoute(RouteEntity route) {
         if (route == null) {
@@ -39,21 +43,56 @@ public class RouteService {
     }
 
     public RouteItem getNextRoute(RouteItem route) {
-        return routeRepository.findById(route.getNextId())
-            // 类型转换
-            .map(this::toBuildRoute).orElse(null);
-    }
-
-    public RouteItem getCurrentRoute(Long selectionId) {
-        return routeRepository.findAll().stream()
-            // 过滤出当前区段所在的进路
-            .filter(item -> item.isContain(selectionId)).findFirst()
-            // 转换类型
-            .map(this::toBuildRoute).orElse(null);
+        Optional<RouteEntity> optional = routeRepository.findById(route.getNextId());
+        if (optional.isEmpty()) {
+            return null;
+        }
+        RouteEntity entity = optional.get();
+        LinkedList<SelectionEntity> selectionList = selectionService.getSelectionList(entity.getId());
+        // TODO 信号灯
+        RouteItem routeItem = new RouteItem(entity, selectionList, new LinkedList<>());
+        routeItem.setStatus(RouteStatusEnum.LOCK);
+        return routeItem;
     }
 
-    public RouteItem getCurrentRoute(TrainItem train) {
-        return getCurrentRoute(train.getSelectionId());
+    public LinkedList<RouteItem> getCurrentRouteList(TrainItem train) {
+        LinkedList<RouteEntity> list = new LinkedList<>();
+        for (RouteEntity route : routeRepository.findAll()) {
+            List<SelectionEntity> selectionList = selectionRepository.findAllById(route.getSelectionList());
+            for (SelectionEntity selection : selectionList) {
+                if (!StreamUtils.filter(list, item -> item.getId().equals(route.getId())).isEmpty()) {
+                    continue;
+                }
+                if (selection.isContain(train.getHeadKilometer(), train.getDirection())) {
+                    switch (selection.getDirection()) {
+                        case UP:
+                            list.addFirst(route);
+                            break;
+                        case DOWN:
+                            list.addLast(route);
+                    }
+                }
+                if (!StreamUtils.filter(list, item -> item.getId().equals(route.getId())).isEmpty()) {
+                    continue;
+                }
+                if (selection.isContain(train.getTailKilometer(), train.getDirection())) {
+                    switch (selection.getDirection()) {
+                        case UP:
+                            list.addLast(route);
+                            break;
+                        case DOWN:
+                            list.addFirst(route);
+                    }
+                }
+            }
+        }
+        return list.stream().map(entity -> {
+            LinkedList<SelectionEntity> selectionList = selectionService.getSelectionList(entity.getId(), train.getDirection(), train.getHeadKilometer(), train.getTailKilometer());
+            // TODO 型号灯
+            RouteItem routeItem = new RouteItem(entity, selectionList, new LinkedList<>());
+            routeItem.setStatus(RouteStatusEnum.OCCUPY);
+            return routeItem;
+        }).collect(Collectors.toCollection(LinkedList::new));
     }
 
 }

+ 6 - 6
train-server/src/main/java/top/haijunit/train/service/SelectionService.java

@@ -46,8 +46,8 @@ public class SelectionService {
      * @param route 进路
      * @return 进路中的区段
      */
-    public LinkedList<SelectionEntity> getSelectionList(RouteItem route) {
-        ArrayList<Long> seleIds = routeRepository.findById(route.getId()).map(RouteEntity::getSelectionList).orElseThrow(() -> new IllegalArgumentException("进路不存在,进路Id:" + route.getId()));
+    public LinkedList<SelectionEntity> getSelectionList(Long routeId) {
+        ArrayList<Long> seleIds = routeRepository.findById(routeId).map(RouteEntity::getSelectionList).orElseThrow(() -> new IllegalArgumentException("进路不存在,进路Id:" + routeId));
         List<SelectionEntity> selectionList = selectionRepository.findAllById(seleIds);
         for (SelectionEntity entity : selectionList) {
             entity.setStatus(RouteStatusEnum.LOCK);
@@ -63,14 +63,14 @@ public class SelectionService {
      * @param tailKilometer 车位
      * @return 进路中未驶过的区段
      */
-    public LinkedList<SelectionEntity> getSelectionList(RouteItem route, BigDecimal headKilometer, BigDecimal tailKilometer) {
-        ArrayList<Long> seleIds = routeRepository.findById(route.getId()).map(RouteEntity::getSelectionList).orElseThrow(() -> new IllegalArgumentException("进路不存在,进路Id:" + route.getId()));
+    public LinkedList<SelectionEntity> getSelectionList(Long routeId, DirectionEnum direction, BigDecimal headKilometer, BigDecimal tailKilometer) {
+        ArrayList<Long> seleIds = routeRepository.findById(routeId).map(RouteEntity::getSelectionList).orElseThrow(() -> new IllegalArgumentException("进路不存在,进路Id:" + routeId));
         List<SelectionEntity> selectionList = selectionRepository.findAllById(seleIds);
         LinkedList<SelectionEntity> list = new LinkedList<>();
         for (SelectionEntity entity : selectionList) {
-            if (entity.isNonPass(headKilometer, tailKilometer, route.getDirection())) {
+            if (entity.isNonPass(headKilometer, tailKilometer, direction)) {
                 // 列车还未驶过该区段
-                if (entity.isContain(headKilometer, route.getDirection()) || entity.isContain(tailKilometer, route.getDirection())) {
+                if (entity.isContain(headKilometer, direction) || entity.isContain(tailKilometer, direction)) {
                     // 车头或者车尾在区段内,则是占用状态
                     entity.setStatus(RouteStatusEnum.OCCUPY);
                 } else {

+ 13 - 9
train-server/src/main/java/top/haijunit/train/simulation/domain/RouteItem.java

@@ -90,17 +90,17 @@ public class RouteItem implements Serializable {
      * @return 是否已经通过当前进路
      */
     public boolean isPass(BigDecimal headKilometer, BigDecimal tailKilometer, DirectionEnum direction) {
-        if (isContain(headKilometer, direction)) {
+        if (!isContain(headKilometer, direction)) {
             return true;
         }
-        if (isContain(tailKilometer, direction)) {
+        if (!isContain(tailKilometer, direction)) {
             return true;
         }
         return switch (direction) {
-            // 上行 车尾 <= 进路的开始里程
-            case UP -> NumberUtil.isLessOrEqual(tailKilometer, this.getHeadKilometer());
-            // 下行 车位 > 进路的结束里程
-            case DOWN -> NumberUtil.isGreater(tailKilometer, this.getTailKilometer());
+            // 上行 车尾 < 进路的开始里程
+            case UP -> NumberUtil.isLess(tailKilometer, this.getHeadKilometer());
+            // 下行 车位 => 进路的结束里程
+            case DOWN -> NumberUtil.isGreaterOrEqual(tailKilometer, this.getTailKilometer());
         };
     }
 
@@ -112,12 +112,16 @@ public class RouteItem implements Serializable {
         }
         return switch (direction) {
             // 上行 进路开始公里数 <= 车头公里数 <= 触发点公里数
-            case UP -> NumberUtil.isIn(kilometer, this.getHeadKilometer(), this.getTrigPosition());
+            case UP -> NumberUtil.isIn(kilometer, this.getHeadKilometer(), this.getTrigKilometer());
             // 下行 触发点公里数 <= 车头公里数 <= 进路结束公里数
-            case DOWN -> NumberUtil.isIn(kilometer, this.getTrigPosition(), this.getTailKilometer());
+            case DOWN -> NumberUtil.isIn(kilometer, this.getTrigKilometer(), this.getTailKilometer());
         };
     }
 
+    public BigDecimal getTrigKilometer() {
+        return this.getHeadKilometer().add(this.getTrigPosition());
+    }
+
 
     // 是否包含道岔
     public boolean isEmptySwitch() {
@@ -125,7 +129,7 @@ public class RouteItem implements Serializable {
     }
 
     // 改变状态
-    public void setStatus(RouteStatusEnum status){
+    public void setStatus(RouteStatusEnum status) {
         this.routeStatus = status;
     }
 }

+ 16 - 5
train-server/src/main/java/top/haijunit/train/simulation/domain/TrainItem.java

@@ -39,10 +39,8 @@ public class TrainItem {
     // 偏移
     private BigDecimal offset;
 
-    @Setter
     private LocalTime updateTime;
     // 运行速度
-    @Setter
     private BigDecimal speed;
     // 运行加速度
     @Setter
@@ -54,10 +52,10 @@ public class TrainItem {
         this.trainNo = train.getName();
         this.kilometer = train.getInitKilometer();
         this.direction = train.getInitDirection();
-        this.setHeadKilometer(train.getInitKilometer(), selection);
-        this.updateTime = LocalTime.now();
         this.speed = new BigDecimal("0.00");
         this.acceleration = new BigDecimal("0.00");
+        this.updateTime = LocalTime.now();
+        this.setHeadKilometer(LocalTime.now(), train.getInitKilometer(), selection);
     }
 
     // 区段Id
@@ -70,7 +68,20 @@ public class TrainItem {
         return this.kilometer;
     }
 
-    public void setHeadKilometer(BigDecimal kilometer, SelectionEntity selection) {
+    /**
+     * 更新列车位置信息
+     *
+     * @param updateTime 更新时间
+     * @param kilometer  公里标
+     * @param selection  区段
+     */
+    public void setHeadKilometer(LocalTime updateTime, BigDecimal kilometer, SelectionEntity selection) {
+        if (this.getUpdateTime() == null) {
+            return;
+        }
+        BigDecimal v = CalculatorUtil.velocity(this.getSpeed(), this.getAcceleration(), Duration.between(this.getUpdateTime(), updateTime).abs());
+        this.updateTime = updateTime;
+        this.speed = v;
         this.kilometer = kilometer;
         this.blockId = selection.getId();
         this.blockNo = selection.getName();

+ 12 - 16
train-server/src/main/java/top/haijunit/train/simulation/train/RouteComputerService.java

@@ -1,5 +1,6 @@
 package top.haijunit.train.simulation.train;
 
+import cn.hutool.core.collection.CollUtil;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
@@ -26,7 +27,6 @@ public class RouteComputerService {
 
     private final SwitchService switchService;
     private final RouteService routeService;
-    private final SelectionService selectionService;
 
     public void run(TrainItem train) {
         // 更新进路共享数据
@@ -42,26 +42,24 @@ public class RouteComputerService {
         // 6、释放车尾已过的进路
         LinkedList<RouteItem> routeList = TrainSimulationHolder.getRouteList(train.getTrainId());
         RouteItem currentRoute = TrainSimulationHolder.getCurrentRoute(train);
+        // 释放资源 进路的全部区段的公里标 小于 当前列车所在的区段
+        routeList.removeIf(item -> item.isPass(train.getHeadKilometer(), train.getTailKilometer(), train.getDirection()));
         if (null == currentRoute) {
             log.info("初始化,没有找到当前的进路信息,列车: {}", train.getTrainId());
             // 初始化为空处理
-            currentRoute = routeService.getCurrentRoute(train);
-            if (null == currentRoute) {
-                log.error("--- 计算列车的初始位置错误:方向:{},列车位置:{}", train.getDirection(), train.getKilometer());
+            routeList = routeService.getCurrentRouteList(train);
+            if (CollUtil.isEmpty(routeList)) {
+                log.error("初始化,车辆位置错误,未找到对应的进路,方向:{},列车位置:{}", train.getDirection(), train.getKilometer());
                 return routeList;
             }
-            LinkedList<SelectionEntity> list = selectionService.getSelectionList(currentRoute, train.getHeadKilometer(), train.getTailKilometer());
-            if (list.isEmpty()) {
-                log.error("--- 进路的区段计算错误:进路:{},列车位置:{}", currentRoute.getId(), train.getKilometer());
-                return routeList;
+            currentRoute = switch (train.getDirection()) {
+                case UP -> routeList.getFirst();
+                case DOWN -> routeList.getLast();
+            };
+            if (currentRoute.getSelectionList().isEmpty()) {
+                log.error("错误进路中区段占用为空:进路:{},列车位置:{}", currentRoute.getId(), train.getKilometer());
             }
-            currentRoute.setStatus(RouteStatusEnum.OCCUPY);
-            currentRoute.setSelectionList(list);
-            routeList = new LinkedList<>();
-            routeList.add(currentRoute);
         }
-        // 释放资源 进路的全部区段的公里标 小于 当前列车所在的区段
-        routeList.removeIf(item -> item.isPass(train.getHeadKilometer(), train.getTailKilometer(), train.getDirection()));
         // 开始计算下一跳进路
         if (!currentRoute.isTrigger(train.getHeadKilometer(), train.getDirection())) {
             // 没有触发进路
@@ -82,8 +80,6 @@ public class RouteComputerService {
             return routeList;
         }
         // c)出清(如果包括道岔,道岔已就位),将进路至于锁闭状态
-        nextRoute.setStatus(RouteStatusEnum.LOCK);
-        nextRoute.setSelectionList(selectionService.getSelectionList(nextRoute));
         routeList.addLast(nextRoute);
         return routeList;
     }

+ 3 - 3
train-server/src/main/java/top/haijunit/train/simulation/train/TrainComputerService.java

@@ -44,18 +44,18 @@ public class TrainComputerService {
             case DOWN -> kilometer = kilometer.add(decimal).abs();
         }
         SelectionEntity selection = selectionService.getSelection(kilometer, trainItem.getDirection());
-        trainItem.setHeadKilometer(kilometer, selection);
+        trainItem.setHeadKilometer(now, kilometer, selection);
 
         // 更新列车运行状态
         RouteItem lastRoute = routeList.getLast();
-        new BigDecimal("0");
         // MA TODO 停车标
         BigDecimal distanceMa = switch (trainItem.getDirection()) {
             case UP -> trainItem.getHeadKilometer().subtract(lastRoute.getHeadKilometer()).abs();
             case DOWN -> trainItem.getHeadKilometer().subtract(lastRoute.getTailKilometer()).abs();
         };
         BigDecimal distance = CalculatorUtil.distance(trainItem.getSpeed(), TrainConstant.DECELERATION_LIMIT);
-        if (NumberUtil.isGreaterOrEqual(distanceMa, distance)) {
+        // log.info("列车信息:列车:{},速度:{},加速度:{}, 滑行距离:{}", trainItem.getTrainId(), trainItem.getSpeed(), trainItem.getAcceleration(), distance);
+        if (NumberUtil.isLessOrEqual(distanceMa, distance)) {
             // 紧急制动
             trainItem.setAcceleration(TrainConstant.DECELERATION_LIMIT);
         } else if (NumberUtil.isGreaterOrEqual(trainItem.getSpeed(), TrainConstant.SPEED_LIMIT_EBI)) {

+ 36 - 7
train-server/src/main/java/top/haijunit/train/utils/CalculatorUtil.java

@@ -21,25 +21,54 @@ public class CalculatorUtil {
      * @return 距离
      */
     public BigDecimal distance(BigDecimal velocity, BigDecimal acceleration) {
+        if (velocity.compareTo(BigDecimal.ZERO) == 0) {
+            return BigDecimal.ZERO;
+        }
         // 初速度平方
         BigDecimal initialVelocitySquared = velocity.pow(2);
         // 滑行距离计算公式
-        return NumberUtil.div(initialVelocitySquared, acceleration.multiply(new BigDecimal("2")));
+        BigDecimal distance = NumberUtil.div(initialVelocitySquared, acceleration.multiply(new BigDecimal("2")));
+        return distance.max(BigDecimal.ZERO);
     }
 
     /**
      * 计算指定时间内的运行距离
      *
-     * @param initialVelocity 速度
-     * @param acceleration    加速度
-     * @param time            时间
+     * @param velocity     速度
+     * @param acceleration 加速度
+     * @param time         时间
      * @return 距离
      */
-    public static BigDecimal distance(BigDecimal initialVelocity, BigDecimal acceleration, Duration time) {
+    public static BigDecimal distance(BigDecimal velocity, BigDecimal acceleration, Duration time) {
+        // 初速度为零时,运行距离为零
+        if (acceleration.compareTo(BigDecimal.ZERO) == 0) {
+            return BigDecimal.ZERO;
+        }
         // 将 Duration 转换为秒数
-        BigDecimal seconds = BigDecimal.valueOf(time.getSeconds());
+        BigDecimal seconds = BigDecimal.valueOf(time.getSeconds()).add(BigDecimal.valueOf(time.getNano(), 9));
         // 运行距离计算公式
-        return initialVelocity.multiply(seconds).add(NumberUtil.div(acceleration.multiply(NumberUtil.pow(seconds, 2)), new BigDecimal("2")));
+        BigDecimal distance = velocity.multiply(seconds).add(NumberUtil.div(acceleration.multiply(NumberUtil.pow(seconds, 2)), new BigDecimal("2")));
+        return distance.max(BigDecimal.ZERO);
+    }
 
+    /**
+     * 计算在给定时间后的速度
+     *
+     * @param Velocity     速度
+     * @param acceleration 加速度
+     * @param time         时间
+     * @return 速度
+     */
+    public static BigDecimal velocity(BigDecimal Velocity, BigDecimal acceleration, Duration time) {
+        // 如果加速度为零,速度保持不变
+        if (acceleration.compareTo(BigDecimal.ZERO) == 0) {
+            return Velocity;
+        }
+        // 将 Duration 转换为秒数
+        BigDecimal seconds = BigDecimal.valueOf(time.getSeconds());
+        // 计算当前速度
+        BigDecimal v = Velocity.add(acceleration.multiply(seconds));
+        // 将速度限制为零或更大的值
+        return v.max(BigDecimal.ZERO);
     }
 }