Merge remote-tracking branch 'origin/test' into dev

This commit is contained in:
joylink_zhangsai 2021-06-07 08:50:41 +08:00
commit f25f8f5972
48 changed files with 1207 additions and 280 deletions

View File

@ -60,6 +60,7 @@ public class WebConfig implements WebMvcConfigurer {
whiteList.add("/api/cgy/**");
//项目域名查询
whiteList.add("/api/projectServer/project/{project}");
whiteList.add("/test/simulation/**");
registry.addInterceptor(authenticateInterceptor).excludePathPatterns(whiteList);
}

View File

@ -1,6 +1,7 @@
package club.joylink.rtss.controller.draft;
import club.joylink.rtss.services.draftData.DraftMapSignalApproachSectionService;
import club.joylink.rtss.services.draftData.SignalApproachSectionGenerator;
import club.joylink.rtss.vo.client.PageVO;
import club.joylink.rtss.vo.client.map.newmap.MapSASQueryVO;
import club.joylink.rtss.vo.client.map.newmap.MapSignalApproachSectionVO;
@ -18,6 +19,11 @@ public class DraftMapSignalApproachSectionController {
@Autowired
private DraftMapSignalApproachSectionService draftMapSignalApproachSectionService;
@PostMapping("/generate")
public List<MapSignalApproachSectionVO> generate(@PathVariable Long id, @RequestBody SignalApproachSectionGenerator.Config config) {
return this.draftMapSignalApproachSectionService.generate(id, config);
}
@GetMapping("/paging")
public PageVO<MapSignalApproachSectionVO> pagingQuery(@PathVariable Long id, MapSASQueryVO queryVO) {
return this.draftMapSignalApproachSectionService.pagingQuery(id, queryVO);

View File

@ -42,4 +42,6 @@ public interface DraftMapService {
void cleanAndSaveParkTime(Long mapId, List<MapStationParkingTimeVO> parkTimeList);
List<MapStationParkingTimeVO> queryParkTimes(Long mapId);
void cleanAndSaveSignalApproachSection(Long mapId, List<MapSignalApproachSectionVO> approachVOList);
}

View File

@ -120,6 +120,12 @@ public class DraftMapServiceImpl implements DraftMapService {
.collect(Collectors.toList());
}
@Override
public void cleanAndSaveSignalApproachSection(Long mapId, List<MapSignalApproachSectionVO> approachVOList) {
this.cleanMapApproachSection(mapId);
this.saveMapApproachSection(mapId, approachVOList);
}
private void saveMapCycle(Long mapId, List<MapAutoReentryVO> autoReentryVOList) {
if (!CollectionUtils.isEmpty(autoReentryVOList)) {
for (MapAutoReentryVO autoReentryVO : autoReentryVOList) {

View File

@ -7,10 +7,11 @@ import club.joylink.rtss.vo.client.map.newmap.MapSignalApproachSectionVO;
import java.util.List;
public interface DraftMapSignalApproachSectionService {
List<MapSignalApproachSectionVO> generate(Long id, SignalApproachSectionGenerator.Config config);
PageVO<MapSignalApproachSectionVO> pagingQuery(Long id, MapSASQueryVO queryVO);
List<MapSignalApproachSectionVO> queryAll(Long id);
void update(Long id, String signalCode, MapSignalApproachSectionVO vo);
}

View File

@ -4,7 +4,10 @@ import club.joylink.rtss.dao.DraftMapSignalApproachSectionDAO;
import club.joylink.rtss.entity.DraftMapSignalApproachSection;
import club.joylink.rtss.entity.DraftMapSignalApproachSectionExample;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.rt.repo.CommonRepository;
import club.joylink.rtss.simulation.rt.repo.CommonRepositoryBuilder;
import club.joylink.rtss.vo.client.PageVO;
import club.joylink.rtss.vo.client.map.MapVO;
import club.joylink.rtss.vo.client.map.newmap.MapSASQueryVO;
import club.joylink.rtss.vo.client.map.newmap.MapSignalApproachSectionVO;
import com.github.pagehelper.Page;
@ -20,6 +23,19 @@ import java.util.stream.Collectors;
public class DraftMapSignalApproachSectionServiceImpl implements DraftMapSignalApproachSectionService {
@Autowired
private DraftMapSignalApproachSectionDAO draftMapSignalApproachSectionDAO;
@Autowired
private DraftMapService draftMapService;
@Autowired
private SignalApproachSectionGenerator signalApproachSectionGenerator;
@Override
public List<MapSignalApproachSectionVO> generate(Long id, SignalApproachSectionGenerator.Config config) {
MapVO mapVO = draftMapService.getDraftMapData(id);
CommonRepository commonRepository = CommonRepositoryBuilder.buildFrom(mapVO.getGraphDataNew());
List<MapSignalApproachSectionVO> voList = this.signalApproachSectionGenerator.generateAll(commonRepository, config);
this.draftMapService.cleanAndSaveSignalApproachSection(id, voList);
return voList;
}
@Override
public PageVO<MapSignalApproachSectionVO> pagingQuery(Long id, MapSASQueryVO queryVO) {

View File

@ -0,0 +1,105 @@
package club.joylink.rtss.services.draftData;
import club.joylink.rtss.simulation.rt.repo.*;
import club.joylink.rtss.vo.client.map.newmap.MapSectionPathVO;
import club.joylink.rtss.vo.client.map.newmap.MapSignalApproachSectionVO;
import lombok.Getter;
import lombok.Setter;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Component
public class SignalApproachSectionGenerator {
public List<MapSignalApproachSectionVO> generateAll(CommonRepository commonRepository, Config config) {
List<MapSignalApproachSectionVO> voList = new ArrayList<>();
for (CommonSignal signal : commonRepository.getSignalMap().values()) {
MapSignalApproachSectionVO vo = this.generate(signal, config);
voList.add(vo);
}
return voList;
}
public MapSignalApproachSectionVO generate(CommonSignal signal, Config config) {
CommonSection section = signal.getSection();
boolean right = signal.isRight();
int offset = signal.getOffset();
CommonSection startSection = section;
if (right) {
if (offset < (section.getLen() - offset)) {
startSection = section.getLeftSection();
}
} else {
if ((section.getLen() - offset) < offset) {
startSection = section.getRightSection();
}
}
List<TrackPath> list = new ArrayList<>();
this.queryPath(startSection, new TrackPath(!right), list, config);
MapSignalApproachSectionVO vo = this.buildVO(signal, list);
return vo;
}
private MapSignalApproachSectionVO buildVO(CommonSignal signal, List<TrackPath> list) {
MapSignalApproachSectionVO vo = new MapSignalApproachSectionVO();
vo.setSignalCode(signal.getId());
vo.setReleaseTime(180);
vo.setSectionPathList(MapSectionPathVO.convertTrackPath2VOList(list));
return vo;
}
private void queryPath(CommonSection section, TrackPath trackPath, List<TrackPath> list, Config config) {
if (section == null) {
list.add(trackPath);
return;
}
if ((trackPath.calTotalLen()/1000) >= config.len) {
list.add(trackPath);
return;
}
boolean right = trackPath.isRight();
List<CommonSignal> signals = section.getSignalOf(!right);
if (!signals.isEmpty()) {
trackPath.addSection(section);
list.add(trackPath);
return;
}
trackPath.addSection(section);
if (section.isSwitchSection()) {
CommonSwitch belongSwitch = section.getBelongSwitch();
if (belongSwitch.isA(section)) {
TrackPath clone = trackPath.clone();
clone.addSection(belongSwitch.getB());
clone.addSwitchPosition(belongSwitch, true);
CommonSection bNext = belongSwitch.getB().queryNextBy(right);
this.queryPath(bNext, clone, list, config);
trackPath.addSection(belongSwitch.getC());
trackPath.addSwitchPosition(belongSwitch, false);
CommonSection cNext = belongSwitch.getC().queryNextBy(right);
this.queryPath(cNext, trackPath, list, config);
} else if (belongSwitch.isB(section)) {
trackPath.addSection(belongSwitch.getA());
CommonSection next = belongSwitch.getA().queryNextBy(right);
trackPath.addSwitchPosition(belongSwitch, true);
this.queryPath(next, trackPath, list, config);
} else {
trackPath.addSection(belongSwitch.getA());
trackPath.addSwitchPosition(belongSwitch, false);
CommonSection next = belongSwitch.getA().queryNextBy(right);
this.queryPath(next, trackPath, list, config);
}
} else {
CommonSection next = section.queryNextBy(right);
this.queryPath(next, trackPath, list, config);
}
}
@Getter
@Setter
public static class Config {
float len;
boolean beyondAheadSignal;
}
}

View File

@ -453,17 +453,17 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
this.checkPublisherExist();
BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.assertNotTrue(this.messagePublisherMap.containsKey(messagePublisher.name));
this.messagePublisherMap.put(messagePublisher.name, messagePublisher);
if (!messagePublisher.isScheduled()) {
return;
}
if (messagePublisher.isFixed()) {
this.addFixedRateJob(messagePublisher.name, () -> {
messagePublisher.buildAndPublish(this.messageSender);
}, messagePublisher.rate);
} else {
this.addJob(messagePublisher.getName(), () -> {
messagePublisher.buildAndPublish(this.messageSender);
}, messagePublisher.rate);
if ((messagePublisher instanceof SimulationScheduleMessagePublisher)) {
SimulationScheduleMessagePublisher publisher = (SimulationScheduleMessagePublisher) messagePublisher;
if (publisher.isFixed()) {
this.addFixedRateJob(publisher.name, () -> {
publisher.buildAndPublish(this.messageSender);
}, publisher.rate);
} else {
this.addJob(publisher.getName(), () -> {
publisher.buildAndPublish(this.messageSender);
}, publisher.rate);
}
}
}

View File

@ -6,6 +6,7 @@ import club.joylink.rtss.simulation.vo.SimulationInfoVO;
import club.joylink.rtss.simulation.vo.SimulationMemberVO;
import club.joylink.rtss.simulation.vo.SimulationUserVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@ -64,9 +65,10 @@ public class SimulationCommonController {
}
@GetMapping("/{id}/members")
public List<SimulationMemberVO> getSimulationMembers(@PathVariable String id) {
public List<SimulationMemberVO> getSimulationMembers(@PathVariable String id, @RequestParam(required = false) String role) {
return this.simulationManager.getSimulationMembers(id).stream()
.map(SimulationMember::convertToVO)
.filter(member -> StringUtils.hasText(role) ? member.getRole().toString().equals(role) : true)
.collect(Collectors.toList());
}

View File

@ -1,85 +1,82 @@
package club.joylink.rtss.simulation;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import lombok.Getter;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Getter
public abstract class SimulationMessagePublisher {
String name;
boolean scheduled; // 是否定时推送
int rate; // 消息发送频率单位ms
boolean fixed; // 是否固定频率
String destinationPatten; // 订阅路径patten
Set<String> subscribeDestinationList = new ConcurrentSkipListSet<>();
List<String> destinationPattenList; // 订阅路径patten
Map<String, List<String>> destinationParamsMap = new ConcurrentHashMap<>();
/**
* 消息推送线程池
*/
private static final ExecutorService Message_Executor = Executors.newSingleThreadExecutor();
private static ExecutorService Message_Executor = Executors.newSingleThreadExecutor();
public SimulationMessagePublisher(String name, String destinationPatten) {
this(name, false, 0, false, destinationPatten);
}
public SimulationMessagePublisher(String name, int rate, String destinationPatten) {
this(name, true, rate, true, destinationPatten);
}
public SimulationMessagePublisher(String name, int rate, boolean fixed, String destinationPatten) {
this(name, true, rate, fixed, destinationPatten);
}
public SimulationMessagePublisher(String name, boolean scheduled, int rate, boolean fixed, String destinationPatten) {
public SimulationMessagePublisher(String name, List<String> destinationPattenList) {
this.name = name;
this.scheduled = scheduled;
this.rate = rate;
this.fixed = fixed;
this.destinationPatten = destinationPatten;
this.destinationPattenList = destinationPattenList;
}
/**
* 接收并处理订阅路径,如果匹配上返回true否则返回false
* @param destination
* @return
*/
public boolean acceptedSubscribePath(String destination) {
if (this.isMatch(destination)) {
this.subscribeDestinationList.add(destination);
List<String> params = this.match(destination);
if (!params.isEmpty()) {
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertTrue(this.isValidParams(params));
this.destinationParamsMap.putIfAbsent(destination, params);
return true;
}
return false;
}
public static ExecutorService getMessage_Executor() {
return Message_Executor;
}
public boolean isValidParams(List<String> params) {
return true;
}
public void unsubscribe(String destination) {
this.subscribeDestinationList.remove(destination);
this.destinationParamsMap.remove(destination);
}
public boolean isMatch(String destination) {
String destPattern = this.destinationPatten;
String[] patterns = StringUtils.tokenizeToStringArray(destPattern, "/");
String[] dests = StringUtils.tokenizeToStringArray(destination, "/");
if (patterns.length == dests.length) {
for (int i = 0; i < patterns.length; i++) {
String p = patterns[i];
if (p.startsWith("{")) {
continue;
}
if (!Objects.equals(p, dests[i])) {
return false;
public List<String> match(String destination) {
List<String> params = new ArrayList<>();
for (String destPattern : this.destinationPattenList) {
String[] patterns = StringUtils.tokenizeToStringArray(destPattern, "/");
String[] dests = StringUtils.tokenizeToStringArray(destination, "/");
if (patterns.length == dests.length) {
for (int i = 0; i < patterns.length; i++) {
String p = patterns[i];
if (p.startsWith("{")) {
params.add(dests[i]);
continue;
}
if (!Objects.equals(p, dests[i])) {
params.clear();
break;
}
}
}
return true;
}
return false;
}
public void buildAndPublish(SimulationMessageSender sender) {
for (String destination : this.subscribeDestinationList) {
Object message = this.getNextSendMessage(destination);
if (message != null) {
Message_Executor.execute(() -> sender.publishMessage(destination, message));
if (!params.isEmpty()) {
break;
}
}
return params;
}
public void buildAndPublishMessageOfSubscribe(SimulationMessageSender sender, String destination) {
@ -89,7 +86,5 @@ public abstract class SimulationMessagePublisher {
}
}
public abstract Object getNextSendMessage(String destination);
public abstract Object buildMessageOfSubscribe(String destination);
}

View File

@ -0,0 +1,29 @@
package club.joylink.rtss.simulation;
import lombok.Getter;
import java.util.List;
@Getter
public abstract class SimulationScheduleMessagePublisher extends SimulationMessagePublisher {
int rate; // 消息发送频率单位ms
boolean fixed; // 是否固定频率
public SimulationScheduleMessagePublisher(String name, int rate, boolean fixed, List<String> destinationPattenList) {
super(name, destinationPattenList);
this.rate = rate;
this.fixed = fixed;
}
public void buildAndPublish(SimulationMessageSender sender) {
for (String destination : this.destinationParamsMap.keySet()) {
Object message = this.buildNextSendMessage(destination);
if (message != null) {
getMessage_Executor().execute(() -> sender.publishMessage(destination, message));
}
}
}
public abstract Object buildNextSendMessage(String destination);
}

View File

@ -0,0 +1,37 @@
package club.joylink.rtss.simulation;
import java.util.List;
public abstract class SimulationTriggerMessagePublisher extends SimulationMessagePublisher implements Watcher {
public SimulationTriggerMessagePublisher(String name, List<String> destinationPattenList) {
super(name, destinationPattenList);
}
/**
* 获取需要此监控对象消息的订阅路径
* @param watchable
* @return
*/
public abstract List<String> getNeedBuildDestination(Watchable watchable);
/**
* 构建监控对象消息
* @param watchable
* @return
*/
public abstract Object buildMessage(Watchable watchable);
@Override
public void handleStateChange(Simulation simulation, Watchable watchable) {
List<String> destinationList = this.getNeedBuildDestination(watchable);
if (!destinationList.isEmpty()) {
Object message = this.buildMessage(watchable);
if (message != null) {
for (String destination : destinationList) {
getMessage_Executor().execute(() -> simulation.getMessageSender().publishMessage(destination, message));
}
}
}
}
}

View File

@ -1,25 +1,30 @@
package club.joylink.rtss.simulation;
public class StateMessagePublisher extends SimulationMessagePublisher implements Watcher<Simulation> {
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class StateMessagePublisher extends SimulationTriggerMessagePublisher {
public static final String Name = "state-sync";
public static final String Destination = String.format("%s/%s", Simulation.MESSAGE_SUB_PREFIX, "state");
Simulation simulation;
public StateMessagePublisher(Simulation simulation) {
super(Name, String.format("%s/%s", Simulation.MESSAGE_SUB_PREFIX, "state"));
super(Name, Arrays.asList(Destination));
this.simulation = simulation;
}
@Override
public Object getNextSendMessage(String destination) {
public List<String> getNeedBuildDestination(Watchable watchable) {
return new ArrayList<>(this.destinationParamsMap.keySet());
}
@Override
public Object buildMessage(Watchable watchable) {
return this.simulation.getState();
}
@Override
public Object buildMessageOfSubscribe(String destination) {
return this.getNextSendMessage(destination);
}
@Override
public void handleStateChange(Simulation simulation, Simulation watchable) {
this.buildAndPublish(watchable.getMessageSender());
return this.buildMessage(this.simulation);
}
}

View File

@ -1,19 +1,22 @@
package club.joylink.rtss.simulation;
public class SysTimeMessagePublisher extends SimulationMessagePublisher {
import java.util.Arrays;
public class SysTimeMessagePublisher extends SimulationScheduleMessagePublisher {
Simulation simulation;
public static final String Destination = String.format("%s/%s", Simulation.MESSAGE_SUB_PREFIX, "sysTime");
public SysTimeMessagePublisher(Simulation simulation) {
super("sys-time-sync", 1000, String.format("%s/%s", Simulation.MESSAGE_SUB_PREFIX, "sysTime"));
super("sys-time-sync", 1000, false, Arrays.asList(Destination));
this.simulation = simulation;
}
@Override
public Object getNextSendMessage(String destination) {
public Object buildNextSendMessage(String destination) {
return this.simulation.getSystemTime().toLocalTime().toSecondOfDay();
}
@Override
public Object buildMessageOfSubscribe(String destination) {
return this.getNextSendMessage(destination);
return this.buildNextSendMessage(destination);
}
}

View File

@ -493,6 +493,14 @@ public class Signal extends MayOutOfOrderDevice {
* 调车信号机
*/
SHUNTING,
/**
* 进站信号机
*/
ARRIVAL,
/**
* 出站信号机
*/
EXIT,
}
public enum SignalFault implements DeviceFault {

View File

@ -1,17 +1,14 @@
package club.joylink.rtss.simulation.rt.ATS;
import club.joylink.rtss.simulation.Simulation;
import club.joylink.rtss.simulation.SimulationMessagePublisher;
import club.joylink.rtss.simulation.SimulationScheduleMessagePublisher;
import club.joylink.rtss.simulation.rt.ATS.bo.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
public class AtsMessagePublisher extends SimulationMessagePublisher {
public class AtsMessagePublisher extends SimulationScheduleMessagePublisher {
public static final String NAME = "AtsMP";
public static final int RATE = 1000;
public static final String DESTINATION = String.format("%s%s", Simulation.MESSAGE_SUB_PREFIX, "/ats");
@ -23,7 +20,7 @@ public class AtsMessagePublisher extends SimulationMessagePublisher {
Map<String, List<Object>> routeMap = new ConcurrentHashMap<>();
public AtsMessagePublisher(AtsRepository atsRepository) {
super(NAME, RATE, DESTINATION);
super(NAME, RATE, true, Arrays.asList(DESTINATION));
this.atsRepository = atsRepository;
this.buildMessage(atsRepository);
}
@ -67,7 +64,7 @@ public class AtsMessagePublisher extends SimulationMessagePublisher {
}
@Override
public Object getNextSendMessage(String destination) {
public Object buildNextSendMessage(String destination) {
HashMap<Object, Object> message = new HashMap<>();
if (!this.switchMap.isEmpty()) {
message.put("switch", new ArrayList<>(this.switchMap.values()));

View File

@ -125,6 +125,7 @@ public class CilLogicService {
}
private void mainLogic(RtSimulation rtSimulation, CilRepository cilRepository) {
this.cilRouteLogicService.ciTriggerRoute(rtSimulation, cilRepository);
this.cilRouteLogicService.routeLogic(rtSimulation, cilRepository);
this.cilSectionLogicService.mainLogic(rtSimulation, cilRepository);
}

View File

@ -3,12 +3,16 @@ package club.joylink.rtss.simulation.rt.CIL;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.rt.CIL.bo.*;
import club.joylink.rtss.simulation.rt.RtSimulation;
import club.joylink.rtss.simulation.rt.SRD.bo.SrTrain;
import club.joylink.rtss.simulation.rt.SRD.bo.SrdRepository;
import club.joylink.rtss.simulation.rt.SRD.bo.TrackPosition;
import club.joylink.rtss.simulation.rt.repo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@ -22,6 +26,32 @@ public class CilRouteLogicService {
@Autowired
private CilSignalLogicService cilSignalLogicService;
public void ciTriggerRoute(RtSimulation rtSimulation, CilRepository cilRepository) {
SrdRepository srdRepository = SrdRepository.getInstanceFrom(rtSimulation);
for (SrTrain srTrain : srdRepository.getTrainList()) {
TrackPosition position = srTrain.getHeadPosition();
if (position == null) {
continue;
}
boolean right = srTrain.isRight();
// 获取区段接近信号机列表
List<CommonSignal> approachSignalList = cilRepository.getApproachSignalOf(position.getTrack().getId());
for (CommonSignal commonSignal : approachSignalList) {
if (!Objects.equals(commonSignal.isRight(), right) || commonSignal.isShunting()) {
continue;
} else {
CommonRoute route = commonSignal.getRouteList().stream()
.sorted(Comparator.comparing(commonRoute -> commonRoute.getPathElement().getReverseSwitchCount()))
.findFirst().get();
if (!cilRepository.isSupervised(route.getId())) {
this.setRoute(rtSimulation, route.getId());
}
break;
}
}
}
}
public void routeLogic(RtSimulation rtSimulation, CilRepository cilRepository) {
List<CilRoute> supervisedRouteList = cilRepository.getSupervisedRouteList();
for (CilRoute cilRoute : supervisedRouteList) {

View File

@ -51,10 +51,10 @@ public class CilSignalLogicService {
CommonRepository commonRepository = simulation.getRepository(CommonRepository.NAME, CommonRepository.class);
CilRepository cilRepository = simulation.getRepository(CilRepository.NAME, CilRepository.class);
CommonSignal commonSignal = commonRepository.getSignalById(signalId);
List<TrackWay> approachList = commonSignal.getApproachList();
List<TrackPath> approachList = commonSignal.getApproachList();
if (!CollectionUtils.isEmpty(approachList)) {
for (TrackWay trackWay : approachList) {
List<CommonSection> sectionList = trackWay.getAllSectionList();
for (TrackPath trackPath : approachList) {
List<CommonSection> sectionList = trackPath.getSectionList();
if (!CollectionUtils.isEmpty(sectionList)) {
for (CommonSection commonSection : sectionList) {
if (cilRepository.getSectionById(commonSection.getId()).isAxcOccupy()) {

View File

@ -2,8 +2,10 @@ package club.joylink.rtss.simulation.rt.CIL.bo;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.SimulationRepository;
import club.joylink.rtss.simulation.rt.RtSimulation;
import club.joylink.rtss.simulation.rt.repo.CommonRepository;
import club.joylink.rtss.simulation.rt.repo.CommonSection;
import club.joylink.rtss.simulation.rt.repo.CommonSignal;
import club.joylink.rtss.simulation.rt.repo.CommonSwitch;
import java.util.ArrayList;
@ -190,4 +192,12 @@ public class CilRepository extends SimulationRepository {
}
public List<CommonSignal> getApproachSignalOf(String sectionId) {
CommonRepository commonRepository = CommonRepository.getInstanceFrom((RtSimulation) this.getSimulation());
List<CommonSignal> signals = commonRepository.getApproachSignalMap().get(sectionId);
if (signals != null) {
return signals;
}
return new ArrayList<>();
}
}

View File

@ -1,6 +1,7 @@
package club.joylink.rtss.simulation.rt;
import club.joylink.rtss.constants.MapPrdTypeEnum;
import club.joylink.rtss.constants.Project;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.services.MapService;
import club.joylink.rtss.simulation.SimulationManager;
@ -10,6 +11,7 @@ import club.joylink.rtss.simulation.rt.SRD.SrdLogicService;
import club.joylink.rtss.simulation.rt.SRD.bo.SrTrain;
import club.joylink.rtss.simulation.rt.SRD.bo.SrdRepository;
import club.joylink.rtss.simulation.rt.TL.TlLogicService;
import club.joylink.rtss.simulation.rt.operation.SrTrainOperationHandler;
import club.joylink.rtss.simulation.rt.repo.CommonRepoService;
import club.joylink.rtss.simulation.rt.repo.CommonRepository;
import club.joylink.rtss.simulation.rt.repo.CommonStation;
@ -38,6 +40,9 @@ public class RtSimulationService {
@Autowired
private TlLogicService tlLogicService;
@Autowired
private SrTrainOperationHandler srTrainOperationHandler;
public RtSimulation create(UserVO userVO, Long mapId, MapPrdTypeEnum prdTypeEnum) {
Objects.requireNonNull(mapId);
MapVO mapVO = this.mapService.getMapDetail(mapId);
@ -48,21 +53,37 @@ public class RtSimulationService {
rtSimulation.mapVO = mapVO;
this.loading(rtSimulation, mapVO);
this.initSimulationMember(rtSimulation);
this.initCreatorPlayMember(rtSimulation);
this.initCreatorPlayMember(rtSimulation, mapVO);
} catch (Exception e) {
this.simulationManager.destroy(rtSimulation.getId());
throw BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.exception(String.format("仿真初始化失败"), e);
}
rtSimulation.init();
// 郑州共赢驾驶默认加载一辆列车
if (Objects.equals(Project.ZZWW.name(), mapVO.getProjectCode()) &&
Objects.equals(MapPrdTypeEnum.DRIVER, prdTypeEnum)) {
this.srTrainOperationHandler.loadTrain(rtSimulation, "001", true, "T21");
}
simulationManager.start(rtSimulation.getId());
return rtSimulation;
}
private void initCreatorPlayMember(RtSimulation rtSimulation) {
private void initCreatorPlayMember(RtSimulation rtSimulation, MapVO mapVO) {
// RtSimulationMember simulationMember = rtSimulation.querySimulationMemberById("2");
// List<RtSimulationMember> memberList = rtSimulation.querySimulationMembersOfRole(RtSimulationMember.Role.LOWS);
// 大铁暂时默认新绛站值班员
this.simulationManager.memberPlayedByUser(rtSimulation.getId(), "2", rtSimulation.getCreator().getId());
// 大铁微机联锁项目默认新绛站值班员
if (Objects.equals(Project.WJLS.name(), mapVO.getProjectCode())) {
this.simulationManager.memberPlayedByUser(rtSimulation.getId(), "2", rtSimulation.getCreator().getId());
} else {
String memberId = "1";
for (RtSimulationMember rtSimulationMember : rtSimulation.getSimulationMembers()) {
if (Objects.equals("001", rtSimulationMember.deviceId)) {
memberId = rtSimulationMember.getId();
break;
}
}
this.simulationManager.memberPlayedByUser(rtSimulation.getId(), memberId, rtSimulation.getCreator().getId());
}
}
private void initSimulationMember(RtSimulation rtSimulation) {

View File

@ -3,6 +3,8 @@ package club.joylink.rtss.simulation.rt.SRD;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.rt.RtSimulation;
import club.joylink.rtss.simulation.rt.SRD.bo.*;
import club.joylink.rtss.simulation.rt.TL.bo.TlRepository;
import club.joylink.rtss.simulation.rt.TL.bo.TlTrain;
import club.joylink.rtss.vo.client.map.MapVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@ -26,20 +28,30 @@ public class SrdLogicService {
// 加载数据
SrdRepository srdRepository = SrdRepositoryBuilder.buildFrom(mapVO);
rtSimulation.addRepository(srdRepository);
SrdStateMessagePublisher srdStateMessagePublisher = new SrdStateMessagePublisher(rtSimulation);
rtSimulation.addMessagePublisher(srdStateMessagePublisher);
// 监控对象
for (SrSwitch srSwitch : srdRepository.getSwitchList()) {
rtSimulation.watch(srSwitch);
rtSimulation.watch(srSwitch, srdStateMessagePublisher);
}
for (SrSignal srSignal : srdRepository.getSignalList()) {
rtSimulation.watch(srSignal);
rtSimulation.watch(srSignal, srdStateMessagePublisher);
}
for (SrAXC srAXC : srdRepository.getAxcList()) {
rtSimulation.watch(srAXC);
rtSimulation.watch(srAXC, srdStateMessagePublisher);
}
for (SrPSD srPSD : srdRepository.getPsdList()) {
rtSimulation.watch(srPSD);
rtSimulation.watch(srPSD, srdStateMessagePublisher);
}
SrdTrainMessagePublisher publisher = new SrdTrainMessagePublisher(srdRepository);
rtSimulation.addMessagePublisher(publisher);
// 加载任务
this.addJobs(rtSimulation);
return srdRepository;
}
@ -93,8 +105,9 @@ public class SrdLogicService {
if (position == null) {
continue;
}
this.tryUpdateDirection(srTrain, repository);
boolean right = srTrain.isRight();
float cv = this.calculateSpeed(srTrain);
float cv = this.calculateSpeed(srTrain, repository);
int s = this.calculateLen(srTrain, cv, TRAIN_RUN_RATE);
// if (s == 0) {
// continue;
@ -120,6 +133,11 @@ public class SrdLogicService {
}
}
private void tryUpdateDirection(SrTrain srTrain, SrdRepository repository) {
TlTrain tlTrain = TlRepository.getInstanceFrom((RtSimulation) repository.getSimulation()).getTrainById(srTrain.getId());
srTrain.updateDirection(tlTrain.calGear());
}
/**
*
* @param srTrain
@ -135,31 +153,14 @@ public class SrdLogicService {
} else {
s = (int) l;
}
if (!srTrain.isNeutralGear()) {
return s * srTrain.getGear();
}
return s;
return s * srTrain.getDirection();
}
private float calculateSpeed(SrTrain srTrain) {
private float calculateSpeed(SrTrain srTrain, SrdRepository repository) {
float speed = srTrain.getSpeed();
// 暂时不考虑在前进挡中直接切到倒挡的情况
float maxSpeed = srTrain.getP() * srTrain.getSpeedMax() / 100;
float f = 0;
if (speed > maxSpeed) {
f -= srTrain.getFbDef();
} else if (speed < maxSpeed) {
f += srTrain.getFkMax() / srTrain.getSpeedMax() * (maxSpeed - speed);
float fkMin = (float) (0.3 * srTrain.getMass());
if (f < fkMin) {
f = fkMin;
}
}
if (srTrain.isEb()) {
f -= srTrain.getFbMax();
} else {
f -= srTrain.getBp() * srTrain.getFbMax() / 100 * 0.6f;
}
TlRepository tlRepository = TlRepository.getInstanceFrom((RtSimulation) repository.getSimulation());
TlTrain tlTrain = tlRepository.getTrainById(srTrain.getId());
float f = tlTrain.calculateF();
float a = f / (srTrain.getMass() + srTrain.getLoadMass());
float cv = (speed + a * TRAIN_RUN_RATE / 1000); // 当前速度
if (cv < 0) {
@ -168,6 +169,15 @@ public class SrdLogicService {
return cv;
}
/**
* 计算列车摩擦阻力
* @param srTrain
* @return
*/
private float calculateFriction(SrTrain srTrain) {
return (float) (0.05*(srTrain.getMass() +srTrain.getLoadMass()));
}
/**
*
* @param position 起始位置
@ -180,6 +190,10 @@ public class SrdLogicService {
if (s == 0) {
return position;
}
if (s < 0) {
right = !right;
s = Math.abs(s);
}
SrTrack track = position.getTrack();
int offset = position.getOffset();
if (right) {

View File

@ -0,0 +1,149 @@
package club.joylink.rtss.simulation.rt.SRD;
import club.joylink.rtss.simulation.Simulation;
import club.joylink.rtss.simulation.SimulationTriggerMessagePublisher;
import club.joylink.rtss.simulation.Watchable;
import club.joylink.rtss.simulation.rt.RtSimulation;
import club.joylink.rtss.simulation.rt.SRD.bo.*;
import java.util.*;
public class SrdStateMessagePublisher extends SimulationTriggerMessagePublisher {
public static final String Name = "SrdStateMP";
public static final String SrDeviceStatePath = "/srDeviceState";
private static final String AllDevicePatten = String.format("%s%s", Simulation.MESSAGE_SUB_PREFIX, SrDeviceStatePath);
public static final String SrSignalPath = "/srSignal";
private static final String SignalPatten = String.format("%s%s%s", Simulation.MESSAGE_SUB_PREFIX, SrSignalPath, "/{signalId}");
public static final String SrSwitchPath = "/srSwitch";
private static final String SwitchPatten = String.format("%s%s%s", Simulation.MESSAGE_SUB_PREFIX, SrSwitchPath, "/{switchId}");
public static final String SrAxcPath = "/srAxc";
private static final String AxcPatten = String.format("%s%s%s", Simulation.MESSAGE_SUB_PREFIX, SrAxcPath, "/{axcId}");
public static final String SrPsdPath = "/srPsd";
private static final String PsdPatten = String.format("%s%s%s", Simulation.MESSAGE_SUB_PREFIX, SrPsdPath, "/{psdId}");
RtSimulation simulation;
public SrdStateMessagePublisher(RtSimulation simulation) {
super(Name, Arrays.asList(AllDevicePatten, SignalPatten, SwitchPatten, AxcPatten, PsdPatten));
this.simulation = simulation;
}
@Override
public Object buildMessageOfSubscribe(String destination) {
Map<String, List<Object>> map = new HashMap<>();
if (destination.contains(SrDeviceStatePath)) {
return this.buildAllSrDeviceMessage();
} else if(destination.contains(SrSignalPath)) {
return this.buildSignalMessage(SrdRepository.getInstanceFrom(simulation).getSignalById(this.getDestinationParamsMap().get(destination).get(1)));
} else if(destination.contains(SrSwitchPath)) {
return this.buildSwitchMessage(SrdRepository.getInstanceFrom(simulation).getSwitchById(this.getDestinationParamsMap().get(destination).get(1)));
} else if(destination.contains(SrAxcPath)) {
return this.buildAxcMessage(SrdRepository.getInstanceFrom(simulation).getAxcById(this.getDestinationParamsMap().get(destination).get(1)));
} else if(destination.contains(SrPsdPath)) {
return this.buildPsdMessage(SrdRepository.getInstanceFrom(simulation).getPsdById(this.getDestinationParamsMap().get(destination).get(1)));
}
return map;
}
private Object buildAllSrDeviceMessage() {
Map<String, List<List<Object>>> map = new HashMap<>();
SrdRepository srdRepository = SrdRepository.getInstanceFrom(this.simulation);
List<List<Object>> signalMsgList = new ArrayList<>();
for (SrSignal srSignal : srdRepository.getSignalList()) {
signalMsgList.add(srSignal.getStateList());
}
map.put("srSignalList", signalMsgList);
List<List<Object>> switchMsgList = new ArrayList<>();
for (SrSwitch srSwitch : srdRepository.getSwitchList()) {
switchMsgList.add(srSwitch.getStateList());
}
map.put("srSwitchList", switchMsgList);
List<List<Object>> axcMsgList = new ArrayList<>();
for (SrAXC srAXC : srdRepository.getAxcList()) {
axcMsgList.add(srAXC.getStateList());
}
map.put("srAxcList", axcMsgList);
List<List<Object>> psdMsgList = new ArrayList<>();
for (SrPSD srPSD : srdRepository.getPsdList()) {
psdMsgList.add(srPSD.getStateList());
}
map.put("srPsdList", psdMsgList);
return map;
}
@Override
public List<String> getNeedBuildDestination(Watchable watchable) {
List<String> list = new ArrayList<>();
for (String destination : this.getDestinationParamsMap().keySet()) {
if (destination.contains(SrDeviceStatePath)) {
list.add(destination);
} else {
List<String> params = this.getDestinationParamsMap().get(destination);
if (destination.contains(SrSignalPath)) {
if (watchable instanceof SrSignal) {
if (((SrSignal) watchable).getId().equals(params.get(1))) {
list.add(destination);
}
}
} else if (destination.contains(SrSwitchPath)) {
if (watchable instanceof SrSwitch) {
if (((SrSwitch) watchable).getId().equals(params.get(1))) {
list.add(destination);
}
}
} else if (destination.contains(SrAxcPath)) {
if (watchable instanceof SrAXC) {
if (((SrAXC) watchable).getId().equals(params.get(1))) {
list.add(destination);
}
}
} else if (destination.contains(SrPsdPath)) {
if (watchable instanceof SrPSD) {
if (((SrPSD) watchable).getId().equals(params.get(1))) {
list.add(destination);
}
}
}
}
}
return list;
}
@Override
public Object buildMessage(Watchable watchable) {
if (watchable instanceof SrSignal) {
return this.buildSignalMessage((SrSignal) watchable);
} else if (watchable instanceof SrSwitch) {
return this.buildSwitchMessage((SrSwitch) watchable);
} else if (watchable instanceof SrAXC) {
return this.buildAxcMessage((SrAXC) watchable);
} else if (watchable instanceof SrPSD) {
return this.buildPsdMessage((SrPSD) watchable);
}
return null;
}
private Object buildSignalMessage(SrSignal srSignal) {
Map<String, List<Object>> map = new HashMap<>();
map.put("srSignal", srSignal.getStateList());
return map;
}
private Object buildSwitchMessage(SrSwitch srSwitch) {
Map<String, List<Object>> map = new HashMap<>();
map.put("srSwitch", srSwitch.getStateList());
return map;
}
private Object buildAxcMessage(SrAXC srAXC) {
Map<String, List<Object>> map = new HashMap<>();
map.put("srAxc", srAXC.getStateList());
return map;
}
private Object buildPsdMessage(SrPSD srPSD) {
Map<String, List<Object>> map = new HashMap<>();
map.put("srPsd", srPSD.getStateList());
return map;
}
}

View File

@ -1,17 +1,14 @@
package club.joylink.rtss.simulation.rt.SRD;
import club.joylink.rtss.simulation.Simulation;
import club.joylink.rtss.simulation.SimulationMessagePublisher;
import club.joylink.rtss.simulation.SimulationScheduleMessagePublisher;
import club.joylink.rtss.simulation.rt.SRD.bo.SrTrain;
import club.joylink.rtss.simulation.rt.SRD.bo.SrdRepository;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class SrdTrainMessagePublisher extends SimulationMessagePublisher {
public class SrdTrainMessagePublisher extends SimulationScheduleMessagePublisher {
public static final String NAME = "SrTrainMP";
public static final int RATE = 20;
public static final String DESTINATION = String.format("%s%s", Simulation.MESSAGE_SUB_PREFIX, "/trainPosition");
@ -19,7 +16,7 @@ public class SrdTrainMessagePublisher extends SimulationMessagePublisher {
Map<String, List<Object>> trainPositionMap = new ConcurrentHashMap<>();
public SrdTrainMessagePublisher(SrdRepository srdRepository) {
super(NAME, RATE, DESTINATION);
super(NAME, RATE, true, Arrays.asList(DESTINATION));
List<SrTrain> trainList = srdRepository.getTrainList();
for (SrTrain train : trainList) {
this.trainPositionMap.put(train.getId(), train.getStateList());
@ -27,7 +24,7 @@ public class SrdTrainMessagePublisher extends SimulationMessagePublisher {
}
@Override
public Object getNextSendMessage(String destination) {
public Object buildNextSendMessage(String destination) {
Map<String, List<List<Object>>> map = new HashMap<>();
List<List<Object>> trainList = new ArrayList<>();
map.put("trainPosList", trainList);
@ -44,6 +41,6 @@ public class SrdTrainMessagePublisher extends SimulationMessagePublisher {
@Override
public Object buildMessageOfSubscribe(String destination) {
return this.getNextSendMessage(destination);
return this.buildNextSendMessage(destination);
}
}

View File

@ -1,16 +0,0 @@
package club.joylink.rtss.simulation.rt.SRD.bo;
public enum DeviceType {
/** 计轴器 */
AXC,
/** 道岔 */
TURNOUT,
/** 信号机 */
SIGNAL,
/** 站台屏蔽门 */
PSD,
TRAIN,
/** 轨道 */
TRACK
}

View File

@ -1,5 +1,6 @@
package club.joylink.rtss.simulation.rt.SRD.bo;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@ -11,16 +12,18 @@ public class SrAXC extends SrDevice {
int state = OFF;
public static final int OFF = 0;//出清
public static final int ON = 1;//占用
boolean right; // 占用方向
Fault fault;
public SrAXC(String id) {
super(id, DeviceType.AXC);
super(id);
}
private boolean updateState(int state) {
if (this.state != state) {
this.state = state;
this.stateList.set(1, this.state);
this.fireWatcher();
return true;
}
@ -44,7 +47,7 @@ public class SrAXC extends SrDevice {
@Override
public void initState() {
this.state = OFF;
this.updateState(OFF);
this.fault = null;
this.fireWatcher();
}
@ -56,7 +59,7 @@ public class SrAXC extends SrDevice {
@Override
List<Object> buildMessage() {
return null;
return Arrays.asList(this.id, this.state);
}
public void setFault(Fault fault) {

View File

@ -13,7 +13,6 @@ import java.util.Objects;
@Getter
public abstract class SrDevice extends Watchable implements Debug {
String id;
DeviceType deviceType;
List<Object> stateList;
/**
@ -23,9 +22,8 @@ public abstract class SrDevice extends Watchable implements Debug {
public SrDevice() {}
public SrDevice(String id, DeviceType deviceType) {
public SrDevice(String id) {
this.id = id;
this.deviceType = deviceType;
this.stateList = this.buildMessage();
}
@ -35,7 +33,7 @@ public abstract class SrDevice extends Watchable implements Debug {
@Override
public String debugStr() {
return String.format("%s:%s", this.deviceType, this.id);
return String.format("%s:%s", getClass().getSimpleName(), this.id);
}
@Override

View File

@ -1,9 +1,10 @@
package club.joylink.rtss.simulation.rt.SRD.bo;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 虚拟真实屏蔽门Platform screen door
@ -17,15 +18,15 @@ public class SrPSD extends SrDevice {
public static final int TURNING = 3;//转换中
public static final int OPEN_FINISH = 4;//打开到位
AtomicInteger command = new AtomicInteger(NONE);
public static final int NONE = 0;//无动作
int command;
public static final int NONE = -1;//无动作
/**
* 转换完成时间
*/
LocalDateTime finishTime;
public SrPSD(String id) {
super(id, DeviceType.PSD);
super(id);
}
public int getState() {
@ -33,7 +34,36 @@ public class SrPSD extends SrDevice {
}
public boolean isTurning() {
return NONE != this.command.get();
return NONE != this.command;
}
private boolean updateState(int state) {
if (this.state != state) {
this.state = state;
this.stateList.set(1, this.state);
this.fireWatcher();
return true;
}
return false;
}
private boolean updateCommand(int command) {
if (this.command != command) {
this.command = (command);
this.stateList.set(2, this.command);
this.fireWatcher();
return true;
}
return false;
}
private boolean updateFinishTime(LocalDateTime finishTime) {
if (!Objects.equals(this.finishTime, finishTime)) {
this.finishTime = finishTime;
// this.fireWatcher();
return true;
}
return false;
}
public void open(LocalDateTime systemTime) {
@ -45,9 +75,9 @@ public class SrPSD extends SrDevice {
}
private void startTurn(LocalDateTime systemTime, int command) {
this.finishTime = systemTime.plusNanos(TimeUnit.MILLISECONDS.toNanos(turnTime));
this.command.set(command);
this.state = TURNING;
this.updateFinishTime(systemTime.plusNanos(TimeUnit.MILLISECONDS.toNanos(turnTime)));
this.updateCommand(command);
this.updateState(TURNING);
}
public void tryFinishTurning(LocalDateTime systemTime) {
@ -57,16 +87,16 @@ public class SrPSD extends SrDevice {
}
public void turnFinish() {
this.state = this.command.get();
this.command.set(NONE);
this.finishTime = null;
this.updateState(this.command);
this.updateCommand(NONE);
this.updateFinishTime(null);
}
@Override
public void initState() {
this.state = CLOSE_LOCK;
this.command.set(NONE);
this.finishTime = null;
this.updateState(CLOSE_LOCK);
this.updateCommand(NONE);
this.updateFinishTime(null);
}
@Override
@ -80,6 +110,6 @@ public class SrPSD extends SrDevice {
@Override
List<Object> buildMessage() {
return null;
return Arrays.asList(this.id, this.state, this.command);
}
}

View File

@ -3,10 +3,10 @@ package club.joylink.rtss.simulation.rt.SRD.bo;
import lombok.Getter;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 虚拟真实信号机
@ -32,7 +32,7 @@ public class SrSignal extends SrDevice {
public static final int B = 11; //
public static final int HS = 12; // 红闪
AtomicInteger command = new AtomicInteger(NONE);
int command;
public static final int NONE = -1;
/**
* 转换完成时间
@ -40,12 +40,13 @@ public class SrSignal extends SrDevice {
LocalDateTime finishTime;
public SrSignal(String id) {
super(id, DeviceType.SIGNAL);
super(id);
}
private boolean updateState(int state) {
public boolean updateState(int state) {
if (this.state != state) {
this.state = state;
this.stateList.set(1, this.state);
this.fireWatcher();
return true;
}
@ -53,8 +54,8 @@ public class SrSignal extends SrDevice {
}
private boolean updateCommand(int command) {
if (this.command.get() != command) {
this.command.set(command);
if (this.command != command) {
this.command = (command);
this.fireWatcher();
return true;
}
@ -64,7 +65,7 @@ public class SrSignal extends SrDevice {
private boolean updateFinishTime(LocalDateTime finishTime) {
if (!Objects.equals(this.finishTime, finishTime)) {
this.finishTime = finishTime;
this.fireWatcher();
// this.fireWatcher();
return true;
}
return false;
@ -75,7 +76,7 @@ public class SrSignal extends SrDevice {
}
public boolean isTurning() {
return NONE != this.command.get();
return NONE != this.command;
}
public void close(LocalDateTime systemTime) {
@ -110,7 +111,7 @@ public class SrSignal extends SrDevice {
}
public void turnFinish() {
this.updateState(this.command.get());
this.updateState(this.command);
this.updateCommand(NONE);
this.updateFinishTime(null);
}
@ -121,9 +122,9 @@ public class SrSignal extends SrDevice {
if (this.shunting) {
state = A;
}
this.state = state;
this.command.set(NONE);
this.finishTime = null;
this.updateState(state);
this.updateCommand(NONE);
this.updateFinishTime(null);
}
@Override
@ -137,7 +138,7 @@ public class SrSignal extends SrDevice {
@Override
List<Object> buildMessage() {
return null;
return Arrays.asList(this.id, this.state);
}
public void open(LocalDateTime systemTime, int aspect) {

View File

@ -3,10 +3,10 @@ package club.joylink.rtss.simulation.rt.SRD.bo;
import lombok.Getter;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 虚拟真实道岔
@ -21,7 +21,7 @@ public class SrSwitch extends SrDevice {
public static final int REVERSE = 2; // 反位
public static final int SQUEEZING = 4; // 挤叉
AtomicInteger command = new AtomicInteger(NONE);
int command;
public static final int NONE = -1;
/**
* 转换完成时间
@ -29,12 +29,13 @@ public class SrSwitch extends SrDevice {
LocalDateTime finishTime;
public SrSwitch(String id) {
super(id, DeviceType.TURNOUT);
super(id);
}
private boolean updateState(int state) {
if (this.state != state) {
this.state = state;
this.stateList.set(1, this.state);
this.fireWatcher();
return true;
}
@ -42,8 +43,9 @@ public class SrSwitch extends SrDevice {
}
private boolean updateCommand(int command) {
if (this.command.get() != command) {
this.command.set(command);
if (this.command != command) {
this.command = (command);
this.stateList.set(2, this.command);
this.fireWatcher();
return true;
}
@ -53,7 +55,7 @@ public class SrSwitch extends SrDevice {
private boolean updateFinishTime(LocalDateTime finishTime) {
if (!Objects.equals(this.finishTime, finishTime)) {
this.finishTime = finishTime;
this.fireWatcher();
// this.fireWatcher();
return true;
}
return false;
@ -72,19 +74,19 @@ public class SrSwitch extends SrDevice {
}
public boolean isTurning() {
return NONE != this.command.get();
return NONE != this.command;
}
public boolean isTurningToNormal() {
return NORMAL == this.command.get();
return NORMAL == this.command;
}
public boolean isTurningToReverse() {
return REVERSE == this.command.get();
return REVERSE == this.command;
}
public boolean turnToNormal(LocalDateTime systemTime) {
if (this.isNormalPosition() || this.command.get() == NORMAL) {
if (this.isNormalPosition() || this.command == NORMAL) {
return false;
}
this.startTurn(systemTime, NORMAL);
@ -92,7 +94,7 @@ public class SrSwitch extends SrDevice {
}
public boolean turnToReverse(LocalDateTime systemTime) {
if (this.isReversePosition() || this.command.get() == REVERSE) {
if (this.isReversePosition() || this.command == REVERSE) {
return false;
}
this.startTurn(systemTime, REVERSE);
@ -112,16 +114,16 @@ public class SrSwitch extends SrDevice {
}
public void turnFinish() {
this.updateState(this.command.get());
this.updateState(this.command);
this.updateCommand(NONE);
this.updateFinishTime(null);
}
@Override
public void initState() {
this.state = NORMAL;
this.command.set(NONE);
this.finishTime = null;
this.updateState(NORMAL);
this.updateCommand(NONE);
this.updateFinishTime(null);
}
@Override
@ -135,6 +137,6 @@ public class SrSwitch extends SrDevice {
@Override
List<Object> buildMessage() {
return null;
return Arrays.asList(this.id, this.state, this.command);
}
}

View File

@ -42,7 +42,7 @@ public class SrTrack extends SrDevice implements Debug {
SrSwitch srSwitch;
public SrTrack(String id) {
super(id, DeviceType.TRACK);
super(id);
}
public void setAxc(SrAXC axc) {

View File

@ -1,5 +1,6 @@
package club.joylink.rtss.simulation.rt.SRD.bo;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import lombok.Getter;
import java.util.Arrays;
@ -24,50 +25,20 @@ public class SrTrain extends SrDevice {
* 负载质量,单位kg
*/
int loadMass = 0;
/**
* 列车最大速度单位: m/s
*/
float speedMax = 33.33f; // 120km/h
/**
* 列车最大牵引力
*/
float fkMax = 560000f; // 按2.5m/s2计算的
/**
* 列车最大制动力
*/
float fbMax = 448000f; //
/**
* 默认阻力
*/
float fbDef = 11200f;
/**
* 发动机牵引功率0 <= p <= 100 (%)
*/
int p;
/**
* 制动功率0 <= bp <= 100 (%)
*/
int bp;
/**
* 是否紧急制动
*/
boolean eb;
int f; // 列车所受合力
/**
* 列车速度,单位m/s
*/
float speed;
/**
* 列车方向
* 列车方向(列车朝向)
*/
boolean right;
/**
* 档位
* 方向
*/
int gear;
public static final int NEUTRAL = 0; //空挡
public static final int FORWARD = 1; //前进挡
public static final int REVERSE = -1; //后退档
int direction;
public static final int FORWARD = 1; //前进
public static final int REVERSE = -1; //后退
/**
* 列车头位置
*/
@ -78,12 +49,17 @@ public class SrTrain extends SrDevice {
TrackPosition tailPosition;
public SrTrain(String id, int len) {
super(id, DeviceType.TRAIN);
super(id);
this.len = len;
}
public boolean isNeutralGear() {
return NEUTRAL == this.gear;
public boolean updateDirection(int direction) {
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertTrue(direction <= FORWARD && direction >= REVERSE);
if (this.direction != direction && this.speed == 0) {
this.direction = direction;
return true;
}
return false;
}
public boolean updateRight(boolean right) {
@ -112,21 +88,6 @@ public class SrTrain extends SrDevice {
return change;
}
public boolean updateP(int p) {
if (this.p != p) {
this.p = p;
return true;
}
return false;
}
public boolean updateBp(int bp) {
if (this.bp != bp) {
this.bp = bp;
}
return false;
}
public void updatePositionAndSpeed(TrackPosition headPosition, TrackPosition tailPosition, float v) {
this.updateHeadPosition(headPosition);
this.speed = v;
@ -134,10 +95,8 @@ public class SrTrain extends SrDevice {
@Override
public void initState() {
this.p = 0;
this.eb = false;
this.speed = 0;
this.gear = NEUTRAL;
this.updateDirection(FORWARD);
this.updateHeadPosition(null);
}
@ -155,4 +114,8 @@ public class SrTrain extends SrDevice {
this.updateHeadPosition(trackPosition);
this.updateRight(right);
}
public float getTotalMass() {
return this.mass+this.loadMass;
}
}

View File

@ -2,6 +2,7 @@ package club.joylink.rtss.simulation.rt.SRD.bo;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.SimulationRepository;
import club.joylink.rtss.simulation.rt.RtSimulation;
import club.joylink.rtss.simulation.rt.repo.CommonRepository;
import club.joylink.rtss.simulation.rt.repo.CommonSection;
import club.joylink.rtss.simulation.rt.repo.CommonSwitch;
@ -31,6 +32,10 @@ public class SrdRepository extends SimulationRepository {
this.trainMap = new HashMap<>();
}
public static SrdRepository getInstanceFrom(RtSimulation simulation) {
return simulation.getRepository(NAME, SrdRepository.class);
}
public List<SrTrain> getTrainList() {
return new ArrayList<>(this.trainMap.values());
}
@ -108,4 +113,10 @@ public class SrdRepository extends SimulationRepository {
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertNotNull(srTrack);
return srTrack;
}
public SrPSD getPsdById(String id) {
SrPSD srPSD = this.psdMap.get(id);
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertNotNull(srPSD);
return srPSD;
}
}

View File

@ -1,42 +1,46 @@
package club.joylink.rtss.simulation.rt.TL;
import club.joylink.rtss.simulation.Simulation;
import club.joylink.rtss.simulation.SimulationMessagePublisher;
import club.joylink.rtss.simulation.SimulationScheduleMessagePublisher;
import club.joylink.rtss.simulation.rt.TL.bo.TlTrain;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class TlHmiMessagePublisher extends SimulationMessagePublisher {
public class TlHmiMessagePublisher extends SimulationScheduleMessagePublisher {
public static final String NAME = "TlHmiMP";
public static final int RATE = 1000;
public static final String DESTINATION = String.format("%s%s", Simulation.MESSAGE_SUB_PREFIX, "/trainHmi");
public static final String DESTINATION = String.format("%s%s", Simulation.MESSAGE_SUB_PREFIX, "/train/{trainId}/Hmi");
Map<String, List<Object>> hmiMap = new ConcurrentHashMap<>();
public TlHmiMessagePublisher(List<TlTrain> tlTrainList) {
super(NAME, RATE, DESTINATION);
super(NAME, RATE, true, Arrays.asList(DESTINATION));
for (TlTrain train : tlTrainList) {
hmiMap.put(train.getId(), train.getStateList());
}
}
@Override
public Object getNextSendMessage(String destination) {
Map<String, List<List<Object>>> map = new HashMap<>();
List<List<Object>> hmiList = new ArrayList<>();
map.put("hmi", hmiList);
for (List<Object> value : this.hmiMap.values()) {
hmiList.add(value);
}
return hmiList.isEmpty() ? null : map;
public boolean isValidParams(List<String> params) {
return this.hmiMap.containsKey(params.get(1));
}
@Override
public Object buildNextSendMessage(String destination) {
Map<String, List<String>> destinationParamsMap = this.getDestinationParamsMap();
List<String> params = destinationParamsMap.get(destination);
String trainId = params.get(1);
Map<String, List<Object>> map = new HashMap<>();
map.putIfAbsent("hmi", this.hmiMap.get(trainId));
return map;
}
@Override
public Object buildMessageOfSubscribe(String destination) {
return this.getNextSendMessage(destination);
return this.buildNextSendMessage(destination);
}
}

View File

@ -0,0 +1,45 @@
package club.joylink.rtss.simulation.rt.TL;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.rt.RtSimulation;
import club.joylink.rtss.simulation.rt.TL.bo.TlRepository;
import club.joylink.rtss.simulation.rt.TL.bo.TlTrain;
import org.springframework.stereotype.Component;
@Component
public class TrainDriveService {
public void changeOverSwitch(RtSimulation simulation, String id, int pos) {
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertTrue(pos >= -1 && pos <= 2);
TlRepository tlRepository = TlRepository.getInstanceFrom(simulation);
TlTrain train = tlRepository.getTrainById(id);
train.updateChangeOverSwitch(pos);
}
public void changeGear(RtSimulation simulation, String id, int pos) {
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertTrue(pos >= -1 && pos <= 9);
TlRepository tlRepository = TlRepository.getInstanceFrom(simulation);
TlTrain train = tlRepository.getTrainById(id);
train.updateGear(pos);
}
public void changeThrottle(RtSimulation simulation, String id, int pos) {
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertTrue(pos >= 0 && pos <= 100);
TlRepository tlRepository = TlRepository.getInstanceFrom(simulation);
TlTrain train = tlRepository.getTrainById(id);
train.updateThrottle(pos);
}
public void changeSingleBreak(RtSimulation simulation, String id, int pos) {
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertTrue(pos >= 0 && pos <= 100);
TlRepository tlRepository = TlRepository.getInstanceFrom(simulation);
TlTrain train = tlRepository.getTrainById(id);
train.updateSingleBreak(pos);
}
public void changeAutoBreak(RtSimulation simulation, String id, int pos) {
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertTrue(pos >= 0 && pos <= 150);
TlRepository tlRepository = TlRepository.getInstanceFrom(simulation);
TlTrain train = tlRepository.getTrainById(id);
train.updateAutoBreak(pos);
}
}

View File

@ -2,6 +2,7 @@ package club.joylink.rtss.simulation.rt.TL.bo;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.SimulationRepository;
import club.joylink.rtss.simulation.rt.RtSimulation;
import lombok.Getter;
import java.util.ArrayList;
@ -20,6 +21,10 @@ public class TlRepository extends SimulationRepository {
this.trainMap = new HashMap<>();
}
public static TlRepository getInstanceFrom(RtSimulation simulation) {
return simulation.getRepository(NAME, TlRepository.class);
}
@Override
public void initState() {
for (TlTrain train : this.trainMap.values()) {

View File

@ -17,6 +17,13 @@ public class TlTrain extends TlDevice {
*/
float speed;
int controlPosition;//司控器手柄位置
int gear; // 档位(-1~9,1挡为起步挡2~9实际为1~8挡)
int throttlePosition; // 油门杆位置(0~100)
int changeOverSwitch; // 换向开关(-1, 0, 1, 2:手动)
int changeOverState; // 换向器状态-1, 0, 1
int singleBreak; // 单独制动阀(单独操纵机车的制动)
int autoBreak; // 自动制动阀操纵全列车的制动
public TlTrain(SrTrain train) {
super(train.getId());
@ -43,16 +50,87 @@ public class TlTrain extends TlDevice {
public boolean updateControlPosition(int controlPosition) {
if (this.controlPosition != controlPosition) {
this.controlPosition = controlPosition;
if (controlPosition > 0) {
this.srTrain.updateP(controlPosition);
this.srTrain.updateBp(0);
} else if (controlPosition < 0) {
this.srTrain.updateP(0);
this.srTrain.updateBp(Math.abs(controlPosition));
} else {
this.srTrain.updateP(0);
this.srTrain.updateBp(0);
return true;
}
return false;
}
public boolean updateChangeOverState(int changeOverState) {
if (this.changeOverState != changeOverState) {
this.changeOverState = changeOverState;
return true;
}
return false;
}
public boolean updateChangeOverSwitch(int changeOverSwitch) {
if (this.changeOverSwitch != changeOverSwitch) {
this.changeOverSwitch = changeOverSwitch;
if (changeOverSwitch < 2) {
this.updateChangeOverState(changeOverSwitch);
}
this.srTrain.updateDirection(this.calGear());
this.stateList.set(2, this.changeOverSwitch);
return true;
}
return false;
}
public boolean updateGear(int gear) {
if (this.gear != gear) {
this.gear = gear;
this.srTrain.updateDirection(this.calGear());
this.stateList.set(3, this.gear);
return true;
}
return false;
}
public int calGear() {
switch (this.changeOverState) {
case -1:
if (this.gear == -1) {
return 1;
} else if (this.gear == 0) {
return 0;
} else {
return -1;
}
case 0:
return 0;
case 1:
if (this.gear > 0) {
return 1;
} else {
return this.gear;
}
default:
throw new RuntimeException("换向器:无效的值");
}
}
public boolean updateThrottle(int pos) {
if (this.throttlePosition != pos) {
this.throttlePosition = pos;
this.stateList.set(4, this.throttlePosition);
return true;
}
return false;
}
public boolean updateSingleBreak(int pos) {
if (this.singleBreak != pos) {
this.singleBreak = pos;
this.stateList.set(5, this.singleBreak);
return true;
}
return false;
}
public boolean updateAutoBreak(int pos) {
if (this.autoBreak != pos) {
this.autoBreak = pos;
this.stateList.set(6, this.autoBreak);
return true;
}
return false;
@ -65,6 +143,121 @@ public class TlTrain extends TlDevice {
@Override
List<Object> buildMessage() {
return Arrays.asList(this.id, this.speed, this.controlPosition);
return Arrays.asList(this.id, this.speed, this.changeOverSwitch, this.gear, this.throttlePosition,
this.singleBreak, this.autoBreak);
}
public float calculateF() {
float f = 0;
float speed = this.srTrain.getSpeed();
// 根据列车档位和油门计算牵引力或制动力
float vmin = 0;
float vmax = 0;
float amin = 0;
float amax = 0;
switch (this.gear) {
case -1: // 倒车3~7km/h; 1.89 ~ 1.64 m/s^2
vmin = 3;
vmax = 7;
amax = 1.89f;
amin = 1.64f;
break;
case 0: // 空挡
break;
case 1: // 起步挡3~8km/h; 1.89 ~ 1.64 m/s^2
vmin = 3;
vmax = 8;
amax = 1.89f;
amin = 1.64f;
break;
case 2: // 1挡5~15km/h; 1.38 ~ 1.15 m/s^2
vmin = 5;
vmax = 15;
amax = 1.38f;
amin = 1.15f;
break;
case 3: // 2挡9~20km/h; 0.92 ~ 0.73 m/s^2
vmin = 9;
vmax = 20;
amax = 0.92f;
amin = 0.73f;
break;
case 4: // 3挡13~28km/h; 0.65 ~ 0.48 m/s^2
vmin = 13;
vmax = 28;
amax = 0.65f;
amin = 0.48f;
break;
case 5: // 4挡20~38km/h; 0.47 ~ 0.32 m/s^2
vmin = 20;
vmax = 38;
amax = 0.47f;
amin = 0.32f;
break;
case 6: // 5挡26~50km/h; 0.30 ~ 0.21 m/s^2
vmin = 26;
vmax = 50;
amax = 0.30f;
amin = 0.21f;
break;
case 7: // 6挡33~60km/h; 0.21 ~ 0.15 m/s^2
vmin = 33;
vmax = 60;
amax = 0.21f;
amin = 0.15f;
break;
case 8: // 7挡52~75km/h; 0.15 ~ 0.11 m/s^2
vmin = 52;
vmax = 75;
amax = 0.15f;
amin = 0.11f;
break;
case 9: // 8挡60~90km/h; 0.11 ~ 0.08 m/s^2
vmin = 60;
vmax = 90;
amax = 0.11f;
amin = 0.08f;
break;
default:
throw new RuntimeException("无效的档位");
}
float fk = 0;
float fb = 0;
if (this.gear != 0 && this.changeOverState != 0) { // 非空挡
float vs = (float) ((vmin + (Float.valueOf(vmax - vmin) * this.throttlePosition / 100)) / 3.6);
if (speed > vs) {
fb += this.calculateAccOf(speed - vs) * this.srTrain.getTotalMass();
} else {
fk = (float) ((amin + ((vs - vmin) / (vmax - vmin) * (amax - amin))) * this.srTrain.getTotalMass());
}
}
// 根据制动阀计算制动力
fb += this.calculateFb();
// 计算合力
f = fk - fb;
// if (fk == 0) {
// float ff = this.calculateFriction(speed, this.srTrain.getTotalMass()); // 摩擦力
// f -= ff;
// }
return f;
}
private float calculateFb() {
float fb1 = (float) ((1.0 * this.autoBreak / 100) * this.srTrain.getTotalMass());
float fb2 = (float) ((0.6 * this.singleBreak / 100) * this.srTrain.getTotalMass());
return Math.max(fb1, fb2);
}
/**
* 计算减速度档位所在速度小于列车速度时
* @param v 当前速度和档位速度差
* @return
*/
private float calculateAccOf(float v) {
return v / 20;
}
private float calculateFriction(float speed, float mass) {
return (float) (0.05*mass);
}
}

View File

@ -0,0 +1,29 @@
package club.joylink.rtss.simulation.rt;
import club.joylink.rtss.simulation.SimulationManager;
import club.joylink.rtss.simulation.rt.SRD.bo.SrSignal;
import club.joylink.rtss.simulation.rt.SRD.bo.SrdRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 快速测试设备状态接口
*/
@RestController
@RequestMapping("/test/simulation/{id}")
public class TestDeviceStateController {
@Autowired
private SimulationManager simulationManager;
@GetMapping("/srSignal/{signalId}/state/{state}")
public void updateSrSignalState(@PathVariable String id, @PathVariable String signalId, @PathVariable int state) {
RtSimulation rtSimulation = this.simulationManager.getById(id, RtSimulation.class);
SrdRepository repository = SrdRepository.getInstanceFrom(rtSimulation);
SrSignal srSignal = repository.getSignalById(signalId);
srSignal.updateState(state);
}
}

View File

@ -4,12 +4,15 @@ import club.joylink.rtss.simulation.operation.SimulationOperationController;
import club.joylink.rtss.simulation.operation.SimulationOperationMapping;
import club.joylink.rtss.simulation.rt.RtSimulation;
import club.joylink.rtss.simulation.rt.SRD.SrdTrainService;
import club.joylink.rtss.simulation.rt.TL.TrainDriveService;
import org.springframework.beans.factory.annotation.Autowired;
@SimulationOperationController()
public class SrTrainOperationHandler {
@Autowired
private SrdTrainService srdTrainService;
@Autowired
private TrainDriveService trainDriveService;
@SimulationOperationMapping("Train_Load_Spare_Train")
public void loadTrain(RtSimulation simulation, String groupNumber,
@ -21,4 +24,47 @@ public class SrTrainOperationHandler {
public void powerControl(RtSimulation simulation, String id, int p) {
this.srdTrainService.powerControl(simulation, id, p);
}
/**
* 换向开关位置
* @param simulation
* @param id
* @param pos
*/
@SimulationOperationMapping("Train_Drive_Change_Over_Switch")
public void changeOverSwitch(RtSimulation simulation, String id, int pos) {
this.trainDriveService.changeOverSwitch(simulation, id, pos);
}
/**
* 换挡
*/
@SimulationOperationMapping("Train_Drive_Gear_Change")
public void gearChange(RtSimulation simulation, String id, int pos) {
this.trainDriveService.changeGear(simulation, id, pos);
}
/**
* 油门杆
*/
@SimulationOperationMapping("Train_Drive_Throttle_Change")
public void throttleChange(RtSimulation simulation, String id, int pos) {
this.trainDriveService.changeThrottle(simulation, id, pos);
}
/**
* 头节车厢制动
*/
@SimulationOperationMapping("Train_Drive_Single_Break")
public void singleBreak(RtSimulation simulation, String id, int pos) {
this.trainDriveService.changeSingleBreak(simulation, id, pos);
}
/**
* 所有车厢制动
*/
@SimulationOperationMapping("Train_Drive_Auto_Break")
public void autoBreak(RtSimulation simulation, String id, int pos) {
this.trainDriveService.changeAutoBreak(simulation, id, pos);
}
}

View File

@ -2,6 +2,7 @@ package club.joylink.rtss.simulation.rt.repo;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.SimulationRepository;
import club.joylink.rtss.simulation.rt.RtSimulation;
import lombok.Getter;
import java.util.HashMap;
@ -21,6 +22,10 @@ public class CommonRepository extends SimulationRepository {
Map<String, CommonFls> flsMap;
Map<String, CommonRoute> routeMap;
Map<String, CommonOverlap> overlapMap;
/**
* key-sectionId 区段id
*/
Map<String, List<CommonSignal>> approachSignalMap;
public CommonRepository() {
super(NAME);
@ -32,6 +37,11 @@ public class CommonRepository extends SimulationRepository {
this.flsMap = new HashMap<>();
this.routeMap = new HashMap<>();
this.overlapMap = new HashMap<>();
this.approachSignalMap = new HashMap<>();
}
public static CommonRepository getInstanceFrom(RtSimulation simulation) {
return simulation.getRepository(NAME, CommonRepository.class);
}
public CommonSignal getSignalById(String id) {

View File

@ -48,11 +48,20 @@ public class CommonRepositoryBuilder {
BusinessExceptionAssertEnum.DATA_ERROR.assertNotNull(signal,
String.format("信号机接近区段关联信号机[%s]不存在", approachVO.getSignalCode()));
List<MapSectionPathVO> sectionPathList = approachVO.getSectionPathList();
List<TrackWay> list = new ArrayList<>();
List<TrackPath> list = new ArrayList<>();
if (!CollectionUtils.isEmpty(sectionPathList)) {
for (MapSectionPathVO pathVO : sectionPathList) {
list.add(buildTrackWay(pathVO.getSectionList(), pathVO.getSwitchPositionList(),
null, !signal.isRight(), commonRepository));
TrackPath trackPath = buildTrackPath(pathVO.getSectionList(), pathVO.getSwitchPositionList(),
!signal.isRight(), commonRepository);
list.add(trackPath);
for (CommonSection commonSection : trackPath.getSectionList()) {
List<CommonSignal> signals = commonRepository.approachSignalMap.get(commonSection.getId());
if (signals == null) {
signals = new ArrayList<>();
commonRepository.approachSignalMap.put(commonSection.getId(), signals);
}
signals.add(signal);
}
}
signal.approachList = list;
}
@ -169,6 +178,7 @@ public class CommonRepositoryBuilder {
BusinessExceptionAssertEnum.DATA_ERROR.assertNotNull(start,
String.format("进路[%s]的始端信号机[%s]不存在", routeVO.getId(), routeVO.getStartSignalCode()));
commonRoute.start = start;
start.routeList.add(commonRoute);
if (StringUtils.hasText(routeVO.getEndSignalCode())) {
CommonSignal end = signalMap.get(routeVO.getEndSignalCode());
BusinessExceptionAssertEnum.DATA_ERROR.assertNotNull(end,
@ -220,6 +230,30 @@ public class CommonRepositoryBuilder {
}
}
private static TrackPath buildTrackPath(List<String> sectionList,
List<MapCISwitchVO> switchList,
boolean right, CommonRepository commonRepository) {
Map<String, CommonSection> sectionMap = commonRepository.sectionMap;
Map<String, CommonSwitch> switchMap = commonRepository.switchMap;
BusinessExceptionAssertEnum.DATA_ERROR.assertTrue(null != sectionList && sectionList.size() >= 1);
TrackPath trackPath = new TrackPath(right);
for (String code : sectionList) {
CommonSection section = sectionMap.get(code);
BusinessExceptionAssertEnum.DATA_ERROR.assertNotNull(section,
String.format("构建路径失败不存在code为[%s]的区段", code));
trackPath.addSection(section);
}
if (switchList != null) {
for (MapCISwitchVO ciSwitchVO : switchList) {
CommonSwitch commonSwitch = switchMap.get(ciSwitchVO.getSwitchCode());
BusinessExceptionAssertEnum.DATA_ERROR.assertNotNull(commonSwitch,
String.format("构建路径失败不存在code为[%s]的道岔", ciSwitchVO.getSwitchCode()));
trackPath.addSwitchPosition(commonSwitch, ciSwitchVO.isNormal());
}
}
return trackPath;
}
private static TrackWay buildTrackWay(List<String> sectionList,
List<MapCISwitchVO> switchList,
List<String> flsList,
@ -320,6 +354,7 @@ public class CommonRepositoryBuilder {
CommonSection section = sectionMap.get(signalVO.getSectionCode());
BusinessExceptionAssertEnum.DATA_ERROR.assertNotNull(section,
String.format("信号机[%s]关联code为[%s]的区段不存在", signalVO.getCode(), signalVO.getSectionCode()));
section.signalList.add(commonSignal);
commonSignal.section = section;
commonSignal.offset = (int) (signalVO.getSectionOffset() * 1000);
}

View File

@ -1,9 +1,12 @@
package club.joylink.rtss.simulation.rt.repo;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import lombok.Getter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@Getter
public class CommonSection extends CommonDevice {
@ -13,15 +16,19 @@ public class CommonSection extends CommonDevice {
CommonStation station;
CommonStation ecStation;// 设备集中站
CommonSection leftSection;
CommonSection leftFlankSection;
CommonSection rightSection;
CommonSection rightFlankSection;
CommonSection parent;
List<CommonSection> relateList;
CommonSwitch belongSwitch;
List<CommonSignal> signalList; // 在此区段上的信号机
List<CommonStand> standList;
public CommonSection(String id, String name) {
super(id, name);
this.relateList = new ArrayList<>();
this.signalList = new ArrayList<>();
this.standList = new ArrayList<>();
}
@ -58,6 +65,37 @@ public class CommonSection extends CommonDevice {
return this.parent == null ? this : this.parent;
}
public CommonSection queryNextBy(boolean right) {
if (right) {
return this.getRightSection();
} else {
return this.getLeftSection();
}
}
public CommonSection queryNextSwitchSectionBy(boolean right, boolean normal) {
BusinessExceptionAssertEnum.INVALID_OPERATION.assertTrue(this.isSwitchSection());
if (!normal) {
if (right) {
return this.rightFlankSection != null ? this.rightFlankSection : this.rightSection;
} else {
return this.leftFlankSection != null ? this.leftFlankSection : this.leftSection;
}
} else {
if (right) {
return rightSection;
} else {
return leftSection;
}
}
}
public List<CommonSignal> getSignalOf(boolean right) {
return this.signalList.stream()
.filter(signal -> Objects.equals(signal.isRight(), right))
.collect(Collectors.toList());
}
public enum Type {
/** 一般计轴区段 */
NAx,

View File

@ -2,6 +2,7 @@ package club.joylink.rtss.simulation.rt.repo;
import lombok.Getter;
import java.util.ArrayList;
import java.util.List;
@Getter
@ -15,10 +16,13 @@ public class CommonSignal extends CommonDevice {
CommonSection section; // 所在区段
int offset; // 所在区段偏移量单位mm
List<TrackWay> approachList;
List<TrackWay> ctcApproachList; // 暂时不使用
List<TrackPath> approachList;
List<TrackPath> ctcApproachList; // 暂时不使用
List<CommonRoute> routeList;
public CommonSignal(String id, String name) {
super(id, name);
this.routeList = new ArrayList<>();
}
}

View File

@ -25,6 +25,17 @@ public class CommonSwitch extends CommonDevice {
a.belongSwitch = this;
b.belongSwitch = this;
c.belongSwitch = this;
if (a.leftSection != null) {
a.rightSection = b;
a.rightFlankSection = c;
b.leftSection = a;
c.leftSection = a;
} else if (a.rightSection != null) {
a.leftSection = b;
a.leftFlankSection = c;
b.rightSection = a;
c.rightSection = a;
}
}
public boolean isA(CommonSection section) {

View File

@ -0,0 +1,45 @@
package club.joylink.rtss.simulation.rt.repo;
import lombok.Getter;
import java.util.ArrayList;
import java.util.List;
@Getter
public class TrackPath {
boolean right;
List<CommonSection> sectionList;
List<SwitchPosition> spList;
public TrackPath(boolean right) {
this.right = right;
this.sectionList = new ArrayList<>();
this.spList = new ArrayList<>();
}
public void addSection(CommonSection section) {
this.sectionList.add(section);
}
public void addSwitchPosition(CommonSwitch commonSwitch, boolean normal) {
SwitchPosition switchPosition = SwitchPosition.buildSwitchPosition(commonSwitch, normal);
this.spList.add(switchPosition);
}
public boolean isEmpty() {
return this.sectionList.isEmpty();
}
public TrackPath clone() {
TrackPath clone = new TrackPath(this.right);
clone.sectionList.addAll(this.sectionList);
clone.spList.addAll(this.spList);
return clone;
}
public int calTotalLen() {
return this.sectionList.stream()
.mapToInt(CommonSection::getLen)
.sum();
}
}

View File

@ -24,6 +24,7 @@ public class TrackWay implements Debug {
Map<String, CommonSection> sectionMap;
List<CommonSection> sectionList; // 不包含start和end
List<SwitchPosition> spList; // 路径中道岔位置
Integer reverseSwitchCount; // 路径中反位道岔数量
List<SwitchPosition> fspList; // 非路径道岔位置
List<CommonFls> flsList; // 侧防
@ -85,6 +86,18 @@ public class TrackWay implements Debug {
return false;
}
public int getReverseSwitchCount() {
if (this.reverseSwitchCount == null) {
this.reverseSwitchCount = 0;
for (SwitchPosition switchPosition : this.spList) {
if (!switchPosition.isNormal()) {
this.reverseSwitchCount++;
}
}
}
return this.reverseSwitchCount;
}
public List<CommonSection> getAllSectionList() {
List<CommonSection> list = new ArrayList<>();
list.add(this.start);

View File

@ -1,10 +1,8 @@
package club.joylink.rtss.simulation.rt.vo;
import club.joylink.rtss.simulation.SimulationMember;
import club.joylink.rtss.simulation.rt.RtSimulationMember;
import club.joylink.rtss.simulation.vo.SimulationMemberVO;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
public class RtSimulationMemberVO extends SimulationMemberVO {

View File

@ -3,6 +3,8 @@ package club.joylink.rtss.vo.client.map.newmap;
import club.joylink.rtss.simulation.cbtc.data.map.RouteFls;
import club.joylink.rtss.simulation.cbtc.data.map.Section;
import club.joylink.rtss.simulation.cbtc.data.map.SectionPath;
import club.joylink.rtss.simulation.rt.repo.CommonSection;
import club.joylink.rtss.simulation.rt.repo.TrackPath;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@ -43,6 +45,18 @@ public class MapSectionPathVO {
return voList;
}
public static MapSectionPathVO from(TrackPath trackPath) {
MapSectionPathVO vo = new MapSectionPathVO();
vo.setRight(trackPath.isRight());
vo.setSectionList(trackPath.getSectionList().stream()
.map(CommonSection::getId)
.collect(Collectors.toList()));
vo.setSwitchPositionList(trackPath.getSpList().stream()
.map(switchPosition -> new MapCISwitchVO(switchPosition.getCommonSwitch().getId(), switchPosition.isNormal()))
.collect(Collectors.toList()));
return vo;
}
private static MapSectionPathVO from(SectionPath sectionPath) {
MapSectionPathVO vo = new MapSectionPathVO();
List<String> sectionList = sectionPath.getSectionList().stream()
@ -60,4 +74,14 @@ public class MapSectionPathVO {
}
return vo;
}
public static List<MapSectionPathVO> convertTrackPath2VOList(List<TrackPath> list) {
List<MapSectionPathVO> voList = new ArrayList<>();
if (!CollectionUtils.isEmpty(list)) {
for (TrackPath trackPath : list) {
voList.add(MapSectionPathVO.from(trackPath));
}
}
return voList;
}
}