Преглед на файлове

fix 雷车行驶调试,数据修复

zhanghaijun преди 2 години
родител
ревизия
f61b0173a8

+ 0 - 1
train-common/train-common-websocket/src/main/java/top/haijunit/websocket/config/WebSocketConfig.java

@@ -3,7 +3,6 @@ package top.haijunit.websocket.config;
 import cn.hutool.core.util.StrUtil;
 import lombok.RequiredArgsConstructor;
 import org.springframework.boot.autoconfigure.AutoConfiguration;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.annotation.Bean;

+ 2 - 0
train-server/src/main/java/top/haijunit/train/domain/entity/SwitchEntity.java

@@ -36,6 +36,8 @@ public class SwitchEntity implements Serializable {
     private Long nextSelectionId;
     // 岔后侧向区段号
     private Long nextSideSelectionId;
+    // 区段编号
+    private Long sectionId;
     // 关联道岔
     private Long switchTie;
     // 所属车站编号

+ 4 - 0
train-server/src/main/java/top/haijunit/train/service/SectionService.java

@@ -55,6 +55,10 @@ public class SectionService {
 
     @Cacheable(cacheNames = CacheNames.SECTION, key = "'sectionId-'+#sectionId+'-direction-'+#direction.name()")
     public SectionItem getSectionItem(Long sectionId, DirectionEnum direction) {
+        List<SectionItem> filter = StreamUtils.filter(getAllSection(), item -> item.getSectionId().equals(sectionId));
+        if (filter.size() == 1) {
+            return filter.get(0);
+        }
         return StreamUtils.filter(getAllSection(), item -> {
             return item.getSectionId().equals(sectionId) && item.getDirection().equals(direction);
         }).stream().findFirst().orElseThrow(() -> new IllegalArgumentException(String.format("不存在该区段,sectionId: %s", sectionId)));

+ 13 - 8
train-server/src/main/java/top/haijunit/train/simulation/domain/TrainItem.java

@@ -24,6 +24,17 @@ public class TrainItem {
     private final BigDecimal trainLength;
     // 列车编号
     private final String trainNo;
+    // 开门状态
+    private boolean isOpenDoor = false;
+
+    // 列车数据更新时间
+    private long updateTimeMillis;
+    // 列车停车时间
+    private long stopTimeMillis;
+    // 运行速度
+    private BigDecimal speed;
+    // 运行加速度
+    private BigDecimal acceleration;
 
     // 运行方向
     private DirectionEnum direction;
@@ -34,13 +45,6 @@ public class TrainItem {
     // 偏移
     private BigDecimal offset;
 
-    private long updateTimeMillis;
-    // 运行速度
-    private BigDecimal speed;
-    // 运行加速度
-    private BigDecimal acceleration;
-
-    private boolean isOpenDoor = false;
 
     public TrainItem(TrainEntity train, String sectionName, DirectionEnum direction) {
         this.trainId = train.getId();
@@ -49,7 +53,8 @@ public class TrainItem {
         this.direction = direction;
         this.speed = new BigDecimal("0.00");
         this.acceleration = new BigDecimal("0.00");
-        this.updateTimeMillis = System.currentTimeMillis() - (TrainConstant.STOP_TIME_SECOND * 1000);
+        this.updateTimeMillis = System.currentTimeMillis();
+        this.stopTimeMillis = this.updateTimeMillis - (TrainConstant.STOP_TIME_SECOND * 1000);
         this.blockId = train.getSectionId();
         this.blockNo = sectionName;
         this.offset = train.getSectionOffset();

+ 13 - 7
train-server/src/main/java/top/haijunit/train/simulation/domain/TrainTravel.java

@@ -1,12 +1,11 @@
 package top.haijunit.train.simulation.domain;
 
+import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.StrUtil;
-import liquibase.util.StringUtil;
 import lombok.AllArgsConstructor;
 import lombok.Data;
-import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import top.haijunit.train.domain.constant.DirectionEnum;
+import top.haijunit.common.utils.StreamUtils;
 import top.haijunit.train.domain.entity.SignStopEntity;
 import top.haijunit.train.utils.NumberUtil;
 
@@ -40,10 +39,17 @@ public class TrainTravel {
     }
 
     public TravelItem travel(TrainItem train, BigDecimal distance) {
-        Optional<SectionItem> sectionOptional = sectionList.stream().filter(item -> {
-            return item.getSectionId().equals(train.getBlockId()) && item.getDirection().equals(train.getDirection());
-        }).findFirst();
-        return sectionOptional.map(sectionItem -> travel(sectionItem.getId(), train.getOffset(), distance)).orElse(null);
+        List<SectionItem> filter = StreamUtils.filter(sectionList, item -> item.getSectionId().equals(train.getBlockId()));
+        if (CollUtil.isEmpty(filter)) {
+            return null;
+        }
+        if (filter.size() > 1) {
+            Optional<SectionItem> optional = StreamUtils.findFirst(filter, item -> item.getDirection().equals(train.getDirection()));
+            if (optional.isPresent()) {
+                return this.travel(optional.get().getId(), train.getOffset(), distance);
+            }
+        }
+        return this.travel(filter.get(0).getId(), train.getOffset(), distance);
     }
 
     /**

+ 1 - 1
train-server/src/main/java/top/haijunit/train/simulation/train/ComputerService.java

@@ -53,7 +53,7 @@ public class ComputerService {
         };
         SectionItem item = sectionService.getSectionItem(uId);
         BigDecimal distanceNext = isBack ? NumberUtil.sub(item.getSectionLength(), decimal.abs()) : NumberUtil.sub(decimal, sectionItem.getSectionLength());
-        return getSectionItem(item.getSectionId(), item.getDirection(), new BigDecimal("0"), distanceNext);
+        return getSectionItem(item.getSectionId(), item.getDirection(), new BigDecimal("0"), NumberUtil.mul(distanceNext,distance.compareTo(BigDecimal.ZERO)));
     }
 
     @Deprecated

+ 18 - 28
train-server/src/main/java/top/haijunit/train/simulation/train/RouteComputerService.java

@@ -19,7 +19,6 @@ import top.haijunit.train.utils.NumberUtil;
 
 import java.math.BigDecimal;
 import java.util.ArrayList;
-import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 
@@ -113,43 +112,34 @@ public class RouteComputerService {
             add(sectionHead.getRouteId());
             add(sectionTail.getRouteId());
         }});
-        ArrayList<Long> useSectionIds = CollUtil.newArrayList(sectionHead.getSectionId(), sectionTail.getSectionId());
-        int index = StreamUtils.findIndex(sectionAll, item -> CollUtil.contains(useSectionIds, item.getSectionId()));
-        int indexLast = StreamUtils.findIndexLast(sectionAll, item -> CollUtil.contains(useSectionIds, item.getSectionId()));
-        for (int i = 0; i < sectionAll.size(); i++) {
-            if (NumberUtil.isInRange(i, index, indexLast)) {
-                sectionAll.get(i).setSectionStatus(SectionStatusEnum.OCCUPY);
+        return getSectionList(new LinkedList<>(sectionAll), sectionHead.getSectionId(), sectionTail.getSectionId());
+    }
+
+    public LinkedList<SectionItem> getSectionList(LinkedList<SectionItem> routeList, Long sectionIdByHead, Long sectionIdByTail) {
+        if (CollUtil.isEmpty(routeList)) {
+            return new LinkedList<>();
+        }
+        int indexHead = StreamUtils.findIndex(routeList, item -> item.getSectionId().equals(sectionIdByHead));
+        int indexTail = StreamUtils.findIndex(routeList, item -> item.getSectionId().equals(sectionIdByTail));
+        for (int i = 0; i < routeList.size(); i++) {
+            if (NumberUtil.isInRange(i, indexHead, indexTail)) {
+                routeList.get(i).setSectionStatus(SectionStatusEnum.OCCUPY);
             } else {
-                sectionAll.get(i).setSectionStatus(SectionStatusEnum.LOCK);
+                routeList.get(i).setSectionStatus(SectionStatusEnum.LOCK);
             }
         }
-        sectionAll.subList(0,Math.min(index,indexLast)).clear();
-        return sectionAll;
+        if (0 < Math.min(indexHead, indexTail)) {
+            routeList.subList(0, Math.min(indexHead, indexTail)).clear();
+        }
+        return routeList;
     }
 
     public LinkedList<SectionItem> getSectionList(LinkedList<SectionItem> routeList, TrainItem train) {
-        if (CollUtil.isEmpty(routeList)) {
-            return new LinkedList<>();
-        }
         // 车头所在的区段
         Long sectionIdByHead = train.getBlockId();
         // 车尾的所在的区段
         Long sectionIdByTail = computerService.getSectionItem(train, NumberUtil.mul(train.getTrainLength(), -1)).getSectionId();
-        Iterator<SectionItem> iterator = routeList.iterator();
-        boolean isPass = true;
-        while (iterator.hasNext()) {
-            SectionItem current = iterator.next();
-            if (current.getSectionId().equals(sectionIdByHead) || current.getSectionId().equals(sectionIdByTail)) {
-                isPass = false;
-                current.setSectionStatus(SectionStatusEnum.OCCUPY);
-            } else {
-                current.setSectionStatus(SectionStatusEnum.LOCK);
-            }
-            if (isPass) {
-                iterator.remove();
-            }
-        }
-        return routeList;
+        return getSectionList(routeList, sectionIdByHead, sectionIdByTail);
     }
 }
 

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

@@ -60,12 +60,19 @@ public class TrainComputerService {
         long nowMillis = System.currentTimeMillis();
         // 1、距离上一个周期 列车运行的距离
         BigDecimal distance = train.getDistance(nowMillis);
-        long timeDifference = Math.abs(nowMillis - train.getUpdateTimeMillis());
+
+        long timeDifference = Math.abs(nowMillis - train.getStopTimeMillis());
         if (NumberUtil.isLessOrEqual(distance, BigDecimal.ZERO) && timeDifference <= TrainConstant.STOP_TIME_SECOND * 1000) {
+            // 更新列车数据时间
+            train.setUpdateTimeMillis(nowMillis);
             // 停车状态 时间不足30S
             train.setOpenDoor(this.openOrCloseDoor(sectionList, train, timeDifference > (TrainConstant.STOP_TIME_SECOND - 2) * 1000 ? 0 : 1));
             return train;
         }
+        // 更新速度和时间
+        train.setSpeed(CalculatorUtil.velocity(train.getSpeed(), train.getAcceleration(), train.getUpdateTimeMillis(), nowMillis).abs());
+        // 更新列车数据时间
+        train.setUpdateTimeMillis(nowMillis);
         if (NumberUtil.isGreater(distance, BigDecimal.ZERO)) {
             Optional<SectionItem> sectionOptional = StreamUtils.filter(sectionList, item -> item.getSectionId().equals(train.getBlockId())).stream().findFirst();
             if (sectionOptional.isEmpty()) {
@@ -74,25 +81,53 @@ public class TrainComputerService {
             HashMap<Long, SignStopEntity> stopSignalMap = sectionService.getStopSignalMap();
             TrainTravel trainTravel = new TrainTravel(sectionList, stopSignalMap);
             TrainTravel.TravelItem travel = trainTravel.travel(train, distance);
-            train.setSpeed(CalculatorUtil.velocity(train.getSpeed(), train.getAcceleration(), train.getUpdateTimeMillis(), nowMillis).abs());
             train.setOffset(travel.getOffset());
             train.setBlockId(travel.getSection().getSectionId());
             train.setBlockNo(travel.getSection().getSectionName());
             train.setDirection(travel.getSection().getDirection());
-            train.setUpdateTimeMillis(nowMillis);
             if (travel.isStop()) {
                 train.setSpeed(BigDecimal.ZERO);
                 train.setAcceleration(BigDecimal.ZERO);
+                train.setStopTimeMillis(nowMillis);
                 return train;
             }
-            if (travel.getSection().isTurnBack() && NumberUtil.isGreater(travel.getOffset(), train.getTrainLength())) {
+            if (travel.getSection().isTurnBack()) {
                 // 存在折返标识 并且 列车已经全部进入区段
-                train.setOffset(BigDecimal.ZERO);
-                train.setDirection(train.getDirection() == DirectionEnum.UP ? DirectionEnum.DOWN : DirectionEnum.UP);
+                switch (train.getDirection()) {
+                    case UP -> {
+                        if (NumberUtil.isLess(travel.getOffset(), travel.getSection().getSectionLength().subtract(train.getTrainLength()).max(BigDecimal.ZERO))) {
+                            Optional<SectionItem> optional = StreamUtils.findFirst(sectionList, item -> item.getId().equals(travel.getSection().getNextId()));
+                            if (optional.isPresent()) {
+                                SectionItem sectionItem = optional.get();
+                                train.setDirection(sectionItem.getDirection());
+                                train.setBlockId(sectionItem.getSectionId());
+                                train.setBlockNo(sectionItem.getSectionName());
+                                train.setOffset(BigDecimal.ZERO);
+                            } else {
+                                train.setSpeed(BigDecimal.ZERO);
+                                train.setAcceleration(BigDecimal.ZERO);
+                                return train;
+                            }
+                        }
+                    }
+                    case DOWN -> {
+                        if (NumberUtil.isGreater(travel.getOffset(), train.getTrainLength())) {
+                            Optional<SectionItem> optional = StreamUtils.findFirst(sectionList, item -> item.getId().equals(travel.getSection().getNextId()));
+                            if (optional.isPresent()) {
+                                SectionItem sectionItem = optional.get();
+                                train.setDirection(sectionItem.getDirection());
+                                train.setBlockId(sectionItem.getSectionId());
+                                train.setBlockNo(sectionItem.getSectionName());
+                                train.setOffset(sectionItem.getSectionLength().subtract(new BigDecimal("1")));
+                            } else {
+                                train.setSpeed(BigDecimal.ZERO);
+                                train.setAcceleration(BigDecimal.ZERO);
+                                return train;
+                            }
+                        }
+                    }
+                }
             }
-        } else {
-            // 停车后更新时间
-            train.setUpdateTimeMillis(nowMillis);
         }
         // 计算MA
         BigDecimal distanceMa = this.getDistanceMa(sectionList, train);
@@ -116,17 +151,32 @@ public class TrainComputerService {
 
 
     private BigDecimal getDistanceMa(LinkedList<SectionItem> list, TrainItem train) {
-        Optional<SectionItem> sectionOptional = list.stream().filter(item -> {
-            return item.getSectionId().equals(train.getBlockId()) && item.getDirection().equals(train.getDirection());
-        }).findFirst();
-        if (sectionOptional.isEmpty()) {
+        List<SectionItem> filter = StreamUtils.filter(list, item -> item.getSectionId().equals(train.getBlockId()));
+        if (CollUtil.isEmpty(filter)) {
             return BigDecimal.ZERO;
         }
-        return getDistanceMa(list, sectionOptional.get(), train.getOffset(), BigDecimal.ZERO);
+        if (filter.size() > 1) {
+            Optional<SectionItem> optional = StreamUtils.findFirst(filter, item -> item.getDirection().equals(train.getDirection()));
+            if (optional.isPresent()) {
+                return getDistanceMa(list, optional.get(), train.getOffset(), BigDecimal.ZERO);
+            }
+        }
+        return getDistanceMa(list, filter.get(0), train.getOffset(), BigDecimal.ZERO);
     }
 
     public BigDecimal getDistanceMa(Collection<SectionItem> list, SectionItem sectionItem, BigDecimal offset, BigDecimal distance) {
-        // TODO 计算MA 区段的停车标、折返标志
+        // TODO 计算MA 、折返标志
+        // 区段的停车标
+        HashMap<Long, SignStopEntity> stopSignalMap = sectionService.getStopSignalMap();
+        if (CollUtil.isNotEmpty(stopSignalMap) && stopSignalMap.containsKey(sectionItem.getSectionId())) {
+            // 当前区段存在停车标
+            SignStopEntity stopEntity = stopSignalMap.get(sectionItem.getSectionId());
+            BigDecimal distanceStop = switch (stopEntity.getDirection()) {
+                case UP -> stopEntity.getSelectionOff().abs();
+                case DOWN -> NumberUtil.sub(sectionItem.getSectionLength().abs(), stopEntity.getSelectionOff().abs());
+            };
+            return NumberUtil.add(distance.abs(), distanceStop.abs(), 5);
+        }
         BigDecimal sectionDistance = null == offset ? sectionItem.getSectionLength() : switch (sectionItem.getDirection()) {
             case UP -> offset.abs();
             case DOWN -> NumberUtil.sub(sectionItem.getSectionLength().abs(), offset.abs());
@@ -152,7 +202,7 @@ public class TrainComputerService {
         trainData.set(CommandEnum.TRAIN_OPEN_DOOR.getStatusStr(), state);
         TrainWebSocketUtils.sendMessage(CommandEnum.TRAIN_OPEN_DOOR, trainData);
         // 站台屏蔽门开关门
-        Optional<SectionItem> optional = sectionList.stream().filter(item -> item.getSectionId().equals(train.getTrainId())).findFirst();
+        Optional<SectionItem> optional = sectionList.stream().filter(item -> item.getSectionId().equals(train.getBlockId())).findFirst();
         if (optional.isPresent()) {
             List<PlatformDoorEntity> doorList = platformDoorRepository.findByStationIdAndDirection(optional.get().getStationId(), train.getDirection());
             for (PlatformDoorEntity entity : doorList) {

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

@@ -1,19 +1,18 @@
 package top.haijunit.train.utils;
 
-import cn.hutool.core.date.DateTime;
-import cn.hutool.core.date.DateUtil;
 import lombok.experimental.UtilityClass;
+import lombok.extern.slf4j.Slf4j;
 import top.haijunit.train.domain.constant.TrainConstant;
 
 import java.math.BigDecimal;
-import java.time.Duration;
-import java.time.LocalTime;
+import java.math.RoundingMode;
 
 /**
  * @author zhanghaijun
  * @date 2023/12/3 21:58
  * @description 速度、距离等计算类
  */
+@Slf4j
 @UtilityClass
 public class CalculatorUtil {
 
@@ -32,30 +31,27 @@ public class CalculatorUtil {
         return distance.max(BigDecimal.ZERO);
     }
 
+
     /**
      * 计算指定时间内的运行距离
      *
-     * @param velocity     速度
-     * @param acceleration 加速度
-     * @param time         时间
+     * @param velocity     速度 m
+     * @param acceleration 加速度 m/s^2
+     * @param timeInMillis 时间(毫秒)
      * @return 距离
      */
-    public static BigDecimal distanceStopLimit(BigDecimal velocity, BigDecimal acceleration, long milliseconds) {
+    public static BigDecimal distanceStopLimit(BigDecimal velocity, BigDecimal acceleration, long timeInMillis) {
         // 初速度为零时,运行距离为零
-        if (acceleration.compareTo(BigDecimal.ZERO) == 0) {
+        if (velocity.compareTo(BigDecimal.ZERO) == 0 && acceleration.compareTo(BigDecimal.ZERO) == 0) {
             return BigDecimal.ZERO;
         }
-        BigDecimal seconds = NumberUtil.div(new BigDecimal(milliseconds), 1000);
-        // 运行距离计算公式
-        BigDecimal distance;
-        if (NumberUtil.isGreaterOrEqual(acceleration, BigDecimal.ZERO)) {
-            // 加速状态
-            distance = NumberUtil.div(NumberUtil.mul(acceleration, NumberUtil.pow(seconds, 2)), new BigDecimal(2));
-        } else {
-            // 减速状态
-            distance = NumberUtil.add(NumberUtil.mul(velocity, seconds), NumberUtil.div(NumberUtil.mul(acceleration, NumberUtil.pow(seconds, 2)), new BigDecimal(2)));
-        }
-        return distance.abs();
+        BigDecimal seconds = NumberUtil.div(new BigDecimal(timeInMillis), 1000);
+
+        // 使用运动方程计算距离:距离 = 初速度 * 时间 + 0.5 * 加速度 * 时间^2
+        BigDecimal distance = velocity.multiply(seconds)
+            .add(acceleration.multiply(seconds.pow(2)).divide(BigDecimal.valueOf(2), 10, RoundingMode.HALF_UP));
+
+        return NumberUtil.max(distance, BigDecimal.ZERO);
     }
 
     /**
@@ -81,4 +77,8 @@ public class CalculatorUtil {
         BigDecimal seconds = NumberUtil.div(new BigDecimal(Math.abs(startMillis - endMillis)), 1000);
         return velocity(velocity, acceleration, seconds);
     }
+
+    public static BigDecimal velocity(BigDecimal velocity, BigDecimal acceleration, Long timeInMillis) {
+        return velocity(velocity, acceleration, NumberUtil.div(new BigDecimal(Math.abs(timeInMillis)), 1000));
+    }
 }

+ 2 - 0
train-server/src/main/resources/db/changelog/train/db-server-train.xml

@@ -196,6 +196,7 @@
             <column name="name" type="VARCHAR(128)" defaultValue="" remarks="名称"/>
             <column name="kilometer" type="DECIMAL(10, 2)" defaultValueNumeric="0.00" remarks="公里标"/>
             <column name="type" type="${number.type}" defaultValueNumeric="1" remarks="类型"/>
+            <column name="section_id" type="${number.type}" defaultValueNumeric="0" remarks="所属区段号"/>
             <column name="pre_selection_id" type="${autoing.type}" defaultValueNumeric="0" remarks="岔前区段区段号"/>
             <column name="next_selection_id" type="${autoing.type}" defaultValueNumeric="0" remarks="岔后区段号"/>
             <column name="next_side_selection_id" type="${autoing.type}" defaultValueNumeric="0" remarks="岔后侧向区段号"/>
@@ -212,6 +213,7 @@
             <column name="name" type="STRING"/>
             <column name="kilometer" type="NUMERIC"/>
             <column name="type" type="NUMERIC"/>
+            <column name="section_id" type="NUMERIC"/>
             <column name="pre_selection_id" type="NUMERIC"/>
             <column name="next_selection_id" type="NUMERIC"/>
             <column name="next_side_selection_id" type="NUMERIC"/>

+ 1 - 1
train-server/src/main/resources/db/changelog/train/db_route.txt

@@ -2,7 +2,7 @@ id,name,signal_ids,signal_state,sele_ids,switch_id,switch_state,trig_position,di
 108001,S0306-S0301,101016,3,103025-103032-103031-103010-103009,102007-102004,2-2,7196.89,1,2,108002
 108002,S0301-S0201,101011,2,103008-103007,-1,-1,6841.26,1,2,108003
 108003,S0201-S0103,101007,2,103006-103005,-1,-1,3941.26,1,2,108004
-108004,S0103-S0102,101002,3,103012-103030-103029-103015-103014,102003-102002,2-2,550,1,2,108005
+108004,S0103-S0102,101002,3,103004-103030-103029-103015-103014,102003-102002,2-2,550,1,2,108005
 108005,S0102-S0106,101002,2,103015-103016-103017-103018,102002-102004,1-1,130,2,2,108006
 108006,S0106-S0204,101006,2,103019-103020,-1,-1,585,2,2,108007
 108007,S0204-S0304,101010,2,103021-103022,-1,-1,3641,2,2,108008

+ 9 - 9
train-server/src/main/resources/db/changelog/train/db_switch.txt

@@ -1,10 +1,10 @@
-id,name,kilometer,type,pre_selection_id,next_selection_id,next_side_selection_id,switch_tie,station_id
-102001,B0101,200,1,103002,103003,103027,102003,104001
-102002,B0102,200,2,103015,103016,103029,102004,104001
-102003,B0103,400,3,103004,103003,103030,102001,104001
-102004,B0104,400,4,103017,103016,103028,102002,104001
+id,name,kilometer,type,section_id,pre_selection_id,next_selection_id,next_side_selection_id,switch_tie,station_id
+102001,B0101,200,1,103027,103002,103003,103027,102003,104001
+102002,B0102,200,2,103029,103015,103016,103029,102004,104001
+102003,B0103,400,3,103028,103004,103003,103030,102001,104001
+102004,B0104,400,4,103030,103017,103016,103028,102002,104001
 
-102005,B0301,6936.89,1,103010,103011,103031,102007,104003
-102006,B0302,6936.89,2,103023,103024,103033,102008,104003
-102007,B0303,7136.89,3,103012,103011,103034,102005,104003
-102008,B0304,7136.89,4,103025,103024,103032,102006,104003
+102005,B0301,6936.89,1,103031,103010,103011,103031,102007,104003
+102006,B0302,6936.89,2,103033,103023,103024,103033,102008,104003
+102007,B0303,7136.89,3,103032,103012,103011,103034,102005,104003
+102008,B0304,7136.89,4,103034,103025,103024,103032,102006,104003

+ 65 - 1
train-server/src/test/java/top/haijunit/train/test/ComputerTrainTest.java

@@ -2,8 +2,17 @@ package top.haijunit.train.test;
 
 import lombok.extern.slf4j.Slf4j;
 import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
 import org.springframework.boot.test.context.SpringBootTest;
 import top.haijunit.train.TrainServerMain;
+import top.haijunit.train.domain.constant.TrainConstant;
+import top.haijunit.train.utils.CalculatorUtil;
+import top.haijunit.train.utils.NumberUtil;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
 
 /**
  * @author zhanghaijun
@@ -11,10 +20,65 @@ import top.haijunit.train.TrainServerMain;
  * @description 列车行驶 单元测试
  */
 @Slf4j
-@DisplayName("进路测试")
+@DisplayName("列车行驶")
 @SpringBootTest(classes = TrainServerMain.class, webEnvironment = SpringBootTest.WebEnvironment.NONE)
 public class ComputerTrainTest {
 
+    // // 初始速度,单位:m/s
+    // BigDecimal initialVelocity = BigDecimal.ZERO;
+    // // 最高速度,将80公里/小时转换为m/s
+    // BigDecimal targetVelocity = TrainConstant.SPEED_LIMIT_EBI;
+    // // 加速度,单位:m/s^2
+    // BigDecimal acceleration = TrainConstant.ACCELERATION_LIMIT;
+
+    // 初始速度,单位:m/s
+    BigDecimal initialVelocity = TrainConstant.SPEED_LIMIT_EBI;
+    // 最高速度,将80公里/小时转换为m/s
+    BigDecimal targetVelocity = BigDecimal.ZERO;
+    // 加速度,单位:m/s^2
+    BigDecimal acceleration = TrainConstant.DECELERATION_LIMIT;
+
+    @Test
+    void testRun() {
+        // 计算加速到最大速度所需的时间
+        BigDecimal timeToMaxVelocity = targetVelocity.subtract(initialVelocity).divide(acceleration, 10, RoundingMode.HALF_UP);
+        // 计算行驶距离
+        BigDecimal distance = initialVelocity.multiply(timeToMaxVelocity).add(acceleration.multiply(timeToMaxVelocity.pow(2)).divide(new BigDecimal("2"), 10, RoundingMode.HALF_UP));
+        // 加速到最大速度所需时间:27.7777777800 秒
+        log.info("加速到最大速度所需时间:{} 秒", timeToMaxVelocity);
+        // 行驶距离:308.6419753580 米
+        log.info("行驶距离:{} 米", distance);
+    }
+
+    @DisplayName("计算行驶得速度")
+    @ParameterizedTest
+    @CsvSource({"1", "2", "3", "4", "5", "10", "20", "27", "28", "30", "32", "36", "38", "40"})
+    void runSpeed(long millis) {
+        long nowMillis = System.currentTimeMillis();
+        BigDecimal velocity = CalculatorUtil.velocity(initialVelocity, acceleration, nowMillis - millis * 1000L, nowMillis);
+        log.info("------列车行驶:{}秒--->速度:{} 米/秒, 最高速度:{}", millis, velocity, TrainConstant.SPEED_LIMIT_EBI);
+    }
 
+    @DisplayName("计算行驶得距离")
+    @ParameterizedTest
+    @CsvSource({"1", "2", "3", "4", "5", "10", "20", "27", "28", "30", "32", "36", "38", "40"})
+    void runDistance(long millis) {
+        BigDecimal distanced = CalculatorUtil.distanceStopLimit(initialVelocity, acceleration, millis * 1000L);
+        log.info("------列车行驶:{}秒--->距离:{} 米", millis, distanced);
+    }
 
+    @DisplayName("分段计算行驶得距离")
+    @Test
+    void run() {
+        // 初始速度,单位:m/s
+        BigDecimal velocity = initialVelocity;
+        BigDecimal distancedTotal = BigDecimal.ZERO;
+        for (int i = 1; i < 42; i++) {
+            velocity = CalculatorUtil.velocity(velocity, acceleration, 1000L);
+            BigDecimal distanced = CalculatorUtil.distanceStopLimit(velocity, acceleration, 1000L);
+            distancedTotal = NumberUtil.add(distancedTotal, distanced);
+            log.info("------列车行驶:{}秒--->速度:{} 米/秒, 距离:{} 米", i, velocity, distanced);
+        }
+        log.info("------30s行驶总距离:{} 米", distancedTotal);
+    }
 }