Compare commits
6 Commits
master
...
thailand_s
Author | SHA1 | Date | |
---|---|---|---|
8709ecab5b | |||
e461a62552 | |||
b653258e75 | |||
ecdf9fdc84 | |||
2a08dab6c9 | |||
21afd1f82f |
@ -48,7 +48,9 @@ import club.joylink.rtss.vo.client.project.sr.SrSectionConfigVO;
|
||||
import club.joylink.rtss.vo.client.project.sr.SrSignalConfigVO;
|
||||
import club.joylink.rtss.vo.client.project.sr.SrSwitchConfigVO;
|
||||
import club.joylink.rtss.vo.client.project.sr.SrTrainConfigVO;
|
||||
import club.joylink.rtss.vo.client.project.thailand.ThailandRunPlanConfigVO;
|
||||
import club.joylink.rtss.vo.client.project.thailand.ThailandSectionConfigVO;
|
||||
import club.joylink.rtss.vo.client.project.thailand.ThailandSignalConfigVO;
|
||||
import club.joylink.rtss.vo.client.project.thailand.ThailandSwitchConfigVO;
|
||||
import club.joylink.rtss.vo.client.project.thailand.ThailandTrainConfigVO;
|
||||
import club.joylink.rtss.vo.client.project.xty.XtyPsdConfigVO;
|
||||
@ -62,6 +64,7 @@ import com.github.pagehelper.Page;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
@ -932,7 +935,7 @@ public class DeviceServiceImpl implements DeviceService {
|
||||
signal.setType(ProjectDeviceType.SIGNAL.name());
|
||||
signal.setCreator(accountVO.getId());
|
||||
signal.setCreateTime(now);
|
||||
SrSignalConfigVO configVO = new SrSignalConfigVO(mapSignalNewVO.getCode(),
|
||||
ThailandSignalConfigVO configVO = new ThailandSignalConfigVO(mapSignalNewVO.getCode(),
|
||||
mapSignalNewVO.getSrCode());
|
||||
signal.setConfig(JsonUtils.writeValueAsString(configVO));
|
||||
list.add(signal);
|
||||
@ -983,100 +986,120 @@ public class DeviceServiceImpl implements DeviceService {
|
||||
train.setConfig(JsonUtils.writeValueAsString(configVO));
|
||||
list.add(train);
|
||||
}
|
||||
//运行计划
|
||||
ProjectDevice runPlan = new ProjectDevice();
|
||||
runPlan.setProjectCode(projectCode);
|
||||
runPlan.setCode("runPlan");
|
||||
runPlan.setType(ProjectDeviceType.SAND_TABLE_RUN_PLAN.name());
|
||||
runPlan.setCreator(accountVO.getId());
|
||||
runPlan.setCreateTime(now);
|
||||
ThailandRunPlanConfigVO configVO = new ThailandRunPlanConfigVO();
|
||||
configVO.setStandTrackList(Arrays.asList("T85", "T158", "T205", "T247", "T206", "T157", "T84"));
|
||||
runPlan.setConfig(JsonUtils.writeValueAsString(configVO));
|
||||
list.add(runPlan);
|
||||
return list;
|
||||
}
|
||||
|
||||
private void thailandFillTime(ThailandSectionConfigVO configVO, MapSectionNewVO section) {
|
||||
Float headDelayTime = null;
|
||||
Float tailDelayTime = null;
|
||||
if (section.isStandTrack()) { //站台轨默认为车尾出清立即停车
|
||||
if (section.isStandTrack()) {
|
||||
headDelayTime = 5f;
|
||||
}
|
||||
switch (section.getCode()) {
|
||||
case "T233": //X302G
|
||||
headDelayTime = 7.3f;
|
||||
case "T1": //X301G
|
||||
headDelayTime = 5f;
|
||||
break;
|
||||
case "T232": //X303G
|
||||
headDelayTime = 6.5f;
|
||||
case "T2": //X302G
|
||||
headDelayTime = 7.9f;
|
||||
break;
|
||||
case "T231": //X304G
|
||||
headDelayTime = 5.5f;
|
||||
case "T3": //X303G
|
||||
headDelayTime = 6.7f;
|
||||
break;
|
||||
case "T178": //4站-3G
|
||||
headDelayTime = 5.2f;
|
||||
case "T4": //X304G
|
||||
headDelayTime = 5.6f;
|
||||
break;
|
||||
case "T177": //4站-IG
|
||||
headDelayTime = 5.4f;
|
||||
break;
|
||||
case "T175": //4站-IIG
|
||||
headDelayTime = 6.6f;
|
||||
break;
|
||||
case "T174": //4站-4G
|
||||
headDelayTime = 6.2f;
|
||||
break;
|
||||
case "T176": //4站-6G
|
||||
headDelayTime = 5.9f;
|
||||
break;
|
||||
case "T179": //4站-5G
|
||||
headDelayTime = 6.5f;
|
||||
break;
|
||||
case "T123": //3站-3G
|
||||
headDelayTime = 5.2f;
|
||||
break;
|
||||
case "T122": //3站-IG
|
||||
case "T5": //X305G
|
||||
headDelayTime = 5.3f;
|
||||
break;
|
||||
case "T121": //3站-IIG
|
||||
headDelayTime = 5.9f;
|
||||
break;
|
||||
case "T120": //3站-4G
|
||||
case "T6": //X306G
|
||||
headDelayTime = 5.5f;
|
||||
break;
|
||||
case "T78": //2站-IG
|
||||
case "T7": //X307G
|
||||
headDelayTime = 5.3f;
|
||||
break;
|
||||
case "T8": //X308G
|
||||
headDelayTime = 5.5f;
|
||||
break;
|
||||
case "T77": //2站-IIG
|
||||
case "T89": //1站6G
|
||||
headDelayTime = 5.9f;
|
||||
break;
|
||||
case "T76": //2站-4G
|
||||
case "T90": //1站4G
|
||||
headDelayTime = 6.4f;
|
||||
break;
|
||||
case "T85": //1站2G
|
||||
headDelayTime = 6.8f;
|
||||
break;
|
||||
case "T84": //1站1G
|
||||
headDelayTime = 5.9f;
|
||||
break;
|
||||
case "T94": //1站3G
|
||||
headDelayTime = 5.2f;
|
||||
break;
|
||||
case "T95": //1站5G
|
||||
headDelayTime = 6.5f;
|
||||
break;
|
||||
case "T160": //2站4G
|
||||
headDelayTime = 5.5f;
|
||||
break;
|
||||
case "T158": //2站2G
|
||||
headDelayTime = 5.2f;
|
||||
break;
|
||||
case "T157": //2站1G
|
||||
headDelayTime = 5.8f;
|
||||
break;
|
||||
case "T159": //2站3G
|
||||
headDelayTime = 5.2f;
|
||||
break;
|
||||
case "T204": //3站4G
|
||||
headDelayTime = 5.7f;
|
||||
break;
|
||||
case "T22": //1站-1G
|
||||
case "T205": //3站2G
|
||||
headDelayTime = 5.6f;
|
||||
break;
|
||||
case "T206": //3站1G
|
||||
headDelayTime = 6f;
|
||||
break;
|
||||
case "T207": //3站3G
|
||||
headDelayTime = 5.3f;
|
||||
break;
|
||||
case "T23": //1站-IIG
|
||||
case "T242": //4站6G
|
||||
headDelayTime = 5.1f;
|
||||
break;
|
||||
case "T27": //1站-5G
|
||||
headDelayTime = 4.9f;
|
||||
case "T243": //3站4G
|
||||
headDelayTime = 5.1f;
|
||||
break;
|
||||
case "T26": //1站-3G
|
||||
case "T244": //3站2G
|
||||
headDelayTime = 5.1f;
|
||||
break;
|
||||
case "T247": //3站1G
|
||||
headDelayTime = 5.5f;
|
||||
break;
|
||||
case "T254": //3站3G
|
||||
headDelayTime = 4.8f;
|
||||
break;
|
||||
case "T24": //1站-4G
|
||||
headDelayTime = 5.1f;
|
||||
case "T255": //3站5G
|
||||
headDelayTime = 4.9f;
|
||||
break;
|
||||
case "T25": //1站-6G
|
||||
headDelayTime = 5.1f;
|
||||
break;
|
||||
case "T145": //QX04
|
||||
case "T142": //QX04
|
||||
headDelayTime = 1.9f;
|
||||
break;
|
||||
case "T146": //QS04
|
||||
headDelayTime = 2.7f;
|
||||
break;
|
||||
case "T104": //QX03
|
||||
case "T141": //其它QX/QS区段
|
||||
case "T183":
|
||||
case "T184":
|
||||
case "T223":
|
||||
case "T224":
|
||||
tailDelayTime = 0f;
|
||||
break;
|
||||
case "T105": //QS03
|
||||
tailDelayTime = 0f;
|
||||
break;
|
||||
case "T62": //QX02
|
||||
tailDelayTime = 0f;
|
||||
break;
|
||||
case "T63": //QS02
|
||||
tailDelayTime = 0f;
|
||||
break;
|
||||
}
|
||||
configVO.setHeadDelayTime(headDelayTime);
|
||||
configVO.setTailDelayTime(tailDelayTime);
|
||||
|
@ -3,12 +3,11 @@ package club.joylink.rtss.simulation.cbtc.data.support;
|
||||
import club.joylink.rtss.simulation.cbtc.constant.SimulationConstants;
|
||||
import club.joylink.rtss.simulation.cbtc.data.CalculateService;
|
||||
import club.joylink.rtss.simulation.cbtc.data.map.Section;
|
||||
import lombok.Getter;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Objects;
|
||||
import lombok.Getter;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* 地图位置坐标
|
||||
@ -16,117 +15,131 @@ import java.util.Objects;
|
||||
@Getter
|
||||
public class SectionPosition {
|
||||
|
||||
private Section section;
|
||||
private Section section;
|
||||
|
||||
private float offset;
|
||||
private float offset;
|
||||
|
||||
public SectionPosition(Section section, float offset) {
|
||||
this.section = section;
|
||||
this.offset = offset;
|
||||
public SectionPosition(Section section, float offset) {
|
||||
this.section = section;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
public boolean isSameSection(Section section) {
|
||||
return this.section.getCode().equals(section.getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前位置是否在other前面。更right的位置视为更前。
|
||||
*
|
||||
* @param other
|
||||
* @param right
|
||||
* @return
|
||||
*/
|
||||
public boolean isAheadOf(SectionPosition other, boolean right) {
|
||||
return isAheadOf(other.getSection(), other.getOffset(), right);
|
||||
}
|
||||
|
||||
private boolean isAheadOf(Section section, float offset, boolean right) {
|
||||
if (Objects.equals(this.getSection(), section)) {
|
||||
// 同一根区段
|
||||
if (right && this.getOffset() > offset) {
|
||||
// 右向,此偏移量大于另一个偏移量
|
||||
return true;
|
||||
} else if (!right && this.getOffset() < offset) {
|
||||
// 左向,此偏移量小于另一个偏移量
|
||||
return true;
|
||||
}
|
||||
} else { // 不是同一区段,查询另一区段在指定方向上是否能找到此位置区段,如果找到,则在前
|
||||
if (CalculateService.isTargetSectionOnDirectionExist(section, right,
|
||||
this.getSection())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isSameSection(Section section) {
|
||||
return this.section.getCode().equals(section.getCode());
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{" +
|
||||
String.format("%s(%s)", section.getName(), section.getCode()) +
|
||||
String.format(", %s", offset) +
|
||||
'}';
|
||||
}
|
||||
|
||||
public boolean isAheadOf(SectionPosition other, boolean right) {
|
||||
return isAheadOf(other.getSection(), other.getOffset(), right);
|
||||
}
|
||||
|
||||
public boolean isAheadOf(Section section, float offset, boolean right) {
|
||||
if (Objects.equals(this.getSection(), section)) {
|
||||
// 同一根区段
|
||||
if (right && this.getOffset() > offset) {
|
||||
// 右向,此偏移量大于另一个偏移量
|
||||
return true;
|
||||
} else if (!right && this.getOffset() < offset) {
|
||||
// 左向,此偏移量小于另一个偏移量
|
||||
return true;
|
||||
}
|
||||
} else { // 不是同一区段,查询另一区段在指定方向上是否能找到此位置区段,如果找到,则在前
|
||||
if (CalculateService.isTargetSectionOnDirectionExist(section, right, this.getSection())) {
|
||||
return true;
|
||||
}
|
||||
public Section getLogicSection() {
|
||||
if (!CollectionUtils.isEmpty(section.getLogicList())) {
|
||||
for (Section logic : section.getLogicList()) {
|
||||
if (this.offset > logic.getMinOffset() && this.offset <= logic.getMaxOffset()) {
|
||||
return logic;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return this.section;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{" +
|
||||
String.format("%s(%s)", section.getName(), section.getCode()) +
|
||||
String.format(", %s", offset) +
|
||||
'}';
|
||||
}
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return section.hashCode() + Float.hashCode(offset);
|
||||
}
|
||||
|
||||
public Section getLogicSection() {
|
||||
if (!CollectionUtils.isEmpty(section.getLogicList())) {
|
||||
for (Section logic : section.getLogicList()) {
|
||||
if (this.offset > logic.getMinOffset() && this.offset <= logic.getMaxOffset()) {
|
||||
return logic;
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.section;
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
SectionPosition sp = (SectionPosition) obj;
|
||||
return Objects.equals(this.getSection(), sp.getSection()) && offset == sp.getOffset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return section.hashCode() + Float.hashCode(offset);
|
||||
}
|
||||
public float getPercent() {
|
||||
return BigDecimal.valueOf(this.offset / this.getSection().getLen())
|
||||
.setScale(4, RoundingMode.HALF_UP).floatValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (obj == null || getClass() != obj.getClass()) return false;
|
||||
SectionPosition sp = (SectionPosition) obj;
|
||||
return Objects.equals(this.getSection(), sp.getSection()) && offset == sp.getOffset();
|
||||
}
|
||||
public boolean isAvailable() {
|
||||
return !(this.offset < 0 || this.offset > this.section.getLen());
|
||||
}
|
||||
|
||||
public float getPercent() {
|
||||
return BigDecimal.valueOf(this.offset / this.getSection().getLen())
|
||||
.setScale(4, RoundingMode.HALF_UP).floatValue();
|
||||
public boolean isBetween(SectionPosition one, SectionPosition two) {
|
||||
if (one.equals(this) || two.equals(this)) {
|
||||
return true;
|
||||
}
|
||||
if (one.isAheadOf(this, true)) {
|
||||
return this.isAheadOf(two, true);
|
||||
} else if (this.isAheadOf(one, true)) {
|
||||
return two.isAheadOf(this, true);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isAvailable() {
|
||||
return !(this.offset < 0 || this.offset > this.section.getLen());
|
||||
public SectionPosition convert2PhysicalSectionPosition() {
|
||||
Section section = this.getSection();
|
||||
if (section.isPhysical()) {
|
||||
return this;
|
||||
} else {
|
||||
Section parent = section.getParent();
|
||||
if (parent != null) {
|
||||
return new SectionPosition(parent, section.getMinOffset() + this.getOffset());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isBetween(SectionPosition one, SectionPosition two) {
|
||||
if (one.equals(this) || two.equals(this))
|
||||
return true;
|
||||
if (one.isAheadOf(this, true)) {
|
||||
return this.isAheadOf(two, true);
|
||||
} else if (this.isAheadOf(one, true)) {
|
||||
return two.isAheadOf(this, true);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public SectionPosition convert2PhysicalSectionPosition() {
|
||||
Section section = this.getSection();
|
||||
if (section.isPhysical()) {
|
||||
return this;
|
||||
} else {
|
||||
Section parent = section.getParent();
|
||||
if (parent != null) {
|
||||
return new SectionPosition(parent, section.getMinOffset() + this.getOffset());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 该位置位于对应区段的停车范围内
|
||||
*/
|
||||
public boolean isWithinParkingRange(boolean right) {
|
||||
SectionPosition targetPosition = new SectionPosition(this.section, this.section.getStopPointByDirection(right));
|
||||
SectionPosition max = CalculateService.calculateNextPositionByStartAndLen(targetPosition,
|
||||
right, SimulationConstants.PARK_POINT_MAX_OFFSET, false);
|
||||
SectionPosition min = CalculateService.calculateNextPositionByStartAndLen(targetPosition,
|
||||
!right, SimulationConstants.PARK_POINT_MAX_OFFSET, false);
|
||||
return this.isAheadOf(min, right) && max.isAheadOf(this, right);
|
||||
}
|
||||
/**
|
||||
* 该位置位于对应区段的停车范围内
|
||||
*/
|
||||
public boolean isWithinParkingRange(boolean right) {
|
||||
SectionPosition targetPosition = new SectionPosition(this.section,
|
||||
this.section.getStopPointByDirection(right));
|
||||
SectionPosition max = CalculateService.calculateNextPositionByStartAndLen(targetPosition,
|
||||
right, SimulationConstants.PARK_POINT_MAX_OFFSET, false);
|
||||
SectionPosition min = CalculateService.calculateNextPositionByStartAndLen(targetPosition,
|
||||
!right, SimulationConstants.PARK_POINT_MAX_OFFSET, false);
|
||||
return this.isAheadOf(min, right) && max.isAheadOf(this, right);
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +1,43 @@
|
||||
package club.joylink.rtss.simulation.cbtc.device.real.udp;
|
||||
|
||||
import club.joylink.rtss.constants.ProjectCode;
|
||||
import club.joylink.rtss.constants.ProjectDeviceType;
|
||||
import club.joylink.rtss.dao.MapDataDAO;
|
||||
import club.joylink.rtss.entity.MapDataExample;
|
||||
import club.joylink.rtss.entity.MapDataWithBLOBs;
|
||||
import club.joylink.rtss.simulation.cbtc.GroupSimulationService;
|
||||
import club.joylink.rtss.simulation.cbtc.Simulation;
|
||||
import club.joylink.rtss.simulation.cbtc.data.map.Section;
|
||||
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.device.RealDeviceConfig;
|
||||
import club.joylink.rtss.simulation.cbtc.device.real.udp.sr.service.SrTrainServiceImpl;
|
||||
import club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.config.ThailandRunPlanConfig;
|
||||
import club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.service.ThailandRunPlanServiceImpl;
|
||||
import club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.service.ThailandTrainServiceImpl;
|
||||
import club.joylink.rtss.util.JsonUtils;
|
||||
import club.joylink.rtss.vo.map.MapLogicDataNewVO;
|
||||
import club.joylink.rtss.vo.client.project.thailand.ThailandRunPlanConfigVO;
|
||||
import club.joylink.rtss.vo.client.project.thailand.ThailandRunPlanConfigVO.Param;
|
||||
import club.joylink.rtss.vo.map.MapGraphDataNewVO;
|
||||
import club.joylink.rtss.vo.map.graph.MapSectionNewVO;
|
||||
import club.joylink.rtss.vo.map.graph.MapSignalNewVO;
|
||||
import club.joylink.rtss.vo.map.graph.MapSwitchVO;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 沙盘项目接口
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/sandTable")
|
||||
public class SandTableTrainController {
|
||||
@ -25,6 +47,8 @@ public class SandTableTrainController {
|
||||
@Autowired
|
||||
private ThailandTrainServiceImpl thailandTrainService;
|
||||
@Autowired
|
||||
private ThailandRunPlanServiceImpl thailandRunPlanService;
|
||||
@Autowired
|
||||
private SrTrainServiceImpl srTrainService;
|
||||
|
||||
@PutMapping("/{simulationId}/control")
|
||||
@ -42,29 +66,89 @@ public class SandTableTrainController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 按计划运行
|
||||
*/
|
||||
@PutMapping("/{simulationId}/runAsPlan")
|
||||
public void runAsPlan(@PathVariable String simulationId,
|
||||
@RequestBody @Validated List<Param> paramList) {
|
||||
Simulation simulation = groupSimulationService.getSimulationByGroup(simulationId);
|
||||
switch (simulation.getProject()) {
|
||||
case ProjectCode.THAILAND_SANDBOX:
|
||||
thailandRunPlanService.runAsPlan(simulation, paramList);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取运行计划详情
|
||||
*/
|
||||
@GetMapping("/{simulationId}/runPlanDetail")
|
||||
public List<ThailandRunPlanConfigVO.Detail> getRunPlanDetail(@PathVariable String simulationId) {
|
||||
Simulation simulation = groupSimulationService.getSimulationByGroup(simulationId);
|
||||
List<RealDeviceConfig> runPlanConfigList = simulation.getRealDeviceByType(
|
||||
ProjectDeviceType.SAND_TABLE_RUN_PLAN);
|
||||
if (CollectionUtils.isEmpty(runPlanConfigList)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
ThailandRunPlanConfig config = (ThailandRunPlanConfig) runPlanConfigList.get(0);
|
||||
List<ThailandRunPlanConfigVO.Detail> list = new ArrayList<>();
|
||||
Integer parkingDuration = config.getParkingDuration();
|
||||
config.getDetailMap().forEach((train, detailList) -> {
|
||||
String groupNumber = train.getGroupNumber();
|
||||
List<ThailandRunPlanConfigVO.Detail> detailVOList = detailList.stream().map(detail -> {
|
||||
String stationName = detail.getTrack().getStation().getName();
|
||||
String trackName = detail.getTrack().getName();
|
||||
boolean finished = detail.isFinished();
|
||||
return new ThailandRunPlanConfigVO.Detail(groupNumber, stationName, trackName,
|
||||
parkingDuration, finished);
|
||||
}).collect(Collectors.toList());
|
||||
detailVOList.get(0).setParkingDuration(0);
|
||||
detailVOList.get(detailVOList.size() - 1).setParkingDuration(0);
|
||||
list.addAll(detailVOList);
|
||||
});
|
||||
return list;
|
||||
}
|
||||
|
||||
@PutMapping("/{simulationId}/occupy")
|
||||
public void setOccupy(@PathVariable String simulationId, @RequestParam List<String> sectionCodes,
|
||||
boolean occupy) {
|
||||
Simulation simulation = groupSimulationService.getSimulationByGroup(simulationId);
|
||||
for (String sectionCode : sectionCodes) {
|
||||
Section section = simulation.getRepository().getByCode(sectionCode, Section.class);
|
||||
section.findAxle().setOccupy(occupy);
|
||||
}
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private MapDataDAO mapDataDAO;
|
||||
|
||||
@PutMapping("/handle")
|
||||
public void handle() {
|
||||
MapDataExample example = new MapDataExample();
|
||||
example.createCriteria().andMapIdEqualTo(183L);
|
||||
example.setOrderByClause("id desc");
|
||||
example.setLimit(1);
|
||||
MapDataWithBLOBs data = mapDataDAO.selectByExampleWithBLOBs(example).get(0);
|
||||
MapLogicDataNewVO logicDataNewVO = JsonUtils.read(data.getLogicData(), MapLogicDataNewVO.class);
|
||||
logicDataNewVO.getRouteList().stream()
|
||||
.filter(route -> route.getStartSignalCode().equals("X542") || route.getStartSignalCode()
|
||||
.equals("X11357")
|
||||
|| route.getStartSignalCode().equals("X47820") || route.getStartSignalCode()
|
||||
.equals("X4371")
|
||||
|| route.getStartSignalCode().equals("X21134") || route.getStartSignalCode()
|
||||
.equals("X99402")
|
||||
|| route.getStartSignalCode().equals("X2670") || route.getStartSignalCode()
|
||||
.equals("X49087"))
|
||||
.forEach(route -> {
|
||||
route.setSignalAspect(3);
|
||||
});
|
||||
data.setLogicData(JsonUtils.writeValueAsString(logicDataNewVO));
|
||||
mapDataDAO.updateByPrimaryKeyWithBLOBs(data);
|
||||
MapGraphDataNewVO graphDataNewVO = JsonUtils.read(data.getGraphData(), MapGraphDataNewVO.class);
|
||||
|
||||
String errSections = graphDataNewVO.getSectionList().stream()
|
||||
.filter(section -> section.getType().equals("04"))
|
||||
.filter(section -> !StringUtils.hasText(section.getSrCode()))
|
||||
.map(MapSectionNewVO::getCode)
|
||||
.collect(Collectors.joining(","));
|
||||
String errSignals = graphDataNewVO.getSignalList().stream()
|
||||
.filter(signal -> !StringUtils.hasText(signal.getSrCode()))
|
||||
.map(MapSignalNewVO::getCode)
|
||||
.collect(Collectors.joining(","));
|
||||
String errSwitches = graphDataNewVO.getSwitchList().stream()
|
||||
.filter(aSwitch -> !StringUtils.hasText(aSwitch.getSrCode()) || aSwitch.getThroat() == null)
|
||||
.map(MapSwitchVO::getCode)
|
||||
.collect(Collectors.joining(","));
|
||||
System.out.println("异常区段:" + errSections);
|
||||
System.out.println("异常信号机:" + errSignals);
|
||||
System.out.println("异常区段:" + errSwitches);
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,6 @@ import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.DatagramPacket;
|
||||
import io.netty.channel.socket.nio.NioDatagramChannel;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -60,16 +59,15 @@ public class UDPClient implements ApplicationRunner {
|
||||
public void write(InetSocketAddress addr, byte[] msg) {
|
||||
if (msg != null) {
|
||||
msgQueue.add(new Msg(addr, msg));
|
||||
System.out.println(LocalDateTime.now());
|
||||
}
|
||||
}
|
||||
|
||||
@Scheduled(fixedRate = 10)
|
||||
public void send() {
|
||||
Msg msg = msgQueue.poll();
|
||||
if (msg == null) {
|
||||
return;
|
||||
}
|
||||
if (msg == null) {
|
||||
return;
|
||||
}
|
||||
InetSocketAddress addr = msg.getAddr();
|
||||
byte[] data = msg.getData();
|
||||
if (channel != null && channel.isWritable() && addr != null && data != null) {
|
||||
|
@ -72,7 +72,7 @@ public class UDPRealDeviceThread {
|
||||
for (RealDeviceConfig config : realDeviceList) {
|
||||
for (UDPRealDeviceService service : serviceList) {
|
||||
if (service.isMatch(udpLowConfig) && service.isMatch(config)
|
||||
&& config.getMapElement() != null) {
|
||||
/*&& config.getMapElement() != null*/) {
|
||||
service.run(simulation, udpLowConfig, config);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,90 @@
|
||||
package club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.config;
|
||||
|
||||
import club.joylink.rtss.simulation.cbtc.data.map.Route;
|
||||
import club.joylink.rtss.simulation.cbtc.data.map.Section;
|
||||
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityTrain;
|
||||
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.device.RealDeviceConfig;
|
||||
import club.joylink.rtss.util.JsonUtils;
|
||||
import club.joylink.rtss.vo.client.project.ProjectDeviceVO;
|
||||
import club.joylink.rtss.vo.client.project.thailand.ThailandRunPlanConfigVO;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class ThailandRunPlanConfig extends RealDeviceConfig {
|
||||
|
||||
private ThailandRunPlanConfigVO configVO;
|
||||
|
||||
/**
|
||||
* 设置计划后生成的实际计划
|
||||
*/
|
||||
private LinkedHashMap<VirtualRealityTrain, List<Detail>> detailMap = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* key - 始终区段code连接 value - 始终区段间的进路
|
||||
*/
|
||||
private Map<String, Route[]> routeMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 表示是否按计划运行中
|
||||
*/
|
||||
private boolean running;
|
||||
|
||||
public ThailandRunPlanConfig(ProjectDeviceVO projectDevice) {
|
||||
super(projectDevice);
|
||||
if (Objects.nonNull(projectDevice.getConfig())) {
|
||||
this.configVO = JsonUtils.read(projectDevice.getConfig(), ThailandRunPlanConfigVO.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String findDeviceCode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getParkingDuration() {
|
||||
return configVO.getParkingDuration();
|
||||
}
|
||||
|
||||
public Integer getDepartureDuration() {
|
||||
return configVO.getDepartureDuration();
|
||||
}
|
||||
|
||||
public void addRoutes(String fromSectionCode, String toSectionCode, Route[] routes) {
|
||||
routeMap.put(fromSectionCode + toSectionCode, routes);
|
||||
}
|
||||
|
||||
public Route[] getRoutes(String fromSectionCode, String toSectionCode) {
|
||||
return routeMap.get(fromSectionCode + toSectionCode);
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Detail {
|
||||
|
||||
private VirtualRealityTrain train;
|
||||
private Section track;
|
||||
private LocalDateTime departureTime;
|
||||
/**
|
||||
* 计划是否完成
|
||||
*/
|
||||
private boolean finished;
|
||||
/**
|
||||
* 进路是否已经办理
|
||||
*/
|
||||
private boolean routeSet;
|
||||
|
||||
public Detail(VirtualRealityTrain train, Section track, LocalDateTime departureTime) {
|
||||
this.train = train;
|
||||
this.track = track;
|
||||
this.departureTime = departureTime;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,293 @@
|
||||
package club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.service;
|
||||
|
||||
import static club.joylink.rtss.constants.ProjectDeviceType.SAND_TABLE_RUN_PLAN;
|
||||
|
||||
import club.joylink.rtss.constants.ProjectDeviceType;
|
||||
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
|
||||
import club.joylink.rtss.simulation.cbtc.ATS.service.AtsTrainLoadService;
|
||||
import club.joylink.rtss.simulation.cbtc.CI.CiApiService;
|
||||
import club.joylink.rtss.simulation.cbtc.Simulation;
|
||||
import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository;
|
||||
import club.joylink.rtss.simulation.cbtc.data.map.Route;
|
||||
import club.joylink.rtss.simulation.cbtc.data.map.Section;
|
||||
import club.joylink.rtss.simulation.cbtc.data.map.Signal;
|
||||
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityTrain;
|
||||
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.device.RealDeviceConfig;
|
||||
import club.joylink.rtss.simulation.cbtc.device.real.udp.UDPLowConfig;
|
||||
import club.joylink.rtss.simulation.cbtc.device.real.udp.UDPRealDeviceService;
|
||||
import club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.config.ThailandRunPlanConfig;
|
||||
import club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.config.ThailandRunPlanConfig.Detail;
|
||||
import club.joylink.rtss.simulation.cbtc.onboard.ATP.ATPService;
|
||||
import club.joylink.rtss.vo.client.project.thailand.ThailandRunPlanConfigVO.Param;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class ThailandRunPlanServiceImpl implements UDPRealDeviceService {
|
||||
|
||||
private AtsTrainLoadService atsTrainLoadService;
|
||||
private CiApiService ciApiService;
|
||||
private ATPService atpService;
|
||||
|
||||
public ThailandRunPlanServiceImpl(AtsTrainLoadService atsTrainLoadService,
|
||||
CiApiService ciApiService, ATPService atpService) {
|
||||
this.atsTrainLoadService = atsTrainLoadService;
|
||||
this.ciApiService = ciApiService;
|
||||
this.atpService = atpService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMatch(UDPLowConfig udpLowConfig) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMatch(RealDeviceConfig realDevice) {
|
||||
return SAND_TABLE_RUN_PLAN.equals(realDevice.getDeviceType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(Simulation simulation, UDPLowConfig udpLowConfig, RealDeviceConfig realDevice) {
|
||||
ThailandRunPlanConfig config = (ThailandRunPlanConfig) realDevice;
|
||||
if (!config.isRunning()) {
|
||||
return;
|
||||
}
|
||||
SimulationDataRepository repository = simulation.getRepository();
|
||||
LocalDateTime systemTime = simulation.getSystemTime();
|
||||
List<Detail> previousTrainPlanDetails = new ArrayList<>();
|
||||
boolean planCompleted = true;
|
||||
for (Entry<VirtualRealityTrain, List<Detail>> entry : config.getDetailMap().entrySet()) {
|
||||
VirtualRealityTrain train = entry.getKey();
|
||||
if (!repository.isVrTrainOnline(train.getGroupNumber())) { //列车上线
|
||||
Section firstTrack = entry.getValue().get(0).getTrack();
|
||||
Section secondTrack = entry.getValue().get(1).getTrack();
|
||||
Route[] routes = config.getRoutes(firstTrack.getCode(), secondTrack.getCode());
|
||||
atsTrainLoadService.loadSpareTrain(simulation, train.getGroupNumber(),
|
||||
firstTrack.getCode(), routes[0].isRight());
|
||||
}
|
||||
Section lastArriveTrack = null;
|
||||
for (Detail detail : entry.getValue()) {
|
||||
if (detail.isFinished()) {
|
||||
lastArriveTrack = detail.getTrack();
|
||||
continue;
|
||||
}
|
||||
Section track = detail.getTrack();
|
||||
if (/*train.isStop() && */Objects.equals(train.getHeadPosition().getSection(), track)) {
|
||||
lastArriveTrack = detail.getTrack();
|
||||
detail.setFinished(true);
|
||||
continue;
|
||||
}
|
||||
planCompleted = false;
|
||||
if (track.isOccupied()) {
|
||||
break;
|
||||
}
|
||||
if (systemTime.isBefore(detail.getDepartureTime())) {
|
||||
break;
|
||||
}
|
||||
Route[] routes = config.getRoutes(lastArriveTrack.getCode(), track.getCode());
|
||||
if (routes == null) {
|
||||
log.error("缺少[{}-{}]的进路路径", lastArriveTrack.getCode(), track.getCode());
|
||||
break;
|
||||
}
|
||||
if (detail.isRouteSet()) {
|
||||
if (routes[0].isRight() != train.isRight()) {
|
||||
atpService.turnDirectionImmediately(train);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (previousTrainPlanDetails.stream()
|
||||
.filter(pd -> pd.getTrack().equals(track))
|
||||
.anyMatch(pd -> !pd.isFinished())) { //前一辆车到该股道的计划尚未完成
|
||||
break;
|
||||
}
|
||||
|
||||
boolean routeLocked = true;
|
||||
for (int i = routes.length - 1; i >= 0; i--) {
|
||||
Route route = routes[i];
|
||||
if (!route.isLock()) {
|
||||
routeLocked = false;
|
||||
ciApiService.settingRoute(simulation, route.getCode());
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (routeLocked) {
|
||||
detail.setRouteSet(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
previousTrainPlanDetails = entry.getValue();
|
||||
}
|
||||
if (planCompleted) {
|
||||
planRunning(simulation, config, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Simulation simulation, UDPLowConfig udpLowConfig, RealDeviceConfig realDevice) {
|
||||
ThailandRunPlanConfig config = (ThailandRunPlanConfig) realDevice;
|
||||
planRunning(simulation, config, false);
|
||||
config.getDetailMap().clear();
|
||||
|
||||
SimulationDataRepository repository = simulation.getRepository();
|
||||
repository.getStandList()
|
||||
.forEach(stand -> {
|
||||
if (stand.getSection().isParkingTrack()) {
|
||||
stand.setParkingTime(0);
|
||||
} else {
|
||||
stand.setParkingTime(config.getParkingDuration());
|
||||
}
|
||||
stand.setParkingAlwaysValid(true);
|
||||
});
|
||||
|
||||
Map<String, Route[]> routeMap = config.getRouteMap();
|
||||
if (CollectionUtils.isEmpty(routeMap)) {
|
||||
List<Section> trackList = config.getConfigVO().getStandTrackList().stream()
|
||||
.map(code -> repository.getByCode(code, Section.class))
|
||||
.collect(Collectors.toList());
|
||||
List<Section> potSections = repository.getSectionList().stream()
|
||||
.filter(Section::isParkingTrack)
|
||||
.collect(Collectors.toList()); //筛选出的都是停车场站台轨
|
||||
boolean right = true;
|
||||
for (Section potSection : potSections) {
|
||||
right = fillRoutes(config, potSection, trackList.get(0), right);
|
||||
}
|
||||
for (int i = 0, trackListSize = trackList.size(); i < trackListSize - 1; i++) {
|
||||
right = fillRoutes(config, trackList.get(i), trackList.get(i + 1), right);
|
||||
}
|
||||
for (Section potSection : potSections) {
|
||||
right = fillRoutes(config, trackList.get(trackList.size() - 1), potSection, right);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Simulation simulation, ByteBuf msg) {
|
||||
|
||||
}
|
||||
|
||||
private boolean fillRoutes(ThailandRunPlanConfig config, Section from, Section to,
|
||||
boolean right) {
|
||||
Route[] routes = findRoutes(from, to, right);
|
||||
if (routes != null) {
|
||||
config.addRoutes(from.getCode(), to.getCode(), routes);
|
||||
return right;
|
||||
}
|
||||
routes = findRoutes(from, to, !right);
|
||||
if (routes == null) {
|
||||
log.error("[{}-{}]的进路找不到", from.debugStr(), to.debugStr());
|
||||
}
|
||||
config.addRoutes(from.getCode(), to.getCode(), routes);
|
||||
return !right;
|
||||
}
|
||||
|
||||
private Route[] findRoutes(Section from, Section to, boolean right) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Signal departureSignal = from.getSignalOf(right);
|
||||
if (departureSignal == null) {
|
||||
return null;
|
||||
}
|
||||
List<Route> departureRoutes = departureSignal.getRouteList();
|
||||
if (CollectionUtils.isEmpty(departureRoutes)) {
|
||||
return null;
|
||||
}
|
||||
Route departureRoute = departureRoutes.stream()
|
||||
.filter(Route::isTrainRoute)
|
||||
.filter(route -> {
|
||||
Signal destination = route.getDestination();
|
||||
return destination.isDepartureSignal();
|
||||
}).findFirst().orElse(null);
|
||||
if (departureRoute == null) {
|
||||
return null;
|
||||
}
|
||||
Section interStationSection = departureRoute.getDestination().getSection();
|
||||
Signal receiveSignal = interStationSection.getSignalOf(right);
|
||||
if (receiveSignal == null) {
|
||||
return null;
|
||||
}
|
||||
List<Route> receiveRoutes = receiveSignal.getRouteList();
|
||||
if (CollectionUtils.isEmpty(receiveRoutes)) {
|
||||
return null;
|
||||
}
|
||||
Optional<Route> receiveRouteOptional = receiveRoutes.stream()
|
||||
.filter(Route::isTrainRoute)
|
||||
.filter(route -> route.getLastRouteSection().equals(to))
|
||||
.findFirst();
|
||||
return receiveRouteOptional.map(route -> new Route[]{departureRoute, route}).orElse(null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public void runAsPlan(Simulation simulation, List<Param> paramList) {
|
||||
SimulationDataRepository repository = simulation.getRepository();
|
||||
List<String> errMsgList = new ArrayList<>();
|
||||
Set<String> set = new HashSet<>();
|
||||
for (Param param : paramList) {
|
||||
Section section = repository.getByCode(param.getTrackCode(), Section.class);
|
||||
if (!section.isOccupied()) {
|
||||
errMsgList.add(String.format("The track named [%s] is unoccupied", section.getName()));
|
||||
}
|
||||
VirtualRealityTrain train = repository.queryOnlineTrainBy(param.getGroupNumber());
|
||||
if (train != null && !train.getHeadPosition().getSection().equals(section)) {
|
||||
errMsgList.add(String.format(
|
||||
"The train with number [%s] is already in use and is not on the selected section.",
|
||||
param.getGroupNumber()));
|
||||
}
|
||||
if (!set.add(param.getGroupNumber())) {
|
||||
errMsgList.add(String.format("[%s] train number is duplicated", param.getGroupNumber()));
|
||||
}
|
||||
if (!set.add(param.getTrackCode())) {
|
||||
errMsgList.add(String.format("[%s] section is duplicated", section.getName()));
|
||||
}
|
||||
}
|
||||
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertCollectionEmpty(errMsgList,
|
||||
String.join("\n", errMsgList));
|
||||
List<RealDeviceConfig> runPlanList = simulation.getRealDeviceByType(
|
||||
ProjectDeviceType.SAND_TABLE_RUN_PLAN);
|
||||
BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertCollectionNotEmpty(runPlanList,
|
||||
"Configuration is missing, unable to set the running plan");
|
||||
|
||||
ThailandRunPlanConfig runPlanConfig = (ThailandRunPlanConfig) runPlanList.get(0);
|
||||
List<Section> standTrackList = runPlanConfig.getConfigVO().getStandTrackList().stream()
|
||||
.map(code -> repository.getByCode(code, Section.class))
|
||||
.collect(Collectors.toList());
|
||||
LocalDateTime now = simulation.getSystemTime();
|
||||
Integer departureDuration = runPlanConfig.getDepartureDuration();
|
||||
for (int i = 0, paramListSize = paramList.size(); i < paramListSize; i++) {
|
||||
Param param = paramList.get(i);
|
||||
VirtualRealityTrain train = repository.getVRByCode(param.getGroupNumber(),
|
||||
VirtualRealityTrain.class);
|
||||
Section section = repository.getByCode(param.getTrackCode(), Section.class);
|
||||
LocalDateTime departureTime =
|
||||
departureDuration == null ? now : now.plusSeconds(departureDuration * i);
|
||||
|
||||
List<Detail> detailList = new ArrayList<>();
|
||||
detailList.add(new Detail(train, section, departureTime));
|
||||
standTrackList.forEach(track -> {
|
||||
Detail detail = new Detail(train, track, departureTime);
|
||||
detailList.add(detail);
|
||||
});
|
||||
detailList.add(new Detail(train, section, departureTime));
|
||||
runPlanConfig.getDetailMap().put(train, detailList);
|
||||
}
|
||||
planRunning(simulation, runPlanConfig, true);
|
||||
}
|
||||
|
||||
private void planRunning(Simulation simulation, ThailandRunPlanConfig config, boolean run) {
|
||||
config.setRunning(run);
|
||||
simulation.getRepository().getStationList().forEach(station -> station.setPlanControl(run));
|
||||
}
|
||||
}
|
@ -4,12 +4,15 @@ import club.joylink.rtss.constants.ProjectCode;
|
||||
import club.joylink.rtss.constants.ProjectDeviceType;
|
||||
import club.joylink.rtss.simulation.cbtc.Simulation;
|
||||
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealitySectionAxleCounter;
|
||||
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityTrain;
|
||||
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.device.RealDeviceConfig;
|
||||
import club.joylink.rtss.simulation.cbtc.device.real.udp.UDPClientConfig;
|
||||
import club.joylink.rtss.simulation.cbtc.device.real.udp.UDPLowConfig;
|
||||
import club.joylink.rtss.simulation.cbtc.device.real.udp.UDPRealDeviceService;
|
||||
import club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.config.ThailandSectionConfig;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
@ -20,21 +23,41 @@ import org.springframework.stereotype.Service;
|
||||
@Service
|
||||
public class ThailandSectionServiceImpl implements UDPRealDeviceService {
|
||||
|
||||
private Map<VirtualRealityTrain, LocalDateTime> map = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public boolean isMatch(RealDeviceConfig realDevice) {
|
||||
return realDevice instanceof UDPClientConfig && ProjectCode.THAILAND_SANDBOX
|
||||
.equals(realDevice.getProject());
|
||||
return (realDevice instanceof UDPClientConfig || realDevice instanceof ThailandSectionConfig)
|
||||
&& ProjectCode.THAILAND_SANDBOX.equals(realDevice.getProject());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(Simulation simulation, UDPLowConfig udpLowConfig, RealDeviceConfig realDevice) {
|
||||
|
||||
//本地测试模拟计轴占用
|
||||
// List<VirtualRealityTrain> trainList = simulation.getRepository().getOnlineTrainList();
|
||||
// LocalDateTime now = LocalDateTime.now();
|
||||
// for (VirtualRealityTrain train : trainList) {
|
||||
// LocalDateTime time = map.computeIfAbsent(train, K -> now.plusSeconds(7));
|
||||
// Section section = train.getHeadPosition().getSection();
|
||||
// VirtualRealitySectionAxleCounter currentAxle = section.findAxle();
|
||||
// if (!train.isStop() && !now.isBefore(time)) {
|
||||
// Section nextSection = section.getNextRunningSectionOf(train.isRight());
|
||||
// if (nextSection == null) {
|
||||
// continue;
|
||||
// }
|
||||
// VirtualRealitySectionAxleCounter nextAxle = nextSection.findAxle();
|
||||
// if (nextAxle != currentAxle) {
|
||||
// nextAxle.occupied(train.isRight());
|
||||
// currentAxle.setOccupy(false);
|
||||
// }
|
||||
// map.put(train, time.plusSeconds(7));
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Simulation simulation, UDPLowConfig udpLowConfig, RealDeviceConfig realDevice) {
|
||||
//沙盘不需要停太长时间
|
||||
simulation.getRepository().getStandList().forEach(stand -> stand.setParkingTime(15));
|
||||
map.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -87,6 +87,23 @@ public class ThailandTrainServiceImpl implements UDPRealDeviceService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Simulation simulation, UDPLowConfig udpLowConfig, RealDeviceConfig realDevice) {
|
||||
ThailandTrainConfig config = (ThailandTrainConfig) realDevice;
|
||||
//控制vr设备
|
||||
VirtualRealityTrain train = (VirtualRealityTrain) config.getMapElement();
|
||||
//控制沙盘设备
|
||||
byte[] data = buildData(train, config);
|
||||
udpClient.write(udpLowConfig.getAddr(), data);
|
||||
//清除状态
|
||||
config.updateHeadSection(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Simulation simulation, ByteBuf msg) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新列车位置。
|
||||
* <p>
|
||||
@ -103,16 +120,22 @@ public class ThailandTrainServiceImpl implements UDPRealDeviceService {
|
||||
ThailandSectionConfig sectionConfig = (ThailandSectionConfig) headSection.findAxle()
|
||||
.getRealDevice(); //车头区段的配置
|
||||
if (nextSection != null) {
|
||||
VirtualRealitySectionAxleCounter nextAxle = nextSection.findAxle();
|
||||
if (nextAxle.isOccupy()) {
|
||||
train.setHeadPosition(
|
||||
new SectionPosition(nextSection, right ? 0 : nextSection.getMaxOffset()));
|
||||
config.setTimeOfArriveStopPoint(null);
|
||||
sectionConfig = (ThailandSectionConfig) nextAxle.getRealDevice();
|
||||
//更新变量
|
||||
previousSection = headSection;
|
||||
headSection = train.getHeadPosition().getSection();
|
||||
nextSection = null;
|
||||
boolean notSwitchTrack = !nextSection.isSwitchTrack();
|
||||
boolean isSwitchRelSections =
|
||||
nextSection.isSwitchTrack() && nextSection.getRelSwitch().getSectionsByPosition()
|
||||
.contains(nextSection);
|
||||
if (notSwitchTrack || isSwitchRelSections) {
|
||||
VirtualRealitySectionAxleCounter nextAxle = nextSection.findAxle();
|
||||
if (nextAxle.isOccupy()) {
|
||||
train.setHeadPosition(
|
||||
new SectionPosition(nextSection, right ? 0 : nextSection.getMaxOffset()));
|
||||
config.setTimeOfArriveStopPoint(null);
|
||||
sectionConfig = (ThailandSectionConfig) nextAxle.getRealDevice();
|
||||
//更新变量
|
||||
previousSection = headSection;
|
||||
headSection = train.getHeadPosition().getSection();
|
||||
nextSection = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
//如果列车车头在进路首个区段,进路开始解锁。
|
||||
@ -162,6 +185,12 @@ public class ThailandTrainServiceImpl implements UDPRealDeviceService {
|
||||
if (config.getManualGear() != null) {
|
||||
return;
|
||||
}
|
||||
if (train.isStop() && headSection.isStandTrack()) {
|
||||
if (headSection.getStandList().stream().anyMatch(stand -> stand.getRemainTime() > 0)) {
|
||||
//此处自行控制停站时间以确保用户的感知和设置的一样
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (stopPosition != null) {
|
||||
Float distance = CalculateService.calculateDistance(train.getHeadPosition(), stopPosition,
|
||||
right, false);
|
||||
@ -215,23 +244,6 @@ public class ThailandTrainServiceImpl implements UDPRealDeviceService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Simulation simulation, UDPLowConfig udpLowConfig, RealDeviceConfig realDevice) {
|
||||
ThailandTrainConfig config = (ThailandTrainConfig) realDevice;
|
||||
//控制vr设备
|
||||
VirtualRealityTrain train = (VirtualRealityTrain) config.getMapElement();
|
||||
//控制沙盘设备
|
||||
byte[] data = buildData(train, config);
|
||||
udpClient.write(udpLowConfig.getAddr(), data);
|
||||
//清除状态
|
||||
config.updateHeadSection(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Simulation simulation, ByteBuf msg) {
|
||||
|
||||
}
|
||||
|
||||
private byte[] buildData(VirtualRealityTrain train, ThailandTrainConfig config) {
|
||||
int gear;
|
||||
if (train.isStop()) {
|
||||
|
@ -196,11 +196,11 @@ public class SimulationRobotService {
|
||||
doBreakMax(simulation, train);
|
||||
}
|
||||
} else if (train.isRobotNeedRun() && (train.isRMMode()
|
||||
|| train.isNRMMode())) { //CM应当根据推荐速度驾驶,待实现
|
||||
|| train.isNRMMode())) { //CM应当根据推荐速度驾驶,待实现
|
||||
VirtualRealityTrain linkTrain = train.getLinkTrain();
|
||||
if (linkTrain == null) {
|
||||
Optional<SectionPosition> targetPositionOptional = calculateTargetPosition(simulation,
|
||||
train);
|
||||
train);
|
||||
targetPositionOptional.ifPresent(tp -> robotDrive(simulation, driver, train, tp));
|
||||
} else {
|
||||
robotDrive(simulation, driver, train, train.getRobotTargetPosition());
|
||||
@ -255,8 +255,10 @@ public class SimulationRobotService {
|
||||
Signal throughSignal = robotDriveParam.getThroughSignal();
|
||||
SignalAspect throughAspect = robotDriveParam.getThroughSignalAspect();
|
||||
Section section = headPosition.getSection();
|
||||
boolean parking = train.isParkingAt();
|
||||
|
||||
if (throughSignal != null && !Objects.equals(section, throughSignal.getSection())) { //当车头与要越过的信号机不在同一区段
|
||||
if (throughSignal != null && !Objects.equals(section,
|
||||
throughSignal.getSection())) { //当车头与要越过的信号机不在同一区段
|
||||
throughSignal = null;
|
||||
throughAspect = null;
|
||||
robotDriveParam.setThrough(DriveParamVO.NO);
|
||||
@ -268,37 +270,25 @@ public class SimulationRobotService {
|
||||
// 车头在正常的站台上
|
||||
if (section.isNormalStandTrack() && !section.equals(train.getParkSection())) { //正常站台轨且未在此处停过车
|
||||
// 如果计划停车区段为空或者计划停车区段中有包含当前区段
|
||||
if (CollectionUtils.isEmpty(plannedParkingSections) || plannedParkingSections.contains(section)) {
|
||||
if (CollectionUtils.isEmpty(plannedParkingSections) || plannedParkingSections.contains(
|
||||
section)) {
|
||||
SectionPosition stopPosition = section.buildStopPointPosition(right);
|
||||
if (targetPosition == null || stopPosition.isAheadOf(targetPosition, right)) {
|
||||
if (targetPosition == null || stopPosition.isAheadOf(targetPosition, !right)) {
|
||||
// 如果头部位置偏移小于停车点位置偏移,目标点为当前停车点
|
||||
if (headPosition.getOffset() < (section.getStopPointByDirection(right) + SimulationConstants.PARK_POINT_MAX_OFFSET)) { //防止意外开过站后无法发车
|
||||
if (headPosition.getOffset() < (section.getStopPointByDirection(right)
|
||||
+ SimulationConstants.PARK_POINT_MAX_OFFSET)) { //防止意外开过站后无法发车
|
||||
targetPosition = stopPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 取禁止信号前停车位置与当前目标停车位置中更近的一个
|
||||
Signal signal = section.getSignalOf(right);
|
||||
if (signal != null && !signal.isShunting()) { // 信号机不为调车信号机
|
||||
VirtualRealitySignal vrSignal = signal.getVirtualSignal();
|
||||
SectionPosition signalPosition = signal.getPosition();
|
||||
if (vrSignal != null && (i != 0 || signalPosition.isAheadOf(headPosition, right))) { //有实体信号机且列车未越过信号机
|
||||
if (Objects.equals(vrSignal.getAspect(), signal.getDefaultAspect()) //禁止信号
|
||||
|| Objects.equals(vrSignal.getAspect(), signal.getGuideAspect())) { //引导信号
|
||||
if (!Objects.equals(signal, throughSignal) || !Objects.equals(vrSignal.getAspect(), throughAspect)) {
|
||||
SectionPosition noPassPosition = CalculateService.calculateNextPositionByStartAndLen(signalPosition, !right, 2, true);
|
||||
if (targetPosition == null || noPassPosition.isAheadOf(targetPosition, right)) {
|
||||
targetPosition = noPassPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
targetPosition = updateTargetPositionOfSignal(headPosition, right,
|
||||
throughSignal, throughAspect, section, i, targetPosition, train.isParkingAt());
|
||||
|
||||
if (targetPosition == null) {
|
||||
if (selectedPosition != null && section.equals(selectedPosition.getSection())) { //不会有比选定位置更靠前的停车点了
|
||||
if (selectedPosition != null && section.equals(
|
||||
selectedPosition.getSection())) { //不会有比选定位置更靠前的停车点了
|
||||
targetPosition = selectedPosition;
|
||||
} else {
|
||||
Section tempSection = section.findNextRunningSectionBaseRealSwitch(right);
|
||||
@ -310,13 +300,13 @@ public class SimulationRobotService {
|
||||
}
|
||||
} else {
|
||||
if (selectedPosition != null) {
|
||||
if (selectedPosition.isAheadOf(targetPosition, right)) {
|
||||
if (selectedPosition.isAheadOf(targetPosition, !right)) {
|
||||
targetPosition = selectedPosition;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (selectedPosition != null && selectedPosition.isAheadOf(targetPosition, right)) {
|
||||
if (selectedPosition != null && selectedPosition.isAheadOf(targetPosition, !right)) {
|
||||
targetPosition = selectedPosition;
|
||||
} else {
|
||||
|
||||
@ -329,7 +319,50 @@ public class SimulationRobotService {
|
||||
if (targetPosition == null) { //上方的区段遍历完后,即没有找到目标区段,也没有找到轨道尽头
|
||||
targetPosition = new SectionPosition(section, right ? 0 : section.getMaxOffset());
|
||||
}
|
||||
return Optional.ofNullable(targetPosition);
|
||||
return Optional.of(targetPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取以信号机为依据的目标位置
|
||||
*
|
||||
* @param i 区段的索引
|
||||
* @return 如果计算出的targetPosition比参数中的更近,则返回新的,否则返回原来的
|
||||
*/
|
||||
private SectionPosition updateTargetPositionOfSignal(SectionPosition headPosition, boolean right,
|
||||
Signal throughSignal, SignalAspect throughAspect, Section section, int i,
|
||||
SectionPosition targetPosition, boolean parking) {
|
||||
Signal signal = section.getSignalOf(right);
|
||||
if (signal == null || signal.isShunting()) {
|
||||
return targetPosition;
|
||||
}
|
||||
VirtualRealitySignal vrSignal = signal.getVirtualSignal();
|
||||
SectionPosition signalPosition = signal.getPosition();
|
||||
if (vrSignal == null || (i == 0 && headPosition.isAheadOf(signalPosition, right))) {
|
||||
//解释下||后面的条件,如果i!=0,则车头位置一定不可能在信号机前方,即i==0只是为了减少计算,对结果没有影响
|
||||
return targetPosition;
|
||||
}
|
||||
if (targetPosition != null && signalPosition.isAheadOf(targetPosition, right)) {
|
||||
//只要目标位置没有越过信号机,则没必要一定和信号机保持2m距离
|
||||
return targetPosition;
|
||||
}
|
||||
if (!Objects.equals(vrSignal.getAspect(), signal.getDefaultAspect())
|
||||
&& !Objects.equals(vrSignal.getAspect(), signal.getGuideAspect())) { //非禁止/引导信号
|
||||
return targetPosition;
|
||||
}
|
||||
if (Objects.equals(signal, throughSignal)
|
||||
&& Objects.equals(vrSignal.getAspect(), throughAspect)) {
|
||||
return targetPosition;
|
||||
}
|
||||
if (parking && section.equals(headPosition.getSection())) { //避免停站结束后向前移动到信号机前
|
||||
return headPosition;
|
||||
}
|
||||
SectionPosition newPosition = CalculateService.calculateNextPositionByStartAndLen(
|
||||
signalPosition, !right, 2, true);
|
||||
if (targetPosition == null || newPosition.isAheadOf(targetPosition, !right)) {
|
||||
return newPosition;
|
||||
} else {
|
||||
return targetPosition;
|
||||
}
|
||||
}
|
||||
|
||||
private void releaseEB(Simulation simulation, SimulationMember driver,
|
||||
|
@ -34,6 +34,7 @@ import club.joylink.rtss.simulation.cbtc.device.real.udp.sr.config.SrSectionConf
|
||||
import club.joylink.rtss.simulation.cbtc.device.real.udp.sr.config.SrSignalConfig;
|
||||
import club.joylink.rtss.simulation.cbtc.device.real.udp.sr.config.SrSwitchConfig;
|
||||
import club.joylink.rtss.simulation.cbtc.device.real.udp.sr.config.SrTrainConfig;
|
||||
import club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.config.ThailandRunPlanConfig;
|
||||
import club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.config.ThailandSectionConfig;
|
||||
import club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.config.ThailandSignalConfig;
|
||||
import club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.config.ThailandSwitchConfig;
|
||||
@ -176,6 +177,9 @@ public class ProjectDeviceVO {
|
||||
case TRAIN:
|
||||
list.add(new ThailandTrainConfig(deviceVO));
|
||||
break;
|
||||
case SAND_TABLE_RUN_PLAN:
|
||||
list.add(new ThailandRunPlanConfig(deviceVO));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return list;
|
||||
|
@ -0,0 +1,59 @@
|
||||
package club.joylink.rtss.vo.client.project.thailand;
|
||||
|
||||
import club.joylink.rtss.vo.client.project.RealConfigVO;
|
||||
import java.util.List;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class ThailandRunPlanConfigVO extends RealConfigVO {
|
||||
|
||||
private List<String> standTrackList;
|
||||
|
||||
/**
|
||||
* 停站时长/s
|
||||
*/
|
||||
private int parkingDuration = 15;
|
||||
|
||||
/**
|
||||
* 发车间隔/s。多辆车从停车场发车的间隔时长
|
||||
*/
|
||||
private Integer departureDuration;
|
||||
|
||||
public ThailandRunPlanConfigVO() {
|
||||
super(null, null);
|
||||
}
|
||||
|
||||
public ThailandRunPlanConfigVO(Integer addr, Integer quantity) {
|
||||
super(addr, quantity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String findDeviceCode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public static class Detail {
|
||||
|
||||
private String groupNumber;
|
||||
private String stationName;
|
||||
private String trackName;
|
||||
private Integer parkingDuration;
|
||||
private boolean finished;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Param {
|
||||
|
||||
@NotBlank(message = "groupNumber cannot be null")
|
||||
private String groupNumber;
|
||||
@NotBlank(message = "track cannot be null")
|
||||
private String trackCode;
|
||||
}
|
||||
}
|
@ -3,50 +3,49 @@ package club.joylink.rtss.websocket.interceptor;
|
||||
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
|
||||
import club.joylink.rtss.services.LoginSessionManager;
|
||||
import club.joylink.rtss.vo.LoginUserInfoVO;
|
||||
import java.util.Map;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.server.ServerHttpRequest;
|
||||
import org.springframework.http.server.ServerHttpResponse;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.socket.WebSocketHandler;
|
||||
import org.springframework.web.socket.server.HandshakeInterceptor;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
public class SessionAuthHandshakeInterceptor extends BaseInterceptor {
|
||||
private static final String Token_Key = "token";
|
||||
public static final String ATTR_USER_KEY = "user";
|
||||
private LoginSessionManager loginSessionManager;
|
||||
|
||||
public SessionAuthHandshakeInterceptor(LoginSessionManager loginSessionManager) {
|
||||
this.loginSessionManager = loginSessionManager;
|
||||
private static final String Token_Key = "token";
|
||||
public static final String ATTR_USER_KEY = "user";
|
||||
private LoginSessionManager loginSessionManager;
|
||||
|
||||
public SessionAuthHandshakeInterceptor(LoginSessionManager loginSessionManager) {
|
||||
this.loginSessionManager = loginSessionManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
|
||||
WebSocketHandler wsHandler,
|
||||
Map<String, Object> attributes) throws Exception {
|
||||
try {
|
||||
LoginUserInfoVO loginUserInfoVO = getLoginUser(request);
|
||||
attributes.put(ATTR_USER_KEY, loginUserInfoVO);
|
||||
return true;
|
||||
} catch (Throwable e) {
|
||||
log.error("未登录或登陆已过期");
|
||||
}
|
||||
response.setStatusCode(HttpStatus.UNAUTHORIZED);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
|
||||
Map<String, Object> attributes) throws Exception {
|
||||
try {
|
||||
LoginUserInfoVO loginUserInfoVO = getLoginUser(request);
|
||||
attributes.put(ATTR_USER_KEY, loginUserInfoVO);
|
||||
return true;
|
||||
} catch (Throwable e) {
|
||||
log.error("未登录或登陆已过期", e);
|
||||
}
|
||||
response.setStatusCode(HttpStatus.UNAUTHORIZED);
|
||||
return false;
|
||||
}
|
||||
|
||||
private LoginUserInfoVO getLoginUser(ServerHttpRequest request) {
|
||||
private LoginUserInfoVO getLoginUser(ServerHttpRequest request) {
|
||||
// String query = request.getURI().getQuery();
|
||||
Map<String, String> map = this.findQueryParams(request);
|
||||
log.info(String.format("webSocket handshake query: [%s]", map));
|
||||
BusinessExceptionAssertEnum.NOT_LOGIN.assertTrue(StringUtils.hasText(map.get(Token_Key)));
|
||||
return this.loginSessionManager.getLoginInfoByToken(map.get(Token_Key));
|
||||
Map<String, String> map = this.findQueryParams(request);
|
||||
log.info(String.format("webSocket handshake query: [%s]", map));
|
||||
BusinessExceptionAssertEnum.NOT_LOGIN.assertTrue(StringUtils.hasText(map.get(Token_Key)));
|
||||
return this.loginSessionManager.getLoginInfoByToken(map.get(Token_Key));
|
||||
// AccountVO accountVO = loginInfoVO.getAccountVO();
|
||||
// BusinessExceptionAssertEnum.NOT_LOGIN.assertNotNull(accountVO);
|
||||
// return accountVO;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user