diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/service/AtsRouteService.java b/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/service/AtsRouteService.java index e2c47746b..c46491ae3 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/service/AtsRouteService.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/service/AtsRouteService.java @@ -1,318 +1,319 @@ -package club.joylink.rtss.simulation.cbtc.ATS.service; - -import club.joylink.rtss.exception.BusinessExceptionAssertEnum; -import club.joylink.rtss.simulation.cbtc.ATS.data.AtsAlarm; -import club.joylink.rtss.simulation.cbtc.CI.CiApiService; -import club.joylink.rtss.simulation.cbtc.CI.device.CiRouteService; -import club.joylink.rtss.simulation.cbtc.Simulation; -import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository; -import club.joylink.rtss.simulation.cbtc.data.map.Cycle; -import club.joylink.rtss.simulation.cbtc.data.map.Route; -import club.joylink.rtss.simulation.cbtc.data.map.Signal; -import club.joylink.rtss.simulation.cbtc.data.status.RouteStatus; -import club.joylink.rtss.simulation.cbtc.exception.SimulationException; -import club.joylink.rtss.simulation.cbtc.exception.SimulationExceptionType; -import club.joylink.rtss.simulation.cbtc.member.SimulationMember; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import org.springframework.util.CollectionUtils; -import org.springframework.util.StringUtils; - -import java.time.LocalDateTime; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; - -@Slf4j -@Component -public class AtsRouteService { - - @Autowired - private CiRouteService routeService; - - @Autowired - private CiApiService ciApiService; - - /** - * 进路收人工控 - * - * @param simulation - * @param signalCode - * @param routeCodeList - */ - public void setRouteHumanControl(Simulation simulation, String signalCode, List routeCodeList) { - if (!CollectionUtils.isEmpty(routeCodeList)) { - routeCodeList.forEach(routeCode -> { - Route route = simulation.getRepository().getByCode(routeCode, Route.class); - route.setAtsControl(false); - }); - } else if (StringUtils.hasText(signalCode)) { - Signal signal = simulation.getRepository().getByCode(signalCode, Signal.class); - List routeList = signal.getRouteList(); - if (!CollectionUtils.isEmpty(routeList)) { - routeList.forEach(route -> route.setAtsControl(false)); - } - } - } - - /** - * 进路交自动控 - */ - public void setRouteAtsControl(Simulation simulation, String signalCode, - List routeCodeList, List checkConflictList) { - SimulationDataRepository repository = simulation.getRepository(); - if (!CollectionUtils.isEmpty(routeCodeList)) { - if (!CollectionUtils.isEmpty(checkConflictList)) { - BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertTrue(routeCodeList.size() == checkConflictList.size(), - String.format("进路数和是否检查冲突数量不一致:[%s], [%s]", - String.join(",", routeCodeList), - String.join(",", checkConflictList.stream().map(String::valueOf).collect(Collectors.toList())))); - } - List routes = routeCodeList.stream().map(routeCode -> repository.getByCode(routeCode, Route.class)).collect(Collectors.toList()); - if (repository.getConfig().isSignalHumanControlBeforeSetAtsControlOrCIAutoTrigger()) { - routes.stream() - .map(Route::getStart) - .distinct() - .forEach(signal -> - BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED - .assertNotTrue(signal.isCiControl(), - String.format("信号机[%s]需处于人工控状态", signal.getCode()))); - } - if (CollectionUtils.isEmpty(checkConflictList)) { - routes.forEach(route -> route.setAtsControl(true)); - } else { - for (int i = 0; i < routeCodeList.size(); i++) { - Route route = repository.getByCode(routeCodeList.get(i), Route.class); - boolean checkConflict = checkConflictList.get(i); - route.setAtsControl(true); - route.setCheckConflict(checkConflict); - } - } - } else if (StringUtils.hasText(signalCode)) { - Signal signal = repository.getByCode(signalCode, Signal.class); - if (repository.getConfig().isSignalHumanControlBeforeSetAtsControlOrCIAutoTrigger()) { - BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertNotTrue(signal.isCiControl(), String.format("信号机[%s]需处于人工控状态", signal.getCode())); - } - List routeList = signal.getRouteList(); - if (!CollectionUtils.isEmpty(routeList)) { - routeList.forEach(route -> route.setAtsControl(true)); - } - } - } - - /** - * 查询进路状态/模式 - */ - public List findRoutesStatus(Simulation simulation, String signalCode) { - Signal signal = simulation.getRepository().getByCode(signalCode, Signal.class); - List routeList = signal.getRouteList(); - return routeList.stream().map(RouteStatus::new).collect(Collectors.toList()); - } - - /** - * 设置联锁自动进路 - */ - public void setCiAuto(Simulation simulation, String signalCode) { - Signal signal = simulation.getRepository().getByCode(signalCode, Signal.class); - if (simulation.getRepository().getConfig().isSetRouteBeforeSetFlt()) { - Route lockedRoute = signal.getLockedRoute(); - if (lockedRoute == null) { - throw new SimulationException(SimulationExceptionType.Operation_Handle_FAIL, - String.format("信号机[%s(%s)]没有已锁闭进路,不能设置联锁自动进路", signal.getName(), signal.getCode())); - } - if (!lockedRoute.isFlt()) { - throw new SimulationException(SimulationExceptionType.Unsupported_Operation, - String.format("进路[%s]不能设置车队进路", lockedRoute.getCode())); - } - if (lockedRoute.isCiControl()) { - throw new SimulationException(SimulationExceptionType.Operation_Conflict, - String.format("进路[%s(%s)]自动追踪已开启,不能设置联锁自动进路", lockedRoute.getName(), lockedRoute.getCode())); - } - lockedRoute.setFleetMode(true); - } else { - List routeList = signal.getRouteList(); - BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertCollectionNotEmpty(routeList, signal.debugStr() + "不是进路始端信号机"); - // 筛选最适合的进路,筛选逻辑与办理引导时筛选逻辑类似 - List fltRoutes = routeList.stream().filter(Route::isFlt).collect(Collectors.toList()); - BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertCollectionNotEmpty(fltRoutes, signal.debugStr() + "下没有可设置的车队进路"); - List collect = fltRoutes.stream() - .filter(r -> !r.isTurnBack() && CollectionUtils.isEmpty(r.getSwitchList())) - .collect(Collectors.toList()); - if (CollectionUtils.isEmpty(collect)) { - collect = fltRoutes.stream().filter(r -> !r.isTurnBack()).collect(Collectors.toList()); - } - if (CollectionUtils.isEmpty(collect)) { - collect = fltRoutes; - } - Route route = collect.get(0); - Route.CheckFailMessage message = routeService.setRoute(simulation, route); - BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertNull(message, route.debugStr() + "无法办理"); - route.setFleetMode(true); - } - } - - /** - * 取消联锁自动进路 - */ - public void cancelCiAuto(Simulation simulation, String signalCode) { - Signal signal = simulation.getRepository().getByCode(signalCode, Signal.class); - Route lockedRoute = signal.getLockedRoute(); - if (Objects.isNull(lockedRoute)) { - throw new SimulationException(SimulationExceptionType.Operation_Handle_FAIL, - String.format("信号机[%s(%s)]没有已锁闭进路,不能执行取消联锁自动进路", signal.getName(), signal.getCode())); - } - if (!lockedRoute.isFleetMode()) { - throw new SimulationException(SimulationExceptionType.Operation_Repetition, String.format("信号机[%s(%s)]没有打开连锁自动进路,不能取消联锁自动进路", signal.getName(), signal.getCode())); - } - lockedRoute.setFleetMode(false); - if (simulation.getRepository().getConfig().isCancelRouteWhenCancelFlt()) { - routeService.unlockRoute(simulation, lockedRoute); - } - } - - /** - * 设置联锁自动触发 - */ - public void setCiAutoTrigger(Simulation simulation, String signalCode, List routeCodeList) { - SimulationDataRepository repository = simulation.getRepository(); - List routeList; - if (StringUtils.hasText(signalCode)) { - Signal signal = repository.getByCode(signalCode, Signal.class); - if (repository.getConfig().isSignalHumanControlBeforeSetAtsControlOrCIAutoTrigger()) { - BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertNotTrue(signal.isAtsControl(), String.format("信号机[%s]需处于人工控", signal.getCode())); - } - routeList = signal.getRouteList(); - } else { - routeList = routeCodeList.stream() - .map(code -> repository.getByCode(code, Route.class)) - .collect(Collectors.toList()); - if (repository.getConfig().isSignalHumanControlBeforeSetAtsControlOrCIAutoTrigger()) { - routeList.stream() - .map(Route::getStart) - .distinct() - .forEach(signal -> - BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED - .assertNotTrue(signal.isAtsControl(), - String.format("信号机[%s]需处于人工控", signal.getCode()))); - } - } - if (!CollectionUtils.isEmpty(routeList)) { - routeList.stream().filter(Route::isArs).forEach(route -> { - if (route.isFleetMode()) { - throw new SimulationException(SimulationExceptionType.Operation_Conflict, - String.format("进路[%s(%s)]自动通过已开启,不能设置自动追踪", route.getName(), route.getCode())); - } -// if (route.isCiControl()) { -// throw new SimulationException(SimulationExceptionType.Operation_Repetition, String.format("进路[%s(%s)]自动追踪/连锁自动触发已开启,无需重复设置", route.getName(), route.getCode())); -// } - }); - for (Route route : routeList) { -// route.setAtsControl(false); - if (route.isArs()) - route.setCiControl(true); - } - } - } - - /** - * 取消联锁自动触发 - */ - public void cancelCiAutoTrigger(Simulation simulation, String signalCode, List routeCodes) { - List routeList; - SimulationDataRepository repository = simulation.getRepository(); - if (StringUtils.hasText(signalCode)) { - Signal signal = repository.getByCode(signalCode, Signal.class); - routeList = signal.getRouteList(); - } else { - routeList = routeCodes.stream() - .map(code -> repository.getByCode(code, Route.class)) - .collect(Collectors.toList()); - } - if (!CollectionUtils.isEmpty(routeList)) { - for (Route route : routeList) { - if (route.isCiControl()) { - route.setCiControl(false); - route.setAtsControl(false); - } - } - } - } - - /** - * 设置自动折返进路 - * - * @param simulation - * @param cycleCode - */ - public void setAutoTurnBack(Simulation simulation, String cycleCode) { - Cycle cycle = simulation.getRepository().getByCode(cycleCode, Cycle.class); - cycle.setSetUp(true); - } - - /** - * 取消自动折返进路 - */ - public void cancelAutoTurnBack(Simulation simulation, String cycleCode) { - Cycle cycle = simulation.getRepository().getByCode(cycleCode, Cycle.class); - cycle.setSetUp(false); - } - - /** - * 总取消 - */ - public void totalCancel(Simulation simulation, String signalCode) { - // todo 总取消操作有很多种操作方式,对应不同的按钮,此处都用信号机编号可能不妥 - Signal signal = simulation.getRepository().getByCode(signalCode, Signal.class); - Route lockedRoute = signal.getLockedRoute(); - if (lockedRoute == null) { - throw new SimulationException(SimulationExceptionType.Operation_Handle_FAIL, - String.format("信号机[%s(%s)]没有已锁闭进路,无需取消进路", signal.getName(), signal.getCode())); - } - if (!signal.isApproachLock()) { //当接近区段未被占用 - this.cancelRoute(simulation, signalCode); - } else { - this.routeService.unlockRoute(simulation, lockedRoute); - this.ciApiService.cancelFleetRoute(simulation, lockedRoute.getCode()); -// if (signal.isGuideAspect()) { //如果引导信号开启中 -// this.ciApiService.closeGuideSignal(simulation, signalCode); -// } else if (signal.isClose()) { //如果信号灯关了 -// } else { -// this.ciApiService.closeSignal(simulation, signalCode); -// } - } - } - - public void cancelRoute(Simulation simulation, String signalCode) { - Route route = this.ciApiService.findLockedRouteByStartSignal(simulation, signalCode); - if (Objects.nonNull(route)) { - BusinessExceptionAssertEnum.OPERATION_FAIL.assertNotTrue( - route.isApproachLock(), "进路接近锁闭,无法取消"); - BusinessExceptionAssertEnum.OPERATION_FAIL.assertNotTrue( - route.getStart().isGuideAspect(), "引导进路,需要人解进路"); - BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertNotTrue(route.isFleetMode(), - String.format("进路[%s]已开启自动通过进路,无法取消", route.debugStr())); - this.ciApiService.unlockRoute(simulation, route.getCode()); - } - } - - public void setOverlap(Simulation simulation, String signalCode, String overlapCode) { - if (signalCode == null || overlapCode == null) { - throw new SimulationException(SimulationExceptionType.Illegal_Argument); - } - this.ciApiService.setOverlap(simulation, signalCode, overlapCode); - } - - public void conflictRouteSetConfirm(Simulation simulation, SimulationMember member, String routeCode, int way) { - BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertTrue( - Route.Conflict_Handle_Way_1 == way || Route.Conflict_Handle_Way_2 == way - ); - Route route = simulation.getRepository().getByCode(routeCode, Route.class); - AtsAlarm conflictAlarm = route.getConflictAlarm(); - if (conflictAlarm != null) { - LocalDateTime systemTime = simulation.getCorrectSystemTime(); - conflictAlarm.confirm(systemTime, member, way); - conflictAlarm.recover(systemTime); - } - } -} +package club.joylink.rtss.simulation.cbtc.ATS.service; + +import club.joylink.rtss.exception.BusinessExceptionAssertEnum; +import club.joylink.rtss.simulation.cbtc.ATS.data.AtsAlarm; +import club.joylink.rtss.simulation.cbtc.CI.CiApiService; +import club.joylink.rtss.simulation.cbtc.CI.device.CiRouteService; +import club.joylink.rtss.simulation.cbtc.Simulation; +import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository; +import club.joylink.rtss.simulation.cbtc.data.map.Cycle; +import club.joylink.rtss.simulation.cbtc.data.map.Route; +import club.joylink.rtss.simulation.cbtc.data.map.Signal; +import club.joylink.rtss.simulation.cbtc.data.status.RouteStatus; +import club.joylink.rtss.simulation.cbtc.exception.SimulationException; +import club.joylink.rtss.simulation.cbtc.exception.SimulationExceptionType; +import club.joylink.rtss.simulation.cbtc.member.SimulationMember; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +@Slf4j +@Component +public class AtsRouteService { + + @Autowired + private CiRouteService routeService; + + @Autowired + private CiApiService ciApiService; + + /** + * 进路收人工控 + * + * @param simulation + * @param signalCode + * @param routeCodeList + */ + public void setRouteHumanControl(Simulation simulation, String signalCode, List routeCodeList) { + if (!CollectionUtils.isEmpty(routeCodeList)) { + routeCodeList.forEach(routeCode -> { + Route route = simulation.getRepository().getByCode(routeCode, Route.class); + route.setAtsControl(false); + }); + } else if (StringUtils.hasText(signalCode)) { + Signal signal = simulation.getRepository().getByCode(signalCode, Signal.class); + List routeList = signal.getRouteList(); + if (!CollectionUtils.isEmpty(routeList)) { + routeList.forEach(route -> route.setAtsControl(false)); + } + } + } + + /** + * 进路交自动控 + */ + public void setRouteAtsControl(Simulation simulation, String signalCode, + List routeCodeList, List checkConflictList) { + SimulationDataRepository repository = simulation.getRepository(); + if (!CollectionUtils.isEmpty(routeCodeList)) { + if (!CollectionUtils.isEmpty(checkConflictList)) { + BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertTrue(routeCodeList.size() == checkConflictList.size(), + String.format("进路数和是否检查冲突数量不一致:[%s], [%s]", + String.join(",", routeCodeList), + String.join(",", checkConflictList.stream().map(String::valueOf).collect(Collectors.toList())))); + } + List routes = routeCodeList.stream().map(routeCode -> repository.getByCode(routeCode, Route.class)).collect(Collectors.toList()); + if (repository.getConfig().isSignalHumanControlBeforeSetAtsControlOrCIAutoTrigger()) { + routes.stream() + .map(Route::getStart) + .distinct() + .forEach(signal -> + BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED + .assertNotTrue(signal.isCiControl(), + String.format("信号机[%s]需处于人工控状态", signal.getCode()))); + } + if (CollectionUtils.isEmpty(checkConflictList)) { + routes.forEach(route -> route.setAtsControl(true)); + } else { + for (int i = 0; i < routeCodeList.size(); i++) { + Route route = repository.getByCode(routeCodeList.get(i), Route.class); + boolean checkConflict = checkConflictList.get(i); + route.setAtsControl(true); + route.setCheckConflict(checkConflict); + } + } + } else if (StringUtils.hasText(signalCode)) { + Signal signal = repository.getByCode(signalCode, Signal.class); + if (repository.getConfig().isSignalHumanControlBeforeSetAtsControlOrCIAutoTrigger()) { + BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertNotTrue(signal.isCiControl(), String.format("信号机[%s]需处于人工控状态", signal.getCode())); + } + List routeList = signal.getRouteList(); + if (!CollectionUtils.isEmpty(routeList)) { + routeList.forEach(route -> route.setAtsControl(true)); + } + } + } + + /** + * 查询进路状态/模式 + */ + public List findRoutesStatus(Simulation simulation, String signalCode) { + Signal signal = simulation.getRepository().getByCode(signalCode, Signal.class); + List routeList = signal.getRouteList(); + return routeList.stream().map(RouteStatus::new).collect(Collectors.toList()); + } + + /** + * 设置联锁自动进路 + */ + public void setCiAuto(Simulation simulation, String signalCode) { + Signal signal = simulation.getRepository().getByCode(signalCode, Signal.class); + if (simulation.getRepository().getConfig().isSetRouteBeforeSetFlt()) { + Route lockedRoute = signal.getLockedRoute(); + if (lockedRoute == null) { + throw new SimulationException(SimulationExceptionType.Operation_Handle_FAIL, + String.format("信号机[%s(%s)]没有已锁闭进路,不能设置联锁自动进路", signal.getName(), signal.getCode())); + } + if (!lockedRoute.isFlt()) { + throw new SimulationException(SimulationExceptionType.Unsupported_Operation, + String.format("进路[%s]不能设置车队进路", lockedRoute.getCode())); + } + if (lockedRoute.isCiControl()) { + throw new SimulationException(SimulationExceptionType.Operation_Conflict, + String.format("进路[%s(%s)]自动追踪已开启,不能设置联锁自动进路", lockedRoute.getName(), lockedRoute.getCode())); + } + lockedRoute.setFleetMode(true); + } else { + List routeList = signal.getRouteList(); + BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertCollectionNotEmpty(routeList, signal.debugStr() + "不是进路始端信号机"); + // 筛选最适合的进路,筛选逻辑与办理引导时筛选逻辑类似 + List fltRoutes = routeList.stream().filter(Route::isFlt).collect(Collectors.toList()); + BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertCollectionNotEmpty(fltRoutes, signal.debugStr() + "下没有可设置的车队进路"); + List collect = fltRoutes.stream() + .filter(r -> !r.isTurnBack() && CollectionUtils.isEmpty(r.getSwitchList())) + .collect(Collectors.toList()); + if (CollectionUtils.isEmpty(collect)) { + collect = fltRoutes.stream().filter(r -> !r.isTurnBack()).collect(Collectors.toList()); + } + if (CollectionUtils.isEmpty(collect)) { + collect = fltRoutes; + } + Route route = collect.get(0); + route.setSettedAspect(route.getAspect()); + Route.CheckFailMessage message = routeService.setRoute(simulation, route); + BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertNull(message, route.debugStr() + "无法办理"); + route.setFleetMode(true); + } + } + + /** + * 取消联锁自动进路 + */ + public void cancelCiAuto(Simulation simulation, String signalCode) { + Signal signal = simulation.getRepository().getByCode(signalCode, Signal.class); + Route lockedRoute = signal.getLockedRoute(); + if (Objects.isNull(lockedRoute)) { + throw new SimulationException(SimulationExceptionType.Operation_Handle_FAIL, + String.format("信号机[%s(%s)]没有已锁闭进路,不能执行取消联锁自动进路", signal.getName(), signal.getCode())); + } + if (!lockedRoute.isFleetMode()) { + throw new SimulationException(SimulationExceptionType.Operation_Repetition, String.format("信号机[%s(%s)]没有打开连锁自动进路,不能取消联锁自动进路", signal.getName(), signal.getCode())); + } + lockedRoute.setFleetMode(false); + if (simulation.getRepository().getConfig().isCancelRouteWhenCancelFlt()) { + routeService.unlockRoute(simulation, lockedRoute); + } + } + + /** + * 设置联锁自动触发 + */ + public void setCiAutoTrigger(Simulation simulation, String signalCode, List routeCodeList) { + SimulationDataRepository repository = simulation.getRepository(); + List routeList; + if (StringUtils.hasText(signalCode)) { + Signal signal = repository.getByCode(signalCode, Signal.class); + if (repository.getConfig().isSignalHumanControlBeforeSetAtsControlOrCIAutoTrigger()) { + BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertNotTrue(signal.isAtsControl(), String.format("信号机[%s]需处于人工控", signal.getCode())); + } + routeList = signal.getRouteList(); + } else { + routeList = routeCodeList.stream() + .map(code -> repository.getByCode(code, Route.class)) + .collect(Collectors.toList()); + if (repository.getConfig().isSignalHumanControlBeforeSetAtsControlOrCIAutoTrigger()) { + routeList.stream() + .map(Route::getStart) + .distinct() + .forEach(signal -> + BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED + .assertNotTrue(signal.isAtsControl(), + String.format("信号机[%s]需处于人工控", signal.getCode()))); + } + } + if (!CollectionUtils.isEmpty(routeList)) { + routeList.stream().filter(Route::isArs).forEach(route -> { + if (route.isFleetMode()) { + throw new SimulationException(SimulationExceptionType.Operation_Conflict, + String.format("进路[%s(%s)]自动通过已开启,不能设置自动追踪", route.getName(), route.getCode())); + } +// if (route.isCiControl()) { +// throw new SimulationException(SimulationExceptionType.Operation_Repetition, String.format("进路[%s(%s)]自动追踪/连锁自动触发已开启,无需重复设置", route.getName(), route.getCode())); +// } + }); + for (Route route : routeList) { +// route.setAtsControl(false); + if (route.isArs()) + route.setCiControl(true); + } + } + } + + /** + * 取消联锁自动触发 + */ + public void cancelCiAutoTrigger(Simulation simulation, String signalCode, List routeCodes) { + List routeList; + SimulationDataRepository repository = simulation.getRepository(); + if (StringUtils.hasText(signalCode)) { + Signal signal = repository.getByCode(signalCode, Signal.class); + routeList = signal.getRouteList(); + } else { + routeList = routeCodes.stream() + .map(code -> repository.getByCode(code, Route.class)) + .collect(Collectors.toList()); + } + if (!CollectionUtils.isEmpty(routeList)) { + for (Route route : routeList) { + if (route.isCiControl()) { + route.setCiControl(false); + route.setAtsControl(false); + } + } + } + } + + /** + * 设置自动折返进路 + * + * @param simulation + * @param cycleCode + */ + public void setAutoTurnBack(Simulation simulation, String cycleCode) { + Cycle cycle = simulation.getRepository().getByCode(cycleCode, Cycle.class); + cycle.setSetUp(true); + } + + /** + * 取消自动折返进路 + */ + public void cancelAutoTurnBack(Simulation simulation, String cycleCode) { + Cycle cycle = simulation.getRepository().getByCode(cycleCode, Cycle.class); + cycle.setSetUp(false); + } + + /** + * 总取消 + */ + public void totalCancel(Simulation simulation, String signalCode) { + // todo 总取消操作有很多种操作方式,对应不同的按钮,此处都用信号机编号可能不妥 + Signal signal = simulation.getRepository().getByCode(signalCode, Signal.class); + Route lockedRoute = signal.getLockedRoute(); + if (lockedRoute == null) { + throw new SimulationException(SimulationExceptionType.Operation_Handle_FAIL, + String.format("信号机[%s(%s)]没有已锁闭进路,无需取消进路", signal.getName(), signal.getCode())); + } + if (!signal.isApproachLock()) { //当接近区段未被占用 + this.cancelRoute(simulation, signalCode); + } else { + this.routeService.unlockRoute(simulation, lockedRoute); + this.ciApiService.cancelFleetRoute(simulation, lockedRoute.getCode()); +// if (signal.isGuideAspect()) { //如果引导信号开启中 +// this.ciApiService.closeGuideSignal(simulation, signalCode); +// } else if (signal.isClose()) { //如果信号灯关了 +// } else { +// this.ciApiService.closeSignal(simulation, signalCode); +// } + } + } + + public void cancelRoute(Simulation simulation, String signalCode) { + Route route = this.ciApiService.findLockedRouteByStartSignal(simulation, signalCode); + if (Objects.nonNull(route)) { + BusinessExceptionAssertEnum.OPERATION_FAIL.assertNotTrue( + route.isApproachLock(), "进路接近锁闭,无法取消"); + BusinessExceptionAssertEnum.OPERATION_FAIL.assertNotTrue( + route.getStart().isGuideAspect(), "引导进路,需要人解进路"); + BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertNotTrue(route.isFleetMode(), + String.format("进路[%s]已开启自动通过进路,无法取消", route.debugStr())); + this.ciApiService.unlockRoute(simulation, route.getCode()); + } + } + + public void setOverlap(Simulation simulation, String signalCode, String overlapCode) { + if (signalCode == null || overlapCode == null) { + throw new SimulationException(SimulationExceptionType.Illegal_Argument); + } + this.ciApiService.setOverlap(simulation, signalCode, overlapCode); + } + + public void conflictRouteSetConfirm(Simulation simulation, SimulationMember member, String routeCode, int way) { + BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertTrue( + Route.Conflict_Handle_Way_1 == way || Route.Conflict_Handle_Way_2 == way + ); + Route route = simulation.getRepository().getByCode(routeCode, Route.class); + AtsAlarm conflictAlarm = route.getConflictAlarm(); + if (conflictAlarm != null) { + LocalDateTime systemTime = simulation.getCorrectSystemTime(); + conflictAlarm.confirm(systemTime, member, way); + conflictAlarm.recover(systemTime); + } + } +} diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/CI/CiApiServiceImpl2.java b/src/main/java/club/joylink/rtss/simulation/cbtc/CI/CiApiServiceImpl2.java index 5000ad0b8..120b948d5 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/CI/CiApiServiceImpl2.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/CI/CiApiServiceImpl2.java @@ -1,809 +1,813 @@ -package club.joylink.rtss.simulation.cbtc.CI; - -import club.joylink.rtss.exception.BusinessExceptionAssertEnum; -import club.joylink.rtss.simulation.cbtc.CI.device.*; -import club.joylink.rtss.simulation.cbtc.Simulation; -import club.joylink.rtss.simulation.cbtc.constant.SignalAspect; -import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository; -import club.joylink.rtss.simulation.cbtc.data.map.*; -import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealitySectionAxleCounter; -import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealitySignal; -import club.joylink.rtss.simulation.cbtc.device.virtual.VirtualRealityDeviceService; -import club.joylink.rtss.simulation.cbtc.exception.SimulationException; -import club.joylink.rtss.simulation.cbtc.exception.SimulationExceptionType; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import org.springframework.util.CollectionUtils; -import org.springframework.util.StringUtils; - -import java.time.LocalTime; -import java.util.*; -import java.util.stream.Collectors; - -/** - * CI子系统 - */ -@Slf4j -@Component -public class CiApiServiceImpl2 implements CiApiService { - @Autowired - private CiSwitchControlService switchService; - @Autowired - private CiSectionService sectionService; - @Autowired - private CiSignalControlService signalService; - @Autowired - private CiRouteService routeService; - @Autowired - private CiService ciService; - @Autowired - private CiStandService standService; - @Autowired - private VirtualRealityDeviceService virtualRealityDeviceService; - - - @Override - public void blockadeSection(Simulation simulation, String sectionCode) { - Section section = simulation.getRepository().getByCode(sectionCode, Section.class); - this.sectionService.blockade(section); - } - - @Override - public void unblockSection(Simulation simulation, String sectionCode) { - Section section = simulation.getRepository().getByCode(sectionCode, Section.class); - this.sectionService.unblock(section); - } - - @Override - public void blockadeSignal(Simulation simulation, String signalCode) { - Signal signal = simulation.getRepository().getByCode(signalCode, Signal.class); - this.signalService.blockade(simulation, signal); - } - - @Override - public void unblockSignal(Simulation simulation, String signalCode) { - Signal signal = simulation.getRepository().getByCode(signalCode, Signal.class); - this.signalService.unblock(signal); - } - - @Override - public void closeSignal(Simulation simulation, String signalCode) { - Signal signal = simulation.getRepository().getByCode(signalCode, Signal.class); - this.signalService.closeRoute(simulation, signal); - } - - @Override - public void reopenSignal(Simulation simulation, String signalCode) { - // 判断信号机是否是关闭状态、进路是否锁闭、联锁关系是否满足 - Signal signal = simulation.getRepository().getByCode(signalCode, Signal.class); - if (signal.isMainAspect()) { - throw new SimulationException(SimulationExceptionType.Operation_Handle_FAIL, - "信号机已经开启,无需重开信号机"); - } - Optional routeOptional = simulation.getRepository().getSettingRoutes().stream() - .filter(route -> route.getStart().equals(signal)).findAny(); - BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(routeOptional.isPresent(), "信号机不是已排进路的始端信号机"); -// settingRoute(simulation, routeOptional.get().getCode()); - Route lockedRoute = signal.getLockedRoute(); - if (Objects.isNull(lockedRoute)) { - throw new SimulationException(SimulationExceptionType.Operation_Handle_FAIL, - "进路未锁闭,不能重开信号机"); - } - BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(!lockedRoute.isDelayUnlocking(), "进路延时解锁中,不能重开"); - signal.setForbidden(false); - } - - @Override - public void turn(Simulation simulation, String switchCode) { - Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class); - if (!this.switchService.turn(simulation, aSwitch)) { - log.info(String.format("道岔[%s(%s)]锁闭,不能转动", aSwitch.getName(), aSwitch.getCode())); - throw new SimulationException(SimulationExceptionType.Operation_Handle_FAIL, "道岔锁闭,不能进行定操"); - } - if (Switch.SwitchFault.SPLIT_1.equals(aSwitch.getFault())) { - Switch.SwitchFault.SPLIT_1.fix(aSwitch); - } - } - - @Override - public void turn2NormalPosition(Simulation simulation, String switchCode) { - Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class); - if (!this.switchService.turn2NormalPosition(simulation, aSwitch)) { - log.info(String.format("道岔[%s(%s)]锁闭,不能进行定操", aSwitch.getName(), aSwitch.getCode())); - throw new SimulationException(SimulationExceptionType.Operation_Handle_FAIL, "道岔锁闭,不能进行定操"); - } - } - - @Override - public void turn2ReversePosition(Simulation simulation, String switchCode) { - Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class); - if (!this.switchService.turn2ReversePosition(simulation, aSwitch)) { - log.info(String.format("道岔[%s(%s)]锁闭,不能进行反操", aSwitch.getName(), aSwitch.getCode())); - throw new SimulationException(SimulationExceptionType.Operation_Handle_FAIL, "道岔锁闭,不能进行反操"); - } - } - - @Override - public void singleLockSwitch(Simulation simulation, String switchCode) { - Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class); - this.switchService.singleLock(aSwitch); - } - - @Override - public void singleUnlockSwitch(Simulation simulation, String switchCode) { - Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class); - this.switchService.singleUnlock(aSwitch); - } - - @Override - public void blockadeSwitch(Simulation simulation, String switchCode) { - Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class); - //条件检查 - MapConfig config = simulation.getRepository().getConfig(); - if (config.isBlockadeCommandOnlyValidInStandbyMode()) { - boolean standbyMode = simulation.getRepository().getRouteList() - .stream().filter(route -> route.isRouteSwitch(aSwitch)) - .anyMatch(route -> !route.getStart().isCbtcMode()); //包含该道岔的进路是否有处于后备模式的 - if (!standbyMode) { - return; - } - } -// if (config.isSomeCommandNeedInit()) { -// BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(aSwitch.isInit(), aSwitch.debugStr() + "未初始化"); -// } - - this.switchService.blockade(aSwitch); - } - - @Override - public void unblockSwitch(Simulation simulation, String switchCode) { - Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class); - this.switchService.unblock(aSwitch); - } - - @Override - public void blockadeSwitchSection(Simulation simulation, String switchCode) { - Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class); - this.switchService.blockade(aSwitch); - } - - @Override - public void unblockSwitchSection(Simulation simulation, String switchCode) { - Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class); - this.switchService.unblock(aSwitch); - } - - @Override - public Route.CheckFailMessage routeSettingCheck(Simulation simulation, String routeCode) { - Route route = simulation.getRepository().getByCode(routeCode, Route.class); - return this.routeService.routeSetCheck(simulation, route, false); - } - - @Override - public Route.CheckFailMessage settingRoute(Simulation simulation, String routeCode) { - Route route = simulation.getRepository().getByCode(routeCode, Route.class); - return this.routeService.setRoute(simulation, route); - } - - @Override - public void unlockRoute(Simulation simulation, String routeCode) { - Route route = simulation.getRepository().getByCode(routeCode, Route.class); - if (route.isTransferRoute() && simulation.getRepository().getConfig().isTransferRouteCanOnlyFaultUnlock()) { - throw BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.exception("转换轨进路只能通过区故解取消"); - } - if (simulation.getRepository().getConfig().isDelayWhenCancelRouteWithAbnormalInterlock()) { - if (this.ciService.isRouteSwitchLost(simulation, route)) { - this.routeService.delayUnlockStart(simulation, route, route.getStart()); - return; - } - } - this.routeService.unlockRoute(simulation, route); - } - - @Override - public void forceUnlockRoute(Simulation simulation, String routeCode) { - Route route = simulation.getRepository().getByCode(routeCode, Route.class); - BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertNotTrue(route.isFleetMode(), - String.format("进路[%s]已开启自动通过进路,无法取消", route.debugStr())); - this.routeService.unlockRoute(simulation, route); - } - - @Override - public void humanCancel(Simulation simulation, String routeCode) { - Route route = simulation.getRepository().getByCode(routeCode, Route.class); -// if (simulation.getRepository().getConfig().isRailway()) { -// BusinessExceptionAssertEnum.OPERATION_FAIL.assertTrue(route.isApproachLock(), -// "进路未接近锁闭,不能人解"); -// } - this.routeService.delayUnlockStart(simulation, route, route.getStart()); - } - - @Override - public void sectionFaultUnlock(Simulation simulation, String sectionCode) { - Section section = simulation.getRepository().getByCode(sectionCode, Section.class); - if (simulation.getRepository().getConfig().isSFUCanOnlyApplyForFaultLockSection()) { - if (!section.isFaultLock()) - return; - } - if (section.isCross()) { - Optional
crossLockedSectionOptional = section.getLogicList().stream().filter(Section::isLocked).findAny(); - if (crossLockedSectionOptional.isEmpty()) { - return; - } -// BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(crossLockedSectionOptional.isPresent(), -// section.debugStr() + "未锁闭,无需解锁"); - section = crossLockedSectionOptional.get(); - } - if (!section.isLocked()) { - return; - } -// BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(section.isLocked(), -// section.debugStr() + "未锁闭,无需解锁"); - List lockedRouteList = simulation.getRepository().queryAllLockedRoute(); - Route lockedRoute = null; - if (section.isRouteLock()) { - lockedRoute = section.getRoute(); - } else if (section.isOverlapLock()) { - for (Route route : lockedRouteList) { - if (route.overlapContainSection(section)) { - lockedRoute = route; - break; - } - } - } - if (lockedRoute != null && lockedRoute.isDelayUnlocking()) { - throw BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.exception("进路延时解锁中,不能区故解"); - } - this.routeService.sectionFaultUnlock(simulation, section, lockedRoute); - } - - @Override - public void switchSectionFaultUnlock(Simulation simulation, String switchCode) { - Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class); - if (!aSwitch.isLocked() && aSwitch.getAllSections().stream().noneMatch(Section::isLocked)) - return; - List lockedRouteList = simulation.getRepository().queryAllLockedRoute(); - Set lockSwitchRoutes = new HashSet<>(); - if (aSwitch.isRouteLock()) { - lockSwitchRoutes = aSwitch.getRoutes(); - } else if (aSwitch.isOverlapLock()) { - for (Route route : lockedRouteList) { - if (route.overlapContainSwitch(aSwitch)) { - lockSwitchRoutes.add(route); - break; - } - } - } - if (!lockSwitchRoutes.isEmpty()) { - for (Route lockedRoute : lockSwitchRoutes) { - this.routeService.switchFaultUnlock(simulation, aSwitch, lockedRoute); - } - } else { - aSwitch.faultUnlock(); - aSwitch.sectionFaultUnlock(); - } - } - - @Override - public void setFleetRoute(Simulation simulation, String routeCode) { - Route route = simulation.getRepository().getByCode(routeCode, Route.class); - this.routeService.setFleet(route); - } - - @Override - public void cancelFleetRoute(Simulation simulation, String routeCode) { - Route route = simulation.getRepository().getByCode(routeCode, Route.class); - this.routeService.cancelFleet(route); - } - - @Override - public void setCIAutoTriggerRoute(Simulation simulation, String routeCode) { - Route route = simulation.getRepository().getByCode(routeCode, Route.class); - this.routeService.setCIAutoTrigger(route); - } - - @Override - public void cancelCIAutoTriggerRoute(Simulation simulation, String routeCode) { - Route route = simulation.getRepository().getByCode(routeCode, Route.class); - this.routeService.cancelCIAutoTrigger(route); - } - - @Override - public Route findLockedRouteByStartSignal(Simulation simulation, String signalCode) { - Signal signal = simulation.getRepository().getByCode(signalCode, Signal.class); - return signal.getLockedRoute(); - } - - @Override - public Route findRouteByStartAndEndSignal(Simulation simulation, String startSignalCode, String endSignalCode) { - Signal start = simulation.getRepository().getByCode(startSignalCode, Signal.class); - List routeList = start.getRouteList(); - if (!CollectionUtils.isEmpty(routeList)) { - for (Route route : routeList) { - if (Objects.equals(route.getDestination().getCode(), endSignalCode)) { - return route; - } - } - } - return null; - } - - @Override - public void settingGuideRoute(Simulation simulation, String routeCode) { - Route route = simulation.getRepository().getByCode(routeCode, Route.class); - this.routeService.setGuide(simulation, route); - } - - @Override - public void openScreenDoor(Simulation simulation, String standCode, CiStandService.PsdCommandSource source) { - Stand stand = simulation.getRepository().getByCode(standCode, Stand.class); - if (Objects.nonNull(stand.getPsd())) { - standService.openScreenDoor(simulation, stand, source); - } - } - - @Override - public void closeScreenDoor(Simulation simulation, String standCode, CiStandService.PsdCommandSource source) { - Stand stand = simulation.getRepository().getByCode(standCode, Stand.class); - if (Objects.nonNull(stand.getPsd())) { - standService.closeScreenDoor(simulation, stand, source); - } - } - - @Override - public void standHoldTrain(Simulation simulation, String standCode, boolean center) { - Stand stand = simulation.getRepository().getByCode(standCode, Stand.class); - this.standService.holdTrain(simulation, stand, center); - } - - @Override - public void sysHoldTrain(Simulation simulation, String standCode) { - Stand stand = simulation.getRepository().getByCode(standCode, Stand.class); - this.standService.sysHoldTrain(simulation, stand); - } - - @Override - public void standHoldTrainCancel(Simulation simulation, String standCode, boolean center) { - Stand stand = simulation.getRepository().getByCode(standCode, Stand.class); - this.standService.cancelHoldTrain(simulation, stand, center); - } - - @Override - public void sysHoldTrainCancel(Simulation simulation, String standCode) { - Stand stand = simulation.getRepository().getByCode(standCode, Stand.class); - this.standService.cancelSysHoldTrain(simulation, stand); - } - - @Override - public void ibpHoldTrain(Simulation simulation, String standCode) { - Stand stand = simulation.getRepository().getByCode(standCode, Stand.class); - this.standService.ibpHoldTrain(simulation, stand); - } - - @Override - public void ibpHoldTrainCancel(Simulation simulation, String standCode) { - Stand stand = simulation.getRepository().getByCode(standCode, Stand.class); - this.standService.cancelIbpHoldTrain(simulation, stand); - } - - @Override - public void standHoldTrainCancelAll(Simulation simulation, String standCode) { - Stand stand = simulation.getRepository().getByCode(standCode, Stand.class); - this.standService.cancelAllHoldTrain(simulation, stand); - } - - /** - * 办理引导 - */ - @Override - public void setGuide(Simulation simulation, String signalCode, String routeCode) { - SimulationDataRepository repository = simulation.getRepository(); - MapConfig config = repository.getConfig(); - Signal signal; - Route route = null; - if (StringUtils.hasText(signalCode)) { - signal = repository.getByCode(signalCode, Signal.class); - } else if (StringUtils.hasText(routeCode)) { - route = repository.getByCode(routeCode, Route.class); - signal = route.getStart(); - } else { - throw BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.exception("signalCode和routeCode不能都为空"); - } - // 判断是否要进行进路判断,大铁可以不对进路判断 - boolean firstCheck = config.isRailway() ? false : config.isGuideNeedRouteSettingFirst(); - //条件检查 - if (firstCheck) { - List routeList = signal.getRouteList(); - BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertCollectionNotEmpty(routeList, String.format("信号机[%s]非进路始端信号机", signal.getCode())); - if (route != null) { - BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(route.isLock(), String.format("进路[%s]未办理", route.getCode())); - } else { - BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertNotNull(signal.getLockedRoute(), String.format("信号机[%s]无已办理进路", signal.getCode())); - } - } -// if (config.isSomeCommandNeedInit()) { -// BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(signal.isInit(), signal.debugStr() + "未初始化"); -// } - if (!simulation.getRepository().getConfig().isRailway()) { - BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(signal.isDefaultAspect(), - String.format("信号机[%s]需处于关闭状态", signal.getCode())); - } - boolean signalApproachOccupied = signal.getApproachPathList() - .stream().anyMatch(sectionPath -> sectionPath.getSectionList().stream().anyMatch(Section::isOccupied)); - if (config.isNeedApproachLockBeforeSetGuide()) { - BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(signalApproachOccupied, - String.format("对%s开放引导操作失败,接近区段没有列车占用", signal.getName())); - } - //办理引导进路或开放引导信号 - if (firstCheck) { - this.signalService.tryControlSignalAspectAccordingLevel(simulation, signal, signal.getSignalModel().getGuideAspect()); - } else { - if (route != null) { - if (route.isLock()) { - this.signalService.tryControlSignalAspectAccordingLevel(simulation, signal, signal.getSignalModel().getGuideAspect()); - } else { - this.routeService.setGuide(simulation, route); - } - } else { - if (signal.getLockedRoute() != null) { //如果有已锁闭进路 - this.signalService.tryControlSignalAspectAccordingLevel(simulation, signal, signal.getSignalModel().getGuideAspect()); - } else if (!CollectionUtils.isEmpty(signal.getRouteList())) { - List collect; - if (config.isRailway()) { // 大铁配置引导进路 -// collect = getCtcGuideRouteList(repository, signal); -// if (collect == null) { -// return; -// } - collect = signal.getRouteList().stream() - .filter(Route::isTrainRoute) - .filter(route1 -> !route1.hasReverseSwitch()) - .filter(route1 -> { - List switchList = route1.getSwitchList(); - if (!CollectionUtils.isEmpty(switchList)) { - return switchList.stream() - .allMatch(se -> se.isOnPosition() || se.getASwitch().isGuideMasterLock()); - } - return true; - }) //大铁直接办理引导进路需道岔在正确位置或道岔引导总锁 - .collect(Collectors.toList()); - BusinessExceptionAssertEnum.OPERATION_FAIL.assertCollectionNotEmpty(collect, - signal.debugStr() + "无符合条件的进路"); - } else { //如果signal锁闭进路为null,筛选最合适的进路(直线进路>分叉进路>折返进路) - collect = signal.getRouteList().stream() - .filter(r -> !r.isTurnBack() && CollectionUtils.isEmpty(r.getSwitchList())) - .collect(Collectors.toList()); - } - if (CollectionUtils.isEmpty(collect)) { - collect = signal.getRouteList().stream().filter(r -> !r.isTurnBack()).collect(Collectors.toList()); - } - if (CollectionUtils.isEmpty(collect)) { - collect = signal.getRouteList(); - } - route = collect.get(0); - this.routeService.setGuide(simulation, route); - } else { //如果信号机没有关联进路 - this.signalService.tryControlSignalAspectAccordingLevel(simulation, signal, signal.getSignalModel().getGuideAspect()); - } - } - } - if (repository.getConfig().isRailway() && signal.isHigherThanGuideLevel()) { - Route lockedRoute = signal.getLockedRoute(); - if (lockedRoute != null && lockedRoute.getFirstLogicSection().isOccupied()) { - signal.guideDelayStart(); - } - } - } - - - @Override - public void setEst(Simulation simulation, ESP esp) { - esp.update(true); - } - - @Override - public void cancelEst(Simulation simulation, ESP esp) { - esp.update(false); - } - - @Override - public void restart(Simulation simulation, Station station) { - Station deviceStation; - if (station.isCentralized()) { - deviceStation = station; - } else { - deviceStation = station.getDeviceStation(); - } - deviceStation.setInterlockMachineStarting(false); - SimulationDataRepository repository = simulation.getRepository(); - repository.getSectionList().forEach(section -> section.setFaultLock(false)); //所有区段取消故障锁闭 - } - - @Override - public void release(Simulation simulation, Station station) { - for (Section section : simulation.getRepository().getSectionList()) { - Integer speedLimitBeforeFault = section.getSpeedLimitBeforeFault(); - if (speedLimitBeforeFault != null) { - section.setSpeedUpLimit(speedLimitBeforeFault); - section.setSpeedLimitBeforeFault(null); - } - } - Server server = simulation.getRepository().getByCode(Server.CODE, Server.class); - Server.Fault.ATP_FAULT.fix(server); - } - - @Override - public void powerOnUnlock(Simulation simulation, Station station) { - if (!station.isCentralized()) { - station = station.getDeviceStation(); - } - Station deviceStation = station; - boolean restartFlag = Objects.nonNull(deviceStation.getRestartTime()) && deviceStation.getRestartTime().isBefore(LocalTime.now()); - // 是否大铁设备 - boolean hasCTCFlag = simulation.getRepository().getConfig().isRailway(); - // 大铁异常提示语 - String exceptionMsg = hasCTCFlag ? "无效操作:车站未下电" : "无效操作或连锁机重启过8分钟需手动解锁"; - // 是否需要重启 - if (restartFlag) { - // 考试、课程上电标识 - boolean powerOnFlag = ((Simulation.FunctionalType.LESSON.equals(simulation.getBuildParams().getFunctionalType()) - || Simulation.FunctionalType.EXAM.equals(simulation.getBuildParams().getFunctionalType())) - ? true : deviceStation.getRestartTime().plusMinutes(8).isAfter(LocalTime.now())); - if (hasCTCFlag || powerOnFlag) { - List
sections = simulation.getRepository().getSectionList(); - sections.stream().filter(section -> Objects.equals(section.getDeviceStation(), deviceStation)).forEach(Section::faultUnlock); - return; - } - } - throw BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.exception(exceptionMsg); - } - - @Override - public void standEC(Simulation simulation, Stand stand) { - if (stand.getEsp() == null) - return; - stand.getEsp().update(true); - } - - @Override - public void cancelStandEC(Simulation simulation, Stand stand) { - if (stand.getEsp() == null) - return; - stand.getEsp().update(false); - } - - @Override - public void switchForceTurn(Simulation simulation, String switchCode) { - Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class); - BusinessExceptionAssertEnum.SIMULATION_EXCEPTION_FOR_SHOW.assertTrue(!aSwitch.isLocked() && aSwitch.isSectionOccupied(), - String.format("对%s强行转岔操作被联锁逻辑取消", aSwitch.getName())); - BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(!aSwitch.isLocked(), String.format("道岔[%s]锁闭,无法转动", aSwitch.getCode())); - this.switchService.forceTurn(simulation, aSwitch); - } - - @Override - public void axlePreReset(Simulation simulation, String sectionCode) { - Section section = simulation.getRepository().getByCode(sectionCode, Section.class); - Section axleSection = section.findAxleCounterSection(); - //条件检查 - BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(axleSection != null && axleSection.isAxleCounter(), - section.debugStr() + "不是计轴区段也不归属于任何计轴区段"); - VirtualRealitySectionAxleCounter virtualAxleCounter = axleSection.getVirtualAxleCounter(); - if (!virtualAxleCounter.isOccupy()) { - VirtualRealitySectionAxleCounter.Fault.FAULT.apply(virtualAxleCounter); - Section.AxleFault.ARB.apply(axleSection); - } - virtualAxleCounter.preReset(); - } - - @Override - public void switchAxlePreReset(Simulation simulation, String switchCode) { - Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class); - aSwitch.setPreReset(true); - } - - @Override - public void switchSqueezeRecovery(Simulation simulation, String switchCode) { - Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class); - Switch.SwitchFault.SQUEEZE.fix(aSwitch); - } - - @Override - public void switchCommand(Simulation simulation, String switchCode, Boolean auto, Boolean reserve, Boolean normal) { - Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class); - if (auto != null) { - aSwitch.setAuto(auto); - } else { - if (normal != null) { - BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(!aSwitch.isAuto(), "道岔未处于人工模式"); - if (normal) { - switchService.turn2NormalPosition(simulation, aSwitch); - } else { - switchService.turn2ReversePosition(simulation, aSwitch); - } - } - } - if (reserve != null) { - aSwitch.setDispatcherReserve(reserve); - } - } - - @Override - public void initializeBlock(Simulation simulation, String switchCode) { - Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class); - aSwitch.setInit(true); - } - - @Override - public void initializeGuide(Simulation simulation, String signalCode) { - Signal signal = simulation.getRepository().getByCode(signalCode, Signal.class); - signal.setInit(true); - } - - @Override - public void cancelGuideInitialization(Simulation simulation, String signalCode) { - Signal signal = simulation.getRepository().getByCode(signalCode, Signal.class); - signal.setInit(false); - } - - @Override - public void axleReset(Simulation simulation, String sectionCode) { - VirtualRealitySectionAxleCounter axle = getAxleCounterAndCheck4Reset(simulation, sectionCode); - if (!axle.isOccupy()) - return; - axle.axleReset(); - } - - @Override - public void setOverlap(Simulation simulation, String signalCode, String overlapCode) { - SimulationDataRepository repository = simulation.getRepository(); - Signal signal = repository.getByCode(signalCode, Signal.class); - RouteOverlap overlap = repository.getByCode(overlapCode, RouteOverlap.class); - this.routeService.setOverlap(simulation, overlap); - } - - @Override - public void setOrCancelInterlockRelease(Simulation simulation, Stand stand, boolean release) { - standService.setOrCancelInterlockRelease(stand, release); - } - - @Override - public void switchMasterLock(Simulation simulation, String stationCode, Station.Throat throat) { - SimulationDataRepository repository = simulation.getRepository(); - Station station = repository.getByCode(stationCode, Station.class); - station.getDeviceMap().values().stream() - .filter(device -> device instanceof Switch) - .map(device -> (Switch) device) - .filter(aSwitch -> throat.equals(aSwitch.getThroat())) - .forEach(aSwitch -> { - aSwitch.setGuideMasterLock(true); - }); - switch (throat) { - case S: - station.setSGuideMasterLock(true); - break; - case X: - station.setXGuideMasterLock(true); - break; - default: - throw new IllegalStateException("Unexpected value: " + throat); - } - } - - @Override - public void switchMasterUnlock(Simulation simulation, String stationCode, Station.Throat throat) { - SimulationDataRepository repository = simulation.getRepository(); - Station station = repository.getByCode(stationCode, Station.class); - station.getDeviceMap().values().stream() - .filter(device -> device instanceof Switch) - .map(device -> (Switch) device) - .filter(aSwitch -> throat.equals(aSwitch.getThroat())) - .forEach(aSwitch -> aSwitch.setGuideMasterLock(false)); - switch (throat) { - case S: - station.setSGuideMasterLock(false); - break; - case X: - station.setXGuideMasterLock(false); - break; - default: - throw new IllegalStateException("Unexpected value: " + throat); - } - } - - @Override - public void signalTurnOn(Simulation simulation, String signalCode) { - SimulationDataRepository repository = simulation.getRepository(); - Signal signal = repository.getByCode(signalCode, Signal.class); - BusinessExceptionAssertEnum.OPERATION_FAIL.assertNull(signal.getLockedRoute(), "信号机有锁闭进路,禁止点灯"); - VirtualRealitySignal vrSignal = signal.getVirtualSignal(); - BusinessExceptionAssertEnum.OPERATION_FAIL.assertNotNull(vrSignal, signal.debugStr() + "无实体信号机"); - virtualRealityDeviceService.control(simulation, vrSignal, vrSignal.getModel().getDefaultAspect()); - } - - @Override - public void signalTurnOff(Simulation simulation, String signalCode) { - SimulationDataRepository repository = simulation.getRepository(); - Signal signal = repository.getByCode(signalCode, Signal.class); - BusinessExceptionAssertEnum.OPERATION_FAIL.assertNotTrue(signal.isShunting(), "调车信号机无法灭灯"); - BusinessExceptionAssertEnum.OPERATION_FAIL.assertNull(signal.getLockedRoute(), "信号机有锁闭进路,禁止灭灯"); - VirtualRealitySignal vrSignal = signal.getVirtualSignal(); - BusinessExceptionAssertEnum.OPERATION_FAIL.assertNotNull(vrSignal, signal.debugStr() + "无实体信号机"); - virtualRealityDeviceService.control(simulation, vrSignal, SignalAspect.No); - } - - /** - * 获取计轴器并为预复位/复位操作检查设备状态 - */ - private VirtualRealitySectionAxleCounter getAxleCounterAndCheck4Reset(Simulation simulation, String sectionCode) { - Section section = simulation.getRepository().getByCode(sectionCode, Section.class); - Section axleSection = section.findAxleCounterSection(); - //条件检查 - BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(axleSection != null && axleSection.isAxleCounter(), - section.debugStr() + "不是计轴区段也不归属于任何计轴区段"); - VirtualRealitySectionAxleCounter virtualAxleCounter = axleSection.getVirtualAxleCounter(); - if (simulation.getRepository().getConfig().isStationPreResetBeforeAxlePreReset()) { - Station deviceStation = axleSection.getDeviceStation(); - BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.assertNotNull(deviceStation, section.debugStr() + "没有所属集中站"); - BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(deviceStation.isPreReset(), deviceStation.debugStr() + "需处于预复位状态"); - } - return virtualAxleCounter; - } - - /** - * 大铁、办理引导时获取进路列表 - * - * @param repository 仿真实体 - * @param signal 信号机 - */ - private List getCtcGuideRouteList(SimulationDataRepository repository, Signal signal) { - // 获取以信号机开头的进路集合 - List routeList = repository.getRouteList().stream() - .filter(routePojo -> routePojo.isTrainRoute() && routePojo.getStart().getCode().equals(signal.getCode())) - .collect(Collectors.toList()); - // 进路走向 - boolean isRight = routeList.stream().anyMatch(Route::isRight); - // 终端信号机类型,信号机类型匹配时停止循环 - List endTypeList = Signal.SignalType.SHUNTING2.equals(signal.getType()) ? - Arrays.asList(Signal.SignalType.RECEIVING, Signal.SignalType.DEPARTURE) : Arrays.asList(Signal.SignalType.SHUNTING2); - // 终止索引,最多循环20次,防止死循环 - int endIndex = 0; - Section nextSection = signal.getSection(); - Signal endSignal; // 终端信号机 - do { - if (nextSection.isSwitchTrack()) { // 如果是计轴区段 - nextSection = nextSection.getNextRunningSectionOf(isRight); - } else { // 下一区段 - nextSection = nextSection.getNextSection(isRight); - } - if (nextSection == null) { // 道岔不连续不能办理进路,直接返回结果 - log.error("进路不连续"); - return null; - } - // 获取信号机 - if (isRight) { - endSignal = nextSection.getSignalToLeft(); - } else { - endSignal = nextSection.getSignalToRight(); - } - endIndex++; - } while (endIndex < 20 && !(endSignal != null && endTypeList.contains(endSignal.getType()))); - - // 过滤符合条件的进路 - if (endSignal != null && endIndex < 20) { - String endSignalCode = endSignal.getCode(); - routeList = routeList.stream() - .filter(routePojo -> routePojo.getDestination().getCode().equals(endSignalCode)) - .collect(Collectors.toList()); - } else { - // 如果是超过第限制停下,获取第endIndex个元素对比 - String routeSectionCode = nextSection.getCode(); - final int sectionIndex = endIndex; - routeList = routeList.stream() - .filter(routePojo -> routePojo.getSectionList().size() >= sectionIndex - && routePojo.getSectionList().get(sectionIndex).getCode().equals(routeSectionCode)) - .collect(Collectors.toList()); - } - return routeList; - } -} +package club.joylink.rtss.simulation.cbtc.CI; + +import club.joylink.rtss.exception.BusinessExceptionAssertEnum; +import club.joylink.rtss.simulation.cbtc.CI.device.*; +import club.joylink.rtss.simulation.cbtc.Simulation; +import club.joylink.rtss.simulation.cbtc.constant.SignalAspect; +import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository; +import club.joylink.rtss.simulation.cbtc.data.map.*; +import club.joylink.rtss.simulation.cbtc.data.map.Route.MultiRouteAspect; +import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealitySectionAxleCounter; +import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealitySignal; +import club.joylink.rtss.simulation.cbtc.device.virtual.VirtualRealityDeviceService; +import club.joylink.rtss.simulation.cbtc.exception.SimulationException; +import club.joylink.rtss.simulation.cbtc.exception.SimulationExceptionType; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +import java.time.LocalTime; +import java.util.*; +import java.util.stream.Collectors; + +/** + * CI子系统 + */ +@Slf4j +@Component +public class CiApiServiceImpl2 implements CiApiService { + @Autowired + private CiSwitchControlService switchService; + @Autowired + private CiSectionService sectionService; + @Autowired + private CiSignalControlService signalService; + @Autowired + private CiRouteService routeService; + @Autowired + private CiService ciService; + @Autowired + private CiStandService standService; + @Autowired + private VirtualRealityDeviceService virtualRealityDeviceService; + + + @Override + public void blockadeSection(Simulation simulation, String sectionCode) { + Section section = simulation.getRepository().getByCode(sectionCode, Section.class); + this.sectionService.blockade(section); + } + + @Override + public void unblockSection(Simulation simulation, String sectionCode) { + Section section = simulation.getRepository().getByCode(sectionCode, Section.class); + this.sectionService.unblock(section); + } + + @Override + public void blockadeSignal(Simulation simulation, String signalCode) { + Signal signal = simulation.getRepository().getByCode(signalCode, Signal.class); + this.signalService.blockade(simulation, signal); + } + + @Override + public void unblockSignal(Simulation simulation, String signalCode) { + Signal signal = simulation.getRepository().getByCode(signalCode, Signal.class); + this.signalService.unblock(signal); + } + + @Override + public void closeSignal(Simulation simulation, String signalCode) { + Signal signal = simulation.getRepository().getByCode(signalCode, Signal.class); + this.signalService.closeRoute(simulation, signal); + } + + @Override + public void reopenSignal(Simulation simulation, String signalCode) { + // 判断信号机是否是关闭状态、进路是否锁闭、联锁关系是否满足 + Signal signal = simulation.getRepository().getByCode(signalCode, Signal.class); + if (signal.isMainAspect()) { + throw new SimulationException(SimulationExceptionType.Operation_Handle_FAIL, + "信号机已经开启,无需重开信号机"); + } + Optional routeOptional = simulation.getRepository().getSettingRoutes().stream() + .filter(route -> route.getStart().equals(signal)).findAny(); + BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(routeOptional.isPresent(), "信号机不是已排进路的始端信号机"); +// settingRoute(simulation, routeOptional.get().getCode()); + Route lockedRoute = signal.getLockedRoute(); + if (Objects.isNull(lockedRoute)) { + throw new SimulationException(SimulationExceptionType.Operation_Handle_FAIL, + "进路未锁闭,不能重开信号机"); + } + BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(!lockedRoute.isDelayUnlocking(), "进路延时解锁中,不能重开"); + signal.setForbidden(false); + } + + @Override + public void turn(Simulation simulation, String switchCode) { + Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class); + if (!this.switchService.turn(simulation, aSwitch)) { + log.info(String.format("道岔[%s(%s)]锁闭,不能转动", aSwitch.getName(), aSwitch.getCode())); + throw new SimulationException(SimulationExceptionType.Operation_Handle_FAIL, "道岔锁闭,不能进行定操"); + } + if (Switch.SwitchFault.SPLIT_1.equals(aSwitch.getFault())) { + Switch.SwitchFault.SPLIT_1.fix(aSwitch); + } + } + + @Override + public void turn2NormalPosition(Simulation simulation, String switchCode) { + Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class); + if (!this.switchService.turn2NormalPosition(simulation, aSwitch)) { + log.info(String.format("道岔[%s(%s)]锁闭,不能进行定操", aSwitch.getName(), aSwitch.getCode())); + throw new SimulationException(SimulationExceptionType.Operation_Handle_FAIL, "道岔锁闭,不能进行定操"); + } + } + + @Override + public void turn2ReversePosition(Simulation simulation, String switchCode) { + Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class); + if (!this.switchService.turn2ReversePosition(simulation, aSwitch)) { + log.info(String.format("道岔[%s(%s)]锁闭,不能进行反操", aSwitch.getName(), aSwitch.getCode())); + throw new SimulationException(SimulationExceptionType.Operation_Handle_FAIL, "道岔锁闭,不能进行反操"); + } + } + + @Override + public void singleLockSwitch(Simulation simulation, String switchCode) { + Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class); + this.switchService.singleLock(aSwitch); + } + + @Override + public void singleUnlockSwitch(Simulation simulation, String switchCode) { + Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class); + this.switchService.singleUnlock(aSwitch); + } + + @Override + public void blockadeSwitch(Simulation simulation, String switchCode) { + Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class); + //条件检查 + MapConfig config = simulation.getRepository().getConfig(); + if (config.isBlockadeCommandOnlyValidInStandbyMode()) { + boolean standbyMode = simulation.getRepository().getRouteList() + .stream().filter(route -> route.isRouteSwitch(aSwitch)) + .anyMatch(route -> !route.getStart().isCbtcMode()); //包含该道岔的进路是否有处于后备模式的 + if (!standbyMode) { + return; + } + } +// if (config.isSomeCommandNeedInit()) { +// BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(aSwitch.isInit(), aSwitch.debugStr() + "未初始化"); +// } + + this.switchService.blockade(aSwitch); + } + + @Override + public void unblockSwitch(Simulation simulation, String switchCode) { + Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class); + this.switchService.unblock(aSwitch); + } + + @Override + public void blockadeSwitchSection(Simulation simulation, String switchCode) { + Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class); + this.switchService.blockade(aSwitch); + } + + @Override + public void unblockSwitchSection(Simulation simulation, String switchCode) { + Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class); + this.switchService.unblock(aSwitch); + } + + @Override + public Route.CheckFailMessage routeSettingCheck(Simulation simulation, String routeCode) { + Route route = simulation.getRepository().getByCode(routeCode, Route.class); + return this.routeService.routeSetCheck(simulation, route, false); + } + + @Override + public Route.CheckFailMessage settingRoute(Simulation simulation, String routeCode) { + Route route = simulation.getRepository().getByCode(routeCode, Route.class); + if(!route.isMultiRoute()) {//一般进路 + route.setSettedAspect(route.getAspect()); + } + return this.routeService.setRoute(simulation, route); + } + + @Override + public void unlockRoute(Simulation simulation, String routeCode) { + Route route = simulation.getRepository().getByCode(routeCode, Route.class); + if (route.isTransferRoute() && simulation.getRepository().getConfig().isTransferRouteCanOnlyFaultUnlock()) { + throw BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.exception("转换轨进路只能通过区故解取消"); + } + if (simulation.getRepository().getConfig().isDelayWhenCancelRouteWithAbnormalInterlock()) { + if (this.ciService.isRouteSwitchLost(simulation, route)) { + this.routeService.delayUnlockStart(simulation, route, route.getStart()); + return; + } + } + this.routeService.unlockRoute(simulation, route); + } + + @Override + public void forceUnlockRoute(Simulation simulation, String routeCode) { + Route route = simulation.getRepository().getByCode(routeCode, Route.class); + BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertNotTrue(route.isFleetMode(), + String.format("进路[%s]已开启自动通过进路,无法取消", route.debugStr())); + this.routeService.unlockRoute(simulation, route); + } + + @Override + public void humanCancel(Simulation simulation, String routeCode) { + Route route = simulation.getRepository().getByCode(routeCode, Route.class); +// if (simulation.getRepository().getConfig().isRailway()) { +// BusinessExceptionAssertEnum.OPERATION_FAIL.assertTrue(route.isApproachLock(), +// "进路未接近锁闭,不能人解"); +// } + this.routeService.delayUnlockStart(simulation, route, route.getStart()); + } + + @Override + public void sectionFaultUnlock(Simulation simulation, String sectionCode) { + Section section = simulation.getRepository().getByCode(sectionCode, Section.class); + if (simulation.getRepository().getConfig().isSFUCanOnlyApplyForFaultLockSection()) { + if (!section.isFaultLock()) + return; + } + if (section.isCross()) { + Optional
crossLockedSectionOptional = section.getLogicList().stream().filter(Section::isLocked).findAny(); + if (crossLockedSectionOptional.isEmpty()) { + return; + } +// BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(crossLockedSectionOptional.isPresent(), +// section.debugStr() + "未锁闭,无需解锁"); + section = crossLockedSectionOptional.get(); + } + if (!section.isLocked()) { + return; + } +// BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(section.isLocked(), +// section.debugStr() + "未锁闭,无需解锁"); + List lockedRouteList = simulation.getRepository().queryAllLockedRoute(); + Route lockedRoute = null; + if (section.isRouteLock()) { + lockedRoute = section.getRoute(); + } else if (section.isOverlapLock()) { + for (Route route : lockedRouteList) { + if (route.overlapContainSection(section)) { + lockedRoute = route; + break; + } + } + } + if (lockedRoute != null && lockedRoute.isDelayUnlocking()) { + throw BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.exception("进路延时解锁中,不能区故解"); + } + this.routeService.sectionFaultUnlock(simulation, section, lockedRoute); + } + + @Override + public void switchSectionFaultUnlock(Simulation simulation, String switchCode) { + Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class); + if (!aSwitch.isLocked() && aSwitch.getAllSections().stream().noneMatch(Section::isLocked)) + return; + List lockedRouteList = simulation.getRepository().queryAllLockedRoute(); + Set lockSwitchRoutes = new HashSet<>(); + if (aSwitch.isRouteLock()) { + lockSwitchRoutes = aSwitch.getRoutes(); + } else if (aSwitch.isOverlapLock()) { + for (Route route : lockedRouteList) { + if (route.overlapContainSwitch(aSwitch)) { + lockSwitchRoutes.add(route); + break; + } + } + } + if (!lockSwitchRoutes.isEmpty()) { + for (Route lockedRoute : lockSwitchRoutes) { + this.routeService.switchFaultUnlock(simulation, aSwitch, lockedRoute); + } + } else { + aSwitch.faultUnlock(); + aSwitch.sectionFaultUnlock(); + } + } + + @Override + public void setFleetRoute(Simulation simulation, String routeCode) { + Route route = simulation.getRepository().getByCode(routeCode, Route.class); + this.routeService.setFleet(route); + } + + @Override + public void cancelFleetRoute(Simulation simulation, String routeCode) { + Route route = simulation.getRepository().getByCode(routeCode, Route.class); + this.routeService.cancelFleet(route); + } + + @Override + public void setCIAutoTriggerRoute(Simulation simulation, String routeCode) { + Route route = simulation.getRepository().getByCode(routeCode, Route.class); + this.routeService.setCIAutoTrigger(route); + } + + @Override + public void cancelCIAutoTriggerRoute(Simulation simulation, String routeCode) { + Route route = simulation.getRepository().getByCode(routeCode, Route.class); + this.routeService.cancelCIAutoTrigger(route); + } + + @Override + public Route findLockedRouteByStartSignal(Simulation simulation, String signalCode) { + Signal signal = simulation.getRepository().getByCode(signalCode, Signal.class); + return signal.getLockedRoute(); + } + + @Override + public Route findRouteByStartAndEndSignal(Simulation simulation, String startSignalCode, String endSignalCode) { + Signal start = simulation.getRepository().getByCode(startSignalCode, Signal.class); + List routeList = start.getRouteList(); + if (!CollectionUtils.isEmpty(routeList)) { + for (Route route : routeList) { + if (Objects.equals(route.getDestination().getCode(), endSignalCode)) { + return route; + } + } + } + return null; + } + + @Override + public void settingGuideRoute(Simulation simulation, String routeCode) { + Route route = simulation.getRepository().getByCode(routeCode, Route.class); + this.routeService.setGuide(simulation, route); + } + + @Override + public void openScreenDoor(Simulation simulation, String standCode, CiStandService.PsdCommandSource source) { + Stand stand = simulation.getRepository().getByCode(standCode, Stand.class); + if (Objects.nonNull(stand.getPsd())) { + standService.openScreenDoor(simulation, stand, source); + } + } + + @Override + public void closeScreenDoor(Simulation simulation, String standCode, CiStandService.PsdCommandSource source) { + Stand stand = simulation.getRepository().getByCode(standCode, Stand.class); + if (Objects.nonNull(stand.getPsd())) { + standService.closeScreenDoor(simulation, stand, source); + } + } + + @Override + public void standHoldTrain(Simulation simulation, String standCode, boolean center) { + Stand stand = simulation.getRepository().getByCode(standCode, Stand.class); + this.standService.holdTrain(simulation, stand, center); + } + + @Override + public void sysHoldTrain(Simulation simulation, String standCode) { + Stand stand = simulation.getRepository().getByCode(standCode, Stand.class); + this.standService.sysHoldTrain(simulation, stand); + } + + @Override + public void standHoldTrainCancel(Simulation simulation, String standCode, boolean center) { + Stand stand = simulation.getRepository().getByCode(standCode, Stand.class); + this.standService.cancelHoldTrain(simulation, stand, center); + } + + @Override + public void sysHoldTrainCancel(Simulation simulation, String standCode) { + Stand stand = simulation.getRepository().getByCode(standCode, Stand.class); + this.standService.cancelSysHoldTrain(simulation, stand); + } + + @Override + public void ibpHoldTrain(Simulation simulation, String standCode) { + Stand stand = simulation.getRepository().getByCode(standCode, Stand.class); + this.standService.ibpHoldTrain(simulation, stand); + } + + @Override + public void ibpHoldTrainCancel(Simulation simulation, String standCode) { + Stand stand = simulation.getRepository().getByCode(standCode, Stand.class); + this.standService.cancelIbpHoldTrain(simulation, stand); + } + + @Override + public void standHoldTrainCancelAll(Simulation simulation, String standCode) { + Stand stand = simulation.getRepository().getByCode(standCode, Stand.class); + this.standService.cancelAllHoldTrain(simulation, stand); + } + + /** + * 办理引导 + */ + @Override + public void setGuide(Simulation simulation, String signalCode, String routeCode) { + SimulationDataRepository repository = simulation.getRepository(); + MapConfig config = repository.getConfig(); + Signal signal; + Route route = null; + if (StringUtils.hasText(signalCode)) { + signal = repository.getByCode(signalCode, Signal.class); + } else if (StringUtils.hasText(routeCode)) { + route = repository.getByCode(routeCode, Route.class); + signal = route.getStart(); + } else { + throw BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.exception("signalCode和routeCode不能都为空"); + } + // 判断是否要进行进路判断,大铁可以不对进路判断 + boolean firstCheck = config.isRailway() ? false : config.isGuideNeedRouteSettingFirst(); + //条件检查 + if (firstCheck) { + List routeList = signal.getRouteList(); + BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertCollectionNotEmpty(routeList, String.format("信号机[%s]非进路始端信号机", signal.getCode())); + if (route != null) { + BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(route.isLock(), String.format("进路[%s]未办理", route.getCode())); + } else { + BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertNotNull(signal.getLockedRoute(), String.format("信号机[%s]无已办理进路", signal.getCode())); + } + } +// if (config.isSomeCommandNeedInit()) { +// BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(signal.isInit(), signal.debugStr() + "未初始化"); +// } + if (!simulation.getRepository().getConfig().isRailway()) { + BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(signal.isDefaultAspect(), + String.format("信号机[%s]需处于关闭状态", signal.getCode())); + } + boolean signalApproachOccupied = signal.getApproachPathList() + .stream().anyMatch(sectionPath -> sectionPath.getSectionList().stream().anyMatch(Section::isOccupied)); + if (config.isNeedApproachLockBeforeSetGuide()) { + BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(signalApproachOccupied, + String.format("对%s开放引导操作失败,接近区段没有列车占用", signal.getName())); + } + //办理引导进路或开放引导信号 + if (firstCheck) { + this.signalService.tryControlSignalAspectAccordingLevel(simulation, signal, signal.getSignalModel().getGuideAspect()); + } else { + if (route != null) { + if (route.isLock()) { + this.signalService.tryControlSignalAspectAccordingLevel(simulation, signal, signal.getSignalModel().getGuideAspect()); + } else { + this.routeService.setGuide(simulation, route); + } + } else { + if (signal.getLockedRoute() != null) { //如果有已锁闭进路 + this.signalService.tryControlSignalAspectAccordingLevel(simulation, signal, signal.getSignalModel().getGuideAspect()); + } else if (!CollectionUtils.isEmpty(signal.getRouteList())) { + List collect; + if (config.isRailway()) { // 大铁配置引导进路 +// collect = getCtcGuideRouteList(repository, signal); +// if (collect == null) { +// return; +// } + collect = signal.getRouteList().stream() + .filter(Route::isTrainRoute) + .filter(route1 -> !route1.hasReverseSwitch()) + .filter(route1 -> { + List switchList = route1.getSwitchList(); + if (!CollectionUtils.isEmpty(switchList)) { + return switchList.stream() + .allMatch(se -> se.isOnPosition() || se.getASwitch().isGuideMasterLock()); + } + return true; + }) //大铁直接办理引导进路需道岔在正确位置或道岔引导总锁 + .collect(Collectors.toList()); + BusinessExceptionAssertEnum.OPERATION_FAIL.assertCollectionNotEmpty(collect, + signal.debugStr() + "无符合条件的进路"); + } else { //如果signal锁闭进路为null,筛选最合适的进路(直线进路>分叉进路>折返进路) + collect = signal.getRouteList().stream() + .filter(r -> !r.isTurnBack() && CollectionUtils.isEmpty(r.getSwitchList())) + .collect(Collectors.toList()); + } + if (CollectionUtils.isEmpty(collect)) { + collect = signal.getRouteList().stream().filter(r -> !r.isTurnBack()).collect(Collectors.toList()); + } + if (CollectionUtils.isEmpty(collect)) { + collect = signal.getRouteList(); + } + route = collect.get(0); + this.routeService.setGuide(simulation, route); + } else { //如果信号机没有关联进路 + this.signalService.tryControlSignalAspectAccordingLevel(simulation, signal, signal.getSignalModel().getGuideAspect()); + } + } + } + if (repository.getConfig().isRailway() && signal.isHigherThanGuideLevel()) { + Route lockedRoute = signal.getLockedRoute(); + if (lockedRoute != null && lockedRoute.getFirstLogicSection().isOccupied()) { + signal.guideDelayStart(); + } + } + } + + + @Override + public void setEst(Simulation simulation, ESP esp) { + esp.update(true); + } + + @Override + public void cancelEst(Simulation simulation, ESP esp) { + esp.update(false); + } + + @Override + public void restart(Simulation simulation, Station station) { + Station deviceStation; + if (station.isCentralized()) { + deviceStation = station; + } else { + deviceStation = station.getDeviceStation(); + } + deviceStation.setInterlockMachineStarting(false); + SimulationDataRepository repository = simulation.getRepository(); + repository.getSectionList().forEach(section -> section.setFaultLock(false)); //所有区段取消故障锁闭 + } + + @Override + public void release(Simulation simulation, Station station) { + for (Section section : simulation.getRepository().getSectionList()) { + Integer speedLimitBeforeFault = section.getSpeedLimitBeforeFault(); + if (speedLimitBeforeFault != null) { + section.setSpeedUpLimit(speedLimitBeforeFault); + section.setSpeedLimitBeforeFault(null); + } + } + Server server = simulation.getRepository().getByCode(Server.CODE, Server.class); + Server.Fault.ATP_FAULT.fix(server); + } + + @Override + public void powerOnUnlock(Simulation simulation, Station station) { + if (!station.isCentralized()) { + station = station.getDeviceStation(); + } + Station deviceStation = station; + boolean restartFlag = Objects.nonNull(deviceStation.getRestartTime()) && deviceStation.getRestartTime().isBefore(LocalTime.now()); + // 是否大铁设备 + boolean hasCTCFlag = simulation.getRepository().getConfig().isRailway(); + // 大铁异常提示语 + String exceptionMsg = hasCTCFlag ? "无效操作:车站未下电" : "无效操作或连锁机重启过8分钟需手动解锁"; + // 是否需要重启 + if (restartFlag) { + // 考试、课程上电标识 + boolean powerOnFlag = ((Simulation.FunctionalType.LESSON.equals(simulation.getBuildParams().getFunctionalType()) + || Simulation.FunctionalType.EXAM.equals(simulation.getBuildParams().getFunctionalType())) + ? true : deviceStation.getRestartTime().plusMinutes(8).isAfter(LocalTime.now())); + if (hasCTCFlag || powerOnFlag) { + List
sections = simulation.getRepository().getSectionList(); + sections.stream().filter(section -> Objects.equals(section.getDeviceStation(), deviceStation)).forEach(Section::faultUnlock); + return; + } + } + throw BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.exception(exceptionMsg); + } + + @Override + public void standEC(Simulation simulation, Stand stand) { + if (stand.getEsp() == null) + return; + stand.getEsp().update(true); + } + + @Override + public void cancelStandEC(Simulation simulation, Stand stand) { + if (stand.getEsp() == null) + return; + stand.getEsp().update(false); + } + + @Override + public void switchForceTurn(Simulation simulation, String switchCode) { + Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class); + BusinessExceptionAssertEnum.SIMULATION_EXCEPTION_FOR_SHOW.assertTrue(!aSwitch.isLocked() && aSwitch.isSectionOccupied(), + String.format("对%s强行转岔操作被联锁逻辑取消", aSwitch.getName())); + BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(!aSwitch.isLocked(), String.format("道岔[%s]锁闭,无法转动", aSwitch.getCode())); + this.switchService.forceTurn(simulation, aSwitch); + } + + @Override + public void axlePreReset(Simulation simulation, String sectionCode) { + Section section = simulation.getRepository().getByCode(sectionCode, Section.class); + Section axleSection = section.findAxleCounterSection(); + //条件检查 + BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(axleSection != null && axleSection.isAxleCounter(), + section.debugStr() + "不是计轴区段也不归属于任何计轴区段"); + VirtualRealitySectionAxleCounter virtualAxleCounter = axleSection.getVirtualAxleCounter(); + if (!virtualAxleCounter.isOccupy()) { + VirtualRealitySectionAxleCounter.Fault.FAULT.apply(virtualAxleCounter); + Section.AxleFault.ARB.apply(axleSection); + } + virtualAxleCounter.preReset(); + } + + @Override + public void switchAxlePreReset(Simulation simulation, String switchCode) { + Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class); + aSwitch.setPreReset(true); + } + + @Override + public void switchSqueezeRecovery(Simulation simulation, String switchCode) { + Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class); + Switch.SwitchFault.SQUEEZE.fix(aSwitch); + } + + @Override + public void switchCommand(Simulation simulation, String switchCode, Boolean auto, Boolean reserve, Boolean normal) { + Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class); + if (auto != null) { + aSwitch.setAuto(auto); + } else { + if (normal != null) { + BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(!aSwitch.isAuto(), "道岔未处于人工模式"); + if (normal) { + switchService.turn2NormalPosition(simulation, aSwitch); + } else { + switchService.turn2ReversePosition(simulation, aSwitch); + } + } + } + if (reserve != null) { + aSwitch.setDispatcherReserve(reserve); + } + } + + @Override + public void initializeBlock(Simulation simulation, String switchCode) { + Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class); + aSwitch.setInit(true); + } + + @Override + public void initializeGuide(Simulation simulation, String signalCode) { + Signal signal = simulation.getRepository().getByCode(signalCode, Signal.class); + signal.setInit(true); + } + + @Override + public void cancelGuideInitialization(Simulation simulation, String signalCode) { + Signal signal = simulation.getRepository().getByCode(signalCode, Signal.class); + signal.setInit(false); + } + + @Override + public void axleReset(Simulation simulation, String sectionCode) { + VirtualRealitySectionAxleCounter axle = getAxleCounterAndCheck4Reset(simulation, sectionCode); + if (!axle.isOccupy()) + return; + axle.axleReset(); + } + + @Override + public void setOverlap(Simulation simulation, String signalCode, String overlapCode) { + SimulationDataRepository repository = simulation.getRepository(); + Signal signal = repository.getByCode(signalCode, Signal.class); + RouteOverlap overlap = repository.getByCode(overlapCode, RouteOverlap.class); + this.routeService.setOverlap(simulation, overlap); + } + + @Override + public void setOrCancelInterlockRelease(Simulation simulation, Stand stand, boolean release) { + standService.setOrCancelInterlockRelease(stand, release); + } + + @Override + public void switchMasterLock(Simulation simulation, String stationCode, Station.Throat throat) { + SimulationDataRepository repository = simulation.getRepository(); + Station station = repository.getByCode(stationCode, Station.class); + station.getDeviceMap().values().stream() + .filter(device -> device instanceof Switch) + .map(device -> (Switch) device) + .filter(aSwitch -> throat.equals(aSwitch.getThroat())) + .forEach(aSwitch -> { + aSwitch.setGuideMasterLock(true); + }); + switch (throat) { + case S: + station.setSGuideMasterLock(true); + break; + case X: + station.setXGuideMasterLock(true); + break; + default: + throw new IllegalStateException("Unexpected value: " + throat); + } + } + + @Override + public void switchMasterUnlock(Simulation simulation, String stationCode, Station.Throat throat) { + SimulationDataRepository repository = simulation.getRepository(); + Station station = repository.getByCode(stationCode, Station.class); + station.getDeviceMap().values().stream() + .filter(device -> device instanceof Switch) + .map(device -> (Switch) device) + .filter(aSwitch -> throat.equals(aSwitch.getThroat())) + .forEach(aSwitch -> aSwitch.setGuideMasterLock(false)); + switch (throat) { + case S: + station.setSGuideMasterLock(false); + break; + case X: + station.setXGuideMasterLock(false); + break; + default: + throw new IllegalStateException("Unexpected value: " + throat); + } + } + + @Override + public void signalTurnOn(Simulation simulation, String signalCode) { + SimulationDataRepository repository = simulation.getRepository(); + Signal signal = repository.getByCode(signalCode, Signal.class); + BusinessExceptionAssertEnum.OPERATION_FAIL.assertNull(signal.getLockedRoute(), "信号机有锁闭进路,禁止点灯"); + VirtualRealitySignal vrSignal = signal.getVirtualSignal(); + BusinessExceptionAssertEnum.OPERATION_FAIL.assertNotNull(vrSignal, signal.debugStr() + "无实体信号机"); + virtualRealityDeviceService.control(simulation, vrSignal, vrSignal.getModel().getDefaultAspect()); + } + + @Override + public void signalTurnOff(Simulation simulation, String signalCode) { + SimulationDataRepository repository = simulation.getRepository(); + Signal signal = repository.getByCode(signalCode, Signal.class); + BusinessExceptionAssertEnum.OPERATION_FAIL.assertNotTrue(signal.isShunting(), "调车信号机无法灭灯"); + BusinessExceptionAssertEnum.OPERATION_FAIL.assertNull(signal.getLockedRoute(), "信号机有锁闭进路,禁止灭灯"); + VirtualRealitySignal vrSignal = signal.getVirtualSignal(); + BusinessExceptionAssertEnum.OPERATION_FAIL.assertNotNull(vrSignal, signal.debugStr() + "无实体信号机"); + virtualRealityDeviceService.control(simulation, vrSignal, SignalAspect.No); + } + + /** + * 获取计轴器并为预复位/复位操作检查设备状态 + */ + private VirtualRealitySectionAxleCounter getAxleCounterAndCheck4Reset(Simulation simulation, String sectionCode) { + Section section = simulation.getRepository().getByCode(sectionCode, Section.class); + Section axleSection = section.findAxleCounterSection(); + //条件检查 + BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(axleSection != null && axleSection.isAxleCounter(), + section.debugStr() + "不是计轴区段也不归属于任何计轴区段"); + VirtualRealitySectionAxleCounter virtualAxleCounter = axleSection.getVirtualAxleCounter(); + if (simulation.getRepository().getConfig().isStationPreResetBeforeAxlePreReset()) { + Station deviceStation = axleSection.getDeviceStation(); + BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.assertNotNull(deviceStation, section.debugStr() + "没有所属集中站"); + BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(deviceStation.isPreReset(), deviceStation.debugStr() + "需处于预复位状态"); + } + return virtualAxleCounter; + } + + /** + * 大铁、办理引导时获取进路列表 + * + * @param repository 仿真实体 + * @param signal 信号机 + */ + private List getCtcGuideRouteList(SimulationDataRepository repository, Signal signal) { + // 获取以信号机开头的进路集合 + List routeList = repository.getRouteList().stream() + .filter(routePojo -> routePojo.isTrainRoute() && routePojo.getStart().getCode().equals(signal.getCode())) + .collect(Collectors.toList()); + // 进路走向 + boolean isRight = routeList.stream().anyMatch(Route::isRight); + // 终端信号机类型,信号机类型匹配时停止循环 + List endTypeList = Signal.SignalType.SHUNTING2.equals(signal.getType()) ? + Arrays.asList(Signal.SignalType.RECEIVING, Signal.SignalType.DEPARTURE) : Arrays.asList(Signal.SignalType.SHUNTING2); + // 终止索引,最多循环20次,防止死循环 + int endIndex = 0; + Section nextSection = signal.getSection(); + Signal endSignal; // 终端信号机 + do { + if (nextSection.isSwitchTrack()) { // 如果是计轴区段 + nextSection = nextSection.getNextRunningSectionOf(isRight); + } else { // 下一区段 + nextSection = nextSection.getNextSection(isRight); + } + if (nextSection == null) { // 道岔不连续不能办理进路,直接返回结果 + log.error("进路不连续"); + return null; + } + // 获取信号机 + if (isRight) { + endSignal = nextSection.getSignalToLeft(); + } else { + endSignal = nextSection.getSignalToRight(); + } + endIndex++; + } while (endIndex < 20 && !(endSignal != null && endTypeList.contains(endSignal.getType()))); + + // 过滤符合条件的进路 + if (endSignal != null && endIndex < 20) { + String endSignalCode = endSignal.getCode(); + routeList = routeList.stream() + .filter(routePojo -> routePojo.getDestination().getCode().equals(endSignalCode)) + .collect(Collectors.toList()); + } else { + // 如果是超过第限制停下,获取第endIndex个元素对比 + String routeSectionCode = nextSection.getCode(); + final int sectionIndex = endIndex; + routeList = routeList.stream() + .filter(routePojo -> routePojo.getSectionList().size() >= sectionIndex + && routePojo.getSectionList().get(sectionIndex).getCode().equals(routeSectionCode)) + .collect(Collectors.toList()); + } + return routeList; + } +} diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/CI/CiLogic.java b/src/main/java/club/joylink/rtss/simulation/cbtc/CI/CiLogic.java index f5658514e..b074f1069 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/CI/CiLogic.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/CI/CiLogic.java @@ -33,7 +33,6 @@ public class CiLogic { private StationDirectionService stationDirectionService; public void run(Simulation simulation) { - // 采集真实设备状态 deviceStatusCollector.collect(simulation); // 信号机监控控制 @@ -119,6 +118,7 @@ public class CiLogic { MapConfig config = simulation.getRepository().getConfig(); if (route.isCiControl()) { // 进路联锁自动触发 if (!route.isLock() && !route.isSetting() && ciService.isCiRouteTrigger(simulation, route)) { + route.setSettedAspect(route.getAspect()); routeService.setRoute(simulation, route); } } else if (route.isFleetMode()) { // 联锁自动进路 diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/CI/device/CiRouteService.java b/src/main/java/club/joylink/rtss/simulation/cbtc/CI/device/CiRouteService.java index 264a323b4..c9e9f78f8 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/CI/device/CiRouteService.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/CI/device/CiRouteService.java @@ -1,735 +1,737 @@ -package club.joylink.rtss.simulation.cbtc.CI.device; - -import club.joylink.rtss.exception.BusinessExceptionAssertEnum; -import club.joylink.rtss.simulation.cbtc.Simulation; -import club.joylink.rtss.simulation.cbtc.constant.SignalAspect; -import club.joylink.rtss.simulation.cbtc.constant.SimulationConstants; -import club.joylink.rtss.simulation.cbtc.constant.SimulationModule; -import club.joylink.rtss.simulation.cbtc.constant.SwitchIndication; -import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository; -import club.joylink.rtss.simulation.cbtc.data.map.*; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import org.springframework.util.CollectionUtils; - -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; - -@Slf4j -@Component -public class CiRouteService { - @Autowired - private CiSwitchControlService switchControlService; - @Autowired - private CiSignalControlService signalControlService; - @Autowired - private CiService ciService; - - /** - * 进路排列检查 - * @param guide 是引导进路? - * @return - */ - public static Route.CheckFailMessage routeSetCheck(Simulation simulation, Route route, boolean guide) { - if (!CollectionUtils.isEmpty(route.getMultiRouteAspects())) { - for (Route.MultiRouteAspect multiRouteAspect : route.getMultiRouteAspects()) { - Route.CheckFailMessage checkFailMessage = routeSetCheck(simulation, multiRouteAspect.getRoute(), false); - if (checkFailMessage != null) { - return checkFailMessage; - } - } - } else { - MapConfig config = simulation.getRepository().getConfig(); - Signal start = route.getStart(); - if (!config.isSignalBlockRouteSettable()) { - // 信号封锁,不能办理 - if (start.isBlockade()) { - return new Route.CheckFailMessage(Route.CheckFailReason.StartSignalBlockade, start); - } - } - // 进路中道岔没有被征用或锁定在相反位置 - Route.CheckFailMessage failMessage = setSwitchCheck(simulation, route.getSwitchList(), guide); - if (failMessage != null) { - return failMessage; - } - // 进路中道岔是否存在和监控中进路延续保护冲突 - failMessage = monitorRouteOverlapConflictCheck(simulation, route); - if (failMessage != null) { - return failMessage; - } - // 进路内区段封锁/锁闭方向检查 - List
sectionList = route.getSectionList(); - for (Section section : sectionList) { - // 封锁状态 - if (section.isBlockade()) { - return new Route.CheckFailMessage(Route.CheckFailReason.SectionBlockade, section); - } else if (!CollectionUtils.isEmpty(section.getLogicList())) { - for (Section logicSection : section.getLogicList()) { - if (logicSection.isBlockade()) { - return new Route.CheckFailMessage(Route.CheckFailReason.SectionBlockade, logicSection); - } - } - } else if (section.getParent() != null) { - if (section.getParent().isCross() && section.getParent().isBlockade()) { - return new Route.CheckFailMessage(Route.CheckFailReason.SectionBlockade, section); - } - } - // 进路内区段锁闭方向不是此进路方向 - if ((section.isRouteLock() || section.isOverlapLock()) && - !Objects.equals(section.isLockRight(), start.isRight())) { - return new Route.CheckFailMessage(Route.CheckFailReason.SectionLockOppositeDirection, section); - } - // 故障占用 - for (int i = 0; i < 3; i++) { - if (section.getParent() == null || section.isAxleCounter()) - break; - section = section.getParent(); - } - if (Section.AxleFault.FAULT.equals(section.getFault())) { - return new Route.CheckFailMessage(Route.CheckFailReason.SectionFaultOccupied, section); - } - } - //敌对进路 - List conflictingRouteList = route.getConflictingRouteList(); - for (Route conflict : conflictingRouteList) { - if (conflict.isSetting() || conflict.isLock()) { - return new Route.CheckFailMessage(Route.CheckFailReason.ConflictingRouteSetting, conflict); - } - } - if (start.isCbtcMode()) { - // CBTC办理检查 - Section firstLogicSection = route.getFirstLogicSection(); - if (firstLogicSection.isOccupied()) { - return new Route.CheckFailMessage(Route.CheckFailReason.SectionNotFree, firstLogicSection); - } - } else { - // 后备办理检查 - // 区段占用 - for (Section section : sectionList) { - if (section.isOccupied()) { - return new Route.CheckFailMessage(Route.CheckFailReason.SectionNotFree, section); - } - } - // 延续保护检查 - RouteOverlap overlap = route.getOverlap(); - if (Objects.nonNull(overlap)) { - SectionPath sectionPath = overlap.selectPath(); - failMessage = setSwitchCheck(simulation, sectionPath.getSwitchList(), guide); - } - } - return failMessage; - } - return null; - } - - private static Route.CheckFailMessage monitorRouteOverlapConflictCheck(Simulation simulation, Route route) { - SimulationDataRepository repository = simulation.getRepository(); - List settingRoutes = repository.getSettingRoutes(); - for (Route sr : settingRoutes) { - if (sr.isSettingOverlap() && (sr.getOverlap().isSetting() || sr.getOverlap().isLock())/*&& !repository.isTrainParking(sr.getOverlap().getSection())*/) { - SectionPath sectionPath = sr.getOverlap().selectPath(); - for (SwitchElement switchElement : sectionPath.getSwitchList()) { - if (route.isConflictSwitch(switchElement)) { - return new Route.CheckFailMessage(Route.CheckFailReason.SwitchCiUseOnOppositePosition, - switchElement.getASwitch()); - } - } - } - } - return null; - } - - private static Route.CheckFailMessage setSwitchCheck(Simulation simulation, List switchList, boolean guide) { - if (switchList != null) { - for (SwitchElement switchElement : switchList) { - Switch aSwitch = switchElement.getASwitch(); - if (aSwitch.isBlockade()) { // 道岔封锁 - return new Route.CheckFailMessage(Route.CheckFailReason.SwitchBlockade, aSwitch); - } - if (!guide && aSwitch.isGuideMasterLock()) { - return new Route.CheckFailMessage(Route.CheckFailReason.SwitchGuideMasterLock, aSwitch); - } - if ((aSwitch.isLocked() || aSwitch.isSectionOccupied()) && - aSwitch.getPos().equals(SwitchIndication.of(!switchElement.isNormal()))) {//道岔锁闭或占用在相反位置 - return new Route.CheckFailMessage(Route.CheckFailReason.SwitchLockPositionError, aSwitch); - } - if (aSwitch.isCiUseOnOppositePosition(switchElement.isNormal())) { // 道岔征用在相反位置 - return new Route.CheckFailMessage(Route.CheckFailReason.SwitchCiUseOnOppositePosition, aSwitch); - } - // 非预先锁闭,道岔相应位置失表则不排进路 - if (!simulation.getRepository().getConfig().isLockFirst() && aSwitch.isLoss()) { - if ((Switch.SwitchFault.NORMAL_SPLIT.equals(aSwitch.getFault()) && switchElement.isNormal()) - || (Switch.SwitchFault.REVERSE_SPLIT.equals(aSwitch.getFault()) && !switchElement.isNormal())) { - return new Route.CheckFailMessage(Route.CheckFailReason.SwitchFault, aSwitch); - } - } - } - } - return null; - } - - /** - * 排列引导进路 - */ - public void setGuide(Simulation simulation, Route route) { - // 进路检查 - Route.CheckFailMessage failMessage = routeSetCheck(simulation, route, true); - if (failMessage == null) { - if (route.isLock() && !route.isFleetMode()) { - log.info("进路[{}]已经锁闭", route.debugStr()); - return; - } - // 引导进路开始办理 - LocalDateTime systemTime = simulation.getSystemTime(); - route.startGuideSetting(systemTime); - // 道岔征用 - for (SwitchElement switchElement : route.getSwitchList()) { - switchElement.getASwitch().ciUse(switchElement.isNormal()); - } - simulation.getRepository().addSettingRoute(route); - } - if (Objects.nonNull(failMessage)) { - log.info(String.format("进路[%s]排列检查失败,无法排列:%s", route.debugStr(), failMessage.debugStr())); - } - } - - /** - * 排列进路 - * - * @param simulation - * @param route - * @return - */ - public Route.CheckFailMessage setRoute(Simulation simulation, Route route) { - Route.CheckFailMessage failMessage = routeSetCheck(simulation, route, false); - if (failMessage == null) { - if (route.isLock() && !route.isFleetMode()) { - log.info("进路[{}]已经锁闭", route.debugStr()); - return null; - } - // 进路开始办理 - LocalDateTime systemTime = simulation.getSystemTime(); - route.startSetting(systemTime); - // 道岔征用 - for (SwitchElement switchElement : route.getSwitchList()) { - switchElement.getASwitch().ciUse(switchElement.isNormal()); - } - // 延续保护进路办理 - this.ciService.checkAndTrySettingOverlap(simulation, route.getOverlap()); - simulation.getRepository().addSettingRoute(route); - } - if (Objects.nonNull(failMessage)) { - log.info(String.format("进路[%s]排列检查失败,无法排列:%s", route.debugStr(), failMessage.debugStr())); - } - return failMessage; - } - - /** - * 排列进路过程控制 - * - * @param simulation - * @param route - */ - public void routeSettingProcess(Simulation simulation, Route route) { - if (route.isSetting()) { // 进路排列中 - MapConfig config = simulation.getRepository().getConfig(); - if (!config.isRouteSettingNoFail()) { - if (simulation.getSystemTime().isAfter(route.getSettingStartTime().plusSeconds(SimulationConstants.ROUTE_SETTING_TIMEOUT))) { - log.info("进路[{}]办理超时,取消办理2", route.debugStr()); - route.settingOver(); - return; - } - } - List multiRouteAspects = route.getMultiRouteAspects(); - if (CollectionUtils.isEmpty(multiRouteAspects)) { - // 道岔位置转换 - boolean mainRouteSwitchOnPos = this.switchControlService.ensureSwitchPosCurrent(simulation, route.getSwitchList(), route.isGuideSetting()); - // 预先锁闭 - if (mainRouteSwitchOnPos || config.isLockFirst()) { - // 进路排列区段预先锁闭 - this.checkAndLockRouteMain(route, config.isRailway()); - } - // 侧防办理 - this.flsSetting(simulation, route.getFlsList()); - // 检查信号开放条件,开信号 - this.ciService.interlockCheck(simulation, route); - SignalAspect aspect = null; - boolean routeRight = route.isRight(); - if (route.isGuideSetting()) { - aspect = route.getStart().getGuideAspect(); - } else if (route.getStart().isBlockade()) { - aspect = route.getStart().getDefaultAspect(); - } else { - aspect = route.getAspect(); - if (config.isRailway() && route.isDepartureRoute()) { - aspect = route.getAspectOfRailway(); - } - } - this.signalControlService.tryControlSignalAspectAccordingLevel(simulation, route.getStart(), aspect); - if (config.isRailway()) { - if (route.isGuideSetting() && route.getStart().isGuideAspect() - || !route.getStart().isDefaultAspect()) { - route.settingOver(); - } - } else if ((route.getAspect().equals(route.getStart().getAspect())) || - (route.isGuideSetting() && route.getStart().isGuideAspect())) { - log.debug("进路[{}]信号开放,办理结束", route.debugStr()); - route.settingOver(); - } - } else { - //由远及近办理进路 - for (int i = multiRouteAspects.size() - 1; i >= 0; i--) { - Route.MultiRouteAspect routeAspect = multiRouteAspects.get(i); - Route subRoute = routeAspect.getRoute(); - if (!subRoute.isLock()) { - setRoute(simulation, subRoute); - break; - } - } - //最近的一条进路已经锁闭 - if (multiRouteAspects.get(0).getRoute().isLock()) { // - route.settingOver(); - } - } - } - } - - private void flsSetting(Simulation simulation, List flsList) { - // 侧防道岔转换 - if (!CollectionUtils.isEmpty(flsList)) { - for (RouteFls routeFls : flsList) { - List level1List = routeFls.getLevel1List(); - for (RouteFls.FlsElement flsElement : level1List) { - SwitchElement pSwitch = flsElement.getPSwitch(); - if (pSwitch != null) { - boolean onPos = this.switchControlService.turnRouteSwitch(simulation, pSwitch); - if (onPos) { - pSwitch.getASwitch().fpLock(); - } - } - } - } - } - } - - /** - * 检查并锁闭主进路(不包含侧防和延续保护) - * - * @param route - * @param railway - */ - private void checkAndLockRouteMain(Route route, boolean railway) { - boolean right = route.isRight(); - List
sectionList = route.getSectionList(); - List switchList = route.getSwitchList(); - for (SwitchElement switchElement : switchList) { - if (switchElement.isOnPosition() || (route.isGuideSetting() && switchElement.getASwitch().isGuideMasterLock())) { - switchElement.getASwitch().routeLock(route); - } - } - for (Section section : sectionList) { - //大铁引导进路只锁闭指定区段(为了解决引导总锁方式办理道岔失表的引导进路时,失表道岔的所有区段都锁闭的问题) - if (section.isSwitchTrack() && !(railway && route.isGuideSetting())) { - Switch relSwitch = section.getRelSwitch(); - relSwitch.sectionRouteLocking(route, right); - } else { - section.routeLocking(route, right); - } - } - route.setLock(true); - } - - /** - * 解锁进路 - * - * @param simulation - * @param route - */ - public void unlockRoute(Simulation simulation, Route route) { - // 取消自动进路 - this.cancelFleet(route); - // 关闭始端信号机 - this.signalControlService.tryControlSignalAspectAccordingLevel(simulation, - route.getStart(), route.getStart().getDefaultAspect()); - log.debug(String.format("取消进路,信号机[%s(%s)]关灯", - route.getStart().getName(), route.getStart().getCode())); - //进路解锁 - route.setLock(false); - route.setSetting(false); - route.setAtsControl(false); - // 始端信号机锁闭进路置为null - route.getStart().setLockedRoute(null); - route.getStart().setLevel(Signal.LEVEL_Close); - simulation.getRepository().removeSettingRoute(route); - // 进路区段取消锁闭 - List
sectionList = route.getSectionList(); - for (Section section : sectionList) { - if (section.isOccupied() && !section.isFaultOccupied()) { // 区段列车占用 - route.startNormalUnlock(); - route.updateUnlockedSection(section); - return; - } - if (section.isSwitchTrack()) { - //解锁道岔 - Switch relSwitch = section.getRelSwitch(); - relSwitch.routeUnlock(route); - //解锁道岔侧防 - RouteFls routeFls = route.queryRouteFlsOfSwitch(relSwitch); - if (routeFls != null) { - routeFls.unlock(); - } - //解锁联动道岔 - Switch linkedSwitch = relSwitch.queryLinkedSwitch(); - if (linkedSwitch != null) { - linkedSwitch.routeUnlock(route); - } - } else { - section.routeUnlocking(route); - } - } - // 进路延续保护解锁 - RouteOverlap overlap = route.getOverlap(); - if (Objects.nonNull(overlap)) { - overlap.releaseImmediately(); - log.debug(overlap.debugStr() + "因取消进路解锁"); - } - } - - public void delayUnlockStart(Simulation simulation, Route route, DelayUnlockDevice device) { - device.delayUnlockStart(route); - route.setDelayUnlockDevice(device); - this.signalControlService.tryControlSignalAspectAccordingLevel(simulation, route.getStart(), route.getStart().getDefaultAspect()); - } - - /** - * 延时解锁进路 - * - * @param simulation - * @param route - */ - public void delayUnlocking(Simulation simulation, Route route, DelayUnlockDevice device) { - if (device.countAndCheckFinish(SimulationModule.CI.getRateMs())) { - // 延时结束,执行解锁 - if (device instanceof Signal) { - // 解锁整条进路 - this.unlockRoute(simulation, route); - } else if (device instanceof Switch) { - Switch aSwitch = (Switch) device; - this.faultUnlock(simulation, route, aSwitch); - } else if (device instanceof Section) { - ((Section) device).faultUnlock(); - } - route.setLock(false); - route.setDelayUnlockDevice(null); - } - } - - private void faultUnlock(Simulation simulation, Route route, Switch aSwitch) { - aSwitch.faultUnlock(); - aSwitch.sectionFaultUnlock(); - if (route != null) { - route.unlockRouteFlsOfSwitch(aSwitch); //进路中该道岔对应的侧防解除锁闭 - RouteOverlap overlap = route.getOverlap(); - if (overlap != null) { - for (SectionPath sectionPath : overlap.getPathList()) { - overlap.unlockFlsOfSwitch(sectionPath.getFlsList(), aSwitch); //延续保护中该道岔的侧防解除锁闭 - } - } - } - } - - /** - * 道岔区段故障解锁 - * - * @param simulation - * @param aSwitch - * @param route - */ - public void switchFaultUnlock(Simulation simulation, Switch aSwitch, Route route) { - if (route != null) { - if (route.isApproachLock() || aSwitch.isOverlapLock()) { - // 延时解锁 - this.delayUnlockStart(simulation, route, aSwitch); - return; - } else { - route.setLock(false); - } - } - this.faultUnlock(simulation, route, aSwitch); - } - - /** - * 区故解 - */ - public void sectionFaultUnlock(Simulation simulation, Section section, Route route) { - if (route != null) { - if (route.getStart().isApproachLock() - || section.isOverlapLock() - || route.getSectionList().stream().anyMatch(Section::isOccupied)) { - // 区段延时解锁 - this.delayUnlockStart(simulation, route, section); - return; - } else { - if (route.isOpenMain() || route.isOpenGuide()) { - this.signalControlService.tryControlSignalAspectAccordingLevel(simulation, route.getStart(), - route.getStart().getDefaultAspect()); - } - route.setLock(false); - } - } - section.faultUnlock(); - if (section.isShowLogic()) { - section.getLogicList().forEach(Section::faultUnlock); - } - } - - /** - * 列车逐段解锁进路 - * - * @param simulation - * @param route - */ - public void trainUnlockRoute(Simulation simulation, Route route) { - if (!route.isNormalUnlock()) { - return; - } - if (!route.isFleetMode()) { // 连续通过进路不解锁,非连续通过进路随最后一辆车的运行而解锁 - boolean right = route.getStart().isRight(); - // 区段是顺序的(否则会有问题) - boolean allUnlock = true; - if (Objects.isNull(route.getUnlockedSection())) { - log.error(String.format("进路[%s(%s)]正常解锁异常", route.getName(), route.getCode())); - return; - } - List
sectionList = route.getSectionList(); - for (int i = 0; i < sectionList.size(); i++) { - Section section = sectionList.get(i); - if (!Objects.equals(route.getUnlockedSection(), section)) { - continue; - } - if (section.isOccupied()) { - // 区段逻辑占用,且有逻辑区段 -// log.warn("进路[{}]区段[{}]逐段解锁", route.debugStr(), section.debugStr()); - if (section.isOccupied() && !CollectionUtils.isEmpty(section.getLogicList())) { - // 逻辑区段占用,根据逻辑区段占用位置解锁 - List
logicList = section.getLogicList(); - if (!right) { // 向左,逻辑区段列表reverse - logicList = new ArrayList<>(section.getLogicList()); - Collections.reverse(logicList); - } - for (Section logic : logicList) { - if (!logic.isOccupied() && /*!logic.isInvalid() &&*/ logic.isRouteLockOn(right)) { - logic.routeUnlocking(route); - logic.overlapUnlocking(); - } else if (logic.isOccupied() /*|| logic.isInvalid()*/) { - break; - } - } - } - allUnlock = false; - break; - } else { // 区段不再占用 - if (section.isSwitchTrack()) { // 如果是道岔区段,解锁道岔 - if (section.getParent() != null && section.getParent().isCross()) { - section.getParent().routeUnlocking(route); - } - Switch relSwitch = section.getRelSwitch(); - relSwitch.routeUnlock(route); - relSwitch.overlapUnLock(); - // 侧防解锁 - route.unlockRouteFlsOfSwitch(relSwitch); - //检查道岔的联动道岔和计轴关联道岔是否可以解锁 - for (SwitchElement switchElement : route.getSwitchList()) { - if (switchElement.getASwitch().equals(relSwitch)) { - continue; - } - Switch aSwitch = switchElement.getASwitch(); - if (route.isRouteSection(aSwitch.getA())) { - continue; - } - if (relSwitch.isLinkedSwitch(aSwitch) || relSwitch.isBConnectTo(aSwitch)) { -// if (!aSwitch.getA().isRouteLock()) { //当两条进路锁闭同一个道岔时,一条进路解锁,道岔的A区段可能仍旧被另一条进路锁闭着,导致无法解锁,故去掉此判断 - aSwitch.routeUnlock(route); -// aSwitch.overlapUnLock(); //应该不需要,暂时注掉 -// } - } - } - } else { - if (!CollectionUtils.isEmpty(section.getLogicList())) { - for (Section logic : section.getLogicList()) { - if (!logic.isOccupied() && logic.isRouteLockOn(right)) { - logic.routeUnlocking(route); - logic.overlapUnlocking(); - } - } - } - section.routeUnlocking(route); - section.overlapUnlocking(); -// log.warn("进路[{}]区段[{}]全部解锁", route.debugStr(), section.debugStr()); - } - log.debug(section.debugStr() + "因正常解锁解锁"); - } - if (!section.isRouteLock() && (i + 1) < sectionList.size()) { - // 区段已经解锁,更新解锁区段 - route.updateUnlockedSection(sectionList.get(i + 1)); - } else if (section.isRouteLock() && (i + 1) >= sectionList.size()) { - allUnlock = true; - } - } - Section firstRouteSection = route.getFirstRouteSection(); - if (firstRouteSection.isFree()) { - route.getStart().setReblockade(false); - } - if (allUnlock) { // 进路所有区段都已经解锁,解锁完成 - route.normalUnlockOver(); - simulation.getRepository().removeSettingRoute(route); - log.debug(String.format("进路[%s(%s)-%s]解锁完毕,移除", route.getName(), route.getCode(), route.isTurnBack() ? "Z" : "B")); - } - } - } - - /** - * 延续保护办理 - * - * @param simulation - * @param overlap - */ - public void setOverlap(Simulation simulation, RouteOverlap overlap) { - if (overlap.isSetting()) { - // 已经在办理了 - return; - } - LocalDateTime systemTime = simulation.getSystemTime(); - overlap.startSetting(systemTime); - } - - public void checkAndAllowOverlap(Simulation simulation, RouteOverlap overlap) { - if (!overlap.getSection().isOccupied()) { - overlap.allow(); - return; - } - SectionPath sectionPath = overlap.selectPath(); - if (simulation.getRepository().isTrainHeadOccupy(sectionPath.getFirstSection())) { - overlap.allow(); - } - } - - /** - * 延续保护办理过程 - * - * @param simulation - * @param overlap - */ - public void overlapSettingProcess(Simulation simulation, RouteOverlap overlap) { - if (!overlap.isSetting()) { - return; - } - if (!overlap.getSection().isRouteLock()) { - return; - } - MapConfig config = simulation.getRepository().getConfig(); - if (!config.isRouteSettingNoFail()) { - if (simulation.getSystemTime().isAfter(overlap.getSettingStartTime().plusSeconds(SimulationConstants.ROUTE_SETTING_TIMEOUT))) { - log.info(String.format("进路延续保护[%s]办理失败", overlap.debugStr())); - overlap.settingOver(); - return; - } - } - SectionPath sectionPath = overlap.selectPath(); - for (SwitchElement switchElement : sectionPath.getSwitchList()) { - if (!switchElement.getASwitch().ciUse(switchElement.isNormal())) { - return; - } - } - // 延续保护位置转动 - boolean onPos = this.switchControlService.ensureSwitchPosCurrent(simulation, sectionPath.getSwitchList(), false); - // 延续保护区段预先锁闭 - if (onPos || config.isLockFirst()) { - this.checkAndLockOverlap(simulation, overlap); - } - // 侧防办理 - this.flsSetting(simulation, sectionPath.getFlsList()); - if (this.ciService.interlockCheck(simulation, overlap)) { - log.debug(String.format("进路延续保护[%s]办理成功", overlap.debugStr())); - overlap.setLock(true); - overlap.settingOver(); - } - } - - private void checkAndLockOverlap(Simulation simulation, RouteOverlap overlap) { - SectionPath sectionPath = overlap.selectPath(); - boolean right = overlap.isRight(); - List
logicList = sectionPath.getLogicList(); - if (!CollectionUtils.isEmpty(logicList)) { - for (Section section : logicList) { - section.overlapLocking(right); - } - } else { - List
sectionList = sectionPath.getSectionList(); - for (Section section : sectionList) { - if (section.isSwitchTrack()) { - Switch relSwitch = section.getRelSwitch(); - relSwitch.sectionOverlapLocking(right); - } else { - section.overlapLocking(right); - } - } - } - } - - /** - * 设置自动进路模式 - * - * @param route - */ - public void setFleet(Route route) { - BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertNotTrue(route.isFlt(), - "不是自动进路,不能设置自动进路"); - BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertNotTrue(route.isCiControl(), - "进路联锁自动触发,不能设置自动进路"); - if (!route.isFleetMode()) { - route.setFleetMode(true); - } - } - - /** - * 取消自动进路 - * - * @param route - */ - public void cancelFleet(Route route) { - if (route.isFleetMode()) { - route.setFleetMode(false); - } - } - - /** - * 设置联锁自动触发 - * - * @param route - */ - public void setCIAutoTrigger(Route route) { - BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertNotTrue(route.isFleetMode(), - "进路处于自动进路模式中,不能设置联锁自动触发"); - BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertNotTrue(route.isArs(), - "进路不具有该功能,无法设置为联锁自动触发"); - if (!route.isCiControl()) { - route.setCiControl(true); - } - } - - /** - * 取消联锁自动触发 - * - * @param route - */ - public void cancelCIAutoTrigger(Route route) { - if (route.isCiControl()) { - route.setCiControl(false); - } - } -} +package club.joylink.rtss.simulation.cbtc.CI.device; + +import club.joylink.rtss.exception.BusinessExceptionAssertEnum; +import club.joylink.rtss.simulation.cbtc.Simulation; +import club.joylink.rtss.simulation.cbtc.constant.SignalAspect; +import club.joylink.rtss.simulation.cbtc.constant.SimulationConstants; +import club.joylink.rtss.simulation.cbtc.constant.SimulationModule; +import club.joylink.rtss.simulation.cbtc.constant.SwitchIndication; +import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository; +import club.joylink.rtss.simulation.cbtc.data.map.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +@Slf4j +@Component +public class CiRouteService { + @Autowired + private CiSwitchControlService switchControlService; + @Autowired + private CiSignalControlService signalControlService; + @Autowired + private CiService ciService; + + /** + * 进路排列检查 + * @param guide 是引导进路? + * @return + */ + public static Route.CheckFailMessage routeSetCheck(Simulation simulation, Route route, boolean guide) { + if (!CollectionUtils.isEmpty(route.getMultiRouteAspects())) { + for (Route.MultiRouteAspect multiRouteAspect : route.getMultiRouteAspects()) { + Route.CheckFailMessage checkFailMessage = routeSetCheck(simulation, multiRouteAspect.getRoute(), false); + if (checkFailMessage != null) { + return checkFailMessage; + } + } + } else { + MapConfig config = simulation.getRepository().getConfig(); + Signal start = route.getStart(); + if (!config.isSignalBlockRouteSettable()) { + // 信号封锁,不能办理 + if (start.isBlockade()) { + return new Route.CheckFailMessage(Route.CheckFailReason.StartSignalBlockade, start); + } + } + // 进路中道岔没有被征用或锁定在相反位置 + Route.CheckFailMessage failMessage = setSwitchCheck(simulation, route.getSwitchList(), guide); + if (failMessage != null) { + return failMessage; + } + // 进路中道岔是否存在和监控中进路延续保护冲突 + failMessage = monitorRouteOverlapConflictCheck(simulation, route); + if (failMessage != null) { + return failMessage; + } + // 进路内区段封锁/锁闭方向检查 + List
sectionList = route.getSectionList(); + for (Section section : sectionList) { + // 封锁状态 + if (section.isBlockade()) { + return new Route.CheckFailMessage(Route.CheckFailReason.SectionBlockade, section); + } else if (!CollectionUtils.isEmpty(section.getLogicList())) { + for (Section logicSection : section.getLogicList()) { + if (logicSection.isBlockade()) { + return new Route.CheckFailMessage(Route.CheckFailReason.SectionBlockade, logicSection); + } + } + } else if (section.getParent() != null) { + if (section.getParent().isCross() && section.getParent().isBlockade()) { + return new Route.CheckFailMessage(Route.CheckFailReason.SectionBlockade, section); + } + } + // 进路内区段锁闭方向不是此进路方向 + if ((section.isRouteLock() || section.isOverlapLock()) && + !Objects.equals(section.isLockRight(), start.isRight())) { + return new Route.CheckFailMessage(Route.CheckFailReason.SectionLockOppositeDirection, section); + } + // 故障占用 + for (int i = 0; i < 3; i++) { + if (section.getParent() == null || section.isAxleCounter()) + break; + section = section.getParent(); + } + if (Section.AxleFault.FAULT.equals(section.getFault())) { + return new Route.CheckFailMessage(Route.CheckFailReason.SectionFaultOccupied, section); + } + } + //敌对进路 + List conflictingRouteList = route.getConflictingRouteList(); + for (Route conflict : conflictingRouteList) { + if (conflict.isSetting() || conflict.isLock()) { + return new Route.CheckFailMessage(Route.CheckFailReason.ConflictingRouteSetting, conflict); + } + } + if (start.isCbtcMode()) { + // CBTC办理检查 + Section firstLogicSection = route.getFirstLogicSection(); + if (firstLogicSection.isOccupied()) { + return new Route.CheckFailMessage(Route.CheckFailReason.SectionNotFree, firstLogicSection); + } + } else { + // 后备办理检查 + // 区段占用 + for (Section section : sectionList) { + if (section.isOccupied()) { + return new Route.CheckFailMessage(Route.CheckFailReason.SectionNotFree, section); + } + } + // 延续保护检查 + RouteOverlap overlap = route.getOverlap(); + if (Objects.nonNull(overlap)) { + SectionPath sectionPath = overlap.selectPath(); + failMessage = setSwitchCheck(simulation, sectionPath.getSwitchList(), guide); + } + } + return failMessage; + } + return null; + } + + private static Route.CheckFailMessage monitorRouteOverlapConflictCheck(Simulation simulation, Route route) { + SimulationDataRepository repository = simulation.getRepository(); + List settingRoutes = repository.getSettingRoutes(); + for (Route sr : settingRoutes) { + if (sr.isSettingOverlap() && (sr.getOverlap().isSetting() || sr.getOverlap().isLock())/*&& !repository.isTrainParking(sr.getOverlap().getSection())*/) { + SectionPath sectionPath = sr.getOverlap().selectPath(); + for (SwitchElement switchElement : sectionPath.getSwitchList()) { + if (route.isConflictSwitch(switchElement)) { + return new Route.CheckFailMessage(Route.CheckFailReason.SwitchCiUseOnOppositePosition, + switchElement.getASwitch()); + } + } + } + } + return null; + } + + private static Route.CheckFailMessage setSwitchCheck(Simulation simulation, List switchList, boolean guide) { + if (switchList != null) { + for (SwitchElement switchElement : switchList) { + Switch aSwitch = switchElement.getASwitch(); + if (aSwitch.isBlockade()) { // 道岔封锁 + return new Route.CheckFailMessage(Route.CheckFailReason.SwitchBlockade, aSwitch); + } + if (!guide && aSwitch.isGuideMasterLock()) { + return new Route.CheckFailMessage(Route.CheckFailReason.SwitchGuideMasterLock, aSwitch); + } + if ((aSwitch.isLocked() || aSwitch.isSectionOccupied()) && + aSwitch.getPos().equals(SwitchIndication.of(!switchElement.isNormal()))) {//道岔锁闭或占用在相反位置 + return new Route.CheckFailMessage(Route.CheckFailReason.SwitchLockPositionError, aSwitch); + } + if (aSwitch.isCiUseOnOppositePosition(switchElement.isNormal())) { // 道岔征用在相反位置 + return new Route.CheckFailMessage(Route.CheckFailReason.SwitchCiUseOnOppositePosition, aSwitch); + } + // 非预先锁闭,道岔相应位置失表则不排进路 + if (!simulation.getRepository().getConfig().isLockFirst() && aSwitch.isLoss()) { + if ((Switch.SwitchFault.NORMAL_SPLIT.equals(aSwitch.getFault()) && switchElement.isNormal()) + || (Switch.SwitchFault.REVERSE_SPLIT.equals(aSwitch.getFault()) && !switchElement.isNormal())) { + return new Route.CheckFailMessage(Route.CheckFailReason.SwitchFault, aSwitch); + } + } + } + } + return null; + } + + /** + * 排列引导进路 + */ + public void setGuide(Simulation simulation, Route route) { + route.setSettedAspect(route.getStart().getGuideAspect()); + // 进路检查 + Route.CheckFailMessage failMessage = routeSetCheck(simulation, route, true); + if (failMessage == null) { + if (route.isLock() && !route.isFleetMode()) { + log.info("进路[{}]已经锁闭", route.debugStr()); + return; + } + // 引导进路开始办理 + LocalDateTime systemTime = simulation.getSystemTime(); + route.startGuideSetting(systemTime); + // 道岔征用 + for (SwitchElement switchElement : route.getSwitchList()) { + switchElement.getASwitch().ciUse(switchElement.isNormal()); + } + simulation.getRepository().addSettingRoute(route); + } + if (Objects.nonNull(failMessage)) { + log.info(String.format("进路[%s]排列检查失败,无法排列:%s", route.debugStr(), failMessage.debugStr())); + } + } + + /** + * 排列进路 + * + * @param simulation + * @param route + * @return + */ + public Route.CheckFailMessage setRoute(Simulation simulation, Route route) { + Route.CheckFailMessage failMessage = routeSetCheck(simulation, route, false); + if (failMessage == null) { + if (route.isLock() && !route.isFleetMode()) { + log.info("进路[{}]已经锁闭", route.debugStr()); + return null; + } + // 进路开始办理 + LocalDateTime systemTime = simulation.getSystemTime(); + route.startSetting(systemTime); + // 道岔征用 + for (SwitchElement switchElement : route.getSwitchList()) { + switchElement.getASwitch().ciUse(switchElement.isNormal()); + } + // 延续保护进路办理 + this.ciService.checkAndTrySettingOverlap(simulation, route.getOverlap()); + simulation.getRepository().addSettingRoute(route); + } + if (Objects.nonNull(failMessage)) { + log.info(String.format("进路[%s]排列检查失败,无法排列:%s", route.debugStr(), failMessage.debugStr())); + } + return failMessage; + } + + /** + * 排列进路过程控制 + * + * @param simulation + * @param route + */ + public void routeSettingProcess(Simulation simulation, Route route) { + if (route.isSetting()) { // 进路排列中 + MapConfig config = simulation.getRepository().getConfig(); + if (!config.isRouteSettingNoFail()) { + if (simulation.getSystemTime().isAfter(route.getSettingStartTime().plusSeconds(SimulationConstants.ROUTE_SETTING_TIMEOUT))) { + log.info("进路[{}]办理超时,取消办理2", route.debugStr()); + route.settingOver(); + return; + } + } + List multiRouteAspects = route.getMultiRouteAspects(); + if (CollectionUtils.isEmpty(multiRouteAspects)) { + // 道岔位置转换 + boolean mainRouteSwitchOnPos = this.switchControlService.ensureSwitchPosCurrent(simulation, route.getSwitchList(), route.isGuideSetting()); + // 预先锁闭 + if (mainRouteSwitchOnPos || config.isLockFirst()) { + // 进路排列区段预先锁闭 + this.checkAndLockRouteMain(route, config.isRailway()); + } + // 侧防办理 + this.flsSetting(simulation, route.getFlsList()); + // 检查信号开放条件,开信号 + this.ciService.interlockCheck(simulation, route); + SignalAspect aspect = null; + boolean routeRight = route.isRight(); + if (route.isGuideSetting()) { + aspect = route.getStart().getGuideAspect(); + } else if (route.getStart().isBlockade()) { + aspect = route.getStart().getDefaultAspect(); + } else { + aspect = route.getAspect(); + if (config.isRailway() && route.isDepartureRoute()) { + aspect = route.getAspectOfRailway(); + } + } + this.signalControlService.tryControlSignalAspectAccordingLevel(simulation, route.getStart(), aspect); + if (config.isRailway()) { + if (route.isGuideSetting() && route.getStart().isGuideAspect() + || !route.getStart().isDefaultAspect()) { + route.settingOver(); + } + } else if ((route.getAspect().equals(route.getStart().getAspect())) || + (route.isGuideSetting() && route.getStart().isGuideAspect())) { + log.debug("进路[{}]信号开放,办理结束", route.debugStr()); + route.settingOver(); + } + } else { + //由远及近办理进路 + for (int i = multiRouteAspects.size() - 1; i >= 0; i--) { + Route.MultiRouteAspect routeAspect = multiRouteAspects.get(i); + Route subRoute = routeAspect.getRoute(); + if (!subRoute.isLock()) { + subRoute.setSettedAspect(routeAspect.getAspect()); + setRoute(simulation, subRoute); + break; + } + } + //最近的一条进路已经锁闭 + if (multiRouteAspects.get(0).getRoute().isLock()) { + route.settingOver(); + } + } + } + } + + private void flsSetting(Simulation simulation, List flsList) { + // 侧防道岔转换 + if (!CollectionUtils.isEmpty(flsList)) { + for (RouteFls routeFls : flsList) { + List level1List = routeFls.getLevel1List(); + for (RouteFls.FlsElement flsElement : level1List) { + SwitchElement pSwitch = flsElement.getPSwitch(); + if (pSwitch != null) { + boolean onPos = this.switchControlService.turnRouteSwitch(simulation, pSwitch); + if (onPos) { + pSwitch.getASwitch().fpLock(); + } + } + } + } + } + } + + /** + * 检查并锁闭主进路(不包含侧防和延续保护) + * + * @param route + * @param railway + */ + private void checkAndLockRouteMain(Route route, boolean railway) { + boolean right = route.isRight(); + List
sectionList = route.getSectionList(); + List switchList = route.getSwitchList(); + for (SwitchElement switchElement : switchList) { + if (switchElement.isOnPosition() || (route.isGuideSetting() && switchElement.getASwitch().isGuideMasterLock())) { + switchElement.getASwitch().routeLock(route); + } + } + for (Section section : sectionList) { + //大铁引导进路只锁闭指定区段(为了解决引导总锁方式办理道岔失表的引导进路时,失表道岔的所有区段都锁闭的问题) + if (section.isSwitchTrack() && !(railway && route.isGuideSetting())) { + Switch relSwitch = section.getRelSwitch(); + relSwitch.sectionRouteLocking(route, right); + } else { + section.routeLocking(route, right); + } + } + route.setLock(true); + } + + /** + * 解锁进路 + * + * @param simulation + * @param route + */ + public void unlockRoute(Simulation simulation, Route route) { + // 取消自动进路 + this.cancelFleet(route); + // 关闭始端信号机 + this.signalControlService.tryControlSignalAspectAccordingLevel(simulation, + route.getStart(), route.getStart().getDefaultAspect()); + log.debug(String.format("取消进路,信号机[%s(%s)]关灯", + route.getStart().getName(), route.getStart().getCode())); + //进路解锁 + route.setLock(false); + route.setSetting(false); + route.setAtsControl(false); + // 始端信号机锁闭进路置为null + route.getStart().setLockedRoute(null); + route.getStart().setLevel(Signal.LEVEL_Close); + simulation.getRepository().removeSettingRoute(route); + // 进路区段取消锁闭 + List
sectionList = route.getSectionList(); + for (Section section : sectionList) { + if (section.isOccupied() && !section.isFaultOccupied()) { // 区段列车占用 + route.startNormalUnlock(); + route.updateUnlockedSection(section); + return; + } + if (section.isSwitchTrack()) { + //解锁道岔 + Switch relSwitch = section.getRelSwitch(); + relSwitch.routeUnlock(route); + //解锁道岔侧防 + RouteFls routeFls = route.queryRouteFlsOfSwitch(relSwitch); + if (routeFls != null) { + routeFls.unlock(); + } + //解锁联动道岔 + Switch linkedSwitch = relSwitch.queryLinkedSwitch(); + if (linkedSwitch != null) { + linkedSwitch.routeUnlock(route); + } + } else { + section.routeUnlocking(route); + } + } + // 进路延续保护解锁 + RouteOverlap overlap = route.getOverlap(); + if (Objects.nonNull(overlap)) { + overlap.releaseImmediately(); + log.debug(overlap.debugStr() + "因取消进路解锁"); + } + } + + public void delayUnlockStart(Simulation simulation, Route route, DelayUnlockDevice device) { + device.delayUnlockStart(route); + route.setDelayUnlockDevice(device); + this.signalControlService.tryControlSignalAspectAccordingLevel(simulation, route.getStart(), route.getStart().getDefaultAspect()); + } + + /** + * 延时解锁进路 + * + * @param simulation + * @param route + */ + public void delayUnlocking(Simulation simulation, Route route, DelayUnlockDevice device) { + if (device.countAndCheckFinish(SimulationModule.CI.getRateMs())) { + // 延时结束,执行解锁 + if (device instanceof Signal) { + // 解锁整条进路 + this.unlockRoute(simulation, route); + } else if (device instanceof Switch) { + Switch aSwitch = (Switch) device; + this.faultUnlock(simulation, route, aSwitch); + } else if (device instanceof Section) { + ((Section) device).faultUnlock(); + } + route.setLock(false); + route.setDelayUnlockDevice(null); + } + } + + private void faultUnlock(Simulation simulation, Route route, Switch aSwitch) { + aSwitch.faultUnlock(); + aSwitch.sectionFaultUnlock(); + if (route != null) { + route.unlockRouteFlsOfSwitch(aSwitch); //进路中该道岔对应的侧防解除锁闭 + RouteOverlap overlap = route.getOverlap(); + if (overlap != null) { + for (SectionPath sectionPath : overlap.getPathList()) { + overlap.unlockFlsOfSwitch(sectionPath.getFlsList(), aSwitch); //延续保护中该道岔的侧防解除锁闭 + } + } + } + } + + /** + * 道岔区段故障解锁 + * + * @param simulation + * @param aSwitch + * @param route + */ + public void switchFaultUnlock(Simulation simulation, Switch aSwitch, Route route) { + if (route != null) { + if (route.isApproachLock() || aSwitch.isOverlapLock()) { + // 延时解锁 + this.delayUnlockStart(simulation, route, aSwitch); + return; + } else { + route.setLock(false); + } + } + this.faultUnlock(simulation, route, aSwitch); + } + + /** + * 区故解 + */ + public void sectionFaultUnlock(Simulation simulation, Section section, Route route) { + if (route != null) { + if (route.getStart().isApproachLock() + || section.isOverlapLock() + || route.getSectionList().stream().anyMatch(Section::isOccupied)) { + // 区段延时解锁 + this.delayUnlockStart(simulation, route, section); + return; + } else { + if (route.isOpenMain() || route.isOpenGuide()) { + this.signalControlService.tryControlSignalAspectAccordingLevel(simulation, route.getStart(), + route.getStart().getDefaultAspect()); + } + route.setLock(false); + } + } + section.faultUnlock(); + if (section.isShowLogic()) { + section.getLogicList().forEach(Section::faultUnlock); + } + } + + /** + * 列车逐段解锁进路 + * + * @param simulation + * @param route + */ + public void trainUnlockRoute(Simulation simulation, Route route) { + if (!route.isNormalUnlock()) { + return; + } + if (!route.isFleetMode()) { // 连续通过进路不解锁,非连续通过进路随最后一辆车的运行而解锁 + boolean right = route.getStart().isRight(); + // 区段是顺序的(否则会有问题) + boolean allUnlock = true; + if (Objects.isNull(route.getUnlockedSection())) { + log.error(String.format("进路[%s(%s)]正常解锁异常", route.getName(), route.getCode())); + return; + } + List
sectionList = route.getSectionList(); + for (int i = 0; i < sectionList.size(); i++) { + Section section = sectionList.get(i); + if (!Objects.equals(route.getUnlockedSection(), section)) { + continue; + } + if (section.isOccupied()) { + // 区段逻辑占用,且有逻辑区段 +// log.warn("进路[{}]区段[{}]逐段解锁", route.debugStr(), section.debugStr()); + if (section.isOccupied() && !CollectionUtils.isEmpty(section.getLogicList())) { + // 逻辑区段占用,根据逻辑区段占用位置解锁 + List
logicList = section.getLogicList(); + if (!right) { // 向左,逻辑区段列表reverse + logicList = new ArrayList<>(section.getLogicList()); + Collections.reverse(logicList); + } + for (Section logic : logicList) { + if (!logic.isOccupied() && /*!logic.isInvalid() &&*/ logic.isRouteLockOn(right)) { + logic.routeUnlocking(route); + logic.overlapUnlocking(); + } else if (logic.isOccupied() /*|| logic.isInvalid()*/) { + break; + } + } + } + allUnlock = false; + break; + } else { // 区段不再占用 + if (section.isSwitchTrack()) { // 如果是道岔区段,解锁道岔 + if (section.getParent() != null && section.getParent().isCross()) { + section.getParent().routeUnlocking(route); + } + Switch relSwitch = section.getRelSwitch(); + relSwitch.routeUnlock(route); + relSwitch.overlapUnLock(); + // 侧防解锁 + route.unlockRouteFlsOfSwitch(relSwitch); + //检查道岔的联动道岔和计轴关联道岔是否可以解锁 + for (SwitchElement switchElement : route.getSwitchList()) { + if (switchElement.getASwitch().equals(relSwitch)) { + continue; + } + Switch aSwitch = switchElement.getASwitch(); + if (route.isRouteSection(aSwitch.getA())) { + continue; + } + if (relSwitch.isLinkedSwitch(aSwitch) || relSwitch.isBConnectTo(aSwitch)) { +// if (!aSwitch.getA().isRouteLock()) { //当两条进路锁闭同一个道岔时,一条进路解锁,道岔的A区段可能仍旧被另一条进路锁闭着,导致无法解锁,故去掉此判断 + aSwitch.routeUnlock(route); +// aSwitch.overlapUnLock(); //应该不需要,暂时注掉 +// } + } + } + } else { + if (!CollectionUtils.isEmpty(section.getLogicList())) { + for (Section logic : section.getLogicList()) { + if (!logic.isOccupied() && logic.isRouteLockOn(right)) { + logic.routeUnlocking(route); + logic.overlapUnlocking(); + } + } + } + section.routeUnlocking(route); + section.overlapUnlocking(); +// log.warn("进路[{}]区段[{}]全部解锁", route.debugStr(), section.debugStr()); + } + log.debug(section.debugStr() + "因正常解锁解锁"); + } + if (!section.isRouteLock() && (i + 1) < sectionList.size()) { + // 区段已经解锁,更新解锁区段 + route.updateUnlockedSection(sectionList.get(i + 1)); + } else if (section.isRouteLock() && (i + 1) >= sectionList.size()) { + allUnlock = true; + } + } + Section firstRouteSection = route.getFirstRouteSection(); + if (firstRouteSection.isFree()) { + route.getStart().setReblockade(false); + } + if (allUnlock) { // 进路所有区段都已经解锁,解锁完成 + route.normalUnlockOver(); + simulation.getRepository().removeSettingRoute(route); + log.debug(String.format("进路[%s(%s)-%s]解锁完毕,移除", route.getName(), route.getCode(), route.isTurnBack() ? "Z" : "B")); + } + } + } + + /** + * 延续保护办理 + * + * @param simulation + * @param overlap + */ + public void setOverlap(Simulation simulation, RouteOverlap overlap) { + if (overlap.isSetting()) { + // 已经在办理了 + return; + } + LocalDateTime systemTime = simulation.getSystemTime(); + overlap.startSetting(systemTime); + } + + public void checkAndAllowOverlap(Simulation simulation, RouteOverlap overlap) { + if (!overlap.getSection().isOccupied()) { + overlap.allow(); + return; + } + SectionPath sectionPath = overlap.selectPath(); + if (simulation.getRepository().isTrainHeadOccupy(sectionPath.getFirstSection())) { + overlap.allow(); + } + } + + /** + * 延续保护办理过程 + * + * @param simulation + * @param overlap + */ + public void overlapSettingProcess(Simulation simulation, RouteOverlap overlap) { + if (!overlap.isSetting()) { + return; + } + if (!overlap.getSection().isRouteLock()) { + return; + } + MapConfig config = simulation.getRepository().getConfig(); + if (!config.isRouteSettingNoFail()) { + if (simulation.getSystemTime().isAfter(overlap.getSettingStartTime().plusSeconds(SimulationConstants.ROUTE_SETTING_TIMEOUT))) { + log.info(String.format("进路延续保护[%s]办理失败", overlap.debugStr())); + overlap.settingOver(); + return; + } + } + SectionPath sectionPath = overlap.selectPath(); + for (SwitchElement switchElement : sectionPath.getSwitchList()) { + if (!switchElement.getASwitch().ciUse(switchElement.isNormal())) { + return; + } + } + // 延续保护位置转动 + boolean onPos = this.switchControlService.ensureSwitchPosCurrent(simulation, sectionPath.getSwitchList(), false); + // 延续保护区段预先锁闭 + if (onPos || config.isLockFirst()) { + this.checkAndLockOverlap(simulation, overlap); + } + // 侧防办理 + this.flsSetting(simulation, sectionPath.getFlsList()); + if (this.ciService.interlockCheck(simulation, overlap)) { + log.debug(String.format("进路延续保护[%s]办理成功", overlap.debugStr())); + overlap.setLock(true); + overlap.settingOver(); + } + } + + private void checkAndLockOverlap(Simulation simulation, RouteOverlap overlap) { + SectionPath sectionPath = overlap.selectPath(); + boolean right = overlap.isRight(); + List
logicList = sectionPath.getLogicList(); + if (!CollectionUtils.isEmpty(logicList)) { + for (Section section : logicList) { + section.overlapLocking(right); + } + } else { + List
sectionList = sectionPath.getSectionList(); + for (Section section : sectionList) { + if (section.isSwitchTrack()) { + Switch relSwitch = section.getRelSwitch(); + relSwitch.sectionOverlapLocking(right); + } else { + section.overlapLocking(right); + } + } + } + } + + /** + * 设置自动进路模式 + * + * @param route + */ + public void setFleet(Route route) { + BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertNotTrue(route.isFlt(), + "不是自动进路,不能设置自动进路"); + BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertNotTrue(route.isCiControl(), + "进路联锁自动触发,不能设置自动进路"); + if (!route.isFleetMode()) { + route.setFleetMode(true); + } + } + + /** + * 取消自动进路 + * + * @param route + */ + public void cancelFleet(Route route) { + if (route.isFleetMode()) { + route.setFleetMode(false); + } + } + + /** + * 设置联锁自动触发 + * + * @param route + */ + public void setCIAutoTrigger(Route route) { + BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertNotTrue(route.isFleetMode(), + "进路处于自动进路模式中,不能设置联锁自动触发"); + BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertNotTrue(route.isArs(), + "进路不具有该功能,无法设置为联锁自动触发"); + if (!route.isCiControl()) { + route.setCiControl(true); + } + } + + /** + * 取消联锁自动触发 + * + * @param route + */ + public void cancelCIAutoTrigger(Route route) { + if (route.isCiControl()) { + route.setCiControl(false); + } + } +} diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/Route.java b/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/Route.java index 531414912..c7bf9a361 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/Route.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/Route.java @@ -1,945 +1,956 @@ -package club.joylink.rtss.simulation.cbtc.data.map; - -import club.joylink.rtss.exception.BusinessExceptionAssertEnum; -import club.joylink.rtss.simulation.cbtc.ATS.data.AtsAlarm; -import club.joylink.rtss.simulation.cbtc.constant.SignalAspect; -import club.joylink.rtss.simulation.cbtc.data.vo.TrainInfo; -import club.joylink.rtss.simulation.cbtc.exception.SimulationException; -import club.joylink.rtss.simulation.cbtc.exception.SimulationExceptionType; -import club.joylink.rtss.util.JsonUtils; -import lombok.Getter; -import lombok.Setter; -import org.springframework.util.CollectionUtils; - -import java.time.LocalDateTime; -import java.util.*; - -/** - * 进路 - */ -@Getter -@Setter -public class Route extends MapNamedElement { - - public Route(String code, String name) { - super(code, name, DeviceType.ROUTE); - this.atsControl = true; - this.psdList = new ArrayList<>(); - this.espList = new ArrayList<>(); - this.conflictingRouteList = new ArrayList<>(); - this.sectionList = new ArrayList<>(); - this.switchList = new ArrayList<>(); - } - - // ------------------固有属性/关联关系--------------------- - - /** - * 所属联锁区 - */ - private Station interlockStation; - - /** - * 是否折返进路 - */ - private boolean turnBack; - - /** - * 是否ATP进路 - */ - private boolean atp; - - /** - * 是否地面信号进路 - */ - private boolean ground; - - /** - * 是否引导进路 - */ - private boolean guide; - - /** - * 连续通过进路/车队模式进路(联锁自动进路) - */ - private boolean flt; - - /** - * 自动排列(联锁自动触发) - */ - private boolean ars; - - /** - * 始端信号机 - */ - private Signal start; - - /** - * 终端信号机 - */ - private Signal destination; - - /** - * 信号显示 - */ - private SignalAspect aspect; - - /** - * 进路区段 - */ - private List
sectionList; - - /** - * 进路道岔 - */ - private List switchList; - - /** - * 进路侧防元件 - */ - private List flsList; - - /** - * 站台屏蔽门 - */ - private List psdList; - - /** - * 站台紧急停车按钮 - */ - private List espList; - - /** - * 站台扣车 - */ - private List standHoldList; - - /** - * CTC模式下需要办理延续保护 - */ - @Deprecated - private boolean setOverlapInCtc = true; - - /** - * 进路延续保护 - */ - private RouteOverlap overlap; - - /** - * 超限区段列表 - */ - private List overrunList; - - /** - * 敌对进路 - */ - private List conflictingRouteList; - - /** - * 进路终端按钮信号机 - */ - private Signal destinationButtonSignal; - - /** - * 组合进路中的所有单进路 - */ - private List multiRouteAspects; - - /** - * 进路类型(大铁) - */ - private Type type; - - /** - * 当离去区段占用时的信号显示 - */ - private LinkedHashMap leaveSectionWithAspectMap; - - // ------------------状态属性--------------------- - /** - * ats自动控制 - */ - private boolean atsControl; - - /** - * 连续通过进路模式(联锁自动进路)开启 - */ - private boolean fleetMode; - - /** - * 自动追踪/联锁自动触发模式开启 - */ - private boolean ciControl; - - /** - * 进路是否可以排列 - */ - private boolean settable; - - /** - * 进路是否排列中 - */ - private boolean setting; - - /** - * 进路开始排列时间 - */ - private LocalDateTime settingStartTime; - - /** - * 是否引导进路排列中 - */ - private boolean guideSetting; - - /** - * 进路是否锁闭 - */ - private boolean lock; - - /** - * 进路延时解锁设备 - */ - private DelayUnlockDevice delayUnlockDevice; - - /** - * 是否正常解锁中 - */ - private boolean normalUnlock; - - /** - * 正常解锁到的区段 - */ - private Section unlockedSection; - - /** - * 进路将要或上一次为哪辆列车排列 - */ - @Deprecated - private TrainInfo train; - /** - * 检查冲突功能是否开启 - */ - private boolean checkConflict; - /** - * 冲突告警 - */ - private AtsAlarm conflictAlarm; - /** - * 按计划执行 - */ - public static final int Conflict_Handle_Way_1 = 1; - /** - * 执行冲突进路 - */ - public static final int Conflict_Handle_Way_2 = 2; - - /** - * 大铁进路排列车次信息 - */ - private String tripNumber; - - @Override - public void reset() { - this.atsControl = true; - this.fleetMode = false; - this.ciControl = false; - this.settable = false; - this.setting = false; - this.guideSetting = false; - this.lock = false; - this.delayUnlockDevice = null; - this.normalUnlock = false; - this.unlockedSection = null; - this.train = null; - this.checkConflict = false; - } - - public boolean isAllSwitchIsOnPos() { - if (!CollectionUtils.isEmpty(switchList)) { - return switchList.stream().allMatch(SwitchElement::isOnPosition); - } - return true; - } - - /** - * 进路是否开放(进路是否锁闭,并开放指定信号灯) - * - * @return - */ - public boolean isOpenMain() { - return this.lock && this.aspect.equals(this.start.getAspect()); - } - - /** - * 进路是否开放引导信号 - * - * @return - */ - public boolean isOpenGuide() { - return this.lock && (this.start.isGuideAspect()); - } - - public void setAtsControl(boolean atsControl) { - this.atsControl = atsControl; - if (!atsControl) - this.checkConflict = false; - } - - /** - * 选择合适的进路延续保护区段 - * - * @return - */ - public SectionPath selectOverlapElement() { - if (Objects.nonNull(this.overlap)) { - return this.overlap.selectPath(); - } - return null; - } - - public Section getFirstRouteSection() { - return this.sectionList.get(0); - } - - /** - * 获取第一个逻辑区段 - */ - public Section getFirstLogicSection() { - Section firstSection = getFirstRouteSection(); - List
logicList = firstSection.getLogicList(); - if (CollectionUtils.isEmpty(logicList)) { - return firstSection; - } else { - boolean right = start.isRight(); - if (right) { - return logicList.get(0); - } else { - return logicList.get(logicList.size() - 1); - } - } - } - - public Section getFirstPhysicalSection() { - Section section = getFirstLogicSection(); - if (section.isPhysical()) - return section; - for (int i = 0; i < 10; i++) { - section = section.getParent(); - BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertNotNull(section, - debugStr() + "未找到第一个物理区段"); - if (section.isPhysical()) - return section; - } - throw BusinessExceptionAssertEnum.DATA_NOT_EXIST.exception(debugStr() + "未找到第一个物理区段"); - } - - /** - * 获取进路内最后一个子进路区段 - * - * @return - */ - public Section getLastRouteSection() { - return this.sectionList.get(this.sectionList.size() - 1); - } - - /** - * 进路是否直向进路 - * - * @return true-直向(进路中道岔定位),false-侧向(进路中道岔反位) - */ - public boolean isStraight() { - if (CollectionUtils.isEmpty(this.switchList)) { - return true; - } else { - for (SwitchElement switchElement : this.switchList) { - if (!switchElement.isNormal()) { - return false; - } - } - } - return true; - } - - /** - * 是否进路区段 - * - * @param section-计轴区段/道岔区段,非逻辑区段 - * @return - */ - public boolean isRouteSection(Section section) { - for (Section rs : this.sectionList) { - if (Objects.equals(rs.getCode(), section.getCode())) { - return true; - } - } - return false; - } - - public boolean isRouteSection(String sectionCode) { - for (Section rs : this.sectionList) { - if (Objects.equals(rs.getCode(), sectionCode)) { - return true; - } - } - return false; - } - - /** - * 是否进路道岔 - * - * @param aSwitch - * @return - */ - public boolean isRouteSwitch(Switch aSwitch) { - for (SwitchElement element : this.switchList) { - if (Objects.equals(element.getASwitch(), aSwitch)) { - return true; - } - } - return false; - } - - public boolean isApproachLock() { - return this.isOpenMain() && this.getStart().isApproachLock(); - } - - public boolean isAnySectionOccupied() { - for (Section section : this.sectionList) { - if (section.isOccupied()) { - return true; - } - } - return false; - } - - /** - * 折返轨占用 - */ - public boolean isAnyTBSectionOccupied() { - for (Section section : this.sectionList) { - if (section.isOccupied() && section.isTurnBackTrack()) { - return true; - } - } - return false; - } - - public boolean isAnySectionOppositeTrainOccupied() { - for (Section section : this.sectionList) { - if (section.isOccupied() && !Objects.equals(start.isRight(), section.isTrainRight())) { - return true; - } - } - return false; - } - - public boolean containConflictRoute(Route route) { - if (!CollectionUtils.isEmpty(this.conflictingRouteList) && - this.conflictingRouteList.contains(route)) { - return true; - } - return false; - } - - public boolean containSameSection(List
sectionList) { - if (!CollectionUtils.isEmpty(sectionList)) { - for (Section section1 : this.sectionList) { - for (Section section2 : sectionList) { - if (Objects.equals(section1, section2)) { - return true; - } - } - } - } - return false; - } - - /** - * 是否包含方向不同的冲突道岔 - * - * @param list - * @return - */ - public boolean containConflictSwitch(List list) { - if (!CollectionUtils.isEmpty(list) && !CollectionUtils.isEmpty(this.switchList)) { - for (SwitchElement se1 : this.switchList) { - for (SwitchElement se2 : list) { - if (Objects.equals(se1.getASwitch(), se2.getASwitch()) && - !Objects.equals(se1.isNormal(), se2.isNormal())) { - return true; - } - } - } - } - return false; - } - - public void addConflictRoute(Route conflict) { - if (!this.conflictingRouteList.contains(conflict)) { - this.conflictingRouteList.add(conflict); - } - } - - public boolean isTriggerSection(String sectionCode) { - return this.start.isApproachSection(sectionCode); - } - - public SwitchElement queryRouteSwitchElement(Switch aSwitch) { - for (SwitchElement element : this.switchList) { - if (Objects.equals(element.getASwitch(), aSwitch)) { - return element; - } - } - return null; - } - - public SwitchElement getRouteSwitchElement(Switch aSwitch) { - SwitchElement switchElement = this.queryRouteSwitchElement(aSwitch); - if (Objects.isNull(switchElement)) { - throw new SimulationException(SimulationExceptionType.System_Fault); - } - return switchElement; - } - - public int getDelayReleaseTime() { - return this.getStart().getRouteReleaseTime(); - } - - public boolean isConflictWith(Route route2) { - if (this.containConflictRoute(route2)) { - return true; - } - if (this.containConflictSwitch(route2.getSwitchList())) { - return true; - } - if (route2.getOverlap() != null && route2.getOverlap().isOnlyOnePath() && - this.containConflictSwitch(route2.getOverlap().getFirstPath().getSwitchList())) { - return true; - } - if (this.getOverlap() != null && this.getOverlap().isOnlyOnePath() && - route2.containConflictSwitch(this.getOverlap().getFirstPath().getSwitchList())) { - return true; - } - return false; - } - - /** - * 存在反位道岔 - * - * @return - */ - public boolean hasReverseSwitch() { - for (SwitchElement element : this.switchList) { - if (!element.isNormal()) { - return true; - } - } - return false; - } - - public void startNormalUnlock() { - this.setSetting(false); - this.unlockedSection = this.sectionList.get(0); - // 进路解锁开始信号 - this.normalUnlock = true; - this.setLock(false); - } - - public void updateUnlockedSection(Section section) { - this.unlockedSection = section; - } - - public void normalUnlockOver() { - this.normalUnlock = false; - this.unlockedSection = null; - } - - public void startSetting(LocalDateTime systemTime) { - this.normalUnlock = false; - this.setSetting(true); - this.settingStartTime = systemTime; - this.setGuideSetting(false); - } - - public void startGuideSetting(LocalDateTime systemTime) { - this.normalUnlock = false; - this.setSetting(true); - this.settingStartTime = systemTime; - this.setGuideSetting(true); - } - - public void settingOver() { - this.setSetting(false); - if (this.overlap != null) { - this.overlap.settingOver(); - } - } - - public void setLock(boolean lock) { - this.lock = lock; - if (lock) { - this.start.setLockedRoute(this); - } else if (this == this.start.getLockedRoute()) { - this.start.setLockedRoute(null); - } - } - - public int getReverseSwitchQuantity() { - int quantity = 0; - if (!CollectionUtils.isEmpty(this.switchList)) { - for (SwitchElement element : this.switchList) { - if (!element.isNormal()) { - ++quantity; - } - } - } - return quantity; - } - - public boolean isCiTrigger() { - List approachPathList = this.start.getApproachPathList(); - for (SectionPath sectionPath : approachPathList) { - //检查区段占用 - List
sectionList = sectionPath.getSectionList(); - boolean sectionOccupied = false; - for (Section section : sectionList) { - if (section.isOccupiedOn(this.getStart().isRight())) { - sectionOccupied = true; - break; - } - } - if (!sectionOccupied) - continue; - //检查道岔位置 - if (CollectionUtils.isEmpty(sectionPath.getSwitchList())) { - boolean switchOnPosition = true; - for (SwitchElement switchElement : sectionPath.getSwitchList()) { - if (!switchElement.isOnPosition()) { - switchOnPosition = false; - break; - } - } - if (!switchOnPosition) - continue; - } - - return true; - } - return false; - } - - public boolean containsRoutePosFaultSwitch() { - if (!CollectionUtils.isEmpty(this.switchList)) { - for (SwitchElement element : this.switchList) { - Switch aSwitch = element.getASwitch(); - if (aSwitch.isFault() && - (Switch.SwitchFault.SPLIT.equals(aSwitch.getFault()) || - (element.isNormal() && Switch.SwitchFault.NORMAL_SPLIT.equals(aSwitch.getFault())) || - (!element.isNormal() && Switch.SwitchFault.REVERSE_SPLIT.equals(aSwitch.getFault())))) { - return true; - } - } - } - return false; - } - - public boolean isLastRouteSection(Section section) { - return Objects.equals(this.getLastRouteSection(), section); - } - - public RouteFls queryRouteFlsOfSwitch(Switch aSwitch) { - if (!CollectionUtils.isEmpty(this.flsList)) { - for (RouteFls routeFls : flsList) { - if (Objects.equals(routeFls.getBase().getASwitch(), aSwitch)) { - return routeFls; - } - } - } - return null; - } - - /** - * 进路是否包含该区段(可以是逻辑区段) - */ - public boolean containSection(Section section) { - for (Section section1 : sectionList) { - if (section1.equals(section)) { - return true; - } - List
logicList = section1.getLogicList(); - if (!CollectionUtils.isEmpty(logicList)) { - if (logicList.stream().anyMatch(logicSection -> logicSection.equals(section))) { - return true; - } - } - } - return false; - } - - /** - * 获取进路的所有子区段 - */ - public List
getLogicSections() { - List
sections = new ArrayList<>(); - for (Section section : sectionList) { - if (CollectionUtils.isEmpty(section.getLogicList())) { - sections.add(section); - } else { - sections.addAll(section.getLogicList()); - } - } - return sections; - } - - public boolean routeLastSection(Section section) { - return Objects.equals(this.sectionList.get(sectionList.size() - 1), section); - } - - public boolean isTransferRoute() { - return this.sectionList.stream().anyMatch(Section::isTransferTrack); - } - - public boolean isRight() { - return this.start.isRight(); - } - - public boolean isConflictConfirmed() { - return this.conflictAlarm != null && this.conflictAlarm.isConfirmed(); - } - - public boolean isConflictHandleRunAsPlan() { - return this.conflictAlarm != null && Route.Conflict_Handle_Way_1 == this.conflictAlarm.getConfirmParam(); - } - - public RouteOverrun findOverrunBySwitch(Switch relSwitch) { - if (!CollectionUtils.isEmpty(this.overrunList)) { - for (RouteOverrun overrun : overrunList) { - if (overrun.getASwitch().equals(relSwitch)) { - return overrun; - } - } - } - return null; - } - - public void unlockRouteFlsOfSwitch(Switch relSwitch) { - RouteFls routeFls = this.queryRouteFlsOfSwitch(relSwitch); - if (routeFls != null && !routeFls.getBase().getASwitch().isRouteLock() && !routeFls.getBase().getASwitch().isOverlapLock()) { - routeFls.unlock(); - } - } - - /** - * 延续保护包含该道岔 - */ - public boolean overlapContainSwitch(Switch aSwitch) { - RouteOverlap overlap = this.getOverlap(); - if (overlap == null) - return false; - return overlap.containSwitch(aSwitch); - } - - public boolean overlapContainSection(Section section) { - RouteOverlap overlap = this.getOverlap(); - if (overlap == null) - return false; - return overlap.containSection(section); - } - - public boolean isSettingOverlap() { - if (this.overlap != null) { - if (this.getStart().isCbtcMode() && this.getDestination().isCbtcMode()) { - return this.getDestination().isCtcSetOverlap(); - } - return true; - } - return false; - } - - public boolean isDelayUnlocking() { - return this.delayUnlockDevice != null; - } - - public boolean isConflictSwitch(SwitchElement switchElement) { - for (SwitchElement element : this.switchList) { - if (element.isConflict(switchElement)) { - return true; - } - } - return false; - } - - /** - * 是否调车进路 - * - * @return 是否调车进路 - */ - public boolean isShutting() { - return Type.SHUNTING.equals(this.type) || Type.LONG_SHUNTING.equals(this.type); - } - - /** - * 是否列车进路 - */ - public boolean isTrainRoute() { - return Type.RECEIVING.equals(type) || Type.DEPARTURE.equals(type); - } - - public boolean isDepartureRoute() { - return Type.DEPARTURE.equals(type); - } - - /** - * 获取大铁进路的信号显示。 - */ - public SignalAspect getAspectOfRailway() { - if (!CollectionUtils.isEmpty(leaveSectionWithAspectMap)) { - for (Map.Entry entry : leaveSectionWithAspectMap.entrySet()) { - if (entry.getKey().isOccupied()) { - return entry.getValue(); - } - } - } - return getAspect(); - } - - public enum Type { - RECEIVING, //接车进路 - DEPARTURE, //发车进路 - SHUNTING, //调车进路 - PASS, //通过进路 - LONG_SHUNTING,// 长调车进路 - } - - /** - * 进路检查失败原因 - */ - public enum CheckFailReason { - /** - * 进路已经排列或正在排列 - */ - RouteSetting, - /** - * 敌对进路已排列 - */ - ConflictingRouteSetting, - /** - * 始端信号机封锁 - */ - StartSignalBlockade, - /** - * 始端信号机侧防锁闭 - */ - StartSignalFlankProtectLock, - /** - * 道岔封锁 - */ - SwitchBlockade, - /** - * 道岔引导总锁 - */ - SwitchGuideMasterLock, - /** - * 道岔锁闭的方向不对 - */ - SwitchLockPositionError, - /** - * 道岔被征用在相反位置 - */ - SwitchCiUseOnOppositePosition, - /** - * 道岔占用位置不对 - */ - SwitchOccupiedPositionError, - /** - * 道岔位置失表故障 - */ - SwitchFault, - /** - * 区段封锁 - */ - SectionBlockade, - /** - * 区段锁闭在相反方向 - */ - SectionLockOppositeDirection, - /** - * 区段不空闲 - */ - SectionNotFree, - /** - * 区段故障占用 - */ - SectionFaultOccupied, - /** - * 站台紧急停车按钮按下 - */ - ESPEffective, - /** - * 延续保护道岔/区段占用 - */ - OverlapOccupy, - /** - * 延续保护道岔锁闭在错误的方向 - */ - OverlapLockWrongPosition, - /** - * 处于自动进路/自动折返状态 - */ - FleetOrTurnBackMode, - /** - * 区间运行方向限制 - */ - DirectionRodLimit, - } - - /** - * 进路排列检查失败消息 - */ - @Getter - public static class CheckFailMessage { - /** - * 失败原因 - */ - private CheckFailReason reason; - - /** - * 设备编号 - */ - private MapNamedElement device; - - public CheckFailMessage(CheckFailReason reason, MapNamedElement device) { - this.reason = reason; - this.device = device; - } - - public String toJson() { - Map map = new HashMap<>(); - map.put("reason", this.reason); - if (Objects.nonNull(this.device)) { - map.put("code", this.device.getCode()); - map.put("name", this.device.getName()); - } - return JsonUtils.writeValueAsString(map); - } - - public String debugStr() { - return String.format("设备%s,失败原因:%s", this.device.debugStr(), this.reason); - } - } - - @Getter - public static class MultiRouteAspect { - private Route route; - - /** - * route在该组合进路中的信号显示。(暂时没用) - */ - private SignalAspect aspect; - - public MultiRouteAspect(Route route, SignalAspect aspect) { - this.route = route; - this.aspect = aspect; - } - } - -} +package club.joylink.rtss.simulation.cbtc.data.map; + +import club.joylink.rtss.exception.BusinessExceptionAssertEnum; +import club.joylink.rtss.simulation.cbtc.ATS.data.AtsAlarm; +import club.joylink.rtss.simulation.cbtc.constant.SignalAspect; +import club.joylink.rtss.simulation.cbtc.data.vo.TrainInfo; +import club.joylink.rtss.simulation.cbtc.exception.SimulationException; +import club.joylink.rtss.simulation.cbtc.exception.SimulationExceptionType; +import club.joylink.rtss.util.JsonUtils; +import lombok.Getter; +import lombok.Setter; +import org.springframework.util.CollectionUtils; + +import java.time.LocalDateTime; +import java.util.*; + +/** + * 进路 + */ +@Getter +@Setter +public class Route extends MapNamedElement { + + public Route(String code, String name) { + super(code, name, DeviceType.ROUTE); + this.atsControl = true; + this.psdList = new ArrayList<>(); + this.espList = new ArrayList<>(); + this.conflictingRouteList = new ArrayList<>(); + this.sectionList = new ArrayList<>(); + this.switchList = new ArrayList<>(); + } + + // ------------------固有属性/关联关系--------------------- + + /** + * 所属联锁区 + */ + private Station interlockStation; + + /** + * 是否折返进路 + */ + private boolean turnBack; + + /** + * 是否ATP进路 + */ + private boolean atp; + + /** + * 是否地面信号进路 + */ + private boolean ground; + + /** + * 是否引导进路 + */ + private boolean guide; + + /** + * 连续通过进路/车队模式进路(联锁自动进路) + */ + private boolean flt; + + /** + * 自动排列(联锁自动触发) + */ + private boolean ars; + + /** + * 始端信号机 + */ + private Signal start; + + /** + * 终端信号机 + */ + private Signal destination; + + /** + * 信号显示 + */ + private SignalAspect aspect; + + /** + * 进路区段 + */ + private List
sectionList; + + /** + * 进路道岔 + */ + private List switchList; + + /** + * 进路侧防元件 + */ + private List flsList; + + /** + * 站台屏蔽门 + */ + private List psdList; + + /** + * 站台紧急停车按钮 + */ + private List espList; + + /** + * 站台扣车 + */ + private List standHoldList; + + /** + * CTC模式下需要办理延续保护 + */ + @Deprecated + private boolean setOverlapInCtc = true; + + /** + * 进路延续保护 + */ + private RouteOverlap overlap; + + /** + * 超限区段列表 + */ + private List overrunList; + + /** + * 敌对进路 + */ + private List conflictingRouteList; + + /** + * 进路终端按钮信号机 + */ + private Signal destinationButtonSignal; + + /** + * 组合进路中的所有单进路 + */ + private List multiRouteAspects; + + /** + * 进路类型(大铁) + */ + private Type type; + + /** + * 当离去区段占用时的信号显示 + */ + private LinkedHashMap leaveSectionWithAspectMap; + + // ------------------状态属性--------------------- + /** + * ats自动控制 + */ + private boolean atsControl; + + /** + * 连续通过进路模式(联锁自动进路)开启 + */ + private boolean fleetMode; + + /** + * 自动追踪/联锁自动触发模式开启 + */ + private boolean ciControl; + + /** + * 进路是否可以排列 + */ + private boolean settable; + + /** + * 进路是否排列中 + */ + private boolean setting; + /** + * 该进路办理成功后要开放的信号 + *

+ * 注意:每次开始触发办理进路时设置 + */ + private SignalAspect settedAspect; + /** + * 进路开始排列时间 + */ + private LocalDateTime settingStartTime; + + /** + * 是否引导进路排列中 + */ + private boolean guideSetting; + + /** + * 进路是否锁闭 + */ + private boolean lock; + + /** + * 进路延时解锁设备 + */ + private DelayUnlockDevice delayUnlockDevice; + + /** + * 是否正常解锁中 + */ + private boolean normalUnlock; + + /** + * 正常解锁到的区段 + */ + private Section unlockedSection; + + /** + * 进路将要或上一次为哪辆列车排列 + */ + @Deprecated + private TrainInfo train; + /** + * 检查冲突功能是否开启 + */ + private boolean checkConflict; + /** + * 冲突告警 + */ + private AtsAlarm conflictAlarm; + /** + * 按计划执行 + */ + public static final int Conflict_Handle_Way_1 = 1; + /** + * 执行冲突进路 + */ + public static final int Conflict_Handle_Way_2 = 2; + + /** + * 大铁进路排列车次信息 + */ + private String tripNumber; + + @Override + public void reset() { + this.atsControl = true; + this.fleetMode = false; + this.ciControl = false; + this.settable = false; + this.setting = false; + this.guideSetting = false; + this.lock = false; + this.delayUnlockDevice = null; + this.normalUnlock = false; + this.unlockedSection = null; + this.train = null; + this.checkConflict = false; + this.settedAspect=null; + } + /** + * 是否是组合进路 + */ + public boolean isMultiRoute() { + return null!=this.multiRouteAspects&&!this.multiRouteAspects.isEmpty(); + } + public boolean isAllSwitchIsOnPos() { + if (!CollectionUtils.isEmpty(switchList)) { + return switchList.stream().allMatch(SwitchElement::isOnPosition); + } + return true; + } + + /** + * 进路是否开放(进路是否锁闭,并开放指定信号灯) + * + * @return + */ + public boolean isOpenMain() { + return this.lock && this.aspect.equals(this.start.getAspect()); + } + + /** + * 进路是否开放引导信号 + * + * @return + */ + public boolean isOpenGuide() { + return this.lock && (this.start.isGuideAspect()); + } + + public void setAtsControl(boolean atsControl) { + this.atsControl = atsControl; + if (!atsControl) + this.checkConflict = false; + } + + /** + * 选择合适的进路延续保护区段 + * + * @return + */ + public SectionPath selectOverlapElement() { + if (Objects.nonNull(this.overlap)) { + return this.overlap.selectPath(); + } + return null; + } + + public Section getFirstRouteSection() { + return this.sectionList.get(0); + } + + /** + * 获取第一个逻辑区段 + */ + public Section getFirstLogicSection() { + Section firstSection = getFirstRouteSection(); + List

logicList = firstSection.getLogicList(); + if (CollectionUtils.isEmpty(logicList)) { + return firstSection; + } else { + boolean right = start.isRight(); + if (right) { + return logicList.get(0); + } else { + return logicList.get(logicList.size() - 1); + } + } + } + + public Section getFirstPhysicalSection() { + Section section = getFirstLogicSection(); + if (section.isPhysical()) + return section; + for (int i = 0; i < 10; i++) { + section = section.getParent(); + BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertNotNull(section, + debugStr() + "未找到第一个物理区段"); + if (section.isPhysical()) + return section; + } + throw BusinessExceptionAssertEnum.DATA_NOT_EXIST.exception(debugStr() + "未找到第一个物理区段"); + } + + /** + * 获取进路内最后一个子进路区段 + * + * @return + */ + public Section getLastRouteSection() { + return this.sectionList.get(this.sectionList.size() - 1); + } + + /** + * 进路是否直向进路 + * + * @return true-直向(进路中道岔定位),false-侧向(进路中道岔反位) + */ + public boolean isStraight() { + if (CollectionUtils.isEmpty(this.switchList)) { + return true; + } else { + for (SwitchElement switchElement : this.switchList) { + if (!switchElement.isNormal()) { + return false; + } + } + } + return true; + } + + /** + * 是否进路区段 + * + * @param section-计轴区段/道岔区段,非逻辑区段 + * @return + */ + public boolean isRouteSection(Section section) { + for (Section rs : this.sectionList) { + if (Objects.equals(rs.getCode(), section.getCode())) { + return true; + } + } + return false; + } + + public boolean isRouteSection(String sectionCode) { + for (Section rs : this.sectionList) { + if (Objects.equals(rs.getCode(), sectionCode)) { + return true; + } + } + return false; + } + + /** + * 是否进路道岔 + * + * @param aSwitch + * @return + */ + public boolean isRouteSwitch(Switch aSwitch) { + for (SwitchElement element : this.switchList) { + if (Objects.equals(element.getASwitch(), aSwitch)) { + return true; + } + } + return false; + } + + public boolean isApproachLock() { + return this.isOpenMain() && this.getStart().isApproachLock(); + } + + public boolean isAnySectionOccupied() { + for (Section section : this.sectionList) { + if (section.isOccupied()) { + return true; + } + } + return false; + } + + /** + * 折返轨占用 + */ + public boolean isAnyTBSectionOccupied() { + for (Section section : this.sectionList) { + if (section.isOccupied() && section.isTurnBackTrack()) { + return true; + } + } + return false; + } + + public boolean isAnySectionOppositeTrainOccupied() { + for (Section section : this.sectionList) { + if (section.isOccupied() && !Objects.equals(start.isRight(), section.isTrainRight())) { + return true; + } + } + return false; + } + + public boolean containConflictRoute(Route route) { + if (!CollectionUtils.isEmpty(this.conflictingRouteList) && + this.conflictingRouteList.contains(route)) { + return true; + } + return false; + } + + public boolean containSameSection(List
sectionList) { + if (!CollectionUtils.isEmpty(sectionList)) { + for (Section section1 : this.sectionList) { + for (Section section2 : sectionList) { + if (Objects.equals(section1, section2)) { + return true; + } + } + } + } + return false; + } + + /** + * 是否包含方向不同的冲突道岔 + * + * @param list + * @return + */ + public boolean containConflictSwitch(List list) { + if (!CollectionUtils.isEmpty(list) && !CollectionUtils.isEmpty(this.switchList)) { + for (SwitchElement se1 : this.switchList) { + for (SwitchElement se2 : list) { + if (Objects.equals(se1.getASwitch(), se2.getASwitch()) && + !Objects.equals(se1.isNormal(), se2.isNormal())) { + return true; + } + } + } + } + return false; + } + + public void addConflictRoute(Route conflict) { + if (!this.conflictingRouteList.contains(conflict)) { + this.conflictingRouteList.add(conflict); + } + } + + public boolean isTriggerSection(String sectionCode) { + return this.start.isApproachSection(sectionCode); + } + + public SwitchElement queryRouteSwitchElement(Switch aSwitch) { + for (SwitchElement element : this.switchList) { + if (Objects.equals(element.getASwitch(), aSwitch)) { + return element; + } + } + return null; + } + + public SwitchElement getRouteSwitchElement(Switch aSwitch) { + SwitchElement switchElement = this.queryRouteSwitchElement(aSwitch); + if (Objects.isNull(switchElement)) { + throw new SimulationException(SimulationExceptionType.System_Fault); + } + return switchElement; + } + + public int getDelayReleaseTime() { + return this.getStart().getRouteReleaseTime(); + } + + public boolean isConflictWith(Route route2) { + if (this.containConflictRoute(route2)) { + return true; + } + if (this.containConflictSwitch(route2.getSwitchList())) { + return true; + } + if (route2.getOverlap() != null && route2.getOverlap().isOnlyOnePath() && + this.containConflictSwitch(route2.getOverlap().getFirstPath().getSwitchList())) { + return true; + } + if (this.getOverlap() != null && this.getOverlap().isOnlyOnePath() && + route2.containConflictSwitch(this.getOverlap().getFirstPath().getSwitchList())) { + return true; + } + return false; + } + + /** + * 存在反位道岔 + * + * @return + */ + public boolean hasReverseSwitch() { + for (SwitchElement element : this.switchList) { + if (!element.isNormal()) { + return true; + } + } + return false; + } + + public void startNormalUnlock() { + this.setSetting(false); + this.unlockedSection = this.sectionList.get(0); + // 进路解锁开始信号 + this.normalUnlock = true; + this.setLock(false); + } + + public void updateUnlockedSection(Section section) { + this.unlockedSection = section; + } + + public void normalUnlockOver() { + this.normalUnlock = false; + this.unlockedSection = null; + } + + public void startSetting(LocalDateTime systemTime) { + this.normalUnlock = false; + this.setSetting(true); + this.settingStartTime = systemTime; + this.setGuideSetting(false); + } + + public void startGuideSetting(LocalDateTime systemTime) { + this.normalUnlock = false; + this.setSetting(true); + this.settingStartTime = systemTime; + this.setGuideSetting(true); + } + + public void settingOver() { + this.setSetting(false); + if (this.overlap != null) { + this.overlap.settingOver(); + } + } + + public void setLock(boolean lock) { + this.lock = lock; + if (lock) { + this.start.setLockedRoute(this); + } else if (this == this.start.getLockedRoute()) { + this.start.setLockedRoute(null); + } + } + + public int getReverseSwitchQuantity() { + int quantity = 0; + if (!CollectionUtils.isEmpty(this.switchList)) { + for (SwitchElement element : this.switchList) { + if (!element.isNormal()) { + ++quantity; + } + } + } + return quantity; + } + + public boolean isCiTrigger() { + List approachPathList = this.start.getApproachPathList(); + for (SectionPath sectionPath : approachPathList) { + //检查区段占用 + List
sectionList = sectionPath.getSectionList(); + boolean sectionOccupied = false; + for (Section section : sectionList) { + if (section.isOccupiedOn(this.getStart().isRight())) { + sectionOccupied = true; + break; + } + } + if (!sectionOccupied) + continue; + //检查道岔位置 + if (CollectionUtils.isEmpty(sectionPath.getSwitchList())) { + boolean switchOnPosition = true; + for (SwitchElement switchElement : sectionPath.getSwitchList()) { + if (!switchElement.isOnPosition()) { + switchOnPosition = false; + break; + } + } + if (!switchOnPosition) + continue; + } + + return true; + } + return false; + } + + public boolean containsRoutePosFaultSwitch() { + if (!CollectionUtils.isEmpty(this.switchList)) { + for (SwitchElement element : this.switchList) { + Switch aSwitch = element.getASwitch(); + if (aSwitch.isFault() && + (Switch.SwitchFault.SPLIT.equals(aSwitch.getFault()) || + (element.isNormal() && Switch.SwitchFault.NORMAL_SPLIT.equals(aSwitch.getFault())) || + (!element.isNormal() && Switch.SwitchFault.REVERSE_SPLIT.equals(aSwitch.getFault())))) { + return true; + } + } + } + return false; + } + + public boolean isLastRouteSection(Section section) { + return Objects.equals(this.getLastRouteSection(), section); + } + + public RouteFls queryRouteFlsOfSwitch(Switch aSwitch) { + if (!CollectionUtils.isEmpty(this.flsList)) { + for (RouteFls routeFls : flsList) { + if (Objects.equals(routeFls.getBase().getASwitch(), aSwitch)) { + return routeFls; + } + } + } + return null; + } + + /** + * 进路是否包含该区段(可以是逻辑区段) + */ + public boolean containSection(Section section) { + for (Section section1 : sectionList) { + if (section1.equals(section)) { + return true; + } + List
logicList = section1.getLogicList(); + if (!CollectionUtils.isEmpty(logicList)) { + if (logicList.stream().anyMatch(logicSection -> logicSection.equals(section))) { + return true; + } + } + } + return false; + } + + /** + * 获取进路的所有子区段 + */ + public List
getLogicSections() { + List
sections = new ArrayList<>(); + for (Section section : sectionList) { + if (CollectionUtils.isEmpty(section.getLogicList())) { + sections.add(section); + } else { + sections.addAll(section.getLogicList()); + } + } + return sections; + } + + public boolean routeLastSection(Section section) { + return Objects.equals(this.sectionList.get(sectionList.size() - 1), section); + } + + public boolean isTransferRoute() { + return this.sectionList.stream().anyMatch(Section::isTransferTrack); + } + + public boolean isRight() { + return this.start.isRight(); + } + + public boolean isConflictConfirmed() { + return this.conflictAlarm != null && this.conflictAlarm.isConfirmed(); + } + + public boolean isConflictHandleRunAsPlan() { + return this.conflictAlarm != null && Route.Conflict_Handle_Way_1 == this.conflictAlarm.getConfirmParam(); + } + + public RouteOverrun findOverrunBySwitch(Switch relSwitch) { + if (!CollectionUtils.isEmpty(this.overrunList)) { + for (RouteOverrun overrun : overrunList) { + if (overrun.getASwitch().equals(relSwitch)) { + return overrun; + } + } + } + return null; + } + + public void unlockRouteFlsOfSwitch(Switch relSwitch) { + RouteFls routeFls = this.queryRouteFlsOfSwitch(relSwitch); + if (routeFls != null && !routeFls.getBase().getASwitch().isRouteLock() && !routeFls.getBase().getASwitch().isOverlapLock()) { + routeFls.unlock(); + } + } + + /** + * 延续保护包含该道岔 + */ + public boolean overlapContainSwitch(Switch aSwitch) { + RouteOverlap overlap = this.getOverlap(); + if (overlap == null) + return false; + return overlap.containSwitch(aSwitch); + } + + public boolean overlapContainSection(Section section) { + RouteOverlap overlap = this.getOverlap(); + if (overlap == null) + return false; + return overlap.containSection(section); + } + + public boolean isSettingOverlap() { + if (this.overlap != null) { + if (this.getStart().isCbtcMode() && this.getDestination().isCbtcMode()) { + return this.getDestination().isCtcSetOverlap(); + } + return true; + } + return false; + } + + public boolean isDelayUnlocking() { + return this.delayUnlockDevice != null; + } + + public boolean isConflictSwitch(SwitchElement switchElement) { + for (SwitchElement element : this.switchList) { + if (element.isConflict(switchElement)) { + return true; + } + } + return false; + } + + /** + * 是否调车进路 + * + * @return 是否调车进路 + */ + public boolean isShutting() { + return Type.SHUNTING.equals(this.type) || Type.LONG_SHUNTING.equals(this.type); + } + + /** + * 是否列车进路 + */ + public boolean isTrainRoute() { + return Type.RECEIVING.equals(type) || Type.DEPARTURE.equals(type); + } + + public boolean isDepartureRoute() { + return Type.DEPARTURE.equals(type); + } + + /** + * 获取大铁进路的信号显示。 + */ + public SignalAspect getAspectOfRailway() { + if (!CollectionUtils.isEmpty(leaveSectionWithAspectMap)) { + for (Map.Entry entry : leaveSectionWithAspectMap.entrySet()) { + if (entry.getKey().isOccupied()) { + return entry.getValue(); + } + } + } + return getAspect(); + } + + public enum Type { + RECEIVING, //接车进路 + DEPARTURE, //发车进路 + SHUNTING, //调车进路 + PASS, //通过进路 + LONG_SHUNTING,// 长调车进路 + } + + /** + * 进路检查失败原因 + */ + public enum CheckFailReason { + /** + * 进路已经排列或正在排列 + */ + RouteSetting, + /** + * 敌对进路已排列 + */ + ConflictingRouteSetting, + /** + * 始端信号机封锁 + */ + StartSignalBlockade, + /** + * 始端信号机侧防锁闭 + */ + StartSignalFlankProtectLock, + /** + * 道岔封锁 + */ + SwitchBlockade, + /** + * 道岔引导总锁 + */ + SwitchGuideMasterLock, + /** + * 道岔锁闭的方向不对 + */ + SwitchLockPositionError, + /** + * 道岔被征用在相反位置 + */ + SwitchCiUseOnOppositePosition, + /** + * 道岔占用位置不对 + */ + SwitchOccupiedPositionError, + /** + * 道岔位置失表故障 + */ + SwitchFault, + /** + * 区段封锁 + */ + SectionBlockade, + /** + * 区段锁闭在相反方向 + */ + SectionLockOppositeDirection, + /** + * 区段不空闲 + */ + SectionNotFree, + /** + * 区段故障占用 + */ + SectionFaultOccupied, + /** + * 站台紧急停车按钮按下 + */ + ESPEffective, + /** + * 延续保护道岔/区段占用 + */ + OverlapOccupy, + /** + * 延续保护道岔锁闭在错误的方向 + */ + OverlapLockWrongPosition, + /** + * 处于自动进路/自动折返状态 + */ + FleetOrTurnBackMode, + /** + * 区间运行方向限制 + */ + DirectionRodLimit, + } + + /** + * 进路排列检查失败消息 + */ + @Getter + public static class CheckFailMessage { + /** + * 失败原因 + */ + private CheckFailReason reason; + + /** + * 设备编号 + */ + private MapNamedElement device; + + public CheckFailMessage(CheckFailReason reason, MapNamedElement device) { + this.reason = reason; + this.device = device; + } + + public String toJson() { + Map map = new HashMap<>(); + map.put("reason", this.reason); + if (Objects.nonNull(this.device)) { + map.put("code", this.device.getCode()); + map.put("name", this.device.getName()); + } + return JsonUtils.writeValueAsString(map); + } + + public String debugStr() { + return String.format("设备%s,失败原因:%s", this.device.debugStr(), this.reason); + } + } + + @Getter + public static class MultiRouteAspect { + private Route route; + + /** + * route在该组合进路中的信号显示。(暂时没用) + */ + private SignalAspect aspect; + + public MultiRouteAspect(Route route, SignalAspect aspect) { + this.route = route; + this.aspect = aspect; + } + } + +} diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/data/storage/device/StorageRoute.java b/src/main/java/club/joylink/rtss/simulation/cbtc/data/storage/device/StorageRoute.java index 755c350ac..471647ab9 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/data/storage/device/StorageRoute.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/data/storage/device/StorageRoute.java @@ -1,177 +1,191 @@ -package club.joylink.rtss.simulation.cbtc.data.storage.device; - -import club.joylink.rtss.simulation.cbtc.Simulation; -import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository; -import club.joylink.rtss.simulation.cbtc.data.map.DelayUnlockDevice; -import club.joylink.rtss.simulation.cbtc.data.map.MapElement; -import club.joylink.rtss.simulation.cbtc.data.map.Route; -import club.joylink.rtss.simulation.cbtc.data.map.Section; -import club.joylink.rtss.util.jsonSerialize.Boolean2NumDeserializer; -import club.joylink.rtss.util.jsonSerialize.Boolean2NumSerializer; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import java.time.LocalDateTime; -import java.util.Objects; - -@Getter -@Setter -@NoArgsConstructor -public class StorageRoute extends StorageDevice { - - /** - * 是否CBTC模式 - */ - @JsonSerialize(using = Boolean2NumSerializer.class) - @JsonDeserialize(using = Boolean2NumDeserializer.class) - private Boolean cbtcMode; - - /** - * ats自动控制 - */ - @JsonSerialize(using = Boolean2NumSerializer.class) - @JsonDeserialize(using = Boolean2NumDeserializer.class) - private Boolean atsControl; - - /** - * 连续通过进路模式(联锁自动进路)开启 - */ - @JsonSerialize(using = Boolean2NumSerializer.class) - @JsonDeserialize(using = Boolean2NumDeserializer.class) - private Boolean fleetMode; - - /** - * 自动追踪/联锁自动触发模式开启 - */ - @JsonSerialize(using = Boolean2NumSerializer.class) - @JsonDeserialize(using = Boolean2NumDeserializer.class) - private Boolean ciControl; - - /** - * 进路是否排列中 - */ - @JsonSerialize(using = Boolean2NumSerializer.class) - @JsonDeserialize(using = Boolean2NumDeserializer.class) - private Boolean setting; - - private LocalDateTime settingStartTime; - - /** - * 是否引导进路排列 - */ - @JsonSerialize(using = Boolean2NumSerializer.class) - @JsonDeserialize(using = Boolean2NumDeserializer.class) - private Boolean settingGuide; - - /** - * 进路是否锁闭 - */ - @JsonSerialize(using = Boolean2NumSerializer.class) - @JsonDeserialize(using = Boolean2NumDeserializer.class) - private Boolean lock; - - /** 进路延时解锁设备 */ - private String delayUnlockDevice; - - /** - * 是否正常解锁中 - */ - @JsonSerialize(using = Boolean2NumSerializer.class) - @JsonDeserialize(using = Boolean2NumDeserializer.class) - private Boolean normalUnlock; - - private String unlockedSection; - -// public StorageRoute(Route route) { -// super(route.getCode()); -// cbtcMode = route.isCbtcMode(); -// turnBackMode = route.isTurnBackMode(); -// atsControl = route.isAtsControl(); -// fleetMode = route.isFleetMode(); -// ciControl = route.isCiControl(); -// setting = route.isSetting(); -// settingGuide = route.isSettingGuide(); -// lock = route.isLock(); -// canceling = route.isCanceling(); -// normalUnlock = route.isNormalUnlock(); -// } - - public StorageRoute(String code) { - super(code); - } - - public static StorageRoute convert2Storage(Route route) { - StorageRoute storageRoute = new StorageRoute(route.getCode()); - if (storageRoute.convert(route)) { - return storageRoute; - } - return null; - } - - @Override - public boolean convert(MapElement element) { - boolean change = false; - Route route = (Route) element; - if (!route.isAtsControl()) { - change = true; - this.setAtsControl(route.isAtsControl()); - } - if (route.isFleetMode()) { - change = true; - this.setFleetMode(route.isFleetMode()); - } - if (route.isCiControl()) { - change = true; - this.setCiControl(route.isCiControl()); - } - if (route.isSetting()) { - change = true; - this.setSetting(route.isSetting()); - this.setSettingStartTime(route.getSettingStartTime()); - } - if (route.isGuideSetting()) { - change = true; - this.setSettingGuide(route.isGuideSetting()); - } - if (route.isLock()) { - change = true; - this.setLock(route.isLock()); - } - if (route.getDelayUnlockDevice() != null) { - change = true; - this.setDelayUnlockDevice(route.getDelayUnlockDevice().getCode()); - } - if (route.isNormalUnlock()) { - change = true; - this.setNormalUnlock(route.isNormalUnlock()); - } - if (Objects.nonNull(route.getUnlockedSection())) { - change = true; - this.setUnlockedSection(route.getUnlockedSection().getCode()); - } - return change; - } - - @Override - public void recover2Simulation(MapElement element, Simulation simulation, SimulationDataRepository repository) { - Route route = (Route) element; - route.setAtsControl(atsControl != null ? atsControl : true); - route.setFleetMode(fleetMode != null ? fleetMode : false); - route.setCiControl(ciControl != null ? ciControl : false); - route.setSetting(setting != null? setting : false); - route.setSettingStartTime(this.settingStartTime); - route.setGuideSetting(settingGuide != null? settingGuide : false); - route.setLock(lock != null ? lock : false); - if (this.delayUnlockDevice != null) { - route.setDelayUnlockDevice((DelayUnlockDevice) repository.getByCode(this.delayUnlockDevice)); - } - route.setNormalUnlock(normalUnlock != null ? normalUnlock : false); - if (Objects.nonNull(this.unlockedSection)) { - route.setUnlockedSection(repository.getByCode(this.unlockedSection, Section.class)); - } - } - -} +package club.joylink.rtss.simulation.cbtc.data.storage.device; + +import club.joylink.rtss.simulation.cbtc.Simulation; +import club.joylink.rtss.simulation.cbtc.constant.SignalAspect; +import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository; +import club.joylink.rtss.simulation.cbtc.data.map.DelayUnlockDevice; +import club.joylink.rtss.simulation.cbtc.data.map.MapElement; +import club.joylink.rtss.simulation.cbtc.data.map.Route; +import club.joylink.rtss.simulation.cbtc.data.map.Section; +import club.joylink.rtss.util.jsonSerialize.Boolean2NumDeserializer; +import club.joylink.rtss.util.jsonSerialize.Boolean2NumSerializer; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.time.LocalDateTime; +import java.util.Objects; + +@Getter +@Setter +@NoArgsConstructor +public class StorageRoute extends StorageDevice { + + /** + * 是否CBTC模式 + */ + @JsonSerialize(using = Boolean2NumSerializer.class) + @JsonDeserialize(using = Boolean2NumDeserializer.class) + private Boolean cbtcMode; + + /** + * ats自动控制 + */ + @JsonSerialize(using = Boolean2NumSerializer.class) + @JsonDeserialize(using = Boolean2NumDeserializer.class) + private Boolean atsControl; + + /** + * 连续通过进路模式(联锁自动进路)开启 + */ + @JsonSerialize(using = Boolean2NumSerializer.class) + @JsonDeserialize(using = Boolean2NumDeserializer.class) + private Boolean fleetMode; + + /** + * 自动追踪/联锁自动触发模式开启 + */ + @JsonSerialize(using = Boolean2NumSerializer.class) + @JsonDeserialize(using = Boolean2NumDeserializer.class) + private Boolean ciControl; + + /** + * 进路是否排列中 + */ + @JsonSerialize(using = Boolean2NumSerializer.class) + @JsonDeserialize(using = Boolean2NumDeserializer.class) + private Boolean setting; + + private LocalDateTime settingStartTime; + + /** + * 是否引导进路排列 + */ + @JsonSerialize(using = Boolean2NumSerializer.class) + @JsonDeserialize(using = Boolean2NumDeserializer.class) + private Boolean settingGuide; + + /** + * 进路是否锁闭 + */ + @JsonSerialize(using = Boolean2NumSerializer.class) + @JsonDeserialize(using = Boolean2NumDeserializer.class) + private Boolean lock; + + /** 进路延时解锁设备 */ + private String delayUnlockDevice; + + /** + * 是否正常解锁中 + */ + @JsonSerialize(using = Boolean2NumSerializer.class) + @JsonDeserialize(using = Boolean2NumDeserializer.class) + private Boolean normalUnlock; + + private String unlockedSection; + + /** + * 该进路办理成功后要开放的信号 + *

+ * 注意:每次开始触发办理进路时设置 + */ + private SignalAspect settedAspect; + +// public StorageRoute(Route route) { +// super(route.getCode()); +// cbtcMode = route.isCbtcMode(); +// turnBackMode = route.isTurnBackMode(); +// atsControl = route.isAtsControl(); +// fleetMode = route.isFleetMode(); +// ciControl = route.isCiControl(); +// setting = route.isSetting(); +// settingGuide = route.isSettingGuide(); +// lock = route.isLock(); +// canceling = route.isCanceling(); +// normalUnlock = route.isNormalUnlock(); +// } + + public StorageRoute(String code) { + super(code); + } + + public static StorageRoute convert2Storage(Route route) { + StorageRoute storageRoute = new StorageRoute(route.getCode()); + if (storageRoute.convert(route)) { + return storageRoute; + } + return null; + } + + @Override + public boolean convert(MapElement element) { + boolean change = false; + Route route = (Route) element; + if (!route.isAtsControl()) { + change = true; + this.setAtsControl(route.isAtsControl()); + } + if (route.isFleetMode()) { + change = true; + this.setFleetMode(route.isFleetMode()); + } + if (route.isCiControl()) { + change = true; + this.setCiControl(route.isCiControl()); + } + if (route.isSetting()) { + change = true; + this.setSetting(route.isSetting()); + this.setSettingStartTime(route.getSettingStartTime()); + } + if (route.isGuideSetting()) { + change = true; + this.setSettingGuide(route.isGuideSetting()); + } + if (route.isLock()) { + change = true; + this.setLock(route.isLock()); + } + if (route.getDelayUnlockDevice() != null) { + change = true; + this.setDelayUnlockDevice(route.getDelayUnlockDevice().getCode()); + } + if (route.isNormalUnlock()) { + change = true; + this.setNormalUnlock(route.isNormalUnlock()); + } + if (Objects.nonNull(route.getUnlockedSection())) { + change = true; + this.setUnlockedSection(route.getUnlockedSection().getCode()); + } + if (Objects.nonNull(route.getSettedAspect())) { + change = true; + this.setSettedAspect(route.getSettedAspect()); + } + + return change; + } + + @Override + public void recover2Simulation(MapElement element, Simulation simulation, SimulationDataRepository repository) { + Route route = (Route) element; + route.setAtsControl(atsControl != null ? atsControl : true); + route.setFleetMode(fleetMode != null ? fleetMode : false); + route.setCiControl(ciControl != null ? ciControl : false); + route.setSetting(setting != null? setting : false); + route.setSettingStartTime(this.settingStartTime); + route.setGuideSetting(settingGuide != null? settingGuide : false); + route.setLock(lock != null ? lock : false); + if (this.delayUnlockDevice != null) { + route.setDelayUnlockDevice((DelayUnlockDevice) repository.getByCode(this.delayUnlockDevice)); + } + route.setNormalUnlock(normalUnlock != null ? normalUnlock : false); + if (Objects.nonNull(this.unlockedSection)) { + route.setUnlockedSection(repository.getByCode(this.unlockedSection, Section.class)); + } + route.setSettedAspect(settedAspect); + } + +} diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/depot/DepotService.java b/src/main/java/club/joylink/rtss/simulation/cbtc/depot/DepotService.java index fc062bcf6..8c6a6dba2 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/depot/DepotService.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/depot/DepotService.java @@ -1,236 +1,237 @@ -package club.joylink.rtss.simulation.cbtc.depot; - -import club.joylink.rtss.simulation.cbtc.ATS.tools.TrainOutboundLoadTool; -import club.joylink.rtss.simulation.cbtc.CI.device.CiRouteService; -import club.joylink.rtss.simulation.cbtc.GroupSimulationService; -import club.joylink.rtss.simulation.cbtc.Simulation; -import club.joylink.rtss.simulation.cbtc.command.CommandBO; -import club.joylink.rtss.simulation.cbtc.command.CommandInitiateVO; -import club.joylink.rtss.simulation.cbtc.constant.SimulationConstants; -import club.joylink.rtss.simulation.cbtc.constant.SimulationModule; -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.Station; -import club.joylink.rtss.simulation.cbtc.data.plan.SchedulingTrainPlan; -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.vo.TrainInfo; -import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityTrain; -import club.joylink.rtss.simulation.cbtc.member.SimulationMember; -import club.joylink.rtss.simulation.cbtc.onboard.ATP.ATPService; -import lombok.Getter; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import java.time.LocalDateTime; -import java.util.*; -import java.util.stream.Collectors; - -@Component -public class DepotService { - - @Autowired - private CiRouteService ciRouteService; - - @Autowired - private TrainOutboundLoadTool trainOutboundLoadTool; - - @Autowired - private GroupSimulationService groupSimulationService; - - @Autowired - private ATPService atpService; - - public void loadDepotTrain(Simulation simulation) { - if (!simulation.getRepository().getConfig().isHandleDepot()) { - return; - } - Map> parkingTracksMap = simulation.getRepository().getParkingTracksMap(); - simulation.getRepository().getAllVrTrain().stream() - .collect(Collectors.groupingBy(VirtualRealityTrain::getDepotStation)) - .forEach((station, trainList) -> { - List

sections = parkingTracksMap.get(station); - // 先加载内侧的停车轨 - sections.sort(Comparator.comparing(section -> - Objects.isNull(section.getLeftSection()) || Objects.isNull(section.getRightSection()))); - boolean right = sections.get(sections.size() - 1).getLeftSection() == null; - for (int i = 0, trainListSize = trainList.size(); i < trainListSize; i++) { - VirtualRealityTrain train = trainList.get(i); - Section section = sections.get(i); - train.initManualTrain(new SectionPosition(section, section.getStopPointByDirection(right)), right); - train.parkingAt(section); - train.initAsRM(); - TrainInfo trainInfo = TrainInfo.constructManualTrain(train); - trainInfo.tracking(train); - simulation.getRepository().addOnlineTrain(train); - simulation.getRepository().addTrainInfo(trainInfo); - } - }); - } - - public void addJobs(Simulation simulation) { - simulation.addJob(SimulationModule.DEPOT.name(), () -> this.run(simulation), SimulationConstants.DEPOT_LOOP_RATE); - } - - private void run(Simulation simulation) { - if (!simulation.isPlanRunning()) { - return; - } - if (!simulation.getRepository().getConfig().isHandleDepot()) { - trainOutboundLoadTool.loadOutboundTrain(simulation); - } else { - timeToDeparture(simulation); - backToParking(simulation); - settingRouteAndMoving(simulation); - arriveDestination(simulation); - } - } - - /** - * 根据时间筛选,从停车轨自动发车 - */ - private void timeToDeparture(Simulation simulation) { - LocalDateTime systemTime = simulation.getSystemTime(); - for (SchedulingTrainPlan schedulingTrainPlan : simulation.getRepository().getSchedulingTrainPlanList()) { - if (schedulingTrainPlan.getOutDepotTrip().isDispatched()) { - continue; - } - if (schedulingTrainPlan.getOutDepotTrip().getStartTime().minusMinutes(10).isBefore(systemTime.toLocalTime())) { - schedulingTrainPlan.getOutDepotTrip().dispatched(); - // 保存信息 - VirtualRealityTrain train = simulation.getRepository().getVRByCode(schedulingTrainPlan.getGroupNumber(), VirtualRealityTrain.class); - Section startSection = train.getHeadPosition().getSection(); - Section endSection = schedulingTrainPlan.getOutDepotTrip().getStartSection(); - List routePaths = simulation.getRepository().queryRoutePaths(startSection, endSection); - RoutePath routePath = routePaths.get(0); - DepotRunningInfo depotRunningInfo = new DepotRunningInfo(endSection, train, routePath, false); - simulation.getRepository().getDepotRunningInfoList().add(depotRunningInfo); - } - } - } - - /** - * 筛选入库 - */ - private void backToParking(Simulation simulation) { - for (TrainInfo trainInfo : simulation.getRepository().getTrainInfoMap().values()) { - if (trainInfo.isInbound() && trainInfo.isParking()) { - VirtualRealityTrain train = simulation.getRepository().getVRByCode(trainInfo.getGroupNumber(), VirtualRealityTrain.class); - if (train.getHeadPosition().getSection().isTransferTrack() - && train.getTailPosition().getSection().isTransferTrack()) { - if (simulation.getRepository().getDepotRunningInfoList().stream() - .anyMatch(depotRunningInfo -> depotRunningInfo.getTrain().equals(train))) { - continue; - } - train.initAsRM(); - Section startSection = train.getHeadPosition().getSection(); - Section endSection = null; - for (Section section : simulation.getRepository().getParkingTracksMap().get(startSection.getStation())) { - if (section.isOccupied()) { - continue; - } - if (section.getLeftSection() == null || section.getRightSection() == null) { - endSection = section; - } else if (section.getLeftSection().isParkingTrack() && !section.getLeftSection().isOccupied()) { - endSection = section.getLeftSection(); - } else if (section.getRightSection().isParkingTrack() && !section.getRightSection().isOccupied()) { - endSection = section.getRightSection(); - } else { - endSection = section; - } - break; - } -// train.setTarget(endSection); - List routePaths = simulation.getRepository().queryRoutePaths(startSection, endSection); - if (routePaths == null || routePaths.isEmpty()) { - return; - } - RoutePath routePath = routePaths.get(0); - DepotRunningInfo depotRunningInfo = new DepotRunningInfo(endSection, train, routePath, true); - simulation.getRepository().getDepotRunningInfoList().add(depotRunningInfo); - break; - } - } - } - } - - /** - * 列车排进路并运行 - */ - private void settingRouteAndMoving(Simulation simulation) { - for (DepotRunningInfo depotRunningInfo : simulation.getRepository().getDepotRunningInfoList()) { - Section endSection = depotRunningInfo.getEndSection(); - SectionPosition position = new SectionPosition(endSection, endSection.getStopPointByDirection(depotRunningInfo.getRight())); - depotRunningInfo.getTrain().setRobotTargetPosition(position); - if (!depotRunningInfo.getRouteList().isEmpty()) { - Route route = depotRunningInfo.getRouteList().get(0); - if (route.isLock()) { - depotRunningInfo.getRouteList().remove(0); - } - if (!route.isSetting()) { - ciRouteService.setRoute(simulation, route); - } - } - } - } - - /** - * 判断运行列车是否到达转换轨并升级 - */ - private void arriveDestination(Simulation simulation) { - for (Iterator iterator = simulation.getRepository().getDepotRunningInfoList().iterator(); iterator.hasNext(); ) { - DepotRunningInfo depotRunningInfo = iterator.next(); - VirtualRealityTrain train = depotRunningInfo.getTrain(); - if (depotRunningInfo.isArrival()) { - // 到达 - iterator.remove(); - if (depotRunningInfo.in) { - atpService.turnDirectionImmediately(train); - } else { - // 升级 - SimulationMember member = simulation.getSimulationMember(train, SimulationMember.Type.DRIVER); - Map param = new HashMap<>(); - param.put("preselectionMode", "AM_C"); - CommandInitiateVO commandInitiateVO = new CommandInitiateVO(CommandBO.CommandType.Change_Preselection_Mode, - member.getId(), param); - groupSimulationService.command(simulation, commandInitiateVO, member); - } - } - } - } - - @Getter - public static class DepotRunningInfo { - - private final List routeList = new ArrayList<>(); - - private final Section endSection; - - private final VirtualRealityTrain train; - - private final Boolean right; - - private final Boolean in; - - public DepotRunningInfo(Section endSection, VirtualRealityTrain train, RoutePath routePath, boolean in) { - this.endSection = endSection; - this.train = train; - for (Signal signal : routePath.getSignalList()) { - for (Route route : signal.getRouteList()) { - if (routePath.getRouteList().contains(route)) { - routeList.add(route); - } - } - } - this.right = routePath.isRight(); - this.in = in; - } - - // 列车是否到达终点 - public boolean isArrival() { - return train.getSpeed() == 0 && train.getHeadPosition().getSection().equals(endSection) - && train.getTailPosition().getSection().equals(endSection); - } - } -} +package club.joylink.rtss.simulation.cbtc.depot; + +import club.joylink.rtss.simulation.cbtc.ATS.tools.TrainOutboundLoadTool; +import club.joylink.rtss.simulation.cbtc.CI.device.CiRouteService; +import club.joylink.rtss.simulation.cbtc.GroupSimulationService; +import club.joylink.rtss.simulation.cbtc.Simulation; +import club.joylink.rtss.simulation.cbtc.command.CommandBO; +import club.joylink.rtss.simulation.cbtc.command.CommandInitiateVO; +import club.joylink.rtss.simulation.cbtc.constant.SimulationConstants; +import club.joylink.rtss.simulation.cbtc.constant.SimulationModule; +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.Station; +import club.joylink.rtss.simulation.cbtc.data.plan.SchedulingTrainPlan; +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.vo.TrainInfo; +import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityTrain; +import club.joylink.rtss.simulation.cbtc.member.SimulationMember; +import club.joylink.rtss.simulation.cbtc.onboard.ATP.ATPService; +import lombok.Getter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; + +@Component +public class DepotService { + + @Autowired + private CiRouteService ciRouteService; + + @Autowired + private TrainOutboundLoadTool trainOutboundLoadTool; + + @Autowired + private GroupSimulationService groupSimulationService; + + @Autowired + private ATPService atpService; + + public void loadDepotTrain(Simulation simulation) { + if (!simulation.getRepository().getConfig().isHandleDepot()) { + return; + } + Map> parkingTracksMap = simulation.getRepository().getParkingTracksMap(); + simulation.getRepository().getAllVrTrain().stream() + .collect(Collectors.groupingBy(VirtualRealityTrain::getDepotStation)) + .forEach((station, trainList) -> { + List
sections = parkingTracksMap.get(station); + // 先加载内侧的停车轨 + sections.sort(Comparator.comparing(section -> + Objects.isNull(section.getLeftSection()) || Objects.isNull(section.getRightSection()))); + boolean right = sections.get(sections.size() - 1).getLeftSection() == null; + for (int i = 0, trainListSize = trainList.size(); i < trainListSize; i++) { + VirtualRealityTrain train = trainList.get(i); + Section section = sections.get(i); + train.initManualTrain(new SectionPosition(section, section.getStopPointByDirection(right)), right); + train.parkingAt(section); + train.initAsRM(); + TrainInfo trainInfo = TrainInfo.constructManualTrain(train); + trainInfo.tracking(train); + simulation.getRepository().addOnlineTrain(train); + simulation.getRepository().addTrainInfo(trainInfo); + } + }); + } + + public void addJobs(Simulation simulation) { + simulation.addJob(SimulationModule.DEPOT.name(), () -> this.run(simulation), SimulationConstants.DEPOT_LOOP_RATE); + } + + private void run(Simulation simulation) { + if (!simulation.isPlanRunning()) { + return; + } + if (!simulation.getRepository().getConfig().isHandleDepot()) { + trainOutboundLoadTool.loadOutboundTrain(simulation); + } else { + timeToDeparture(simulation); + backToParking(simulation); + settingRouteAndMoving(simulation); + arriveDestination(simulation); + } + } + + /** + * 根据时间筛选,从停车轨自动发车 + */ + private void timeToDeparture(Simulation simulation) { + LocalDateTime systemTime = simulation.getSystemTime(); + for (SchedulingTrainPlan schedulingTrainPlan : simulation.getRepository().getSchedulingTrainPlanList()) { + if (schedulingTrainPlan.getOutDepotTrip().isDispatched()) { + continue; + } + if (schedulingTrainPlan.getOutDepotTrip().getStartTime().minusMinutes(10).isBefore(systemTime.toLocalTime())) { + schedulingTrainPlan.getOutDepotTrip().dispatched(); + // 保存信息 + VirtualRealityTrain train = simulation.getRepository().getVRByCode(schedulingTrainPlan.getGroupNumber(), VirtualRealityTrain.class); + Section startSection = train.getHeadPosition().getSection(); + Section endSection = schedulingTrainPlan.getOutDepotTrip().getStartSection(); + List routePaths = simulation.getRepository().queryRoutePaths(startSection, endSection); + RoutePath routePath = routePaths.get(0); + DepotRunningInfo depotRunningInfo = new DepotRunningInfo(endSection, train, routePath, false); + simulation.getRepository().getDepotRunningInfoList().add(depotRunningInfo); + } + } + } + + /** + * 筛选入库 + */ + private void backToParking(Simulation simulation) { + for (TrainInfo trainInfo : simulation.getRepository().getTrainInfoMap().values()) { + if (trainInfo.isInbound() && trainInfo.isParking()) { + VirtualRealityTrain train = simulation.getRepository().getVRByCode(trainInfo.getGroupNumber(), VirtualRealityTrain.class); + if (train.getHeadPosition().getSection().isTransferTrack() + && train.getTailPosition().getSection().isTransferTrack()) { + if (simulation.getRepository().getDepotRunningInfoList().stream() + .anyMatch(depotRunningInfo -> depotRunningInfo.getTrain().equals(train))) { + continue; + } + train.initAsRM(); + Section startSection = train.getHeadPosition().getSection(); + Section endSection = null; + for (Section section : simulation.getRepository().getParkingTracksMap().get(startSection.getStation())) { + if (section.isOccupied()) { + continue; + } + if (section.getLeftSection() == null || section.getRightSection() == null) { + endSection = section; + } else if (section.getLeftSection().isParkingTrack() && !section.getLeftSection().isOccupied()) { + endSection = section.getLeftSection(); + } else if (section.getRightSection().isParkingTrack() && !section.getRightSection().isOccupied()) { + endSection = section.getRightSection(); + } else { + endSection = section; + } + break; + } +// train.setTarget(endSection); + List routePaths = simulation.getRepository().queryRoutePaths(startSection, endSection); + if (routePaths == null || routePaths.isEmpty()) { + return; + } + RoutePath routePath = routePaths.get(0); + DepotRunningInfo depotRunningInfo = new DepotRunningInfo(endSection, train, routePath, true); + simulation.getRepository().getDepotRunningInfoList().add(depotRunningInfo); + break; + } + } + } + } + + /** + * 列车排进路并运行 + */ + private void settingRouteAndMoving(Simulation simulation) { + for (DepotRunningInfo depotRunningInfo : simulation.getRepository().getDepotRunningInfoList()) { + Section endSection = depotRunningInfo.getEndSection(); + SectionPosition position = new SectionPosition(endSection, endSection.getStopPointByDirection(depotRunningInfo.getRight())); + depotRunningInfo.getTrain().setRobotTargetPosition(position); + if (!depotRunningInfo.getRouteList().isEmpty()) { + Route route = depotRunningInfo.getRouteList().get(0); + if (route.isLock()) { + depotRunningInfo.getRouteList().remove(0); + } + if (!route.isSetting()) { + route.setSettedAspect(route.getAspect()); + ciRouteService.setRoute(simulation, route); + } + } + } + } + + /** + * 判断运行列车是否到达转换轨并升级 + */ + private void arriveDestination(Simulation simulation) { + for (Iterator iterator = simulation.getRepository().getDepotRunningInfoList().iterator(); iterator.hasNext(); ) { + DepotRunningInfo depotRunningInfo = iterator.next(); + VirtualRealityTrain train = depotRunningInfo.getTrain(); + if (depotRunningInfo.isArrival()) { + // 到达 + iterator.remove(); + if (depotRunningInfo.in) { + atpService.turnDirectionImmediately(train); + } else { + // 升级 + SimulationMember member = simulation.getSimulationMember(train, SimulationMember.Type.DRIVER); + Map param = new HashMap<>(); + param.put("preselectionMode", "AM_C"); + CommandInitiateVO commandInitiateVO = new CommandInitiateVO(CommandBO.CommandType.Change_Preselection_Mode, + member.getId(), param); + groupSimulationService.command(simulation, commandInitiateVO, member); + } + } + } + } + + @Getter + public static class DepotRunningInfo { + + private final List routeList = new ArrayList<>(); + + private final Section endSection; + + private final VirtualRealityTrain train; + + private final Boolean right; + + private final Boolean in; + + public DepotRunningInfo(Section endSection, VirtualRealityTrain train, RoutePath routePath, boolean in) { + this.endSection = endSection; + this.train = train; + for (Signal signal : routePath.getSignalList()) { + for (Route route : signal.getRouteList()) { + if (routePath.getRouteList().contains(route)) { + routeList.add(route); + } + } + } + this.right = routePath.isRight(); + this.in = in; + } + + // 列车是否到达终点 + public boolean isArrival() { + return train.getSpeed() == 0 && train.getHeadPosition().getSection().equals(endSection) + && train.getTailPosition().getSection().equals(endSection); + } + } +}