ソースを参照

列车行驶区段计算优化

zhanghaijun 2 年 前
親
コミット
579ab29578

+ 4 - 8
train-server/src/main/java/top/haijunit/train/listener/TrainApplication.java

@@ -5,17 +5,13 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.boot.ApplicationArguments;
 import org.springframework.boot.ApplicationRunner;
 import org.springframework.stereotype.Component;
-import top.haijunit.train.domain.entity.SelectionEntity;
 import top.haijunit.train.domain.entity.TrainEntity;
 import top.haijunit.train.domain.repository.TrainRepository;
 import top.haijunit.train.service.SectionService;
-import top.haijunit.train.service.SelectionService;
 import top.haijunit.train.simulation.domain.SectionItem;
 import top.haijunit.train.simulation.domain.TrainItem;
 import top.haijunit.train.simulation.train.TrainSimulationHolder;
 
-import java.math.BigDecimal;
-import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -33,10 +29,10 @@ public class TrainApplication implements ApplicationRunner {
 
     @Override
     public void run(ApplicationArguments args) {
-        // List<TrainEntity> list = trainRepository.findAll();
-        List<TrainEntity> list = trainRepository.findAllById(new ArrayList<>() {{
-            add(110001L);
-        }});
+        List<TrainEntity> list = trainRepository.findAll();
+        // List<TrainEntity> list = trainRepository.findAllById(new ArrayList<>() {{
+        //     add(110001L);
+        // }});
         for (TrainEntity train : list) {
             try {
                 SectionItem sectionItem = sectionService.getSection(train.getSectionId());

+ 0 - 1
train-server/src/main/java/top/haijunit/train/service/RouteService.java

@@ -27,7 +27,6 @@ public class RouteService {
     private final SwitchRepository switchRepository;
     private final RouteRepository routeRepository;
 
-
     public boolean changeSwitchState(Long routeId) {
         RouteEntity route = routeRepository.findById(routeId).orElseThrow(() -> new IllegalArgumentException(String.format("---进路不存在, id: %s", routeId)));
         return changeSwitchState(route.getSwitchMap());

+ 13 - 1
train-server/src/main/java/top/haijunit/train/service/SectionService.java

@@ -9,8 +9,10 @@ import top.haijunit.train.domain.constant.SectionStatusEnum;
 import top.haijunit.train.domain.constant.TrainConstant;
 import top.haijunit.train.domain.entity.RouteEntity;
 import top.haijunit.train.domain.entity.SelectionEntity;
+import top.haijunit.train.domain.entity.SignStopEntity;
 import top.haijunit.train.domain.repository.RouteRepository;
 import top.haijunit.train.domain.repository.SelectionRepository;
+import top.haijunit.train.domain.repository.SignStopRepository;
 import top.haijunit.train.simulation.domain.SectionItem;
 import top.haijunit.train.utils.NumberUtil;
 
@@ -22,7 +24,7 @@ import java.util.stream.Collectors;
 /**
  * @author zhanghaijun
  * @date 2023/12/9 11:14
- * @description [一句话描述该类的功能]
+ * @description 进路区段计算
  */
 @Slf4j
 @Service
@@ -31,6 +33,16 @@ public class SectionService {
 
     private final RouteRepository routeRepository;
     private final SelectionRepository selectionRepository;
+    private final SignStopRepository signStopRepository;
+
+    /**
+     * 获取所有停车标信息
+     * @return 停车标集合
+     */
+    public HashMap<Long, SignStopEntity> getStopSignalMap() {
+        List<SignStopEntity> list = signStopRepository.findAll();
+        return list.stream().collect(HashMap::new, (map, entity) -> map.put(entity.getSelectionId(), entity), HashMap::putAll);
+    }
 
     /**
      * 根据sectionId获取section

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

@@ -1,96 +0,0 @@
-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.train.domain.constant.DirectionEnum;
-import top.haijunit.train.domain.constant.SectionStatusEnum;
-import top.haijunit.train.domain.entity.RouteEntity;
-import top.haijunit.train.domain.entity.SelectionEntity;
-import top.haijunit.train.domain.entity.SignStopEntity;
-import top.haijunit.train.domain.repository.RouteRepository;
-import top.haijunit.train.domain.repository.SelectionRepository;
-import top.haijunit.train.domain.repository.SignStopRepository;
-import top.haijunit.train.utils.NumberUtil;
-
-import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * @author zhanghaijun
- * @date 2023/12/2 23:07
- * @description 区段的计算方法
- */
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class SelectionService {
-
-    private final SelectionRepository selectionRepository;
-    private final RouteRepository routeRepository;
-    private final SignStopRepository signStopRepository;
-
-    // 根据公里标和上下行获取区段的问题
-    public SelectionEntity getSelection(BigDecimal kilometer, DirectionEnum direction) {
-        for (SelectionEntity selection : selectionRepository.findByDirection(direction)) {
-            if (NumberUtil.isContain(kilometer, selection.getStartKilometer(), selection.getEndKilometer())) {
-                return selection;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * 获取进路中的区段
-     *
-     * @param route 进路
-     * @return 进路中的区段
-     */
-    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(SectionStatusEnum.LOCK);
-        }
-        return new LinkedList<>(selectionList);
-    }
-
-    /**
-     * 获取列车当前进路中未驶过的区段
-     *
-     * @param route         进路
-     * @param headKilometer 车头
-     * @param tailKilometer 车位
-     * @return 进路中未驶过的区段
-     */
-    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, direction)) {
-                // 列车还未驶过该区段
-                if (entity.isContain(headKilometer, direction) || entity.isContain(tailKilometer, direction)) {
-                    // 车头或者车尾在区段内,则是占用状态
-                    entity.setStatus(SectionStatusEnum.OCCUPY);
-                } else {
-                    entity.setStatus(SectionStatusEnum.LOCK);
-                }
-                list.addLast(entity);
-            }
-        }
-        return list;
-    }
-
-    public HashMap<Long, SignStopEntity> getStopSignalMap(List<Long> selectionAllList) {
-        if(CollUtil.isEmpty(selectionAllList)){
-            return new HashMap<>();
-        }
-        List<SignStopEntity> list = signStopRepository.findAllByStationId(selectionAllList);
-        return list.stream().collect(HashMap::new, (map, entity) -> map.put(entity.getSelectionId(), entity), HashMap::putAll);
-    }
-}

+ 92 - 0
train-server/src/main/java/top/haijunit/train/simulation/domain/TrainTravel.java

@@ -0,0 +1,92 @@
+package top.haijunit.train.simulation.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.RequiredArgsConstructor;
+import top.haijunit.train.domain.entity.SignStopEntity;
+import top.haijunit.train.utils.NumberUtil;
+
+import java.math.BigDecimal;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * @author zhanghaijun
+ * @date 2023/12/17 21:30
+ * @description [一句话描述该类的功能]
+ * @version 1.0
+ */
+@Data
+public class TrainTravel {
+
+    // 可行驶的区段集合
+    private final List<SectionItem> sectionList;
+    // 停车标的位置
+    private final HashMap<Long, SignStopEntity> signStopMap;
+
+    public TrainTravel(List<SectionItem> sectionList, List<SignStopEntity> signStopEntityList) {
+        this.sectionList = sectionList;
+        this.signStopMap = signStopEntityList.stream().collect(HashMap::new, (map, entity) -> map.put(entity.getSelectionId(), entity), HashMap::putAll);
+    }
+
+    public TrainTravel(List<SectionItem> sectionList, HashMap<Long, SignStopEntity> signStopMap) {
+        this.sectionList = sectionList;
+        this.signStopMap = signStopMap;
+    }
+
+    /**
+     * 列车行驶
+     * @param section 当前区段
+     * @param offset 偏移量
+     * @param distance 行驶距离
+     * @return 行驶后的位置
+     */
+    public TravelItem travel(long sectionId, BigDecimal offset, BigDecimal distance) {
+        Optional<SectionItem> sectionOptional = sectionList.stream().filter(item -> item.getSectionId().equals(sectionId)).findFirst();
+        if (sectionOptional.isEmpty()) {
+            return null;
+        }
+        SectionItem sectionItem = sectionOptional.get();
+        if (null == offset) {
+            // 偏移量为当前区段长度 上行的开始位置是区段的末端
+            offset = sectionItem.getSectionLength();
+        }
+        BigDecimal travelDistance = NumberUtil.mul(sectionItem.getDirection().getFactor(), distance.abs());
+        BigDecimal travelOffset = NumberUtil.add(offset, travelDistance);
+        // 计算停车标
+        SignStopEntity stopEntity = signStopMap.get(sectionId);
+        if (null != stopEntity) {
+            BigDecimal minInclude = NumberUtil.min(offset.abs(), travelOffset);
+            BigDecimal maxInclude = NumberUtil.max(offset.abs(), travelOffset);
+            Boolean isStop = switch (sectionItem.getDirection()) {
+                case UP -> NumberUtil.isGreaterOrEqual(stopEntity.getSelectionOff().abs(), minInclude) && NumberUtil.isLess(stopEntity.getSelectionOff().abs(), maxInclude);
+                case DOWN -> NumberUtil.isGreater(stopEntity.getSelectionOff().abs(), minInclude) && NumberUtil.isLessOrEqual(stopEntity.getSelectionOff().abs(), maxInclude);
+            };
+            if (isStop) {
+                return new TravelItem(sectionItem, stopEntity.getSelectionOff().abs(), true);
+            }
+        }
+        if (NumberUtil.isLess(travelOffset, BigDecimal.ZERO)) {
+            // <0 上行 行驶到下一个区段
+            return travel(sectionItem.getSectionNextId(), null, travelOffset.abs());
+        } else if (NumberUtil.isGreaterOrEqual(travelOffset, sectionItem.getSectionLength())) {
+            // >= 区段的长度 下行 实行到下一个区段
+            return travel(sectionItem.getSectionNextId(), BigDecimal.ZERO, travelOffset.subtract(sectionItem.getSectionLength()));
+        } else {
+            // 行驶后的位置在当前区段
+            return new TravelItem(sectionItem, travelOffset, false);
+        }
+    }
+
+    @Data
+    @AllArgsConstructor
+    public static class TravelItem {
+        // 区段
+        private SectionItem section;
+        // 偏移量
+        private BigDecimal offset;
+        // 是否停车
+        private boolean isStop;
+    }
+}

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

@@ -8,9 +8,10 @@ import top.haijunit.common.utils.ErrorUtil;
 import top.haijunit.common.utils.StreamUtils;
 import top.haijunit.train.domain.constant.TrainConstant;
 import top.haijunit.train.domain.entity.SignStopEntity;
-import top.haijunit.train.service.SelectionService;
+import top.haijunit.train.service.SectionService;
 import top.haijunit.train.simulation.domain.SectionItem;
 import top.haijunit.train.simulation.domain.TrainItem;
+import top.haijunit.train.simulation.domain.TrainTravel;
 import top.haijunit.train.utils.CalculatorUtil;
 import top.haijunit.train.utils.NumberUtil;
 
@@ -27,7 +28,7 @@ import java.util.stream.Collectors;
 @Service
 @RequiredArgsConstructor
 public class TrainComputerService {
-    private final SelectionService selectionService;
+    private final SectionService sectionService;
 
     public void run(TrainItem trainItem) {
         try {
@@ -61,39 +62,22 @@ public class TrainComputerService {
             if (sectionOptional.isEmpty()) {
                 throw new IllegalArgumentException(String.format("没有找到当前列车的所在的区段, 区段Name: %s, offset: %s", train.getBlockNo(), train.getOffset()));
             }
-            List<SectionItem> list = CollUtil.reverse(this.getSectionByDistance(sectionList, train.getBlockId(), train.getOffset(), distance));
-            log.info("列车预计行驶的区段:{}", list.stream().map(SectionItem::getSectionName).collect(Collectors.joining(",")));
-            // 停车标数据
-            HashMap<Long, SignStopEntity> stopSignalMap = selectionService.getStopSignalMap(list.stream().map(SectionItem::getSectionId).collect(Collectors.toList()));
-            SectionItem currentSection = sectionOptional.get();
-            BigDecimal currentOffset = NumberUtil.add(train.getOffset(), NumberUtil.mul(train.getDirection().getFactor(), distance.abs())).abs();
-            for (int i = 0; i < list.size(); i++) {
-                SectionItem sectionItem = list.get(i);
-                SignStopEntity stopSign = stopSignalMap.get(sectionItem.getSectionId());
-                if (null != stopSign && train.getBlockId().equals(sectionItem.getSectionId())) {
-                    // 存在停车标
-                    if (NumberUtil.isGreater(stopSign.getSelectionOff(), train.getOffset()) && NumberUtil.isLessOrEqual(stopSign.getSelectionOff(), currentOffset)) {
-                        train.setSpeed(BigDecimal.ZERO);
-                        train.setAcceleration(BigDecimal.ZERO);
-                        train.setBlockId(sectionItem.getSectionId());
-                        train.setBlockNo(sectionItem.getSectionName());
-                        train.setOffset(stopSign.getSelectionOff());
-                        train.setDirection(sectionItem.getDirection());
-                        train.setUpdateTimeMillis(nowMillis);
-                        return train;
-                    }
+            HashMap<Long, SignStopEntity> stopSignalMap = sectionService.getStopSignalMap();
+            TrainTravel trainTravel = new TrainTravel(sectionList, stopSignalMap);
+            TrainTravel.TravelItem travel = trainTravel.travel(train.getBlockId(), train.getOffset(), distance);
+            if (null != travel) {
+                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);
+                    return train;
                 }
-                if (i != list.size() - 1) {
-                    currentOffset = NumberUtil.sub(currentOffset, sectionItem.getSectionLength()).abs();
-                }
-                currentSection = sectionItem;
             }
-            train.setSpeed(CalculatorUtil.velocity(train.getSpeed(), train.getAcceleration(), train.getUpdateTimeMillis(), nowMillis).abs());
-            train.setOffset(currentOffset);
-            train.setBlockId(currentSection.getSectionId());
-            train.setBlockNo(currentSection.getSectionName());
-            train.setDirection(currentSection.getDirection());
-            train.setUpdateTimeMillis(nowMillis);
         } else {
             // 停车后更新时间
             train.setUpdateTimeMillis(nowMillis);

+ 0 - 31
train-server/src/test/java/top/haijunit/train/RouteComputerTest.java

@@ -1,31 +0,0 @@
-package top.haijunit.train;
-
-import lombok.extern.slf4j.Slf4j;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import top.haijunit.train.service.SectionService;
-import top.haijunit.train.simulation.domain.SectionItem;
-
-import java.util.List;
-
-/**
- * @author zhanghaijun
- * @date 2023/12/9 11:47
- * @description [一句话描述该类的功能]
- */
-@Slf4j
-@SpringBootTest
-public class RouteComputerTest {
-
-    @Autowired
-    private SectionService sectionService;
-
-    @Test
-    void localAllRoute() {
-        List<SectionItem> allSection = sectionService.getAllSection();
-        for (SectionItem item : allSection) {
-            log.info("进路:{},区段名称:{},区段Id:{},上一个区段:{},下一个区段:{}", item.getRouteName(), item.getSectionName(), item.getSectionId(), item.getSectionPreId(), item.getSectionNextId());
-        }
-    }
-}

+ 48 - 0
train-server/src/test/java/top/haijunit/train/test/ComputerRouteTest.java

@@ -0,0 +1,48 @@
+package top.haijunit.train.test;
+
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import top.haijunit.train.domain.entity.SignStopEntity;
+import top.haijunit.train.service.SectionService;
+import top.haijunit.train.simulation.domain.SectionItem;
+import top.haijunit.train.simulation.domain.TrainTravel;
+
+import java.math.BigDecimal;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * @author zhanghaijun
+ * @date 2023/12/9 11:47
+ * @description 进路触发 单元测试
+ */
+@Slf4j
+@SpringBootTest
+public class ComputerRouteTest {
+
+    @Autowired
+    private SectionService sectionService;
+
+    @DisplayName("进路集合")
+    @Test
+    void localAllRoute() {
+        List<SectionItem> allSection = sectionService.getAllSection();
+        for (SectionItem item : allSection) {
+            log.info("进路:{},区段名称:{},区段Id:{},上一个区段:{},下一个区段:{}", item.getRouteName(), item.getSectionName(), item.getSectionId(), item.getSectionPreId(), item.getSectionNextId());
+        }
+    }
+
+    @DisplayName("列车行驶")
+    @Test
+    void trainTravelTest() {
+        List<SectionItem> sectionItems = sectionService.getAllSection();
+        sectionItems.forEach(item -> log.info("进路:{},区段名称:{},区段Id:{},上一个区段:{},下一个区段:{}", item.getRouteName(), item.getSectionName(), item.getSectionId(), item.getSectionPreId(), item.getSectionNextId()));
+        HashMap<Long, SignStopEntity> stopSignalMap = sectionService.getStopSignalMap();
+        TrainTravel trainTravel = new TrainTravel(sectionItems, stopSignalMap);
+        TrainTravel.TravelItem travel = trainTravel.travel(103009L, new BigDecimal("10"), new BigDecimal("200"));
+        log.info("当前的位置,是否停车:{},区段:{},偏移量:{}", travel.isStop(), travel.getSection().getSectionName(), travel.getOffset());
+    }
+}

+ 32 - 0
train-server/src/test/java/top/haijunit/train/test/DemoTest.java

@@ -0,0 +1,32 @@
+package top.haijunit.train.test;
+
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.springframework.boot.test.context.SpringBootTest;
+
+/**
+ * @author zhanghaijun
+ * @description [一句话描述该类的功能]
+ * @version 1.0
+ */
+@Slf4j
+@SpringBootTest
+public class DemoTest {
+
+    @Test
+    public void test() {
+        log.info("test");
+        Assertions.assertEquals("666", new String("666"));
+    }
+
+    @DisplayName("测试 @ValueSource 注解")
+    @ParameterizedTest
+    @ValueSource(strings = {"t1", "t2", "t3"})
+    public void testValueSource(String str) {
+        System.out.println(str);
+    }
+}