Sfoglia il codice sorgente

区段+偏移量计算

zhanghaijun 2 anni fa
parent
commit
31db4fb9cd

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

@@ -56,7 +56,7 @@ public class JacksonConfig {
         JavaTimeModule module = new JavaTimeModule();
         module.addSerializer(Long.class, BigNumberSerializer.INSTANCE);
         module.addSerializer(BigInteger.class, BigNumberSerializer.INSTANCE);
-        module.addSerializer(BigDecimal.class, ToStringSerializer.instance);
+        module.addSerializer(BigDecimal.class, BigNumberSerializer.instance);
         // ======================= 时间序列化规则 ===============================
         // yyyy-MM-dd HH:mm:ss
         module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DatePattern.NORM_DATETIME_FORMATTER));

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

@@ -21,7 +21,6 @@ import top.haijunit.websocket.handler.WebSocketTopicListener;
  * @description [一句话描述该类的功能]
  */
 @AutoConfiguration
-@ConditionalOnProperty(value = "websocket.enabled", havingValue = "true")
 @EnableConfigurationProperties(WebSocketProperties.class)
 @EnableWebSocket
 @RequiredArgsConstructor

+ 5 - 0
train-server/pom.xml

@@ -11,6 +11,11 @@
     <packaging>jar</packaging>
 
     <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>top.haijunit</groupId>
             <artifactId>train-common-core</artifactId>

+ 1 - 1
train-server/src/main/java/top/haijunit/train/domain/constant/TrainConstant.java

@@ -10,7 +10,7 @@ import java.math.RoundingMode;
  */
 public interface TrainConstant {
 
-    BigDecimal SPEED_LIMIT = new BigDecimal("180");
+    BigDecimal SPEED_LIMIT = new BigDecimal("80");
     // 全线列车限速默认为80km/h 转换单位公式:速度(m/s) = 速度(km/h) * 1000 / 3600
     BigDecimal SPEED_LIMIT_EBI = SPEED_LIMIT.multiply(new BigDecimal("1000").divide(new BigDecimal("3600"), 10, RoundingMode.HALF_UP));
     // 推荐惰性速度为80-2=78km/h

+ 20 - 11
train-server/src/main/java/top/haijunit/train/simulation/train/RouteComputerService.java

@@ -15,6 +15,7 @@ import top.haijunit.train.utils.NumberUtil;
 
 import java.util.Iterator;
 import java.util.LinkedList;
+import java.util.List;
 import java.util.stream.Collectors;
 
 /**
@@ -34,7 +35,7 @@ public class RouteComputerService {
         try {
             LinkedList<SectionItem> list = routeCompute(train);
             log.info("---进路数据,列车:{},进路:{}", train.getTrainNo(), list.stream().map(item -> {
-                return item.getRouteId() + "-" + item.getSectionName();
+                return item.getSectionName() + "-" + item.getSectionStatus().getDescribe();
             }).collect(Collectors.joining(",")));
             if (CollUtil.isNotEmpty(list)) {
                 // 更新进路共享数据
@@ -85,7 +86,11 @@ public class RouteComputerService {
             return routeList;
         }
         // c)出清(如果包括道岔,道岔已就位),将进路至于锁闭状态
-        routeList.addAll(sectionService.getSectionAll(routeId));
+        List<SectionItem> sectionAll = sectionService.getSectionAll(routeId);
+        for (SectionItem item : sectionAll) {
+            item.setSectionStatus(SectionStatusEnum.LOCK);
+        }
+        routeList.addAll(sectionAll);
         return routeList;
     }
 
@@ -94,19 +99,23 @@ public class RouteComputerService {
         if (CollUtil.isEmpty(routeList)) {
             return new LinkedList<>();
         }
-        Long sectionId = switch (train.getDirection()) {
-            // 车头所在的区段
-            case UP -> train.getBlockId();
-            // 车尾的所在的区段
-            case DOWN -> sectionService.getSection(train.getBlockId(), train.getOffset(), NumberUtil.mul(train.getTrainLength(),-1)).getSectionId();
-        };
+        // 车头所在的区段
+        Long sectionIdByHead = train.getBlockId();
+        // 车尾的所在的区段
+        Long sectionIdByTail = sectionService.getSection(train.getBlockId(), train.getOffset(), 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(sectionId)) {
-                break;
+            if (current.getSectionId().equals(sectionIdByHead) || current.getSectionId().equals(sectionIdByTail)) {
+                isPass = false;
+                current.setSectionStatus(SectionStatusEnum.OCCUPY);
+            } else {
+                current.setSectionStatus(SectionStatusEnum.IDLE);
+            }
+            if (isPass) {
+                iterator.remove();
             }
-            iterator.remove();
         }
         return routeList;
     }

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

@@ -15,8 +15,6 @@ import top.haijunit.train.utils.CalculatorUtil;
 import top.haijunit.train.utils.NumberUtil;
 
 import java.math.BigDecimal;
-import java.time.Duration;
-import java.time.LocalTime;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -63,40 +61,41 @@ public class TrainComputerService {
             if (sectionOptional.isEmpty()) {
                 throw new IllegalArgumentException(String.format("没有找到当前列车的所在的区段, 区段Name: %s, offset: %s", train.getBlockNo(), train.getOffset()));
             }
-            List<SectionItem> list = this.getSectionByDistance(sectionList, train.getBlockId(), train.getOffset(), distance);
+            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 currentSectionOffset = train.getOffset();
-            BigDecimal currentDistance = distance.abs();
-            for (SectionItem sectionItem : list) {
-                BigDecimal offsetDistance = NumberUtil.add(currentSectionOffset, NumberUtil.mul(sectionItem.getDirection().getFactor(), currentDistance));
-                SignStopEntity stopSign = stopSignalMap.get(sectionItem.getSectionId());
-                if (null != stopSign && NumberUtil.isIn(stopSign.getSelectionOff(), NumberUtil.min(currentSectionOffset, offsetDistance), NumberUtil.max(currentSectionOffset, offsetDistance))) {
-                    // 存在停车标
-                    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;
+            BigDecimal currentAllOffset = NumberUtil.add(train.getOffset(), NumberUtil.mul(train.getDirection().getFactor(), distance.abs()));
+            if (list.size() > 1) {
+                for (int i = 1; i < list.size(); i++) {
+                    SectionItem sectionItem = list.get(i);
+                    SignStopEntity stopSign = stopSignalMap.get(sectionItem.getSectionId());
+                    if (null != stopSign && NumberUtil.isIn(stopSign.getSelectionOff(), NumberUtil.min(BigDecimal.ZERO, currentAllOffset), NumberUtil.max(BigDecimal.ZERO, currentAllOffset))) {
+                        // 存在停车标
+                        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;
+                    }
+                    currentAllOffset = NumberUtil.sub(currentAllOffset, currentSection.getSectionLength());
+                    currentSection = sectionItem;
                 }
-                currentSection = sectionItem;
-                currentDistance = NumberUtil.add(currentSectionOffset, NumberUtil.mul(sectionItem.getDirection().getFactor(), currentDistance)).abs();
-                currentSectionOffset = BigDecimal.ZERO;
             }
             train.setSpeed(CalculatorUtil.velocity(train.getSpeed(), train.getAcceleration(), train.getUpdateTimeMillis(), nowMillis).abs());
+            train.setOffset(currentAllOffset.abs());
             train.setBlockId(currentSection.getSectionId());
             train.setBlockNo(currentSection.getSectionName());
-            train.setOffset(currentDistance);
             train.setDirection(currentSection.getDirection());
             train.setUpdateTimeMillis(nowMillis);
         }
         // 计算MA
-        BigDecimal distanceMa = this.getDistanceMa(sectionList, train.getBlockId(), train.getOffset());
+        List<BigDecimal> list = this.getDistanceMa(sectionList, train.getBlockId(), train.getOffset(), 0);
+        BigDecimal distanceMa = list.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
         BigDecimal distanceLimit = CalculatorUtil.distanceStopLimit(train.getSpeed());
         // log.info("列车信息:列车:{},速度:{},加速度:{}, 滑行距离:{}", trainItem.getTrainId(), trainItem.getSpeed(), trainItem.getAcceleration(), distance);
         if (NumberUtil.isLessOrEqual(distanceMa, distanceLimit)) {
@@ -115,18 +114,25 @@ public class TrainComputerService {
         return train;
     }
 
-    private BigDecimal getDistanceMa(List<SectionItem> list, Long sectionId, BigDecimal offset) {
-        BigDecimal ma = BigDecimal.ZERO;
+    private List<BigDecimal> getDistanceMa(LinkedList<SectionItem> list, Long sectionId, BigDecimal offset, int count) {
+        List<BigDecimal> maList = new ArrayList<>();
+        if (count > 10) {
+            log.error("循环太多了-- 计算MA,当前count:{}", count);
+        }
         Optional<SectionItem> sectionItem = list.stream().filter(item -> item.getSectionId().equals(sectionId)).findFirst();
         if (sectionItem.isPresent()) {
             SectionItem item = sectionItem.get();
-            ma = ma.add(switch (item.getDirection()) {
+            maList.add(switch (item.getDirection()) {
                 case UP -> NumberUtil.equals(offset, BigDecimal.ZERO) ? item.getSectionLength().abs() : offset.abs();
                 case DOWN -> NumberUtil.sub(sectionItem.get().getSectionLength(), offset).abs();
             });
-            ma = ma.add(getDistanceMa(list, sectionItem.get().getSectionNextId(), BigDecimal.ZERO));
+            if (!list.getLast().getSectionId().equals(sectionId)) {
+                // list 是有序的,最后一个不需要再去找了,避免无限循环
+                List<BigDecimal> distanceMa = getDistanceMa(list, sectionItem.get().getSectionNextId(), BigDecimal.ZERO, count + 1);
+                maList.addAll(distanceMa);
+            }
         }
-        return ma;
+        return maList;
     }
 
     /**
@@ -141,7 +147,9 @@ public class TrainComputerService {
     private List<SectionItem> getSectionByDistance(LinkedList<SectionItem> list, Long sectionId, BigDecimal offset, BigDecimal distance) {
         Optional<SectionItem> sectionOptional = StreamUtils.filter(list, item -> item.getSectionId().equals(sectionId)).stream().findFirst();
         if (sectionOptional.isEmpty()) {
-            throw new IllegalArgumentException(String.format("没有找到当前列车的所在的区段, 区段Id: %s, offset: %s", sectionId, offset));
+            log.error("没有找到当前列车的所在的区段, 区段Id: {}, offset: {}", sectionId, offset);
+            return new ArrayList<>();
+            // throw new IllegalArgumentException(String.format("没有找到当前列车的所在的区段, 区段Id: %s, offset: %s", sectionId, offset));
         }
         List<SectionItem> resultList = new ArrayList<>();
         SectionItem sectionItem = sectionOptional.get();
@@ -152,10 +160,9 @@ public class TrainComputerService {
                 case UP -> offsetDistance.abs();
                 case DOWN -> NumberUtil.sub(offsetDistance, sectionItem.getSectionLength());
             };
-            return getSectionByDistance(list, sectionItem.getSectionNextId(), new BigDecimal("0.00"), distanceNext);
-        } else {
-            resultList.add(sectionItem);
-            return CollUtil.reverse(resultList);
+            resultList.addAll(getSectionByDistance(list, sectionItem.getSectionNextId(), new BigDecimal("0.00"), distanceNext));
         }
+        resultList.add(sectionItem);
+        return resultList;
     }
 }

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

@@ -55,7 +55,7 @@ public class CalculatorUtil {
             // 减速状态
             distance = NumberUtil.add(NumberUtil.mul(velocity, seconds), NumberUtil.div(NumberUtil.mul(acceleration, NumberUtil.pow(seconds, 2)), new BigDecimal(2)));
         }
-        return distance.max(BigDecimal.ZERO);
+        return distance.abs();
     }
 
     /**

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

@@ -2,10 +2,8 @@ package top.haijunit.train;
 
 import lombok.extern.slf4j.Slf4j;
 import org.junit.jupiter.api.Test;
-import org.junit.runner.RunWith;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringRunner;
 import top.haijunit.train.service.SectionService;
 import top.haijunit.train.simulation.domain.SectionItem;
 

+ 47 - 20
train-web/src/pages/train/controller/DrawTrack.ts

@@ -1,9 +1,7 @@
-import { crtPath } from '../core/Utils'
-import { RouteStatusEnum, SelectionItem, SignalItem, SwitchItem } from "@/types/train-travel";
-import { LINE_DOWN, LINE_UP } from './Constant'
-import { useStoreSocket } from '@/store/socket'
-
-const storeSocket = useStoreSocket();
+import {crtPath} from '../core/Utils'
+import {DirectionEnum, RouteItem, SectionStatusEnum, SelectionItem, SignalItem, SignalStateEnum, SwitchItem} from "@/types/train-travel";
+import {LINE_DOWN, LINE_UP} from './Constant'
+import {useStoreSocket} from '@/store/socket'
 
 export class DrawTrack {
 
@@ -31,16 +29,22 @@ export class DrawTrack {
   }
 
   // 绘制信号灯
-  drawSignalList(upList: SignalItem[], isUp: boolean = true): void {
-    const Y: number = isUp ? LINE_UP : LINE_DOWN;
-    upList.forEach((signal: SignalItem) => {
-      this.drawSignal(signal.name, signal.kilometer, Y, true);
+  drawSignalList(upList: SignalItem[]): void {
+    const storeSocket = useStoreSocket();
+    const routeList: RouteItem[] = storeSocket.getRouteList;
+    upList.forEach((signal: SignalItem): void => {
+      const routeItem: RouteItem | undefined = routeList.find(item => item.sectionId == signal.selectionId);
+      // if (signal.name == 'S0104') {
+      //   console.log(signal.name, routeItem, routeList);
+      // }
+      this.drawSignal(signal.name, signal.kilometer, signal.direction, routeItem);
     });
   }
 
   // 绘制信号灯
-  drawSignal(name: string = "", x: number = 0, y: number = 0, isUp: boolean = true): void {
-    const space: number = isUp ? 10 : -10;
+  drawSignal(name: string = "", x: number = 0, direction: DirectionEnum = DirectionEnum.UP, routeItem: RouteItem | undefined): void {
+    const space: number = direction == DirectionEnum.UP ? 10 : -10;
+    const y: number = direction == DirectionEnum.UP ? LINE_UP : LINE_DOWN;
     this.canvas.save();
     this.canvas.beginPath();
     crtPath(this.canvas, [x, y - space * 0.6, x, y + 0.6 * space], true);
@@ -48,7 +52,20 @@ export class DrawTrack {
     crtPath(this.canvas, [x, y - 1.5 * space, x - 0.5 * space, y - 1.5 * space], false);
     this.canvas.arc(x - space, y - 1.5 * space, Math.abs(space * 0.5), 0, Math.PI * 2);
     this.canvas.lineWidth = 0.5;
-    this.canvas.fillStyle = "red";
+    switch (routeItem?.sectionStatus) {
+      case SectionStatusEnum.LOCK:
+        this.canvas.fillStyle = "#00FF00";
+        break;
+      case SectionStatusEnum.IDLE:
+        this.canvas.fillStyle = "#FF0000";
+        break;
+      case SectionStatusEnum.OCCUPY:
+        this.canvas.fillStyle = "#FF0000";
+        break;
+      default:
+        this.canvas.fillStyle = "#FF0000";
+        break;
+    }
     this.canvas.strokeStyle = "#000000";
     this.canvas.fill();
     this.canvas.stroke();
@@ -59,22 +76,32 @@ export class DrawTrack {
   }
 
   // 绘制轨道的上行和下行线
-  drawLine(selectionList: SelectionItem[], isUp: boolean = true): void {
-    const Y: number = isUp ? LINE_UP : LINE_DOWN;
-    const routeSelectionList: SelectionItem[] = storeSocket.getSelectionList;
+  drawLine(selectionList: SelectionItem[]): void {
+    const storeSocket = useStoreSocket();
+    const routeList: RouteItem[] = storeSocket.getRouteList;
     for (let i: number = 0; i < selectionList.length; i++) {
       const item: SelectionItem = selectionList[i];
+      let Y: number = 0;
+      switch (item.direction) {
+        case DirectionEnum.UP:
+          Y = LINE_UP;
+          break;
+        case DirectionEnum.DOWN:
+          Y = LINE_DOWN;
+          break;
+      }
       this.canvas.save();
       this.canvas.beginPath();
       this.canvas.moveTo(item.startKilometer, Y)
       this.canvas.lineTo(Number(item.startKilometer) + Number(item.selectionLength), Y)
       this.canvas.lineWidth = 1;
-      const sele: SelectionItem | undefined = routeSelectionList.find(s => s.id == item.id);
-      if (sele?.status == RouteStatusEnum.OCCUPY) {
+
+      const sectionItem: RouteItem | undefined = routeList.find(s => s.sectionId == item.id)
+      if (sectionItem?.sectionStatus == SectionStatusEnum.OCCUPY) {
         this.canvas.strokeStyle = "#FF0000";
-      } else if (sele?.status == RouteStatusEnum.IDLE) {
+      } else if (sectionItem?.sectionStatus == SectionStatusEnum.IDLE) {
         this.canvas.strokeStyle = "#898989";
-      } else if (sele?.status == RouteStatusEnum.LOCK) {
+      } else if (sectionItem?.sectionStatus == SectionStatusEnum.LOCK) {
         this.canvas.strokeStyle = "#00FF00";
       } else {
         this.canvas.strokeStyle = "#898989";

+ 88 - 29
train-web/src/pages/train/controller/DrewTrain.ts

@@ -1,41 +1,100 @@
 import TrainImg from "./train.svg"
-import { LINE_DOWN, LINE_UP } from "@/pages/train/controller/Constant";
+import {LINE_DOWN, LINE_UP} from "@/pages/train/controller/Constant";
+import {DirectionEnum, SelectionItem, TrainItem} from "@/types/train-travel.ts";
+import {StoreTrain} from '@/store/modules/train.ts'
+
 
 export class DrewTrain {
 
   private readonly canvas: CanvasRenderingContext2D;
-  private readonly trainWidth: number = 135.63;
-  private readonly trainHeight: number = 30;
-  private x: number;
-  private y: number;
-
+  private readonly image: HTMLImageElement;
 
-  constructor(canvas: CanvasRenderingContext2D, x: number = 0, y: number = 0) {
+  constructor(canvas: CanvasRenderingContext2D) {
     this.canvas = canvas;
-    this.x = x;
-    this.y = y;
+    this.image = new Image()
+    this.image.src = TrainImg
+  }
+
+  public drawTrain(train: TrainItem): void {
+    const storeTrain = StoreTrain();
+    const selectionList: SelectionItem[] = storeTrain.getSelectionList;
+    const currentItem: SelectionItem | undefined = selectionList.find((item: SelectionItem) => item.id == train.blockId);
+    const position: number = Number(currentItem ? currentItem.startKilometer : 0) + Number(train.offset);
+    this.draw(position, train);
   }
 
-  public draw(new_x: number = this.x, isUp: boolean = true): void {
-    const new_y: number = isUp ? LINE_UP : LINE_DOWN;
-    const image = new Image()
-    image.src = TrainImg
-    image.onload = (): void => {
-      // 清除之前的绘图
-      // this.canvas.clearRect(this.x, this.y - this.trainHeight, this.x + this.trainWidth, this.y);
-      // 绘制列车
-      this.x = new_x;
-      this.y = new_y;
-      this.canvas.translate(this.x, this.y);
-      // !isUp && this.canvas.rotate(Math.PI);
-      // 镜像处理
-      !isUp && this.canvas.scale(-1, 1);
-      this.canvas.globalCompositeOperation = 'source-over';
-      this.canvas.drawImage(image, 0, 0 - this.trainHeight, this.trainWidth, this.trainHeight);
-      // 恢复镜像
-      !isUp && this.canvas.scale(-1, 1);
-      this.canvas.restore();
+  public draw(position: number = 0, train: TrainItem): void {
+    const direction: DirectionEnum = train.direction;
+    const trainWidth: number = train.trainLength
+    const isUp: boolean = direction === DirectionEnum.UP;
+    const position_y: number = isUp ? LINE_UP : LINE_DOWN;
+    // const image: HTMLImageElement = new Image()
+    // image.src = TrainImg
+    // image.onload = (): void => {
+    // 绘制列车
+    this.canvas.translate(position, position_y);
+    // 镜像处理
+    !isUp && this.canvas.scale(-1, 1);
+    this.canvas.globalCompositeOperation = 'source-over';
+    this.canvas.drawImage(this.image, 0, 0 - 30, trainWidth, 30);
+    // 恢复镜像
+    !isUp && this.canvas.scale(-1, 1);
+    this.canvas.restore();
+    this.canvas.save();
+    const titleArray: string[] = [];
+    titleArray.push("列车:" + Number(train.trainNo).toFixed(2));
+    titleArray.push("速度:" + Number(train.speed).toFixed(2) + "  加速度:" + Number(train.acceleration).toFixed(2));
+    this.drawTitle(position - (trainWidth * 0.5), (position_y - 35), 150, 50, titleArray);
+    this.canvas.save();
+    // };
+  }
+
+  private drawTitle(x: number, y: number, width: number, height: number, titleArray: string[] = []): void {
+    const position_x: number = x - width * 0.5;
+    const position_y: number = y - height;
+    // 定义圆角的半径、宽度、高度
+    let r: number = 10;
+    let w: number = width;
+    let h: number = height - r;
+    // 缩放
+    this.canvas.scale(1, 1);
+    // 文字提示框的颜色
+    this.canvas.fillStyle = '#ccc';
+
+    // 开始
+    this.canvas.beginPath();
+    // 画笔移动到起始位置
+    this.canvas.moveTo(position_x + r, position_y);
+    // 绘制右上角的圆角
+    this.canvas.arcTo(position_x + w, position_y, position_x + w, position_y + h, r);
+    // 绘制右下角的圆角
+    this.canvas.arcTo(position_x + w, position_y + h, position_x, position_y + h, r);
+    // 画三角形轮廓
+    // 绘制到三角形起点的位置
+    this.canvas.lineTo(position_x + w, position_y + h);
+    // 绘制三角形的起点到顶点的线段
+    this.canvas.lineTo(position_x + w / 2 + 10, position_y + h);
+    // 绘制顶点到三角形另一边的线段
+    this.canvas.lineTo(position_x + w / 2, position_y + h + r);
+    // 绘制三角形结束点到左下方的圆角起始处
+    this.canvas.lineTo(position_x + w / 2 - 10, position_y + h);
+    // 绘制左下角的圆角
+    this.canvas.arcTo(position_x, position_y + h, position_x, position_y, r);
+    // 绘制左上角的圆角
+    this.canvas.arcTo(position_x, position_y, position_x + w, position_y, r);
+    // 设置阴影
+    // this.canvas.fillStyle = '#d9d9d4';
+    this.canvas.shadowBlur = 5; // 模糊尺寸
+    this.canvas.shadowOffsetX = 2; // 阴影Y轴偏移
+    this.canvas.shadowOffsetY = 2; // 阴影X轴偏移
+    // 关闭,形成一个闭合的回路---->轮廓
+    this.canvas.closePath();
+    this.canvas.fill();
+    this.canvas.font = '12px Arial';
+    this.canvas.fillStyle = '#0f1659';
+    for (let i: number = 0; i < titleArray.length; i++) {
+      this.canvas.fillText(titleArray[i], position_x + 6, position_y + ((i + 1) * 16));
       this.canvas.save();
-    };
+    }
   }
 }

+ 10 - 12
train-web/src/pages/train/index.vue

@@ -4,11 +4,11 @@
   </div>
 </template>
 <script setup lang="ts">
-import { DrawTrack } from './controller/DrawTrack'
-import { DrewTrain } from './controller/DrewTrain.ts'
-import { StoreTrain } from '@/store/modules/train.ts'
-import { useStoreSocket } from '@/store/socket'
-import { TrainItem } from "@/types/train-travel";
+import {DrawTrack} from './controller/DrawTrack'
+import {DrewTrain} from './controller/DrewTrain.ts'
+import {StoreTrain} from '@/store/modules/train.ts'
+import {useStoreSocket} from '@/store/socket'
+import {TrainItem} from "@/types/train-travel";
 
 const canvasRef = ref<HTMLCanvasElement>();
 const storeTrain = StoreTrain();
@@ -45,21 +45,19 @@ const drawAll = function (): void {
   ctx.save();
 
   // 绘制车道
-  drawTrack.drawLine(storeTrain.getSelectionUpList, true);
-  drawTrack.drawLine(storeTrain.getSelectionDownList, false);
+  drawTrack.drawLine(storeTrain.getSelectionUpList);
+  drawTrack.drawLine(storeTrain.getSelectionDownList);
   // 绘制信号灯
   drawTrack.drawSignalList(storeTrain.getSignalUpList, true);
   drawTrack.drawSignalList(storeTrain.getSignalDownList, false);
   // 绘制道岔
   drawTrack.drawSwitchList(storeTrain.getSwitchList);
 
+  const drawTrain = new DrewTrain(ctx);
   const storeSocket = useStoreSocket();
   let trainList = storeSocket.trainList;
   for (let i = 0; i < trainList.length; i++) {
-    const item: TrainItem = trainList[i];
-    // 绘制列车
-    const drawTrain = new DrewTrain(ctx);
-    drawTrain.draw(Number(item.kilometer), item.direction == 1);
+    drawTrain.drawTrain(trainList[i]);
   }
 }
 // 组件初始化
@@ -73,4 +71,4 @@ onBeforeUnmount(() => {
     clearInterval(intervalId.value);
   }
 })
-</script>
+</script>

+ 7 - 7
train-web/src/store/modules/train.ts

@@ -1,6 +1,6 @@
-import {defineStore} from "pinia";
-import {signalAll, selectionAll, switchAll} from '@/api/train'
-import {SignalItem, SelectionItem, SwitchItem} from '@/types/train-travel'
+import { defineStore } from "pinia";
+import { signalAll, selectionAll, switchAll } from '@/api/train'
+import { SignalItem, SelectionItem, SwitchItem, DirectionEnum } from '@/types/train-travel'
 
 export const StoreTrain = defineStore("train", {
   state: () => {
@@ -15,19 +15,19 @@ export const StoreTrain = defineStore("train", {
       return this.signalList;
     },
     getSignalUpList(): SignalItem[] {
-      return this.signalList.filter(item => item.direction == 1);
+      return this.signalList.filter(item => item.direction == DirectionEnum.UP);
     },
     getSignalDownList(): SignalItem[] {
-      return this.signalList.filter(item => item.direction == 2);
+      return this.signalList.filter(item => item.direction == DirectionEnum.DOWN);
     },
     getSelectionList(): SelectionItem[] {
       return this.selectionList;
     },
     getSelectionUpList(): SelectionItem[] {
-      return this.selectionList.filter(item => item.direction == 1);
+      return this.selectionList.filter(item => item.direction == DirectionEnum.UP);
     },
     getSelectionDownList(): SelectionItem[] {
-      return this.selectionList.filter(item => item.direction == 2);
+      return this.selectionList.filter(item => item.direction == DirectionEnum.DOWN);
     },
     getSwitchList(): SwitchItem[] {
       return this.switchList;

+ 0 - 3
train-web/src/store/socket.ts

@@ -26,9 +26,6 @@ export const useStoreSocket = defineStore("websocket", {
     getRouteList(): RouteItem[] {
       return this.routeList;
     },
-    getSelectionList(): SelectionItem[] {
-      return this.routeList.map(item => item.selectionList).flatMap(item => item);
-    }
   },
   actions: {
     connect(url: string, protocol?: string) {

+ 30 - 11
train-web/src/types/train-travel.ts

@@ -5,23 +5,27 @@ export enum CommandEnum {
   ROAD_SWITCH = 10103, // 道岔状态信息
   ROUTE_STATUS = 10104, // 进路状态信息
 }
+
 // 枚举上下行
 export enum DirectionEnum {
   UP = 1, // 上行
   DOWN = 2 // 下行
 }
+
 // 进路状态
-export enum RouteStatusEnum {
+export enum SectionStatusEnum {
   OCCUPY = 1, // 占用 红光带 #FF0000
   IDLE = 2, // 出清/空闲 灰光带 #EEEEEE
   LOCK = 3, //锁闭 白光带 #FFFFFF
 }
+
 export enum SignalStateEnum {
   RED = 1, // 禁止通行
   GREEN = 2, // 允许通行
   YELLOW = 3, // 道岔
   RED_YELLOW = 4, //
 }
+
 export enum SwitchStateEnum {
   LOCATE = 1, // 定位
   REVERSE = 2, // 反位
@@ -49,7 +53,7 @@ export type SelectionItem = {
   direction: DirectionEnum;
   zfState: boolean;
   stationId: number;
-  status: RouteStatusEnum;
+  status: SectionStatusEnum;
   isSwitch: boolean;
 }
 // 道岔
@@ -70,7 +74,6 @@ export type TrainItem = {
   trainNo: string;
   trainLength: number
   direction: number;
-  kilometer: number;
   blockId: number;
   blockNo: number;
   offset: number;
@@ -79,12 +82,28 @@ export type TrainItem = {
 }
 // 进路
 export type RouteItem = {
-  id: number;
-  name: string;
-  trigPosition: number;
-  routeStatus: RouteStatusEnum;
-  nextId: number | null;
+  // 区段Id
+  sectionId: number;
+  // 区段名称
+  sectionName: string;
+  // 区段长度
+  sectionLength: number;
+  // 区段状态
+  sectionStatus: SectionStatusEnum;
+  // 开始公里标
+  startKilometer: number;
+  // 是否是道岔
+  isSwitch: boolean;
+  // 方向
+  direction: DirectionEnum;
+
+  // 进路Id
+  routeId: number;
+  // 进路名称
+  routeName: string;
 
-  selectionList: SelectionItem[];
-  signalList: SignalItem[];
-}
+  // 下一个区段Id
+  sectionNextId: number;
+  // 上一个区段Id
+  sectionPreId: number;
+}