修改新版ATS进路排列逻辑

This commit is contained in:
joylink_zhangsai 2021-07-26 14:08:52 +08:00
parent 63da590542
commit b4776ffaa3
7 changed files with 220 additions and 131 deletions

View File

@ -308,7 +308,8 @@ public class AtsTrainService {
if (!sections.get(0).equals(headSection)) {
sections.add(0, headSection);
}
supervisedTrain.setHeadPath(sections);
SectionPath headPath = new SectionPath(selectRouting.isRight(), null, sections, null);
supervisedTrain.setHeadPath(headPath);
break;
default:
throw new SimulationException(SimulationExceptionType.System_Fault, String.format("无法识别的目的地码类型[%s]", destinationCodeDefinition.getType()));
@ -674,7 +675,7 @@ public class AtsTrainService {
}
break;
case OTHER:
List<Section> path = train.getHeadPath();
List<Section> path = train.getHeadPath().getSectionList();
if (path != null) {
int index = path.indexOf(headSection);
if (index == -1) {

View File

@ -1,10 +1,8 @@
package club.joylink.rtss.simulation.cbtc.ATS.service.ars;
import club.joylink.rtss.simulation.cbtc.ATS.service.stage.AtsHeadTrainStageService;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository;
import club.joylink.rtss.simulation.cbtc.data.map.DestinationCodeDefinition;
import club.joylink.rtss.simulation.cbtc.data.map.MapConfig;
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.plan.StationPlan;
@ -17,7 +15,6 @@ import org.springframework.util.CollectionUtils;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
/**
* 头码车进路选择
@ -36,49 +33,8 @@ public class AtsHeadTrainRouteSelectServiceImpl extends AtsRouteSelectService {
if (right == null)
return null;
DestinationCodeDefinition dcd = repository.getDestinationCodeDefinition(trainInfo.getDestinationCode());
Section headSection = repository.getByCode(trainInfo.getPhysicalSection(), Section.class);
String estimatedArriveStandTrack = trainInfo.getEstimatedArriveStandTrack();
if (estimatedArriveStandTrack == null)
return null;
Section targetSection = repository.getByCode(estimatedArriveStandTrack, Section.class);
if (!CollectionUtils.isEmpty(dcd.getRoutes())) {
return dcd.queryNextRoute(headSection);
} else {
// 根据车次计划查找可触发进路列表
Object[] results = this.queryByDestinationCode(simulation, trainInfo, headSection, targetSection, right);
// 根据计划筛选需触发进路
return filterRoutes(repository, trainInfo, results, dcd);
}
}
private Object[] queryByDestinationCode(Simulation simulation, TrainInfo trainInfo, Section headSection, Section targetSection, Boolean right) {
SimulationDataRepository repository = simulation.getRepository();
List<RoutePath> routePathList = repository.queryRoutePathsByEnd(targetSection);
if (CollectionUtils.isEmpty(routePathList)) {
return null;
}
routePathList = routePathList.stream()
.filter(routePath -> routePath.containsSection(headSection))
.collect(Collectors.toList());
Object[] result = this.queryTriggerRoutesOfRoutePath(repository, trainInfo, routePathList);
if (!(boolean) result[1] && !(boolean) result[2]) { //不存在未触发的进路和未接近的信号机
// 判断配置是否列车停站才触发接下来的进路
MapConfig config = repository.getConfig();
if (!config.isSignalOpenAfterParking() || trainInfo.isPlanTrain()) {
Section nextTarget = AtsHeadTrainStageService.queryNextTarget(simulation, targetSection, trainInfo, right);
if (nextTarget != null) {
routePathList = repository.queryRoutePathsByEnd(nextTarget);
if (!CollectionUtils.isEmpty(routePathList)) {
routePathList = routePathList.stream()
.filter(routePath -> routePath.containsSection(headSection))
.collect(Collectors.toList());
return this.queryTriggerRoutesOfRoutePath(repository, trainInfo, routePathList);
}
}
}
return null;
}
return result;
Object[] results = queryTriggerRoutes(repository, trainInfo.getHeadPath().getSectionList(), trainInfo, null, trainInfo.getHeadPath().isRight());
return filterRoutes(repository, trainInfo, results, dcd);
}
private Route filterRoutes(SimulationDataRepository repository, TrainInfo trainInfo, Object[] results, DestinationCodeDefinition dcd) {
@ -93,30 +49,6 @@ public class AtsHeadTrainRouteSelectServiceImpl extends AtsRouteSelectService {
} else {
route = triggers.stream().min(Comparator.comparingInt(Route::getReverseSwitchQuantity)).get();
}
boolean hasReverseConflictRoute = false; //有反向冲突进路
if (!CollectionUtils.isEmpty(route.getConflictingRouteList())) {
for (Route conflictingRoute : route.getConflictingRouteList()) {
if (repository.isSettingRoute(conflictingRoute)) { //有冲突进路正在办理
return null;
} else if (conflictingRoute.isRight() != route.isRight()) {
hasReverseConflictRoute = true;
}
}
}
if (hasReverseConflictRoute) {
Section section = route.getSectionList().stream()
.filter(Section::isOccupied)
.limit(1)
.findAny()
.orElse(null);
if (section != null) {
if (repository.getSuperviseTrainList().stream()
.filter(info -> info.getPhysicalSection().equals(section.getCode()))
.anyMatch(info -> isConflicting(repository, info, route))) {
return null;
}
}
}
return route;
}

View File

@ -43,12 +43,35 @@ public class AtsPlanTrainRouteSelectServiceImpl extends AtsRouteSelectService {
TripPlan tripPlan = repository.getTripPlan(trainInfo.getServiceNumber(), trainInfo.getTripNumber());
LocalDateTime systemTime = simulation.getSystemTime();
// 根据车次计划查找可触发进路列表
Object[] results = this.queryByStationPlan(repository, systemTime, trainInfo, tripPlan);
// Object[] results = this.queryByStationPlan(repository, systemTime, trainInfo, tripPlan);
Object[] results = queryByStationPlan2(repository, systemTime, trainInfo, tripPlan);
// 根据计划筛选需触发进路
Route route = filterRoutes(simulation, trainInfo, tripPlan, results);
return route;
}
private Object[] queryByStationPlan2(SimulationDataRepository repository, LocalDateTime systemTime, TrainInfo trainInfo, TripPlan tripPlan) {
// 计划时间
List<StationPlan> planList = tripPlan.getPlanList();
LocalTime startTime = tripPlan.getStartTime();
for (StationPlan stationPlan : planList) {
if (stationPlan.getSection().getCode().equals(trainInfo.getPlanStandTrack())) {
break;
}
startTime = stationPlan.getLeaveTime();
}
if (!systemTime.toLocalTime().plusSeconds(50).isAfter(startTime)) {
log.debug(String.format("列车[%s]未到发车时间,不触发进路", trainInfo.getGroupNumber()));
return null;
}
List<Section> targetList = tripPlan.getPlanList().stream().map(StationPlan::getSection).collect(Collectors.toList());
if (tripPlan.isBehindTurnBack()) {
return queryTriggerRoutes(repository, targetList, trainInfo, tripPlan.getEndSection(), tripPlan.isRight());
} else {
return queryTriggerRoutes(repository, targetList, trainInfo, null, tripPlan.isRight());
}
}
/**
* 先选取需要征用的进路再根据计划判断是否存在冲突的未完成计划
* @param simulation
@ -348,7 +371,6 @@ public class AtsPlanTrainRouteSelectServiceImpl extends AtsRouteSelectService {
private Route filter(SimulationDataRepository repository, TrainInfo trainInfo,
TripPlan tripPlan, List<Route> triggerList, boolean turnBack) {
Section section = repository.getByCode(trainInfo.getPlanStandTrack(), Section.class);
Route route = triggerList.get(0);
if (turnBack) {
for (Route temp : triggerList) {
@ -368,6 +390,7 @@ public class AtsPlanTrainRouteSelectServiceImpl extends AtsRouteSelectService {
}
}
} else if (triggerList.size() > 1) {
Section section = repository.getByCode(trainInfo.getPlanStandTrack(), Section.class);
List<Route> routeList = new ArrayList<>();
for (Route temp : triggerList) {
if (!routeList.isEmpty() && routeList.get(0).getReverseSwitchQuantity() > temp.getReverseSwitchQuantity()) {

View File

@ -2,10 +2,9 @@ package club.joylink.rtss.simulation.cbtc.ATS.service.ars;
import club.joylink.rtss.simulation.cbtc.Simulation;
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.map.*;
import club.joylink.rtss.simulation.cbtc.data.support.RoutePath;
import club.joylink.rtss.simulation.cbtc.data.support.StationTurnBackStrategyOption;
import club.joylink.rtss.simulation.cbtc.data.vo.TrainInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
@ -13,13 +12,115 @@ import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@Slf4j
public abstract class AtsRouteSelectService {
public abstract Route select(Simulation simulation, TrainInfo trainInfo);
/**
* 查询需要触发的进路
*
* @param turnBackSection 站后折返的折返轨
* @param right 计划运行方向
*/
public Object[] queryTriggerRoutes(SimulationDataRepository repository, List<Section> targetList,
TrainInfo trainInfo, Section turnBackSection, boolean right) {
Section headSection = repository.getByCode(trainInfo.getPhysicalSection(), Section.class);
Object[] result = {null, false, false};
MapConfig config = repository.getConfig();
Section targetSection = null;
Section nextTarget = null;
//选择目标区段
for (int i = targetList.size() - 1; i >= 0; i--) {
Section target = targetList.get(i);
List<RoutePath> routePaths = repository.queryRoutePathsByEndAndContainsSection(target, headSection);
routePaths.removeIf(routePath -> routePath.isRight() != right);
if (!CollectionUtils.isEmpty(routePaths)) {
result = queryTriggerRoutesOfRoutePath(repository, trainInfo, routePaths);
targetSection = target;
if (i < targetList.size() - 1) {
nextTarget = targetList.get(i + 1);
}
}
}
//选择进路
boolean noRoute2Trigger = result != null && !(boolean) result[1] && !(boolean) result[2];
if (targetSection != null) {
if (!config.isSignalOpenAfterParking()) {
if (noRoute2Trigger) {
if (nextTarget != null) {
List<RoutePath> routePaths = repository.queryRoutePathsByEndAndContainsSection(nextTarget, headSection);
routePaths.removeIf(routePath -> routePath.isRight() != right);
result = this.queryTriggerRoutesOfRoutePath(repository, trainInfo, routePaths);
} else if (turnBackSection != null) {
List<Route> triggerRoutes = queryTriggerRoutes4TurnBack(repository, targetSection, turnBackSection, trainInfo);
return new Object[]{triggerRoutes, true};
}
}
} else {
if (nextTarget == null && targetSection.equals(headSection) && trainInfo.isParking()) {
List<Route> triggerRoutes = queryTriggerRoutes4TurnBack(repository, targetSection, turnBackSection, trainInfo);
return new Object[]{triggerRoutes, true};
}
}
}
return result;
}
public List<Route> queryTriggerRoutes4TurnBack(SimulationDataRepository repository, Section standSection, Section tbSection, TrainInfo trainInfo) {
Station station = standSection.getStation();
StationTurnBackStrategyOption strategy = station.getCurrentTurnBackStrategy();
List<Section> tbSectionList = new ArrayList<>();
if (Objects.isNull(strategy)) {
tbSectionList.add(tbSection);
} else {
switch (strategy.getType()) {
// 按计划
case NONE: {
tbSectionList.add(tbSection);
break;
}
// 仅某个折返轨
case ONLY: {
tbSectionList.add(strategy.getSectionList().get(0));
break;
}
// 折返轨等价
case FIRST:
case EQUAL: {
tbSectionList.addAll(strategy.getSectionList());
break;
}
}
}
List<RoutePath> list = repository.getRoutePaths(standSection, tbSection);
boolean right = list.get(0).isRight();
Signal signal = standSection.getSignalOf(right);
if (!this.isApproachSignal(repository, trainInfo, signal)) {
return null;
}
List<Route> routeList = signal.getRouteList();
List<Route> tbRouteList = new ArrayList<>();
for (Route route : routeList) {
if (route.isTurnBack()) {
tbRouteList.add(route);
}
}
if (!tbRouteList.isEmpty()) {
routeList = tbRouteList;
}
routeList = routeList.stream()
.filter(route -> !repository.hasSameStartTriggerRoute(trainInfo, route))
.filter(route -> route.containSameSection(tbSectionList))
.collect(Collectors.toList());
return routeList;
}
/**
* 筛选列车路径
*
* @param pathList
* @return
*/
@ -34,7 +135,7 @@ public abstract class AtsRouteSelectService {
}
public Object[] queryTriggerRoutesOfRoutePath(SimulationDataRepository repository,
TrainInfo trainInfo, List<RoutePath> routePathList) {
TrainInfo trainInfo, List<RoutePath> routePathList) {
Boolean right = trainInfo.getRight();
Section section = repository.getByCode(trainInfo.getPhysicalSection(), Section.class); // 列车所在区段
Section logicSection = repository.getByCode(trainInfo.getSection(), Section.class);
@ -42,8 +143,8 @@ public abstract class AtsRouteSelectService {
}
public Object[] queryTriggers(SimulationDataRepository repository, TrainInfo trainInfo, List<RoutePath> routePathList,
Boolean right, Section section, Section logicSection) {
Object[] result = new Object[3]; // 结果0为可触发的进路列表1为是否存在未触发的进路,2为是否存在未接近的信号机或无法触发信号机
Boolean right, Section section, Section logicSection) {
Object[] result = new Object[3]; // 结果0为可触发的进路列表1为是否存在未触发的进路,2为是否存在未接近的信号机
List<Route> triggerList = new ArrayList<>();
result[0] = triggerList;
result[1] = false;

View File

@ -121,50 +121,63 @@ public class AtsHeadTrainStageService implements AtsStageService {
} else {
runningTime = 180;
}
trainInfo.updateEstimatedArriveInfo(nextTarget, simulation.getSystemTime().toLocalTime().plusSeconds(runningTime));
trainInfo.updatePlanInfo(nextTarget, null, null);
// trainInfo.updateEstimatedArriveInfo(nextTarget, simulation.getSystemTime().toLocalTime().plusSeconds(runningTime));
boolean jump = this.atsStandService.isJump(nextTarget, trainInfo.getGroupNumber());
onboardAtpApiService.updateNextArriveInfo(simulation, trainInfo.getGroupNumber(), nextTarget, true, runningTime, jump);
}
public static Section queryNextTarget(Simulation simulation, Section section, TrainInfo trainInfo, Boolean right) {
public static Section queryNextTarget(Simulation simulation, Section headSection, TrainInfo trainInfo, Boolean right) {
SimulationDataRepository repository = simulation.getRepository();
String dc = trainInfo.getDestinationCode();
List<Routing> routings = repository.queryRoutingByDestCode(dc);
Section nextSection = null;
if (!CollectionUtils.isEmpty(routings)) { //目的地码在区段上
for (Routing routing : routings) {
if (section.isTurnBackTrack()) { //是折返轨不限制方向
nextSection = routing.queryNextSection(section);
if (nextSection != null)
break;
for (Section s : routing.getAllSections()) {
List<RoutePath> routePaths = repository.queryRoutePathsByEndAndContainsSection(s, section);
if (!CollectionUtils.isEmpty(routePaths)) {
if (routePaths.stream().anyMatch(routePath -> routePath.isRight() == routing.isRight())) {
return s;
}
}
}
} else { //不是折返轨必须和列车同向
if (routing.isRight() == right) {
nextSection = routing.queryNextSection(section);
if (nextSection != null)
break;
for (Section s : routing.getAllSections()) {
List<RoutePath> routePaths = repository.queryRoutePathsByEndAndContainsSection(s, section);
if (routePaths.stream().anyMatch(routePath -> routePath.isRight() == right)) {
return s;
}
}
}
}
List<Section> targetList = trainInfo.getHeadPath().getSectionList();
for (int i = targetList.size() - 1; i >= 0; i--) {
Section target = targetList.get(i);
List<RoutePath> routePaths = repository.queryRoutePathsByEndAndContainsSection(target, headSection);
if (!CollectionUtils.isEmpty(routePaths)) {
return target;
}
} else {
DestinationCodeDefinition dcd = repository.findDestinationCodeDefinition(dc);
if (dcd == null)
return null;
nextSection = AtsTrainService.findNextTarget4HeadTrain(simulation, trainInfo, repository, section, section.getStation(), dcd);
}
return nextSection;
return null;
// SimulationDataRepository repository = simulation.getRepository();
// String dc = trainInfo.getDestinationCode();
// List<Routing> routings = repository.queryRoutingByDestCode(dc);
// Section nextSection = null;
// if (!CollectionUtils.isEmpty(routings)) { //目的地码在区段上
// for (Routing routing : routings) {
// if (headSection.isTurnBackTrack()) { //是折返轨不限制方向
// nextSection = routing.queryNextSection(headSection);
// if (nextSection != null)
// break;
// for (Section s : routing.getAllSections()) {
// List<RoutePath> routePaths = repository.queryRoutePathsByEndAndContainsSection(s, headSection);
// if (!CollectionUtils.isEmpty(routePaths)) {
// if (routePaths.stream().anyMatch(routePath -> routePath.isRight() == routing.isRight())) {
// return s;
// }
// }
// }
// } else { //不是折返轨必须和列车同向
// if (routing.isRight() == right) {
// nextSection = routing.queryNextSection(headSection);
// if (nextSection != null)
// break;
// for (Section s : routing.getAllSections()) {
// List<RoutePath> routePaths = repository.queryRoutePathsByEndAndContainsSection(s, headSection);
// if (routePaths.stream().anyMatch(routePath -> routePath.isRight() == right)) {
// return s;
// }
// }
// }
// }
// }
// } else {
// DestinationCodeDefinition dcd = repository.findDestinationCodeDefinition(dc);
// if (dcd == null)
// return null;
// nextSection = AtsTrainService.findNextTarget4HeadTrain(simulation, trainInfo, repository, headSection, headSection.getStation(), dcd);
// }
// return nextSection;
}
}

View File

@ -148,9 +148,9 @@ public class StorageTrainInfo {
this.actualLeaveStandTrack = info.getActualLeaveStandTrack();
this.actualLeaveTime = info.getActualLeaveTime();
this.backUp = info.isBackUp();
if (!CollectionUtils.isEmpty(info.getHeadPath())) {
this.headPath = info.getHeadPath().stream().map(MapElement::getCode).collect(Collectors.toList());
}
// if (!CollectionUtils.isEmpty(info.getHeadPath())) {
// this.headPath = info.getHeadPath().stream().map(MapElement::getCode).collect(Collectors.toList());
// }
}
public TrainInfo convert2SimulationObj(SimulationDataRepository repository) {

View File

@ -206,7 +206,7 @@ public class TrainInfo extends MapElement {
* 头码车的区段路径
*/
@Setter
private List<Section> headPath;
private SectionPath headPath;
/**
* 下令停车
@ -331,9 +331,9 @@ public class TrainInfo extends MapElement {
this.actualLeaveStandTrack = info.getActualLeaveStandTrack();
this.actualLeaveTime = info.getActualLeaveTime();
this.backUp = info.isBackUp();
if (!CollectionUtils.isEmpty(info.getHeadPath())) {
this.headPath = info.getHeadPath().stream().map(code -> repository.getByCode(code, Section.class)).collect(Collectors.toList());
}
// if (!CollectionUtils.isEmpty(info.getHeadPath())) {
// this.headPath = info.getHeadPath().stream().map(code -> repository.getByCode(code, Section.class)).collect(Collectors.toList());
// }
}
@Override
@ -455,19 +455,38 @@ public class TrainInfo extends MapElement {
}
public void updatePlanInfo(StationPlan nextStationPlan) {
// if (Objects.nonNull(nextStationPlan)) {
// this.planStandTrack = nextStationPlan.getSection().getCode();
// this.planArriveTime = nextStationPlan.getArriveTime();
// this.planLeaveTime = nextStationPlan.getLeaveTime();
// List<Stand> standList = nextStationPlan.getSection().getStandList();
// if (!CollectionUtils.isEmpty(standList)) {
// this.turnBackStrategy = standList.get(0).getTypeStrategy().name();
// }
// } else {
// this.planStandTrack = null;
// this.planArriveTime = null;
// this.planLeaveTime = null;
// }
if (Objects.nonNull(nextStationPlan)) {
this.planStandTrack = nextStationPlan.getSection().getCode();
this.planArriveTime = nextStationPlan.getArriveTime();
this.planLeaveTime = nextStationPlan.getLeaveTime();
List<Stand> standList = nextStationPlan.getSection().getStandList();
updatePlanInfo(nextStationPlan.getSection(), nextStationPlan.getArriveTime(), nextStationPlan.getLeaveTime());
} else {
updatePlanInfo(null, null, null);
}
}
public void updatePlanInfo(Section planSection, LocalTime planArriveTime, LocalTime planLeaveTime) {
if (planSection != null) {
this.planStandTrack = planSection.getCode();
List<Stand> standList = planSection.getStandList();
if (!CollectionUtils.isEmpty(standList)) {
this.turnBackStrategy = standList.get(0).getTypeStrategy().name();
}
} else {
this.planStandTrack = null;
this.planArriveTime = null;
this.planLeaveTime = null;
}
this.planArriveTime = planArriveTime;
this.planLeaveTime = planLeaveTime;
}
public void updateArriveInfo(LocalTime arriveTime, Station arriveStation, Section section) {