diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/Operation.java b/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/Operation.java index d29d19f73..941f4337f 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/Operation.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/Operation.java @@ -732,6 +732,10 @@ public class Operation { /** * 托管 */ + Train_Drive(Operation.CLIENT), + /** + * TODO 托管,由于之前剧本中已包含Train_Trust,暂时留下,后续删除 + */ Train_Trust(Operation.CLIENT), /** * 连挂 diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/handler/TrainOperateHandler.java b/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/handler/TrainOperateHandler.java index 296e20214..5bf5537e0 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/handler/TrainOperateHandler.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/handler/TrainOperateHandler.java @@ -277,6 +277,15 @@ public class TrainOperateHandler { /** * 列车托管。使用司机的驾驶指令 */ + @OperateHandlerMapping(type = Operation.Type.Train_Drive) + public void drive(Simulation simulation, String groupNumber, DriveParamVO param) { + atsTrainService.trust(simulation, groupNumber, param); + } + + /** + * 列车托管。使用司机的驾驶指令 + * TODO 后续同Train_Trust一起删除 + */ @OperateHandlerMapping(type = Operation.Type.Train_Trust) public void trust(Simulation simulation, String groupNumber, DriveParamVO param) { atsTrainService.trust(simulation, groupNumber, param); 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..0cb770a82 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,320 @@ -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.CheckFailMessage message = routeService.setRoute(simulation, route,route.getAspect()); + 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())); + BusinessExceptionAssertEnum.OPERATION_FAIL.assertNotTrue( + Objects.nonNull(route.getDelayUnlockDevice()), 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..73c623778 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,812 @@ -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); + //当为一般进路时直接获取信号显示,当为组合进路时信号显示获取到办理子进路时 + SignalAspect settedAspect=route.isMultiRoute()?null:route.getAspect(); + return this.routeService.setRoute(simulation, route,settedAspect); + } + + @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 3b86e4c9f..fb4f1a1c5 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 @@ -1,238 +1,238 @@ -package club.joylink.rtss.simulation.cbtc.CI; - -import club.joylink.rtss.simulation.cbtc.CI.device.CiDeviceStatusCollector; -import club.joylink.rtss.simulation.cbtc.CI.device.CiRouteService; -import club.joylink.rtss.simulation.cbtc.CI.device.CiService; -import club.joylink.rtss.simulation.cbtc.CI.device.CiSignalControlService; -import club.joylink.rtss.simulation.cbtc.CI.service.assist.StationDirectionService; -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.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 java.util.List; -import java.util.Objects; - -@Slf4j -@Component -public class CiLogic { - @Autowired - private CiDeviceStatusCollector deviceStatusCollector; - @Autowired - private CiRouteService routeService; - @Autowired - private CiSignalControlService signalControlService; - @Autowired - private CiService ciService; - @Autowired - private StationDirectionService stationDirectionService; - - public void run(Simulation simulation) { - // 采集真实设备状态 - deviceStatusCollector.collect(simulation); - // 信号机监控控制 - SimulationDataRepository repository = simulation.getRepository(); - for (Signal signal : repository.getSignalList()) { - signalMonitor(simulation, signal); - } - // 联锁监控逻辑 - List routeList = repository.getRouteList(); - for (Route route : routeList) { - interlockMonitor(simulation, route); - } - List routeOverlapList = repository.getRouteOverlapList(); - for (RouteOverlap routeOverlap : routeOverlapList) { - overlapMonitor(simulation, routeOverlap); - } - - // 区间灯点灯逻辑 - if (simulation.getRepository().getConfig().isRailway()) { - // 车站 - simulation.getRepository().getStationList().stream().forEach(station -> { - // 允许自律状态刷新 - station.refreshAllowAutonomyStatus(); - // 接、发辅助按钮倒计时刷新 - station.getStationDirectionMap().values().stream() - .forEach(stationDirection -> { - // 判断进路状态是否发生变化 - if (stationDirection.monitorRouteChangeStatus()) { - stationDirection.modifyRunStatus(); - } - // 如果倒数结束弹起接、发辅助按钮,超过50秒时,不再自动抬起 - if (!stationDirection.isAssistReadyStatus() - && !stationDirection.assistDurationPass50(simulation.getCorrectSystemTime()) - && stationDirection.getCountDown().decrementAndGet() <= 0) { - stationDirection.setDeliverAssistStatus(false); - stationDirection.setReceiveAssistStatus(false); - stationDirection.getCountDown().set(0); - } - // 联锁数据检查 - stationDirectionService.refreshSectionLightStatus(simulation, stationDirection); - }); - }); - } - } - - private void signalMonitor(Simulation simulation, Signal signal) { - signalControlService.controlLightOfSignal(simulation, signal); - //控制通过信号机的显示:信号机前第一个区段被占用开红灯;第二个区段被占用开黄灯;否则开绿灯 - if (signal.isPassingSignal()) { - if (simulation.getRepository().getConfig().isRailway()) { - boolean right = signal.isRight(); - Section section = signal.getSection(); - Section one = section.getNextSection(right); - if (one == null) { - signalControlService.controlSignalAspect(simulation, signal, SignalAspect.G); - return; - } - if (one.isOccupied()) { - signalControlService.controlSignalAspect(simulation, signal, SignalAspect.R); - return; - } - Section two = one.getNextSection(right); - if (two == null) { - signalControlService.controlSignalAspect(simulation, signal, SignalAspect.G); - return; - } - if (two.isOccupied()) { - signalControlService.controlSignalAspect(simulation, signal, SignalAspect.Y); - return; - } - signalControlService.controlSignalAspect(simulation, signal, SignalAspect.G); - } - } - } - - /** - * 进路监控 - * - * @param simulation - * @param route - */ - public void interlockMonitor(Simulation simulation, Route route) { - MapConfig config = simulation.getRepository().getConfig(); - if (route.isCiControl()) { // 进路联锁自动触发 - if (!route.isLock() && !route.isSetting() && ciService.isCiRouteTrigger(simulation, route)) { - routeService.setRoute(simulation, route); - } - } else if (route.isFleetMode()) { // 联锁自动进路 - if (ciService.isCiRouteTrigger(simulation, route)) { - signalControlService.tryControlSignalAspectAccordingLevel(simulation, route.getStart(), route.getAspect()); - } - } - if (route.isSetting() || route.isLock() || route.isNormalUnlock()) { // 监控中的进路 - if (route.isDelayUnlocking()) { - routeService.delayUnlocking(simulation, route, route.getDelayUnlockDevice()); - } - if (route.isSetting()) { - routeService.routeSettingProcess(simulation, route); - } - if (route.isNormalUnlock()) { - routeService.trainUnlockRoute(simulation, route); - } - if (route.isLock()) { - // 进路首区段列车占用,进路开始解锁 - Section firstLogicSection = route.getFirstLogicSection(); - SimulationDataRepository repository = simulation.getRepository(); - if (repository.isTrainHeadOccupy(firstLogicSection)) { - trainUnlockStart(simulation, route); - } - } - Signal start = route.getStart(); - int guideRemain = start.getGuideRemain(); - if (guideRemain != 0) { - guideRemain -= SimulationConstants.CI_LOOP_RATE; - if (guideRemain <= 0) { //计时结束,关闭信号 - start.setGuideRemain(0); - signalControlService.tryControlSignalAspectAccordingLevel(simulation, - start, start.getDefaultAspect()); - } else { - start.setGuideRemain(guideRemain); - } - } - if (route.isLock() && !route.isSetting()) { - ciService.interlockCheck(simulation, route); - if (!config.isRailway()) { - if (route.isOpenMain() && !start.isSupportMainAspect()) {//与联锁显示不同,关闭信号 - CiLogic.log.info("进路[{}]联锁条件不满足,关闭信号", route.debugStr()); - signalControlService.tryControlSignalAspectAccordingLevel(simulation, - start, start.getDefaultAspect()); - } else if (start.isDefaultAspect() && !start.isForbidden() && !start.isBlockade() && start.isSupportMainAspect()) { - CiLogic.log.info("进路[{}]联锁条件满足,开放信号", route.debugStr()); - signalControlService.tryControlSignalAspectAccordingLevel(simulation, - start, route.getAspect()); - } - } else { - if (route.isOpenMain() && !start.isSupportMainAspect()) {//与联锁显示不同,关闭信号 - CiLogic.log.info("进路[{}]联锁条件不满足,关闭信号", route.debugStr()); - signalControlService.tryControlSignalAspectAccordingLevel(simulation, - start, start.getDefaultAspect()); - start.setForcePhysical(true); //大铁线路暂时限制自动重开信号 - } else if (!start.isForbidden() && !start.isBlockade() && start.isSupportMainAspect()) { - SignalAspect aspect = route.getAspectOfRailway(); - if (!Objects.equals(route.getStart().getAspect(), aspect)) { - signalControlService.tryControlSignalAspectAccordingLevel(simulation, start, aspect); - } - } - } - } - // 进路延续保护办理判断 - if (route.isSettingOverlap()) { - ciService.checkAndTrySettingOverlap(simulation, route.getOverlap()); - } - } - } - - public void trainUnlockStart(Simulation simulation, Route route) { - route.startNormalUnlock(); - CiLogic.log.info("进路[{}]因列车进入,关闭信号", route.debugStr()); - signalControlService.tryControlSignalAspectAccordingLevel(simulation, - route.getStart(), route.getStart().getDefaultAspect()); - } - - /** - * 延续保护进路监控 - * - * @param simulation - * @param overlap - */ - public void overlapMonitor(Simulation simulation, RouteOverlap overlap) { - MapConfig config = simulation.getRepository().getConfig(); - if (config.isOverlapSettingByTrigger() && overlap.isTriggerSectionOccupied()) { - ciService.checkAndTrySettingOverlap(simulation, overlap); - } - if (overlap.isSetting()) { - routeService.overlapSettingProcess(simulation, overlap); - } - if (overlap.isForbidden()) { - routeService.checkAndAllowOverlap(simulation, overlap); - } - if (overlap.isLock() && !ciService.interlockCheck(simulation, overlap)) { - overlap.setLock(false); - } - if (overlap.isSectionOverlapLocked()) { - if (simulation.getRepository().isTrainParking(overlap.getSection())) { - CiLogic.log.debug("列车停稳,延续保护[{}}],触发区段[{}}]立即解锁", - overlap.getName(), - overlap.getSection().debugStr()); - overlap.releaseImmediately(); - return; - } - if (overlap.isReleasing()) { - overlap.releaseProgress(); - } else if (!overlap.isReleasing() && simulation.getRepository().isTrainHeadOccupy(overlap.getSection())) { - // 进路首区段列车占用,进路开始解锁 - overlap.startReleasing(); - } - } - } - - public void addJobs(Simulation simulation) { - simulation.addJob(SimulationModule.CI.name(), () -> run(simulation), SimulationConstants.CI_LOOP_RATE); - } -} +package club.joylink.rtss.simulation.cbtc.CI; + +import club.joylink.rtss.simulation.cbtc.CI.device.CiDeviceStatusCollector; +import club.joylink.rtss.simulation.cbtc.CI.device.CiRouteService; +import club.joylink.rtss.simulation.cbtc.CI.device.CiService; +import club.joylink.rtss.simulation.cbtc.CI.device.CiSignalControlService; +import club.joylink.rtss.simulation.cbtc.CI.service.assist.StationDirectionService; +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.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 java.util.List; +import java.util.Objects; + +@Slf4j +@Component +public class CiLogic { + @Autowired + private CiDeviceStatusCollector deviceStatusCollector; + @Autowired + private CiRouteService routeService; + @Autowired + private CiSignalControlService signalControlService; + @Autowired + private CiService ciService; + @Autowired + private StationDirectionService stationDirectionService; + + public void run(Simulation simulation) { + // 采集真实设备状态 + deviceStatusCollector.collect(simulation); + // 信号机监控控制 + SimulationDataRepository repository = simulation.getRepository(); + for (Signal signal : repository.getSignalList()) { + signalMonitor(simulation, signal); + } + // 联锁监控逻辑 + List routeList = repository.getRouteList(); + for (Route route : routeList) { + interlockMonitor(simulation, route); + } + List routeOverlapList = repository.getRouteOverlapList(); + for (RouteOverlap routeOverlap : routeOverlapList) { + overlapMonitor(simulation, routeOverlap); + } + + // 区间灯点灯逻辑 + if (simulation.getRepository().getConfig().isRailway()) { + // 车站 + simulation.getRepository().getStationList().stream().forEach(station -> { + // 允许自律状态刷新 + station.refreshAllowAutonomyStatus(); + // 接、发辅助按钮倒计时刷新 + station.getStationDirectionMap().values().stream() + .forEach(stationDirection -> { + // 判断进路状态是否发生变化 + if (stationDirection.monitorRouteChangeStatus()) { + stationDirection.modifyRunStatus(); + } + // 如果倒数结束弹起接、发辅助按钮,超过50秒时,不再自动抬起 + if (!stationDirection.isAssistReadyStatus() + && !stationDirection.assistDurationPass50(simulation.getCorrectSystemTime()) + && stationDirection.getCountDown().decrementAndGet() <= 0) { + stationDirection.setDeliverAssistStatus(false); + stationDirection.setReceiveAssistStatus(false); + stationDirection.getCountDown().set(0); + } + // 联锁数据检查 + stationDirectionService.refreshSectionLightStatus(simulation, stationDirection); + }); + }); + } + } + + private void signalMonitor(Simulation simulation, Signal signal) { + signalControlService.controlLightOfSignal(simulation, signal); + //控制通过信号机的显示:信号机前第一个区段被占用开红灯;第二个区段被占用开黄灯;否则开绿灯 + if (signal.isPassingSignal()) { + if (simulation.getRepository().getConfig().isRailway()) { + boolean right = signal.isRight(); + Section section = signal.getSection(); + Section one = section.getNextSection(right); + if (one == null) { + signalControlService.controlSignalAspect(simulation, signal, SignalAspect.G); + return; + } + if (one.isOccupied()) { + signalControlService.controlSignalAspect(simulation, signal, SignalAspect.R); + return; + } + Section two = one.getNextSection(right); + if (two == null) { + signalControlService.controlSignalAspect(simulation, signal, SignalAspect.G); + return; + } + if (two.isOccupied()) { + signalControlService.controlSignalAspect(simulation, signal, SignalAspect.Y); + return; + } + signalControlService.controlSignalAspect(simulation, signal, SignalAspect.G); + } + } + } + + /** + * 进路监控 + * + * @param simulation + * @param route + */ + public void interlockMonitor(Simulation simulation, Route route) { + MapConfig config = simulation.getRepository().getConfig(); + if (route.isCiControl()) { // 进路联锁自动触发 + if (!route.isLock() && !route.isSetting() && ciService.isCiRouteTrigger(simulation, route)) { + routeService.setRoute(simulation, route,route.getAspect()); + } + } else if (route.isFleetMode()) { // 联锁自动进路 + if (ciService.isCiRouteTrigger(simulation, route)) { + signalControlService.tryControlSignalAspectAccordingLevel(simulation, route.getStart(), route.getSettedAspect()); + } + } + if (route.isSetting() || route.isLock() || route.isNormalUnlock()) { // 监控中的进路 + if (route.isDelayUnlocking()) { + routeService.delayUnlocking(simulation, route, route.getDelayUnlockDevice()); + } + if (route.isSetting()) { + routeService.routeSettingProcess(simulation, route); + } + if (route.isNormalUnlock()) { + routeService.trainUnlockRoute(simulation, route); + } + if (route.isLock()) { + // 进路首区段列车占用,进路开始解锁 + Section firstLogicSection = route.getFirstLogicSection(); + SimulationDataRepository repository = simulation.getRepository(); + if (repository.isTrainHeadOccupy(firstLogicSection)) { + trainUnlockStart(simulation, route); + } + } + Signal start = route.getStart(); + int guideRemain = start.getGuideRemain(); + if (guideRemain != 0) { + guideRemain -= SimulationConstants.CI_LOOP_RATE; + if (guideRemain <= 0) { //计时结束,关闭信号 + start.setGuideRemain(0); + signalControlService.tryControlSignalAspectAccordingLevel(simulation, + start, start.getDefaultAspect()); + } else { + start.setGuideRemain(guideRemain); + } + } + if (route.isLock() && !route.isSetting()) { + ciService.interlockCheck(simulation, route); + if (!config.isRailway()) { + if (route.isOpenMain() && !start.isSupportMainAspect()) {//与联锁显示不同,关闭信号 + CiLogic.log.info("进路[{}]联锁条件不满足,关闭信号", route.debugStr()); + signalControlService.tryControlSignalAspectAccordingLevel(simulation, + start, start.getDefaultAspect()); + } else if (start.isDefaultAspect() && !start.isForbidden() && !start.isBlockade() && start.isSupportMainAspect()) { + CiLogic.log.info("进路[{}]联锁条件满足,开放信号", route.debugStr()); + signalControlService.tryControlSignalAspectAccordingLevel(simulation, + start, route.getSettedAspect()); + } + } else { + if (route.isOpenMain() && !start.isSupportMainAspect()) {//与联锁显示不同,关闭信号 + CiLogic.log.info("进路[{}]联锁条件不满足,关闭信号", route.debugStr()); + signalControlService.tryControlSignalAspectAccordingLevel(simulation, + start, start.getDefaultAspect()); + start.setForcePhysical(true); //大铁线路暂时限制自动重开信号 + } else if (!start.isForbidden() && !start.isBlockade() && start.isSupportMainAspect()) { + SignalAspect aspect = route.getAspectOfRailway(); + if (!Objects.equals(route.getStart().getAspect(), aspect)) { + signalControlService.tryControlSignalAspectAccordingLevel(simulation, start, aspect); + } + } + } + } + // 进路延续保护办理判断 + if (route.isSettingOverlap()) { + ciService.checkAndTrySettingOverlap(simulation, route.getOverlap()); + } + } + } + + public void trainUnlockStart(Simulation simulation, Route route) { + route.startNormalUnlock(); + CiLogic.log.info("进路[{}]因列车进入,关闭信号", route.debugStr()); + signalControlService.tryControlSignalAspectAccordingLevel(simulation, + route.getStart(), route.getStart().getDefaultAspect()); + } + + /** + * 延续保护进路监控 + * + * @param simulation + * @param overlap + */ + public void overlapMonitor(Simulation simulation, RouteOverlap overlap) { + MapConfig config = simulation.getRepository().getConfig(); + if (config.isOverlapSettingByTrigger() && overlap.isTriggerSectionOccupied()) { + ciService.checkAndTrySettingOverlap(simulation, overlap); + } + if (overlap.isSetting()) { + routeService.overlapSettingProcess(simulation, overlap); + } + if (overlap.isForbidden()) { + routeService.checkAndAllowOverlap(simulation, overlap); + } + if (overlap.isLock() && !ciService.interlockCheck(simulation, overlap)) { + overlap.setLock(false); + } + if (overlap.isSectionOverlapLocked()) { + if (simulation.getRepository().isTrainParking(overlap.getSection())) { + CiLogic.log.debug("列车停稳,延续保护[{}}],触发区段[{}}]立即解锁", + overlap.getName(), + overlap.getSection().debugStr()); + overlap.releaseImmediately(); + return; + } + if (overlap.isReleasing()) { + overlap.releaseProgress(); + } else if (!overlap.isReleasing() && simulation.getRepository().isTrainHeadOccupy(overlap.getSection())) { + // 进路首区段列车占用,进路开始解锁 + overlap.startReleasing(); + } + } + } + + public void addJobs(Simulation simulation) { + simulation.addJob(SimulationModule.CI.name(), () -> run(simulation), SimulationConstants.CI_LOOP_RATE); + } +} 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..9c314f797 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,739 @@ -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.CheckFailMessage failMessage = routeSetCheck(simulation, route, true); + if (failMessage == null) { + if (route.isLock() && !route.isFleetMode()) { + log.info("进路[{}]已经锁闭", route.debugStr()); + return; + } + // + route.setSettedAspect(route.getStart().getGuideAspect()); + // 引导进路开始办理 + 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,SignalAspect settedAspect) { + Route.CheckFailMessage failMessage = routeSetCheck(simulation, route, false); + if (failMessage == null) { + if (route.isLock() && !route.isFleetMode()) { + log.info("进路[{}]已经锁闭", route.debugStr()); + return null; + } + // 设置根据进路性质开放的信号 + route.setSettedAspect(settedAspect); + // 进路开始办理 + 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.getSettedAspect(); + } else if (route.getStart().isBlockade()) { + aspect = route.getStart().getDefaultAspect(); + } else { + aspect = route.getSettedAspect(); + 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.getSettedAspect().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,routeAspect.getAspect()); + 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,simulation.getRepository().getConfig()); + 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/conversation/ConversationManagerService.java b/src/main/java/club/joylink/rtss/simulation/cbtc/conversation/ConversationManagerService.java index 5cb611e0d..4e11e1ccb 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/conversation/ConversationManagerService.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/conversation/ConversationManagerService.java @@ -404,12 +404,8 @@ public class ConversationManagerService { * 会话操作 */ public ConversationMessageVO conversationChat(Simulation simulation, SimulationMember member, String content, String audioPath) { - String path = audioPath; - if (StringUtils.isEmpty(audioPath)) { - path = iVoiceService.synthesis(content, "0"); - } ConversationMessage conversationMessage = new ConversationMessage(simulation.getIdGenerator().nextConversationMessageId(), - member, simulation.getCorrectSystemTime(), content, path); + member, simulation.getCorrectSystemTime(), content, audioPath); return sendChatMessage(simulation.getId(), simulation.getSimulationUserIds(), conversationMessage); } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/conversation/ConversationMessage.java b/src/main/java/club/joylink/rtss/simulation/cbtc/conversation/ConversationMessage.java index 6a88c6904..9897aba5b 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/conversation/ConversationMessage.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/conversation/ConversationMessage.java @@ -2,6 +2,7 @@ package club.joylink.rtss.simulation.cbtc.conversation; import club.joylink.rtss.simulation.cbtc.member.SimulationMember; import lombok.Getter; +import org.springframework.util.StringUtils; import java.time.LocalDateTime; @@ -18,6 +19,8 @@ public class ConversationMessage { private String audioPath; + private MessageType type; + public void setContent(String content) { this.content = content; } @@ -28,5 +31,10 @@ public class ConversationMessage { this.time = systemTime; this.content = content; this.audioPath = filePath; + this.type = StringUtils.isEmpty(filePath) ? MessageType.Text : MessageType.Voice; + } + + public enum MessageType { + Voice, Text; } } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/DelayUnlockDevice.java b/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/DelayUnlockDevice.java index 4e91191d3..140c86fe6 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/DelayUnlockDevice.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/DelayUnlockDevice.java @@ -10,6 +10,21 @@ public abstract class DelayUnlockDevice extends MayOutOfOrderDevice { super(code, name, deviceType); } + public void delayUnlockStart(Route route,MapConfig mc) { +// route.getType() == Type + int baseDelayTime = route.getDelayReleaseTime(); + if(mc.isRailway()){ + switch (route.getType()){ + case DEPARTURE: + case RECEIVING: + baseDelayTime = 180; + break; + case SHUNTING: + baseDelayTime = 30; + } + } + this.remain = baseDelayTime * 1000; + } public void delayUnlockStart(Route route) { this.remain = route.getDelayReleaseTime() * 1000; } 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..996645c26 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,957 @@ -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(); + } + } + } + SignalAspect rt=getSettedAspect()==null?getAspect():getSettedAspect(); + return rt; + } + + 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/map/Signal.java b/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/Signal.java index 6d3bf6207..6901e555c 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/Signal.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/Signal.java @@ -318,7 +318,7 @@ public class Signal extends DelayUnlockDevice { public boolean isMainAspect() { if (this.lockedRoute != null) { - return this.aspect.equals(this.lockedRoute.getAspect()); + return this.aspect.equals(this.lockedRoute.getSettedAspect()); } return false; } 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/data/vo/ConversationMessageVO.java b/src/main/java/club/joylink/rtss/simulation/cbtc/data/vo/ConversationMessageVO.java index e1e39c7ce..8b6a6fc9a 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/data/vo/ConversationMessageVO.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/data/vo/ConversationMessageVO.java @@ -23,12 +23,15 @@ public class ConversationMessageVO { private String audioPath; + private ConversationMessage.MessageType type; + public ConversationMessageVO(ConversationMessage message) { this.id = message.getId(); this.memberId = message.getMember().getId(); this.time = message.getTime(); this.content = message.getContent(); this.audioPath = message.getAudioPath(); + this.type = message.getType(); } public static List convert2VOList(List list) { 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..a275087b6 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,236 @@ -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()) { + ciRouteService.setRoute(simulation, route,route.getAspect()); + } + } + } + } + + /** + * 判断运行列车是否到达转换轨并升级 + */ + 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); + } + } +} diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/onboard/ATP/ATPService.java b/src/main/java/club/joylink/rtss/simulation/cbtc/onboard/ATP/ATPService.java index 3983ece2a..b269c0489 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/onboard/ATP/ATPService.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/onboard/ATP/ATPService.java @@ -530,7 +530,7 @@ public class ATPService { public void inbound(Simulation simulation, String groupNumber) { VirtualRealityTrain train = simulation.getRepository().getOnlineTrainBy(groupNumber); Section headSection = train.getHeadPosition().getSection(); - if (headSection.isTransferTrack() && train.isStop()) { //列车停在折返轨 + if (headSection.isTurnBackTrack() && train.isStop()) { //列车停在折返轨 SimulationDataRepository repository = simulation.getRepository(); TrainInfo trainInfo = repository.getSupervisedTrainByGroup(train.getGroupNumber()); List routePathList = repository.queryRoutePathsByEnd(headSection); @@ -624,6 +624,7 @@ public class ATPService { } } } else if (trainMode.isMatchTheDriveMode(DriveMode.AM) && !train.isAMMode()) { + train.getRobotDriveParam().setRun(false); // 关闭机器人自动驾驶 if (!train.isInTheGear(VirtualRealityTrain.Handwheel.ATO)) { this.changeGear(train, VirtualRealityTrain.Handwheel.ATO); } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/robot/SimulationRobotService.java b/src/main/java/club/joylink/rtss/simulation/cbtc/robot/SimulationRobotService.java index a5525d218..36c22c703 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/robot/SimulationRobotService.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/robot/SimulationRobotService.java @@ -11,6 +11,7 @@ import club.joylink.rtss.simulation.cbtc.CTC.data.CtcStationRunPlanLog; import club.joylink.rtss.simulation.cbtc.Simulation; import club.joylink.rtss.simulation.cbtc.command.CommandBO; import club.joylink.rtss.simulation.cbtc.constant.SignalAspect; +import club.joylink.rtss.simulation.cbtc.constant.SignalModel; import club.joylink.rtss.simulation.cbtc.constant.SimulationConstants; import club.joylink.rtss.simulation.cbtc.constant.SimulationModule; import club.joylink.rtss.simulation.cbtc.data.CalculateService; @@ -436,13 +437,31 @@ public class SimulationRobotService { */ private void robotDrive(Simulation simulation, VirtualRealityTrain train, SectionPosition targetPosition) { SimulationDataRepository repository = simulation.getRepository(); - if (!train.getDoor1().isCloseAndLock() || !train.getDoor2().isCloseAndLock()) { //如果车门没关 - return; - } SectionPosition headPosition = train.getHeadPosition(); boolean right = train.isRight(); float speed = train.getSpeed(); - + if (!train.getDoor1().isCloseAndLock() || !train.getDoor2().isCloseAndLock()) { //如果车门没关 + return; + } + /** + * 添加车辆停靠车站时,车门关闭后向前行驶一点的问题,因为车头偏移与目标偏移大于 @seeSimulationConstants.PARK_POINT_MAX_OFFSET位置,故修正逻辑如下 + * 判断车辆是否停靠车站,没有开发的信号,没有新车命令,如果有其中一项的条件那么车辆可以启动 + * begin 2022-08-15 + */ + boolean trainPackingForStand = train.isParkingAt(); +// headPosition.getSection().getStandList().stream().anyMatch(d->d.isTrainParking()); + Signal targetSignal = headPosition.getSection().getSignalOf(right); + boolean closeSignal = false; + if(Objects.nonNull(targetSignal)){ + closeSignal = targetSignal.getAspect() == targetSignal.getSignalModel().getDefaultAspect(); + } + boolean noCommond = Objects.isNull(train.getRobotDriveParam().getThroughSignal()); + if(trainPackingForStand && closeSignal && noCommond){ + return; + } + /** + * end 2022-08-15 + */ Float distance = CalculateService.calculateDistance(headPosition, targetPosition, right, true); if (distance == null || distance <= SimulationConstants.PARK_POINT_MAX_OFFSET) { //如果列车已经抵达或越过目标位置 atoService.doBreakMax(train); diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/tool/DeviceStatusModifyTool.java b/src/main/java/club/joylink/rtss/simulation/cbtc/tool/DeviceStatusModifyTool.java index ed3f43bcd..f6bffc4a3 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/tool/DeviceStatusModifyTool.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/tool/DeviceStatusModifyTool.java @@ -1,306 +1,307 @@ -package club.joylink.rtss.simulation.cbtc.tool; - -import club.joylink.rtss.exception.BusinessExceptionAssertEnum; -import club.joylink.rtss.simulation.cbtc.ATS.service.AtsTrainLoadService; -import club.joylink.rtss.simulation.cbtc.CI.device.CiRouteService; -import club.joylink.rtss.simulation.cbtc.Simulation; -import club.joylink.rtss.simulation.cbtc.constant.RunLevel; -import club.joylink.rtss.simulation.cbtc.constant.SignalAspect; -import club.joylink.rtss.simulation.cbtc.constant.SwitchIndication; -import club.joylink.rtss.simulation.cbtc.data.CalculateService; -import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository; -import club.joylink.rtss.simulation.cbtc.data.map.*; -import club.joylink.rtss.simulation.cbtc.data.support.SectionPosition; -import club.joylink.rtss.simulation.cbtc.data.vo.TrainInfo; -import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealitySignal; -import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealitySwitch; -import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityTrain; -import club.joylink.rtss.simulation.cbtc.device.virtual.VRTrainRunningService; -import club.joylink.rtss.simulation.cbtc.device.virtual.VirtualRealityDeviceService; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import org.springframework.util.CollectionUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -/** - * 设备状态修改工具(有动作设备不需要动作过程可直接设置为想要的状态) - * warn:此工具类只在加载列车或实训生成场景使用,正常仿真过程请勿使用 - */ -@Slf4j -@Component -public class DeviceStatusModifyTool { - @Autowired - private VirtualRealityDeviceService virtualRealityDeviceService; - @Autowired - private CiRouteService routeService; - @Autowired - private AtsTrainLoadService atsTrainLoadService; - @Autowired - private VRTrainRunningService vrTrainRunningService; - - /** - * 直接开放进路 - * - * @param route - */ - public void openRouteDirect(Simulation simulation, Route route) { - // 修改进路涉及的所有道岔元素到指定位置 - this.batchSetRouteSwitchPositionAndLock(route, route.getSwitchList(), true); - // 修改进路侧防到指定位置 - this.batchSetRouteFlsSwitchPositionAndLock(route.getFlsList()); - // 进路元素锁闭 - route.getSectionList().forEach(section -> section.routeLocking(route, route.getStart().isRight())); - if (route.isSettingOverlap()) { - SectionPath overlapPath = route.selectOverlapElement(); - if (Objects.nonNull(overlapPath)) { - this.batchSetRouteFlsSwitchPositionAndLock(overlapPath.getFlsList()); - this.batchSetRouteSwitchPositionAndLock(route, overlapPath.getSwitchList(), false); - overlapPath.getSectionList().forEach(section -> section.overlapLocking(route.getStart().isRight())); - this.batchSetRouteFlsSwitchPositionAndLock(overlapPath.getFlsList()); - route.getOverlap().setLock(true); - } - } - route.setNormalUnlock(false); - route.setLock(true); - simulation.getRepository().addSettingRoute(route); - this.openSignalDirectly(route.getStart(), route.getAspect()); - route.getStart().setLockedRoute(route); - } - - private void batchSetRouteFlsSwitchPositionAndLock(List flsList) { - if (!CollectionUtils.isEmpty(flsList)) { - List switchElementList = new ArrayList<>(); - for (RouteFls routeFls : flsList) { - for (RouteFls.FlsElement flsElement : routeFls.getLevel1List()) { - SwitchElement pSwitch = flsElement.getPSwitch(); - if (pSwitch != null) { - switchElementList.add(pSwitch); - } else if (flsElement.getFpae() != null) { - switchElementList.add(flsElement.getFpae()); - } - } - } - for (SwitchElement switchElement : switchElementList) { -// switchElement.getASwitch().ciUse(switchElement.isNormal()); - this.setSingleSwitchPositionDirectly(switchElement.getASwitch(), switchElement.isNormal()); - switchElement.getASwitch().fpLock(); - } - } - } - - public void openGuideRouteDirect(Simulation simulation, Route route) { - // 修改进路涉及的所有道岔元素到指定位置 - this.batchSetRouteSwitchPositionAndLock(route, route.getSwitchList(), true); - // 修改进路侧防到指定位置 - this.batchSetRouteFlsSwitchPositionAndLock(route.getFlsList()); - // 进路元素锁闭 - route.getSectionList().forEach(section -> section.routeLocking(route, route.getStart().isRight())); - SectionPath overlapPath = route.selectOverlapElement(); - if (Objects.nonNull(overlapPath)) { - this.batchSetRouteSwitchPositionAndLock(route, overlapPath.getSwitchList(), false); - this.batchSetRouteFlsSwitchPositionAndLock(overlapPath.getFlsList()); - overlapPath.getSectionList().forEach(section -> section.overlapLocking(route.getStart().isRight())); - } - route.setLock(true); - this.openGuideSignalDirectly(route.getStart()); - route.getStart().setLockedRoute(route); - } - - public void openGuideSignalDirectly(Signal signal) { - VirtualRealitySignal virtualSignal = signal.getVirtualSignal(); - SignalAspect guideAspect = virtualSignal.getModel().getGuideAspect(); - virtualSignal.control(guideAspect); - virtualSignal.finish(); - signal.changeLightType(false); - signal.setAspect(guideAspect); - } - - /** - * 直接开灯(默认逻辑点灯) - * - * @param signal - * @param aspect - */ - private void openSignalDirectly(Signal signal, SignalAspect aspect) { - VirtualRealitySignal virtualSignal = signal.getVirtualSignal(); - signal.changeLightType(true); - if (virtualSignal != null) { - if (signal.isLogicLight()) { - virtualSignal.control(SignalAspect.No); - } else { - virtualSignal.control(aspect); - } - virtualSignal.finish(); - } - signal.setAspect(aspect); - } - - /** - * 直接关灯(默认逻辑点灯) - * - * @param signal - */ - public void closeSignalDirectly(Signal signal) { - VirtualRealitySignal virtualSignal = signal.getVirtualSignal(); - signal.changeLightType(true); - SignalAspect defaultAspect = virtualSignal.getModel().getDefaultAspect(); - if (signal.isLogicLight()) { - virtualSignal.control(SignalAspect.No); - } else { - virtualSignal.control(defaultAspect); - } - virtualSignal.finish(); - signal.setAspect(defaultAspect); - } - - /** - * 批量设置进路道岔位置并锁闭 - * - * @param route - * @param switchList - * @param routeLock - */ - private void batchSetRouteSwitchPositionAndLock(Route route, List switchList, boolean routeLock) { - if (!CollectionUtils.isEmpty(switchList)) { - for (SwitchElement switchElement : switchList) { -// if (switchElement.getASwitch().isOverlapLock() && -// switchElement.isOnPosition()) { -// continue; -// } -// switchElement.getASwitch().ciUse(switchElement.isNormal()); - this.setSingleSwitchPositionDirectly(switchElement.getASwitch(), switchElement.isNormal()); - if (routeLock) { - switchElement.getASwitch().routeLock(route); - } else { // 延续保护锁闭 - switchElement.getASwitch().overlapLock(); - } - } - } - } - - /** - * 直接把单个道岔转到指定位置 - * - * @param aSwitch - * @param normal - */ - public void setSingleSwitchPositionDirectly(Switch aSwitch, boolean normal) { - VirtualRealitySwitch virtualSwitch = aSwitch.getVirtualSwitch(); - if (normal) { - virtualSwitch.control(VirtualRealitySwitch.Operation.NP); - virtualSwitch.finish(); - aSwitch.setPos(SwitchIndication.N); - } else { - virtualSwitch.control(VirtualRealitySwitch.Operation.RP); - virtualSwitch.finish(); - aSwitch.setPos(SwitchIndication.R); - } - } - - /** - * 直接把道岔及其联动道岔转动到指定位置 - * - * @param aSwitch - * @param normal - */ - public void setCoupleSwitchPositionDirectly(Simulation simulation, Switch aSwitch, boolean normal) { - SimulationDataRepository repository = simulation.getRepository(); - this.setSingleSwitchPositionDirectly(aSwitch, normal); - Switch linkedSwitch = aSwitch.queryLinkedSwitch(); - if (Objects.nonNull(linkedSwitch)) { - this.setSingleSwitchPositionDirectly(linkedSwitch, normal); - } - } - - /** - * 直接根据最后一根区段解锁进路 - * - * @param route - */ - public void routeUnlockByEndSection(Route route, Section tailSection) { - if (!route.isRouteSection(tailSection)) { - // 不是进路区段,不解锁 - return; - } - route.startNormalUnlock(); - // 关闭始端信号机 - openSignalDirectly(route.getStart(), route.getStart().getSignalModel().getDefaultAspect()); - boolean right = route.getStart().isRight(); - // 区段是顺序的(否则会有问题) - List
sectionList = route.getSectionList(); - for (Section section : sectionList) { - if (section.isSamePhysical(tailSection.getCode())) { - route.updateUnlockedSection(tailSection); - break; - } - // 直接解锁区段 - if (section.isSwitchTrack()) { // 如果是道岔区段,解锁道岔 - Switch relSwitch = section.getRelSwitch(); - if (tailSection.isSwitchTrack() && tailSection.getRelSwitch().equals(relSwitch)) { - route.updateUnlockedSection(tailSection); - break; - } - if (section.getParent() != null && section.getParent().isCross()) { - section.getParent().routeUnlocking(route); - } - 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()) { - aSwitch.routeUnlock(route); - aSwitch.overlapUnLock(); - } - } - } - } else { - section.routeUnlocking(route); - } - } - } - - public void loadManualTrainOfGroup(Simulation simulation, String groupNumber, Section section, boolean right) { - SimulationDataRepository repository = simulation.getRepository(); - VirtualRealityTrain train = repository.getVRByCode(groupNumber, VirtualRealityTrain.class); - if (!section.isPhysical()) { - section = section.getParent(); - } - BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertNotNull(section.isPhysical(), "列车需加载到物理区段上"); - //重叠检测 - SectionPosition headPosition = new SectionPosition(section, section.getStopPointByDirection(right)); - SectionPosition tailPosition = CalculateService.calculateNextPositionByStartAndLen(headPosition, !right, train.getLen(), false); - boolean willOverlap = vrTrainRunningService.willOverlap(simulation, headPosition, tailPosition); - BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertNotTrue(willOverlap, "列车重叠"); - // 列车上线并构建ATS监控列车信息 - train.initManualTrain(headPosition, right); - //设置列车预选模式、驾驶模式、运行级别 - if (!headPosition.getSection().anyZcWorking()) { - train.initAsRM(); - } else { - MapConfig config = repository.getConfig(); - if (RunLevel.ITC.equals(config.getRunMode())) { - train.initAsAM_I(); - } else if (RunLevel.IL.equals(config.getRunMode())) { - train.initAsRM(); - } - } - TrainInfo trainInfo = TrainInfo.constructManualTrain(train); - trainInfo.tracking(train); - repository.addOnlineTrain(train); - repository.addTrainInfo(trainInfo); - } -} +package club.joylink.rtss.simulation.cbtc.tool; + +import club.joylink.rtss.exception.BusinessExceptionAssertEnum; +import club.joylink.rtss.simulation.cbtc.ATS.service.AtsTrainLoadService; +import club.joylink.rtss.simulation.cbtc.CI.device.CiRouteService; +import club.joylink.rtss.simulation.cbtc.Simulation; +import club.joylink.rtss.simulation.cbtc.constant.RunLevel; +import club.joylink.rtss.simulation.cbtc.constant.SignalAspect; +import club.joylink.rtss.simulation.cbtc.constant.SwitchIndication; +import club.joylink.rtss.simulation.cbtc.data.CalculateService; +import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository; +import club.joylink.rtss.simulation.cbtc.data.map.*; +import club.joylink.rtss.simulation.cbtc.data.support.SectionPosition; +import club.joylink.rtss.simulation.cbtc.data.vo.TrainInfo; +import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealitySignal; +import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealitySwitch; +import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityTrain; +import club.joylink.rtss.simulation.cbtc.device.virtual.VRTrainRunningService; +import club.joylink.rtss.simulation.cbtc.device.virtual.VirtualRealityDeviceService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * 设备状态修改工具(有动作设备不需要动作过程可直接设置为想要的状态) + * warn:此工具类只在加载列车或实训生成场景使用,正常仿真过程请勿使用 + */ +@Slf4j +@Component +public class DeviceStatusModifyTool { + @Autowired + private VirtualRealityDeviceService virtualRealityDeviceService; + @Autowired + private CiRouteService routeService; + @Autowired + private AtsTrainLoadService atsTrainLoadService; + @Autowired + private VRTrainRunningService vrTrainRunningService; + + /** + * 直接开放进路 + * + * @param route + */ + public void openRouteDirect(Simulation simulation, Route route) { + // 修改进路涉及的所有道岔元素到指定位置 + this.batchSetRouteSwitchPositionAndLock(route, route.getSwitchList(), true); + // 修改进路侧防到指定位置 + this.batchSetRouteFlsSwitchPositionAndLock(route.getFlsList()); + // 进路元素锁闭 + route.getSectionList().forEach(section -> section.routeLocking(route, route.getStart().isRight())); + if (route.isSettingOverlap()) { + SectionPath overlapPath = route.selectOverlapElement(); + if (Objects.nonNull(overlapPath)) { + this.batchSetRouteFlsSwitchPositionAndLock(overlapPath.getFlsList()); + this.batchSetRouteSwitchPositionAndLock(route, overlapPath.getSwitchList(), false); + overlapPath.getSectionList().forEach(section -> section.overlapLocking(route.getStart().isRight())); + this.batchSetRouteFlsSwitchPositionAndLock(overlapPath.getFlsList()); + route.getOverlap().setLock(true); + } + } + route.setNormalUnlock(false); + route.setLock(true); + route.setSettedAspect(route.getAspect()); + simulation.getRepository().addSettingRoute(route); + this.openSignalDirectly(route.getStart(), route.getSettedAspect()); + route.getStart().setLockedRoute(route); + } + + private void batchSetRouteFlsSwitchPositionAndLock(List flsList) { + if (!CollectionUtils.isEmpty(flsList)) { + List switchElementList = new ArrayList<>(); + for (RouteFls routeFls : flsList) { + for (RouteFls.FlsElement flsElement : routeFls.getLevel1List()) { + SwitchElement pSwitch = flsElement.getPSwitch(); + if (pSwitch != null) { + switchElementList.add(pSwitch); + } else if (flsElement.getFpae() != null) { + switchElementList.add(flsElement.getFpae()); + } + } + } + for (SwitchElement switchElement : switchElementList) { +// switchElement.getASwitch().ciUse(switchElement.isNormal()); + this.setSingleSwitchPositionDirectly(switchElement.getASwitch(), switchElement.isNormal()); + switchElement.getASwitch().fpLock(); + } + } + } + + public void openGuideRouteDirect(Simulation simulation, Route route) { + // 修改进路涉及的所有道岔元素到指定位置 + this.batchSetRouteSwitchPositionAndLock(route, route.getSwitchList(), true); + // 修改进路侧防到指定位置 + this.batchSetRouteFlsSwitchPositionAndLock(route.getFlsList()); + // 进路元素锁闭 + route.getSectionList().forEach(section -> section.routeLocking(route, route.getStart().isRight())); + SectionPath overlapPath = route.selectOverlapElement(); + if (Objects.nonNull(overlapPath)) { + this.batchSetRouteSwitchPositionAndLock(route, overlapPath.getSwitchList(), false); + this.batchSetRouteFlsSwitchPositionAndLock(overlapPath.getFlsList()); + overlapPath.getSectionList().forEach(section -> section.overlapLocking(route.getStart().isRight())); + } + route.setLock(true); + this.openGuideSignalDirectly(route.getStart()); + route.getStart().setLockedRoute(route); + } + + public void openGuideSignalDirectly(Signal signal) { + VirtualRealitySignal virtualSignal = signal.getVirtualSignal(); + SignalAspect guideAspect = virtualSignal.getModel().getGuideAspect(); + virtualSignal.control(guideAspect); + virtualSignal.finish(); + signal.changeLightType(false); + signal.setAspect(guideAspect); + } + + /** + * 直接开灯(默认逻辑点灯) + * + * @param signal + * @param aspect + */ + private void openSignalDirectly(Signal signal, SignalAspect aspect) { + VirtualRealitySignal virtualSignal = signal.getVirtualSignal(); + signal.changeLightType(true); + if (virtualSignal != null) { + if (signal.isLogicLight()) { + virtualSignal.control(SignalAspect.No); + } else { + virtualSignal.control(aspect); + } + virtualSignal.finish(); + } + signal.setAspect(aspect); + } + + /** + * 直接关灯(默认逻辑点灯) + * + * @param signal + */ + public void closeSignalDirectly(Signal signal) { + VirtualRealitySignal virtualSignal = signal.getVirtualSignal(); + signal.changeLightType(true); + SignalAspect defaultAspect = virtualSignal.getModel().getDefaultAspect(); + if (signal.isLogicLight()) { + virtualSignal.control(SignalAspect.No); + } else { + virtualSignal.control(defaultAspect); + } + virtualSignal.finish(); + signal.setAspect(defaultAspect); + } + + /** + * 批量设置进路道岔位置并锁闭 + * + * @param route + * @param switchList + * @param routeLock + */ + private void batchSetRouteSwitchPositionAndLock(Route route, List switchList, boolean routeLock) { + if (!CollectionUtils.isEmpty(switchList)) { + for (SwitchElement switchElement : switchList) { +// if (switchElement.getASwitch().isOverlapLock() && +// switchElement.isOnPosition()) { +// continue; +// } +// switchElement.getASwitch().ciUse(switchElement.isNormal()); + this.setSingleSwitchPositionDirectly(switchElement.getASwitch(), switchElement.isNormal()); + if (routeLock) { + switchElement.getASwitch().routeLock(route); + } else { // 延续保护锁闭 + switchElement.getASwitch().overlapLock(); + } + } + } + } + + /** + * 直接把单个道岔转到指定位置 + * + * @param aSwitch + * @param normal + */ + public void setSingleSwitchPositionDirectly(Switch aSwitch, boolean normal) { + VirtualRealitySwitch virtualSwitch = aSwitch.getVirtualSwitch(); + if (normal) { + virtualSwitch.control(VirtualRealitySwitch.Operation.NP); + virtualSwitch.finish(); + aSwitch.setPos(SwitchIndication.N); + } else { + virtualSwitch.control(VirtualRealitySwitch.Operation.RP); + virtualSwitch.finish(); + aSwitch.setPos(SwitchIndication.R); + } + } + + /** + * 直接把道岔及其联动道岔转动到指定位置 + * + * @param aSwitch + * @param normal + */ + public void setCoupleSwitchPositionDirectly(Simulation simulation, Switch aSwitch, boolean normal) { + SimulationDataRepository repository = simulation.getRepository(); + this.setSingleSwitchPositionDirectly(aSwitch, normal); + Switch linkedSwitch = aSwitch.queryLinkedSwitch(); + if (Objects.nonNull(linkedSwitch)) { + this.setSingleSwitchPositionDirectly(linkedSwitch, normal); + } + } + + /** + * 直接根据最后一根区段解锁进路 + * + * @param route + */ + public void routeUnlockByEndSection(Route route, Section tailSection) { + if (!route.isRouteSection(tailSection)) { + // 不是进路区段,不解锁 + return; + } + route.startNormalUnlock(); + // 关闭始端信号机 + openSignalDirectly(route.getStart(), route.getStart().getSignalModel().getDefaultAspect()); + boolean right = route.getStart().isRight(); + // 区段是顺序的(否则会有问题) + List
sectionList = route.getSectionList(); + for (Section section : sectionList) { + if (section.isSamePhysical(tailSection.getCode())) { + route.updateUnlockedSection(tailSection); + break; + } + // 直接解锁区段 + if (section.isSwitchTrack()) { // 如果是道岔区段,解锁道岔 + Switch relSwitch = section.getRelSwitch(); + if (tailSection.isSwitchTrack() && tailSection.getRelSwitch().equals(relSwitch)) { + route.updateUnlockedSection(tailSection); + break; + } + if (section.getParent() != null && section.getParent().isCross()) { + section.getParent().routeUnlocking(route); + } + 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()) { + aSwitch.routeUnlock(route); + aSwitch.overlapUnLock(); + } + } + } + } else { + section.routeUnlocking(route); + } + } + } + + public void loadManualTrainOfGroup(Simulation simulation, String groupNumber, Section section, boolean right) { + SimulationDataRepository repository = simulation.getRepository(); + VirtualRealityTrain train = repository.getVRByCode(groupNumber, VirtualRealityTrain.class); + if (!section.isPhysical()) { + section = section.getParent(); + } + BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertNotNull(section.isPhysical(), "列车需加载到物理区段上"); + //重叠检测 + SectionPosition headPosition = new SectionPosition(section, section.getStopPointByDirection(right)); + SectionPosition tailPosition = CalculateService.calculateNextPositionByStartAndLen(headPosition, !right, train.getLen(), false); + boolean willOverlap = vrTrainRunningService.willOverlap(simulation, headPosition, tailPosition); + BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertNotTrue(willOverlap, "列车重叠"); + // 列车上线并构建ATS监控列车信息 + train.initManualTrain(headPosition, right); + //设置列车预选模式、驾驶模式、运行级别 + if (!headPosition.getSection().anyZcWorking()) { + train.initAsRM(); + } else { + MapConfig config = repository.getConfig(); + if (RunLevel.ITC.equals(config.getRunMode())) { + train.initAsAM_I(); + } else if (RunLevel.IL.equals(config.getRunMode())) { + train.initAsRM(); + } + } + TrainInfo trainInfo = TrainInfo.constructManualTrain(train); + trainInfo.tracking(train); + repository.addOnlineTrain(train); + repository.addTrainInfo(trainInfo); + } +} diff --git a/src/main/java/club/joylink/rtss/vo/map/graph/MapSignalButtonVO.java b/src/main/java/club/joylink/rtss/vo/map/graph/MapSignalButtonVO.java index 1fdaffcba..47ec944f7 100644 --- a/src/main/java/club/joylink/rtss/vo/map/graph/MapSignalButtonVO.java +++ b/src/main/java/club/joylink/rtss/vo/map/graph/MapSignalButtonVO.java @@ -37,6 +37,11 @@ public class MapSignalButtonVO { */ private DirectionLabelEnum labelEnum; + /** + * 有计数器? + */ + private boolean hasCount; + public enum Type { /** * 接车按钮 diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index c56892162..403ddd9d1 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,208 +1,208 @@ -server: - port: 9000 - -modbus-tcp: - port: 19000 - -udp: - serverPort: 20002 - clientPort: 20001 - -spring: - profiles: - active: dev - application: - name: joylink-rtss - jackson: - date-format: yyyy-MM-dd HH:mm:ss - time-zone: GMT+8 - default-property-inclusion: non_null - servlet: - multipart: - max-file-size: 10MB - # JavaMailSender 邮件发送的配置 - mail: - host: smtp.exmail.qq.com - port: 465 - username: ServiceEmail@joylink.club - password: wFHcZQFuigKPvpSr - properties: - mail: - smtp: - auth: true - starttls: - enable: true - required: true - socketFactory: - port: 465 - class: javax.net.ssl.SSLSocketFactory - fallback: false - datasource: - driverClassName: com.mysql.cj.jdbc.Driver - hikari: - minimum-idle: 5 # 连接池维护的最小空闲连接数 - maximum-pool-size: 10 #配置最大连接池大小 - auto-commit: true #配置从池返回的连接的默认自动提交行为 - idle-timeout: 30000 # 允许连接在连接池中空闲的最长时间,单位ms - pool-name: HikariPool - max-lifetime: 1800000 # 池中连接关闭后的最长生命周期,单位ms - connection-timeout: 30000 # 等待连接的超时时间,单位ms -mybatis: - mapper-locations: classpath:mybatis/mapper/*.xml - type-aliases-package: club.joylink.rtss.entity - -pagehelper: - helper-dialect: mysql - reasonable: true - support-methods-arguments: true - params: count=countSql - -wechat: - app-id: wx41cb66db5faf330f - app-secret: eb7199c1e73417be6a4d38b4a848effb - domain-uri: https://api.weixin.qq.com - wx-api-url: https://open.weixin.qq.com/connect/oauth2/authorize?appid=${wechat.app-id}&redirect_uri=http://joylink.club/wx/%s&response_type=code&scope=snsapi_base&state=%s#wechat_redirect - sp-app-id: wxe9150dbbcbf9440b - sp-app-secret: 4b5d453e5ec246a3f1b72360c59e4fab - sp-app2-id: wxecb0321367be529c - sp-app2-secret: 3c31cb41588f27a78160092249123766 - sp-app3-id: wxe6140d5985333338 - sp-app3-secret: 6b7359860c22e3607467df421cd24eef - wm-base-url: https://joylink.club/oss/joylink/%s?state=%s - wx-module-url: http://localhost:9001 - mini: - access-token-task-on: false - app-id: wxe9150dbbcbf9440b - app-secret: 4b5d453e5ec246a3f1b72360c59e4fab - -tencent-cloud: - app-id: 1400093601 - app-key: 4a724df65b2bb7e4dc9b4302693f2485 - domain-uri: https://yun.tim.qq.com/v5/tlssmssvr - allow-send: true - -common: - env: dev - -#修改swgger接口前缀,默认为/v2/api-docs -springfox: - documentation: - swagger: - v2: - path: /swagger/api-docs - ---- -spring: - profiles: dev - datasource: - url: jdbc:mysql://localhost:3306/joylink?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true - username: root - password: root - -tencent-cloud: - allow-send: false - -logging: - file: - path: /logs/joylink/rtss - max-size: 100MB - level: - club.joylink.rtss: DEBUG - -common: - env: dev - license-secret-key: joylink - ---- -spring: - profiles: test - datasource: - url: jdbc:mysql://172.16.0.128:3306/joylink?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai - username: root - password: Joylink@0503 - -wechat: - wx-api-url: https://open.weixin.qq.com/connect/oauth2/authorize?appid=${wechat.app-id}&redirect_uri=https://test.joylink.club/wx/%s&response_type=code&scope=snsapi_base&state=%s#wechat_redirect - wx-module-url: https://joylink.club/jlwxs -tencent-cloud: - allow-send: false - -logging: - file: - path: /usr/local/joylink/logs/rtss - level: - club.joylink.rtss: INFO - -common: - env: test - ---- -spring: - profiles: local-test - datasource: - url: jdbc:mysql://192.168.53.22:3306/joylink?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai - username: root - password: joylink0503 - -wechat: - wx-api-url: https://open.weixin.qq.com/connect/oauth2/authorize?appid=${wechat.app-id}&redirect_uri=https://test.joylink.club/wx/%s&response_type=code&scope=snsapi_base&state=%s#wechat_redirect - wx-module-url: https://joylink.club/jlwxs -tencent-cloud: - allow-send: false - -logging: - file: - path: /usr/local/joylink/logs/rtss - level: - club.joylink.rtss: INFO - -common: - env: test - ---- -spring: - profiles: prd - datasource: - url: jdbc:mysql://192.168.0.169:3306/joylink?useSSL=false&serverTimezone=Asia/Shanghai - username: root - password: joylink@0503 -wechat: - app-id: wx41cb66db5faf330f - app-secret: eb7199c1e73417be6a4d38b4a848effb - wx-api-url: https://open.weixin.qq.com/connect/oauth2/authorize?appid=${wechat.app-id}&redirect_uri=https://joylink.club/wx/%s&response_type=code&scope=snsapi_base&state=%s#wechat_redirect - wx-module-url: http://172.21.0.4:9001 - mini: - access-token-task-on: true - -file: - path: https://joylink.club/jlfile/api/upload/joylink/avatar - -logging: - file: - path: /usr/local/joylink/logs/rtss - level: - club.joylink.rtss: INFO - -common: - env: prd - ---- -spring: - profiles: local - datasource: - url: jdbc:mysql://192.168.3.233:3306/joylink?useSSL=false&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true - username: root - password: joylink0503 - -tencent-cloud: - allow-send: false - -logging: - file: - path: /usr/local/joylink/logs/rtss - level: - club.joylink.rtss: INFO - -common: - env: local - license-secret-key: joylink +server: + port: 9000 + +modbus-tcp: + port: 19000 + +udp: + serverPort: 20002 + clientPort: 20001 + +spring: + profiles: + active: dev + application: + name: joylink-rtss + jackson: + date-format: yyyy-MM-dd HH:mm:ss + time-zone: GMT+8 + default-property-inclusion: non_null + servlet: + multipart: + max-file-size: 10MB + # JavaMailSender 邮件发送的配置 + mail: + host: smtp.exmail.qq.com + port: 465 + username: ServiceEmail@joylink.club + password: wFHcZQFuigKPvpSr + properties: + mail: + smtp: + auth: true + starttls: + enable: true + required: true + socketFactory: + port: 465 + class: javax.net.ssl.SSLSocketFactory + fallback: false + datasource: + driverClassName: com.mysql.cj.jdbc.Driver + hikari: + minimum-idle: 5 # 连接池维护的最小空闲连接数 + maximum-pool-size: 10 #配置最大连接池大小 + auto-commit: true #配置从池返回的连接的默认自动提交行为 + idle-timeout: 30000 # 允许连接在连接池中空闲的最长时间,单位ms + pool-name: HikariPool + max-lifetime: 1800000 # 池中连接关闭后的最长生命周期,单位ms + connection-timeout: 30000 # 等待连接的超时时间,单位ms +mybatis: + mapper-locations: classpath:mybatis/mapper/*.xml + type-aliases-package: club.joylink.rtss.entity + +pagehelper: + helper-dialect: mysql + reasonable: true + support-methods-arguments: true + params: count=countSql + +wechat: + app-id: wx41cb66db5faf330f + app-secret: eb7199c1e73417be6a4d38b4a848effb + domain-uri: https://api.weixin.qq.com + wx-api-url: https://open.weixin.qq.com/connect/oauth2/authorize?appid=${wechat.app-id}&redirect_uri=http://joylink.club/wx/%s&response_type=code&scope=snsapi_base&state=%s#wechat_redirect + sp-app-id: wxe9150dbbcbf9440b + sp-app-secret: 4b5d453e5ec246a3f1b72360c59e4fab + sp-app2-id: wxecb0321367be529c + sp-app2-secret: 3c31cb41588f27a78160092249123766 + sp-app3-id: wxe6140d5985333338 + sp-app3-secret: 6b7359860c22e3607467df421cd24eef + wm-base-url: https://joylink.club/oss/joylink/%s?state=%s + wx-module-url: http://localhost:9001 + mini: + access-token-task-on: false + app-id: wxe9150dbbcbf9440b + app-secret: 4b5d453e5ec246a3f1b72360c59e4fab + +tencent-cloud: + app-id: 1400093601 + app-key: 4a724df65b2bb7e4dc9b4302693f2485 + domain-uri: https://yun.tim.qq.com/v5/tlssmssvr + allow-send: true + +common: + env: dev + +#修改swgger接口前缀,默认为/v2/api-docs +springfox: + documentation: + swagger: + v2: + path: /swagger/api-docs + +--- +spring: + profiles: dev + datasource: + url: jdbc:mysql://192.168.3.233:3306/joylink?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true + username: root + password: joylink0503 + +tencent-cloud: + allow-send: false + +logging: + file: + path: /logs/joylink/rtss + max-size: 100MB + level: + club.joylink.rtss: DEBUG + +common: + env: dev + license-secret-key: joylink + +--- +spring: + profiles: test + datasource: + url: jdbc:mysql://172.16.0.128:3306/joylink?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai + username: root + password: Joylink@0503 + +wechat: + wx-api-url: https://open.weixin.qq.com/connect/oauth2/authorize?appid=${wechat.app-id}&redirect_uri=https://test.joylink.club/wx/%s&response_type=code&scope=snsapi_base&state=%s#wechat_redirect + wx-module-url: https://joylink.club/jlwxs +tencent-cloud: + allow-send: false + +logging: + file: + path: /usr/local/joylink/logs/rtss + level: + club.joylink.rtss: INFO + +common: + env: test + +--- +spring: + profiles: local-test + datasource: + url: jdbc:mysql://192.168.53.22:3306/joylink?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai + username: root + password: joylink0503 + +wechat: + wx-api-url: https://open.weixin.qq.com/connect/oauth2/authorize?appid=${wechat.app-id}&redirect_uri=https://test.joylink.club/wx/%s&response_type=code&scope=snsapi_base&state=%s#wechat_redirect + wx-module-url: https://joylink.club/jlwxs +tencent-cloud: + allow-send: false + +logging: + file: + path: /usr/local/joylink/logs/rtss + level: + club.joylink.rtss: INFO + +common: + env: test + +--- +spring: + profiles: prd + datasource: + url: jdbc:mysql://192.168.0.169:3306/joylink?useSSL=false&serverTimezone=Asia/Shanghai + username: root + password: joylink@0503 +wechat: + app-id: wx41cb66db5faf330f + app-secret: eb7199c1e73417be6a4d38b4a848effb + wx-api-url: https://open.weixin.qq.com/connect/oauth2/authorize?appid=${wechat.app-id}&redirect_uri=https://joylink.club/wx/%s&response_type=code&scope=snsapi_base&state=%s#wechat_redirect + wx-module-url: http://172.21.0.4:9001 + mini: + access-token-task-on: true + +file: + path: https://joylink.club/jlfile/api/upload/joylink/avatar + +logging: + file: + path: /usr/local/joylink/logs/rtss + level: + club.joylink.rtss: INFO + +common: + env: prd + +--- +spring: + profiles: local + datasource: + url: jdbc:mysql://192.168.3.233:3306/joylink?useSSL=false&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true + username: root + password: joylink0503 + +tencent-cloud: + allow-send: false + +logging: + file: + path: /usr/local/joylink/logs/rtss + level: + club.joylink.rtss: INFO + +common: + env: local + license-secret-key: joylink