Merge remote-tracking branch 'origin/test' into simulation-ATS-restruct

# Conflicts:
#	src/main/java/club/joylink/rtss/simulation/cbtc/ATS/AtsApiServiceImpl.java
#	src/main/java/club/joylink/rtss/simulation/cbtc/build/RunPlanBuilder.java
#	src/main/java/club/joylink/rtss/simulation/cbtc/data/SimulationDataRepository.java
This commit is contained in:
walker-sheng 2021-07-02 18:49:19 +08:00
commit 9b62d12915
39 changed files with 541 additions and 222 deletions

View File

@ -73,6 +73,14 @@ public class RunPlanUserDataController {
return iRunPlanRoutingService.getUserRoutingBy(user.getId(), mapId);
}
/**
* 查询用户交路数据
*/
@GetMapping("/{mapId}/routing/select")
public List<RunPlanRoutingVO> queryRoutings(@PathVariable Long mapId, RunPlanRoutingQueryVO queryVO, @RequestAttribute AccountVO user) {
return iRunPlanRoutingService.queryRoutes(mapId, queryVO, user);
}
/**
*获取用户交路详情
*/

View File

@ -6,6 +6,7 @@ import club.joylink.rtss.vo.client.PageVO;
import club.joylink.rtss.vo.client.map.MapRoutingSectionVO;
import club.joylink.rtss.vo.client.runplan.*;
import club.joylink.rtss.vo.map.MapStationRunLevelVO;
import club.joylink.rtss.vo.map.MapVO;
import club.joylink.rtss.vo.runplan.RunPlanInputData;
import org.springframework.transaction.annotation.Transactional;
@ -147,6 +148,11 @@ public interface IRunPlanDraftService {
*/
void addRunPlanService(Long planId, RunPlanServiceConfigVO serviceConfig, AccountVO accountVO);
/**
* 构建车次计划
*/
RunPlanTripVO buildTripPlan(RunPlanServiceConfigVO serviceConfig, MapVO mapVO, RunPlanTripConfigVO tripConfigVO);
void generateRunPlanService(Long userId, Long planId, RunPlanInputData inputData);
/**

View File

@ -348,8 +348,6 @@ public class RunPlanDraftService implements IRunPlanDraftService {
RunPlanVO planVO = getRunPlanById(planId);
MapVO mapVO = this.iMapService.getMapDetail(planVO.getMapId());
List<RunPlanTripVO> newTripList = new ArrayList<>();
List<RunPlanRoutingVO> userRoutings = runPlanRoutingService.getUserRoutingBy(accountVO.getId(), mapVO.getId());
Map<Long, RunPlanRoutingVO> userRoutingMap = userRoutings.stream().collect(Collectors.toMap(RunPlanRoutingVO::getId, Function.identity(), (o, n) -> o));
for (RunPlanTripConfigVO tripConfigVO : serviceConfig.getTripConfigList()) {
if (StringUtils.hasText(tripConfigVO.getTripNumber())) {
RunPlanTripVO update = planVO.getTripList().stream()
@ -358,19 +356,17 @@ public class RunPlanDraftService implements IRunPlanDraftService {
return true;
}
return false;
}).findFirst().orElseThrow(() -> BusinessExceptionAssertEnum.DATA_NOT_EXIST.exception());
}).findFirst().orElseThrow(BusinessExceptionAssertEnum.DATA_NOT_EXIST::exception);
setTripTimes(tripConfigVO, update, mapVO);
newTripList.add(update);
} else {
// 查询交路
RunPlanRoutingVO routingData = userRoutingMap.get(tripConfigVO.getRoutingCode());
RunPlanTripVO tripVO = new RunPlanTripVO(routingData);
setDirectionCode(mapVO.getConfigVO().getUpRight(), tripVO);
// 构建类车到站数据
tripVO.setServiceNumber(serviceConfig.getServiceNumber());
setTripTimes(tripConfigVO, routingData, tripVO);
// List<RunPlanRoutingVO> userRoutings = runPlanRoutingService.getUserRoutingBy(accountVO.getId(), mapVO.getId());
// Map<Long, RunPlanRoutingVO> userRoutingMap = userRoutings.stream()
// .collect(Collectors.toMap(RunPlanRoutingVO::getId, Function.identity(), (o, n) -> o));
// // 查询交路
// RunPlanRoutingVO routingData = userRoutingMap.get(tripConfigVO.getRoutingCode());
RunPlanTripVO tripVO = buildTripPlan(serviceConfig, mapVO, tripConfigVO);
newTripList.add(tripVO);
}
}
@ -378,10 +374,18 @@ public class RunPlanDraftService implements IRunPlanDraftService {
this.sortAndResetServiceTripNumber(newTripList);
planVO.getTripList().removeAll(planVO.getTripList().stream().filter(tripVO -> tripVO.getServiceNumber().equals(serviceConfig.getServiceNumber())).collect(Collectors.toList()));
planVO.getTripList().addAll(newTripList);
RunPlanDraft planDraft = planVO.convert2Draft();
planDraft.setTrips(JsonUtils.writeValueAsString(planVO.getTripList()));
planDraft.setStatus(BusinessConsts.ReleaseReview.RELEASE_STATUS_01);
runPlanDraftDAO.updateByPrimaryKeySelective(planDraft);
}
@Override
public RunPlanTripVO buildTripPlan(RunPlanServiceConfigVO serviceConfig, MapVO mapVO, RunPlanTripConfigVO tripConfigVO) {
RunPlanRoutingVO routingData = runPlanRoutingService.getUserRouting(tripConfigVO.getRoutingCode());
RunPlanTripVO tripVO = new RunPlanTripVO(routingData);
setDirectionCode(mapVO.getConfigVO().getUpRight(), tripVO);
// 构建列车到站数据
tripVO.setServiceNumber(serviceConfig.getServiceNumber());
setTripTimes(tripConfigVO, routingData, tripVO);
return tripVO;
}
private void updateRunPlanTrip(RunPlanVO runPlanVO, String SDTNumber, RunPlanTripConfigVO tripConfig, MapVO mapVO) {

View File

@ -1,5 +1,6 @@
package club.joylink.rtss.services.runplan;
import club.joylink.rtss.vo.AccountVO;
import club.joylink.rtss.vo.client.PageVO;
import club.joylink.rtss.vo.client.runplan.user.RunPlanRoutingQueryVO;
import club.joylink.rtss.vo.client.runplan.user.RunPlanRoutingSection;
@ -40,4 +41,6 @@ public interface IRunPlanRoutingService {
void syncDefaultRoutingRefData(Long userId, Long mapId);
RunPlanRoutingVO generateUserRoutingData(RunPlanRoutingVO routingVO);
List<RunPlanRoutingVO> queryRoutes(Long mapId, RunPlanRoutingQueryVO queryVO, AccountVO user);
}

View File

@ -14,6 +14,7 @@ import club.joylink.rtss.simulation.cbtc.data.map.MapElement;
import club.joylink.rtss.simulation.cbtc.data.map.Section;
import club.joylink.rtss.simulation.cbtc.exception.SimulationException;
import club.joylink.rtss.util.JsonUtils;
import club.joylink.rtss.vo.AccountVO;
import club.joylink.rtss.vo.client.PageVO;
import club.joylink.rtss.vo.client.runplan.RunPlanTripVO;
import club.joylink.rtss.vo.client.runplan.RunPlanVO;
@ -200,6 +201,13 @@ public class RunPlanRoutingService implements IRunPlanRoutingService {
return routingVO;
}
@Override
public List<RunPlanRoutingVO> queryRoutes(Long mapId, RunPlanRoutingQueryVO queryVO, AccountVO user) {
return getUserRoutingBy(user.getId(), mapId).stream()
.filter(routing -> Objects.equals(routing.getDestinationCode(), queryVO.getDestinationCode()))
.collect(Collectors.toList());
}
private void generateUserRoutingSections(RunPlanRoutingVO routingVO, Map<String, MapElement> deviceMap) {
Section startSection = (Section) deviceMap.get(routingVO.getStartSectionCode());
Section endSection = (Section) deviceMap.get(routingVO.getEndSectionCode());

View File

@ -94,9 +94,9 @@ public class SectionGeneratorNew implements GeneratorNew {
case Section_Confirm_Axis_Valid:
// 设置计轴失效ARB
if (Objects.nonNull(section.getParent())) {
section.getParent().judgeAsInvalid();
section.getParent().judgeAsNctOccupied();
} else {
section.judgeAsInvalid();
section.judgeAsNctOccupied();
}
break;
case Section_Fault_Unlock:

View File

@ -6,7 +6,6 @@ import club.joylink.rtss.services.training.generatornew.annotation.GeneratorSele
import club.joylink.rtss.simulation.cbtc.ATS.operation.Operation;
import club.joylink.rtss.simulation.cbtc.ATS.service.AtsSectionService;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.data.map.Section;
import club.joylink.rtss.simulation.cbtc.data.map.Switch;
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealitySectionAxleCounter;
import club.joylink.rtss.simulation.cbtc.tool.DeviceStatusModifyTool;
@ -108,7 +107,7 @@ public class SwitchGeneratorNew implements GeneratorNew {
}
case Switch_Confirm_Axis_Valid:{
// 背景为道岔计轴失效
aSwitch.getA().getParent().judgeAsInvalid();
aSwitch.getA().getParent().judgeAsNctOccupied();
break;
}
default:

View File

@ -178,13 +178,17 @@ public class AtpSectionService {
* @param sectionList
*/
public void sectionARBCheck(Simulation simulation, Section section, List<Section> sectionList) {
if (!section.isInvalid() && section.isNctOccupied()) {
if (!sectionList.contains(section)) {
log.debug(String.format("区段[%s(%s)]检测为ARB故障",
section.getName(), section.getCode()));
section.judgeAsInvalid();
}
//目前ARB故障才会导致ARB判定
if (Section.AxleFault.ARB.equals(section.getFault()) && section.getVirtualAxleCounter().isOccupy() && !sectionList.contains(section)) {
section.judgeAsARB();
} else if (section.getVirtualAxleCounter().isOccupy() && sectionList.contains(section)){
section.judgeAsNctOccupied();
}
// if (/*!section.isInvalid() &&*/ section.isNctOccupied()) {
// if (!sectionList.contains(section)) {
// section.judgeAsNctOccupied();
// }
// }
//ARB故障恢复判断
if (Section.AxleFault.ARB.equals(section.getFault()) && !section.getVirtualAxleCounter().isOccupy()) {
Section.AxleFault.ARB.fix(section);
@ -192,7 +196,7 @@ public class AtpSectionService {
}
/**
* 获取车可能存在的范围
* 获取非通信车可能存在的范围
*
* @param simulation
* @param trainList
@ -201,6 +205,9 @@ public class AtpSectionService {
public List<Section> getTrainExistAxleSectionsUnderDelay(Simulation simulation, List<VirtualRealityTrain> trainList) {
List<Section> list = new ArrayList<>();
for (VirtualRealityTrain train : trainList) {
//只统计非通信车
if (train.isCBTC())
continue;
boolean right = train.isRight();
SectionPosition headPosition = train.getHeadPosition();
float offset = 50;

View File

@ -72,8 +72,8 @@ public class GroundAtpApiServiceImpl implements GroundAtpApiService {
for (Section section : axleSectionList) {
this.atpSectionService.sectionARBCheck(simulation, section, trainExistAxleSectionList);
}
// 判断是否要将ARB设为非通信车占用
this.atpSectionService.judgeFaultSectionAsNctOccupied(nctApproachSignalMap);
// // 判断是否要将ARB设为非通信车占用
// this.atpSectionService.judgeFaultSectionAsNctOccupied(nctApproachSignalMap);
// 根据道岔的位置修改道岔区段的占用暂时只处理因故障导致的占用
repository.getSwitchList().stream().filter(aSwitch -> Section.AxleFault.CBTC_OCCUPIED_FAULT.equals(aSwitch.getA().getFault()))
.forEach(aSwitch -> {

View File

@ -56,6 +56,7 @@ public class ZCLogicLoop {
if (!Station.Fault.INTERLOCK_MACHINE_FAULT.equals(deviceStation.getFault())) {
Float distance2NextSignal = train.calculateDistance2NextNormalOpenSignal();
if (distance2NextSignal != null && distance2NextSignal <= 5) {
train.setPositioned(true);
this.calculateMAOfITC(simulation, train);
}
}
@ -177,7 +178,7 @@ public class ZCLogicLoop {
break;
}
//非通信车占用区段
if (temp.isNonCbtcOccupy() && !section.isInvalid()) {
if (temp.isNonCbtcOccupy() && !temp.isInvalid()) {
endList.add(new MovementAuthority.End(temp, MovementAuthority.EndType.NCT_OCCUPIED_SECTION));
}
//检查关闭的区段

View File

@ -3,6 +3,8 @@ package club.joylink.rtss.simulation.cbtc.ATS;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.data.map.MapElement;
import club.joylink.rtss.simulation.cbtc.data.support.TrainStopMessage;
import club.joylink.rtss.vo.AccountVO;
import club.joylink.rtss.vo.client.runplan.RunPlanServiceConfigVO;
import java.util.List;
@ -52,4 +54,14 @@ public interface AtsApiService {
void handleTrainOnTransfer(Simulation simulation, String groupNumber, String sectionCode);
void cancelStandSkipSetOfTrain(Simulation simulation, String groupNumber, String standCode);
/**
* 添加车次计划加线
*/
void addTripPlan(Simulation simulation, RunPlanServiceConfigVO serviceConfig, AccountVO user);
/**
* 删除车次计划抽线
*/
void deleteTripPlan(Simulation simulation, String serviceNumber, String tripNumber);
}

View File

@ -1,20 +1,34 @@
package club.joylink.rtss.simulation.cbtc.ATS;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.services.IRunPlanDraftService;
import club.joylink.rtss.simulation.cbtc.ATS.service.AtsPlanService;
import club.joylink.rtss.simulation.cbtc.ATS.service.AtsStandService;
import club.joylink.rtss.simulation.cbtc.ATS.service.AtsTrainMonitorService;
import club.joylink.rtss.simulation.cbtc.ATS.service.AtsTrainService;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.build.RunPlanBuilder;
import club.joylink.rtss.simulation.cbtc.build.SimulationBuilder;
import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository;
import club.joylink.rtss.simulation.cbtc.data.map.MapElement;
import club.joylink.rtss.simulation.cbtc.data.map.Section;
import club.joylink.rtss.simulation.cbtc.data.map.Station;
import club.joylink.rtss.simulation.cbtc.data.plan.TripPlan;
import club.joylink.rtss.simulation.cbtc.data.support.TrainStopMessage;
import club.joylink.rtss.simulation.cbtc.data.vo.TrainInfo;
import club.joylink.rtss.simulation.cbtc.event.SimulationTripPlanChangeEvent;
import club.joylink.rtss.util.JsonUtils;
import club.joylink.rtss.vo.AccountVO;
import club.joylink.rtss.vo.client.runplan.RunPlanServiceConfigVO;
import club.joylink.rtss.vo.client.runplan.RunPlanTripConfigVO;
import club.joylink.rtss.vo.client.runplan.RunPlanTripVO;
import club.joylink.rtss.vo.client.runplan.RunPlanVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@ -36,6 +50,12 @@ public class AtsApiServiceImpl implements AtsApiService {
@Autowired
private AtsTrainMonitorService atsTrainMonitorService;
@Autowired
private IRunPlanDraftService iRunPlanDraftService;
@Autowired
private ApplicationContext applicationContext;
@Override
public void handleDeviceStatus(Simulation simulation, List<? extends MapElement> deviceList) {
this.atsMessageCollectAndDispatcher.collectDeviceStatusAndSend(simulation, deviceList);
@ -54,7 +74,7 @@ public class AtsApiServiceImpl implements AtsApiService {
public void handleTrainStopMessage(Simulation simulation, TrainStopMessage stopMessage) {
// 处理正常站台停车
SimulationDataRepository repository = simulation.getRepository();
TrainInfo train = repository.findSupervisedTrainByGroup(stopMessage.getGroupNumber());
TrainInfo train = repository.findSupervisedTrainByGroup(stopMessage.getTrain().getGroupNumber());
Section section = stopMessage.getSection();
Station station = section.getStation();
if (train == null || station == null) {
@ -120,7 +140,42 @@ public class AtsApiServiceImpl implements AtsApiService {
if (Objects.isNull(train)) {
return;
}
atsStandService.cancelJumpStop(simulation, standCode,groupNumber);
atsStandService.cancelJumpStop(simulation, standCode, groupNumber);
}
@Override
public void addTripPlan(Simulation simulation, RunPlanServiceConfigVO serviceConfig, AccountVO user) {
RunPlanTripConfigVO tripConfig = serviceConfig.getTripConfigList().get(0);
String serviceNumber = serviceConfig.getServiceNumber();
String tripNumber = tripConfig.getTripNumber();
BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED
.assertNull(simulation.getRepository().findTripPlan(serviceNumber, tripNumber),
String.format("车次计划[%s-%s]已存在", serviceNumber, tripNumber));
RunPlanTripVO tripPlanVO = iRunPlanDraftService.buildTripPlan(serviceConfig, simulation.getBuildParams().getMap(), tripConfig);
tripPlanVO.setTripNumber(tripConfig.getTripNumber());
tripPlanVO.setAdd(true);
RunPlanVO runPlan = simulation.getBuildParams().getRunPlan();
runPlan.getTripList().add(tripPlanVO);
try {
List<String> errMsgList = new ArrayList<>();
TripPlan tripPlan = RunPlanBuilder.buildTripPlan(simulation.getRepository().getDeviceMap(), errMsgList, tripPlanVO);
BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.assertNotNull(tripPlan, JsonUtils.writeValueAsString(errMsgList));
simulation.getRepository().addTrip(tripPlan);
} catch (RuntimeException e) {
runPlan.getTripList().remove(tripPlanVO);
throw e;
}
applicationContext.publishEvent(new SimulationTripPlanChangeEvent(this, simulation, List.of(tripPlanVO)));
}
@Override
public void deleteTripPlan(Simulation simulation, String serviceNumber, String tripNumber) {
List<TripPlan> invalidList = simulation.getRepository().invalidPlanFrom(serviceNumber, tripNumber);
BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertCollectionNotEmpty(invalidList, "车次计划不存在");
RunPlanVO runPlan = simulation.getBuildParams().getRunPlan();
List<RunPlanTripVO> changeTrips = runPlan.invalidTripPlan(invalidList);
simulation.getRepository().addChangeTrips(changeTrips);
applicationContext.publishEvent(new SimulationTripPlanChangeEvent(this, simulation, changeTrips));
}
}

View File

@ -1,24 +1,30 @@
package club.joylink.rtss.simulation.cbtc.ATS.operation.handler;
import club.joylink.rtss.simulation.cbtc.ATS.AtsApiService;
import club.joylink.rtss.simulation.cbtc.ATS.operation.Operation;
import club.joylink.rtss.simulation.cbtc.ATS.operation.annotation.OperateHandler;
import club.joylink.rtss.simulation.cbtc.ATS.operation.annotation.OperateHandlerMapping;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.vo.AccountVO;
import club.joylink.rtss.vo.client.runplan.RunPlanServiceConfigVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@Slf4j
@OperateHandler
public class RunPlanOperateHandler {
@OperateHandlerMapping(type = Operation.Type.RunPlan_Add_Trip)
public void addTripPlan(Simulation simulation) {
@Autowired
private AtsApiService atsApiService;
@OperateHandlerMapping(type = Operation.Type.RunPlan_Add_Trip)
public void addTripPlan(Simulation simulation, RunPlanServiceConfigVO serviceConfig, AccountVO user) {
atsApiService.addTripPlan(simulation, serviceConfig, user);
}
@OperateHandlerMapping(type = Operation.Type.RunPlan_Delete_Trip)
public void deleteTripPlan(Simulation simulation, String serviceNumber,
String tripNumber, String stationCode) {
public void deleteTripPlan(Simulation simulation, String serviceNumber, String tripNumber) {
atsApiService.deleteTripPlan(simulation, serviceNumber, tripNumber);
}
}

View File

@ -1,5 +1,6 @@
package club.joylink.rtss.simulation.cbtc.CI.service;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.constant.SimulationConstants;
import club.joylink.rtss.simulation.cbtc.constant.SimulationModule;
@ -343,6 +344,8 @@ public class RouteService {
if (switchElement.getASwitch().isFaultOnPosition(switchElement.isNormal()) && switchElement.getASwitch().isLoss()) {
// 道岔指定位置故障且失表,不再触发
return false;
} else if (switchElement.getASwitch().isLocked() && !switchElement.getASwitch().isOnPosition(switchElement.isNormal())) {
return false;
}
}
}
@ -726,6 +729,9 @@ public class RouteService {
* @param route
*/
public boolean cancelNoApproachLock(Simulation simulation, Route route) {
if (route.isTransferRoute() && simulation.getRepository().getConfig().isTransferRouteCanOnlyFaultUnlock()) {
throw BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.exception("转换轨进路只能通过区故解取消");
}
if (route.isLock()) { // 进路锁闭
// 取消进路逻辑
if (simulation.getRepository().getConfig().isCancelAtsControlOfAllRoutesWhenCancelRoute()) {
@ -812,6 +818,9 @@ public class RouteService {
* @param route
*/
public boolean humanCancel(Simulation simulation, Route route) {
if (route.isTransferRoute() && simulation.getRepository().getConfig().isTransferRouteCanOnlyFaultUnlock()) {
throw BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.exception("转换轨进路只能通过区故解取消");
}
if (route.isGuideSignalOpen()) { //根据宁波一HMI教学视频添加该分支
this.cancelGuideRoute(simulation, route);
} else {
@ -1463,7 +1472,7 @@ public class RouteService {
List<RouteOverlap> overlapList = simulation.getRepository()
.getListByType(MapElement.DeviceType.OVERLAP, RouteOverlap.class);
for (RouteOverlap routeOverlap : overlapList) {
if (routeOverlap.allSectionsOl() && section.isRouteLockOn(routeOverlap.isRight()) && routeOverlap.isRouteLastSection(section)) {
if (routeOverlap.allSectionsOl() && stopMessage.getTrain().isParkingAt() && section.isRouteLockOn(routeOverlap.isRight()) && routeOverlap.isRouteLastSection(section)) {
// 是此延续保护的解锁区段立即解锁
routeOverlap.releaseImmediately();
log.debug(String.format("收到列车停稳消息,[%s]延续保护[%s],触发区段[%s(%s)]立即解锁",

View File

@ -643,6 +643,7 @@ public class GroupSimulationServiceImpl implements GroupSimulationService {
SchedulingPlanNewVO schedulingPlan = this.schedulingService
.querySchedulingPlanUserFirst(userId, templateId, SimulationConstants.getRunPlanDate());
this.simulationLifeCycleService.reloadRunPlan(simulation, runPlan, schedulingPlan);
simulation.getRepository().clearChangeTrips(); //清除掉之前的车次计划变化信息
}
@Override

View File

@ -28,6 +28,7 @@ import club.joylink.rtss.simulation.cbtc.script.ScriptBO;
import club.joylink.rtss.simulation.vo.SimulationInfoVO;
import club.joylink.rtss.vo.AccountVO;
import club.joylink.rtss.vo.client.fault.FaultRuleVO;
import club.joylink.rtss.vo.client.runplan.RunPlanTripVO;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
@ -39,6 +40,7 @@ import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;
/**

View File

@ -13,8 +13,6 @@ import club.joylink.rtss.simulation.cbtc.communication.Joylink3DMessageService;
import club.joylink.rtss.simulation.cbtc.communication.vo.fault.DeviceFaultInfo;
import club.joylink.rtss.simulation.cbtc.competition.CompetitionAndScriptManager;
import club.joylink.rtss.simulation.cbtc.competition.ScriptExecuteService;
import club.joylink.rtss.simulation.cbtc.constant.SimulationConstants;
import club.joylink.rtss.simulation.cbtc.constant.SimulationModule;
import club.joylink.rtss.simulation.cbtc.conversation.Conversation;
import club.joylink.rtss.simulation.cbtc.conversation.ConversationMessage;
import club.joylink.rtss.simulation.cbtc.data.plan.RealRun;
@ -28,8 +26,6 @@ import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.SimulationRealDev
import club.joylink.rtss.simulation.cbtc.device.virtual.VRDeviceLogicLoop;
import club.joylink.rtss.simulation.cbtc.device.virtual.VRTrainRunningService;
import club.joylink.rtss.simulation.cbtc.event.*;
import club.joylink.rtss.simulation.cbtc.exception.SimulationException;
import club.joylink.rtss.simulation.cbtc.exception.SimulationExceptionType;
import club.joylink.rtss.simulation.cbtc.fault.FaultGenerator;
import club.joylink.rtss.simulation.cbtc.member.SimulationMember;
import club.joylink.rtss.simulation.cbtc.member.SimulationUser;
@ -40,6 +36,8 @@ import club.joylink.rtss.vo.client.SocketMessageVO;
import club.joylink.rtss.vo.client.WebSocketMessageType;
import club.joylink.rtss.vo.client.factory.SocketMessageFactory;
import club.joylink.rtss.vo.client.psl.PslStatus;
import club.joylink.rtss.vo.client.runplan.RunPlanEChartsDataVO;
import club.joylink.rtss.vo.client.runplan.RunPlanTripVO;
import club.joylink.rtss.vo.client.script.ScriptActionVO;
import club.joylink.rtss.vo.client.simulationv1.SimulationMemberMessageVO;
import club.joylink.rtss.vo.client.simulationv1.SimulationUserMessageVO;
@ -497,6 +495,12 @@ public class SimulationMainThread {
group, realRunRecordList);
this.stompMessageService.sendToUser(String.valueOf(event.getUserId()), allTrainRealRunRecord);
}
// 将车次计划变化信息同步给用户
List<RunPlanTripVO> changeTrips = simulation.getRepository().getChangeTrips();
if (!CollectionUtils.isEmpty(changeTrips)) {
SocketMessageVO<RunPlanEChartsDataVO> tripPlanChangeMessage = SocketMessageFactory.buildTripPlanChangeMessage(event.getGroup(), changeTrips);
this.stompMessageService.sendToUser(String.valueOf(event.getUserId()), tripPlanChangeMessage);
}
}
}
@ -849,4 +853,10 @@ public class SimulationMainThread {
SocketMessageVO<String> message = SocketMessageFactory.buildOrderPaySuccessMessage(event.getOrderCode());
this.stompMessageService.sendToUser(event.getUserId(), message);
}
@EventListener
public void handleTripPlanChangeEvent(SimulationTripPlanChangeEvent event) {
SocketMessageVO<RunPlanEChartsDataVO> message = SocketMessageFactory.buildTripPlanChangeMessage(event.getSimulation().getId(), event.getChangeTrips());
this.stompMessageService.sendToUser(event.getSimulation().getSimulationUserIds(), message);
}
}

View File

@ -112,103 +112,8 @@ public class RunPlanBuilder {
List<RunPlanTripVO> tripList = runPlan.getTripList();
if (!CollectionUtils.isEmpty(tripList)) {
tripList.forEach(runPlanTripVO -> {
TripPlan.TripPlanBuilder tripBuilder = TripPlan.builder();
tripBuilder.serviceNumber(runPlanTripVO.getServiceNumber())
.tripNumber(runPlanTripVO.getTripNumber())
.destinationCode(runPlanTripVO.getDestinationCode())
.right(runPlanTripVO.getRight())
.startTime(runPlanTripVO.getStartTime())
.endTime(runPlanTripVO.getEndTime());
MapElement start = deviceMap.get(runPlanTripVO.getStartSectionCode());
if (Objects.isNull(start) ||
!Objects.equals(MapElement.DeviceType.SECTION, start.getDeviceType())) {
errMsgList.add(String.format("计划车次[%s|%s|%s]起始区段[%s]数据不存在或不是区段",
runPlanTripVO.getServiceNumber(), runPlanTripVO.getTripNumber(),
runPlanTripVO.getDestinationCode(),
runPlanTripVO.getStartSectionCode()));
} else {
tripBuilder.startSection((Section) start);
}
MapElement end = deviceMap.get(runPlanTripVO.getEndSectionCode());
if (Objects.isNull(end) ||
!Objects.equals(MapElement.DeviceType.SECTION, end.getDeviceType())) {
errMsgList.add(String.format("计划车次[%s|%s|%s]终点区段[%s]数据不存在或不是区段",
runPlanTripVO.getServiceNumber(), runPlanTripVO.getTripNumber(),
runPlanTripVO.getDestinationCode(),
runPlanTripVO.getStartSectionCode()));
} else {
Section section = (Section) end;
tripBuilder.endSection(section);
}
boolean outbound = Objects.nonNull(runPlanTripVO.getIsOutbound()) ? runPlanTripVO.getIsOutbound() : false;
tripBuilder.outbound(outbound);
boolean inbound = Objects.nonNull(runPlanTripVO.getIsInbound()) ? runPlanTripVO.getIsInbound() : false;
tripBuilder.inbound(inbound);
boolean backup = Objects.nonNull(runPlanTripVO.getIsBackUp()) ? runPlanTripVO.getIsBackUp() : false;
tripBuilder.backup(backup);
boolean turnBack = Objects.nonNull(runPlanTripVO.getIsReentry()) ? runPlanTripVO.getIsReentry() : false;
tripBuilder.turnBack(turnBack);
// 车站到发时刻表
List<StationPlan> stationPlanList = new ArrayList<>();
tripBuilder.planList(stationPlanList);
List<RunPlanTripTimeVO> timeList = runPlanTripVO.getTimeList();
if (CollectionUtils.isEmpty(timeList)) {
errMsgList.add(String.format("计划车次[%s|%s|%s]没有车站到发时刻表",
runPlanTripVO.getServiceNumber(), runPlanTripVO.getTripNumber(),
runPlanTripVO.getDestinationCode()));
} else {
timeList.forEach(runPlanTripTimeVO -> {
StationPlan.StationPlanBuilder builder = StationPlan.builder();
MapElement station = deviceMap.get(runPlanTripTimeVO.getStationCode());
if (Objects.isNull(station) ||
!Objects.equals(MapElement.DeviceType.STATION, station.getDeviceType())) {
errMsgList.add(String.format("计划车次[%s|%s|%s]车站到发时刻表车站[%s]数据不存在或不是车站",
runPlanTripVO.getServiceNumber(), runPlanTripVO.getTripNumber(),
runPlanTripVO.getDestinationCode(),
runPlanTripTimeVO.getStationCode()));
} else {
builder.station((Station) station);
}
MapElement section = deviceMap.get(runPlanTripTimeVO.getSectionCode());
if (Objects.isNull(section) ||
!Objects.equals(MapElement.DeviceType.SECTION, section.getDeviceType())) {
errMsgList.add(String.format("计划车次[%s|%s|%s]车站到发时刻表区段[%s]数据不存在或不是区段",
runPlanTripVO.getServiceNumber(), runPlanTripVO.getTripNumber(),
runPlanTripVO.getDestinationCode(),
runPlanTripTimeVO.getSectionCode()));
} else {
builder.section((Section) section);
}
LocalTime arrivalTime = runPlanTripTimeVO.getArrivalTime();
LocalTime departureTime = runPlanTripTimeVO.getDepartureTime();
if (Objects.isNull(arrivalTime) || Objects.isNull(departureTime)) {
errMsgList.add(String.format("计划车次[%s|%s|%s]车站到发时刻表计划到达时间和计划发车时间不能为空",
runPlanTripVO.getServiceNumber(), runPlanTripVO.getTripNumber(),
runPlanTripVO.getDestinationCode()));
} else if (arrivalTime.isAfter(departureTime)) {
errMsgList.add(String.format("计划车次[%s|%s|%s]车站到发时刻表计划到达时间不能比计划发车时间晚",
runPlanTripVO.getServiceNumber(), runPlanTripVO.getTripNumber(),
runPlanTripVO.getDestinationCode()));
} else {
builder.arriveTime(arrivalTime);
builder.leaveTime(departureTime);
int parkTime = departureTime.toSecondOfDay() - arrivalTime.toSecondOfDay();
if (parkTime <= 0) {
builder.park(false);
builder.parkTime(0);
} else {
builder.park(true);
builder.parkTime(parkTime);
}
}
StationPlan plan = builder.build();
stationPlanList.add(plan);
});
if (CollectionUtils.isEmpty(errMsgList)) {
// 排序
stationPlanList.sort(Comparator.comparing(StationPlan::getArriveTime));
}
TripPlan tripPlan = tripBuilder.build();
TripPlan tripPlan = buildTripPlan(deviceMap, errMsgList, runPlanTripVO);
if (tripPlan != null) {
result.addTripPlan(tripPlan);
}
});
@ -351,4 +256,106 @@ public class RunPlanBuilder {
result.sort();
return result;
}
public static TripPlan buildTripPlan(Map<String, ? extends MapElement> deviceMap, List<String> errMsgList, RunPlanTripVO runPlanTripVO) {
TripPlan.TripPlanBuilder tripBuilder = TripPlan.builder();
tripBuilder.serviceNumber(runPlanTripVO.getServiceNumber())
.tripNumber(runPlanTripVO.getTripNumber())
.destinationCode(runPlanTripVO.getDestinationCode())
.right(runPlanTripVO.getRight())
.startTime(runPlanTripVO.getStartTime())
.endTime(runPlanTripVO.getEndTime());
MapElement start = deviceMap.get(runPlanTripVO.getStartSectionCode());
if (Objects.isNull(start) ||
!Objects.equals(MapElement.DeviceType.SECTION, start.getDeviceType())) {
errMsgList.add(String.format("计划车次[%s|%s|%s]起始区段[%s]数据不存在或不是区段",
runPlanTripVO.getServiceNumber(), runPlanTripVO.getTripNumber(),
runPlanTripVO.getDestinationCode(),
runPlanTripVO.getStartSectionCode()));
} else {
tripBuilder.startSection((Section) start);
}
MapElement end = deviceMap.get(runPlanTripVO.getEndSectionCode());
if (Objects.isNull(end) ||
!Objects.equals(MapElement.DeviceType.SECTION, end.getDeviceType())) {
errMsgList.add(String.format("计划车次[%s|%s|%s]终点区段[%s]数据不存在或不是区段",
runPlanTripVO.getServiceNumber(), runPlanTripVO.getTripNumber(),
runPlanTripVO.getDestinationCode(),
runPlanTripVO.getStartSectionCode()));
} else {
Section section = (Section) end;
tripBuilder.endSection(section);
}
boolean outbound = Objects.nonNull(runPlanTripVO.getIsOutbound()) ? runPlanTripVO.getIsOutbound() : false;
tripBuilder.outbound(outbound);
boolean inbound = Objects.nonNull(runPlanTripVO.getIsInbound()) ? runPlanTripVO.getIsInbound() : false;
tripBuilder.inbound(inbound);
boolean backup = Objects.nonNull(runPlanTripVO.getIsBackUp()) ? runPlanTripVO.getIsBackUp() : false;
tripBuilder.backup(backup);
boolean turnBack = Objects.nonNull(runPlanTripVO.getIsReentry()) ? runPlanTripVO.getIsReentry() : false;
tripBuilder.turnBack(turnBack);
// 车站到发时刻表
List<StationPlan> stationPlanList = new ArrayList<>();
tripBuilder.planList(stationPlanList);
List<RunPlanTripTimeVO> timeList = runPlanTripVO.getTimeList();
if (CollectionUtils.isEmpty(timeList)) {
errMsgList.add(String.format("计划车次[%s|%s|%s]没有车站到发时刻表",
runPlanTripVO.getServiceNumber(), runPlanTripVO.getTripNumber(),
runPlanTripVO.getDestinationCode()));
return null;
} else {
timeList.forEach(runPlanTripTimeVO -> {
StationPlan.StationPlanBuilder builder = StationPlan.builder();
MapElement station = deviceMap.get(runPlanTripTimeVO.getStationCode());
if (Objects.isNull(station) ||
!Objects.equals(MapElement.DeviceType.STATION, station.getDeviceType())) {
errMsgList.add(String.format("计划车次[%s|%s|%s]车站到发时刻表车站[%s]数据不存在或不是车站",
runPlanTripVO.getServiceNumber(), runPlanTripVO.getTripNumber(),
runPlanTripVO.getDestinationCode(),
runPlanTripTimeVO.getStationCode()));
} else {
builder.station((Station) station);
}
MapElement section = deviceMap.get(runPlanTripTimeVO.getSectionCode());
if (Objects.isNull(section) ||
!Objects.equals(MapElement.DeviceType.SECTION, section.getDeviceType())) {
errMsgList.add(String.format("计划车次[%s|%s|%s]车站到发时刻表区段[%s]数据不存在或不是区段",
runPlanTripVO.getServiceNumber(), runPlanTripVO.getTripNumber(),
runPlanTripVO.getDestinationCode(),
runPlanTripTimeVO.getSectionCode()));
} else {
builder.section((Section) section);
}
LocalTime arrivalTime = runPlanTripTimeVO.getArrivalTime();
LocalTime departureTime = runPlanTripTimeVO.getDepartureTime();
if (Objects.isNull(arrivalTime) || Objects.isNull(departureTime)) {
errMsgList.add(String.format("计划车次[%s|%s|%s]车站到发时刻表计划到达时间和计划发车时间不能为空",
runPlanTripVO.getServiceNumber(), runPlanTripVO.getTripNumber(),
runPlanTripVO.getDestinationCode()));
} else if (arrivalTime.isAfter(departureTime)) {
errMsgList.add(String.format("计划车次[%s|%s|%s]车站到发时刻表计划到达时间不能比计划发车时间晚",
runPlanTripVO.getServiceNumber(), runPlanTripVO.getTripNumber(),
runPlanTripVO.getDestinationCode()));
} else {
builder.arriveTime(arrivalTime);
builder.leaveTime(departureTime);
int parkTime = departureTime.toSecondOfDay() - arrivalTime.toSecondOfDay();
if (parkTime <= 0) {
builder.park(false);
builder.parkTime(0);
} else {
builder.park(true);
builder.parkTime(parkTime);
}
}
StationPlan plan = builder.build();
stationPlanList.add(plan);
});
if (CollectionUtils.isEmpty(errMsgList)) {
// 排序
stationPlanList.sort(Comparator.comparing(StationPlan::getArriveTime));
}
return tripBuilder.build();
}
}
}

View File

@ -21,6 +21,7 @@ import club.joylink.rtss.simulation.cbtc.exception.SimulationException;
import club.joylink.rtss.simulation.cbtc.exception.SimulationExceptionType;
import club.joylink.rtss.util.StrUtils;
import club.joylink.rtss.vo.client.psl.PslStatus;
import club.joylink.rtss.vo.client.runplan.RunPlanTripVO;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
@ -207,7 +208,7 @@ public class SimulationDataRepository {
*/
private final Map<String, Set<Catenary>> catenaryMap = new ConcurrentHashMap<>();
private Map<Section,List<Responder>> sectionRespondersMap = new HashMap<>();
private Map<Section, List<Responder>> sectionRespondersMap = new HashMap<>();
/**
* ats用户设置的列车偏离操作信息
@ -215,6 +216,17 @@ public class SimulationDataRepository {
*/
private final Map<String, DeviationInfo> deviationInfoMap = new ConcurrentHashMap<>();
/** 加线、抽线的计划 */
private List<RunPlanTripVO> changeTrips = new CopyOnWriteArrayList<>();
public void addChangeTrips(Collection<RunPlanTripVO> trips) {
this.changeTrips.addAll(trips);
}
public void clearChangeTrips() {
this.changeTrips.clear();
}
public void addDeviationInfo(DeviationInfo deviationInfo) {
deviationInfoMap.put(deviationInfo.getStartStand().getCode(), deviationInfo);
deviationInfoMap.put(deviationInfo.getEndStand().getCode(), deviationInfo);
@ -316,6 +328,7 @@ public class SimulationDataRepository {
/**
* 根据设备集中站的code获取设备集中站下的道岔
*
* @param code
* @return
*/
@ -460,6 +473,7 @@ public class SimulationDataRepository {
/**
* 查找路径
*
* @param start
* @param end
* @return
@ -470,6 +484,7 @@ public class SimulationDataRepository {
/**
* 根据终到区段查找路径
*
* @param start
* @return
*/
@ -485,6 +500,7 @@ public class SimulationDataRepository {
/**
* 根据终到区段查找路径
*
* @param end
* @return
*/
@ -708,6 +724,18 @@ public class SimulationDataRepository {
this.deviceInfoMap.clear();
this.trainHmiMap.clear();
this.tdtStatusMap.clear();
// 运行图
this.changeTrips.clear();
serviceTripsMap.forEach((k, v) -> {
for (Iterator<TripPlan> iterator = v.iterator(); iterator.hasNext(); ) {
TripPlan tripPlan = iterator.next();
if (tripPlan.isAdd()) {
iterator.remove();
} else if (tripPlan.isInvalid()) {
tripPlan.setInvalid(false);
}
}
});
}
/**
@ -765,7 +793,7 @@ public class SimulationDataRepository {
// tripPlans.sort(Comparator.comparing(TripPlan::getStartTime));
TripPlan next = null;
for (int i = 0; i < tripPlans.size(); i++) {
if (Objects.equals(tripPlans.get(i).getTripNumber(), tripNumber) && i+1<tripPlans.size()) {
if (Objects.equals(tripPlans.get(i).getTripNumber(), tripNumber) && i + 1 < tripPlans.size()) {
next = tripPlans.get(i + 1);
break;
}
@ -846,6 +874,7 @@ public class SimulationDataRepository {
/**
* 此方法只能用于计划车次号唯一的线路比如西门子风格的运行计划
*
* @param tripNumber
* @return
*/
@ -1101,6 +1130,7 @@ public class SimulationDataRepository {
/**
* 查询指定时间范围内的出库计划
*
* @param start
* @param end
* @return
@ -1165,6 +1195,37 @@ public class SimulationDataRepository {
return null;
}
public List<TripPlan> invalidPlanFrom(String serviceNumber, String tripNumber) {
List<TripPlan> invalidList = new ArrayList<>();
TripPlan tripPlan = findTripPlan(serviceNumber, tripNumber);
if (tripPlan != null) {
TrainInfo trainInfo = findSupervisedTrainByTrip(serviceNumber, tripNumber);
BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED
.assertNull(trainInfo, String.format("车次计划[%s-%s]已在运行", serviceNumber, tripNumber));
invalidList.add(tripPlan);
List<TripPlan> tripPlans = serviceTripsMap.get(serviceNumber);
for (TripPlan plan : tripPlans) {
if (plan.getStartTime().isAfter(tripPlan.getStartTime())) {
trainInfo = findSupervisedTrainByTrip(plan.getServiceNumber(), plan.getTripNumber());
BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED
.assertNull(trainInfo, String.format("车次计划[%s-%s]已在运行", plan.getServiceNumber(), plan.getTripNumber()));
invalidList.add(plan);
}
}
invalidList.forEach(plan -> plan.setInvalid(true));
}
return invalidList;
}
public void addTrip(TripPlan tripPlan) {
List<TripPlan> trips = this.serviceTripsMap.get(tripPlan.getServiceNumber());
if (trips == null) {
trips = new ArrayList<>();
serviceTripsMap.put(tripPlan.getServiceNumber(), trips);
}
trips.add(tripPlan);
}
public List<TripPlan> getTripPlanListOfStand(Section section) {
return this.standTripMap.get(section.getCode());
}

View File

@ -207,6 +207,9 @@ public class MapConfig {
/** 设置头码车时检查方向 */
private boolean checkDirectionWhenSetHead;
/** 转换轨进路只能通过故障解锁来取消 */
private boolean transferRouteCanOnlyFaultUnlock;
private Set<SimulationMember.Type> needConfirmConnectMembers =
Stream.of(DISPATCHER, STATION_SUPERVISOR, MAINTAINER, ELECTRIC_DISPATCHER).collect(Collectors.toSet());
@ -255,6 +258,7 @@ public class MapConfig {
setFiguresOfTripNumber(configVO.getFiguresOfTripNumber());
setFiguresOfServiceNumber(configVO.getFiguresOfServiceNumber());
setCheckDirectionWhenSetHead(configVO.isCheckDirectionWhenSetHead());
setTransferRouteCanOnlyFaultUnlock(configVO.isTransferRouteCanOnlyFaultUnlock());
}
}

View File

@ -574,6 +574,10 @@ public class Route extends MapNamedElement {
getLogicSections().forEach(section -> section.setDelayUnlock(false));
}
public boolean isTransferRoute() {
return this.sectionList.stream().anyMatch(Section::isTransferTrack);
}
/**
* 进路检查失败原因
*/

View File

@ -71,14 +71,14 @@ public class RouteOverlap extends MapNamedElement {
}
public synchronized void startSetting(LocalDateTime systemTime) {
this.lock = false;
this.setLock(false);
this.settingStartTime = systemTime;
this.requisition = false;
this.setting = true;
}
public void settingFinish() {
this.lock = true;
this.setLock(true);
this.setting = false;
this.settingStartTime = null;
this.requisition = false;
@ -113,7 +113,7 @@ public class RouteOverlap extends MapNamedElement {
}
}
this.forbidden = true;
this.lock = false;
this.setLock(false);
this.remainTime = 0;
this.releasing = false;
}
@ -249,4 +249,9 @@ public class RouteOverlap extends MapNamedElement {
}
return true;
}
public void setLock(boolean lock) {
this.signal.setOverlapLock(lock);
this.lock = lock;
}
}

View File

@ -434,7 +434,8 @@ public class Section extends MayOutOfOrderDevice {
public void axleCounterOccupy(boolean right) {
if (!this.isInvalid()) {
this.trainRight = right;
this.nctOccupied = true;
this.setNctOccupied(true);
// this.nctOccupied = true;
// if (!CollectionUtils.isEmpty(logicList)) {
// logicList.forEach(logic -> logic.axleCounterOccupy(right));
// }
@ -685,9 +686,17 @@ public class Section extends MayOutOfOrderDevice {
this.ctOccupied = true;
}
public void setNctOccupied(boolean nctOccupied) {
if (nctOccupied) {
this.invalid = false;
}
this.nctOccupied = nctOccupied;
}
public void nonCommunicateTrainOccupy(boolean right) {
this.trainRight = right;
this.nctOccupied = true;
this.setNctOccupied(true);
// this.nctOccupied = true;
this.ctOccupied = false;
}
@ -726,10 +735,9 @@ public class Section extends MayOutOfOrderDevice {
}
/**
* 判定为失效ARB暂时改为判定非通信车占用
* 判定为非通信车占用
*/
public void judgeAsInvalid() {
//暂时改为判定非通信车占用国赛用
public void judgeAsNctOccupied() {
if (!this.isAxleCounter()) {
return;
}
@ -758,37 +766,6 @@ public class Section extends MayOutOfOrderDevice {
logic.setNctOccupied(true);
}
}
// if (!this.isAxleCounter()) {
// throw new SimulationException(SimulationExceptionType.System_Fault);
// }
// this.setInvalid(true);
// this.setNctOccupied(false);
// if (this.isSwitchAxleCounterSection()) { // 道岔计轴区段
// List<Switch> relSwitchList = this.getRelSwitchList();
// for (Switch aSwitch : relSwitchList) {
// aSwitch.getA().setInvalid(true);
// aSwitch.getA().setNctOccupied(false);
// if (aSwitch.isNormalPosition()) {
// aSwitch.getB().setInvalid(true);
// aSwitch.getB().setNctOccupied(false);
// } else if (aSwitch.isReversePosition()) {
// aSwitch.getC().setInvalid(true);
// aSwitch.getC().setNctOccupied(false);
// } else {
// aSwitch.getB().setInvalid(true);
// aSwitch.getB().setNctOccupied(false);
// aSwitch.getC().setInvalid(true);
// aSwitch.getC().setNctOccupied(false);
// }
// }
// } else if (!CollectionUtils.isEmpty(this.logicList)) {
// for (Section logic : this.logicList) {
// logic.setInvalid(true);
// logic.setNctOccupied(false);
// }
// }
}
/**
@ -1033,6 +1010,40 @@ public class Section extends MayOutOfOrderDevice {
return false;
}
public void setInvalid(boolean invalid) {
if (invalid) {
this.setNctOccupied(false);
}
this.invalid = invalid;
}
public void judgeAsARB() {
if (!this.isAxleCounter()) {
return;
}
this.setInvalid(true);
if (this.isSwitchAxleCounterSection()) { // 道岔计轴区段
List<Switch> relSwitchList = this.getRelSwitchList();
for (Switch aSwitch : relSwitchList) {
aSwitch.getA().setInvalid(true);
if (aSwitch.isNormalPosition()) {
aSwitch.getB().setInvalid(true);
aSwitch.getC().setInvalid(false);
} else if (aSwitch.isReversePosition()) {
aSwitch.getC().setInvalid(true);
aSwitch.getB().setInvalid(false);
} else {
aSwitch.getB().setInvalid(true);
aSwitch.getC().setInvalid(true);
}
}
} else if (!CollectionUtils.isEmpty(this.logicList)) {
for (Section logic : this.logicList) {
logic.setInvalid(true);
}
}
}
public enum SectionRoadType {
/**
* 左行线
@ -1154,10 +1165,10 @@ public class Section extends MayOutOfOrderDevice {
flag = true;
VirtualRealitySectionAxleCounter.Fault.FAULT.apply(axleSection.getVirtualAxleCounter());
axleSection.setFault(this);
axleSection.setInvalid(true);
if (!CollectionUtils.isEmpty(axleSection.getLogicList())) {
axleSection.getLogicList().forEach(logic -> logic.setInvalid(true));
}
// axleSection.setInvalid(true);
// if (!CollectionUtils.isEmpty(axleSection.getLogicList())) {
// axleSection.getLogicList().forEach(logic -> logic.setInvalid(true));
// }
}
}
return flag;

View File

@ -220,6 +220,9 @@ public class Signal extends MayOutOfOrderDevice {
*/
private boolean approachLock;
/** 延续保护锁闭 */
private boolean overlapLock;
@Override
public void reset() {
super.reset();
@ -239,6 +242,7 @@ public class Signal extends MayOutOfOrderDevice {
this.noStatus = false;
this.init = false;
this.approachLock = false;
this.overlapLock = false;
}
@Override

View File

@ -167,7 +167,7 @@ public class Switch extends MayOutOfOrderDevice {
* 是否道岔区段被占用
*/
public boolean isSectionOccupied() {
return this.a.isOccupied();
return this.a.isOccupied() && !this.a.isInvalid();
}
/**

View File

@ -5,6 +5,7 @@ import club.joylink.rtss.simulation.cbtc.data.map.Stand;
import club.joylink.rtss.simulation.cbtc.data.map.Station;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.time.LocalTime;
import java.util.ArrayList;
@ -63,6 +64,14 @@ public class TripPlan {
/** 是否发车 */
private boolean departure;
/** 失效(抽线) */
@Setter
private boolean invalid;
/** 加线 */
@Setter
private boolean add;
/**
* 获取正线车站运行计划起始时间
* @return

View File

@ -69,6 +69,9 @@ public class SignalStatus extends DeviceStatus {
@JsonSerialize(using = Boolean2NumSerializer.class)
private boolean approachLock;
@JsonSerialize(using = Boolean2NumSerializer.class)
private boolean overlapLock;
/**故障*/
private String fault;
@ -85,6 +88,7 @@ public class SignalStatus extends DeviceStatus {
this.remainTime = signal.getDelayTime();
this.noStatus = signal.isNoStatus();
this.approachLock = signal.isApproachLock();
this.overlapLock = signal.isOverlapLock();
this.fault = Objects.nonNull(signal.getFault())?((Signal.SignalFault)signal.getFault()).name():null;
}
@ -153,6 +157,11 @@ public class SignalStatus extends DeviceStatus {
status.setApproachLock(approachLock);
change = true;
}
if (!Objects.equals(this.overlapLock, signal.isOverlapLock())) {
this.overlapLock = signal.isOverlapLock();
status.setOverlapLock(this.overlapLock);
change = true;
}
MayOutOfOrderDevice.DeviceFault fault = signal.getFault();
if (!Objects.equals(this.fault, Objects.nonNull(fault) ? ((Signal.SignalFault) fault).name():null)) {
if(Objects.isNull(fault)){
@ -179,6 +188,8 @@ public class SignalStatus extends DeviceStatus {
statusVO.setReblockade(this.reblockade);
statusVO.setLockedRouteCode(lockedRouteCode);
statusVO.setNoStatus(noStatus);
statusVO.setApproachLock(approachLock);
statusVO.setOverlapLock(overlapLock);
statusVO.setFault(fault);
return statusVO;
}

View File

@ -10,12 +10,12 @@ import lombok.Getter;
@Getter
public class TrainStopMessage {
private String groupNumber;
private VirtualRealityTrain train;
private Section section;
public TrainStopMessage(VirtualRealityTrain train) {
this.groupNumber = train.getGroupNumber();
this.train = train;
this.section = train.getHeadPosition().getSection();
}

View File

@ -60,6 +60,9 @@ public class SignalStatusVO extends DeviceStatusVO{
@JsonSerialize(using = Boolean2NumSerializer.class)
private Boolean approachLock;
@JsonSerialize(using = Boolean2NumSerializer.class)
private Boolean overlapLock;
/** 信号机故障 */
@JsonInclude(JsonInclude.Include.ALWAYS)
private String fault;

View File

@ -712,14 +712,20 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
// this.setSignalEB(false);
this.setAtoOn(false);
this.setDriveMode(DriveMode.RM);
this.positioned = false; //定位丢失
this.lossPosition();
// this.positioned = false; //定位丢失
this.setCbtcMaMiss(); //通信断开
this.lastTwoPassedResponders.clear();
// this.lastTwoPassedResponders.clear();
// if (RunLevel.CBTC.equals(this.runLevel)) {
// this.setCbtcMaMiss();
// }
}
public void lossPosition() {
this.positioned = false;
this.lastTwoPassedResponders.clear();
}
public void useCMMode() {
if (!this.isAtpOn()) {
throw new SimulationException(SimulationExceptionType.Invalid_Operation, String.format("列车[%s]未打开ATP", this.getCode()));
@ -1125,13 +1131,19 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
* 通信异常
*/
COMMUNICATION_ABNORMAL {
@Override
public void fix(MapElement device) {
VirtualRealityTrain train = (VirtualRealityTrain) device;
train.setFault(null);
train.getLastTwoPassedResponders().clear();
}
// @Override
// public boolean apply(MapElement device) {
// VirtualRealityTrain train = (VirtualRealityTrain) device;
// if (Objects.equals(this, train.getFault())) {
// return false;
// }
// train.setFault(this);
// train.lossPosition();
// return true;
// }
},
/** 驾驶异常 */
DRIVE_FAULT {
@Override
public boolean apply(MapElement device) {

View File

@ -0,0 +1,19 @@
package club.joylink.rtss.simulation.cbtc.event;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.vo.client.runplan.RunPlanTripVO;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
public class SimulationTripPlanChangeEvent extends AbstractSimulationEvent{
List<RunPlanTripVO> changeTrips;
public SimulationTripPlanChangeEvent(Object source, Simulation simulation, List<RunPlanTripVO> changeTrips) {
super(source, simulation);
this.changeTrips = changeTrips;
}
}

View File

@ -87,6 +87,7 @@ public class ATPLogicLoop {
} else { //列车有定位
if (train.isCBTC() && train.isCbtcMaMiss()) { //CBTC列车的移动授权丢失
train.setRunLevel(RunLevel.IL);
train.lossPosition();
atpService.triggerSignalEB(train);
train.setMa(null);
} else if (!train.isCbtcMaMiss() && defaultRunLevel.equals(RunLevel.CBTC)) {

View File

@ -65,6 +65,8 @@ public enum WebSocketMessageType {
Simulation_Reset,
/** 仿真-仿真运行计划重新加载消息 */
Simulation_Run_Plan_Reload,
/** 车次计划变化消息 */
Simulation_Trip_Plan_Change,
/** 仿真-仿真场景重新加载 */
Simulation_Scenes_Reload,
/** 仿真-仿真成员改变消息 */

View File

@ -14,6 +14,8 @@ import club.joylink.rtss.vo.client.SocketMessageVO;
import club.joylink.rtss.vo.client.WebSocketMessageType;
import club.joylink.rtss.vo.client.passenger.PassengerFlowMessage2TD;
import club.joylink.rtss.vo.client.psl.PslStatus;
import club.joylink.rtss.vo.client.runplan.RunPlanEChartsDataVO;
import club.joylink.rtss.vo.client.runplan.RunPlanTripVO;
import club.joylink.rtss.vo.client.script.ScriptActionVO;
import club.joylink.rtss.vo.client.simulationv1.SimulationMemberMessageVO;
import club.joylink.rtss.vo.client.simulationv1.SimulationUserMessageVO;
@ -89,6 +91,7 @@ public class SocketMessageFactory {
case Simulation_Control_Pause:
case Simulation_Permission_Over:
case Simulation_Run_Plan_Reload:
case Simulation_Trip_Plan_Change:
case Simulation_Scenes_Reload:
case Simulation_Quest_Finish:
case Simulation_PlayBack_Finish:
@ -366,4 +369,12 @@ public class SocketMessageFactory {
public static SocketMessageVO<String> buildOrderPaySuccessMessage(String orderCode) {
return build(WebSocketMessageType.Order_Pay_Result, null, orderCode);
}
/**
* 车次计划变化
*/
public static SocketMessageVO<RunPlanEChartsDataVO> buildTripPlanChangeMessage(String simulationId, List<RunPlanTripVO> changeTrips) {
RunPlanEChartsDataVO eChartsDataVO = new RunPlanEChartsDataVO(changeTrips);
return build(WebSocketMessageType.Simulation_Trip_Plan_Change, simulationId, eChartsDataVO);
}
}

View File

@ -103,6 +103,12 @@ public class RunPlanEChartsDataVO {
List<StationTime> stationTimeList;
Boolean add;
Boolean firstInvalid;
Boolean invalid;
TripNumberData(RunPlanTripVO runPlanTripVO) {
this.startSectionCode = runPlanTripVO.getStartSectionCode();
this.startSecondTime = runPlanTripVO.getStartTime().toSecondOfDay();
@ -117,6 +123,9 @@ public class RunPlanEChartsDataVO {
this.outbound = runPlanTripVO.getIsOutbound();
this.backup = runPlanTripVO.getIsBackUp();
this.stationTimeList = new ArrayList<>();
this.add = runPlanTripVO.isAdd() ? true : null;
this.firstInvalid = runPlanTripVO.isFirstInvalid() ? true : null;
this.invalid = runPlanTripVO.isInvalid() ? true : null;
}
}

View File

@ -106,6 +106,12 @@ public class RunPlanTripVO {
@JsonProperty(value = "n")
private Boolean right;
private boolean add;
private boolean firstInvalid;
private boolean invalid;
public RunPlanTripVO(RunPlanImport runPlanImport) {
this.serviceNumber = runPlanImport.getServiceNumber();
this.tripNumber = runPlanImport.getTripNumber();

View File

@ -3,6 +3,7 @@ package club.joylink.rtss.vo.client.runplan;
import club.joylink.rtss.entity.RunPlanDaily;
import club.joylink.rtss.entity.RunPlanDraft;
import club.joylink.rtss.entity.RunPlanTemplate;
import club.joylink.rtss.simulation.cbtc.data.plan.TripPlan;
import club.joylink.rtss.util.JsonUtils;
import club.joylink.rtss.vo.client.validGroup.RunPlanCreateCheck;
import club.joylink.rtss.vo.client.validGroup.RunPlanNameCheck;
@ -20,10 +21,9 @@ import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;
@Getter
@Setter
@ -213,28 +213,30 @@ public class RunPlanVO {
return vo;
}
// public void setStationDiagramList(List<RunPlanStationTimeVO> stationDiagramList) {
// stationDiagramList.sort(Comparator.comparing(RunPlanStationTimeVO::getArriveTime));
// this.stationDiagramList = stationDiagramList;
// if(!CollectionUtils.isEmpty(stationDiagramList)) {
// Set<String> serverNoList = new HashSet<>();
// Set<String> trainNoList = new HashSet<>();
// Map<String, Set<String>> serverNoTrainNoRelMap = new HashMap<>();
// Map<String, List<RunPlanStationTimeVO>> serverStationMap = new HashMap<>();
// Map<String, List<RunPlanStationTimeVO>> trainStationMap = new HashMap<>();
// stationDiagramList.forEach(diagram -> {
// serverNoList.add(diagram.getServiceNumber());
// trainNoList.add(diagram.getTripNumber());
// Set<String> trainNoSet = serverNoTrainNoRelMap.computeIfAbsent(diagram.getServiceNumber(), k -> new HashSet<>());
// trainNoSet.add(diagram.getTripNumber());
// List<RunPlanStationTimeVO> tsList = trainStationMap.computeIfAbsent(diagram.getTripNumber(), k -> new ArrayList<>());
// tsList.add(diagram);
// List<RunPlanStationTimeVO> ssList = serverStationMap.computeIfAbsent(diagram.getServiceNumber(), k -> new ArrayList<>());
// ssList.add(diagram);
// });
// this.serverNoList = serverNoList;
// this.trainNoList = trainNoList;
// this.serverStationMap = serverStationMap;
// }
// }
public List<RunPlanTripVO> invalidTripPlan(List<TripPlan> removeList) {
TripPlan first = removeList.get(0);
String serviceNumber = first.getServiceNumber();
LocalTime startTime = first.getStartTime();
return this.tripList.stream()
.filter(plan -> {
if (!plan.getServiceNumber().equals(serviceNumber))
return false;
if (plan.getStartTime().isBefore(startTime))
return false;
if (plan.isInvalid() && !plan.isFirstInvalid())
return false;
return true;
})
.peek(plan -> {
if (!plan.getStartTime().isBefore(startTime)) {
if (plan.isFirstInvalid())
plan.setFirstInvalid(false);
plan.setInvalid(true);
if (plan.getTripNumber().equals(first.getTripNumber())) {
plan.setFirstInvalid(true);
}
}
})
.collect(Collectors.toList());
}
}

View File

@ -23,4 +23,8 @@ public class RunPlanRoutingQueryVO extends PageQueryVO {
* 终到站台区段code
*/
private String endSectionCode;
/**
* 目的地码
*/
private String destinationCode;
}

View File

@ -196,6 +196,9 @@ public class RealLineConfigVO {
/** 设置头码车时检查方向 */
private boolean checkDirectionWhenSetHead;
/** 转换轨进路只能通过故障解锁来取消 */
private boolean transferRouteCanOnlyFaultUnlock;
public static RealLineConfigVO parseJsonStr(String configData) {
if (StringUtils.hasText(configData)) {
return JsonUtils.read(configData, RealLineConfigVO.class);