仿真ats重构-MA移动授权逻辑重构,ATS进路触发逻辑调整,进路正常开始解锁逻辑判断流程调整(现根据进路第一区段占用情况触发)

This commit is contained in:
walker-sheng 2021-08-03 13:53:49 +08:00
parent 670ed1163a
commit 653a29eb65
24 changed files with 739 additions and 176 deletions

View File

@ -281,13 +281,13 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
public void pause() {
this.updateState(PAUSE);
while (true) {
try {
Thread.sleep(BASE_RATE);
} catch (InterruptedException e) {
}
if (this.mainLogicRunning.get() == false) {
break;
}
try {
Thread.sleep(5);
} catch (InterruptedException e) {
}
}
log.debug(String.format("仿真[%s]暂停", this.id));
}

View File

@ -4,7 +4,6 @@ import club.joylink.rtss.simulation.cbtc.CI.CiApiService;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.data.CalculateService;
import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository;
import club.joylink.rtss.simulation.cbtc.data.map.Route;
import club.joylink.rtss.simulation.cbtc.data.map.Section;
import club.joylink.rtss.simulation.cbtc.data.map.Signal;
import club.joylink.rtss.simulation.cbtc.data.support.SectionPosition;
@ -28,40 +27,6 @@ public class AtpSectionService {
@Autowired
private CiApiService ciApiService;
/**
* 收集信号机跨压信息发送给CI
*/
public void collectAndSendSignalAcrossMessage2CI(Simulation simulation, List<VirtualRealityTrain> onlineTrainList,
Map<String, List<Section>> trainAtpSectionMap) {
Set<String> signalAcrossSet = new HashSet<>(); // 跨压信号机
List<Signal> signalList = simulation.getRepository().getSignalList();
signalList.forEach(signal -> {
// if (!signal.isNormalOpen()) {
// return;
// }
Route lockedRoute = signal.getLockedRoute();
if (Objects.isNull(lockedRoute)) {
return;
}
Section section = signal.getSection();
Section nextSection = section.getNextRunningSectionOf(signal.isRight());
boolean across = false;
for (VirtualRealityTrain train : onlineTrainList) {
List<Section> atpSectionList = trainAtpSectionMap.get(train.getGroupNumber());
List<Section> physicalList = this.convert2PhysicalSectionList(atpSectionList);
if (physicalList.contains(section) && physicalList.contains(nextSection)) {
across = true;
break;
}
}
String signalCode = signal.getCode();
if (across) {
signalAcrossSet.add(signalCode);
}
});
this.ciApiService.handleSignalAcrossMessage(simulation, signalAcrossSet);
}
/**
* 收集列车接近信号机消息并发送给CI
*/

View File

@ -56,8 +56,7 @@ public class GroundAtpApiServiceImpl implements GroundAtpApiService {
// 更新保存新的占用
repository.addOrUpdateTrainOccupyAtpSectionList(train.getGroupNumber(), trainAtpSectionList);
}
// 信号机接近信息停稳信息跨压信息通知
this.atpSectionService.collectAndSendSignalAcrossMessage2CI(simulation, onlineTrainList, trainAtpSectionMap);
// 信号机接近信息停稳信息通知
Map<VirtualRealityTrain, Signal> nctApproachSignalMap =
this.atpSectionService.collectAndSendSignalApproachMessage2CI(simulation, onlineTrainList, trainAtpSectionMap);

View File

@ -0,0 +1,428 @@
package club.joylink.rtss.simulation.cbtc.ATP.ground;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.data.CalculateService;
import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository;
import club.joylink.rtss.simulation.cbtc.data.map.*;
import club.joylink.rtss.simulation.cbtc.data.support.SectionPosition;
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityTrain;
import club.joylink.rtss.simulation.cbtc.onboard.ATO.SpeedCurve;
import club.joylink.rtss.simulation.cbtc.onboard.ATP.OnboardAtpApiService;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.stream.Collectors;
/**
* 移动授权计算服务
*/
@Component
public class MaService {
@Autowired
private OnboardAtpApiService onboardAtpApiService;
@Getter
public static class Ma {
public static final int Safety_Margin = 10; // 安全余量单位m
public static final int EB_Trigger = 20; // 紧急制动触发点偏移量单位m
public static final int Safety_Distance = 30; // 安全距离 单位m
VirtualRealityTrain train; // 列车
MapNamedElement device; // 终端设备
MaType type; // 类型
SectionPosition eoaPosition; // 授权终端位置
float distanceToEoa; // 距离
/**
* 紧急制动触发曲线
*/
private SpeedCurve ebTriggerCurve;
/**
* ATO停车曲线
*/
private SpeedCurve atoStopCurve;
/**
* 移动的累计距离
*/
private float moveLen;
public Ma(VirtualRealityTrain train, MapNamedElement device, MaType type) {
this.train = train;
this.device = device;
this.type = type;
this.getEoaPosition();
this.calculateDistanceToEoa();
}
public void addMoveLen(float len) {
this.moveLen += len;
}
public void setEbTriggerCurve(SpeedCurve ebTriggerCurve) {
this.ebTriggerCurve = ebTriggerCurve;
}
public void setAtoStopCurve(SpeedCurve atoStopCurve) {
this.atoStopCurve = atoStopCurve;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Ma ma = (Ma) o;
return Objects.equals(eoaPosition, ma.eoaPosition);
}
@Override
public int hashCode() {
return Objects.hash(eoaPosition);
}
public String debugStr() {
return String.format("列车[%s]位置:%s, 移动授权为:{类型: %s, 设备: %s, EOA: %s, distance: %s}",
this.train.getGroupNumber(),
this.train.getHeadPosition().toString(),
this.type,
this.device.debugStr(),
this.eoaPosition.toString(),
this.distanceToEoa);
}
public float calculateDistanceToEoa() {
SectionPosition headPosition = train.getHeadPosition();
boolean right = train.isRight();
Float distance = CalculateService.calculateDistance(headPosition, this.eoaPosition, right);
if (distance == null) {
distance = CalculateService.calculateDistance(headPosition, this.eoaPosition, !right);
if (distance > 0) {
distance = -distance;
}
}
this.distanceToEoa = distance;
return distanceToEoa;
}
public float calculateDistanceOfEbTriggerEnd() {
if (this.type.equals(MaType.Limit_Signal_Without_Overlap)) {
Signal signal = (Signal) this.device;
if (signal.getSection().isJustTurnBackTrack()) {
return this.calculateDistanceToEoa();
}
}
return this.calculateDistanceToEoa() - EB_Trigger;
}
public float calculateDistanceOfAtoEnd() {
if (this.type.equals(MaType.Limit_Signal_With_Overlap) ||
this.type.equals(MaType.Limit_Signal_Without_Overlap)) {
Signal signal = (Signal) this.device;
SectionPosition sectionPosition = new SectionPosition(signal.getSection(), signal.getOffset());
boolean right = this.train.isRight();
SectionPosition end = CalculateService.calculateNextPositionByStartAndLen(sectionPosition, !right, 2);
return CalculateService.calculateDistance(this.train.getHeadPosition(), end, right);
} else {
return this.calculateDistanceOfEbTriggerEnd() - Safety_Distance;
}
}
public SectionPosition getEoaPosition() {
SectionPosition eoa;
boolean right = this.train.isRight();
switch (this.type) {
case Front_Train: {
VirtualRealityTrain frontTrain = (VirtualRealityTrain) this.device;
if (frontTrain.isRight() == right) {
eoa = frontTrain.getTailPosition();
} else {
eoa = frontTrain.getHeadPosition();
}
eoa = CalculateService.calculateNextPositionByStartAndLen(eoa, !right, 10 + frontTrain.getSpeed() * 2);
break;
}
case Axle_Occupy_Section:{
Section aoSection = (Section) this.device;
eoa = this.buildEoaOfAxleOccupySection(aoSection, right);
break;
}
case Limit_Signal_Without_Overlap:{
Signal signal = (Signal) this.device;
Section section = signal.getSection();
eoa = new SectionPosition(section, right ? section.getLen() : 0);
break;
}
case Limit_Signal_With_Overlap:{
Signal signal = (Signal) this.device;
eoa = this.buildEoaOfLimitSignalWithOverlap(signal, right);
break;
}
case ZC_Boundary:{
Section section = (Section) this.device;
eoa = new SectionPosition(section, right ? section.getLen() : 0);
break;
}
case Closed_Section:
case Fault_Route:{
Section section = (Section) this.device;
eoa = new SectionPosition(section, right ? 0 : section.getLen());
break;
}
case Stand:{
Section section = (Section) this.device;
float offset = section.getStopPointByDirection(right);
offset = right ? offset - train.getLen() - 20 : offset + train.getLen() + 20;
eoa = CalculateService.getAvailableSectionPositionOf(new SectionPosition(section, offset));
break;
}
default:
throw new IllegalStateException("未知的移动授权类型: " + this.type);
}
this.eoaPosition = eoa;
return eoa;
}
private SectionPosition buildEoaOfAxleOccupySection(Section aoSection, boolean right) {
SectionPosition headPosition = this.train.getHeadPosition();
if (aoSection.equals(headPosition.getSection())) { // 车头区段
return new SectionPosition(aoSection, right ? 0 : aoSection.getLen());
}
// 非车头区段取非通信车占用区段与列车运行方向反向区段
// 如果此区段是道岔区段且不是车头区段则从列车车头区段往前找,直到第一个和此道岔区段为同一道岔计轴的道岔区段
Section front = aoSection.getSectionOf(!right);
if (front.isSwitchTrack() && !front.equals(headPosition.getSection())) {
Section section = headPosition.getSection();
for (int i = 0; i < 20; i++) {
Section fs = section.getNextRunningSectionOf(right);
if (fs.isSameAxle(front.getCode())) {
front = fs;
break;
}
}
}
return new SectionPosition(front, right ? 0 : front.getLen());
}
private SectionPosition buildEoaOfLimitSignalWithOverlap(Signal signal, boolean right) {
List<RouteOverlap> overlapList = signal.getOverlapList();
Section section = this.queryOverlapLockedEndSection(overlapList);
if (section == null) {
section = signal.getSection();
}
return new SectionPosition(section, right ? section.getLen() : 0);
}
private Section queryOverlapLockedEndSection(List<RouteOverlap> overlapList) {
for (RouteOverlap routeOverlap : overlapList) {
if (routeOverlap.isLock()) {
List<SectionPath> pathList = routeOverlap.getPathList();
for (SectionPath sectionPath : pathList) {
List<Section> sectionList = sectionPath.getSectionList();
if (sectionList.get(sectionList.size() - 1).isOverlapLock()) {
return sectionList.get(sectionList.size() - 1);
}
}
}
}
return null;
}
}
/**
* 移动授权类型
*/
public enum MaType {
/** 前方列车 */
Front_Train,
/** 计轴占用区段 */
Axle_Occupy_Section,
/** 没有延续保护的限制信号机 */
Limit_Signal_Without_Overlap,
/** 有延续保护的限制信号机 */
Limit_Signal_With_Overlap,
/** ZC边界 */
ZC_Boundary,
/** 关闭的区段 */
Closed_Section,
/** 进路联锁条件不再完备 */
Fault_Route,
/** 站台问题(屏蔽门或紧急停车) */
Stand,
}
public void calculateMaOfCtcTrains(Simulation simulation) {
SimulationDataRepository repository = simulation.getRepository();
Map<String, VirtualRealityTrain> usedTrainMap = repository.getUsedTrainMap();
usedTrainMap.values().forEach(vrTrain -> vrTrain.calculateTailPosition());
for (VirtualRealityTrain vrTrain : usedTrainMap.values()) {
if (vrTrain.isRMMode() || vrTrain.isNRMMode()) {
continue;
}
if (vrTrain.isCommunication()) {
Ma ma = this.calculateCtcMa(simulation, vrTrain, usedTrainMap);
if (ma.distanceToEoa <= 0) {
System.out.println(ma.debugStr());
}
this.onboardAtpApiService.updateCtcMa(simulation, ma);
}
}
}
public Ma calculateCtcMa(Simulation simulation, VirtualRealityTrain train, Map<String, VirtualRealityTrain> trainMap) {
SectionPosition headPosition = train.getHeadPosition();
SectionPosition tailPosition = train.getTailPosition();
boolean right = train.isRight();
Ma ma = null;
boolean front = false;
Section section = tailPosition.getSection();
for (int i = 0; i < 20 && section != null; i++) {
if (section.equals(headPosition.getSection())) {
front = true;
}
Route route = section.getRoute();
if (route != null) {
if (this.isSwitchFaultRoute(route, section)) {
// 道岔故障进路直接构建返回
ma = new Ma(train, section, MaType.Fault_Route);
break;
}
}
if (section.isClosed()) {
// 关闭的区段
ma = this.checkAndUpdateMa(ma, new Ma(train, section, MaType.Closed_Section));
}
if (this.isFaultStand(section)) {
// 故障/紧急停车站台
ma = this.checkAndUpdateMa(ma, new Ma(train, section, MaType.Stand));
}
Section next = section.getNextRunningSectionOf(right);
if (front) { // 车头前方
Signal signal = section.getSignalOf(right);
if (signal != null && !signal.isNormalOpen()) {
// 限制信号机
if (signal.isOverlapLock()) {
ma = this.checkAndUpdateMa(ma, new Ma(train, signal, MaType.Limit_Signal_With_Overlap));
} else {
ma = this.checkAndUpdateMa(ma, new Ma(train, signal, MaType.Limit_Signal_Without_Overlap));
}
}
if (section.hasNctOccupy()) {
// 计轴占用区段
ma = this.checkAndUpdateMa(ma, new Ma(train, section, MaType.Axle_Occupy_Section));
} else if (section.isOnlyCtcOccupy()) {
// 前方列车
Ma ma2 = this.queryFrontTrain(train, section, trainMap);
ma = this.checkAndUpdateMa(ma, ma2);
}
// ZC(尽头区段)边界
if (!section.anyZcWorking() &&
(headPosition.getSection().equals(section) ||
!headPosition.isAheadOf(new SectionPosition(section, right ? section.getLen() : 0), right))) {
ma = this.checkAndUpdateMa(ma, new Ma(train, section, MaType.ZC_Boundary));
}
if (next == null || (!next.anyZcWorking())) {
ma = this.checkAndUpdateMa(ma, new Ma(train, section, MaType.ZC_Boundary));
}
}
section = next;
if (ma != null) {
break;
}
}
return ma;
}
private boolean isFaultStand(Section section) {
if (section.isNormalStandTrack()) {
for (Stand stand : section.getStandList()) {
if (stand.isEmergencyClosed()) {
return true;
}
PSD psd = stand.getPsd();
if (psd != null && (!psd.isCloseAndLock() && !psd.isInterlockRelease()) && !stand.isTrainParking()) {
return true;
}
}
}
return false;
}
private boolean isSwitchFaultRoute(Route route, Section section) {
boolean switchFault = false;
List<Section> sectionList = route.getSectionList();
Set<String> handledSwitchSet = new HashSet<>();
boolean flag = false;
for (Section routeSection : sectionList) {
if (routeSection.equals(section)) {
flag = true;
}
if (flag) {
if (routeSection.isSwitchTrack()) {
if (handledSwitchSet.contains(routeSection.getRelSwitch().getCode())) {
continue;
}
SwitchElement switchElement = route.getRouteSwitchElement(routeSection.getRelSwitch());
Switch aSwitch = switchElement.getASwitch();
handledSwitchSet.add(aSwitch.getCode());
if (route.equals(aSwitch.getRoute())) {
if (aSwitch.isLoss()) {
switchFault = true;
break;
} else {
RouteFls fls = route.getRouteFlsOfSwitch(aSwitch);
if (fls != null) {
List<RouteFls.FlsElement> level1List = fls.getLevel1List();
for (RouteFls.FlsElement flsElement : level1List) {
SwitchElement pSwitch = flsElement.getPSwitch();
if (pSwitch != null && pSwitch.getASwitch().isLoss()) {
switchFault = true;
break;
}
}
}
}
}
if (switchFault) {
break;
}
}
}
}
return switchFault;
}
private Ma checkAndUpdateMa(Ma ma, Ma ma2) {
if (ma == null) {
return ma2;
} else if(ma2 != null) {
if (ma.distanceToEoa > ma2.distanceToEoa) {
return ma2;
}
}
return ma;
}
private Ma queryFrontTrain(VirtualRealityTrain train, Section section,
Map<String, VirtualRealityTrain> trainMap) {
List<VirtualRealityTrain> trainList = trainMap.values().stream()
.filter(vrTrain -> !vrTrain.equals(train) &&
(vrTrain.getHeadPosition().getSection().equals(section) ||
vrTrain.getTailPosition().getSection().equals(section)))
.collect(Collectors.toList());
Ma ma = null;
if (trainList.isEmpty()) {
return null;
} else {
for (VirtualRealityTrain vrTrain : trainList) {
Ma ma1 = new Ma(train, vrTrain, MaType.Front_Train);
if (ma1.getDistanceToEoa() > 0) {
ma = this.checkAndUpdateMa(ma, ma1);
}
}
}
return ma;
}
}

View File

@ -5,8 +5,6 @@ import club.joylink.rtss.simulation.cbtc.ATS.AtsApiService;
import club.joylink.rtss.simulation.cbtc.CI.service.RouteService;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.constant.RunLevel;
import club.joylink.rtss.simulation.cbtc.constant.SimulationConstants;
import club.joylink.rtss.simulation.cbtc.constant.SimulationModule;
import club.joylink.rtss.simulation.cbtc.data.CalculateService;
import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository;
import club.joylink.rtss.simulation.cbtc.data.map.*;
@ -39,6 +37,9 @@ public class ZCLogicLoop {
@Autowired
private AtsApiService atsApiService;
@Autowired
private MaService maService;
@Autowired
private RouteService routeService;
@ -680,6 +681,7 @@ public class ZCLogicLoop {
}
public void addJobs(Simulation simulation) {
simulation.addJob(SimulationModule.ZC.name(), () -> this.run(simulation), SimulationConstants.ZC_LOOP_RATE);
// simulation.addJob(SimulationModule.ZC.name(), () -> this.run(simulation), SimulationConstants.ZC_LOOP_RATE);
simulation.addJob("MaCal", () -> this.maService.calculateMaOfCtcTrains(simulation), 1000);
}
}

View File

@ -349,7 +349,7 @@ public class ATSMessageCollectAndDispatcher {
}
public void addJobs(Simulation simulation) {
simulation.addFixedRateJob(SimulationModule.SYNC_TIME.name(), () -> this.syncTime(simulation), SimulationConstants.SYNC_TIME_RATE);
simulation.addJob(SimulationModule.SYNC_TIME.name(), () -> this.syncTime(simulation), SimulationConstants.SYNC_TIME_RATE);
simulation.addFixedRateJob(SimulationModule.MESSAGE.name(), () -> this.run(simulation), SimulationConstants.SEND_CLIENT_RATE);
}
}

View File

@ -2,6 +2,7 @@ package club.joylink.rtss.simulation.cbtc.ATS.service;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.cbtc.ATP.ground.GroundAtpApiService;
import club.joylink.rtss.simulation.cbtc.ATP.ground.MaService;
import club.joylink.rtss.simulation.cbtc.ATP.ground.ZCLogicLoop;
import club.joylink.rtss.simulation.cbtc.CI.CILogicLoop;
import club.joylink.rtss.simulation.cbtc.CI.service.RouteService;
@ -65,6 +66,8 @@ public class AtsTrainLoadService {
@Autowired
private ZCLogicLoop zcLogicLoop;
@Autowired
private MaService maService;
@Autowired
private VRTrainRunningService vrTrainRunningService;
@ -405,6 +408,7 @@ public class AtsTrainLoadService {
// 列车上线并构建ATS监控列车信息
this.trainOnlineAndBuildSupervise(simulation, loadedList);
// 计算移动授权
// this.maService.calculateMaOfCtcTrains(simulation);
this.zcLogicLoop.run(simulation);
// // 更新列车速度
// this.updateTrainSpeed(simulation);

View File

@ -109,9 +109,7 @@ public class AtsTrainMonitorService {
if (dlen < SimulationConstants.PARK_POINT_MAX_OFFSET) {
// 停车点停车
this.trainParking(simulation, trainInfo, headSection.getStation(), headSection);
if (headSection.isNormalStandTrack()) {
this.onboardAtpApiService.parkingInPlace(simulation, vrTrain);
}
this.onboardAtpApiService.parkingInPlace(simulation, vrTrain, headSection);
}
}
}

View File

@ -147,6 +147,10 @@ public class AtsTriggerRouteService {
if (!trainInfo.isPlanTrain()) {
return false;
}
// 计划车没有下一个计划可能是加载折返情况
if (trainInfo.getPlanStandTrack() == null) {
return true;
}
SimulationDataRepository repository = simulation.getRepository();
TripPlan tripPlan = repository.getTripPlan(trainInfo.getServiceNumber(), trainInfo.getTripNumber());
List<StationPlan> planList = tripPlan.getPlanList();
@ -155,12 +159,6 @@ public class AtsTriggerRouteService {
StationPlan stationPlan = planList.get(i - 1);
StationPlan next = planList.get(i);
List<RoutePath> currentPaths = repository.getRoutePaths(stationPlan.getSection(), next.getSection());
if (i == 1 && stationPlan.getSection().getCode().equals(trainInfo.getPlanStandTrack())) {
if (currentPaths.get(0).isRight() != route.isRight()) {
return true;
}
break;
}
boolean opposite = false;
if (next.getSection().getCode().equals(trainInfo.getPlanStandTrack())) {
if (i + 1 < size) {

View File

@ -9,7 +9,6 @@ import club.joylink.rtss.simulation.cbtc.data.support.SignalApproachMessage;
import club.joylink.rtss.simulation.cbtc.data.support.TrainStopMessage;
import java.util.List;
import java.util.Set;
/**
* CI子系统接口
@ -275,13 +274,6 @@ public interface CiApiService {
*/
void handleSignalApproachMessage(Simulation simulation, List<SignalApproachMessage> approachMessageList);
/**
* 接收处理信号机跨压信息
* @param simulation
* @param acrossMessageList
*/
void handleSignalAcrossMessage(Simulation simulation, Set<String> acrossMessageList);
/**
* 接收处理列车停稳信息
* @param simulation

View File

@ -7,7 +7,6 @@ import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository;
import club.joylink.rtss.simulation.cbtc.data.map.*;
import club.joylink.rtss.simulation.cbtc.data.support.SignalApproachMessage;
import club.joylink.rtss.simulation.cbtc.data.support.TrainStopMessage;
import club.joylink.rtss.simulation.cbtc.data.vo.TrainInfo;
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealitySectionAxleCounter;
import club.joylink.rtss.simulation.cbtc.exception.SimulationException;
import club.joylink.rtss.simulation.cbtc.exception.SimulationExceptionType;
@ -21,7 +20,6 @@ import java.time.LocalTime;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
/**
@ -394,20 +392,6 @@ public class CiApiServiceImpl implements CiApiService {
});
}
@Override
public void handleSignalAcrossMessage(Simulation simulation,
Set<String> acrossMessageList) {
acrossMessageList.forEach(signalCode -> {
Signal signal = simulation.getRepository().getByCode(signalCode, Signal.class);
// if (signal.isNormalOpen()) {
Route lockedRoute = signal.getLockedRoute();
if (Objects.nonNull(lockedRoute)) {
this.routeService.normalUnlockStart(simulation, lockedRoute);
}
// }
});
}
@Override
public void handleTrainStopMessage(Simulation simulation, TrainStopMessage stopMessage) {
this.routeService.handleTrainStopMessage(simulation, stopMessage);

View File

@ -1336,6 +1336,12 @@ public class RouteService {
}
}
if (route.isOpen()) {
// 判断是否列车进入正常解锁
Section firstLogicSection = route.getFirstLogicSection();
if (firstLogicSection.isCtOccupied() || firstLogicSection.isNctOccupied()) {
this.normalUnlockStart(simulation, route);
return;
}
boolean interlocked = this.isInterlocked(route);
if (!interlocked) {
// 进路信号开放联锁逻辑不满足需关闭信号

View File

@ -52,8 +52,10 @@ public class InterlockBuilder2 {
Signal signal = unlockSection.getSignalOf(mapOverlapVO.isRight());
if (Objects.isNull(signal)) {
errMsgList.add(String.format("延续保护[%s(%s)]数据异常,无法找到防护起始信号机", routeOverlap.getName(), routeOverlap.getCode()));
} else {
routeOverlap.setSignal(signal);
signal.getOverlapList().add(routeOverlap);
}
routeOverlap.setSignal(signal);
}
if (Objects.isNull(mapOverlapVO.getUnlockTime()) || mapOverlapVO.getUnlockTime() <= 0) {
errMsgList.add(String.format("延续保护[%s(%s)]的解锁时间未设置或小于0", routeOverlap.getName(), routeOverlap.getCode()));

View File

@ -522,16 +522,35 @@ public class Section extends MayOutOfOrderDevice {
}
/**
* 有非通信车占用
* 是否有非通信车占用
*
* @return
*/
public boolean hasNctOccupy() {
boolean nct = this.nctOccupied && !this.ctOccupied;
if (!CollectionUtils.isEmpty(this.logicList)) {
return this.logicList.stream().anyMatch(section -> !section.isCtOccupied() && section.isNctOccupied());
} else {
return !this.isCtOccupied() && this.isNctOccupied();
nct = false;
for (Section logic : this.logicList) {
if (!logic.isCtOccupied() && logic.isNctOccupied()) {
nct = true;
break;
}
}
}
return nct;
}
public boolean isOnlyCtcOccupy() {
boolean ctOccupied = this.ctOccupied;
if (!CollectionUtils.isEmpty(this.logicList)) {
for (Section logic : this.logicList) {
if (logic.isCtOccupied()) {
ctOccupied = true;
break;
}
}
}
return ctOccupied;
}
public List<Section> getAtpSectionListBy(float offset1, float offset2) {

View File

@ -24,6 +24,7 @@ public class Signal extends MayOutOfOrderDevice {
super(code, name, DeviceType.SIGNAL);
this.redOpen = true;
this.routeList = new ArrayList<>();
this.overlapList = new ArrayList<>();
}
// ------------------固有属性/关联关系---------------------
@ -119,6 +120,10 @@ public class Signal extends MayOutOfOrderDevice {
* 进路列表
*/
private List<Route> routeList;
/**
* 延续保护列表
*/
private List<RouteOverlap> overlapList;
/**
* 接近锁闭解锁时间

View File

@ -50,8 +50,8 @@ public class SectionPosition {
@Override
public String toString() {
return "{" +
String.format("section:[%s(%s)]", section.getName(), section.getCode()) +
String.format(", offset:[%s]", offset) +
String.format("%s(%s)", section.getName(), section.getCode()) +
String.format(", %s", offset) +
'}';
}

View File

@ -1,5 +1,6 @@
package club.joylink.rtss.simulation.cbtc.data.vr;
import club.joylink.rtss.simulation.cbtc.ATP.ground.MaService;
import club.joylink.rtss.simulation.cbtc.constant.*;
import club.joylink.rtss.simulation.cbtc.data.CalculateService;
import club.joylink.rtss.simulation.cbtc.data.map.*;
@ -31,6 +32,11 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
*/
public static final float Emergency_Acceleration = -1.5f;
/**
* 紧急制动触发曲线计算加速度矢量
*/
public static final float Emergency_Trigger_Acceleration = -1.1f;
/**
* 非紧急制动状态下最大制动加速度标量
*/
@ -176,6 +182,10 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
* 车头位置
*/
private SectionPosition headPosition;
/**
* 车尾位置
*/
private SectionPosition tailPosition;
/**
* 是否向右行驶
@ -191,6 +201,10 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
* 移动授权
*/
private MovementAuthority ma;
/**
* 移动授权
*/
private MaService.Ma ma2;
/**
* 未收到CBTC级别ma的时长单位毫秒
@ -461,6 +475,7 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
super(code, groupNumber, DeviceType.TRAIN);
this.groupNumber = groupNumber;
this.gear = ControlGear.Drive;
this.communication = true;
this.atpOn = true;
this.door1 = new Door("1");
this.door2 = new Door("2");
@ -489,6 +504,7 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
this.terminalStation = null;
this.headPosition = null;
this.robotTargetPosition = null;
this.ma2 = null;
this.ma = null;
this.cbtcMaMissDuration = 0;
this.itcMaMissDuration = 0;
@ -613,9 +629,16 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
this.autoOpenATO = this.atoOn;
}
public void setTarget(Section target) {
this.target = target;
// if (this.ma2 != null) {
// SpeedCurve.calculateAtoStopCurveAndUpdate(this, this.ma2);
// }
}
public synchronized void updateNextStationPlan(Station nextStation, Section targetSection, boolean nextParking) {
this.nextStation = nextStation;
this.target = targetSection;
this.setTarget(targetSection);
this.nextParking = nextParking;
// log.info(String.format("列车[%s]更新下一站[%s] 轨道[%s], [%s]",
@ -625,7 +648,7 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
}
public void startTurnBack(Section tbSection) {
this.target = tbSection;
this.setTarget(tbSection);
this.dtro = true;
this.nextStation = null;
this.terminalStation = null;
@ -688,6 +711,7 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
public void clearMa() {
this.ma = null;
this.ma2 = null;
}
/**
@ -715,7 +739,8 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
}
public SectionPosition calculateTailPosition() {
return CalculateService.calculateNextPositionByStartAndLen(this.headPosition, !right, this.getLen());
this.tailPosition = CalculateService.calculateNextPositionByStartAndLen(this.headPosition, !right, this.getLen());
return this.tailPosition;
}
/**
@ -986,9 +1011,12 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
}
}
public synchronized void parkingAt() {
// this.parkRemainTime = 30 * 1000;
this.standParkedTrainActivity = StandParkedTrainActivity.PARK;
public synchronized void parkingAt(Section headSection) {
if (headSection.isNormalStandTrack()) {
this.standParkedTrainActivity = StandParkedTrainActivity.PARK;
} else {
this.standParkedTrainActivity = StandParkedTrainActivity.START;
}
}
public boolean isParkingAt() {

View File

@ -1,5 +1,7 @@
package club.joylink.rtss.simulation.cbtc.onboard.ATO;
import club.joylink.rtss.simulation.cbtc.ATP.ground.MaService;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.data.CalculateService;
import club.joylink.rtss.simulation.cbtc.data.map.Section;
import club.joylink.rtss.simulation.cbtc.data.storage.ato.StorageSpeedCalculator;
@ -14,6 +16,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@ -44,6 +47,51 @@ public class SpeedCurve {
this.speedCalculators = speedCalculators;
}
public static void calculateAndUpdate(Simulation simulation, VirtualRealityTrain train, MaService.Ma ma) {
if (ma.equals(train.getMa2())) {
return;
}
// log.debug(String.format("系统时间:[%s],更新——%s",
// simulation.getSystemTime(),
// ma.debugStr()));
train.setMa2(ma);
SpeedCurve.calculateEbTriggerCurveAndUpdate(train, ma);
SpeedCurve.calculateAtoStopCurveAndUpdate(train, ma);
}
public static void calculateEbTriggerCurveAndUpdate(VirtualRealityTrain train, MaService.Ma ma) {
float distance = ma.calculateDistanceOfEbTriggerEnd();
SpeedCurve ebTriggerCurve = SpeedCurve.generateProtectSpeedCurve(distance, train.getAtpSpeedMax());
ma.setEbTriggerCurve(ebTriggerCurve);
}
public static SpeedCurve calculateAtoStopCurveAndUpdate(VirtualRealityTrain train, MaService.Ma ma) {
SectionPosition headPosition = train.getHeadPosition();
SectionPosition tailPosition = train.getTailPosition();
boolean right = train.isRight();
float stopDistance = ma.calculateDistanceOfAtoEnd();
float speedMax = Math.min(train.getAtoSpeedMax(), train.getSpeedLimit() * 0.9f);
SpeedCurve atoStopCurve;
if (train.isNextParking() || train.isHold()) { // 列车下一站停车
Section target = train.getTarget();
if (target != null) {
float stopPoint = target.getStopPointByDirection(right);
SectionPosition stopPosition = new SectionPosition(target, stopPoint);
Float stopPointDistance = CalculateService.calculateDistance(headPosition, stopPosition, right);
float ebTriggerDistance = ma.calculateDistanceOfEbTriggerEnd();
if (stopPointDistance != null && stopPointDistance.floatValue() <= ebTriggerDistance) {
// 列车停车位置距离小于eb触发距离
stopDistance = stopPointDistance;
}
}
}
atoStopCurve = SpeedCurve
.buildTargetSpeedCurve(headPosition, tailPosition, right,
stopDistance, train.getSpeed(), speedMax);
// ma.setAtoStopCurve(atoStopCurve);
return atoStopCurve;
}
@Override
public String toString() {
return "SpeedCurve{" +
@ -127,12 +175,12 @@ public class SpeedCurve {
// 先不考虑区段临时限速
// 减速段
// 减速段总距离
float dvDistance = (float) (Math.pow(speedMax, 2) / (2 * VirtualRealityTrain.Emergency_Acceleration));
float dvDistance = (float) (Math.pow(speedMax, 2) / (2 * VirtualRealityTrain.Emergency_Trigger_Acceleration));
if (dvDistance >= safeDistance) { // 只有减速段
// 计算减速段开始位置防护初速度
float v0 = (float) Math.sqrt(2 * VirtualRealityTrain.Emergency_Acceleration * safeDistance);
float v0 = (float) Math.sqrt(2 * VirtualRealityTrain.Emergency_Trigger_Acceleration * safeDistance);
speedCurve.addCalculator(new SpeedCalculator(0, safeDistance,
v0, 0, VirtualRealityTrain.Emergency_Acceleration,
v0, 0, VirtualRealityTrain.Emergency_Trigger_Acceleration,
VSFormula.UNIFORM_DECELERATION));
} else { // 有匀速有减速
// 匀速-减速分界位置
@ -141,12 +189,58 @@ public class SpeedCurve {
speedMax, speedMax, 0,
VSFormula.UNIFORM));
speedCurve.addCalculator(new SpeedCalculator(point, safeDistance,
speedMax, 0, VirtualRealityTrain.Emergency_Acceleration,
speedMax, 0, VirtualRealityTrain.Emergency_Trigger_Acceleration,
VSFormula.UNIFORM_DECELERATION));
}
return speedCurve;
}
public static SpeedCurve buildAtoCurve(SectionPosition headPosition, boolean right,
float v0, float speedMax, float totalDistance) {
if (totalDistance <= 0) {
return SpeedCurve.ZERO;
}
SpeedCurve speedCurve = new SpeedCurve(totalDistance);
List<SpeedCalculator> limitSpeedList = new ArrayList<>();
float start = 0;
float end = 0;
float limitSpeed = speedMax;
Section logicSection = headPosition.getLogicSection();
Section base = headPosition.getSection();
if (logicSection.equals(headPosition.getSection())) { // 非逻辑区段
end += right ? logicSection.getLen() - headPosition.getOffset() : headPosition.getOffset();
} else { // 逻辑区段
end += right ? logicSection.getMaxOffset() - headPosition.getOffset() : headPosition.getOffset() - logicSection.getMinOffset();
}
if (base.getNeedLimitSpeed() != null && base.getNeedLimitSpeed().floatValue() < limitSpeed) {
limitSpeed = base.getNeedLimitSpeed();
}
if (end >= totalDistance) {
end = totalDistance;
}
for (int i = 0; i < 15 && base != null; i++) {
Float needLimitSpeed = base.getNeedLimitSpeed();
if (needLimitSpeed != null) {
end += base.getLen();
} else if (!CollectionUtils.isEmpty(base.getLogicList())) {
List<Section> logicList;
if (!right) {
logicList = new ArrayList<>(base.getLogicList());
Collections.reverse(logicList);
} else {
logicList = base.getLogicList();
}
for (Section logic : logicList) {
if (headPosition.getLogicSection().equals(logic)) {
}
}
}
}
return speedCurve;
}
public static SpeedCurve buildTargetSpeedCurve(SectionPosition headPosition,
SectionPosition tailPosition, boolean right,
float totalLen, float v0, float recommendedSpeedMax) {

View File

@ -1,5 +1,6 @@
package club.joylink.rtss.simulation.cbtc.onboard.ATO.service;
import club.joylink.rtss.simulation.cbtc.ATP.ground.MaService;
import club.joylink.rtss.simulation.cbtc.CI.CiApiService;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.communication.vo.TrainDoorSwitch;
@ -71,6 +72,37 @@ public class ATOService {
}
}
public void ato2(VirtualRealityTrain train) {
if (!train.isPowerOn() || !train.isAtoOn()) {
return;
}
//下令停车
if (train.isOrderStop()) {
this.doBreakMax(train);
return;
}
// 是否EB
if (train.isEB()) { // EB中不控制
return;
}
// 是否停车制动
if (train.isBreaking()) { // 站台持续停车制动中输出持续制动
doBreakMax(train);
return;
}
if (train.getTarget() == null)
return;
MaService.Ma ma = train.getMa2();
if (ma == null) {
return;
}
SpeedCurve speedCurve = SpeedCurve.calculateAtoStopCurveAndUpdate(train, ma);
// 更新目标距离和建议速度
train.setTargetDistance(speedCurve.getTotalDistance());
train.setAtoSpeed(speedCurve.getSpeedOf(speedCurve.getTotalDistance()));
this.doControlBySpeedCurve(train, speedCurve, speedCurve.getTotalDistance());
}
/**
* ATO运算逻辑
*/

View File

@ -1,15 +1,15 @@
package club.joylink.rtss.simulation.cbtc.onboard.ATP;
import club.joylink.rtss.simulation.cbtc.ATP.ground.GroundAtpApiService;
import club.joylink.rtss.simulation.cbtc.ATP.ground.MaService;
import club.joylink.rtss.simulation.cbtc.ATS.AtsApiService;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.constant.*;
import club.joylink.rtss.simulation.cbtc.data.CalculateService;
import club.joylink.rtss.simulation.cbtc.data.map.MapConfig;
import club.joylink.rtss.simulation.cbtc.data.map.Section;
import club.joylink.rtss.simulation.cbtc.data.map.Signal;
import club.joylink.rtss.simulation.cbtc.data.map.Stand;
import club.joylink.rtss.simulation.cbtc.data.map.Station;
import club.joylink.rtss.simulation.cbtc.data.support.MovementAuthority;
import club.joylink.rtss.simulation.cbtc.data.support.SectionPosition;
import club.joylink.rtss.simulation.cbtc.data.support.TrainStopMessage;
import club.joylink.rtss.simulation.cbtc.data.vr.StandParkedTrainActivity;
@ -130,25 +130,10 @@ public class ATPLogicLoop {
// 施加常规制动防止倒溜
this.atoService.openBreaking(train);
}
if (!train.isParkingAt()) {
this.checkParkingAndSend2Ats(simulation, train);
} else { // 列车站台停靠
if (train.isParkingAt()) {// 列车站台停靠
this.handleStandParkedTrain(simulation, train);
}
// if (train.isEB()) { // 列车EB
// if (train.isAtpOn()) { // 尝试自动缓解信号EB
// if (train.getLeverPosition() == 0 && train.getMa() != null) {
// Float distance = CalculateService.calculateDistance(headPosition, train.getMa().getEnd().getEndPosition(), right);
// if (distance != null && distance > 100) {
// atpService.cancelSignalEB(train);
// applicationContext.publishEvent(new SimulationATPAutoCancelEBEvent(this, simulation, train));
// log.info(String.format("列车[%s]移动授权距离超过100mEB自动缓解", train.getGroupNumber()));
// }
// }
// }
// }
/* 缓解EB检查 */
if (train.isEB()) {
if (train.isRMMode() && train.getControlLeaver() <= 0) { //停车RM模式操纵杆非牵引位
@ -183,65 +168,81 @@ public class ATPLogicLoop {
}
// 列车ATO自动驾驶逻辑运行
this.atoService.ATO(train);
// this.atoService.ATO(train);
this.atoService.ato2(train);
}
private void calculateSpeedCurve(Simulation simulation, VirtualRealityTrain train) {
if (!train.isAtpOn())
return;
DriveMode driveMode = train.getDriveMode();
float atpSpeed = 0;
float atoSpeed = 0;
switch (driveMode) {
case RM: {
atpSpeed = simulation.getRepository().getConfig().getRmAtpSpeed();
atoSpeed = train.getAtpSpeed() - 5 / 3.6f;
float atpSpeed = simulation.getRepository().getConfig().getRmAtpSpeed();
float atoSpeed = train.getAtpSpeed() - 5 / 3.6f;
train.setAtpSpeed(atpSpeed);
train.setAtoSpeed(atoSpeed);
break;
}
case AM:
case CM: {
// 驾驶故障导致EB
MovementAuthority ma = train.getMa();
if (Objects.nonNull(ma)) { // 通信正常,移动授权可用
// 获取移动授权剩余距离
Float remainDistance = atpService.calculateProtectDistance(train, ma.getEnd());
if (Objects.isNull(remainDistance) || remainDistance <= 0) {
log.warn(String.format("列车[%s]无法计算出移动防护剩余距离或防护距离不为正", train.getGroupNumber()));
atpSpeed = 0;
atoSpeed = 0;
} else {
// // 获取防护速度
// SpeedCurve protectSpeedCurve = ma.getProtectSpeedCurve();
// float protectSpeed = protectSpeedCurve.getSpeedOf(remainDistance);
// atpSpeed = protectSpeed;
// 计算推荐速度曲线
float targetDistance = ATOService.calculateTargetRemainDistance(train, ma);
SectionPosition headPosition = train.getHeadPosition();
SectionPosition tailPosition = train.calculateTailPosition();
boolean right = train.isRight();
float speedMax = Math.min(train.getAtoSpeedMax(), train.getSpeedLimit() * 0.9f);
SpeedCurve speedCurve = SpeedCurve
.buildTargetSpeedCurve(headPosition, tailPosition, right,
targetDistance, train.getSpeed(), speedMax);
// 更新目标距离和建议速度
train.setTargetDistance(targetDistance);
train.setSpeedCurve(speedCurve);
atoSpeed = speedCurve.getSpeedOf(speedCurve.getTotalDistance());
atpSpeed = atoSpeed + 5 / 3.6f;
MaService.Ma ma = train.getMa2();
if (ma != null) {
// EB 触发速度计算
SpeedCurve ebTriggerCurve = ma.getEbTriggerCurve();
float ebTriggerRemain = ma.calculateDistanceOfEbTriggerEnd();
float totalDistance = ebTriggerCurve.getTotalDistance();
if (totalDistance < ebTriggerRemain) {
ebTriggerRemain = totalDistance;
}
} else {
atpSpeed = 0;
atoSpeed = 0;
log.warn(String.format("列车[%s-%s|%s|%s]速度[%s]没有移动授权触发EB",
train.getGroupNumber(), train.getServiceNumber(),
train.getTripNumber(), train.getDestinationCode(),
train.getSpeed()));
float atpSpeed = ebTriggerCurve.getSpeedOf(ebTriggerRemain);
// ATO推荐速度计算
SpeedCurve speedCurve = SpeedCurve.calculateAtoStopCurveAndUpdate(train, ma);
float atoSpeed = speedCurve.getSpeedOf(speedCurve.getTotalDistance());
train.setAtpSpeed(atpSpeed);
train.setAtoSpeed(atoSpeed);
}
break;
// // 驾驶故障导致EB
// MovementAuthority ma = train.getMa();
// if (Objects.nonNull(ma)) { // 通信正常,移动授权可用
// // 获取移动授权剩余距离
// Float remainDistance = atpService.calculateProtectDistance(train, ma.getEnd());
// if (Objects.isNull(remainDistance) || remainDistance <= 0) {
// log.warn(String.format("列车[%s]无法计算出移动防护剩余距离或防护距离不为正", train.getGroupNumber()));
// atpSpeed = 0;
// atoSpeed = 0;
// } else {
//// // 获取防护速度
//// SpeedCurve protectSpeedCurve = ma.getProtectSpeedCurve();
//// float protectSpeed = protectSpeedCurve.getSpeedOf(remainDistance);
//// atpSpeed = protectSpeed;
// // 计算推荐速度曲线
// float targetDistance = ATOService.calculateTargetRemainDistance(train, ma);
// SectionPosition headPosition = train.getHeadPosition();
// SectionPosition tailPosition = train.calculateTailPosition();
// boolean right = train.isRight();
// float speedMax = Math.min(train.getAtoSpeedMax(), train.getSpeedLimit() * 0.9f);
// SpeedCurve speedCurve = SpeedCurve
// .buildTargetSpeedCurve(headPosition, tailPosition, right,
// targetDistance, train.getSpeed(), speedMax);
// // 更新目标距离和建议速度
// train.setTargetDistance(targetDistance);
// train.setSpeedCurve(speedCurve);
// atoSpeed = speedCurve.getSpeedOf(speedCurve.getTotalDistance());
// atpSpeed = atoSpeed + 5 / 3.6f;
// }
// } else {
// atpSpeed = 0;
// atoSpeed = 0;
// log.warn(String.format("列车[%s-%s|%s|%s]速度[%s]没有移动授权触发EB",
// train.getGroupNumber(), train.getServiceNumber(),
// train.getTripNumber(), train.getDestinationCode(),
// train.getSpeed()));
// }
// break;
}
}
train.setAtpSpeed(atpSpeed);
train.setAtoSpeed(atoSpeed);
}
private void driveModeControl(Simulation simulation, VirtualRealityTrain train) {
@ -415,14 +416,21 @@ public class ATPLogicLoop {
}
public boolean checkConditionToMove2(Simulation simulation, VirtualRealityTrain train) {
if (train.isParkingAt() && !train.isStandReadyStart()) { // 站台停靠未完成
return false;
if (train.isParkingAt()) {
if (!train.isStandReadyStart()) { // 站台停靠未完成
return false;
}
SectionPosition headPosition = train.getHeadPosition();
Signal signal = headPosition.getSection().getSignalOf(train.isRight());
if (signal != null && !signal.isNormalOpen() && !(train.isRMMode() || train.isNRMMode())) {// 站台前方信号未开放
return false;
}
}
if (train.isHold()) {
return false;
}
if (simulation.getRepository().getConfig().isAdjustOperationAutomatically()) {
if (train.getDelayTime() == 0) {
if (train.getDelayTime() <= 0) {
train.setDelayTime(SimulationConstants.ATO_TRAIN_GET_SIGNAL_TO_START_DELAY);
return false;
}

View File

@ -99,7 +99,7 @@ public class ATPService {
* @param train
*/
public void speedProtect(Simulation simulation, VirtualRealityTrain train) {
if (train.isEB() || !train.isAtpOn()) {
if (train.isEB() || !train.isAtpOn() || (!train.isRMMode() && train.getMa2() == null)) {
return;
}
DriveMode driveMode = train.getDriveMode();

View File

@ -1,5 +1,6 @@
package club.joylink.rtss.simulation.cbtc.onboard.ATP;
import club.joylink.rtss.simulation.cbtc.ATP.ground.MaService;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.data.map.Section;
import club.joylink.rtss.simulation.cbtc.data.plan.TripPlan;
@ -11,6 +12,8 @@ import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityTrain;
*/
public interface OnboardAtpApiService {
void updateCtcMa(Simulation simulation, MaService.Ma ma);
/**
* 更新CBTC移动授权
*/
@ -116,5 +119,5 @@ public interface OnboardAtpApiService {
void checkAndChangeDirection(Simulation simulation, VirtualRealityTrain train,
Section targetSection);
void parkingInPlace(Simulation simulation, VirtualRealityTrain vrTrain);
void parkingInPlace(Simulation simulation, VirtualRealityTrain vrTrain, Section headSection);
}

View File

@ -1,5 +1,6 @@
package club.joylink.rtss.simulation.cbtc.onboard.ATP;
import club.joylink.rtss.simulation.cbtc.ATP.ground.MaService;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.constant.DriveMode;
import club.joylink.rtss.simulation.cbtc.constant.RunLevel;
@ -11,6 +12,7 @@ import club.joylink.rtss.simulation.cbtc.data.plan.TripPlan;
import club.joylink.rtss.simulation.cbtc.data.support.MovementAuthority;
import club.joylink.rtss.simulation.cbtc.data.support.RoutePath;
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityTrain;
import club.joylink.rtss.simulation.cbtc.onboard.ATO.SpeedCurve;
import club.joylink.rtss.simulation.cbtc.onboard.ATO.service.ATOService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@ -30,6 +32,13 @@ public class OnboardAtpApiServiceImpl implements OnboardAtpApiService {
@Autowired
private ATOService ATOService;
@Override
public void updateCtcMa(Simulation simulation, MaService.Ma ma) {
VirtualRealityTrain train = ma.getTrain();
SpeedCurve.calculateAndUpdate(simulation, train, ma);
train.setCbtcMaMissDuration(0);
}
@Override
public void updateMA4CBTC(VirtualRealityTrain train, MovementAuthority ma) {
if (ma == null)
@ -275,7 +284,7 @@ public class OnboardAtpApiServiceImpl implements OnboardAtpApiService {
}
@Override
public void parkingInPlace(Simulation simulation, VirtualRealityTrain vrTrain) {
vrTrain.parkingAt();
public void parkingInPlace(Simulation simulation, VirtualRealityTrain vrTrain, Section headSection) {
vrTrain.parkingAt(headSection);
}
}

View File

@ -12,12 +12,6 @@ public class SimulationInfoVO {
String name;
Integer speed;
LocalDateTime systemTime;
// Integer year;
// Integer month;
// Integer day;
// Integer hour;
// Integer minute;
// Integer second;
Integer state;
List<SimulationUserVO> userList;
@ -27,13 +21,6 @@ public class SimulationInfoVO {
this.speed = simulation.getSpeed();
this.state = simulation.getState();
this.systemTime = simulation.getSystemTime();
// LocalDateTime systemTime = simulation.getSystemTime();
// this.year = systemTime.getYear();
// this.month = systemTime.getMonthValue();
// this.day = systemTime.getDayOfMonth();
// this.hour = systemTime.getHour();
// this.minute = systemTime.getMinute();
// this.second = systemTime.getSecond();
}
public void setUserList(List<SimulationUserVO> userList) {