运行线逻辑完善

This commit is contained in:
joylink_zhangsai 2021-03-05 13:54:55 +08:00
parent e091dac76a
commit 97a3baedb7
13 changed files with 518 additions and 193 deletions

View File

@ -1362,6 +1362,7 @@ public class DraftMapService implements IDraftMapService {
@Override
public void saveOperationDefinitions(Long mapId, MapDestinationCodeDefinitionVO definitionVO) {
check(definitionVO);
DraftMapWithBLOBs entity = getEntity(mapId);
String logicData = entity.getLogicData();
@ -1517,4 +1518,24 @@ public class DraftMapService implements IDraftMapService {
BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertNotNull(data);
return data;
}
/**
* 检查目的地码定义数据
*/
private void check(MapDestinationCodeDefinitionVO definitionVO) {
switch (definitionVO.getType()) {
case NORMAL_OPERATION:
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertNotNull(definitionVO.getStationACode(), "车站A必须选择");
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertNotNull(definitionVO.getStationBCode(), "车站B必须选择");
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertNotNull(definitionVO.getStationAFrontTurnBack(), "车站A是否站前折返必须选择");
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertNotNull(definitionVO.getStationBFrontTurnBack(), "车站B是否站前折返必须选择");
break;
case LAST_OPERATION:
case NON_OPERATION:
case LAST_NON_OPERATION:
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertNotNull(definitionVO.getSectionCode(), "目标区段必须选择");
case OTHER:
break;
}
}
}

View File

@ -2,6 +2,7 @@ package club.joylink.rtss.simulation.cbtc.ATS.service;
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.*;
import club.joylink.rtss.simulation.cbtc.data.plan.StationPlan;
@ -90,50 +91,109 @@ public class AtsRouteSettingService {
if (Objects.equals(headSection, destDefinition.getSection())) {
return null;
}
// 目的地定义存在根据目的地定义查询路径办理进路
// 判断是否终点站折返办理
if (train.isParking() && destDefinition.isLoop()) { // 列车停车且目的地为环路运营
Section section = destDefinition.getEndStationParkSection(right);
if (Objects.equals(section, headSection)) { // 列车停靠终点站对应站台
Station station = destDefinition.getStationOf(right);
if (destDefinition.isFrontTurnBack(station)) { // 站前折返
neededSignal = section.getSignalOf(!right);
List<RoutePath> paths = repository.queryRoutePathsByStart(section);
for (RoutePath path : paths) { // 筛选方向一致且终端区段是站台轨的
if (Objects.equals(path.isRight(), !right) && path.getEnd().isNormalStandTrack()) {
routePaths.add(path);
if (!CollectionUtils.isEmpty(destDefinition.getRoutes())) {
return destDefinition.queryNextRoute(headSection);
} else if (train.getEstimatedArriveStandTrack() != null) {
Section targetSection = repository.getByCode(train.getEstimatedArriveStandTrack(), Section.class);
routePaths = CalculateService.queryRoutePathsOnDirection(headSection, targetSection, true);
if (CollectionUtils.isEmpty(routePaths)) {
routePaths = CalculateService.queryRoutePathsOnDirection(headSection, targetSection, false);
}
} else {
// 目的地定义存在根据目的地定义查询路径办理进路
// 判断是否终点站折返办理
if (train.isParking() && destDefinition.isLoop()) { // 列车停车且目的地为环路运营
Section section = destDefinition.getEndStationParkSection(right);
if (Objects.equals(section, headSection)) { // 列车停靠终点站对应站台
Station station = destDefinition.getStationOf(right);
if (destDefinition.isFrontTurnBack(station)) { // 站前折返
neededSignal = section.getSignalOf(!right);
List<RoutePath> paths = repository.queryRoutePathsByStart(section);
for (RoutePath path : paths) { // 筛选方向一致且终端区段是站台轨的
if (Objects.equals(path.isRight(), !right) && path.getEnd().isNormalStandTrack()) {
routePaths.add(path);
}
}
} else { // 站后折返
train.startTurnBack(null);
StationTurnBackStrategyOption strategy = null;
if (Objects.nonNull(station.getTbStrategyId())) {
strategy = station.getCurrentTurnBackStrategy();
}
return this.selectTbRouteByStrategy(simulation, train, signal, null, strategy, trainList);
}
}
}
// 非终点折返办理根据列车预计到站查询
if (Objects.nonNull(train.getEstimatedArriveStandTrack())) {
// 查询到达预计到站的路径
Section eaStandSection = repository.getByCode(train.getEstimatedArriveStandTrack(), Section.class);
List<RoutePath> paths = repository.queryRoutePathsByEnd(eaStandSection);
for (RoutePath path : paths) {
if (path.containsSection(headSection) && path.isRight() == right) {
routePaths.add(path);
}
}
// 如果预计到达不是终点尝试查询从预计到达开始的路径
if (!destDefinition.isEndSection(eaStandSection, right)) {
List<RoutePath> pathList = repository.queryRoutePathsByStart(eaStandSection);
for (RoutePath routePath : pathList) {
if (destDefinition.containsSection(routePath.getEnd(), right)) {
routePaths.add(routePath);
}
}
} else { // 站后折返
train.startTurnBack(null);
StationTurnBackStrategyOption strategy = null;
if (Objects.nonNull(station.getTbStrategyId())) {
strategy = station.getCurrentTurnBackStrategy();
}
return this.selectTbRouteByStrategy(simulation, train, signal, null, strategy, trainList);
}
}
}
// 非终点折返办理根据列车预计到站查询
if (Objects.nonNull(train.getEstimatedArriveStandTrack())) {
// 查询到达预计到站的路径
Section eaStandSection = repository.getByCode(train.getEstimatedArriveStandTrack(), Section.class);
List<RoutePath> paths = repository.queryRoutePathsByEnd(eaStandSection);
for (RoutePath path : paths) {
if (path.containsSection(headSection) && path.isRight() == right) {
routePaths.add(path);
}
}
// 如果预计到达不是终点尝试查询从预计到达开始的路径
if (!destDefinition.isEndSection(eaStandSection, right)) {
List<RoutePath> pathList = repository.queryRoutePathsByStart(eaStandSection);
for (RoutePath routePath : pathList) {
if (destDefinition.containsSection(routePath.getEnd(), right)) {
routePaths.add(routePath);
}
}
}
}
// // 如果已经到达目的地返回
// if (Objects.equals(headSection, destDefinition.getSection())) {
// return null;
// }
// // 目的地定义存在根据目的地定义查询路径办理进路
// // 判断是否终点站折返办理
// if (train.isParking() && destDefinition.isLoop()) { // 列车停车且目的地为环路运营
// Section section = destDefinition.getEndStationParkSection(right);
// if (Objects.equals(section, headSection)) { // 列车停靠终点站对应站台
// Station station = destDefinition.getStationOf(right);
// if (destDefinition.isFrontTurnBack(station)) { // 站前折返
// neededSignal = section.getSignalOf(!right);
// List<RoutePath> paths = repository.queryRoutePathsByStart(section);
// for (RoutePath path : paths) { // 筛选方向一致且终端区段是站台轨的
// if (Objects.equals(path.isRight(), !right) && path.getEnd().isNormalStandTrack()) {
// routePaths.add(path);
// }
// }
// } else { // 站后折返
// train.startTurnBack(null);
// StationTurnBackStrategyOption strategy = null;
// if (Objects.nonNull(station.getTbStrategyId())) {
// strategy = station.getCurrentTurnBackStrategy();
// }
// return this.selectTbRouteByStrategy(simulation, train, signal, null, strategy, trainList);
// }
// }
// }
// // 非终点折返办理根据列车预计到站查询
// if (Objects.nonNull(train.getEstimatedArriveStandTrack())) {
// // 查询到达预计到站的路径
// Section eaStandSection = repository.getByCode(train.getEstimatedArriveStandTrack(), Section.class);
// List<RoutePath> paths = repository.queryRoutePathsByEnd(eaStandSection);
// for (RoutePath path : paths) {
// if (path.containsSection(headSection) && path.isRight() == right) {
// routePaths.add(path);
// }
// }
// // 如果预计到达不是终点尝试查询从预计到达开始的路径
// if (!destDefinition.isEndSection(eaStandSection, right)) {
// List<RoutePath> pathList = repository.queryRoutePathsByStart(eaStandSection);
// for (RoutePath routePath : pathList) {
// if (destDefinition.containsSection(routePath.getEnd(), right)) {
// routePaths.add(routePath);
// }
// }
// }
// }
} else {
// 按交路查询办理如果找到才办理
Routing routing = train.getRouting();
@ -278,6 +338,7 @@ public class AtsRouteSettingService {
/**
* 判断当前时间到折返计划的下一计划第一站到站时间之间是否存在冲突的出库计划
*
* @param simulation
* @param tripPlan
* @return
@ -390,10 +451,11 @@ public class AtsRouteSettingService {
/**
* 根据折返策略选择进路
*
* @param simulation
* @param train
* @param signal
* @param defaultTb 默认折返轨可能为null
* @param defaultTb 默认折返轨可能为null
* @param strategy
* @return
*/
@ -434,6 +496,7 @@ public class AtsRouteSettingService {
for (Route route : routeList) {
if (route.isTurnBack()) {
tbRouteList.add(route);
tbSectionList.add(route.getSectionList().get(route.getSectionList().size() - 1));
}
}
if (!tbRouteList.isEmpty()) {
@ -467,7 +530,7 @@ public class AtsRouteSettingService {
if (config.isRouteLikeHa1()) {
if (train.isCbtcTrack() && !route.isAtp()) { // 通信车
return false;
} else if(!train.isCbtcTrack() && !route.isGround()) {
} else if (!train.isCbtcTrack() && !route.isGround()) {
return false;
}
}
@ -620,6 +683,7 @@ public class AtsRouteSettingService {
/**
* 获取需要排列进路的列车位置及对应信号机
*
* @return
*/
private Map<Signal, TrainInfo> getTrain2SignalOfSetRoute(Simulation simulation, List<TrainInfo> trainList,
@ -631,7 +695,7 @@ public class AtsRouteSettingService {
}
Boolean right = train.getRight();
SectionPosition trainPosition = trainPositionMap.get(train.getGroupNumber());
if(Objects.isNull(trainPosition)){
if (Objects.isNull(trainPosition)) {
continue;
}
Section section = trainPosition.getSection();
@ -647,7 +711,7 @@ public class AtsRouteSettingService {
SectionPosition otherPosition = trainPositionMap.get(other.getGroupNumber());
if (trainPosition.isAheadOf(otherPosition, right)) {
signalTrainMap.put(signal, train);
}else{
} else {
continue;
}
}

View File

@ -12,6 +12,7 @@ import club.joylink.rtss.simulation.cbtc.data.plan.StationPlan;
import club.joylink.rtss.simulation.cbtc.data.plan.TripPlan;
import club.joylink.rtss.simulation.cbtc.data.support.RoutePath;
import club.joylink.rtss.simulation.cbtc.data.support.SectionPosition;
import club.joylink.rtss.simulation.cbtc.data.support.StationTurnBackStrategyOption;
import club.joylink.rtss.simulation.cbtc.data.vo.RoutePathVO;
import club.joylink.rtss.simulation.cbtc.data.vo.TrainInfo;
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityTrain;
@ -220,48 +221,56 @@ public class AtsTrainService {
}
boolean stop = supervisedTrain.isStop();
switch (destinationCodeDefinition.getType()) {
case NORMAL_OPERATION: {
BusinessExceptionAssertEnum.INVALID_OPERATION.assertNotNull(targetStation,
String.format("列车[%s]目标区段为null", supervisedTrain.getGroupNumber()));
Station leftStation = destinationCodeDefinition.getLeftStation();
Station rightStation = destinationCodeDefinition.getRightStation();
boolean beyondStationRage =
Math.min(leftStation.getSn(), rightStation.getSn()) > targetStation.getSn()
|| targetStation.getSn() > Math.max(leftStation.getSn(), rightStation.getSn()); //是否超出车站范围
if (beyondStationRage) {
throw new SimulationException(SimulationExceptionType.Illegal_Argument,
String.format("列车目标轨道[%s]超出目的地码[%s]的范围", targetSection, destinationCode));
}
if (destinationCodeDefinition.isBorder(targetStation) && destinationCodeDefinition.isFrontTurnBack(targetStation)) {
boolean bothNormalAndTurnBack = targetSection.isNormalStandTrack() && targetSection.isTurnBackTrack();
if (!bothNormalAndTurnBack) {
throw new SimulationException(SimulationExceptionType.Invalid_Operation, "列车已无法站前折返");
}
}
break;
}
case NORMAL_OPERATION:
// Station leftStation = destinationCodeDefinition.getLeftStation();
// Station rightStation = destinationCodeDefinition.getRightStation();
// boolean beyondStationRage =
// Math.min(leftStation.getSn(), rightStation.getSn()) > targetStation.getSn()
// || targetStation.getSn() > Math.max(leftStation.getSn(), rightStation.getSn()); //是否超出车站范围
// if (beyondStationRage) {
// throw new SimulationException(SimulationExceptionType.Illegal_Argument,
// String.format("列车目标轨道[%s]超出目的地码[%s]的范围", targetSection, destinationCode));
// }
// if (destinationCodeDefinition.isBorder(targetStation) && destinationCodeDefinition.isFrontTurnBack(targetStation)) {
// boolean bothNormalAndTurnBack = targetSection.isNormalStandTrack() && targetSection.isTurnBackTrack();
// if (!bothNormalAndTurnBack) {
// throw new SimulationException(SimulationExceptionType.Invalid_Operation, "列车已无法站前折返");
// }
// }
case LAST_OPERATION:
case NON_OPERATION:
case LAST_NON_OPERATION: {
Section startSection = targetSection;
if (startSection == null) {
startSection = headSection;
}
if (right == null) {
throw new SimulationException(SimulationExceptionType.Illegal_Argument,
String.format("列车[%s]方向未知", groupNumber));
}
BusinessExceptionAssertEnum.INVALID_OPERATION.assertNotNull(targetSection,
String.format("列车[%s]目标区段为null", supervisedTrain.getGroupNumber()));
Boolean destinationRight = destinationCodeDefinition.getRight();
if (!targetSection.isTurnBackTrack() || !stop) {
if (!Objects.equals(right, destinationRight)) {
throw new SimulationException(SimulationExceptionType.Illegal_Argument,
String.format("列车方向与目的地码[%s]的方向相反", destinationCode));
}
}
Station station = destinationSection.getStation();
if ((destinationRight && targetStation.getSn() > station.getSn())
|| (!destinationRight && targetStation.getSn() < station.getSn())) {
throw new SimulationException(SimulationExceptionType.Illegal_Argument,
String.format("列车目标轨道[%s]超出目的地码[%s]的范围", targetSection, destinationCode));
}
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertTrue(destinationCodeDefinition.containsSection(startSection, right),
String.format("%s超出%s范围", String.format("列车[%s]", groupNumber), destinationCodeDefinition.logStr()));
// if (right == null) {
// throw new SimulationException(SimulationExceptionType.Illegal_Argument,
// String.format("列车[%s]方向未知", groupNumber));
// }
// BusinessExceptionAssertEnum.INVALID_OPERATION.assertNotNull(targetSection,
// String.format("列车[%s]目标区段为null", supervisedTrain.getGroupNumber()));
// Boolean destinationRight = destinationCodeDefinition.getRight();
// if (!targetSection.isTurnBackTrack() || !stop) {
// if (!Objects.equals(right, destinationRight)) {
// throw new SimulationException(SimulationExceptionType.Illegal_Argument,
// String.format("列车方向与目的地码[%s]的方向相反", destinationCode));
// }
// }
// Station station = destinationSection.getStation();
// if ((destinationRight && targetStation.getSn() > station.getSn())
// || (!destinationRight && targetStation.getSn() < station.getSn())) {
// throw new SimulationException(SimulationExceptionType.Illegal_Argument,
// String.format("列车目标轨道[%s]超出目的地码[%s]的范围", targetSection, destinationCode));
// }
break;
}
case OTHER:
@ -375,6 +384,7 @@ public class AtsTrainService {
Long mapId = simulation.getBuildParams().getMap().getId();
LocalTime systemTime = simulation.getSystemTime().toLocalTime();
Section headSection = repository.getByCode(train.getPhysicalSection(), Section.class);
Station headStation = headSection.getStation();
float offset = train.getOffsetp() * headSection.getLen();
SectionPosition headPosition = new SectionPosition(headSection, offset);
Boolean trainRight = train.getRight();
@ -386,12 +396,6 @@ public class AtsTrainService {
targetSection = repository.getByCode(estimatedArriveStandTrack, Section.class);
targetStation = targetSection.getStation();
}
// String estimatedArriveStandTrack = train.getEstimatedArriveStandTrack();
// if (Objects.isNull(estimatedArriveStandTrack)) {
// return;
// }
// Section targetSection = repository.getByCode(estimatedArriveStandTrack, Section.class);
// Station targetStation = targetSection.getStation();
boolean stop = train.isStop();
Section nextTarget = null;
long runningTime = 0;
@ -475,7 +479,7 @@ public class AtsTrainService {
Map<String, DestinationCodeDefinition> destinationMap = repository.getDestinationMap();
String destinationCode = train.getDestinationCode();
if (!CollectionUtils.isEmpty(destinationMap)) { //有目的地码定义数据
if (!stop)
if (!stop || (targetSection != null && !headSection.equals(targetSection))) //列车没有停在目标轨
break;
if (trainRight == null)
break;
@ -489,12 +493,103 @@ public class AtsTrainService {
Section destinationSection = destinationCodeDefinition.getSection();
Boolean destinationRight = destinationCodeDefinition.getRight();
switch (destinationCodeDefinition.getType()) {
case NORMAL_OPERATION:
case NORMAL_OPERATION: {
nextTarget = destinationCodeDefinition.queryNextTargetSection(headSection);
if (nextTarget != null) {
break;
}
Station leftStation = destinationCodeDefinition.getLeftStation();
Station rightStation = destinationCodeDefinition.getRightStation();
if (destinationCodeDefinition.isBorder(headStation)) { //到达边界车站
boolean rightEnd = headStation.equals(rightStation); //是否右端车站
if (headSection.isNormalStandTrack()) {
boolean standRight = headStation.isStandOfSectionRight(headSection); //是否是右行站台
if (rightEnd == standRight && !destinationCodeDefinition.isFrontTurnBack(headStation)) { //需要站后折返
//查询目的地码定义指定的折返轨
nextTarget = destinationCodeDefinition.getNecessarySections().stream()
.filter(section -> section.isTurnBackTrack() && !section.isStandTrack() && section.getStation().equals(headStation))
.findAny().orElse(null);
//查询车站指定的折返轨
if (nextTarget == null) {
if (!CollectionUtils.isEmpty(headStation.getTbStrategyMap()) && headStation.getTbStrategyId() != null) {
StationTurnBackStrategyOption strategy = headStation.getCurrentTurnBackStrategy();
Section tbSection = strategy.getSectionList().get(0);
switch (strategy.getType()) {
case FIRST:
List<RoutePath> routePaths = CalculateService.queryRoutePathsOnDirection(headSection, tbSection, standRight);
if (routePaths.stream().anyMatch(path -> !path.isOccupied())) {
nextTarget = tbSection;
}
break;
case ONLY:
nextTarget = tbSection;
break;
}
}
}
//随意选择能用的折返轨
if (nextTarget == null) {
for (Section section : headStation.getTurnBackList()) {
if (section.isNormalStandTrack()) {
continue;
}
List<RoutePath> routePaths = CalculateService.queryRoutePathsOnDirection(headSection, section, standRight);
if (routePaths.stream().anyMatch(path -> !path.isOccupied())) {
nextTarget = section;
break;
}
}
}
} else { //站前折返或已到站后折返轨
Station adjacentStation = simulation.getRepository().findAdjacentStation(headStation, !rightEnd);
BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.assertNotNull(adjacentStation,
String.format("%s的%s侧相邻车站不存在", headStation.debugStr(), rightEnd ? "" : ""));
nextTarget = adjacentStation.getNormalStand(!rightEnd).get(0).getSection();
}
} else if (headSection.isTurnBackTrack()) { //认为是站后折返轨
nextTarget = headStation.getNormalStand(!rightEnd).get(0).getSection();
}
} else { //不在边界车站
if (!headSection.isNormalStandTrack()) { //认为此时列车一定在站台轨如果是在折返轨不好处理故略过
break;
}
boolean standRight = headStation.isStandOfSectionRight(headSection);
Station adjacentStation = simulation.getRepository().findAdjacentStation(headStation, standRight);
if (destinationCodeDefinition.isBorder(adjacentStation)) {
if (destinationCodeDefinition.isFrontTurnBack(adjacentStation)) {
nextTarget = destinationCodeDefinition.getNecessarySections().stream()
.filter(section -> section.isStandTrack() && adjacentStation.equals(section.getStation()))
.limit(1).findAny().orElse(null);
if (nextTarget != null) {
break;
}
nextTarget = adjacentStation.getNormalStand(!standRight).get(0).getSection();
if (CollectionUtils.isEmpty(CalculateService.queryRoutePathsOnDirection(headSection, nextTarget, standRight))) {
nextTarget = adjacentStation.getNormalStand(standRight).get(0).getSection();
}
} else {
nextTarget = adjacentStation.getNormalStand(standRight).get(0).getSection();
}
} else {
nextTarget = adjacentStation.getNormalStand(standRight).get(0).getSection();
}
}
break;
}
case LAST_OPERATION:
case NON_OPERATION:
case LAST_NON_OPERATION:
if (targetSection != null) {
nextTarget = destinationCodeDefinition.queryNextFunctionSection(targetSection);
nextTarget = destinationCodeDefinition.queryNextTargetSection(headSection);
if (nextTarget == null) {
nextTarget = headStation.getNormalStand(destinationRight).get(0).getSection();
if (!headSection.equals(nextTarget)) {
List<RoutePath> routePaths = CalculateService.queryRoutePathsOnDirection(headSection, nextTarget, destinationRight);
if (!CollectionUtils.isEmpty(routePaths)) {
break;
}
}
Station adjacentStation = simulation.getRepository().findAdjacentStation(headStation, destinationRight);
nextTarget = adjacentStation.getNormalStand(destinationRight).get(0).getSection();
}
break;
case OTHER:
@ -815,7 +910,7 @@ public class AtsTrainService {
* 设置全线列车扣车
*/
public void setAllHold(Simulation simulation) {
simulation.getRepository().getOnlineTrainList().forEach(train->{
simulation.getRepository().getOnlineTrainList().forEach(train -> {
train.setTrainHold(true);
train.setHold(true);
});

View File

@ -536,14 +536,16 @@ public class InterlockBuilder2 {
String code = null;
DestinationCodeDefinition.Type type = null;
String description = null;
Section startSection = null;
Section section = null;
Boolean right = vo.getRight();
List<Section> necessarySections = new ArrayList<>();
Station leftStation = null;
Station rightStation = null;
Boolean leftFrontTurnBack = null;
Boolean rightFrontTurnBack = null;
List<Section> runPath = null;
Boolean leftFrontTurnBack = null;
List<Route> routes = null;
code = vo.getCode();
if (!checkCodeDuplicateSet.add(code)) {
@ -554,6 +556,12 @@ public class InterlockBuilder2 {
errMsgList.add(String.format("目的地码[%s]没有类型", code));
continue;
}
if (vo.getStartSectionCode() != null) {
startSection = (Section) elementMap.get(vo.getStartSectionCode());
}
if (vo.getSectionCode() != null) {
section = (Section) elementMap.get(vo.getSectionCode());
}
if (!CollectionUtils.isEmpty(vo.getRunPath())) {
necessarySections = vo.getRunPath().stream().map(pathSectionCode -> (Section) elementMap.get(pathSectionCode))
.collect(Collectors.toList());
@ -589,50 +597,62 @@ public class InterlockBuilder2 {
}
//从左边车站右行站台站台轨开始构建运行路径--- 不标准的目的地码定义数据会导致运行路径构建错误
Set<Section> necessarySectionSet = new HashSet<>(necessarySections); //必经区段副本
Section startSection = null; //查询路径的起始区段
Section endSection = null; //查询路径的终点区段
Section startSection4RoutePath = null; //查询路径的起始区段
Section endSection4RoutePath = null; //查询路径的终点区段
runPath = new ArrayList<>();
routes = new ArrayList<>();
//从左端车站开始选择路径
startSection = screeningSection4DestinationCode(leftStation, leftFrontTurnBack, necessarySectionSet, true);
runPath.add(startSection);
endSection = screeningSection4DestinationCode(rightStation, rightFrontTurnBack, necessarySectionSet, false);
startSection4RoutePath = screeningSection4DestinationCode(leftStation, leftFrontTurnBack, necessarySectionSet, true);
runPath.add(startSection4RoutePath);
endSection4RoutePath = screeningSection4DestinationCode(rightStation, rightFrontTurnBack, necessarySectionSet, false);
//查询并添加路径
RoutePath optimalPath = CalculateService.queryShortestRoutePath(startSection, endSection, necessarySectionSet, true);
RoutePath optimalPath = CalculateService.queryLeastSwitchRoutePath(startSection4RoutePath, endSection4RoutePath, necessarySectionSet, true);
BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.assertNotNull(optimalPath,
String.format("从%s到%s的路径未找到", startSection.debugStr(), endSection.debugStr()));
String.format("从%s到%s的路径未找到", startSection4RoutePath.debugStr(), endSection4RoutePath.debugStr()));
runPath.addAll(optimalPath.getSectionList());
routes.addAll(optimalPath.getRouteList());
//寻找反向的路径
Section t = startSection;
startSection = endSection;
endSection = t;
runPath.add(startSection);
RoutePath optimalPath2 = CalculateService.queryShortestRoutePath(startSection, endSection, necessarySectionSet, false);
Section t = startSection4RoutePath;
startSection4RoutePath = endSection4RoutePath;
endSection4RoutePath = t;
runPath.add(startSection4RoutePath);
RoutePath optimalPath2 = CalculateService.queryLeastSwitchRoutePath(startSection4RoutePath, endSection4RoutePath, necessarySectionSet, false);
BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.assertNotNull(optimalPath2,
String.format("从%s到%s的路径未找到", startSection.debugStr(), endSection.debugStr()));
String.format("从%s到%s的路径未找到", startSection4RoutePath.debugStr(), endSection4RoutePath.debugStr()));
runPath.addAll(optimalPath2.getSectionList());
routes.addAll(optimalPath2.getRouteList());
break;
}
case LAST_OPERATION:
case NON_OPERATION:
case LAST_NON_OPERATION:
case LAST_NON_OPERATION: {
description = vo.getDescription();
if (!StringUtils.hasText(description)) {
errMsgList.add(String.format("目的地码[%s]没有描述", code));
}
if (right == null) {
errMsgList.add(String.format("交路类目的地码[%s]没有方向", code));
if (startSection == null || right == null) {
errMsgList.add(String.format("单向目的地码[%s]没有起始区段或方向", code));
continue;
}
if (section == null) {
errMsgList.add(String.format("单向目的地码[%s]没有目标区段", code));
continue;
}
RoutePath routePath = CalculateService.queryLeastSwitchRoutePath(startSection, section, necessarySections, right);
BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.assertNotNull(routePath,
String.format("从%s到%s的路径未找到", startSection.debugStr(), section.debugStr()));
runPath = new ArrayList<>(routePath.getSectionList());
routes = new ArrayList<>(routePath.getRouteList());
}
case OTHER:
if (!StringUtils.hasText(vo.getSectionCode())) {
errMsgList.add(String.format("交路类目的地码[%s]没有目标区段", code));
if (section == null) {
errMsgList.add(String.format("单向目的地码[%s]没有目标区段", code));
continue;
}
section = (Section) elementMap.get(vo.getSectionCode());
break;
}
DestinationCodeDefinition destinationCodeDefinition = new DestinationCodeDefinition(code, type, description, section,
right, necessarySections, leftStation, leftFrontTurnBack, rightStation, rightFrontTurnBack, runPath);
DestinationCodeDefinition destinationCodeDefinition = new DestinationCodeDefinition(code, type, description, startSection, section,
right, necessarySections, leftStation, leftFrontTurnBack, rightStation, rightFrontTurnBack, runPath, routes);
destinationMap.put(code, destinationCodeDefinition);
}
}

View File

@ -654,10 +654,11 @@ public class CalculateService {
}
/**
* 查询最短的进路路径
* 查询道岔最少的进路路径
*
* @param preferredSections 优先经过这些区段可以为null
*/
public static RoutePath queryShortestRoutePath(Section startSection, Section endSection, Set<Section> preferredSections, boolean toRight) {
public static RoutePath queryLeastSwitchRoutePath(Section startSection, Section endSection, Collection<Section> preferredSections, boolean toRight) {
List<RoutePath> routePaths = CalculateService.queryRoutePathsOnDirection(startSection, endSection, toRight);
if (CollectionUtils.isEmpty(routePaths)) {
return null;
@ -665,22 +666,26 @@ public class CalculateService {
if (!CollectionUtils.isEmpty(preferredSections)) { //按经过优先区段的数量和长度筛选最优路径
RoutePath optimalPath = null;
int preferredSectionNum = 0;
int switchNum = 0;
for (RoutePath routePath : routePaths) {
int num = 0;
int preferredSectionNumCopy = 0;
for (Section section : preferredSections) {
if (routePath.containsSection(section)) {
num ++;
preferredSectionNumCopy++;
}
}
if (optimalPath == null) {
optimalPath = routePath;
preferredSectionNum = num;
preferredSectionNum = preferredSectionNumCopy;
switchNum = routePath.getSwitchQuantity();
} else {
if (num > preferredSectionNum) {
preferredSectionNum = num;
if (preferredSectionNumCopy > preferredSectionNum) {
preferredSectionNum = preferredSectionNumCopy;
optimalPath = routePath;
} else if (num == preferredSectionNum && routePath.getLength() < optimalPath.getLength()) {
switchNum = routePath.getSwitchQuantity();
} else if (preferredSectionNumCopy == preferredSectionNum && routePath.getSwitchQuantity() < switchNum) {
optimalPath = routePath;
switchNum = routePath.getSwitchQuantity();
}
}
}
@ -698,7 +703,7 @@ public class CalculateService {
return;
}
if (iter > 100) {
warnList.add(String.format("进路路径[%s]未找到迭代10次,最后区段为[%s]",
warnList.add(String.format("进路路径[%s]未找到迭代100次,最后区段为[%s]",
routePath.debugStr(), routePath.getLastSection().debugStr()));
return;
}

View File

@ -1,5 +1,6 @@
package club.joylink.rtss.simulation.cbtc.data.map;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.cbtc.exception.SimulationException;
import club.joylink.rtss.simulation.cbtc.exception.SimulationExceptionType;
import lombok.Getter;
@ -18,6 +19,8 @@ public class DestinationCodeDefinition {
private String description;
//----------- 交路类属性 -----------
private Section startSection;
/**
* 交路类目的地码对应的区段
*/
@ -56,16 +59,19 @@ public class DestinationCodeDefinition {
*/
private List<Section> runPath;
private List<Route> routes;
public DestinationCodeDefinition(String code, Type type, Section section) {
this(code, type, null, section, null, null, null, null, null, null, null);
this(code, type, null, null, section, null, null, null, null, null, null, null, null);
}
public DestinationCodeDefinition(String code, Type type, String description, Section section, Boolean right,
public DestinationCodeDefinition(String code, Type type, String description, Section startSection, Section section, Boolean right,
List<Section> necessarySections, Station leftStation, Boolean leftFrontTurnBack,
Station rightStation, Boolean rightFrontTurnBack, List<Section> runPath) {
Station rightStation, Boolean rightFrontTurnBack, List<Section> runPath, List<Route> routes) {
this.code = code;
this.type = type;
this.description = description;
this.startSection = startSection;
this.section = section;
this.right = right;
this.necessarySections = necessarySections;
@ -74,6 +80,7 @@ public class DestinationCodeDefinition {
this.rightStation = rightStation;
this.rightFrontTurnBack = rightFrontTurnBack;
this.runPath = runPath;
this.routes = routes;
}
/**
@ -99,9 +106,9 @@ public class DestinationCodeDefinition {
}
/**
* 该区段在运行路径上
* 该区段是必经区段
*/
public boolean isOnThePath(Section section) {
public boolean isNecessarySection(Section section) {
if (CollectionUtils.isEmpty(necessarySections)) {
return false;
}
@ -150,42 +157,47 @@ public class DestinationCodeDefinition {
* 该目的地码定义中是否包含该区段
*/
public boolean containsSection(Section section, boolean right) {
Station station = section.getStation();
if (this.isLoop()) { // 环路判断逻辑是站台轨在范围内或为终点站台轨
if (!section.isNormalStandTrack()) {
return false;
}
if (Objects.equals(this.getEndStationParkSection(right), section)) {
return true;
}
int sn = this.getStationOf(right).getSn();
if (Objects.equals(section.getStandList().get(0).isRight(), right)) {
if ((right && station.getSn() < sn) ||
(!right && station.getSn() > sn)) {
if (!CollectionUtils.isEmpty(runPath)) {
BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.assertNotTrue(Type.OTHER.equals(type), logStr() + "是其它类目的地码,无法判定是否包含某区段");
return runPath.contains(section);
} else {
Station station = section.getStation();
if (this.isLoop()) { // 环路判断逻辑是站台轨在范围内或为终点站台轨
if (!section.isNormalStandTrack()) {
return false;
}
if (Objects.equals(this.getEndStationParkSection(right), section)) {
return true;
}
}
} else {
if (!Objects.equals(this.right, right)) {
return false;
}
// 暂时判断逻辑为或者是runPath中一个或者是范围内车站且是对应方向站台
if (!CollectionUtils.isEmpty(this.necessarySections)) {
return this.necessarySections.contains(section);
}
if (Objects.nonNull(station)) {
if (!CollectionUtils.isEmpty(section.getStandList()) &&
Objects.equals(section.getStandList().get(0).isRight(), this.right)) {
int sn = this.section.getStation().getSn();
if ((this.right && station.getSn() <= sn) ||
(!this.right && station.getSn() >= sn)) {
int sn = this.getStationOf(right).getSn();
if (Objects.equals(section.getStandList().get(0).isRight(), right)) {
if ((right && station.getSn() < sn) ||
(!right && station.getSn() > sn)) {
return true;
}
}
} else {
if (!Objects.equals(this.right, right)) {
return false;
}
// 暂时判断逻辑为或者是runPath中一个或者是范围内车站且是对应方向站台
if (!CollectionUtils.isEmpty(this.necessarySections)) {
return this.necessarySections.contains(section);
}
if (Objects.nonNull(station)) {
if (!CollectionUtils.isEmpty(section.getStandList()) &&
Objects.equals(section.getStandList().get(0).isRight(), this.right)) {
int sn = this.section.getStation().getSn();
if ((this.right && station.getSn() <= sn) ||
(!this.right && station.getSn() >= sn)) {
return true;
}
}
}
return Objects.equals(this.section, section);
}
return Objects.equals(this.section, section);
return false;
}
return false;
}
/**
@ -198,36 +210,51 @@ public class DestinationCodeDefinition {
/**
* 查询下一个功能区段
*/
public Section queryNextFunctionSection(Section currentSection) {
int index = runPath.indexOf(currentSection);
if (index == -1) {
return null;
} else if (index == runPath.size() - 1) {
if (!Type.NORMAL_OPERATION.equals(type)) {
public Section queryNextTargetSection(Section currentSection) {
if (!CollectionUtils.isEmpty(runPath)) { //有指定路径
int index = runPath.indexOf(currentSection);
if (index == -1) {
return null;
} else if (index == runPath.size() - 1) {
if (!Type.NORMAL_OPERATION.equals(type)) {
return null;
}
}
if (!Type.NORMAL_OPERATION.equals(type)) { //非环路找到路径末就结束
for (int i = index + 1; i < runPath.size(); i++) {
Section section = runPath.get(i);
if (section.isNormalStandTrack()) {
return section;
}
if (section.isFunctionTrack()) {
if (necessarySections.contains(section)) {
return section;
}
}
}
} else { //环路循环找
int next = index + 1;
for (int i = 0; i < runPath.size(); i++) {
if (next == runPath.size()) {
next = 0;
continue;
}
Section section = runPath.get(next);
if (section.isNormalStandTrack()) {
return section;
}
if (section.isFunctionTrack()) {
if (necessarySections.contains(section)) {
return section;
}
}
next++;
}
}
} else { //无指定路径
}
if (!Type.NORMAL_OPERATION.equals(type)) { //非环路找到路径末就结束
for (int i = index + 1; i < runPath.size(); i++) {
Section section = runPath.get(i);
if (section.isFunctionTrack()) {
return section;
}
}
} else { //环路循环找
int next = index + 1;
for (int i = 0; i < runPath.size(); i++) {
if (next == runPath.size()) {
next = 0;
continue;
}
Section section = runPath.get(next);
if (section.isFunctionTrack()) {
return section;
}
next++;
}
}
return null;
}
@ -235,6 +262,35 @@ public class DestinationCodeDefinition {
return String.format("目的地码[%s]", code);
}
/**
* 查询下一个要办理的进路
*/
public Route queryNextRoute(Section section) {
List<Route> routeList = this.routes;
if (CollectionUtils.isEmpty(routeList)) {
return null;
}
Integer routeIndex = null;
for (int i = 0; i < routeList.size(); i++) {
Route route = routeList.get(i);
if (route.isRouteSection(section)) {
routeIndex = i;
}
}
if (routeIndex == null) {
return null;
}
if (routeIndex < routes.size() - 1) {
return routes.get(routeIndex + 1);
} else {
if (Type.NORMAL_OPERATION.equals(type)) {
return routes.get(0);
} else {
return null;
}
}
}
public enum Type {
/**
* 正常运营环路

View File

@ -1,5 +1,6 @@
package club.joylink.rtss.simulation.cbtc.data.map;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.cbtc.constant.SimulationConstants;
import club.joylink.rtss.simulation.cbtc.constant.TurnBackStrategyType;
import club.joylink.rtss.simulation.cbtc.data.support.StationTurnBackStrategyOption;
@ -376,10 +377,10 @@ public class Station extends MayOutOfOrderDevice {
}
/**
* 该区段所属的站台是否右向
* 该区段所属的正常站台是否右向
*/
public boolean isStandOfSectionRight(@NonNull Section section) {
List<Stand> stands = this.getAllStandList();
List<Stand> stands = this.getAllNormalStands();
for (Stand stand : stands) {
if (section.equals(stand.getSection())) {
return stand.isRight();
@ -410,6 +411,26 @@ public class Station extends MayOutOfOrderDevice {
return this.preResetValidDuration != null && this.preResetValidDuration.get() > 0;
}
/**
* 查询优先的折返轨
*/
public Section queryFirstTurnBackSection() {
if (CollectionUtils.isEmpty(this.tbStrategyMap) || this.tbStrategyId == null) {
return null;
}
StationTurnBackStrategyOption strategy = getCurrentTurnBackStrategy();
switch (strategy.getType()) {
case NONE:
case EQUAL:
return null;
case FIRST:
case ONLY:
return strategy.getSectionList().get(0);
default:
throw BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.exception("未知的折返策略类型" + strategy.getType());
}
}
public enum ControlMode {
/**
* 交出未被接收
@ -484,6 +505,13 @@ public class Station extends MayOutOfOrderDevice {
return stands.stream().filter(stand -> !stand.isSmall()).collect(Collectors.toList());
}
/**
* 获取所有正常站台
*/
public List<Stand> getAllNormalStands() {
return getAllStandList().stream().filter(stand -> !stand.isSmall()).collect(Collectors.toList());
}
public String debugStr() {
return String.format("车站[%s]", this.getName());
}

View File

@ -277,6 +277,7 @@ public class TrainStatus extends DeviceStatus {
statusVO.setDispose(dispose);
statusVO.setStop(stop);
statusVO.setBackUp(backUp);
statusVO.setOrderStop(orderStop);
return statusVO;
}

View File

@ -95,6 +95,7 @@ public class RoutePath {
routePath.addSignal(signal);
}
routePath.addSections(this.sectionList);
routePath.addRoutes(this.routeList);
return routePath;
}
@ -373,10 +374,19 @@ public class RoutePath {
return this.sectionList.get(this.sectionList.size() - 1);
}
public int getSwitchQuantity() {
if (CollectionUtils.isEmpty(routeList)) {
return 0;
}
return routeList.stream().mapToInt(route -> CollectionUtils.isEmpty(route.getSwitchList()) ? 0 : route.getSwitchList().size()).sum();
}
public String debugStr() {
Station startStation = this.start.getStation();
Station endStation = this.end.getStation();
return String.format("%s(%s)->%s(%s)",
this.start.getStation().getName(), this.start.getName(),
this.end.getStation().getName(), this.end.getName());
startStation != null ? startStation.getName() : null, this.start.getName(),
endStation != null ? endStation.getName() : null, this.end.getName());
}
public String debugStr2() {
@ -400,4 +410,11 @@ public class RoutePath {
signals,
routes);
}
/**
* 路径包含的区段是否被占用除了start
*/
public boolean isOccupied() {
return end.isOccupied() || sectionList.stream().anyMatch(Section::isOccupied);
}
}

View File

@ -477,6 +477,7 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
this.linkTrain = null;
this.lastTwoPassedResponders = new FixedQueue<>(Responders_Record);
this.runType = null;
this.orderStop = false;
}
public boolean isEB() {

View File

@ -78,6 +78,7 @@ public class ATOService {
//下令停车
if (train.isOrderStop()) {
this.doBreakMax(train);
return;
}
// 计算到目标/授权终点剩余距离根据距离计算速度根据速度控制牵引/制动输出
MovementAuthority ma = train.getMa();

View File

@ -20,14 +20,25 @@ public class DestinationCodeVO {
public DestinationCodeVO(DestinationCodeDefinition definition) {
this.code = definition.getCode();
this.description = definition.getDescription();
if (!CollectionUtils.isEmpty(definition.getRunPath())) {
this.runPath = definition.getRunPath().stream().flatMap(section -> {
if (!CollectionUtils.isEmpty(section.getLogicList())) {
return section.getLogicList().stream();
} else {
return Stream.of(section);
}
}).map(MapElement::getCode).collect(Collectors.toList());
if (!CollectionUtils.isEmpty(definition.getRoutes())) {
this.runPath = definition.getRoutes().stream().flatMap(route -> {
return route.getSectionList().stream().flatMap(section -> {
if (!CollectionUtils.isEmpty(section.getLogicList())) {
return section.getLogicList().stream();
} else {
return Stream.of(section);
}
}).map(MapElement::getCode);
}).collect(Collectors.toList());
}
// if (!CollectionUtils.isEmpty(definition.getRunPath())) {
// this.runPath = definition.getRunPath().stream().flatMap(section -> {
// if (!CollectionUtils.isEmpty(section.getLogicList())) {
// return section.getLogicList().stream();
// } else {
// return Stream.of(section);
// }
// }).map(MapElement::getCode).collect(Collectors.toList());
// }
}
}

View File

@ -28,6 +28,11 @@ public class MapDestinationCodeDefinitionVO {
private String description;
//----------- 交路类属性 -----------
/**
* 单向目的地码的起始区段
*/
private String startSectionCode;
/**
* 交路类目的地码对应的区段
*/