Merge remote-tracking branch 'origin/test' into master-huawei

This commit is contained in:
joylink_zhangsai 2021-03-10 19:43:32 +08:00
commit b4d9b340d8
91 changed files with 3673 additions and 1228 deletions

View File

@ -0,0 +1,52 @@
package club.joylink.rtss.controller;
import club.joylink.rtss.controller.advice.AuthenticateInterceptor;
import club.joylink.rtss.services.pfp.PfpService;
import club.joylink.rtss.vo.UserVO;
import club.joylink.rtss.vo.pfp.PfpVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 客流车站参数管理接口
*/
@RestController
@RequestMapping("/api/pfp")
public class PassengerFlowParamController {
@Autowired
private PfpService pfpService;
@GetMapping(path = "/list")
public List<PfpVO> queryList(@RequestAttribute(name = AuthenticateInterceptor.LOGIN_USER_KEY)
UserVO userVO) {
List<PfpVO> list = this.pfpService.queryEntityList(userVO);
return list;
}
@GetMapping(path = "/{id}")
public PfpVO getById(@PathVariable Long id) {
PfpVO param = this.pfpService.getById(id);
return param;
}
@PostMapping(path = "")
public String create(@RequestBody PfpVO param,
@RequestAttribute(name = AuthenticateInterceptor.LOGIN_USER_KEY)
UserVO userVO) {
String id = this.pfpService.create(param, userVO);
return id;
}
@PutMapping(path = "/{id}")
public void update(@PathVariable Long id, @RequestBody PfpVO param) {
this.pfpService.update(id, param);
}
@DeleteMapping(path = "/{id}")
public void delete(@PathVariable Long id) {
this.pfpService.delete(id);
}
}

View File

@ -43,7 +43,7 @@ public class RunPlanUserDataController {
@ApiOperation(value = "生成通用交路区段数据")
@PostMapping(path = "/routing/path/generate")
public RunPlanRoutingVO generateUserRoutingPath(@RequestBody @Validated RunPlanRoutingVO routingVO) {
return iRunPlanRoutingService.generateUserRouting(routingVO);
return iRunPlanRoutingService.generateUserRoutingSections(routingVO);
}
@ApiOperation(value = "分页获取用户交路")

View File

@ -20,8 +20,8 @@ import club.joylink.rtss.vo.LoginUserInfoVO;
import club.joylink.rtss.vo.UserVO;
import club.joylink.rtss.vo.client.PageVO;
import club.joylink.rtss.vo.client.fault.FaultRuleVO;
import club.joylink.rtss.vo.client.map.DestinationCodeVO;
import club.joylink.rtss.vo.client.map.MapVO;
import club.joylink.rtss.vo.client.map.newmap.MapDestinationCodeDefinitionVO;
import club.joylink.rtss.vo.client.map.newmap.MapStationNewVO;
import club.joylink.rtss.vo.client.runplan.PlanTripNumberVO;
import club.joylink.rtss.vo.client.runplan.RunPlanEChartsDataVO;
@ -264,7 +264,7 @@ public class SimulationV1Controller {
@ApiOperation(value = "查询所有目的地码")
@GetMapping("/{group}/destinationCode/list")
public List<MapDestinationCodeDefinitionVO> getAllDestinationCode(@PathVariable String group) {
public List<DestinationCodeVO> getAllDestinationCode(@PathVariable String group) {
return this.groupSimulationService.getAllDestinationCode(group);
}

View File

@ -0,0 +1,42 @@
package club.joylink.rtss.dao;
import club.joylink.rtss.entity.PfStationParam;
import club.joylink.rtss.entity.PfStationParamExample;
import club.joylink.rtss.entity.PfStationParamWithBLOBs;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
@Mapper
@Repository
public interface PfStationParamDAO {
long countByExample(PfStationParamExample example);
int deleteByExample(PfStationParamExample example);
int deleteByPrimaryKey(Long id);
int insert(PfStationParamWithBLOBs record);
int insertSelective(PfStationParamWithBLOBs record);
List<PfStationParamWithBLOBs> selectByExampleWithBLOBs(PfStationParamExample example);
List<PfStationParam> selectByExample(PfStationParamExample example);
PfStationParamWithBLOBs selectByPrimaryKey(Long id);
int updateByExampleSelective(@Param("record") PfStationParamWithBLOBs record, @Param("example") PfStationParamExample example);
int updateByExampleWithBLOBs(@Param("record") PfStationParamWithBLOBs record, @Param("example") PfStationParamExample example);
int updateByExample(@Param("record") PfStationParam record, @Param("example") PfStationParamExample example);
int updateByPrimaryKeySelective(PfStationParamWithBLOBs record);
int updateByPrimaryKeyWithBLOBs(PfStationParamWithBLOBs record);
int updateByPrimaryKey(PfStationParam record);
}

View File

@ -0,0 +1,32 @@
package club.joylink.rtss.entity;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* @author
* 客流车站站型参数管理
*/
@Data
public class PfStationParam implements Serializable {
private Long id;
/**
* 名称
*/
private String name;
/**
* 用户id
*/
private Long userId;
/**
* 更新时间
*/
private LocalDateTime updateTime;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,473 @@
package club.joylink.rtss.entity;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
public class PfStationParamExample {
protected String orderByClause;
protected boolean distinct;
protected List<Criteria> oredCriteria;
private Integer limit;
private Long offset;
public PfStationParamExample() {
oredCriteria = new ArrayList<Criteria>();
}
public void setOrderByClause(String orderByClause) {
this.orderByClause = orderByClause;
}
public String getOrderByClause() {
return orderByClause;
}
public void setDistinct(boolean distinct) {
this.distinct = distinct;
}
public boolean isDistinct() {
return distinct;
}
public List<Criteria> getOredCriteria() {
return oredCriteria;
}
public void or(Criteria criteria) {
oredCriteria.add(criteria);
}
public Criteria or() {
Criteria criteria = createCriteriaInternal();
oredCriteria.add(criteria);
return criteria;
}
public Criteria createCriteria() {
Criteria criteria = createCriteriaInternal();
if (oredCriteria.size() == 0) {
oredCriteria.add(criteria);
}
return criteria;
}
protected Criteria createCriteriaInternal() {
Criteria criteria = new Criteria();
return criteria;
}
public void clear() {
oredCriteria.clear();
orderByClause = null;
distinct = false;
}
public void setLimit(Integer limit) {
this.limit = limit;
}
public Integer getLimit() {
return limit;
}
public void setOffset(Long offset) {
this.offset = offset;
}
public Long getOffset() {
return offset;
}
protected abstract static class GeneratedCriteria {
protected List<Criterion> criteria;
protected GeneratedCriteria() {
super();
criteria = new ArrayList<Criterion>();
}
public boolean isValid() {
return criteria.size() > 0;
}
public List<Criterion> getAllCriteria() {
return criteria;
}
public List<Criterion> getCriteria() {
return criteria;
}
protected void addCriterion(String condition) {
if (condition == null) {
throw new RuntimeException("Value for condition cannot be null");
}
criteria.add(new Criterion(condition));
}
protected void addCriterion(String condition, Object value, String property) {
if (value == null) {
throw new RuntimeException("Value for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value));
}
protected void addCriterion(String condition, Object value1, Object value2, String property) {
if (value1 == null || value2 == null) {
throw new RuntimeException("Between values for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value1, value2));
}
public Criteria andIdIsNull() {
addCriterion("id is null");
return (Criteria) this;
}
public Criteria andIdIsNotNull() {
addCriterion("id is not null");
return (Criteria) this;
}
public Criteria andIdEqualTo(Long value) {
addCriterion("id =", value, "id");
return (Criteria) this;
}
public Criteria andIdNotEqualTo(Long value) {
addCriterion("id <>", value, "id");
return (Criteria) this;
}
public Criteria andIdGreaterThan(Long value) {
addCriterion("id >", value, "id");
return (Criteria) this;
}
public Criteria andIdGreaterThanOrEqualTo(Long value) {
addCriterion("id >=", value, "id");
return (Criteria) this;
}
public Criteria andIdLessThan(Long value) {
addCriterion("id <", value, "id");
return (Criteria) this;
}
public Criteria andIdLessThanOrEqualTo(Long value) {
addCriterion("id <=", value, "id");
return (Criteria) this;
}
public Criteria andIdIn(List<Long> values) {
addCriterion("id in", values, "id");
return (Criteria) this;
}
public Criteria andIdNotIn(List<Long> values) {
addCriterion("id not in", values, "id");
return (Criteria) this;
}
public Criteria andIdBetween(Long value1, Long value2) {
addCriterion("id between", value1, value2, "id");
return (Criteria) this;
}
public Criteria andIdNotBetween(Long value1, Long value2) {
addCriterion("id not between", value1, value2, "id");
return (Criteria) this;
}
public Criteria andNameIsNull() {
addCriterion("`name` is null");
return (Criteria) this;
}
public Criteria andNameIsNotNull() {
addCriterion("`name` is not null");
return (Criteria) this;
}
public Criteria andNameEqualTo(String value) {
addCriterion("`name` =", value, "name");
return (Criteria) this;
}
public Criteria andNameNotEqualTo(String value) {
addCriterion("`name` <>", value, "name");
return (Criteria) this;
}
public Criteria andNameGreaterThan(String value) {
addCriterion("`name` >", value, "name");
return (Criteria) this;
}
public Criteria andNameGreaterThanOrEqualTo(String value) {
addCriterion("`name` >=", value, "name");
return (Criteria) this;
}
public Criteria andNameLessThan(String value) {
addCriterion("`name` <", value, "name");
return (Criteria) this;
}
public Criteria andNameLessThanOrEqualTo(String value) {
addCriterion("`name` <=", value, "name");
return (Criteria) this;
}
public Criteria andNameLike(String value) {
addCriterion("`name` like", value, "name");
return (Criteria) this;
}
public Criteria andNameNotLike(String value) {
addCriterion("`name` not like", value, "name");
return (Criteria) this;
}
public Criteria andNameIn(List<String> values) {
addCriterion("`name` in", values, "name");
return (Criteria) this;
}
public Criteria andNameNotIn(List<String> values) {
addCriterion("`name` not in", values, "name");
return (Criteria) this;
}
public Criteria andNameBetween(String value1, String value2) {
addCriterion("`name` between", value1, value2, "name");
return (Criteria) this;
}
public Criteria andNameNotBetween(String value1, String value2) {
addCriterion("`name` not between", value1, value2, "name");
return (Criteria) this;
}
public Criteria andUserIdIsNull() {
addCriterion("user_id is null");
return (Criteria) this;
}
public Criteria andUserIdIsNotNull() {
addCriterion("user_id is not null");
return (Criteria) this;
}
public Criteria andUserIdEqualTo(Long value) {
addCriterion("user_id =", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdNotEqualTo(Long value) {
addCriterion("user_id <>", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdGreaterThan(Long value) {
addCriterion("user_id >", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdGreaterThanOrEqualTo(Long value) {
addCriterion("user_id >=", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdLessThan(Long value) {
addCriterion("user_id <", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdLessThanOrEqualTo(Long value) {
addCriterion("user_id <=", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdIn(List<Long> values) {
addCriterion("user_id in", values, "userId");
return (Criteria) this;
}
public Criteria andUserIdNotIn(List<Long> values) {
addCriterion("user_id not in", values, "userId");
return (Criteria) this;
}
public Criteria andUserIdBetween(Long value1, Long value2) {
addCriterion("user_id between", value1, value2, "userId");
return (Criteria) this;
}
public Criteria andUserIdNotBetween(Long value1, Long value2) {
addCriterion("user_id not between", value1, value2, "userId");
return (Criteria) this;
}
public Criteria andUpdateTimeIsNull() {
addCriterion("update_time is null");
return (Criteria) this;
}
public Criteria andUpdateTimeIsNotNull() {
addCriterion("update_time is not null");
return (Criteria) this;
}
public Criteria andUpdateTimeEqualTo(LocalDateTime value) {
addCriterion("update_time =", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeNotEqualTo(LocalDateTime value) {
addCriterion("update_time <>", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeGreaterThan(LocalDateTime value) {
addCriterion("update_time >", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeGreaterThanOrEqualTo(LocalDateTime value) {
addCriterion("update_time >=", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeLessThan(LocalDateTime value) {
addCriterion("update_time <", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeLessThanOrEqualTo(LocalDateTime value) {
addCriterion("update_time <=", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeIn(List<LocalDateTime> values) {
addCriterion("update_time in", values, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeNotIn(List<LocalDateTime> values) {
addCriterion("update_time not in", values, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeBetween(LocalDateTime value1, LocalDateTime value2) {
addCriterion("update_time between", value1, value2, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeNotBetween(LocalDateTime value1, LocalDateTime value2) {
addCriterion("update_time not between", value1, value2, "updateTime");
return (Criteria) this;
}
}
/**
*/
public static class Criteria extends GeneratedCriteria {
protected Criteria() {
super();
}
}
public static class Criterion {
private String condition;
private Object value;
private Object secondValue;
private boolean noValue;
private boolean singleValue;
private boolean betweenValue;
private boolean listValue;
private String typeHandler;
public String getCondition() {
return condition;
}
public Object getValue() {
return value;
}
public Object getSecondValue() {
return secondValue;
}
public boolean isNoValue() {
return noValue;
}
public boolean isSingleValue() {
return singleValue;
}
public boolean isBetweenValue() {
return betweenValue;
}
public boolean isListValue() {
return listValue;
}
public String getTypeHandler() {
return typeHandler;
}
protected Criterion(String condition) {
super();
this.condition = condition;
this.typeHandler = null;
this.noValue = true;
}
protected Criterion(String condition, Object value, String typeHandler) {
super();
this.condition = condition;
this.value = value;
this.typeHandler = typeHandler;
if (value instanceof List<?>) {
this.listValue = true;
} else {
this.singleValue = true;
}
}
protected Criterion(String condition, Object value) {
this(condition, value, null);
}
protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
super();
this.condition = condition;
this.value = value;
this.secondValue = secondValue;
this.typeHandler = typeHandler;
this.betweenValue = true;
}
protected Criterion(String condition, Object value, Object secondValue) {
this(condition, value, secondValue, null);
}
}
}

View File

@ -0,0 +1,20 @@
package club.joylink.rtss.entity;
import lombok.Data;
import java.io.Serializable;
/**
* @author
* 客流车站站型参数管理
*/
@Data
public class PfStationParamWithBLOBs extends PfStationParam implements Serializable {
private String regionData;
private String sceneConfig;
private String simulationConfig;
private static final long serialVersionUID = 1L;
}

View File

@ -30,12 +30,13 @@ public enum BusinessExceptionAssertEnum implements BusinessExceptionAssert {
SIMULATION_PERMISSION_NOT_AVAILABLE(10014, "simulation permission not available"),
UNSUPPORTED_FILE_FORMAT(10015, "unsupported file format"),
OPERATION_REPEAT(10016, "operation repeat"),
SIMULATION_EXCEPTION_FOR_SHOW(10017, ""), //错误信息用于展示给仿真用户
DATA_ERROR(11000, "data error"),
CI_GENERATE_ERROR(11001, "ci data generate error"),
MAP_PASSENGER_FLOW_DATA_ERROR(11002, "map passenger flow data error"),
DATA_UNIQUE_PROPERTY_REPEAT(10013, "data unique property repeat"),
DATA_UNIQUE_PROPERTY_REPEAT(11013, "data unique property repeat"),
DATA_INVALID(11004, "data invalid"),
DATA_BEEN_USED(11005, "data has been used"),
DATA_STATE_INCORRECT(11007, "data state incorrect"),
@ -45,6 +46,7 @@ public enum BusinessExceptionAssertEnum implements BusinessExceptionAssert {
// 仿真
SIMULATION_NOT_EXIST(30001, "simulation not exist"),
SIMULATION_OPERATION_FAILED(30002, "simulation operation failed"),
//
LOGIN_INFO_ERROR(40003, "login info error"),

View File

@ -4,8 +4,6 @@ import club.joylink.rtss.constants.BusinessConsts;
import club.joylink.rtss.dao.*;
import club.joylink.rtss.entity.*;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.services.draftData.DraftMapFlankProtectionService;
import club.joylink.rtss.services.draftData.DraftMapRunLevelService;
import club.joylink.rtss.simulation.cbtc.build.SimulationBuilder;
import club.joylink.rtss.simulation.cbtc.data.CalculateService;
import club.joylink.rtss.simulation.cbtc.data.map.Section;
@ -27,7 +25,6 @@ import org.springframework.util.StringUtils;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@Slf4j
@ -1365,6 +1362,7 @@ public class DraftMapService implements IDraftMapService {
@Override
public void saveOperationDefinitions(Long mapId, MapDestinationCodeDefinitionVO definitionVO) {
check(definitionVO);
DraftMapWithBLOBs entity = getEntity(mapId);
String logicData = entity.getLogicData();
@ -1398,7 +1396,7 @@ public class DraftMapService implements IDraftMapService {
return new PageVO<>(queryVO.getPageNum(), queryVO.getPageSize(), 0, new ArrayList<>());
}
List<MapDestinationCodeDefinitionVO> vos = JsonUtils.read(logicData, JsonUtils.getCollectionType(ArrayList.class, MapDestinationCodeDefinitionVO.class));
vos.sort(Comparator.comparing(o -> Integer.valueOf(o.getCode())));
// vos.sort(Comparator.comparing(o -> Integer.valueOf(o.getCode())));
int startIndex = (queryVO.getPageNum() - 1) * queryVO.getPageSize();
if (startIndex > vos.size() - 1) {
return new PageVO<>(queryVO.getPageNum(), queryVO.getPageSize(), 0, new ArrayList<>());
@ -1520,4 +1518,25 @@ public class DraftMapService implements IDraftMapService {
BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertNotNull(data);
return data;
}
/**
* 检查目的地码定义数据
*/
private void check(MapDestinationCodeDefinitionVO definitionVO) {
switch (definitionVO.getType()) {
case NORMAL_OPERATION:
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertNotNull(definitionVO.getStationACode(), "车站A必须选择");
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertNotNull(definitionVO.getStationBCode(), "车站B必须选择");
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertNotNull(definitionVO.getStationAFrontTurnBack(), "车站A是否站前折返必须选择");
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertNotNull(definitionVO.getStationBFrontTurnBack(), "车站B是否站前折返必须选择");
break;
case LAST_OPERATION:
case NON_OPERATION:
case LAST_NON_OPERATION:
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertNotNull(definitionVO.getSectionCode(), "目标区段必须选择");
break;
case OTHER:
break;
}
}
}

View File

@ -9,7 +9,7 @@ import club.joylink.rtss.entity.*;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.services.runplan.IRunPlanRoutingService;
import club.joylink.rtss.services.runplan.IRunPlanUserConfigService;
import club.joylink.rtss.services.runplan.RunPlanGenerator;
import club.joylink.rtss.services.runplan.RunPlanGenerator1;
import club.joylink.rtss.services.runplan.importReal.IRunPlanStrategyNew;
import club.joylink.rtss.services.runplan.importReal.RunPlanImportStrategyEnum;
import club.joylink.rtss.simulation.cbtc.GroupSimulationService;
@ -21,7 +21,6 @@ import club.joylink.rtss.util.JsonUtils;
import club.joylink.rtss.vo.LoginUserInfoVO;
import club.joylink.rtss.vo.UserVO;
import club.joylink.rtss.vo.client.PageVO;
import club.joylink.rtss.vo.client.map.MapRoutingVO;
import club.joylink.rtss.vo.client.map.MapVO;
import club.joylink.rtss.vo.client.map.RealLineConfigVO;
import club.joylink.rtss.vo.client.map.newmap.*;
@ -80,7 +79,7 @@ public class RunPlanDraftService implements IRunPlanDraftService {
private IRunPlanUserConfigService runPlanUserConfigService;
@Autowired
private RunPlanGenerator runPlanGenerator;
private RunPlanGenerator1 runPlanGenerator;
@Override
@Transactional
@ -199,8 +198,6 @@ public class RunPlanDraftService implements IRunPlanDraftService {
checkNameRepeat(null, name, mapId, userVO);
// 查询车站数据车站 --- 站台 --- 站台轨
MapVO mapVO = this.iMapService.getMapDetail(mapId);
List<RunPlanTripVO> tripVOList;
List<MapStationNewVO> stationList = this.prepareStationDataNew(mapVO);
BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertCollectionNotEmpty(stationList);
// 查询目的地码-区段code关系
@ -226,7 +223,7 @@ public class RunPlanDraftService implements IRunPlanDraftService {
IRunPlanStrategyNew runPlanStrategy =RunPlanImportStrategyEnum.matchImportStrategy(mapVO.getLineCode());
runPlanStrategy.importDataCheckAndPreHandle(runPlanImportList, stationList, upDirection);
// 生成到站计划数据
tripVOList = runPlanStrategy.parseRunPlanImport(runPlanImportList, sectionMap, upDirection);
List<RunPlanTripVO> tripVOList = runPlanStrategy.parseRunPlanImport(runPlanImportList, sectionMap, upDirection);
// 生成计划对象
RunPlanDraft plan = new RunPlanDraft();
plan.setMapId(mapId);
@ -393,56 +390,54 @@ public class RunPlanDraftService implements IRunPlanDraftService {
List<RunPlanTripVO> newTripList = new ArrayList<>();
RunPlanUserConfigVO config = runPlanUserConfigService.getConfig(userVO.getId(), mapVO.getId());
BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertTrue(Objects.nonNull(config) && config.hasReentryData(), "运行图-用户缺少配置或没有配置车站折返数据");
Map<String, String> userReentryData = config.getConfig().getRunPlanUserReentryData();
Map<String, RunPlanUserConfigVO.ReentryTime> userReentryData = config.getConfig().getReentryData();
List<RunPlanRoutingVO> userRoutings = runPlanRoutingService.getUserRoutingBy(userVO.getId(), mapVO.getId());
Map<String, RunPlanRoutingVO> userRoutingMap = userRoutings.stream().collect(Collectors.toMap(RunPlanRoutingVO::getCode, Function.identity()));
for (RunPlanTripConfigVO tripConfigVO : serviceConfig.getTripConfigList()) {
// 查询交路
// MapRoutingDataVO routingData = mapVO.findRoutingDataByCode(tripConfigVO.getRoutingCode());
RunPlanRoutingVO routingData = userRoutingMap.get(tripConfigVO.getRoutingCode());
String endSectionCode = routingData.getEndSectionCode();
String startSectionCode = routingData.getStartSectionCode();
MapSectionNewVO endSection = mapVO.findSectionNew(endSectionCode);
MapSectionNewVO endReentrySection = null;
if (endSection.isStandTrack()) {
String endReentrySectionCode = userReentryData.get(routingData.getEndStationCode());
BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertNotNull(endReentrySectionCode, "车站" + routingData.getEndStationCode() + "折返轨未设置");
endReentrySection = mapVO.findSectionNew(endReentrySectionCode);
}
MapSectionNewVO startSection = mapVO.findSectionNew(startSectionCode);
MapSectionNewVO startReentrySection = null;
if (startSection.isStandTrack()) {
String startReentrySectionCode = userReentryData.get(routingData.getStartStationCode());
BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertNotNull(startReentrySectionCode, "车站" + routingData.getStartStationCode() + "折返轨未设置");
startReentrySection = mapVO.findSectionNew(startReentrySectionCode);
}
RunPlanTripVO tripVO = new RunPlanTripVO(tripConfigVO, routingData, startReentrySection, endReentrySection);
if (mapVO.getConfigVO().getUpRight()) {
if (routingData.getRight()) {
tripVO.setDirectionCode(DirectionType.Type02);
} else {
tripVO.setDirectionCode(DirectionType.Type01);
}
} else {
if (routingData.getRight()) {
tripVO.setDirectionCode(DirectionType.Type01);
} else {
tripVO.setDirectionCode(DirectionType.Type02);
}
}
// String endSectionCode = routingData.getEndSectionCode();
// String startSectionCode = routingData.getStartSectionCode();
// MapSectionNewVO endSection = mapVO.findSectionNew(endSectionCode);
//// MapSectionNewVO endReentrySection = null;
// if (endSection.isStandTrack()) {
// RunPlanUserConfigVO.ReentryTime endReentryTime = userReentryData.get(routingData.getEndStationCode());
// BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertNotNull(endReentryTime, "车站未设置折返数据");
//// endReentrySection = mapVO.findSectionNew(endReentrySectionCode);
// }
// MapSectionNewVO startSection = mapVO.findSectionNew(startSectionCode);
//// MapSectionNewVO startReentrySection = null;
// if (startSection.isStandTrack()) {
// RunPlanUserConfigVO.ReentryTime startReentryTime = userReentryData.get(routingData.getStartStationCode());
// BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertNotNull(startReentryTime, "车站未设置折返数据");
//// startReentrySection = mapVO.findSectionNew(startReentrySectionCode);
// }
RunPlanTripVO tripVO = new RunPlanTripVO(routingData);
setDirectionCode(mapVO.getConfigVO().getUpRight(), tripVO);
// if (mapVO.getConfigVO().getUpRight()) {
// if (routingData.getRight()) {
// tripVO.setDirectionCode(DirectionType.Type02);
// } else {
// tripVO.setDirectionCode(DirectionType.Type01);
// }
// } else {
// if (routingData.getRight()) {
// tripVO.setDirectionCode(DirectionType.Type01);
// } else {
// tripVO.setDirectionCode(DirectionType.Type02);
// }
// }
// 构建类车到站数据
tripVO.setServiceNumber(serviceConfig.getServiceNumber());
//增加方向码
List<RunPlanArriveConfigVO> arriveConfigList = tripConfigVO.getArriveConfigList();
arriveConfigList.stream().map(RunPlanTripTimeVO::new).forEach(timeVO -> tripVO.getTimeList().add(timeVO));
if (Objects.equals(tripVO.getEndSectionCode(), (new LinkedList<>(tripVO.getTimeList())).getLast().getSectionCode())) {
arriveConfigList.stream().map(RunPlanTripTimeVO::new).forEach(timeVO -> tripVO.addTime(timeVO));
// if (Objects.equals(tripVO.getEndSectionCode(), (new LinkedList<>(tripVO.getTimeList())).getLast().getSectionCode())) {
tripVO.setEndTime(tripConfigVO.getEndTime().minusHours(SimulationConstants.RUN_DIAGRAM_TRANS_TIME));
}
if (Objects.equals(tripVO.getStartSectionCode(), (new LinkedList<>(tripVO.getTimeList())).getFirst().getSectionCode())) {
// }
// if (Objects.equals(tripVO.getStartSectionCode(), (new LinkedList<>(tripVO.getTimeList())).getFirst().getSectionCode())) {
tripVO.setStartTime(tripConfigVO.getStartTime().minusHours(SimulationConstants.RUN_DIAGRAM_TRANS_TIME));
}
// }
newTripList.add(tripVO);
}
// 添加数据
@ -688,44 +683,44 @@ public class RunPlanDraftService implements IRunPlanDraftService {
MapVO mapVO = this.iMapService.getMapDetail(runPlanVO.getMapId());
RunPlanUserConfigVO config = runPlanUserConfigService.getConfig(userVO.getId(), mapVO.getId());
BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertTrue(Objects.nonNull(config) && config.hasReentryData(), "运行图-用户缺少配置或没有配置车站折返数据");
Map<String, String> userReentryData = config.getConfig().getRunPlanUserReentryData();
Map<String, RunPlanUserConfigVO.ReentryTime> userReentryData = config.getConfig().getReentryData();
List<RunPlanRoutingVO> userRoutings = runPlanRoutingService.getUserRoutingBy(userVO.getId(), mapVO.getId());
Map<String, RunPlanRoutingVO> userRoutingMap = userRoutings.stream().collect(Collectors.toMap(RunPlanRoutingVO::getCode, Function.identity()));
String tripNumber = "000";
RunPlanTripVO tripVO;
// 查询交路
// MapRoutingDataVO routing = mapVO.findRoutingDataByCode(tripConfig.getRoutingCode());
RunPlanRoutingVO routingData = userRoutingMap.get(tripConfig.getRoutingCode());
String endSectionCode = routingData.getEndSectionCode();
String startSectionCode = routingData.getStartSectionCode();
MapSectionNewVO endSection = mapVO.findSectionNew(endSectionCode);
MapSectionNewVO endReentrySection = null;
if (endSection.isStandTrack()) {
String endReentrySectionCode = userReentryData.get(routingData.getEndStationCode());
BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertNotNull(endReentrySectionCode, "车站" + routingData.getEndStationCode() + "折返轨未设置");
endReentrySection = mapVO.findSectionNew(endReentrySectionCode);
}
MapSectionNewVO startSection = mapVO.findSectionNew(startSectionCode);
MapSectionNewVO startReentrySection = null;
if (startSection.isStandTrack()) {
String startReentrySectionCode = userReentryData.get(routingData.getStartStationCode());
BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertNotNull(startReentrySectionCode, "车站" + routingData.getStartStationCode() + "折返轨未设置");
startReentrySection = mapVO.findSectionNew(startReentrySectionCode);
}
tripVO = new RunPlanTripVO(tripConfig, routingData, startReentrySection, endReentrySection);
// String endSectionCode = routingData.getEndSectionCode();
// String startSectionCode = routingData.getStartSectionCode();
// MapSectionNewVO endSection = mapVO.findSectionNew(endSectionCode);
// MapSectionNewVO endReentrySection = null;
// if (endSection.isStandTrack()) {
// String endReentrySectionCode = userReentryData.get(routingData.getEndStationCode());
// BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertNotNull(endReentrySectionCode, "车站" + routingData.getEndStationCode() + "折返轨未设置");
// endReentrySection = mapVO.findSectionNew(endReentrySectionCode);
// }
// MapSectionNewVO startSection = mapVO.findSectionNew(startSectionCode);
// MapSectionNewVO startReentrySection = null;
// if (startSection.isStandTrack()) {
// String startReentrySectionCode = userReentryData.get(routingData.getStartStationCode());
// BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertNotNull(startReentrySectionCode, "车站" + routingData.getStartStationCode() + "折返轨未设置");
// startReentrySection = mapVO.findSectionNew(startReentrySectionCode);
// }
RunPlanTripVO tripVO = new RunPlanTripVO(routingData);
// 构建类车到站数据
// tripVO = new RunPlanTripVO(tripConfig, routing);
setDirectionCode(mapVO.getConfigVO().getUpRight(), tripVO);
setDirectionCode(mapVO.getConfigVO().getUpRight(), tripVO);
tripVO.setServiceNumber(serviceNumber);
tripVO.setTripNumber(tripVO.getDirectionCode() + tripNumber);
tripConfig.getArriveConfigList().stream().map(RunPlanTripTimeVO::new).sorted(Comparator.comparing(RunPlanTripTimeVO::getArrivalTime)).forEach(timeVO -> tripVO.getTimeList().add(timeVO));
if (Objects.equals(tripVO.getEndSectionCode(), (new LinkedList<> (tripVO.getTimeList())).getLast().getSectionCode())) {
// if (Objects.equals(tripVO.getEndSectionCode(), (new LinkedList<> (tripVO.getTimeList())).getLast().getSectionCode())) {
tripVO.setEndTime(tripConfig.getEndTime().minusHours(SimulationConstants.RUN_DIAGRAM_TRANS_TIME));
}
if (Objects.equals(tripVO.getStartSectionCode(), (new LinkedList<> (tripVO.getTimeList())).getFirst().getSectionCode())) {
// }
// if (Objects.equals(tripVO.getStartSectionCode(), (new LinkedList<> (tripVO.getTimeList())).getFirst().getSectionCode())) {
tripVO.setStartTime(tripConfig.getStartTime().minusHours(SimulationConstants.RUN_DIAGRAM_TRANS_TIME));
}
// }
if (CollectionUtils.isEmpty(runPlanVO.getTripList())) {
runPlanVO.setTripList(new ArrayList<>());

View File

@ -315,9 +315,9 @@ public class SysUserService implements ISysUserService {
@Transactional
public CompanyVO userScanCodeBindCompanyManager(Long userId, Integer companyId) {
Org company = companyDAO.selectByPrimaryKey(companyId);
BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertNotNull(company, "不存在此单位");
BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertNotNull(company, String.format("id为[%s]的组织不存在", companyId));
SysUser sysUser = sysUserDAO.selectByPrimaryKey(userId);
BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertNotNull(sysUser, "不存在的用户");
BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertNotNull(sysUser, String.format("id为[%s]的用户不存在", userId));
UserVO userVO = new UserVO(sysUser);
userBindCompanyManager(userVO, companyId);
this.loginSessionManager.updateLoginUser(userVO);

View File

@ -182,6 +182,12 @@ public class DraftMapCiDataGeneratorImpl implements DraftMapCiDataGenerator {
.filter(mapElement -> MapElement.DeviceType.SECTION.equals(mapElement.getDeviceType()))
.map(mapElement -> (Section) mapElement)
.collect(Collectors.toList());
// 所有车站
List<Station> stationList = deviceMap.values().stream()
.filter(mapElement -> MapElement.DeviceType.STATION.equals(mapElement.getDeviceType()))
.map(mapElement -> (Station) mapElement)
.sorted(Comparator.comparingInt(Station::getSn))
.collect(Collectors.toList());
Map<String, List<RouteOverlap>> overlapMap = new HashMap<>();
List<Signal> approachList = new ArrayList<>();
@ -296,58 +302,6 @@ public class DraftMapCiDataGeneratorImpl implements DraftMapCiDataGenerator {
// // 生成交路数据
// List<MapRoutingDataVO> generateRoutingList = this.generateRoutings(deviceMap, generatedRouteList, autoSignalList, errorList);
// // 获取所有转换轨或者折返轨
// List<Section> sectionList = deviceMap.values().stream()
// .filter(mapElement -> mapElement.getDeviceType().equals(MapElement.DeviceType.SECTION))
// .map(mapElement -> ((Section) mapElement)).filter(section -> section.isTurnBackTrack() || section.isTransferTrack())
// .collect(Collectors.toList());
// CodeGenerator routingCodeGenerator = new CodeGenerator("Routing");
// //交路生成
// List<MapRoutingDataVO> generatedRoutingList = new ArrayList<>();
// int size = sectionList.size();
// log.info(String.format("共有折返轨和转换轨[%s]个", size));
// for (int i = 0; i < size - 1; i++) {
// Section startSection = sectionList.get(i);
// for (int j = i + 1; j < size; j++) {
// Section endSection = sectionList.get(j);
// //站台轨之间反向暂不生成
// if(startSection.isNormalStandTrack() && endSection.isNormalStandTrack()){
// boolean noNeed = startSection.getStandList().stream()
// .filter(stand -> !stand.isSmall())
// .anyMatch(stand -> {
// for (Stand stand1 : endSection.getStandList()) {
// if (!stand1.isSmall() && !Objects.equals(stand1.isRight(), stand.isRight())) {
// return true;
// }
// }
// return false;
// });
// if(noNeed) continue;
// }
// // 同一车站间不生成
// if (Objects.equals(startSection.getStation(), endSection.getStation())) {
// continue;
// }
// //生成交路
// MapRoutingDataVO routingData = generateRouting(errorList,
// routingCodeGenerator, startSection, endSection);
// if (Objects.nonNull(routingData)) {
// generatedRoutingList.add(routingData);
// }
// //生成上面交路的回路
// MapRoutingDataVO routingDataLoop = generateRouting(errorList, routingCodeGenerator, endSection, startSection);
// if (Objects.nonNull(routingDataLoop)) {
// if(Objects.nonNull(routingData)){
// routingDataLoop.setCode(routingData.getCode() + "-LOOP");
// routingDataLoop.setName(routingData.getName() + "-LOOP");
// }
// generatedRoutingList.add(routingDataLoop);
// }
//
// }
// }
//站间运行等级生成
List<MapStationRunLevelVO> generatedStationRunLevelList = new ArrayList<>();
// generateRunLevel(deviceMap, errorList, generateRoutingList, generatedStationRunLevelList);
@ -355,21 +309,132 @@ public class DraftMapCiDataGeneratorImpl implements DraftMapCiDataGenerator {
//目的地码生成
List<DestinationCodeDefinition> destinationCodeDefinitionList = new ArrayList<>();
if (!CollectionUtils.isEmpty(sectionList)) {
for (Section section : sectionList) {
String destinationCode = section.getDestinationCode();
if (!StringUtils.hasText(destinationCode)) {
if (config.isGenerateDestination()) {
String code = null;
DestinationCodeDefinition.Type type = null;
String description = null;
Section startSection = null;
Section section = null;
Boolean right = null;
List<Section> necessarySections = null;
Station leftStation = null;
Boolean leftFrontTurnBack = null;
Station rightStation = null;
Boolean rightFrontTurnBack = null;
int codeNum = 1;
for (int i = 0; i < stationList.size(); i++) {
leftStation = stationList.get(i);
if (CollectionUtils.isEmpty(leftStation.getTurnBackList())) //没有折返轨的略过
continue;
if (i == stationList.size() - 1)
break;
List<Section> leftTbSections = queryAfterTurnBackList(leftStation, false);
leftTbSections.addAll(queryFrontTurnBackList(stationList, leftStation, false));
for (Section startTbSection : leftTbSections) {
for (int j = stationList.size() - 1; j >= 0; j--) {
rightStation = stationList.get(j);
if (leftStation.equals(rightStation)) {
break;
}
List<Section> rightTbSections = queryAfterTurnBackList(rightStation, true);
rightTbSections.addAll(queryFrontTurnBackList(stationList, rightStation, true));
for (Section endTbSection : rightTbSections) {
code = String.format("%03d", codeNum++);
type = DestinationCodeDefinition.Type.NORMAL_OPERATION;
description = String.format("%s-%s", leftStation.getName(), rightStation.getName());
necessarySections = List.of(startTbSection, endTbSection);
leftFrontTurnBack = startTbSection.isNormalStandTrack();
rightFrontTurnBack = endTbSection.isNormalStandTrack();
destinationCodeDefinitionList.add(
new DestinationCodeDefinition(code, type, description, startSection, section, right, necessarySections,
leftStation, leftFrontTurnBack, rightStation, rightFrontTurnBack, null, null)
);
}
}
}
}
} else {
if (!CollectionUtils.isEmpty(sectionList)) {
for (Section section : sectionList) {
String destinationCode = section.getDestinationCode();
if (!StringUtils.hasText(destinationCode)) {
continue;
}
destinationCodeDefinitionList.add(new DestinationCodeDefinition(destinationCode, DestinationCodeDefinition.Type.OTHER, section));
}
destinationCodeDefinitionList.add(new DestinationCodeDefinition(destinationCode, DestinationCodeDefinition.Type.OTHER, section));
}
}
return new CiGenerateResult(errorList, approachList,
autoSignalList, generatedRouteList, generatedOverlapList, flsList,
generateCycleList, generatedStationRunLevelList, destinationCodeDefinitionList);
}
/**
* 筛选站后折返轨优先右行站台折返
* @param stations 所有车站
* @param right 是否是右端车站
*/
private List<Section> queryFrontTurnBackList(List<Station> stations, Station station, boolean right) {
List<Section> turnBackList = station.getTurnBackList();
if (CollectionUtils.isEmpty(turnBackList) || CollectionUtils.isEmpty(station.getAllNormalStands())) {
return new ArrayList<>();
}
int sn;
if (right) {
sn = station.getSn() - 1;
} else {
sn = station.getSn() + 1;
}
Station adjacentStation = stations.stream().filter(sta -> sta.getSn() == sn).limit(1).findAny().get();
if (CollectionUtils.isEmpty(adjacentStation.getAllNormalStands())) {
return new ArrayList<>();
}
Section leftStandTrack = station.getNormalStand(false).get(0).getSection();
Section rightStandTrack = station.getNormalStand(true).get(0).getSection();
Section adjacentLeftStandTrack = adjacentStation.getNormalStand(false).get(0).getSection();
Section adjacentRightStandTrack = adjacentStation.getNormalStand(true).get(0).getSection();
List<Section> tbSections = new ArrayList<>();
if (right) {
if (rightStandTrack.isTurnBackTrack()
&& !CollectionUtils.isEmpty(CalculateService.queryRoutePathsOnDirection(rightStandTrack, adjacentLeftStandTrack, false))) {
tbSections.add(rightStandTrack);
}
if (leftStandTrack.isTurnBackTrack()
&& !CollectionUtils.isEmpty(CalculateService.queryRoutePathsOnDirection(adjacentRightStandTrack, leftStandTrack, true))) {
tbSections.add(leftStandTrack);
}
} else {
if (rightStandTrack.isTurnBackTrack()
&& !CollectionUtils.isEmpty(CalculateService.queryRoutePathsOnDirection(adjacentLeftStandTrack, rightStandTrack, false))) {
tbSections.add(rightStandTrack);
}
if (leftStandTrack.isTurnBackTrack()
&& !CollectionUtils.isEmpty(CalculateService.queryRoutePathsOnDirection(leftStandTrack, adjacentRightStandTrack, true))) {
tbSections.add(leftStandTrack);
}
}
return tbSections;
}
/**
* 筛选站前折返轨
* @param right 是否是右端车站
*/
private List<Section> queryAfterTurnBackList(Station station, boolean right) {
List<Section> turnBackList = station.getTurnBackList();
if (CollectionUtils.isEmpty(turnBackList)) {
return new ArrayList<>();
}
Section standTrack = station.getNormalStand(right).get(0).getSection();
return turnBackList.stream().filter(section -> !section.isNormalStandTrack())
.filter(section -> !CollectionUtils.isEmpty(CalculateService.queryRoutePathsOnDirection(standTrack, section, right)))
.collect(Collectors.toList());
}
private Collection<? extends Route> generateRouteLikeHa1(Signal signal, CodeGenerator routeCodeGenerator,
Map<String, List<RouteOverlap>> overlapMap,
CodeGenerator overlapCodeGenerator,
@ -1095,8 +1160,12 @@ public class DraftMapCiDataGeneratorImpl implements DraftMapCiDataGenerator {
if (!CollectionUtils.isEmpty(ignoreEndCodeList)) {
if (ignoreEndCodeList.contains(route.getDestination().getCode())) {
removeList.add(route);
continue;
}
}
if (signal.isNoRoute()) {
removeList.add(route);
}
}
generatedRouteList.removeAll(removeList);
}

View File

@ -0,0 +1,18 @@
package club.joylink.rtss.services.pfp;
import club.joylink.rtss.vo.UserVO;
import club.joylink.rtss.vo.pfp.PfpVO;
import java.util.List;
public interface PfpService {
List<PfpVO> queryEntityList(UserVO userVO);
PfpVO getById(Long id);
String create(PfpVO param, UserVO userVO);
void update(Long id, PfpVO param);
void delete(Long id);
}

View File

@ -0,0 +1,72 @@
package club.joylink.rtss.services.pfp;
import club.joylink.rtss.dao.PfStationParamDAO;
import club.joylink.rtss.entity.PfStationParam;
import club.joylink.rtss.entity.PfStationParamExample;
import club.joylink.rtss.entity.PfStationParamWithBLOBs;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.vo.UserVO;
import club.joylink.rtss.vo.pfp.PfpVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.time.LocalDateTime;
import java.util.List;
@Service
public class PfpServiceImpl implements PfpService {
@Autowired
private PfStationParamDAO pfStationParamDAO;
@Override
public List<PfpVO> queryEntityList(UserVO userVO) {
PfStationParamExample example = new PfStationParamExample();
example.createCriteria()
.andUserIdEqualTo(userVO.getId());
List<PfStationParam> list = this.pfStationParamDAO.selectByExample(example);
List<PfpVO> voList = PfpVO.convert2VOList(list);
return voList;
}
@Override
public PfpVO getById(Long id) {
PfStationParamWithBLOBs param = this.pfStationParamDAO.selectByPrimaryKey(id);
return new PfpVO(param);
}
@Override
public String create(PfpVO param, UserVO userVO) {
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertHasText(param.getName());
PfStationParamExample example = new PfStationParamExample();
example.createCriteria()
.andUserIdEqualTo(userVO.getId())
.andNameEqualTo(param.getName());
BusinessExceptionAssertEnum.DATA_ALREADY_EXIST
.assertTrue(this.pfStationParamDAO.countByExample(example) == 0,
String.format("名称重复"));
PfStationParamWithBLOBs db = param.toDb();
db.setUserId(userVO.getId());
db.setUpdateTime(LocalDateTime.now());
this.pfStationParamDAO.insert(db);
return db.getId().toString();
}
@Override
public void update(Long id, PfpVO param) {
PfStationParamWithBLOBs db = this.pfStationParamDAO.selectByPrimaryKey(id);
db.setUpdateTime(LocalDateTime.now());
if (StringUtils.hasText(param.getName())) {
db.setName(param.getName());
}
db.setRegionData(param.getRegionData());
db.setSceneConfig(param.getSceneConfig());
db.setSimulationConfig(param.getSimulationConfig());
this.pfStationParamDAO.updateByPrimaryKeySelective(db);
}
@Override
public void delete(Long id) {
this.pfStationParamDAO.deleteByPrimaryKey(id);
}
}

View File

@ -30,5 +30,5 @@ public interface IRunPlanRoutingService {
List<RunPlanRoutingSection> getRoutingSectionDataBy(Long userId, Long planId, String routingCode);
RunPlanRoutingVO generateUserRouting(RunPlanRoutingVO routingVO);
RunPlanRoutingVO generateUserRoutingSections(RunPlanRoutingVO routingVO);
}

View File

@ -1,474 +0,0 @@
package club.joylink.rtss.services.runplan;
import club.joylink.rtss.constants.BusinessConsts;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.vo.client.map.MapVO;
import club.joylink.rtss.vo.client.map.newmap.MapSectionNewVO;
import club.joylink.rtss.vo.client.runplan.RunPlanTripTimeVO;
import club.joylink.rtss.vo.client.runplan.RunPlanTripVO;
import club.joylink.rtss.vo.client.runplan.user.*;
import club.joylink.rtss.vo.runplan.RunPlanInput;
import club.joylink.rtss.vo.runplan.RunPlanInputData;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;
/**
* 通用运行图生成
*/
@Component
public class RunPlanGenerator {
private static final int OFFSET_TIME_HOURS = 2; //时间偏移早两小时
@Autowired
private IRunPlanRoutingService runPlanRoutingService;
@Autowired
private IRunPlanRunlevelService runPlanRunlevelService;
@Autowired
private IRunPlanParktimeService runPlanParktimeService;
@Autowired
private IRunPlanUserConfigService runPlanUserConfigService;
public List<RunPlanTripVO> generatorTrips(Long userId, RunPlanInput runPlanInput, MapVO mapVO) {
//校验发车停运时间
BusinessExceptionAssertEnum.DATA_ERROR.assertTrue(runPlanInput.getOverTime().isAfter(runPlanInput.getBeginTime()));
//校验车站
LocalTime beginTimeOffset = runPlanInput.getBeginTime().minusHours(OFFSET_TIME_HOURS);
//向前推两小时如果到前一天则时间不合理
BusinessExceptionAssertEnum.DATA_ERROR.assertTrue(runPlanInput.getBeginTime().isAfter(beginTimeOffset), "发车时间过早,建议晚于上午两点");
runPlanInput.setBeginTime(beginTimeOffset);
runPlanInput.setOverTime(runPlanInput.getOverTime().minusHours(OFFSET_TIME_HOURS));
//检查环路
RunPlanRoutingVO running1Routing = runPlanRoutingService.queryUserRoutingByCode(userId, mapVO.getId(), runPlanInput.getRunningRouting1());
RunPlanRoutingVO running2Routing = runPlanRoutingService.queryUserRoutingByCode(userId, mapVO.getId(), runPlanInput.getRunningRouting2());
boolean isLoop = running1Routing.getParkSectionCodeList().get(0).getStationCode().equals(running2Routing.getParkSectionCodeList().get(running2Routing.getParkSectionCodeList().size() - 1).getStationCode())
&& running2Routing.getParkSectionCodeList().get(0).getStationCode().equals(running1Routing.getParkSectionCodeList().get(running1Routing.getParkSectionCodeList().size() - 1).getStationCode());
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertTrue(isLoop, "运行两交路无法构成环路数据");
//查站间运行等级
List<RunPlanRunlevelVO> levels = runPlanRunlevelService.queryUserRunLevels(userId, mapVO.getId());
Map<String, Integer> runLevelTime = levels.stream().collect(Collectors.toMap(runLevelVO -> String.format("%s-%s", runLevelVO.getStartSectionCode(), runLevelVO.getEndSectionCode()), runLevelVO -> runLevelVO.getLevelTime(runPlanInput.getRunLevel())));
//查停站时间
List<RunPlanParkingTimeVO> parkTimes = runPlanParktimeService.queryUserParktimes(userId, mapVO.getId());
Map<String, Integer> parkTime = parkTimes.stream().collect(Collectors.toMap(RunPlanParkingTimeVO::getSectionCode, RunPlanParkingTimeVO::getParkingTime));
//查折返
RunPlanUserConfigVO config = runPlanUserConfigService.getConfig(userId, mapVO.getId());
BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertTrue(Objects.nonNull(config) && config.hasReentryData(), "运行图-用户缺少配置或没有配置车站折返数据");
Map<String, String> userReentryData = config.getConfig().getRunPlanUserReentryData();
// 检测折返轨配置
if (Objects.isNull(userReentryData.get(running1Routing.getParkSectionCodeList().get(0).getStationCode()))
|| Objects.isNull(userReentryData.get(running1Routing.getParkSectionCodeList().get(running1Routing.getParkSectionCodeList().size() - 1).getStationCode()))) {
throw BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.exception("折返轨未设置");
}
//生成车次
LinkedList<RunPlanTripVO> tripList = new LinkedList<>();
//是否同时相向发车
boolean opposite = Objects.isNull(runPlanInput.getRight());
if (opposite) {
//相向发车
int initialServiceNum = 1;
/*分别先发一辆车,计算控制左右发车服务号*/
//上个服务号发车时刻
//首班发车时间,首班车往返回来时间 来限定发车服务数量
ServiceTempResult tempResultLeft = new ServiceTempResult(runPlanInput.getBeginTime(), null);
serviceNumberDepart(mapVO, runPlanInput, running1Routing, running2Routing, initialServiceNum++, tripList, tempResultLeft, false, runLevelTime, parkTime, userReentryData);
//上个服务号发车时刻
//首班发车时间,首班车往返回来时间 来限定发车服务数量
ServiceTempResult tempResultRight = new ServiceTempResult(runPlanInput.getBeginTime(), null);
serviceNumberDepart(mapVO, runPlanInput, running1Routing, running2Routing, initialServiceNum++, tripList, tempResultRight, true, runLevelTime, parkTime, userReentryData);
LocalTime firstRoundTripTimeLeft = tempResultLeft.getFirstRoundTripTime();
LocalTime firstRoundTripTimeRight = tempResultRight.getFirstRoundTripTime();
tempResultRight.setFirstRoundTripTime(firstRoundTripTimeLeft);
tempResultLeft.setFirstRoundTripTime(firstRoundTripTimeRight);
//暂时先定义发完左行再发右行..
do {
tempResultLeft.setPreServiceDepartTime(tempResultLeft.getPreServiceDepartTime().plusSeconds(runPlanInput.getDepartureTimeInterval()));
serviceNumberDepart(mapVO, runPlanInput, running1Routing, running2Routing, initialServiceNum++, tripList, tempResultLeft, false, runLevelTime, parkTime, userReentryData);
} while (tempResultLeft.getPreServiceDepartTime().minusSeconds(runPlanInput.getReentryTime()).plusSeconds(runPlanInput.getDepartureTimeInterval() * 2).compareTo(tempResultLeft.getFirstRoundTripTime()) <= 0);
//发完左行再发右行
do {
tempResultRight.setPreServiceDepartTime(tempResultRight.getPreServiceDepartTime().plusSeconds(runPlanInput.getDepartureTimeInterval()));
serviceNumberDepart(mapVO, runPlanInput, running1Routing, running2Routing, initialServiceNum++, tripList, tempResultRight, true, runLevelTime, parkTime, userReentryData);
} while (tempResultRight.getPreServiceDepartTime().minusSeconds(runPlanInput.getReentryTime()).plusSeconds(runPlanInput.getDepartureTimeInterval() * 2).compareTo(tempResultRight.getFirstRoundTripTime()) <= 0);
} else {
//单向发车
allServiceNumberDepart(mapVO, runPlanInput, running1Routing, running2Routing, tripList, runLevelTime, parkTime, userReentryData);
}
return tripList;
}
/**
* 服务号发车
*/
private void serviceNumberDepart(MapVO mapVO, RunPlanInput runPlanInput, RunPlanRoutingVO running1Routing, RunPlanRoutingVO running2Routing, int initialServiceNum, LinkedList<RunPlanTripVO> tripList, ServiceTempResult tempResult, boolean isRight, Map<String, Integer> runLevelTime, Map<String, Integer> parkTime, Map<String, String> userReentryData) {
String serviceNumber = String.format("%03d", initialServiceNum);
//初始化车次号,右行偶数左行奇数
int initTripNumber = isRight ? 0 : 1;
LocalTime lastTripEndTime = null;//一个车次终点时间
LinkedList<RunPlanTripVO> tempTripList = new LinkedList<>();
//根据运行时间判断结束末班车次
do {
RunPlanRoutingVO routing = Objects.equals(running1Routing.getRight(), isRight) ? running1Routing : running2Routing;
String startReentrySectionCode = userReentryData.get(routing.getStartStationCode());
String endReentrySectionCode = userReentryData.get(routing.getEndStationCode());
MapSectionNewVO endReentrySection = null;
if (Objects.nonNull(endReentrySectionCode)) {
endReentrySection = mapVO.findSectionNew(endReentrySectionCode);
}
MapSectionNewVO startReentrySection = null;
if (Objects.nonNull(startReentrySectionCode)) {
startReentrySection = mapVO.findSectionNew(startReentrySectionCode);
}
RunPlanTripVO runPlanTripVO = new RunPlanTripVO(routing, startReentrySection, endReentrySection);
runPlanTripVO.setServiceNumber(serviceNumber);
setDirectionCode(mapVO, runPlanTripVO);
runPlanTripVO.setIsReentry(true);
//车次号
String tripNumber = String.format("%03d", initTripNumber++);
runPlanTripVO.setTripNumber(runPlanTripVO.getDirectionCode() + tripNumber);
//首班右行方向
LinkedList<RunPlanTripTimeVO> tripTimeList = new LinkedList<>();//车次时刻表
routing.getParkSectionCodeList().forEach(runPlanRoutingSection -> {
RunPlanTripTimeVO runPlanTripTimeVO = new RunPlanTripTimeVO();
runPlanTripTimeVO.setStationCode(runPlanRoutingSection.getStationCode());
runPlanTripTimeVO.setSectionCode(runPlanRoutingSection.getSectionCode());
runPlanTripTimeVO.setArrivalTime(CollectionUtils.isEmpty(tempTripList) && CollectionUtils.isEmpty(tripTimeList) ?
tempResult.getPreServiceDepartTime() :
(CollectionUtils.isEmpty(tripTimeList) ?
(Objects.equals(tempTripList.getLast().getEndSectionCode(), runPlanTripTimeVO.getSectionCode()) ?
tempTripList.getLast().getEndTime() : ((LinkedList<RunPlanTripTimeVO>) tempTripList.getLast().getTimeList()).getLast().getDepartureTime().plusSeconds(runPlanInput.getReentryTime())) : tripTimeList.getLast().getDepartureTime().plusSeconds(runLevelTime.get(tripTimeList.getLast().getSectionCode() + "-" + runPlanTripTimeVO.getSectionCode()))));
runPlanTripTimeVO.setDepartureTime(CollectionUtils.isEmpty(tempTripList) && CollectionUtils.isEmpty(tripTimeList) ? tempResult.getPreServiceDepartTime() : runPlanTripTimeVO.getArrivalTime().plusSeconds(parkTime.getOrDefault(runPlanTripTimeVO.getSectionCode(), 0)));
tripTimeList.add(runPlanTripTimeVO);
});
runPlanTripVO.setTimeList(tripTimeList);
setTripTerminalTime(runPlanTripVO, tripTimeList, runPlanInput.getReentryTime());
lastTripEndTime = runPlanTripVO.getEndTime();
if(CollectionUtils.isEmpty(tempTripList)){
runPlanTripVO.setIsOutbound(true);
}
tempTripList.add(runPlanTripVO);
if (tempTripList.size() > 50) { // 最快半小时跑一趟的一天车次数如果大于这个可能死循环此时停止发车
break;
}
isRight = !isRight;
} while (lastTripEndTime.isBefore(runPlanInput.getOverTime()));
//设置服务号末班车次入库
RunPlanTripVO lastrunPlanTrip = tempTripList.get(tempTripList.size() - 1);
lastrunPlanTrip.setIsInbound(true);
lastrunPlanTrip.setIsReentry(false);
LinkedList<RunPlanTripTimeVO> tripTimeList = (LinkedList<RunPlanTripTimeVO>) lastrunPlanTrip.getTimeList();
setTripEndTime(lastrunPlanTrip, tripTimeList, runPlanInput.getReentryTime());
tripList.addAll(tempTripList);
if (Objects.isNull(tempResult.getFirstRoundTripTime())) {
tempResult.setFirstRoundTripTime(((RunPlanTripTimeVO) (((LinkedList) (tempTripList.get(0).getTimeList())).getLast())).getDepartureTime());
}
tempResult.setPreServiceDepartTime(((RunPlanTripTimeVO) (((LinkedList) (tempTripList.get(0).getTimeList())).getFirst())).getArrivalTime());
}
/**
* 单向发车
*/
private void allServiceNumberDepart(MapVO mapVO, RunPlanInput runPlanInput, RunPlanRoutingVO running1Routing, RunPlanRoutingVO running2Routing, LinkedList<RunPlanTripVO> tripList, Map<String, Integer> runLevelTime, Map<String, Integer> parkTime, Map<String, String> userReentryData) {
//设置初始服务号
int initialServiceNum = 1;
//上个服务号发车时刻
//首班发车时间,首班车往返回来时间 来限定发车服务数量
ServiceTempResult tempResult = new ServiceTempResult(runPlanInput.getBeginTime(), null);
do {
if (initialServiceNum != 1) {
tempResult.setPreServiceDepartTime(tempResult.getPreServiceDepartTime().plusSeconds(runPlanInput.getDepartureTimeInterval()));
}
serviceNumberDepart(mapVO, runPlanInput, running1Routing, running2Routing, initialServiceNum++, tripList, tempResult, runPlanInput.getRight(), runLevelTime, parkTime, userReentryData);
} while (tempResult.getPreServiceDepartTime().minusSeconds(runPlanInput.getReentryTime()).plusSeconds(runPlanInput.getDepartureTimeInterval() * 2).compareTo(tempResult.getFirstRoundTripTime()) <= 0);
}
public List<RunPlanTripVO> generatorTrips(Long userId, RunPlanInputData inputData, MapVO mapVO) {
//校验时间
BusinessExceptionAssertEnum.DATA_ERROR.assertTrue(inputData.getOverTime().isAfter(inputData.getBeginTime()),"输入参数错误:发车时间应早于结束时间");
LocalTime beginTimeOffset = inputData.getBeginTime().minusHours(OFFSET_TIME_HOURS);
//向前推两小时如果到前一天则时间不合理
BusinessExceptionAssertEnum.DATA_ERROR.assertTrue(inputData.getBeginTime().isAfter(beginTimeOffset), "发车时间过早,建议晚于上午两点");
inputData.setBeginTime(beginTimeOffset);
inputData.setOverTime(inputData.getOverTime().minusHours(OFFSET_TIME_HOURS));
//查交路
RunPlanRoutingVO outboundRouting = null;
if (inputData.hasOutbound()) {
outboundRouting = runPlanRoutingService.queryUserRoutingByCode(userId, mapVO.getId(), inputData.getOutboundRouting());
}
RunPlanRoutingVO inboundRouting = null;
if (inputData.hasInbound()) {
inboundRouting = runPlanRoutingService.queryUserRoutingByCode(userId, mapVO.getId(), inputData.getInboundRouting());
}
RunPlanRoutingVO running1Routing = runPlanRoutingService.queryUserRoutingByCode(userId, mapVO.getId(), inputData.getRunningRouting1());
RunPlanRoutingVO running2Routing = runPlanRoutingService.queryUserRoutingByCode(userId, mapVO.getId(), inputData.getRunningRouting2());
//构建环路 出入库关系
//验证 出库和入库 一端折返轨 一段转换轨验证环路 两端折返轨 环路是否闭环 或出入库跟环路是否衔接
boolean isLoop = running1Routing.getParkSectionCodeList().get(0).getStationCode().equals(running2Routing.getParkSectionCodeList().get(running2Routing.getParkSectionCodeList().size() - 1).getStationCode())
&& running2Routing.getParkSectionCodeList().get(0).getStationCode().equals(running1Routing.getParkSectionCodeList().get(running1Routing.getParkSectionCodeList().size() - 1).getStationCode());
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertTrue(isLoop, "运行两交路无法构成环路数据");
boolean outToRun1 = outboundRouting.getParkSectionCodeList().get(outboundRouting.getParkSectionCodeList().size() - 1).getStationCode().equals(running1Routing.getParkSectionCodeList().get(0).getStationCode());
boolean outToRun2 = outboundRouting.getParkSectionCodeList().get(outboundRouting.getParkSectionCodeList().size() - 1).getStationCode().equals(running2Routing.getParkSectionCodeList().get(0).getStationCode());
boolean inToRun1 = inboundRouting.getParkSectionCodeList().get(0).getStationCode().equals(running1Routing.getParkSectionCodeList().get(running1Routing.getParkSectionCodeList().size() - 1).getStationCode());
boolean inToRun2 = inboundRouting.getParkSectionCodeList().get(0).getStationCode().equals(running2Routing.getParkSectionCodeList().get(running2Routing.getParkSectionCodeList().size() - 1).getStationCode());
//出库关联环路某交楼
RunPlanRoutingVO outRef = null;
//环路其它交路
RunPlanRoutingVO other = null;
boolean same = false;
if (outToRun1 && inToRun1) {
same = true;
outRef = running1Routing;
other = running2Routing;
} else if (outToRun2 && inToRun2) {
same = true;
outRef = running2Routing;
other = running1Routing;
} else if (outToRun1 && inToRun2) {
outRef = running1Routing;
other = running2Routing;
} else if (outToRun2 && inToRun1) {
outRef = running2Routing;
other = running1Routing;
} else {
throw BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.exception("出库交路 无法与环路交路相接");
}
//查站间运行等级
List<RunPlanRunlevelVO> levels = runPlanRunlevelService.queryUserRunLevels(userId, mapVO.getId());
Map<String, Integer> runLevelMap = levels.stream().collect(Collectors.toMap(runLevelVO -> String.format("%s-%s", runLevelVO.getStartSectionCode(), runLevelVO.getEndSectionCode()), runLevelVO -> runLevelVO.getLevelTime(inputData.getRunLevel())));
//查停站时间
List<RunPlanParkingTimeVO> parktimes = runPlanParktimeService.queryUserParktimes(userId, mapVO.getId());
Map<String, Integer> parkTimeMap = parktimes.stream().collect(Collectors.toMap(RunPlanParkingTimeVO::getSectionCode, RunPlanParkingTimeVO::getParkingTime));
//查折返
RunPlanUserConfigVO config = runPlanUserConfigService.getConfig(userId, mapVO.getId());
BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertTrue(Objects.nonNull(config) && config.hasReentryData(), "运行图-用户缺少配置或没有配置车站折返数据");
Map<String, String> userReentryData = config.getConfig().getRunPlanUserReentryData();
// 检测折返轨配置
if (Objects.isNull(userReentryData.get(running1Routing.getParkSectionCodeList().get(0).getStationCode()))
|| Objects.isNull(userReentryData.get(running1Routing.getParkSectionCodeList().get(running1Routing.getParkSectionCodeList().size() - 1).getStationCode()))) {
throw BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.exception("折返轨未设置");
}
List<RunPlanTripVO> tripList = new ArrayList<>(100);
ServiceTempResult serviceResult = new ServiceTempResult();
//单个服务号还是多个
if (Objects.nonNull(inputData.getDepartureInterval())) {
do {
generateService(inputData, mapVO, outboundRouting, inboundRouting, outRef, same, other, runLevelMap, parkTimeMap, userReentryData, tripList, serviceResult);
inputData.setServiceNumber(String.format("%03d", Integer.parseInt(inputData.getServiceNumber()) + 1));
inputData.setBeginTime(inputData.getBeginTime().plusSeconds(inputData.getDepartureInterval()));
} while (serviceResult.preServiceDepartTime.plusSeconds(inputData.getDepartureInterval()).compareTo(serviceResult.firstRoundTripTime) <= 0);
} else {
generateService(inputData, mapVO, outboundRouting, inboundRouting, outRef, same, other, runLevelMap, parkTimeMap, userReentryData, tripList, serviceResult);
}
return tripList;
}
private void generateService(RunPlanInputData inputData, MapVO mapVO, RunPlanRoutingVO outboundRouting, RunPlanRoutingVO inboundRouting, RunPlanRoutingVO outRef, final boolean same, RunPlanRoutingVO other, Map<String, Integer> runLevelMap, Map<String, Integer> parkTimeMap, Map<String, String> userReentryData, List<RunPlanTripVO> tripList, ServiceTempResult serviceResult) {
LinkedList<RunPlanTripVO> serviceTripList = new LinkedList<>();
int initTripNumber = 1;
TripTempResult temp = new TripTempResult(initTripNumber, inputData.getBeginTime());
//构建出库车次
buildServiceTrips(inputData, mapVO, outboundRouting, true, runLevelMap, parkTimeMap, userReentryData, serviceTripList, temp);
//计算出库车次运行所需时间
int size = inboundRouting.getParkSectionCodeList().size();
int inboundTripRunTime = inputData.getReentryTime()/2;
for (int i = 0; i < size - 1; i++) {
RunPlanRoutingSection routingSection = inboundRouting.getParkSectionCodeList().get(i);
RunPlanRoutingSection nextRoutingSection = inboundRouting.getParkSectionCodeList().get(i + 1);
Integer parkTime = parkTimeMap.get(routingSection.getSectionCode() );
Integer runTime = runLevelMap.get(routingSection.getSectionCode() + "-" + nextRoutingSection.getSectionCode());
inboundTripRunTime = inboundTripRunTime + parkTime + runTime;
}
//计算出库对接环路运行所需时间
int oSize = outRef.getParkSectionCodeList().size();
int outRefTripRunTime = inputData.getReentryTime()+parkTimeMap.get(outRef.getParkSectionCodeList().get(oSize - 1).getSectionCode());
for (int i = 0; i < oSize - 1; i++) {
RunPlanRoutingSection routingSection = outRef.getParkSectionCodeList().get(i);
RunPlanRoutingSection nextRoutingSection = outRef.getParkSectionCodeList().get(i + 1);
Integer parkTime = parkTimeMap.get(routingSection.getSectionCode());
Integer runTime = runLevelMap.get(routingSection.getSectionCode() + "-" + nextRoutingSection.getSectionCode());
outRefTripRunTime = outRefTripRunTime + parkTime + runTime;
}
//计算另一环路运行所需时间
int iSize = other.getParkSectionCodeList().size();
int otherTripRunTime = inputData.getReentryTime()+parkTimeMap.get(other.getParkSectionCodeList().get(iSize - 1).getSectionCode());
for (int i = 0; i < iSize - 1; i++) {
RunPlanRoutingSection routingSection = other.getParkSectionCodeList().get(i);
RunPlanRoutingSection nextRoutingSection = other.getParkSectionCodeList().get(i + 1);
Integer parkTime = parkTimeMap.get(routingSection.getSectionCode());
Integer runTime = runLevelMap.get(routingSection.getSectionCode() + "-" + nextRoutingSection.getSectionCode());
otherTripRunTime = otherTripRunTime + parkTime + runTime;
}
if (same ? true :
(temp.getLastStationDepartTime().plusSeconds(inputData.getReentryTime()/2 + inboundTripRunTime).isBefore(inputData.getOverTime()) &&
(temp.getLastStationDepartTime().plusSeconds(inputData.getReentryTime()/2).getHour()<3
|| temp.getLastStationDepartTime().plusSeconds(inputData.getReentryTime()/2 + outRefTripRunTime + otherTripRunTime + inboundTripRunTime).getHour()>3))
) {
//构建环路车次
boolean loop = false;
do {
if (same) {
if (!loop) {
buildServiceTrips(inputData, mapVO, outRef, null, runLevelMap, parkTimeMap, userReentryData, serviceTripList, temp);
loop = true;
} else {
buildServiceTrips(inputData, mapVO, other, null, runLevelMap, parkTimeMap, userReentryData, serviceTripList, temp);
buildServiceTrips(inputData, mapVO, outRef, null, runLevelMap, parkTimeMap, userReentryData, serviceTripList, temp);
}
} else {
buildServiceTrips(inputData, mapVO, outRef, null, runLevelMap, parkTimeMap, userReentryData, serviceTripList, temp);
buildServiceTrips(inputData, mapVO, other, null, runLevelMap, parkTimeMap, userReentryData, serviceTripList, temp);
}
}
while (temp.getLastStationDepartTime().plusSeconds(inputData.getReentryTime()/2 + inboundTripRunTime).isBefore(inputData.getOverTime())
&&
(temp.getLastStationDepartTime().plusSeconds(inputData.getReentryTime()/2).getHour()<3||temp.getLastStationDepartTime().plusSeconds(inputData.getReentryTime()/2 + outRefTripRunTime + otherTripRunTime + inboundTripRunTime).getHour()>3));
}
//构建回库计划
buildServiceTrips(inputData, mapVO, inboundRouting, false, runLevelMap, parkTimeMap, userReentryData, serviceTripList, temp);
if (Objects.isNull(serviceResult.getFirstRoundTripTime())) {
serviceResult.setFirstRoundTripTime(serviceTripList.get(1).getEndTime());
}
serviceResult.setPreServiceDepartTime(serviceTripList.getFirst().getStartTime());
tripList.addAll(serviceTripList);
}
private void buildServiceTrips(RunPlanInputData inputData, MapVO mapVO, RunPlanRoutingVO routing, Boolean outbound,
Map<String, Integer> runLevelMap, Map<String, Integer> parkTimeMap, Map<String, String> userReentryData,
LinkedList<RunPlanTripVO> tripList, TripTempResult tempResult) {
String startReentrySectionCode = userReentryData.get(routing.getStartStationCode());
String endReentrySectionCode = userReentryData.get(routing.getEndStationCode());
MapSectionNewVO endReentrySection = null;
if (Objects.nonNull(endReentrySectionCode)) {
endReentrySection = mapVO.findSectionNew(endReentrySectionCode);
}
MapSectionNewVO startReentrySection = null;
if (Objects.nonNull(startReentrySectionCode)) {
startReentrySection = mapVO.findSectionNew(startReentrySectionCode);
}
RunPlanTripVO tripVO = new RunPlanTripVO(routing, startReentrySection, endReentrySection);
setDirectionCode(mapVO, tripVO);
tripVO.setServiceNumber(inputData.getServiceNumber());
tripVO.setTripNumber(tripVO.getDirectionCode() + String.format("%03d", tempResult.getTripNumber()));
tripVO.setIsReentry(true);
if (Objects.nonNull(outbound)) {
if (outbound) {
tripVO.setIsOutbound(true);
} else {
tripVO.setIsInbound(true);
tripVO.setIsReentry(false);
}
}
LinkedList<RunPlanTripTimeVO> tripTimeList = new LinkedList<>();
routing.getParkSectionCodeList().forEach(runPlanRoutingSection -> {
RunPlanTripTimeVO runPlanTripTimeVO = new RunPlanTripTimeVO();
runPlanTripTimeVO.setStationCode(runPlanRoutingSection.getStationCode());
runPlanTripTimeVO.setSectionCode(runPlanRoutingSection.getSectionCode());
runPlanTripTimeVO.setArrivalTime(CollectionUtils.isEmpty(tripList) && CollectionUtils.isEmpty(tripTimeList) ?
tempResult.getLastStationDepartTime() :
(CollectionUtils.isEmpty(tripTimeList) ?
(Objects.equals(tripList.getLast().getEndSectionCode(), runPlanTripTimeVO.getSectionCode()) ?
tripList.getLast().getEndTime() : tempResult.getLastStationDepartTime().plusSeconds(inputData.getReentryTime())) : tempResult.getLastStationDepartTime().plusSeconds(runLevelMap.get(tripTimeList.getLast().getSectionCode() + "-" + runPlanTripTimeVO.getSectionCode()))));
runPlanTripTimeVO.setDepartureTime(CollectionUtils.isEmpty(tripList) && CollectionUtils.isEmpty(tripTimeList) ? tempResult.getLastStationDepartTime() : runPlanTripTimeVO.getArrivalTime().plusSeconds(parkTimeMap.getOrDefault(runPlanTripTimeVO.getSectionCode(), 0)));
tempResult.setLastStationDepartTime(runPlanTripTimeVO.getDepartureTime());
tripTimeList.add(runPlanTripTimeVO);
});
tripVO.setTimeList(tripTimeList);
setTripTerminalTime(tripVO, tripTimeList, inputData.getReentryTime());
tripList.add(tripVO);
tempResult.incrementTripNumber();
}
private void setDirectionCode(MapVO mapVO, RunPlanTripVO tripVO) {
if (mapVO.getConfigVO().getUpRight()) {
if (tripVO.getRight()) {
tripVO.setDirectionCode(BusinessConsts.RunPlan.DirectionType.Type02);
} else {
tripVO.setDirectionCode(BusinessConsts.RunPlan.DirectionType.Type01);
}
} else {
if (tripVO.getRight()) {
tripVO.setDirectionCode(BusinessConsts.RunPlan.DirectionType.Type01);
} else {
tripVO.setDirectionCode(BusinessConsts.RunPlan.DirectionType.Type02);
}
}
}
public void setTripTerminalTime(RunPlanTripVO runPlanTripVO, LinkedList<RunPlanTripTimeVO> tripTimeList, int reentryTime) {
setTripStartTime(runPlanTripVO, tripTimeList, reentryTime);
setTripEndTime(runPlanTripVO, tripTimeList, reentryTime);
}
private void setTripEndTime(RunPlanTripVO lastRunPlanTrip, LinkedList<RunPlanTripTimeVO> tripTimeList, int reentryTime) {
if (Objects.equals(lastRunPlanTrip.getEndSectionCode(), tripTimeList.getLast().getSectionCode())) {
lastRunPlanTrip.setEndTime(tripTimeList.getLast().getDepartureTime());
} else {
lastRunPlanTrip.setEndTime(tripTimeList.getLast().getDepartureTime().plusSeconds(reentryTime / 2));
}
}
private void setTripStartTime(RunPlanTripVO runPlanTripVO, LinkedList<RunPlanTripTimeVO> tripTimeList, int reentryTime) {
if (Objects.equals(runPlanTripVO.getStartSectionCode(), tripTimeList.getFirst().getSectionCode())) {
runPlanTripVO.setStartTime(tripTimeList.getFirst().getArrivalTime());
} else {
runPlanTripVO.setStartTime(tripTimeList.getFirst().getArrivalTime().minusSeconds(reentryTime / 2));
}
}
@Getter
@Setter
@AllArgsConstructor
private class TripTempResult {
private int tripNumber;
private LocalTime lastStationDepartTime;
public void incrementTripNumber() {
tripNumber++;
}
}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
private class ServiceTempResult {
private LocalTime preServiceDepartTime;
private LocalTime firstRoundTripTime;
}
}

View File

@ -0,0 +1,598 @@
package club.joylink.rtss.services.runplan;
import club.joylink.rtss.constants.BusinessConsts;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.vo.client.map.MapVO;
import club.joylink.rtss.vo.client.map.newmap.MapSectionNewVO;
import club.joylink.rtss.vo.client.runplan.RunPlanTripTimeVO;
import club.joylink.rtss.vo.client.runplan.RunPlanTripVO;
import club.joylink.rtss.vo.client.runplan.user.*;
import club.joylink.rtss.vo.runplan.RunPlanInput;
import club.joylink.rtss.vo.runplan.RunPlanInputData;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;
/**
* 通用运行图生成
*/
@Component
public class RunPlanGenerator1 {
private static final int OFFSET_TIME_HOURS = 2; //时间偏移早两小时
@Autowired
private IRunPlanRoutingService runPlanRoutingService;
@Autowired
private IRunPlanRunlevelService runPlanRunlevelService;
@Autowired
private IRunPlanParktimeService runPlanParktimeService;
@Autowired
private IRunPlanUserConfigService runPlanUserConfigService;
public List<RunPlanTripVO> generatorTrips(Long userId, RunPlanInput runPlanInput, MapVO mapVO) {
//校验发车停运时间
BusinessExceptionAssertEnum.DATA_ERROR.assertTrue(runPlanInput.getOverTime().isAfter(runPlanInput.getBeginTime()));
//校验车站
LocalTime beginTimeOffset = runPlanInput.getBeginTime().minusHours(OFFSET_TIME_HOURS);
//向前推两小时如果到前一天则时间不合理
BusinessExceptionAssertEnum.DATA_ERROR.assertTrue(runPlanInput.getBeginTime().isAfter(beginTimeOffset), "发车时间过早,建议晚于上午两点");
runPlanInput.setBeginTime(beginTimeOffset);
runPlanInput.setOverTime(runPlanInput.getOverTime().minusHours(OFFSET_TIME_HOURS));
//检查环路
RunPlanRoutingVO running1Routing = runPlanRoutingService.queryUserRoutingByCode(userId, mapVO.getId(), runPlanInput.getRunningRouting1());
RunPlanRoutingVO running2Routing = runPlanRoutingService.queryUserRoutingByCode(userId, mapVO.getId(), runPlanInput.getRunningRouting2());
boolean isLoop = running1Routing.getParkSectionCodeList().get(0).getStationCode().equals(running2Routing.getParkSectionCodeList().get(running2Routing.getParkSectionCodeList().size() - 1).getStationCode())
&& running2Routing.getParkSectionCodeList().get(0).getStationCode().equals(running1Routing.getParkSectionCodeList().get(running1Routing.getParkSectionCodeList().size() - 1).getStationCode());
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertTrue(isLoop, "运行两交路无法构成环路数据");
//查站间运行等级
List<RunPlanRunlevelVO> levels = runPlanRunlevelService.queryUserRunLevels(userId, mapVO.getId());
Map<String, Integer> runLevelTime = levels.stream().collect(Collectors.toMap(runLevelVO -> String.format("%s-%s", runLevelVO.getStartSectionCode(), runLevelVO.getEndSectionCode()), runLevelVO -> runLevelVO.getLevelTime(runPlanInput.getRunLevel())));
//查停站时间
List<RunPlanParkingTimeVO> parkTimes = runPlanParktimeService.queryUserParktimes(userId, mapVO.getId());
Map<String, Integer> parkTime = parkTimes.stream().collect(Collectors.toMap(RunPlanParkingTimeVO::getSectionCode, RunPlanParkingTimeVO::getParkingTime));
//查折返
RunPlanUserConfigVO config = runPlanUserConfigService.getConfig(userId, mapVO.getId());
Map<String, RunPlanUserConfigVO.ReentryTime> userReentryData = checkStationReentry(mapVO, running1Routing, config);
//生成车次
LinkedList<RunPlanTripVO> tripList = new LinkedList<>();
//是否同时相向发车
boolean opposite = Objects.isNull(runPlanInput.getRight());
if (opposite) {
//相向发车
int initialServiceNum = 1;
/*分别先发一辆车,计算控制左右发车服务号*/
//上个服务号发车时刻
//首班发车时间,首班车往返回来时间 来限定发车服务数量
ServiceTempResult tempResultLeft = new ServiceTempResult(runPlanInput.getBeginTime(), null);
serviceNumberDepart(mapVO, runPlanInput, running1Routing, running2Routing, initialServiceNum++, tripList, tempResultLeft, false, runLevelTime, parkTime, userReentryData);
//上个服务号发车时刻
//首班发车时间,首班车往返回来时间 来限定发车服务数量
ServiceTempResult tempResultRight = new ServiceTempResult(runPlanInput.getBeginTime(), null);
serviceNumberDepart(mapVO, runPlanInput, running1Routing, running2Routing, initialServiceNum++, tripList, tempResultRight, true, runLevelTime, parkTime, userReentryData);
LocalTime firstRoundTripTimeLeft = tempResultLeft.getFirstRoundTripTime();
LocalTime firstRoundTripTimeRight = tempResultRight.getFirstRoundTripTime();
tempResultRight.setFirstRoundTripTime(firstRoundTripTimeLeft);
tempResultLeft.setFirstRoundTripTime(firstRoundTripTimeRight);
//暂时先定义发完左行再发右行..
do {
tempResultLeft.setPreServiceDepartTime(tempResultLeft.getPreServiceDepartTime().plusSeconds(runPlanInput.getDepartureTimeInterval()));
serviceNumberDepart(mapVO, runPlanInput, running1Routing, running2Routing, initialServiceNum++, tripList, tempResultLeft, false, runLevelTime, parkTime, userReentryData);
} while (tempResultLeft.getPreServiceDepartTime().plusSeconds(runPlanInput.getDepartureTimeInterval()).compareTo(tempResultLeft.getFirstRoundTripTime()) <= 0);
//发完左行再发右行
do {
tempResultRight.setPreServiceDepartTime(tempResultRight.getPreServiceDepartTime().plusSeconds(runPlanInput.getDepartureTimeInterval()));
serviceNumberDepart(mapVO, runPlanInput, running1Routing, running2Routing, initialServiceNum++, tripList, tempResultRight, true, runLevelTime, parkTime, userReentryData);
} while (tempResultRight.getPreServiceDepartTime().plusSeconds(runPlanInput.getDepartureTimeInterval()).compareTo(tempResultRight.getFirstRoundTripTime()) <= 0);
} else {
//单向发车
allServiceNumberDepart(mapVO, runPlanInput, running1Routing, running2Routing, tripList, runLevelTime, parkTime, userReentryData);
}
return tripList;
}
/**
* 服务号发车
*/
private void serviceNumberDepart(MapVO mapVO, RunPlanInput runPlanInput, RunPlanRoutingVO running1Routing, RunPlanRoutingVO running2Routing, int initialServiceNum, LinkedList<RunPlanTripVO> tripList, ServiceTempResult serviceTempResult, boolean isRight, Map<String, Integer> runLevelMap, Map<String, Integer> parkTimeMap, Map<String, RunPlanUserConfigVO.ReentryTime> reentryData) {
String serviceNumber = String.format("%03d", initialServiceNum);
//初始化车次号,右行偶数左行奇数
int initTripNumber = isRight ? 0 : 1;
LocalTime lastTripEndTime;//一个车次终点时间
LinkedList<RunPlanTripVO> tempTripList = new LinkedList<>();
String endStation = null;
//根据运行时间判断结束末班车次
do {
RunPlanRoutingVO routing = Objects.equals(running1Routing.getRight(), isRight) ? running1Routing : running2Routing;
RunPlanTripVO runPlanTripVO = new RunPlanTripVO(routing);
runPlanTripVO.setServiceNumber(serviceNumber);
setDirectionCode(mapVO, runPlanTripVO);
runPlanTripVO.setIsReentry(true);
//车次号
String tripNumber = String.format("%03d", initTripNumber++);
runPlanTripVO.setTripNumber(runPlanTripVO.getDirectionCode() + tripNumber);
//首班右行方向
LinkedList<RunPlanTripTimeVO> tripTimeList = new LinkedList<>();//车次时刻表
int size = routing.getParkSectionCodeList().size();
for (int i = 0; i < size; i++) {
RunPlanRoutingSection routingSection = routing.getParkSectionCodeList().get(i);
RunPlanTripTimeVO runPlanTripTimeVO = new RunPlanTripTimeVO();
runPlanTripTimeVO.setStationCode(routingSection.getStationCode());
runPlanTripTimeVO.setSectionCode(routingSection.getSectionCode());
if (CollectionUtils.isEmpty(tempTripList) && i == 0) {//首发车次
runPlanTripTimeVO.setArrivalTime(serviceTempResult.getPreServiceDepartTime());
runPlanTripTimeVO.setDepartureTime(runPlanTripTimeVO.getArrivalTime());
} else if (i == 0) { //其它车次发车
if (!startTBIsFront(routing, mapVO)) {
continue;
}
RunPlanUserConfigVO.ReentryTime reentryTime = reentryData.get(routingSection.getStationCode());
runPlanTripTimeVO.setArrivalTime(
tempTripList.getLast().getEndTime().plusSeconds(reentryTime.getTbFront() - parkTimeMap.get(runPlanTripTimeVO.getSectionCode()) * 2));
runPlanTripTimeVO.setDepartureTime(runPlanTripTimeVO.getArrivalTime().plusSeconds(parkTimeMap.get(runPlanTripTimeVO.getSectionCode())));
} else if (i == size - 1) {
Boolean endTBIsFront = endTBIsFront(routing, mapVO);
if (Objects.nonNull(endTBIsFront) && !endTBIsFront) {
continue;
}
runPlanTripTimeVO.setArrivalTime(CollectionUtils.isEmpty(tripTimeList)?tripList.getLast().getEndTime().plusSeconds(45)
: tripTimeList.getLast().getDepartureTime().plusSeconds(runLevelMap.get(tripTimeList.getLast().getSectionCode() + "-" + runPlanTripTimeVO.getSectionCode())));
runPlanTripTimeVO.setDepartureTime(Objects.isNull(endTBIsFront)
? runPlanTripTimeVO.getArrivalTime()
: runPlanTripTimeVO.getArrivalTime().plusSeconds(parkTimeMap.get(runPlanTripTimeVO.getSectionCode())));
} else {
Boolean startTBIsFront = startTBIsFront(routing, mapVO);
if (i == 1 && Objects.nonNull(startTBIsFront) && !startTBIsFront) {
RunPlanUserConfigVO.ReentryTime reentryTime = reentryData.get( routing.getStartStationCode());
runPlanTripTimeVO.setArrivalTime(CollectionUtils.isEmpty(tempTripList)?serviceTempResult.getPreServiceDepartTime():tempTripList.getLast().getEndTime().plusSeconds(reentryTime.getTbBack() - reentryTime.getTbFrom()));
runPlanTripTimeVO.setDepartureTime(runPlanTripTimeVO.getArrivalTime());
}else{
runPlanTripTimeVO.setArrivalTime(tripTimeList.getLast().getDepartureTime().plusSeconds(runLevelMap.get(tripTimeList.getLast().getSectionCode() + "-" + runPlanTripTimeVO.getSectionCode())));
runPlanTripTimeVO.setDepartureTime(runPlanTripTimeVO.getArrivalTime().plusSeconds(parkTimeMap.get(runPlanTripTimeVO.getSectionCode())));
}
}
tripTimeList.add(runPlanTripTimeVO);
}
runPlanTripVO.setTimeList(tripTimeList);
setTripTerminalTime(runPlanTripVO, routing,tripTimeList,reentryData);
lastTripEndTime = runPlanTripVO.getEndTime();
if(CollectionUtils.isEmpty(tempTripList)){
runPlanTripVO.setIsOutbound(true);
}
tempTripList.add(runPlanTripVO);
if (tempTripList.size() > 50) { // 最快半小时跑一趟的一天车次数如果大于这个可能死循环此时停止发车
break;
}
isRight = !isRight;
endStation = routing.getEndStationCode();
} while (lastTripEndTime.isBefore(runPlanInput.getOverTime()));
//设置服务号末班车次入库
RunPlanTripVO lastrunPlanTrip = tempTripList.getLast();
lastrunPlanTrip.setIsInbound(true);
lastrunPlanTrip.setIsReentry(false);
LinkedList<RunPlanTripTimeVO> tripTimeList = (LinkedList) lastrunPlanTrip.getTimeList();
setTripEndTime(lastrunPlanTrip, endStation, tripTimeList, reentryData);
tripList.addAll(tempTripList);
if (Objects.isNull(serviceTempResult.getFirstRoundTripTime())) {
serviceTempResult.setFirstRoundTripTime(tempTripList.get(0).getEndTime());
}
serviceTempResult.setPreServiceDepartTime(tempTripList.getFirst().getStartTime());
}
/**
* 单向发车
*/
private void allServiceNumberDepart(MapVO mapVO, RunPlanInput runPlanInput, RunPlanRoutingVO running1Routing, RunPlanRoutingVO running2Routing, LinkedList<RunPlanTripVO> tripList, Map<String, Integer> runLevelTime, Map<String, Integer> parkTime, Map<String, RunPlanUserConfigVO.ReentryTime> userReentryData) {
//设置初始服务号
int initialServiceNum = 1;
//上个服务号发车时刻
//首班发车时间,首班车往返回来时间 来限定发车服务数量
ServiceTempResult serviceTempResult = new ServiceTempResult(runPlanInput.getBeginTime(), null);
do {
if (initialServiceNum != 1) {
if(initialServiceNum==2){
serviceTempResult.setFirstRoundTripTime(tripList.get(1).getEndTime());
}
serviceTempResult.setPreServiceDepartTime(serviceTempResult.getPreServiceDepartTime().plusSeconds(runPlanInput.getDepartureTimeInterval()));
}
serviceNumberDepart(mapVO, runPlanInput, running1Routing, running2Routing, initialServiceNum++, tripList, serviceTempResult, runPlanInput.getRight(), runLevelTime, parkTime, userReentryData);
} while (serviceTempResult.getPreServiceDepartTime().plusSeconds(runPlanInput.getDepartureTimeInterval()).compareTo(serviceTempResult.getFirstRoundTripTime()) <= 0);
}
public List<RunPlanTripVO> generatorTrips(Long userId, RunPlanInputData inputData, MapVO mapVO) {
//校验时间
BusinessExceptionAssertEnum.DATA_ERROR.assertTrue(inputData.getOverTime().isAfter(inputData.getBeginTime()),"输入参数错误:发车时间应早于结束时间");
LocalTime beginTimeOffset = inputData.getBeginTime().minusHours(OFFSET_TIME_HOURS);
//向前推两小时如果到前一天则时间不合理
BusinessExceptionAssertEnum.DATA_ERROR.assertTrue(inputData.getBeginTime().isAfter(beginTimeOffset), "发车时间过早,建议晚于上午两点");
inputData.setBeginTime(beginTimeOffset);
inputData.setOverTime(inputData.getOverTime().minusHours(OFFSET_TIME_HOURS));
//查交路
RunPlanRoutingVO outboundRouting = null;
if (inputData.hasOutbound()) {
outboundRouting = runPlanRoutingService.queryUserRoutingByCode(userId, mapVO.getId(), inputData.getOutboundRouting());
BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(outboundRouting.isOutBoundRoute(), "出库交路选择错误");
}
RunPlanRoutingVO inboundRouting = null;
if (inputData.hasInbound()) {
inboundRouting = runPlanRoutingService.queryUserRoutingByCode(userId, mapVO.getId(), inputData.getInboundRouting());
BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(inboundRouting.isInBoundRoute(), "入库交路选择错误");
}
RunPlanRoutingVO running1Routing = runPlanRoutingService.queryUserRoutingByCode(userId, mapVO.getId(), inputData.getRunningRouting1());
RunPlanRoutingVO running2Routing = runPlanRoutingService.queryUserRoutingByCode(userId, mapVO.getId(), inputData.getRunningRouting2());
BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(running1Routing.isLoopRoute() && running2Routing.isLoopRoute(), "环线交路选择错误");
//构建环路 出入库关系
//验证 出库和入库 一端折返轨 一段转换轨验证环路 两端折返轨 环路是否闭环 或出入库跟环路是否衔接
boolean isLoop = running1Routing.getParkSectionCodeList().get(0).getSectionCode().equals(running2Routing.getParkSectionCodeList().get(running2Routing.getParkSectionCodeList().size() - 1).getSectionCode())
&& running2Routing.getParkSectionCodeList().get(0).getSectionCode().equals(running1Routing.getParkSectionCodeList().get(running1Routing.getParkSectionCodeList().size() - 1).getSectionCode());
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertTrue(isLoop, "运行两交路无法构成环路数据");
boolean outToRun1 = outboundRouting.getParkSectionCodeList().get(outboundRouting.getParkSectionCodeList().size() - 1).getSectionCode().equals(running1Routing.getParkSectionCodeList().get(0).getSectionCode());
boolean outToRun2 = outboundRouting.getParkSectionCodeList().get(outboundRouting.getParkSectionCodeList().size() - 1).getSectionCode().equals(running2Routing.getParkSectionCodeList().get(0).getSectionCode());
boolean inToRun1 = inboundRouting.getParkSectionCodeList().get(0).getSectionCode().equals(running1Routing.getParkSectionCodeList().get(running1Routing.getParkSectionCodeList().size() - 1).getSectionCode());
boolean inToRun2 = inboundRouting.getParkSectionCodeList().get(0).getSectionCode().equals(running2Routing.getParkSectionCodeList().get(running2Routing.getParkSectionCodeList().size() - 1).getSectionCode());
//出库的衔接环路
RunPlanRoutingVO outRefLoop;
//另一个交路
RunPlanRoutingVO otherLoop;
boolean same = false;
if (outToRun1 && inToRun1) {
same = true;
outRefLoop = running1Routing;
otherLoop = running2Routing;
} else if (outToRun2 && inToRun2) {
same = true;
outRefLoop = running2Routing;
otherLoop = running1Routing;
} else if (outToRun1 && inToRun2) {
outRefLoop = running1Routing;
otherLoop = running2Routing;
} else if (outToRun2 && inToRun1) {
outRefLoop = running2Routing;
otherLoop = running1Routing;
} else {
throw BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.exception("出入库交路与运行环路无法衔接匹配");
}
//查站间运行等级
List<RunPlanRunlevelVO> levels = runPlanRunlevelService.queryUserRunLevels(userId, mapVO.getId());
Map<String, Integer> runLevelMap = levels.stream().collect(Collectors.toMap(runLevelVO -> String.format("%s-%s", runLevelVO.getStartSectionCode(), runLevelVO.getEndSectionCode()), runLevelVO -> runLevelVO.getLevelTime(inputData.getRunLevel())));
//查停站时间
List<RunPlanParkingTimeVO> parktimes = runPlanParktimeService.queryUserParktimes(userId, mapVO.getId());
Map<String, Integer> parkTimeMap = parktimes.stream().collect(Collectors.toMap(RunPlanParkingTimeVO::getSectionCode, RunPlanParkingTimeVO::getParkingTime));
//查折返
RunPlanUserConfigVO config = runPlanUserConfigService.getConfig(userId, mapVO.getId());
Map<String, RunPlanUserConfigVO.ReentryTime> reentryData = checkStationReentry(mapVO, running1Routing, config);
List<RunPlanTripVO> tripList = new ArrayList<>(100);
ServiceTempResult serviceResult = new ServiceTempResult();
//单个服务号还是多个
if (Objects.nonNull(inputData.getDepartureInterval())) {
do {
generateService(inputData, mapVO, outboundRouting, inboundRouting, outRefLoop, same, otherLoop, runLevelMap, parkTimeMap, reentryData, tripList, serviceResult);
inputData.setServiceNumber(String.format("%03d", Integer.parseInt(inputData.getServiceNumber()) + 1));
inputData.setBeginTime(inputData.getBeginTime().plusSeconds(inputData.getDepartureInterval()));
} while (serviceResult.preServiceDepartTime.plusSeconds(inputData.getDepartureInterval()).compareTo(serviceResult.firstRoundTripTime) <= 0);
} else {
generateService(inputData, mapVO, outboundRouting, inboundRouting, outRefLoop, same, otherLoop, runLevelMap, parkTimeMap, reentryData, tripList, serviceResult);
}
return tripList;
}
private Map<String, RunPlanUserConfigVO.ReentryTime> checkStationReentry(MapVO mapVO, RunPlanRoutingVO running1Routing, RunPlanUserConfigVO config) {
BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertTrue(Objects.nonNull(config) && config.hasReentryData(), "请配置所选运行线路折返数据");
Map<String, RunPlanUserConfigVO.ReentryTime> reentryData = config.getConfig().getReentryData();
// 检测折返站配置
String startStationCode = running1Routing.getParkSectionCodeList().get(0).getStationCode();
String endStationCode = running1Routing.getParkSectionCodeList().get(running1Routing.getParkSectionCodeList().size() - 1).getStationCode();
if (Objects.isNull(reentryData.get(startStationCode))) {
throw BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.exception(String.format("车站[%s]缺少折返数据", mapVO.findStation(startStationCode).getName()));
}
if(Objects.isNull(reentryData.get(endStationCode))){
throw BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.exception(String.format("车站[%s]缺少折返数据", mapVO.findStation(endStationCode).getName()));
}
Boolean startTBIsFront = startTBIsFront(running1Routing, mapVO);
if(Objects.nonNull(startTBIsFront) ){
if (startTBIsFront) {
BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertTrue(Objects.nonNull(reentryData.get(startStationCode).getTbFront()), String.format("车站[%s]请配置站前折返数据", mapVO.findStation(startStationCode).getName()));
} else {
BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertTrue(Objects.nonNull(reentryData.get(startStationCode).getTbBack()), String.format("车站[%s]请配置站后折返数据", mapVO.findStation(startStationCode).getName()));
}
}
Boolean endTBIsFront = endTBIsFront(running1Routing, mapVO);
if(Objects.nonNull(endTBIsFront) ){
if (endTBIsFront) {
BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertTrue(Objects.nonNull(reentryData.get(endStationCode).getTbFront()), String.format("车站[%s]请配置站前折返数据", mapVO.findStation(endStationCode).getName()));
} else {
BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertTrue(Objects.nonNull(reentryData.get(endStationCode).getTbBack()), String.format("车站[%s]请配置站后折返数据", mapVO.findStation(endStationCode).getName()));
}
}
return reentryData;
}
private void generateService(RunPlanInputData inputData, MapVO mapVO, RunPlanRoutingVO outboundRouting, RunPlanRoutingVO inboundRouting, RunPlanRoutingVO outRefLoop, final boolean same, RunPlanRoutingVO otherLoop, Map<String, Integer> runLevelMap, Map<String, Integer> parkTimeMap, Map<String, RunPlanUserConfigVO.ReentryTime> reentryData, List<RunPlanTripVO> tripList, ServiceTempResult serviceResult) {
LinkedList<RunPlanTripVO> serviceTripList = new LinkedList<>();
int nextTripNumber = 1;
//构建出库车次
nextTripNumber = buildServiceTrip(inputData, mapVO, outboundRouting, runLevelMap, parkTimeMap, reentryData, serviceTripList, nextTripNumber);
//计算入库车次运行所需时间
int num = inboundRouting.getParkSectionCodeList().size() - 1;
int inboundTripRunTime = 0;
int parkTime=0;
int runTime;
for (int i = 0; i < num - 1; i++) {
RunPlanRoutingSection routingSection = inboundRouting.getParkSectionCodeList().get(i);
RunPlanRoutingSection nextRoutingSection = inboundRouting.getParkSectionCodeList().get(i + 1);
if (i == 0) {
if (startTBIsFront(inboundRouting, mapVO)) {
parkTime = reentryData.get(routingSection.getStationCode()).getTbFront() - parkTimeMap.get(routingSection.getSectionCode());
runTime = runLevelMap.get(routingSection.getSectionCode() + "-" + nextRoutingSection.getSectionCode());
} else {
runTime = reentryData.get(routingSection.getStationCode()).getTbBack() - reentryData.get(routingSection.getStationCode()).getTbFrom();
}
} else {
parkTime = parkTimeMap.get(routingSection.getSectionCode());
runTime = runLevelMap.get(routingSection.getSectionCode() + "-" + nextRoutingSection.getSectionCode());
}
inboundTripRunTime = inboundTripRunTime + parkTime + runTime;
parkTime = 0;
}
//计算出库对接环路运行所需时间
int oNum = outRefLoop.getParkSectionCodeList().size() - 1;
int outRefTripRunTime = 0;
for (int i = 0; i < oNum; i++) {
RunPlanRoutingSection routingSection = outRefLoop.getParkSectionCodeList().get(i);
RunPlanRoutingSection nextRoutingSection = outRefLoop.getParkSectionCodeList().get(i + 1);
if(i==0){
if(startTBIsFront(outRefLoop, mapVO)){
parkTime = reentryData.get(routingSection.getStationCode()).getTbFront()- parkTimeMap.get(routingSection.getSectionCode());
runTime = runLevelMap.get(routingSection.getSectionCode() + "-" + nextRoutingSection.getSectionCode());
}else {
runTime = reentryData.get(routingSection.getStationCode()).getTbBack()-reentryData.get(routingSection.getStationCode()).getTbFrom();
}
}else if(i == oNum-1){
if(endTBIsFront(outRefLoop,mapVO )){
parkTime = parkTimeMap.get(routingSection.getSectionCode())+parkTimeMap.get(routingSection.getSectionCode());
runTime = runLevelMap.get(routingSection.getSectionCode() + "-" + nextRoutingSection.getSectionCode());
}else{
parkTime = parkTimeMap.get(routingSection.getSectionCode());
runTime = reentryData.get(nextRoutingSection.getStationCode()).getTbFrom();
}
}else{
parkTime = parkTimeMap.get(routingSection.getSectionCode());
runTime = runLevelMap.get(routingSection.getSectionCode() + "-" + nextRoutingSection.getSectionCode());
}
outRefTripRunTime = outRefTripRunTime + parkTime + runTime;
parkTime = 0;
}
//计算另一环路运行所需时间
int iNum = otherLoop.getParkSectionCodeList().size()-1;
int otherTripRunTime = 0;
for (int i = 0; i < iNum; i++) {
RunPlanRoutingSection routingSection = otherLoop.getParkSectionCodeList().get(i);
RunPlanRoutingSection nextRoutingSection = otherLoop.getParkSectionCodeList().get(i + 1);
if(i==0){
if(startTBIsFront(otherLoop, mapVO)){
parkTime = reentryData.get(routingSection.getStationCode()).getTbFront()- parkTimeMap.get(routingSection.getSectionCode());
runTime = runLevelMap.get(routingSection.getSectionCode() + "-" + nextRoutingSection.getSectionCode());
}else {
runTime = reentryData.get(routingSection.getStationCode()).getTbBack()-reentryData.get(routingSection.getStationCode()).getTbFrom();
}
}else if(i == oNum-1){
if(endTBIsFront(otherLoop,mapVO )){
parkTime = parkTimeMap.get(routingSection.getSectionCode())+parkTimeMap.get(routingSection.getSectionCode());
runTime = runLevelMap.get(routingSection.getSectionCode() + "-" + nextRoutingSection.getSectionCode());
}else{
parkTime = parkTimeMap.get(routingSection.getSectionCode());
runTime = reentryData.get(nextRoutingSection.getStationCode()).getTbFrom();
}
}else{
parkTime = parkTimeMap.get(routingSection.getSectionCode());
runTime = runLevelMap.get(routingSection.getSectionCode() + "-" + nextRoutingSection.getSectionCode());
}
otherTripRunTime = otherTripRunTime + parkTime + runTime;
parkTime = 0;
}
if (same ? true :
(serviceTripList.getLast().getEndTime().plusSeconds(inboundTripRunTime).isBefore(inputData.getOverTime()) &&
(serviceTripList.getLast().getEndTime().getHour()<3
|| serviceTripList.getLast().getEndTime().plusSeconds(outRefTripRunTime + otherTripRunTime + inboundTripRunTime).getHour() > 3))
) {
//构建环路车次
boolean loop = false;
do {
if (same) {
if (!loop) {
nextTripNumber = buildServiceTrip(inputData, mapVO, outRefLoop, runLevelMap, parkTimeMap, reentryData, serviceTripList, nextTripNumber);
loop = true;
} else {
nextTripNumber = buildServiceTrip(inputData, mapVO, otherLoop, runLevelMap, parkTimeMap, reentryData, serviceTripList, nextTripNumber);
nextTripNumber = buildServiceTrip(inputData, mapVO, outRefLoop, runLevelMap, parkTimeMap, reentryData, serviceTripList, nextTripNumber);
}
} else {
nextTripNumber = buildServiceTrip(inputData, mapVO, outRefLoop, runLevelMap, parkTimeMap, reentryData, serviceTripList, nextTripNumber);
nextTripNumber = buildServiceTrip(inputData, mapVO, otherLoop, runLevelMap, parkTimeMap, reentryData, serviceTripList, nextTripNumber);
}
}
while (serviceTripList.getLast().getEndTime().plusSeconds(inboundTripRunTime).isBefore(inputData.getOverTime())
&&
(serviceTripList.getLast().getEndTime().getHour() < 3 || serviceTripList.getLast().getEndTime().plusSeconds(outRefTripRunTime + otherTripRunTime + inboundTripRunTime).getHour() > 3));
}
//构建回库计划
buildServiceTrip(inputData, mapVO, inboundRouting, runLevelMap, parkTimeMap, reentryData, serviceTripList, nextTripNumber);
if (Objects.isNull(serviceResult.getFirstRoundTripTime())) {
serviceResult.setFirstRoundTripTime(serviceTripList.get(1).getEndTime());
}
serviceResult.setPreServiceDepartTime(serviceTripList.getFirst().getStartTime());
tripList.addAll(serviceTripList);
}
private int buildServiceTrip(RunPlanInputData inputData, MapVO mapVO, RunPlanRoutingVO routing,
Map<String, Integer> runLevelMap, Map<String, Integer> parkTimeMap, Map<String, RunPlanUserConfigVO.ReentryTime> reentryData,
LinkedList<RunPlanTripVO> tripList, int tripNumber) {
RunPlanTripVO tripVO = new RunPlanTripVO(routing);
setDirectionCode(mapVO, tripVO);
tripVO.setServiceNumber(inputData.getServiceNumber());
tripVO.setTripNumber(tripVO.getDirectionCode() + String.format("%03d", tripNumber));
tripVO.setIsReentry(true);
if (routing.isOutBoundRoute()) {
tripVO.setIsOutbound(true);
}
if (routing.isInBoundRoute()) {
tripVO.setIsInbound(true);
tripVO.setIsReentry(false);
}
LinkedList<RunPlanTripTimeVO> tripTimeList = new LinkedList<>();
int size = routing.getParkSectionCodeList().size();
for (int i = 0; i < size; i++) {
RunPlanRoutingSection routingSection = routing.getParkSectionCodeList().get(i);
RunPlanTripTimeVO runPlanTripTimeVO = new RunPlanTripTimeVO();
runPlanTripTimeVO.setStationCode(routingSection.getStationCode());
runPlanTripTimeVO.setSectionCode(routingSection.getSectionCode());
if (CollectionUtils.isEmpty(tripList) && i == 0) {//首发车次
runPlanTripTimeVO.setArrivalTime(inputData.getBeginTime());
runPlanTripTimeVO.setDepartureTime(runPlanTripTimeVO.getArrivalTime());
} else if (i == 0) { //其它车次发车
if (!startTBIsFront(routing, mapVO)) {
continue;
}
RunPlanUserConfigVO.ReentryTime reentryTime = reentryData.get(routingSection.getStationCode());
runPlanTripTimeVO.setArrivalTime(
tripList.getLast().getEndTime().plusSeconds(reentryTime.getTbFront() - parkTimeMap.get(runPlanTripTimeVO.getSectionCode()) * 2));
runPlanTripTimeVO.setDepartureTime(runPlanTripTimeVO.getArrivalTime().plusSeconds(parkTimeMap.get(runPlanTripTimeVO.getSectionCode())));
} else if (i == size - 1) {
Boolean endTBIsFront = endTBIsFront(routing, mapVO);
if (Objects.nonNull(endTBIsFront) && !endTBIsFront) {
continue;
}
runPlanTripTimeVO.setArrivalTime(CollectionUtils.isEmpty(tripTimeList)?tripList.getLast().getEndTime().plusSeconds(45)
: tripTimeList.getLast().getDepartureTime().plusSeconds(runLevelMap.get(tripTimeList.getLast().getSectionCode() + "-" + runPlanTripTimeVO.getSectionCode())));
runPlanTripTimeVO.setDepartureTime(Objects.isNull(endTBIsFront)
? runPlanTripTimeVO.getArrivalTime()
: runPlanTripTimeVO.getArrivalTime().plusSeconds(parkTimeMap.get(runPlanTripTimeVO.getSectionCode())));
} else {
Boolean startTBIsFront = startTBIsFront(routing, mapVO);
if (i == 1 && Objects.nonNull(startTBIsFront) && !startTBIsFront) {
RunPlanUserConfigVO.ReentryTime reentryTime = reentryData.get(routing.getStartStationCode());
runPlanTripTimeVO.setArrivalTime(CollectionUtils.isEmpty(tripList)?inputData.getBeginTime():tripList.getLast().getEndTime().plusSeconds(reentryTime.getTbBack() - reentryTime.getTbFrom()));
runPlanTripTimeVO.setDepartureTime(runPlanTripTimeVO.getArrivalTime());
}else{
runPlanTripTimeVO.setArrivalTime(tripTimeList.getLast().getDepartureTime().plusSeconds(runLevelMap.get(tripTimeList.getLast().getSectionCode() + "-" + runPlanTripTimeVO.getSectionCode())));
runPlanTripTimeVO.setDepartureTime(runPlanTripTimeVO.getArrivalTime().plusSeconds(parkTimeMap.get(runPlanTripTimeVO.getSectionCode())));
}
}
tripTimeList.add(runPlanTripTimeVO);
}
tripVO.setTimeList(tripTimeList);
setTripTerminalTime(tripVO, routing,tripTimeList, reentryData);
tripList.add(tripVO);
return ++tripNumber;
}
private void setDirectionCode(MapVO mapVO, RunPlanTripVO tripVO) {
if (mapVO.getConfigVO().getUpRight()) {
if (tripVO.getRight()) {
tripVO.setDirectionCode(BusinessConsts.RunPlan.DirectionType.Type02);
} else {
tripVO.setDirectionCode(BusinessConsts.RunPlan.DirectionType.Type01);
}
} else {
if (tripVO.getRight()) {
tripVO.setDirectionCode(BusinessConsts.RunPlan.DirectionType.Type01);
} else {
tripVO.setDirectionCode(BusinessConsts.RunPlan.DirectionType.Type02);
}
}
}
public void setTripTerminalTime(RunPlanTripVO runPlanTripVO, RunPlanRoutingVO routing,LinkedList<RunPlanTripTimeVO> tripTimeList, Map<String, RunPlanUserConfigVO.ReentryTime> reentryData) {
setTripStartTime(runPlanTripVO, routing.getStartStationCode(),tripTimeList, reentryData);
setTripEndTime(runPlanTripVO, routing.getEndStationCode(),tripTimeList, reentryData);
}
private void setTripStartTime(RunPlanTripVO runPlanTripVO, String startStation,LinkedList<RunPlanTripTimeVO> tripTimeList, Map<String, RunPlanUserConfigVO.ReentryTime> reentryData) {
RunPlanTripTimeVO firstTripTime = tripTimeList.getFirst();
if (Objects.equals(runPlanTripVO.getStartSectionCode(), firstTripTime.getSectionCode())) {
runPlanTripVO.setStartTime(tripTimeList.getFirst().getArrivalTime());
} else {
// BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertTrue(Objects.nonNull(reentryData.get(firstTripTime.getStationCode()).getTbTo()), String.format("车站[%s]折返数据请配置折返轨至起始股道",firstTripTime.getStationCode()));
runPlanTripVO.setStartTime(firstTripTime.getArrivalTime().minusSeconds(reentryData.get(startStation).getTbTo()));
}
}
private void setTripEndTime(RunPlanTripVO runPlanTripVO, String endStation,LinkedList<RunPlanTripTimeVO> tripTimeList, Map<String, RunPlanUserConfigVO.ReentryTime> reentryData) {
RunPlanTripTimeVO lastTripTime = tripTimeList.getLast();
if (Objects.equals(runPlanTripVO.getEndSectionCode(), lastTripTime.getSectionCode())) {
runPlanTripVO.setEndTime(lastTripTime.getDepartureTime());
} else if(Objects.equals(runPlanTripVO.getStartSectionCode(), lastTripTime.getSectionCode())){
runPlanTripVO.setEndTime(lastTripTime.getDepartureTime().plusSeconds(45));//转换轨直接到折返轨的交路
} else{
// BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertTrue(Objects.nonNull(reentryData.get(lastTripTime.getStationCode()).getTbFrom()), String.format("车站[%s]折返数据请配置轨道至折返轨",lastTripTime.getStationCode()));
runPlanTripVO.setEndTime(lastTripTime.getDepartureTime().plusSeconds(reentryData.get(endStation).getTbFrom()));
}
}
public Boolean startTBIsFront(RunPlanRoutingVO runningRouting, MapVO mapVO) {
MapSectionNewVO startReentrySection = mapVO.findSection(runningRouting.getStartSectionCode());
if (startReentrySection.isReentryTrack()) {
if (startReentrySection.isStandTrack()) {
return true;
}
return false;
}
return null;
}
public Boolean endTBIsFront(RunPlanRoutingVO runningRouting, MapVO mapVO) {
MapSectionNewVO endReentrySection = mapVO.findSection(runningRouting.getEndSectionCode());
if (endReentrySection.isReentryTrack()) {
if (endReentrySection.isStandTrack()) {
return true;
}
return false;
}
return null;
}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
private class ServiceTempResult {
private LocalTime preServiceDepartTime;
private LocalTime firstRoundTripTime;
}
}

View File

@ -11,7 +11,6 @@ import club.joylink.rtss.simulation.cbtc.build.SimulationBuilder;
import club.joylink.rtss.simulation.cbtc.data.CalculateService;
import club.joylink.rtss.simulation.cbtc.data.map.MapElement;
import club.joylink.rtss.simulation.cbtc.data.map.Section;
import club.joylink.rtss.simulation.cbtc.data.support.SectionPosition;
import club.joylink.rtss.simulation.cbtc.exception.SimulationException;
import club.joylink.rtss.util.JsonUtils;
import club.joylink.rtss.vo.client.PageVO;
@ -21,6 +20,7 @@ import club.joylink.rtss.vo.client.runplan.RunPlanVO;
import club.joylink.rtss.vo.client.runplan.user.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -47,13 +47,16 @@ public class RunPlanRoutingService implements IRunPlanRoutingService {
@Autowired
private IRunPlanParktimeService planParktimeService;
@Autowired
private IRunPlanUserConfigService planConfigService;
@Autowired
private IMapService iMapService;
@Transactional
@Override
public void createUserRouting(RunPlanRoutingVO routingVO) {
BusinessExceptionAssertEnum.DATA_ALREADY_EXIST.assertNotTrue(ifRoutingDataExist(routingVO),"存在相同经停轨道的交路");
BusinessExceptionAssertEnum.DATA_ALREADY_EXIST.assertNotTrue(ifRoutingDataExist(routingVO), "存在相同经停轨道的交路");
MapVO map = this.iMapService.getMapDetail(routingVO.getMapId());
SimulationBuilder.SimulationDeviceBuildResult buildResult = SimulationBuilder.checkAndBuildMapDeviceData(map);
BusinessExceptionAssertEnum.DATA_ERROR.assertCollectionEmpty(buildResult.getErrMsgList(),
@ -61,23 +64,24 @@ public class RunPlanRoutingService implements IRunPlanRoutingService {
Map<String, MapElement> deviceMap = buildResult.getDeviceMap();
Section startSection = (Section) deviceMap.get(routingVO.getStartSectionCode());
Section endSection = (Section) deviceMap.get(routingVO.getEndSectionCode());
if (startSection.isTransferTrack() && endSection.isTransferTrack()) {
routingVO.setRoutingType(RunPlanRoutingVO.UserRoutingType.OTHER);
} else if (startSection.isTransferTrack()) {
if (startSection.isTransferTrack() && endSection.isTurnBackTrack()) {
routingVO.setRoutingType(RunPlanRoutingVO.UserRoutingType.OUTBOUND);
} else if (endSection.isTransferTrack()) {
} else if (startSection.isTurnBackTrack() && endSection.isTransferTrack()) {
routingVO.setRoutingType(RunPlanRoutingVO.UserRoutingType.INBOUND);
} else {
} else if (startSection.isTurnBackTrack() && endSection.isTurnBackTrack()) {
routingVO.setRoutingType(RunPlanRoutingVO.UserRoutingType.LOOP);
} else {
routingVO.setRoutingType(RunPlanRoutingVO.UserRoutingType.OTHER);
}
RunPlanRouting routing = routingVO.convert2Entity();
runPlanRoutingDAO.insert(routing);
generateUserRunlevels(routingVO, deviceMap);
generateUserParktimes(routingVO, deviceMap);
generateUserStationReentryTimes(routingVO, deviceMap);
}
@Override
public RunPlanRoutingVO generateUserRouting(RunPlanRoutingVO routingVO) {
public RunPlanRoutingVO generateUserRoutingSections(RunPlanRoutingVO routingVO) {
MapVO map = this.iMapService.getMapDetail(routingVO.getMapId());
SimulationBuilder.SimulationDeviceBuildResult buildResult = SimulationBuilder.checkAndBuildMapDeviceData(map);
BusinessExceptionAssertEnum.DATA_ERROR.assertCollectionEmpty(buildResult.getErrMsgList(),
@ -113,44 +117,49 @@ public class RunPlanRoutingService implements IRunPlanRoutingService {
Map<String, MapElement> deviceMap = buildResult.getDeviceMap();
Section startSection = (Section) deviceMap.get(routingVO.getStartSectionCode());
Section endSection = (Section) deviceMap.get(routingVO.getEndSectionCode());
if (startSection.isTransferTrack() && endSection.isTransferTrack()) {
routingVO.setRoutingType(RunPlanRoutingVO.UserRoutingType.OTHER);
} else if (startSection.isTransferTrack()) {
if (startSection.isTransferTrack() && endSection.isTurnBackTrack()) {
routingVO.setRoutingType(RunPlanRoutingVO.UserRoutingType.OUTBOUND);
} else if (endSection.isTransferTrack()) {
} else if (startSection.isTurnBackTrack() && endSection.isTransferTrack()) {
routingVO.setRoutingType(RunPlanRoutingVO.UserRoutingType.INBOUND);
} else {
} else if (startSection.isTurnBackTrack() && endSection.isTurnBackTrack()) {
routingVO.setRoutingType(RunPlanRoutingVO.UserRoutingType.LOOP);
} else {
routingVO.setRoutingType(RunPlanRoutingVO.UserRoutingType.OTHER);
}
RunPlanRouting newRouting = routingVO.convert2Entity();
newRouting.setId(routingId);
runPlanRoutingDAO.updateByPrimaryKeyWithBLOBs(newRouting);
generateUserRunlevels(routingVO, deviceMap);
generateUserParktimes(routingVO, deviceMap);
generateUserStationReentryTimes(routingVO, deviceMap);
}
private void generateUserParktimes(RunPlanRoutingVO routingVO, Map<String, MapElement> deviceMap) {
List<RunPlanParkingTimeVO> parkingTimeVOS = RunPlanParkingTimeVO.parkingTimeFromRouting(routingVO);
parkingTimeVOS.forEach(p -> {
if (!((Section) deviceMap.get(p.getSectionCode())).isTransferTrack() && !planParktimeService.isExisted(p)) {
// if (!((Section) deviceMap.get(p.getSectionCode())).isTransferTrack() && !planParktimeService.isExisted(p)) {
if (((Section) deviceMap.get(p.getSectionCode())).isStandTrack() && !planParktimeService.isExisted(p)) {
planParktimeService.createUserParktime(p);
}
});
}
private void generateUserRunlevels(RunPlanRoutingVO routingVO, Map<String, MapElement> deviceMap) {
List<RunPlanRunlevelVO> levels = RunPlanRunlevelVO.runLevelsFromRouting(routingVO);
levels.forEach(l -> {
Section startSection = (Section) deviceMap.get(l.getStartSectionCode());
Section endSection = (Section) deviceMap.get(l.getEndSectionCode());
if ((startSection.isTurnBackTrack() && !startSection.isStandTrack())
|| (endSection.isTurnBackTrack() && !endSection.isStandTrack())) {
return;
}
if (!planRunlevelService.isExisted(l)) {
Section startSection = (Section) deviceMap.get(l.getStartSectionCode());
Section endSection = (Section) deviceMap.get(l.getEndSectionCode());
if((startSection.isStandTrack() && endSection.isTransferTrack()) || (endSection.isStandTrack() && startSection.isTransferTrack())){
if ((startSection.isStandTrack() && endSection.isTransferTrack()) || (endSection.isStandTrack() && startSection.isTransferTrack())) {
Float distance;
try{
distance = CalculateService.calculateDistance(startSection, endSection, l.getRight());
}catch (SimulationException e){
distance = CalculateService.calculateDistance(startSection, endSection, !l.getRight());
try {
distance = CalculateService.calculateDistance(startSection, endSection, l.getRight());
} catch (SimulationException e) {
distance = CalculateService.calculateDistance(startSection, endSection, !l.getRight());
}
l.setDistance(distance);
l.generateDefaultRunLevel();
@ -165,6 +174,28 @@ public class RunPlanRoutingService implements IRunPlanRoutingService {
});
}
private void generateUserStationReentryTimes(RunPlanRoutingVO routingVO, Map<String, MapElement> deviceMap) {
RunPlanUserConfigVO userConfig = planConfigService.getConfig(routingVO.getUserId(), routingVO.getMapId());
Map<String, RunPlanUserConfigVO.ReentryTime> reentryData;
if (Objects.nonNull(userConfig)) {
reentryData = userConfig.getConfig().getReentryData();
}else{
RunPlanUserConfigVO.Config config = new RunPlanUserConfigVO.Config();
reentryData = config.getReentryData();
userConfig = new RunPlanUserConfigVO( routingVO.getMapId(),routingVO.getUserId(),config);
}
//交路是折返轨的一头 设置折返时间
Section startSection = (Section) deviceMap.get(routingVO.getStartSectionCode());
if (startSection.isTurnBackTrack()) {
reentryData.putIfAbsent(routingVO.getStartStationCode(),new RunPlanUserConfigVO.ReentryTime(120,210,45,45));
}
Section endSection = (Section) deviceMap.get(routingVO.getEndSectionCode());
if (endSection.isTurnBackTrack()) {
reentryData.putIfAbsent(routingVO.getEndStationCode(),new RunPlanUserConfigVO.ReentryTime(120,210,45,45));
}
planConfigService.saveConfig(routingVO.getUserId(), routingVO.getMapId(),userConfig.getConfig());
}
@Override
public void deleteUserRouting(Long routingId) {
runPlanRoutingDAO.deleteByPrimaryKey(routingId);
@ -199,7 +230,7 @@ public class RunPlanRoutingService implements IRunPlanRoutingService {
RunPlanRoutingExample example = new RunPlanRoutingExample();
example.createCriteria().andMapIdEqualTo(mapId).andUserIdEqualTo(userId);
List<RunPlanRouting> runPlanRoutings = runPlanRoutingDAO.selectByExampleWithBLOBs(example);
return RunPlanRoutingVO.convert2VOList(runPlanRoutings);
return RunPlanRoutingVO.convert2VOList(runPlanRoutings,this.iMapService.getMapDetail(mapId));
}
@Override
@ -209,15 +240,11 @@ public class RunPlanRoutingService implements IRunPlanRoutingService {
.filter(tripVO -> tripVO.getSDTNumberNew().equals(SDTNumber))
.findFirst()
.orElseThrow(() -> BusinessExceptionAssertEnum.DATA_NOT_EXIST.exception());
List<RunPlanRoutingSection> routingSections = trip.getTimeList().stream().map(rt -> {
RunPlanRoutingSection routingSection = new RunPlanRoutingSection();
routingSection.setStationCode(rt.getStationCode());
routingSection.setSectionCode(rt.getSectionCode());
return routingSection;
}).collect(Collectors.toList());
RunPlanRouting runPlanRouting = runPlanRoutingDAO.getUserRoutingBySectionData(userId,planVO.getMapId(),JsonUtils.writeValueAsString(routingSections));
if (Objects.isNull(runPlanRouting)) return null;
return RunPlanRoutingVO.convert2VO(runPlanRouting);
RunPlanRoutingExample example = new RunPlanRoutingExample();
example.createCriteria().andMapIdEqualTo(planVO.getMapId()).andUserIdEqualTo(userId).andStartSectionCodeEqualTo(trip.getStartSectionCode()).andEndSectionCodeEqualTo(trip.getEndSectionCode());
List<RunPlanRouting> runPlanRoutings = runPlanRoutingDAO.selectByExampleWithBLOBs(example);
if (CollectionUtils.isEmpty(runPlanRoutings)) return null;
return RunPlanRoutingVO.convert2VO(runPlanRoutings.get(0), this.iMapService.getMapDetail(planVO.getMapId()));
}
@Override
@ -232,12 +259,11 @@ public class RunPlanRoutingService implements IRunPlanRoutingService {
@Override
public List<RunPlanRoutingSection> getRoutingSectionDataBy(Long userId, Long planId, String routingCode) {
RunPlanDraft runPlanDraft = runPlanDraftDAO.selectByPrimaryKey(planId);
RunPlanRoutingExample example = new RunPlanRoutingExample();
example.createCriteria().andMapIdEqualTo(runPlanDraft.getMapId()).andUserIdEqualTo(userId).andCodeEqualTo(routingCode);
List<RunPlanRouting> runPlanRoutings = runPlanRoutingDAO.selectByExampleWithBLOBs(example);
if (CollectionUtils.isEmpty(runPlanRoutings)) return Collections.emptyList();
return RunPlanRoutingVO.convert2VO(runPlanRoutings.get(0)).getParkSectionCodeList();
List<RunPlanRouting> list = runPlanRoutingDAO.selectByExampleWithBLOBs(example);
if (CollectionUtils.isEmpty(list)) return Collections.emptyList();
return RunPlanRoutingVO.convert2VO(list.get(0)).getParkSectionCodeList();
}

View File

@ -185,7 +185,7 @@ public interface GeneratorNew {
* @param string
* @return
*/
private boolean containPlaceholder(String string) {
default boolean containPlaceholder(String string) {
if (StringUtils.hasText(string)) {
return Pattern.matches(".*\\{\\d+}.*", string);
}
@ -200,7 +200,7 @@ public interface GeneratorNew {
* @param mapDevice
* @return
*/
private String replacePlaceholder(String str, Map<String, OperatePlaceholderVO> placeholderVOMap, MapElement mapDevice, Object mapButton, MapVO map) {
default String replacePlaceholder(String str, Map<String, OperatePlaceholderVO> placeholderVOMap, MapElement mapDevice, Object mapButton, MapVO map) {
Pattern pattern = Pattern.compile(".*?(\\{(\\d+)}).*?");
Matcher matcher = pattern.matcher(str);
while (matcher.find()) {

View File

@ -1,35 +1,89 @@
package club.joylink.rtss.services.training.generatornew.base;
import club.joylink.rtss.constants.BusinessConsts;
import club.joylink.rtss.services.training.constant.TrainingConsts;
import club.joylink.rtss.services.training.data.GenerateConfig;
import club.joylink.rtss.services.training.generatornew.GeneratorNew;
import club.joylink.rtss.services.training.generatornew.annotation.GeneratorSelectorNew;
import club.joylink.rtss.simulation.cbtc.ATP.ground.TempSpeedLimitService;
import club.joylink.rtss.simulation.cbtc.ATS.operation.Operation;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.data.map.*;
import club.joylink.rtss.simulation.cbtc.data.storage.StorageSimulation;
import club.joylink.rtss.vo.client.map.MapTempSpeedLimitVO;
import club.joylink.rtss.vo.client.map.newmap.MapAutomaticRouteButtonVO;
import club.joylink.rtss.vo.client.map.newmap.MapCycleButtonVO;
import club.joylink.rtss.vo.client.map.newmap.MapTotalGuideLockButtonVO;
import club.joylink.rtss.vo.client.map.newmap.MapTurnBackStrategyVO;
import club.joylink.rtss.vo.client.training.TrainingStepVO;
import club.joylink.rtss.vo.client.training.definition.OperateDefinitionVO;
import club.joylink.rtss.vo.client.training.TrainingNewVO;
import club.joylink.rtss.vo.client.training.definition.OperatePlaceholderVO;
import club.joylink.rtss.vo.client.training.definition.OperateStepVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@GeneratorSelectorNew(operateObject = Operation.Object.WholeLineTempSpeedLimit)
@GeneratorSelectorNew(operateObject = Operation.Object.LimitControl)
public class SpeedLimitGeneratorNew implements GeneratorNew {
private final static int LIMIT_SPEED = 30;
@Autowired
private TempSpeedLimitService tempSpeedLimitService;
@Override
public List<TrainingNewVO> generate(GenerateConfig config, Simulation simulation, OperateDefinitionVO operateDefinitionVO) {
List<TrainingNewVO> trainingVOList = new ArrayList<>();
//TODO
// simulation.getRepository().getSectionList()
// tempLimitSpeedList.forEach(tempLimitSpeed -> {
// switch (Operation.Type.valueOf (operateDefinitionVO.getOperateType())) {
// case Cancel_Whole_Line_Temp_Speed_Limit: // 取消全线临时限速
// trainingVOList.add(cancelWholeLineTempSpeedLimit(tempLimitSpeed, config, simulation, operateDefinitionVO));
// break;
// }
// });
simulation.getRepository().getSectionList().forEach(section -> tempSpeedLimitService.setSectionLimitSpeed(simulation, section, LIMIT_SPEED));
switch (Operation.Type.valueOf(operateDefinitionVO.getOperateType())) {
case Cancel_All_Limit_Speed: // 取消全线临时限速
List<MapTempSpeedLimitVO> tempSpeedLimitList = simulation.getBuildParams().getMap().getGraphDataNew().getTempSpeedLimitList();
tempSpeedLimitList.forEach(mapTempSpeedLimitVO -> {
trainingVOList.add(this.build(config, simulation,null,mapTempSpeedLimitVO, operateDefinitionVO));
simulation.reset();
});
break;
}
return trainingVOList;
}
@Override
public TrainingNewVO build(GenerateConfig config, Simulation simulation, MapElement nullableDevice, Object mapButton, OperateDefinitionVO operateDefinitionVO) {
// 实训基本信息
TrainingNewVO trainingVO = new TrainingNewVO(config, operateDefinitionVO);
// 设置每一步操作的设备
List<OperateStepVO> stepList = operateDefinitionVO.getStepVOList();
stepList.get(0).setDeviceCode(((MapTempSpeedLimitVO) mapButton).getCode());
Map<String, OperatePlaceholderVO> placeholderVOMap = operateDefinitionVO.getPlaceholderVOMap();
// 设置定位
trainingVO.setLocateDeviceCode(((MapTempSpeedLimitVO) mapButton).getCode());
// 替换占位符
if (containPlaceholder(trainingVO.getName())) {
trainingVO.setName(replacePlaceholder(trainingVO.getName(), placeholderVOMap, nullableDevice, mapButton, simulation.getBuildParams().getMap()));
}
if (containPlaceholder(trainingVO.getRemarks())) {
trainingVO.setRemarks(replacePlaceholder(trainingVO.getRemarks(), placeholderVOMap, nullableDevice, mapButton, simulation.getBuildParams().getMap()));
}
// 添加步骤
List<TrainingStepVO> steps = new ArrayList<>(stepList.size());
stepList.forEach(operateStepVO -> {
TrainingStepVO stepVO = new TrainingStepVO(operateStepVO);
if (containPlaceholder(stepVO.getTip())) {
stepVO.setTip(replacePlaceholder(stepVO.getTip(), placeholderVOMap, nullableDevice, mapButton, simulation.getBuildParams().getMap()));
}
if (containPlaceholder(stepVO.getVal())) {
stepVO.setVal(replacePlaceholder(stepVO.getVal(), placeholderVOMap, nullableDevice, mapButton, simulation.getBuildParams().getMap()));
}
steps.add(stepVO);
});
trainingVO.setSteps(steps);
trainingVO.setScenes(new StorageSimulation(simulation, false));
return trainingVO;
}
}

View File

@ -1,5 +1,6 @@
package club.joylink.rtss.services.training.generatornew.base;
import club.joylink.rtss.constants.BusinessConsts;
import club.joylink.rtss.services.training.data.GenerateConfig;
import club.joylink.rtss.services.training.generatornew.GeneratorNew;
import club.joylink.rtss.services.training.generatornew.annotation.GeneratorSelectorNew;
@ -76,7 +77,8 @@ public class StationGeneratorNew implements GeneratorNew {
}
break;
case Station_CIArea_Close_AllSignal:
station.setControlMode(Station.ControlMode.Center);
if(!station.isInterlock())continue;
station.getDeviceStation().setControlMode(Station.ControlMode.Center);
// simulation.getRepository().getSignalList().stream()
// .filter(s -> Objects.equals(station.getCode(), s.getInterlockStation().getCode()))
// .forEach(signal -> {
@ -86,7 +88,13 @@ public class StationGeneratorNew implements GeneratorNew {
// });
break;
case Station_Close_AllSignal:
station.setControlMode(Station.ControlMode.Local);
if (BusinessConsts.MapPrd.PrdType.Type01.equals(config.getPrdType())) {
if(station.isCentralized()) {
station.setControlMode(Station.ControlMode.Local);
}else{
station.getDeviceStation().setControlMode(Station.ControlMode.Local);
}
}
// simulation.getRepository().getSignalList().stream()
// .filter(s -> Objects.equals(station.getCode(), s.getDeviceStation().getCode()))
// .forEach(signal -> {
@ -99,7 +107,7 @@ public class StationGeneratorNew implements GeneratorNew {
if(!station.isTurnBack()) {
continue;
}
station.setControlMode(Station.ControlMode.Center);
station.getDeviceStation().setControlMode(Station.ControlMode.Center);
if(operateDefinitionVO.turnBackStrategyButton()){
simulation.getBuildParams().getMap().getGraphDataNew().getTbStrategyList()
.stream().filter(turnBackStrategyO -> turnBackStrategyO.getStationCode().equals(station.getCode()))
@ -115,7 +123,7 @@ public class StationGeneratorNew implements GeneratorNew {
continue;
}
station.setControlMode(Station.ControlMode.Local);
station.setRestartTime(LocalTime.now());
station.setRestartTime(LocalTime.of(2,0));
List<Section> sections = simulation.getRepository().getSectionList();
sections.stream().filter(section -> Objects.equals(section.getDeviceStation(), station)).forEach(section -> section.setFaultLock(true));
break;
@ -203,6 +211,16 @@ public class StationGeneratorNew implements GeneratorNew {
});
}
continue;
case Station_Set_Or_Cancel_Force_Physical_Signal:
if(!station.isInterlock())continue;
if (BusinessConsts.MapPrd.PrdType.Type01.equals(config.getPrdType())) {
if(station.isCentralized()) {
station.setControlMode(Station.ControlMode.Local);
}else{
station.getDeviceStation().setControlMode(Station.ControlMode.Local);
}
}
break;
default:
// 其他操作不生成
continue;

View File

@ -1,12 +1,11 @@
package club.joylink.rtss.simulation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.PropertyPlaceholderHelper;
import org.springframework.util.StringUtils;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@ -22,17 +21,19 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
* 运行速度
*/
private volatile int speed;
public static final int MIN_SPEED = 1;
public static final int MAX_SPEED = 10;
/**
* 仿真系统时间
*/
private LocalDateTime systemTime;
private static final int SYSTEM_TIME_RATE = 10;
private static final int SYSTEM_TIME_RATE = 1;
private final AtomicBoolean mainLogicRunning = new AtomicBoolean(false);
/**
* 实际运行间隔单位ns
*/
long runPeriod;
long timeAdd;
/**
* 用来取消仿真线程逻辑定时执行的任务
*/
@ -63,9 +64,12 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
public static final String MESSAGE_SUB_PREFIX = "/queue/simulation/{id}";
public static final String PATH_SEPARATOR = "/";
private SimulationSubscribePathChecker subscribePathChecker;
private Map<String, String> destinationMap = new HashMap<>();
private static final PropertyPlaceholderHelper placeholderHelper = new PropertyPlaceholderHelper("{", "}");
private List<SimulationSubscribeMessageService> subscribeMessageServiceList;
private SimulationMessagePublisher publisher;
private Map<String, SimulationRepository> repositoryMap = new ConcurrentHashMap<>();
private Map<String, M> simulationMemberMap = new ConcurrentHashMap<>();
private Map<String, U> simulationUserMap = new ConcurrentHashMap<>();
@ -78,25 +82,40 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
throw new IllegalArgumentException("仿真id不能为空");
}
this.id = id;
this.systemTime = LocalDateTime.now();
this.runAsSpeed(speed);
}
private void runAsSpeed(int speed) {
this.speed = speed;
if (this.future != null) {
if (!this.future.cancel(false)) {
log.error(String.format("仿真旧主线程无法取消"));
}
}
this.updateRunPeriod(speed);
ScheduledFuture<?> scheduledFuture = EXECUTOR.scheduleAtFixedRate(()->this.logic(),
this.runPeriod, this.runPeriod, TimeUnit.NANOSECONDS);
this.future = scheduledFuture;
this.systemTime = LocalDateTime.now();
}
private void updateRunPeriod(int speed) {
this.runPeriod = TimeUnit.MILLISECONDS.toNanos(SYSTEM_TIME_RATE) / speed;
public static void main(String[] args) {
Simulation simulation = new Simulation("1") {
@Override
public String debugStr() {
return null;
}
};
simulation.addJob("b", () -> {
log.info("logic");
}, 500);
simulation.addFixedRateJob("c", () -> {
log.warn("fixed");
}, 1000);
simulation.updateSpeed(5);
simulation.start();
}
private void runAsSpeed() {
if (this.future == null) {
// if (!this.future.cancel(false)) {
// log.error(String.format("仿真旧主线程无法取消"));
// }
ScheduledFuture<?> scheduledFuture = EXECUTOR.scheduleAtFixedRate(()->this.logic(),
this.SYSTEM_TIME_RATE, this.SYSTEM_TIME_RATE, TimeUnit.MILLISECONDS);
this.future = scheduledFuture;
}
this.updateTimeUpdateSpeed(this.speed);
}
private void updateTimeUpdateSpeed(int speed) {
this.timeAdd = TimeUnit.MILLISECONDS.toNanos(SYSTEM_TIME_RATE) * speed;
}
private void logic() {
@ -105,7 +124,7 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
}
try {
this.mainLogicRunning.set(true);
this.systemTime = this.systemTime.plusNanos(TimeUnit.MILLISECONDS.toNanos(SYSTEM_TIME_RATE));
this.systemTime = this.systemTime.plusNanos(timeAdd);
for (SimulationScheduledJob scheduledJob : this.scheduledJobMap.values()) {
if (scheduledJob.isTimeToRun(this.systemTime)) {
scheduledJob.run();
@ -136,11 +155,6 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
return this.systemTime;
}
/**
* 仿真数据状态初始化由具体仿真实现
*/
protected abstract void initState();
/**
* 仿真初始化
*/
@ -148,7 +162,9 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
this.pause(); // 先暂停
this.reset();
// 通知实现初始化数据
this.initState();
for (SimulationRepository repository : this.repositoryMap.values()) {
repository.initState();
}
this.start();
}
@ -174,12 +190,29 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
this.scheduledJobMap.put(name, scheduledJob);
}
/**
* 添加固定频率运行的逻辑可能主要是消息推送类逻辑
* @param name 任务名称同时也是id
* @param job 仿真逻辑
* @param rate 执行频率单位ms
*/
public void addFixedRateJob(String name, SimulationJob job, int rate) {
if (null == name) {
throw new IllegalArgumentException("name can't be null");
}
if (this.scheduledJobMap.containsKey(name)) {
throw new IllegalArgumentException(String.format("job name [%s] already exist", name));
}
SimulationScheduledJob scheduledJob = new SimulationScheduledJob(this, name, job, rate, true);
this.scheduledJobMap.put(name, scheduledJob);
}
/**
* 延时执行逻辑只执行一次
* @param job
* @param delay
*/
public void delayExecute(SimulationJob job, long delay) {
public void addDelayExecuteJob(SimulationJob job, long delay) {
SimulationDelayJob delayJob = new SimulationDelayJob(this, job, delay);
this.delayJobMap.put(delayJob.getId(), delayJob);
}
@ -203,6 +236,7 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
*/
public void start() {
this.state.set(RUNNING);
this.runAsSpeed();
}
/**
@ -232,25 +266,25 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
/**
* 更新仿真速度
* @param speed [1,8] 1<=speed<=8
* @param speed Simulation.MIN_SPEED <= speed <= Simulation.MAX_SPEED
*/
public void updateSpeed(int speed) {
if (speed < 1) {
throw new IllegalArgumentException("speed must big or equal than 1");
if (speed < MIN_SPEED) {
throw new IllegalArgumentException(String.format("speed must big or equal than [%s]", MIN_SPEED));
}
if (speed > 8) {
throw new IllegalArgumentException("speed must small or equal than 8");
if (speed > MAX_SPEED) {
throw new IllegalArgumentException(String.format("speed must small or equal than [%s]", MAX_SPEED));
}
if (this.speed == speed) { // 速度与当前相同返回
return;
if (this.speed != speed) { // 速度不同重新更改并重新按新速度运行
this.speed = speed;
int state = this.state.get();
this.pause();
this.runAsSpeed();
for (SimulationScheduledJob job : this.scheduledJobMap.values()) {
job.updateRunPeriod(speed);
}
this.state.set(state);
}
this.pause();
this.speed = speed;
this.runAsSpeed(speed);
for (SimulationScheduledJob job : this.scheduledJobMap.values()) {
job.updateRunPeriod(speed);
}
this.start();
}
public void runError(Throwable throwable) {
@ -269,6 +303,18 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
return this.throwable;
}
public void addRepository(SimulationRepository repository) {
if (this.repositoryMap.containsKey(repository.getName())) {
throw new IllegalArgumentException(String.format("repository [%s] already exist", repository.getName()));
}
this.repositoryMap.put(repository.getName(), repository);
}
public <T extends SimulationRepository> T getRepository(String name, Class<T> cls) {
Objects.requireNonNull(name);
return (T) this.repositoryMap.get(name);
}
public M querySimulationMemberById(String id) {
Objects.requireNonNull(id, "id 不能为空");
return this.simulationMemberMap.get(id);
@ -300,9 +346,13 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
return this.simulationMemberMap.remove(id);
}
public U querySimulationUserById(String id) {
Objects.requireNonNull(id, "id 不能为空");
return this.simulationUserMap.get(id);
public U querySimulationUserById(String uid) {
Objects.requireNonNull(uid, "uid 不能为空");
U user = this.simulationUserMap.get(uid);
if (user == null) {
log.info(String.format("仿真[%s]下id为[%s]的仿真用户不存在", this.id, uid));
}
return user;
}
public U getSimulationUserById(String id) {
@ -330,9 +380,9 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
}
public void publishMessage(String destination, Object message) {
if (this.publisher == null) {
throw new UnsupportedOperationException(String.format("仿真[%s]没有消息发布对象:publisher = null", this.id));
}
this.checkPublisherExist();
Objects.requireNonNull(destination);
destination = this.handleDestination(destination);
for (U simulationUser : this.simulationUserMap.values()) {
if (simulationUser.isSubscribe(destination)) {
this.publisher.publishToUser(simulationUser.getId(), destination, message);
@ -340,9 +390,62 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
}
}
public void publishMessageToUser(String userId, String destination, Object message) {
this.checkPublisherExist();
Objects.requireNonNull(destination);
destination = this.handleDestination(destination);
if (userId != null && message != null) {
this.publisher.publishToUser(userId, destination, message);
}
}
private void checkPublisherExist() {
if (this.publisher == null) {
throw new UnsupportedOperationException(String.format("仿真[%s]没有消息发布对象:publisher = null.无法发布消息", this.id));
}
}
public abstract String debugStr();
public void setSubscribeMessageServiceList(List<SimulationSubscribeMessageService> list) {
this.subscribeMessageServiceList = list;
}
public void addSubscribeMessageService(SimulationSubscribeMessageService subscribeMessageService) {
if (this.subscribeMessageServiceList == null) {
this.subscribeMessageServiceList = new ArrayList<>();
}
this.subscribeMessageServiceList.add(subscribeMessageService);
}
public String handleDestination(String destinationPattern) {
String destination = this.destinationMap.get(destinationPattern);
if (destination != null) {
return destination;
}
Properties properties = new Properties();
properties.put("id", this.id);
String dest = placeholderHelper.replacePlaceholders(destinationPattern, properties);
this.destinationMap.put(destinationPattern, dest);
return dest;
}
public boolean isAcceptedSubscribe(String destination) {
if (this.subscribeMessageServiceList != null) {
for (SimulationSubscribeMessageService service : this.subscribeMessageServiceList) {
if (service.acceptedSubscribePath(destination)) {
return true;
}
}
}
return false;
}
public static String tryExtractSidFromDestination(String destination) {
Objects.requireNonNull(destination);
if (!destination.startsWith(MESSAGE_SUB_PREFIX.substring(0, MESSAGE_SUB_PREFIX.length() - 5))) {
return null;
}
String[] patterns = StringUtils.tokenizeToStringArray(MESSAGE_SUB_PREFIX, PATH_SEPARATOR);
String[] dests = StringUtils.tokenizeToStringArray(destination, PATH_SEPARATOR);
for (int i = 0; i < patterns.length; i++) {
@ -356,4 +459,33 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
}
return null;
}
public boolean handleUserSubscribe(String userId, String wsSessionId, String destination) {
if (!this.isAcceptedSubscribe(destination)) {
log.warn(String.format("仿真[%s]不支持的订阅: [%s]", this.id, destination));
}
U user = this.querySimulationUserById(userId);
if (user == null) {
return false;
}
user.subscribe(wsSessionId, destination);
if (this.subscribeMessageServiceList != null) {
for (SimulationSubscribeMessageService service : this.subscribeMessageServiceList) {
if (service.acceptedSubscribePath(destination)) {
Object msg = service.buildMessageOfSubscribe(destination);
if (msg != null) {
this.publishMessageToUser(userId, destination, msg);
}
}
}
}
return true;
}
public void handleUserUnsubscribe(String userId, String wsSessionId, String destination) {
U user = this.querySimulationUserById(userId);
if (user != null) {
user.unsubscribe(wsSessionId, destination);
}
}
}

View File

@ -1,17 +1,21 @@
package club.joylink.rtss.simulation;
import io.swagger.annotations.Api;
import club.joylink.rtss.simulation.operation.SimulationOperationDispatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@Api(tags = {"仿真公共控制接口"})
/**
* 仿真通用接口
*/
@RestController
@RequestMapping("/common/simulation")
public class SimulationCommonController {
@Autowired
private SimulationManager simulationManager;
@Autowired
private SimulationOperationDispatcher simulationOperationDispatcher;
@PutMapping("/{id}/pause")
public void pause(@PathVariable String id) {
@ -29,9 +33,9 @@ public class SimulationCommonController {
}
@PostMapping("/{id}/member/{memberId}/operate/{type}")
public void operate(@PathVariable String id, @PathVariable String memberId,
public Object operate(@PathVariable String id, @PathVariable String memberId,
@PathVariable String type, @RequestBody Map<String, Object> params) {
return this.simulationOperationDispatcher.doDispatch(id, memberId, type, params);
}
@PutMapping("/{id}/member/{memberId}/playby/{userId}")

View File

@ -9,7 +9,7 @@ import java.util.concurrent.atomic.AtomicLong;
@Slf4j
@Getter
public final class SimulationDelayJob implements Runnable {
final class SimulationDelayJob implements Runnable {
private static final AtomicLong ID_SEED = new AtomicLong(0);
private Simulation simulation;
@ -42,11 +42,7 @@ public final class SimulationDelayJob implements Runnable {
@Override
public void run() {
try {
this.job.run();
} catch (Throwable e) {
log.error("仿真延时任务执行异常", e);
}
this.job.run();
}
public boolean isTimeToRun(LocalDateTime systemTime) {

View File

@ -2,5 +2,5 @@ package club.joylink.rtss.simulation;
public interface SimulationJob {
void run() throws InterruptedException;
void run();
}

View File

@ -1,9 +1,22 @@
package club.joylink.rtss.simulation;
public abstract class SimulationRepository {
private Simulation simulation;
import java.util.Objects;
public Simulation getSimulation() {
return simulation;
public abstract class SimulationRepository {
private String name;
public SimulationRepository(String name) {
Objects.requireNonNull(name);
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public abstract void initState();
}

View File

@ -6,7 +6,7 @@ import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;
@Slf4j
public final class SimulationScheduledJob implements Runnable {
final class SimulationScheduledJob implements Runnable {
private Simulation simulation;
private String name;
/**
@ -16,14 +16,18 @@ public final class SimulationScheduledJob implements Runnable {
/**
* 原始频率单位ms
*/
private int rate;
private final int rate;
/**
* 是否固定频率
*/
private final boolean fixed;
/**
* 实际运行间隔单位ns
*/
long runPeriod;
LocalDateTime nextRunTime;
public SimulationScheduledJob(Simulation simulation, String name, SimulationJob job, int rate) {
public SimulationScheduledJob(Simulation simulation, String name, SimulationJob job, int rate, boolean fixed) {
if (null == job) {
throw new IllegalArgumentException("job must not be null");
}
@ -34,28 +38,32 @@ public final class SimulationScheduledJob implements Runnable {
this.name = name;
this.job = job;
this.rate = rate;
this.fixed = fixed;
this.updateRunPeriod(1);
}
public static final int TIMEOUT = 10;
public SimulationScheduledJob(Simulation simulation, String name, SimulationJob job, int rate) {
this(simulation, name, job, rate, false);
}
public static final long TIMEOUT_NANO = TimeUnit.MILLISECONDS.toNanos(10);
@Override
public void run() {
try {
long start = System.nanoTime();
this.job.run();
long used = System.nanoTime() - start;
if (used > TimeUnit.MILLISECONDS.toNanos(TIMEOUT)) {
log.warn(String.format("仿真任务[%s]执行耗时[%sns]超过[%sms],请检查并调优",
this.name, TimeUnit.NANOSECONDS.toMillis(used), TIMEOUT));
}
} catch (Throwable e) {
simulation.runError(e);
log.error(String.format("仿真任务[%s]执行异常,仿真停止运行", this.name), e);
long start = System.nanoTime();
this.job.run();
long used = System.nanoTime() - start;
if (used > TIMEOUT_NANO) {
log.warn(String.format("仿真任务[%s]执行耗时[%sns]超过[%sns],请检查并调优",
this.name, used, TIMEOUT_NANO));
}
}
public void updateRunPeriod(int speed) {
this.runPeriod = TimeUnit.MILLISECONDS.toNanos(this.rate) / speed;
if (this.fixed) {
this.runPeriod = TimeUnit.MILLISECONDS.toNanos(this.rate) * speed;
} else {
this.runPeriod = TimeUnit.MILLISECONDS.toNanos(this.rate);
}
}
public boolean isTimeToRun(LocalDateTime systemTime) {

View File

@ -0,0 +1,8 @@
package club.joylink.rtss.simulation;
public interface SimulationSubscribeMessageService {
boolean acceptedSubscribePath(String destination);
Object buildMessageOfSubscribe(String destination);
}

View File

@ -1,6 +0,0 @@
package club.joylink.rtss.simulation;
public interface SimulationSubscribePathChecker {
boolean acceptedSubscribePath(String destination);
}

View File

@ -13,6 +13,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -73,6 +74,27 @@ public class GroundAtpApiServiceImpl implements GroundAtpApiService {
}
// 判断是否要将ARB设为非通信车占用
this.atpSectionService.judgeFaultSectionAsNctOccupied(nctApproachSignalMap);
// 根据道岔的位置修改道岔区段的占用暂时只处理因故障导致的占用
repository.getSwitchList().stream().filter(aSwitch -> Section.AxleFault.CBTC_OCCUPIED_FAULT.equals(aSwitch.getA().getFault()))
.forEach(aSwitch -> {
List<Section> allSections = aSwitch.getAllSections();
if (aSwitch.isLoss()) {
allSections.forEach(section -> section.setCtOccupied(true));
} else {
List<Section> sections = Arrays.asList(aSwitch.getA(), aSwitch.getNextSectionOnBaseSection(aSwitch.getA()));
for (Section section : sections) {
if (section != null) {
section.setCtOccupied(true);
}
}
allSections.forEach(section -> {
if (!sections.contains(section)) {
section.setCtOccupied(false);
}
});
}
});
// 发送区段状态
this.atsApiService.handleDeviceStatus(simulation, repository.getSectionList());
}

View File

@ -93,6 +93,7 @@ public class ZCLogicLoop {
/**
* 计算移动授权终端
*
* @param simulation
* @param train
* @param trainList
@ -144,17 +145,17 @@ public class ZCLogicLoop {
int count = 0;
while (count < 50) {
++count;
// 区段未进路锁闭或延时解锁中转换轨除外因为出库列车加载到转换轨没有进路
if (!section.isTransferTrack()) {
if (section.isDelayUnlock()) {
deviceEnd = new MovementAuthority.End(section, MovementAuthority.EndType.UNLOCK_SECTION);
break;
}
if (!section.isRouteLock()) {
deviceEnd = new MovementAuthority.End(section, MovementAuthority.EndType.UNLOCK_SECTION);
break;
}
}
// // 区段未进路锁闭或延时解锁中转换轨除外因为出库列车加载到转换轨没有进路
// if (!section.isTransferTrack()) {
// if (section.isDelayUnlock()) {
// deviceEnd = new MovementAuthority.End(section, MovementAuthority.EndType.UNLOCK_SECTION);
// break;
// }
// if (!section.isRouteLock()) {
// deviceEnd = new MovementAuthority.End(section, MovementAuthority.EndType.UNLOCK_SECTION);
// break;
// }
// }
// 站台屏蔽门
MovementAuthority.End psdEnd = checkPsdOpen(section, tailPosition);
if (Objects.nonNull(psdEnd)) {

View File

@ -1,5 +1,7 @@
package club.joylink.rtss.simulation.cbtc.ATS.operation;
import club.joylink.rtss.exception.BusinessException;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.event.SimulationOperationEvent;
import club.joylink.rtss.simulation.cbtc.exception.SimulationException;
@ -43,6 +45,12 @@ public class AtsOperationDispatcher {
try {
result = handlerMethod.execute(simulation, params, member);
} catch (Exception e) {
if (e instanceof BusinessException) {
BusinessException be = (BusinessException) e;
if (BusinessExceptionAssertEnum.SIMULATION_EXCEPTION_FOR_SHOW.getCode() == be.getCode()) {
throw e;
}
}
throw new SimulationException(SimulationExceptionType.Operation_Handle_FAIL,
String.format("操作【%s】执行失败%s", operate, e.getMessage()), e);
}

View File

@ -356,6 +356,10 @@ public class Operation {
Train_Set_Route,
/** 设置运行类型 */
Train_Set_Run_Type,
/** 下令停车 */
Train_Order_Stop,
/** 取消停车命令 */
Train_Cancel_Order_Stop,
//--------------------------- 司机 ---------------------------
/** 改变列车的牵引/制动力 */
@ -395,7 +399,7 @@ public class Operation {
/** 集中站 */
Station,
/**全线临时限速*/
WholeLineTempSpeedLimit
LimitControl
}

View File

@ -1,5 +1,6 @@
package club.joylink.rtss.simulation.cbtc.ATS.operation.handler;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.cbtc.ATS.operation.Operation;
import club.joylink.rtss.simulation.cbtc.ATS.operation.annotation.OperateHandler;
import club.joylink.rtss.simulation.cbtc.ATS.operation.annotation.OperateHandlerMapping;
@ -8,8 +9,6 @@ import club.joylink.rtss.simulation.cbtc.CI.CiApiService;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.data.map.Route;
import club.joylink.rtss.simulation.cbtc.data.status.RouteStatus;
import club.joylink.rtss.simulation.cbtc.exception.SimulationException;
import club.joylink.rtss.simulation.cbtc.exception.SimulationExceptionType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@ -35,10 +34,7 @@ public class SignalOperateHandler {
@OperateHandlerMapping(type = Operation.Type.Signal_Set_Route)
public void settingRoute(Simulation simulation, String routeCode) {
Route.CheckFailMessage checkResult = this.ciApiService.routeSettingCheck(simulation, routeCode);
if (Objects.nonNull(checkResult)) {
throw new SimulationException(SimulationExceptionType.Operation_Handle_FAIL,
checkResult.toJson());
}
BusinessExceptionAssertEnum.SIMULATION_EXCEPTION_FOR_SHOW.assertNull(checkResult, "进路排列失败,被联锁逻辑取消");
this.ciApiService.settingRoute(simulation, routeCode);
}

View File

@ -12,6 +12,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
import java.util.Objects;
@Slf4j
@OperateHandler
@ -170,7 +171,10 @@ public class StandOperateHandler {
* 区间列车数量限制
*/
@OperateHandlerMapping(type = Operation.Type.Stand_Set_Hold_Train_Auto)
public void setHoldTrainAuto(Simulation simulation, String standCode, int limit) {
public void setHoldTrainAuto(Simulation simulation, String standCode, Integer limit) {
if (Objects.isNull(limit)) {
limit = 0;
}
atsStandService.setAutoHoldTrainLimit(simulation, standCode, limit);
}

View File

@ -179,7 +179,14 @@ public class StationOperateHandler {
@OperateHandlerMapping(type = Operation.Type.Station_Close_AllSignal)
public void closeAllSignal(Simulation simulation, String stationCode){
SimulationDataRepository repository = simulation.getRepository();
repository.getSignalList().stream().filter(s -> Objects.equals(stationCode,s.getDeviceStation().getCode())).forEach(signal -> ciApiService.blockadeSignal(simulation, signal.getCode()));
repository.getSignalList().stream()
.filter(s -> s.getStation() != null && Objects.equals(stationCode, s.getStation().getCode()))
.forEach(signal -> {
ciApiService.blockadeSignal(simulation, signal.getCode());
if (signal.getLockedRoute() != null) {
ciApiService.closeSignal(simulation, signal.getCode());
}
});
}
/**关区信号*/

View File

@ -1,5 +1,6 @@
package club.joylink.rtss.simulation.cbtc.ATS.operation.handler;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.cbtc.ATP.ground.GroundAtpApiService;
import club.joylink.rtss.simulation.cbtc.ATS.operation.Operation;
import club.joylink.rtss.simulation.cbtc.ATS.operation.annotation.OperateHandler;
@ -38,10 +39,8 @@ public class SwitchOperateHandler {
@OperateHandlerMapping(type = Operation.Type.Switch_Turn)
public void turn(Simulation simulation, String switchCode) {
Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class);
if (!aSwitch.canTurn()) {
throw new SimulationException(SimulationExceptionType.Operation_Handle_FAIL,
"道岔锁闭或占用,无法转动");
}
BusinessExceptionAssertEnum.SIMULATION_EXCEPTION_FOR_SHOW.assertTrue(!aSwitch.isLocked(),
String.format("联锁操作被取消,道岔%s被锁定", aSwitch.getName()));
this.ciApiService.turn(simulation, switchCode);
}

View File

@ -333,4 +333,14 @@ public class TrainOperateHandler {
public void setRunType(Simulation simulation, String groupNumber, VirtualRealityTrain.RunType runType) {
atsTrainService.setRunType(simulation, groupNumber, runType);
}
@OperateHandlerMapping(type = Operation.Type.Train_Order_Stop)
public void orderStop(Simulation simulation, String groupNumber) {
atsTrainService.orderStop(simulation, groupNumber);
}
@OperateHandlerMapping(type = Operation.Type.Train_Cancel_Order_Stop)
public void cancelOrderStop(Simulation simulation, String groupNumber) {
atsTrainService.cancelOrderStop(simulation, groupNumber);
}
}

View File

@ -171,9 +171,9 @@ public class AtsPlanService {
// 更新扣车状态
if (!Objects.equals(train.isHold(), hold)) {
if (hold) {
this.onboardAtpApiService.holdTrain(simulation, train.getGroupNumber());
this.onboardAtpApiService.standHoldTrain(simulation, train.getGroupNumber());
} else {
this.onboardAtpApiService.cancelHoldTrain(simulation, train.getGroupNumber());
this.onboardAtpApiService.standCancelHoldTrain(simulation, train.getGroupNumber());
}
}
} else {
@ -578,6 +578,7 @@ public class AtsPlanService {
Section startSection = firstStationPlan.getSection();
StationPlan secondStationPlan = tripPlan.getSecondStationPlan();
Section endSection = secondStationPlan.getSection();
// Objects.nonNull(secondStationPlan)?secondStationPlan.getSection():tripPlan.getEndSection();
if (tripPlan.isBehindDepart()) {
endSection = startSection;
startSection = tripPlan.getStartSection();
@ -624,6 +625,9 @@ public class AtsPlanService {
trainInfo.initPlan(tripPlan, firstStationPlan, repository.getConfig());
StationPlan nextPlan = firstStationPlan;
if (Objects.equals(firstStationPlan.getSection(), startSection)) {
// if (Objects.isNull(secondStationPlan)) {
// secondStationPlan = StationPlan.builder().park(true).arriveTime(tripPlan.getEndTime()).leaveTime(tripPlan.getEndTime()).section(tripPlan.getEndSection()).station(tripPlan.getEndSection().getStation()).build();
// }
nextPlan = secondStationPlan;
}
trainInfo.updatePlanInfo(nextPlan);

View File

@ -2,6 +2,7 @@ package club.joylink.rtss.simulation.cbtc.ATS.service;
import club.joylink.rtss.simulation.cbtc.CI.CiApiService;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.data.CalculateService;
import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository;
import club.joylink.rtss.simulation.cbtc.data.map.*;
import club.joylink.rtss.simulation.cbtc.data.plan.StationPlan;
@ -90,50 +91,109 @@ public class AtsRouteSettingService {
if (Objects.equals(headSection, destDefinition.getSection())) {
return null;
}
// 目的地定义存在根据目的地定义查询路径办理进路
// 判断是否终点站折返办理
if (train.isParking() && destDefinition.isLoop()) { // 列车停车且目的地为环路运营
Section section = destDefinition.getEndStationParkSection(right);
if (Objects.equals(section, headSection)) { // 列车停靠终点站对应站台
Station station = destDefinition.getStationOf(right);
if (destDefinition.isFrontTurnBack(station)) { // 站前折返
neededSignal = section.getSignalOf(!right);
List<RoutePath> paths = repository.queryRoutePathsByStart(section);
for (RoutePath path : paths) { // 筛选方向一致且终端区段是站台轨的
if (Objects.equals(path.isRight(), !right) && path.getEnd().isNormalStandTrack()) {
routePaths.add(path);
if (!CollectionUtils.isEmpty(destDefinition.getRoutes())) {
return destDefinition.queryNextRoute(headSection);
} else if (train.getEstimatedArriveStandTrack() != null) {
Section targetSection = repository.getByCode(train.getEstimatedArriveStandTrack(), Section.class);
routePaths = CalculateService.queryRoutePathsOnDirection(headSection, targetSection, true);
if (CollectionUtils.isEmpty(routePaths)) {
routePaths = CalculateService.queryRoutePathsOnDirection(headSection, targetSection, false);
}
} else {
// 目的地定义存在根据目的地定义查询路径办理进路
// 判断是否终点站折返办理
if (train.isParking() && destDefinition.isLoop()) { // 列车停车且目的地为环路运营
Section section = destDefinition.getEndStationParkSection(right);
if (Objects.equals(section, headSection)) { // 列车停靠终点站对应站台
Station station = destDefinition.getStationOf(right);
if (destDefinition.isFrontTurnBack(station)) { // 站前折返
neededSignal = section.getSignalOf(!right);
List<RoutePath> paths = repository.queryRoutePathsByStart(section);
for (RoutePath path : paths) { // 筛选方向一致且终端区段是站台轨的
if (Objects.equals(path.isRight(), !right) && path.getEnd().isNormalStandTrack()) {
routePaths.add(path);
}
}
} else { // 站后折返
train.startTurnBack(null);
StationTurnBackStrategyOption strategy = null;
if (Objects.nonNull(station.getTbStrategyId())) {
strategy = station.getCurrentTurnBackStrategy();
}
return this.selectTbRouteByStrategy(simulation, train, signal, null, strategy, trainList);
}
}
}
// 非终点折返办理根据列车预计到站查询
if (Objects.nonNull(train.getEstimatedArriveStandTrack())) {
// 查询到达预计到站的路径
Section eaStandSection = repository.getByCode(train.getEstimatedArriveStandTrack(), Section.class);
List<RoutePath> paths = repository.queryRoutePathsByEnd(eaStandSection);
for (RoutePath path : paths) {
if (path.containsSection(headSection) && path.isRight() == right) {
routePaths.add(path);
}
}
// 如果预计到达不是终点尝试查询从预计到达开始的路径
if (!destDefinition.isEndSection(eaStandSection, right)) {
List<RoutePath> pathList = repository.queryRoutePathsByStart(eaStandSection);
for (RoutePath routePath : pathList) {
if (destDefinition.containsSection(routePath.getEnd(), right)) {
routePaths.add(routePath);
}
}
} else { // 站后折返
train.startTurnBack(null);
StationTurnBackStrategyOption strategy = null;
if (Objects.nonNull(station.getTbStrategyId())) {
strategy = station.getCurrentTurnBackStrategy();
}
return this.selectTbRouteByStrategy(simulation, train, signal, null, strategy, trainList);
}
}
}
// 非终点折返办理根据列车预计到站查询
if (Objects.nonNull(train.getEstimatedArriveStandTrack())) {
// 查询到达预计到站的路径
Section eaStandSection = repository.getByCode(train.getEstimatedArriveStandTrack(), Section.class);
List<RoutePath> paths = repository.queryRoutePathsByEnd(eaStandSection);
for (RoutePath path : paths) {
if (path.containsSection(headSection) && path.isRight() == right) {
routePaths.add(path);
}
}
// 如果预计到达不是终点尝试查询从预计到达开始的路径
if (!destDefinition.isEndSection(eaStandSection, right)) {
List<RoutePath> pathList = repository.queryRoutePathsByStart(eaStandSection);
for (RoutePath routePath : pathList) {
if (destDefinition.containsSection(routePath.getEnd(), right)) {
routePaths.add(routePath);
}
}
}
}
// // 如果已经到达目的地返回
// if (Objects.equals(headSection, destDefinition.getSection())) {
// return null;
// }
// // 目的地定义存在根据目的地定义查询路径办理进路
// // 判断是否终点站折返办理
// if (train.isParking() && destDefinition.isLoop()) { // 列车停车且目的地为环路运营
// Section section = destDefinition.getEndStationParkSection(right);
// if (Objects.equals(section, headSection)) { // 列车停靠终点站对应站台
// Station station = destDefinition.getStationOf(right);
// if (destDefinition.isFrontTurnBack(station)) { // 站前折返
// neededSignal = section.getSignalOf(!right);
// List<RoutePath> paths = repository.queryRoutePathsByStart(section);
// for (RoutePath path : paths) { // 筛选方向一致且终端区段是站台轨的
// if (Objects.equals(path.isRight(), !right) && path.getEnd().isNormalStandTrack()) {
// routePaths.add(path);
// }
// }
// } else { // 站后折返
// train.startTurnBack(null);
// StationTurnBackStrategyOption strategy = null;
// if (Objects.nonNull(station.getTbStrategyId())) {
// strategy = station.getCurrentTurnBackStrategy();
// }
// return this.selectTbRouteByStrategy(simulation, train, signal, null, strategy, trainList);
// }
// }
// }
// // 非终点折返办理根据列车预计到站查询
// if (Objects.nonNull(train.getEstimatedArriveStandTrack())) {
// // 查询到达预计到站的路径
// Section eaStandSection = repository.getByCode(train.getEstimatedArriveStandTrack(), Section.class);
// List<RoutePath> paths = repository.queryRoutePathsByEnd(eaStandSection);
// for (RoutePath path : paths) {
// if (path.containsSection(headSection) && path.isRight() == right) {
// routePaths.add(path);
// }
// }
// // 如果预计到达不是终点尝试查询从预计到达开始的路径
// if (!destDefinition.isEndSection(eaStandSection, right)) {
// List<RoutePath> pathList = repository.queryRoutePathsByStart(eaStandSection);
// for (RoutePath routePath : pathList) {
// if (destDefinition.containsSection(routePath.getEnd(), right)) {
// routePaths.add(routePath);
// }
// }
// }
// }
} else {
// 按交路查询办理如果找到才办理
Routing routing = train.getRouting();
@ -278,6 +338,7 @@ public class AtsRouteSettingService {
/**
* 判断当前时间到折返计划的下一计划第一站到站时间之间是否存在冲突的出库计划
*
* @param simulation
* @param tripPlan
* @return
@ -390,10 +451,11 @@ public class AtsRouteSettingService {
/**
* 根据折返策略选择进路
*
* @param simulation
* @param train
* @param signal
* @param defaultTb 默认折返轨可能为null
* @param defaultTb 默认折返轨可能为null
* @param strategy
* @return
*/
@ -434,6 +496,7 @@ public class AtsRouteSettingService {
for (Route route : routeList) {
if (route.isTurnBack()) {
tbRouteList.add(route);
tbSectionList.add(route.getSectionList().get(route.getSectionList().size() - 1));
}
}
if (!tbRouteList.isEmpty()) {
@ -467,7 +530,7 @@ public class AtsRouteSettingService {
if (config.isRouteLikeHa1()) {
if (train.isCbtcTrack() && !route.isAtp()) { // 通信车
return false;
} else if(!train.isCbtcTrack() && !route.isGround()) {
} else if (!train.isCbtcTrack() && !route.isGround()) {
return false;
}
}
@ -620,6 +683,7 @@ public class AtsRouteSettingService {
/**
* 获取需要排列进路的列车位置及对应信号机
*
* @return
*/
private Map<Signal, TrainInfo> getTrain2SignalOfSetRoute(Simulation simulation, List<TrainInfo> trainList,
@ -631,7 +695,7 @@ public class AtsRouteSettingService {
}
Boolean right = train.getRight();
SectionPosition trainPosition = trainPositionMap.get(train.getGroupNumber());
if(Objects.isNull(trainPosition)){
if (Objects.isNull(trainPosition)) {
continue;
}
Section section = trainPosition.getSection();
@ -647,7 +711,7 @@ public class AtsRouteSettingService {
SectionPosition otherPosition = trainPositionMap.get(other.getGroupNumber());
if (trainPosition.isAheadOf(otherPosition, right)) {
signalTrainMap.put(signal, train);
}else{
} else {
continue;
}
}

View File

@ -341,7 +341,7 @@ public class AtsStandService {
if (trainInfo.isParkingStand(stand) ||
Objects.equals(stand.getSection().getCode(),
trainInfo.getEstimatedArriveStandTrack())) {
this.onboardAtpApiService.holdTrain(simulation, trainInfo.getGroupNumber());
this.onboardAtpApiService.standHoldTrain(simulation, trainInfo.getGroupNumber());
}
}
}
@ -391,7 +391,7 @@ public class AtsStandService {
for (TrainInfo trainInfo : superviseTrainList) {
if (trainInfo.isParkingStand(stand) ||
Objects.equals(stand.getSection().getCode(), trainInfo.getEstimatedArriveStandTrack())) {
this.onboardAtpApiService.cancelHoldTrain(simulation, trainInfo.getGroupNumber());
this.onboardAtpApiService.standCancelHoldTrain(simulation, trainInfo.getGroupNumber());
}
}
}
@ -426,7 +426,7 @@ public class AtsStandService {
for (TrainInfo trainInfo : superviseTrainList) {
if (trainInfo.isParkingStand(stand) ||
Objects.equals(stand.getSection().getCode(), trainInfo.getPlanStandTrack())) {
this.onboardAtpApiService.cancelHoldTrain(simulation, trainInfo.getGroupNumber());
this.onboardAtpApiService.standCancelHoldTrain(simulation, trainInfo.getGroupNumber());
}
}
}

View File

@ -12,6 +12,7 @@ import club.joylink.rtss.simulation.cbtc.data.plan.StationPlan;
import club.joylink.rtss.simulation.cbtc.data.plan.TripPlan;
import club.joylink.rtss.simulation.cbtc.data.support.RoutePath;
import club.joylink.rtss.simulation.cbtc.data.support.SectionPosition;
import club.joylink.rtss.simulation.cbtc.data.support.StationTurnBackStrategyOption;
import club.joylink.rtss.simulation.cbtc.data.vo.RoutePathVO;
import club.joylink.rtss.simulation.cbtc.data.vo.TrainInfo;
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityTrain;
@ -220,48 +221,56 @@ public class AtsTrainService {
}
boolean stop = supervisedTrain.isStop();
switch (destinationCodeDefinition.getType()) {
case NORMAL_OPERATION: {
BusinessExceptionAssertEnum.INVALID_OPERATION.assertNotNull(targetStation,
String.format("列车[%s]目标区段为null", supervisedTrain.getGroupNumber()));
Station leftStation = destinationCodeDefinition.getLeftStation();
Station rightStation = destinationCodeDefinition.getRightStation();
boolean beyondStationRage =
Math.min(leftStation.getSn(), rightStation.getSn()) > targetStation.getSn()
|| targetStation.getSn() > Math.max(leftStation.getSn(), rightStation.getSn()); //是否超出车站范围
if (beyondStationRage) {
throw new SimulationException(SimulationExceptionType.Illegal_Argument,
String.format("列车目标轨道[%s]超出目的地码[%s]的范围", targetSection, destinationCode));
}
if (destinationCodeDefinition.isBorder(targetStation) && destinationCodeDefinition.isFrontTurnBack(targetStation)) {
boolean bothNormalAndTurnBack = targetSection.isNormalStandTrack() && targetSection.isTurnBackTrack();
if (!bothNormalAndTurnBack) {
throw new SimulationException(SimulationExceptionType.Invalid_Operation, "列车已无法站前折返");
}
}
break;
}
case NORMAL_OPERATION:
// Station leftStation = destinationCodeDefinition.getLeftStation();
// Station rightStation = destinationCodeDefinition.getRightStation();
// boolean beyondStationRage =
// Math.min(leftStation.getSn(), rightStation.getSn()) > targetStation.getSn()
// || targetStation.getSn() > Math.max(leftStation.getSn(), rightStation.getSn()); //是否超出车站范围
// if (beyondStationRage) {
// throw new SimulationException(SimulationExceptionType.Illegal_Argument,
// String.format("列车目标轨道[%s]超出目的地码[%s]的范围", targetSection, destinationCode));
// }
// if (destinationCodeDefinition.isBorder(targetStation) && destinationCodeDefinition.isFrontTurnBack(targetStation)) {
// boolean bothNormalAndTurnBack = targetSection.isNormalStandTrack() && targetSection.isTurnBackTrack();
// if (!bothNormalAndTurnBack) {
// throw new SimulationException(SimulationExceptionType.Invalid_Operation, "列车已无法站前折返");
// }
// }
case LAST_OPERATION:
case NON_OPERATION:
case LAST_NON_OPERATION: {
Section startSection = targetSection;
if (startSection == null) {
startSection = headSection;
}
if (right == null) {
throw new SimulationException(SimulationExceptionType.Illegal_Argument,
String.format("列车[%s]方向未知", groupNumber));
}
BusinessExceptionAssertEnum.INVALID_OPERATION.assertNotNull(targetSection,
String.format("列车[%s]目标区段为null", supervisedTrain.getGroupNumber()));
Boolean destinationRight = destinationCodeDefinition.getRight();
if (!targetSection.isTurnBackTrack() || !stop) {
if (!Objects.equals(right, destinationRight)) {
throw new SimulationException(SimulationExceptionType.Illegal_Argument,
String.format("列车方向与目的地码[%s]的方向相反", destinationCode));
}
}
Station station = destinationSection.getStation();
if ((destinationRight && targetStation.getSn() > station.getSn())
|| (!destinationRight && targetStation.getSn() < station.getSn())) {
throw new SimulationException(SimulationExceptionType.Illegal_Argument,
String.format("列车目标轨道[%s]超出目的地码[%s]的范围", targetSection, destinationCode));
}
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertTrue(destinationCodeDefinition.containsSection(startSection, right),
String.format("%s超出%s范围", String.format("列车[%s]", groupNumber), destinationCodeDefinition.logStr()));
// if (right == null) {
// throw new SimulationException(SimulationExceptionType.Illegal_Argument,
// String.format("列车[%s]方向未知", groupNumber));
// }
// BusinessExceptionAssertEnum.INVALID_OPERATION.assertNotNull(targetSection,
// String.format("列车[%s]目标区段为null", supervisedTrain.getGroupNumber()));
// Boolean destinationRight = destinationCodeDefinition.getRight();
// if (!targetSection.isTurnBackTrack() || !stop) {
// if (!Objects.equals(right, destinationRight)) {
// throw new SimulationException(SimulationExceptionType.Illegal_Argument,
// String.format("列车方向与目的地码[%s]的方向相反", destinationCode));
// }
// }
// Station station = destinationSection.getStation();
// if ((destinationRight && targetStation.getSn() > station.getSn())
// || (!destinationRight && targetStation.getSn() < station.getSn())) {
// throw new SimulationException(SimulationExceptionType.Illegal_Argument,
// String.format("列车目标轨道[%s]超出目的地码[%s]的范围", targetSection, destinationCode));
// }
break;
}
case OTHER:
@ -375,6 +384,7 @@ public class AtsTrainService {
Long mapId = simulation.getBuildParams().getMap().getId();
LocalTime systemTime = simulation.getSystemTime().toLocalTime();
Section headSection = repository.getByCode(train.getPhysicalSection(), Section.class);
Station headStation = headSection.getStation();
float offset = train.getOffsetp() * headSection.getLen();
SectionPosition headPosition = new SectionPosition(headSection, offset);
Boolean trainRight = train.getRight();
@ -386,12 +396,6 @@ public class AtsTrainService {
targetSection = repository.getByCode(estimatedArriveStandTrack, Section.class);
targetStation = targetSection.getStation();
}
// String estimatedArriveStandTrack = train.getEstimatedArriveStandTrack();
// if (Objects.isNull(estimatedArriveStandTrack)) {
// return;
// }
// Section targetSection = repository.getByCode(estimatedArriveStandTrack, Section.class);
// Station targetStation = targetSection.getStation();
boolean stop = train.isStop();
Section nextTarget = null;
long runningTime = 0;
@ -475,7 +479,7 @@ public class AtsTrainService {
Map<String, DestinationCodeDefinition> destinationMap = repository.getDestinationMap();
String destinationCode = train.getDestinationCode();
if (!CollectionUtils.isEmpty(destinationMap)) { //有目的地码定义数据
if (!stop)
if (!stop || (targetSection != null && !headSection.equals(targetSection))) //列车没有停在目标轨
break;
if (trainRight == null)
break;
@ -490,54 +494,84 @@ public class AtsTrainService {
Boolean destinationRight = destinationCodeDefinition.getRight();
switch (destinationCodeDefinition.getType()) {
case NORMAL_OPERATION: {
if (Objects.isNull(estimatedArriveStandTrack)) {
return;
}
Station leftStation = destinationCodeDefinition.getLeftStation();
Station rightStation = destinationCodeDefinition.getRightStation();
if (Math.min(leftStation.getSn(), rightStation.getSn()) > targetStation.getSn()
|| targetStation.getSn() > Math.max(leftStation.getSn(), rightStation.getSn())) { //超出环路范围
log.warn(String.format("仿真[%s]列车[%s]目标轨不在环路范围内", simulation.getGroup(), train.getGroupNumber()));
nextTarget = destinationCodeDefinition.queryNextTargetSection(headSection);
if (nextTarget != null) {
break;
}
Station station = destinationCodeDefinition.getStationOf(trainRight);
if (Objects.equals(station.getSn(), targetStation.getSn())) { //已经抵达同向边界车站
if (targetSection.isNormalStandTrack()) { //如果是在站台轨并开始折返
List<Section> turnBackList = targetStation.getTurnBackList();
if (!CollectionUtils.isEmpty(turnBackList)) {
nextTarget = turnBackList.get(0);
// 站后折返
train.startTurnBack(nextTarget);
// 开始折返
this.onboardAtpApiService.startTurnBack(simulation, train.getGroupNumber(),
nextTarget.getCode());
break;
Station leftStation = destinationCodeDefinition.getLeftStation();
Station rightStation = destinationCodeDefinition.getRightStation();
if (destinationCodeDefinition.isBorder(headStation)) { //到达边界车站
boolean rightEnd = headStation.equals(rightStation); //是否右端车站
if (headSection.isNormalStandTrack()) {
boolean standRight = headStation.isStandOfSectionRight(headSection); //是否是右行站台
if (rightEnd == standRight && !destinationCodeDefinition.isFrontTurnBack(headStation)) { //需要站后折返
//查询目的地码定义指定的折返轨
nextTarget = destinationCodeDefinition.getNecessarySections().stream()
.filter(section -> section.isTurnBackTrack() && !section.isStandTrack() && section.getStation().equals(headStation))
.findAny().orElse(null);
//查询车站指定的折返轨
if (nextTarget == null) {
if (!CollectionUtils.isEmpty(headStation.getTbStrategyMap()) && headStation.getTbStrategyId() != null) {
StationTurnBackStrategyOption strategy = headStation.getCurrentTurnBackStrategy();
Section tbSection = strategy.getSectionList().get(0);
switch (strategy.getType()) {
case FIRST:
List<RoutePath> routePaths = CalculateService.queryRoutePathsOnDirection(headSection, tbSection, standRight);
if (routePaths.stream().anyMatch(path -> !path.isOccupied())) {
nextTarget = tbSection;
}
break;
case ONLY:
nextTarget = tbSection;
break;
}
}
}
//随意选择能用的折返轨
if (nextTarget == null) {
for (Section section : headStation.getTurnBackList()) {
if (section.isNormalStandTrack()) {
continue;
}
List<RoutePath> routePaths = CalculateService.queryRoutePathsOnDirection(headSection, section, standRight);
if (routePaths.stream().anyMatch(path -> !path.isOccupied())) {
nextTarget = section;
break;
}
}
}
} else { //站前折返或已到站后折返轨
Station adjacentStation = simulation.getRepository().findAdjacentStation(headStation, !rightEnd);
BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.assertNotNull(adjacentStation,
String.format("%s的%s侧相邻车站不存在", headStation.debugStr(), rightEnd ? "" : ""));
nextTarget = adjacentStation.getNormalStand(!rightEnd).get(0).getSection();
}
} else if (headSection.isTurnBackTrack()) { //认为是站后折返轨
nextTarget = headStation.getNormalStand(!rightEnd).get(0).getSection();
}
} else { //未抵达同向边界车站
Station adjacentStation = repository.findAdjacentStation(targetStation, trainRight);
Optional<Stand> first;
if ((adjacentStation.equals(leftStation)
|| adjacentStation.equals(rightStation))
&& destinationCodeDefinition.isFrontTurnBack(adjacentStation)) { //相邻站是环路的边界车站且是站前折返
first = adjacentStation.getStandOf(!trainRight).stream().filter(stand -> !stand.isSmall()).limit(1).findFirst();
} else {
first = adjacentStation.getStandOf(trainRight).stream().filter(stand -> !stand.isSmall()).limit(1).findFirst();
} else { //不在边界车站
if (!headSection.isNormalStandTrack()) { //认为此时列车一定在站台轨如果是在折返轨不好处理故略过
break;
}
if (first.isPresent()) {
nextTarget = first.get().getSection();
} else {
log.warn(String.format("地图[%s]车站[%s]所有站台都是小站台", mapId, adjacentStation.getCode()));
}
}
if (targetSection.isTurnBackTrack()) { //如果是在折返轨选择能到达的站台
for (Stand stand : targetStation.getAllStandList()) {
Section section = stand.getSection();
if (!CollectionUtils.isEmpty(repository.queryRoutePaths(targetSection, section))) {
nextTarget = section;
break;
boolean standRight = headStation.isStandOfSectionRight(headSection);
Station adjacentStation = simulation.getRepository().findAdjacentStation(headStation, standRight);
if (destinationCodeDefinition.isBorder(adjacentStation)) {
if (destinationCodeDefinition.isFrontTurnBack(adjacentStation)) {
nextTarget = destinationCodeDefinition.getNecessarySections().stream()
.filter(section -> section.isStandTrack() && adjacentStation.equals(section.getStation()))
.limit(1).findAny().orElse(null);
if (nextTarget != null) {
break;
}
nextTarget = adjacentStation.getNormalStand(!standRight).get(0).getSection();
if (CollectionUtils.isEmpty(CalculateService.queryRoutePathsOnDirection(headSection, nextTarget, standRight))) {
nextTarget = adjacentStation.getNormalStand(standRight).get(0).getSection();
}
} else {
nextTarget = adjacentStation.getNormalStand(standRight).get(0).getSection();
}
} else {
nextTarget = adjacentStation.getNormalStand(standRight).get(0).getSection();
}
}
break;
@ -545,56 +579,17 @@ public class AtsTrainService {
case LAST_OPERATION:
case NON_OPERATION:
case LAST_NON_OPERATION:
if (Objects.isNull(estimatedArriveStandTrack)) {
return;
}
if (!targetSection.isTurnBackTrack()) {
if (!Objects.equals(trainRight, destinationRight)) {
log.warn(String.format("仿真[%s]列车[%s]目标轨方向和目的地码方向不同", simulation.getGroup(), train.getGroupNumber()));
break;
}
//如果列车目标轨已经超出目的地码的对应区段
if (trainRight) {
if (targetStation.getSn() >= destinationSection.getStation().getSn()) {
break;
}
} else {
if (targetStation.getSn() <= destinationSection.getStation().getSn()) {
nextTarget = destinationCodeDefinition.queryNextTargetSection(headSection);
if (nextTarget == null) {
nextTarget = headStation.getNormalStand(destinationRight).get(0).getSection();
if (!headSection.equals(nextTarget)) {
List<RoutePath> routePaths = CalculateService.queryRoutePathsOnDirection(headSection, nextTarget, destinationRight);
if (!CollectionUtils.isEmpty(routePaths)) {
break;
}
}
}
//-------------------------- 找下一目标轨 --------------------------
Station adjacentStation = repository.findAdjacentStation(targetStation, destinationRight);
Section lastRunPathSection = destinationCodeDefinition.getLastSectionFromRunPath();
//---运行路径最后一个区段存在且列车没有越过时找相邻车站并注意路径---
if (lastRunPathSection != null) {
Station lastStationOnPath = lastRunPathSection.getStation();
//如果列车目标车站没有到达/越过目的地码运行路径的最后一个车站
if ((destinationRight && targetStation.getSn() < lastStationOnPath.getSn())
|| (!destinationRight && targetStation.getSn() > lastStationOnPath.getSn())) {
if (adjacentStation == null) {
break;
}
for (Stand stand : adjacentStation.getAllStandList()) {
if (destinationCodeDefinition.isOnThePath(stand.getSection())) {
nextTarget = stand.getSection();
break;
}
}
}
}
//尝试找到直达终点的路径
if (!CollectionUtils.isEmpty(repository.queryRoutePaths(targetSection, destinationSection))) {
nextTarget = destinationSection;
break;
}
//找到相邻车站的同向站台轨
for (Stand stand : adjacentStation.getStandOf(destinationRight)) {
if (!stand.isSmall()) {
nextTarget = stand.getSection();
break;
}
Station adjacentStation = simulation.getRepository().findAdjacentStation(headStation, destinationRight);
nextTarget = adjacentStation.getNormalStand(destinationRight).get(0).getSection();
}
break;
case OTHER:
@ -722,9 +717,9 @@ public class AtsTrainService {
// 更新扣车状态
if (!Objects.equals(train.isHold(), hold)) {
if (hold) {
this.onboardAtpApiService.holdTrain(simulation, train.getGroupNumber());
this.onboardAtpApiService.standHoldTrain(simulation, train.getGroupNumber());
} else {
this.onboardAtpApiService.cancelHoldTrain(simulation, train.getGroupNumber());
this.onboardAtpApiService.standCancelHoldTrain(simulation, train.getGroupNumber());
}
}
@ -795,14 +790,20 @@ public class AtsTrainService {
* 扣车
*/
public void hold(Simulation simulation, String groupNumber) {
onboardAtpApiService.holdTrain(simulation, groupNumber);
simulation.getRepository().getOnlineTrainList().forEach(train -> {
train.setTrainHold(true);
train.setHold(true);
});
}
/**
* 取消扣车
*/
public void cancelHold(Simulation simulation, String groupNumber) {
onboardAtpApiService.cancelHoldTrain(simulation, groupNumber);
simulation.getRepository().getOnlineTrainList().forEach(train -> {
train.setTrainHold(false);
train.setHold(false);
});
}
/**
@ -904,4 +905,42 @@ public class AtsTrainService {
VirtualRealityTrain train = simulation.getRepository().getOnlineTrainBy(groupNumber);
train.setRunType(runType);
}
/**
* 设置全线列车扣车
*/
public void setAllHold(Simulation simulation) {
simulation.getRepository().getOnlineTrainList().forEach(train -> {
train.setTrainHold(true);
train.setHold(true);
});
}
/**
* 取消权限列车扣车
*/
public void cancelAllHold(Simulation simulation) {
simulation.getRepository().getOnlineTrainList().forEach(train -> {
if (train.isTrainHold()) {
train.setTrainHold(false);
train.setHold(false);
}
});
}
/**
* 下令停车
*/
public void orderStop(Simulation simulation, String groupNumber) {
VirtualRealityTrain train = simulation.getRepository().getOnlineTrainBy(groupNumber);
train.setOrderStop(true);
}
/**
* 取消停车命令
*/
public void cancelOrderStop(Simulation simulation, String groupNumber) {
VirtualRealityTrain train = simulation.getRepository().getOnlineTrainBy(groupNumber);
train.setOrderStop(false);
}
}

View File

@ -9,7 +9,6 @@ import club.joylink.rtss.simulation.cbtc.data.support.SignalApproachMessage;
import club.joylink.rtss.simulation.cbtc.data.support.TrainStopMessage;
import club.joylink.rtss.simulation.cbtc.data.vo.TrainInfo;
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealitySectionAxleCounter;
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealitySwitch;
import club.joylink.rtss.simulation.cbtc.exception.SimulationException;
import club.joylink.rtss.simulation.cbtc.exception.SimulationExceptionType;
import lombok.extern.slf4j.Slf4j;
@ -87,7 +86,7 @@ public class CiApiServiceImpl implements CiApiService {
}
Optional<Route> routeOptional = simulation.getRepository().getSettingRoutes().stream()
.filter(route -> route.getStart().equals(signal)).limit(1).findAny();
BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(routeOptional.isPresent(),"信号机不是已排进路的始端信号机");
BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(routeOptional.isPresent(), "信号机不是已排进路的始端信号机");
// settingRoute(simulation, routeOptional.get().getCode());
Route lockedRoute = signal.getLockedRoute();
if (Objects.isNull(lockedRoute)) {
@ -107,15 +106,17 @@ public class CiApiServiceImpl implements CiApiService {
@Override
public void turn(Simulation simulation, String switchCode) {
Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class);
if (aSwitch.isReversePosition()) {
boolean toNormal = aSwitch.judgeTurnToNormal();
aSwitch.setLastTurnToNormal(toNormal);
if (toNormal) {
if (!this.switchService.turn2NormalPosition(simulation, aSwitch)) {
log.info(String.format("道岔[%s(%s)]锁闭,不能进行定操", aSwitch.getName(), aSwitch.getCode()));
throw new SimulationException(SimulationExceptionType.Operation_Handle_FAIL,"道岔锁闭,不能进行定操");
throw new SimulationException(SimulationExceptionType.Operation_Handle_FAIL, "道岔锁闭,不能进行定操");
}
} else {
if (!this.switchService.turn2ReversePosition(simulation, aSwitch)) {
log.info(String.format("道岔[%s(%s)]锁闭,不能进行反操", aSwitch.getName(), aSwitch.getCode()));
throw new SimulationException(SimulationExceptionType.Operation_Handle_FAIL,"道岔锁闭,不能进行反操");
throw new SimulationException(SimulationExceptionType.Operation_Handle_FAIL, "道岔锁闭,不能进行反操");
}
}
}
@ -125,7 +126,7 @@ public class CiApiServiceImpl implements CiApiService {
Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class);
if (!this.switchService.turn2NormalPosition(simulation, aSwitch)) {
log.info(String.format("道岔[%s(%s)]锁闭,不能进行定操", aSwitch.getName(), aSwitch.getCode()));
throw new SimulationException(SimulationExceptionType.Operation_Handle_FAIL,"道岔锁闭,不能进行定操");
throw new SimulationException(SimulationExceptionType.Operation_Handle_FAIL, "道岔锁闭,不能进行定操");
}
}
@ -134,7 +135,7 @@ public class CiApiServiceImpl implements CiApiService {
Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class);
if (!this.switchService.turn2ReversePosition(simulation, aSwitch)) {
log.info(String.format("道岔[%s(%s)]锁闭,不能进行反操", aSwitch.getName(), aSwitch.getCode()));
throw new SimulationException(SimulationExceptionType.Operation_Handle_FAIL,"道岔锁闭,不能进行反操");
throw new SimulationException(SimulationExceptionType.Operation_Handle_FAIL, "道岔锁闭,不能进行反操");
}
}
@ -512,17 +513,23 @@ public class CiApiServiceImpl implements CiApiService {
}
@Override
public void powerOnUnlock(Simulation simulation, Station station){
public void powerOnUnlock(Simulation simulation, Station station) {
if (!station.isCentralized()) {
station = station.getDeviceStation();
}
Station deviceStation = station;
if (Objects.nonNull(deviceStation.getRestartTime()) && deviceStation.getRestartTime().plusMinutes(8).isBefore(LocalTime.now())) {
if (Objects.nonNull(deviceStation.getRestartTime())
&& deviceStation.getRestartTime().isBefore(LocalTime.now())
&& ((Simulation.FunctionalType.LESSON.equals(simulation.getBuildParams().getFunctionalType())
|| Simulation.FunctionalType.EXAM.equals(simulation.getBuildParams().getFunctionalType()))
? true : deviceStation.getRestartTime().plusMinutes(8).isAfter(LocalTime.now()))) {
List<Section> sections = simulation.getRepository().getSectionList();
sections.stream().filter(section -> Objects.equals(section.getDeviceStation(), deviceStation)).forEach(Section::faultUnlock);
return;
}
throw BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.exception("无效操作或连锁机重启过8分钟需手动解锁");
throw BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.exception("无效操作或连锁机重启过8分钟需手动解锁");
}
@Override
public void standEB(Simulation simulation, Stand stand) {
if (stand.getEsp() == null)
@ -540,14 +547,13 @@ public class CiApiServiceImpl implements CiApiService {
@Override
public void switchForceTurn(Simulation simulation, String switchCode, Boolean normal) {
Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class);
BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(aSwitch.isSectionOccupied(), "道岔未被占用,不能使用强转");
BusinessExceptionAssertEnum.SIMULATION_EXCEPTION_FOR_SHOW.assertTrue(!aSwitch.isLocked() && aSwitch.isSectionOccupied(),
String.format("对%s强行转岔操作被联锁逻辑取消", aSwitch.getName()));
BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(!aSwitch.isLocked(), String.format("道岔[%s]锁闭,无法转动", aSwitch.getCode()));
VirtualRealitySwitch vrSwitch = aSwitch.getVirtualSwitch();
if (normal == null) {
BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertNotTrue(vrSwitch.isLoss(), "道岔不在定反位,不能转动");
normal = vrSwitch.isReverse();
normal = aSwitch.judgeTurnToNormal();
}
vrSwitch.startSetting(normal);
switchService.controlSwitch(simulation, aSwitch, normal);
}
@Override

View File

@ -34,10 +34,10 @@ public class SignalService {
public void blockade(Simulation simulation, Signal signal) {
if(!signal.isBlockade()) {
signal.setBlockade(true);
// if (signal.getLockedRoute() != null) {
// signal.setReblockade(true);
// log.debug(signal.debugStr() + "因信号机封锁且有锁闭的进路而重复封锁");
// }
if (signal.getLockedRoute() != null) {
signal.setReblockade(true);
log.debug(signal.debugStr() + "因信号机封锁且有锁闭的进路而重复封锁");
}
}
}

View File

@ -20,6 +20,7 @@ import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Objects;
import java.util.Random;
import java.util.stream.Collectors;
/**
@ -41,7 +42,14 @@ public class SwitchService {
* @param aSwitch
* @param toNormal
*/
private void controlSwitch(Simulation simulation, Switch aSwitch, boolean toNormal) {
public void controlSwitch(Simulation simulation, Switch aSwitch, boolean toNormal) {
if (simulation.getRepository().getConfig().isSwitchTurnOperationCanRecoverSplitFault()) {
if (new Random().nextInt(3) == 0) {
Switch.SwitchFault.SPLIT.fix(aSwitch);
Switch.SwitchFault.NORMAL_SPLIT.fix(aSwitch);
Switch.SwitchFault.REVERSE_SPLIT.fix(aSwitch);
}
}
VirtualRealitySwitch virtualSwitch = aSwitch.getVirtualSwitch();
if ((virtualSwitch.isNormal() && toNormal) ||
(virtualSwitch.isReverse() && !toNormal)) {

View File

@ -14,8 +14,8 @@ import club.joylink.rtss.vo.LoginUserInfoVO;
import club.joylink.rtss.vo.UserVO;
import club.joylink.rtss.vo.client.PageVO;
import club.joylink.rtss.vo.client.fault.FaultRuleVO;
import club.joylink.rtss.vo.client.map.DestinationCodeVO;
import club.joylink.rtss.vo.client.map.MapVO;
import club.joylink.rtss.vo.client.map.newmap.MapDestinationCodeDefinitionVO;
import club.joylink.rtss.vo.client.map.newmap.MapStationNewVO;
import club.joylink.rtss.vo.client.runplan.PlanTripNumberVO;
import club.joylink.rtss.vo.client.runplan.RunPlanEChartsDataVO;
@ -250,8 +250,9 @@ public interface GroupSimulationService {
/**
* 获取所有目的地码
* @return
*/
List<MapDestinationCodeDefinitionVO> getAllDestinationCode(String group);
List<DestinationCodeVO> getAllDestinationCode(String group);
/**
* 获取仿真报警列表

View File

@ -23,6 +23,7 @@ import club.joylink.rtss.simulation.cbtc.command.CommandInitiateVO;
import club.joylink.rtss.simulation.cbtc.communication.vo.fault.DeviceFaultInfo;
import club.joylink.rtss.simulation.cbtc.constant.SimulationConstants;
import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository;
import club.joylink.rtss.simulation.cbtc.data.map.DestinationCodeDefinition;
import club.joylink.rtss.simulation.cbtc.data.map.MayOutOfOrderDevice;
import club.joylink.rtss.simulation.cbtc.data.plan.TripPlan;
import club.joylink.rtss.simulation.cbtc.data.storage.StorageSimulation;
@ -45,8 +46,8 @@ import club.joylink.rtss.vo.client.*;
import club.joylink.rtss.vo.client.company.CompanyVO;
import club.joylink.rtss.vo.client.factory.SocketMessageFactory;
import club.joylink.rtss.vo.client.fault.FaultRuleVO;
import club.joylink.rtss.vo.client.map.DestinationCodeVO;
import club.joylink.rtss.vo.client.map.MapVO;
import club.joylink.rtss.vo.client.map.newmap.MapDestinationCodeDefinitionVO;
import club.joylink.rtss.vo.client.map.newmap.MapStationNewVO;
import club.joylink.rtss.vo.client.project.ProjectDeviceVO;
import club.joylink.rtss.vo.client.runplan.*;
@ -852,9 +853,11 @@ public class GroupSimulationServiceImpl implements GroupSimulationService {
}
@Override
public List<MapDestinationCodeDefinitionVO> getAllDestinationCode(String group) {
public List<DestinationCodeVO> getAllDestinationCode(String group) {
Simulation simulation = groupSimulationCache.getSimulationByGroup(group);
return simulation.getBuildParams().getMap().getLogicDataNew().getDestinationCodeDefinitionList();
Map<String, DestinationCodeDefinition> destinationMap = simulation.getRepository().getDestinationMap();
return simulation.getBuildParams().getMap().getLogicDataNew().getDestinationCodeDefinitionList()
.stream().map(vo -> new DestinationCodeVO(destinationMap.get(vo.getCode()))).collect(Collectors.toList());
}
@Override

View File

@ -1,5 +1,6 @@
package club.joylink.rtss.simulation.cbtc.build;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.cbtc.data.CalculateService;
import club.joylink.rtss.simulation.cbtc.data.map.*;
import club.joylink.rtss.simulation.cbtc.data.support.RoutePath;
@ -524,18 +525,27 @@ public class InterlockBuilder2 {
}
Set<String> checkCodeDuplicateSet = new HashSet<>(); //用于检查code重复
// List<Station> sortedBySnStations = elementMap.values().stream()
// .filter(element -> MapElement.DeviceType.STATION.equals(element.getDeviceType()))
// .map(element -> (Station) element)
// .sorted(Comparator.comparingInt(Station::getSn))
// .collect(Collectors.toList());
for (MapDestinationCodeDefinitionVO vo : destinationCodeDefinitionList) {
//构建目的地码定义需要的所有参数
String code = null;
DestinationCodeDefinition.Type type = null;
String description = null;
Section startSection = null;
Section section = null;
Boolean right = vo.getRight();
List<Section> necessarySections = new ArrayList<>();
Station leftStation = null;
Station rightStation = null;
Boolean leftFrontTurnBack = null;
Boolean rightFrontTurnBack = null;
List<Section> runPath = null;
Station stationA = null;
Boolean stationAFrontTurnBack = vo.getStationAFrontTurnBack();
Station stationB = null;
Boolean stationBFrontTurnBack = vo.getStationBFrontTurnBack();
List<Route> routes = null;
code = vo.getCode();
if (!checkCodeDuplicateSet.add(code)) {
@ -546,8 +556,18 @@ public class InterlockBuilder2 {
errMsgList.add(String.format("目的地码[%s]没有类型", code));
continue;
}
if (vo.getStartSectionCode() != null) {
startSection = (Section) elementMap.get(vo.getStartSectionCode());
}
if (vo.getSectionCode() != null) {
section = (Section) elementMap.get(vo.getSectionCode());
}
if (!CollectionUtils.isEmpty(vo.getRunPath())) {
necessarySections = vo.getRunPath().stream().map(pathSectionCode -> (Section) elementMap.get(pathSectionCode))
.collect(Collectors.toList());
}
switch (type) {
case NORMAL_OPERATION:
case NORMAL_OPERATION: {
description = vo.getDescription();
if (!StringUtils.hasText(description)) {
errMsgList.add(String.format("目的地码[%s]没有描述", code));
@ -560,38 +580,115 @@ public class InterlockBuilder2 {
errMsgList.add(String.format("环路类目的地码[%s]没有车站B", code));
continue;
}
stationA = (Station) elementMap.get(vo.getStationACode());
stationB = (Station) elementMap.get(vo.getStationBCode());
Station stationA = (Station) elementMap.get(vo.getStationACode());
Station stationB = (Station) elementMap.get(vo.getStationBCode());
boolean stationAFrontTurnBack = vo.getStationAFrontTurnBack() != null ? vo.getStationAFrontTurnBack() : false;
boolean stationBFrontTurnBack = vo.getStationBFrontTurnBack() != null ? vo.getStationBFrontTurnBack() : false;
if (stationA.getSn() > stationB.getSn()) {
leftStation = stationB;
leftFrontTurnBack = stationBFrontTurnBack;
rightStation = stationA;
rightFrontTurnBack = stationAFrontTurnBack;
} else {
leftStation = stationA;
leftFrontTurnBack = stationAFrontTurnBack;
rightStation = stationB;
rightFrontTurnBack = stationBFrontTurnBack;
}
//从左边车站右行站台站台轨开始构建运行路径--- 不标准的目的地码定义数据会导致运行路径构建错误
Set<Section> necessarySectionSet = new HashSet<>(necessarySections); //必经区段副本
Section startSection4RoutePath = null; //查询路径的起始区段
Section endSection4RoutePath = null; //查询路径的终点区段
runPath = new ArrayList<>();
routes = new ArrayList<>();
//从左端车站开始选择路径
startSection4RoutePath = screeningSection4DestinationCode(leftStation, leftFrontTurnBack, necessarySectionSet, true);
runPath.add(startSection4RoutePath);
endSection4RoutePath = screeningSection4DestinationCode(rightStation, rightFrontTurnBack, necessarySectionSet, false);
//查询并添加路径
RoutePath optimalPath = CalculateService.queryLeastSwitchRoutePath(startSection4RoutePath, endSection4RoutePath, necessarySectionSet, true);
BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.assertNotNull(optimalPath,
String.format("从%s到%s的路径未找到", startSection4RoutePath.debugStr(), endSection4RoutePath.debugStr()));
runPath.addAll(optimalPath.getSectionList());
routes.addAll(optimalPath.getRouteList());
//寻找反向的路径
Section t = startSection4RoutePath;
startSection4RoutePath = endSection4RoutePath;
endSection4RoutePath = t;
runPath.add(startSection4RoutePath);
RoutePath optimalPath2 = CalculateService.queryLeastSwitchRoutePath(startSection4RoutePath, endSection4RoutePath, necessarySectionSet, false);
BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.assertNotNull(optimalPath2,
String.format("从%s到%s的路径未找到", startSection4RoutePath.debugStr(), endSection4RoutePath.debugStr()));
runPath.addAll(optimalPath2.getSectionList());
routes.addAll(optimalPath2.getRouteList());
break;
}
case LAST_OPERATION:
case NON_OPERATION:
case LAST_NON_OPERATION:
case LAST_NON_OPERATION: {
description = vo.getDescription();
if (!StringUtils.hasText(description)) {
errMsgList.add(String.format("目的地码[%s]没有描述", code));
}
if (right == null) {
errMsgList.add(String.format("交路类目的地码[%s]没有方向", code));
if (startSection == null || right == null) {
errMsgList.add(String.format("单向目的地码[%s]没有起始区段或方向", code));
continue;
}
if (section == null) {
errMsgList.add(String.format("单向目的地码[%s]没有目标区段", code));
continue;
}
RoutePath routePath = CalculateService.queryLeastSwitchRoutePath(startSection, section, necessarySections, right);
BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.assertNotNull(routePath,
String.format("从%s到%s的路径未找到", startSection.debugStr(), section.debugStr()));
runPath = new ArrayList<>(routePath.getSectionList());
routes = new ArrayList<>(routePath.getRouteList());
}
case OTHER:
if (!StringUtils.hasText(vo.getSectionCode())) {
errMsgList.add(String.format("交路类目的地码[%s]没有目标区段", code));
if (section == null) {
errMsgList.add(String.format("单向目的地码[%s]没有目标区段", code));
continue;
}
section = (Section) elementMap.get(vo.getSectionCode());
if (!CollectionUtils.isEmpty(vo.getRunPath())) {
runPath = vo.getRunPath().stream().map(pathSectionCode -> (Section) elementMap.get(pathSectionCode))
.collect(Collectors.toList());
}
break;
}
DestinationCodeDefinition destinationCodeDefinition = new DestinationCodeDefinition(code, type, description, section,
right, runPath, stationA, stationAFrontTurnBack, stationB, stationBFrontTurnBack);
DestinationCodeDefinition destinationCodeDefinition = new DestinationCodeDefinition(code, type, description, startSection, section,
right, necessarySections, leftStation, leftFrontTurnBack, rightStation, rightFrontTurnBack, runPath, routes);
destinationMap.put(code, destinationCodeDefinition);
}
}
/**
* 为目的码筛选区段
*
* @param station
* @param ftb 是否站前折返
* @param preferredSections 优先区段
* @param right 站前折返时是否优先选择右向站台轨
*/
private static Section screeningSection4DestinationCode(Station station, Boolean ftb, Set<Section> preferredSections, boolean right) {
Section section;
if (ftb) {
Optional<Section> selectedSectionOptional = preferredSections.stream()
.filter(ns -> ns.isNormalStandTrack() && station.equals(ns.getStation())).limit(1).findAny(); //查询指定的站台轨
if (selectedSectionOptional.isPresent()) {
section = selectedSectionOptional.get();
} else { //没有指定折返轨
Section rdStandTack = station.getNormalStand(right).get(0).getSection();
if (rdStandTack.isTurnBackTrack()) {
section = rdStandTack;
} else {
section = station.getNormalStand(!right).get(0).getSection();
}
}
} else {
Optional<Section> selectedSectionOptional = preferredSections.stream()
.filter(ns -> ns.isTurnBackTrack() && station.equals(ns.getStation())).limit(1).findAny();
section = selectedSectionOptional.orElseGet(() -> station.getTurnBackList().get(0));
}
return section;
}
private static List<Routing> checkAndBuildRouting(List<MapRoutingDataVO> routingVOList, Map<String, MapElement> elementMap, List<String> errMsgList) {
List<Routing> routingList = new ArrayList<>();
if (CollectionUtils.isEmpty(routingVOList)) {

View File

@ -866,6 +866,15 @@ public class MapDeviceBuilder {
} else {
signal.setDeviceStation(deviceStation);
}
signal.setStation((Station) elementMap.get(signalVO.getBelongStationCode()));
// 所属车站
Station station = (Station) elementMap.get(signalVO.getBelongStationCode());
if (Objects.isNull(station)) {
// errMsgList.add(String.format("信号机[%s(%s)]未设置所属车站或所属车站不存在", signal.getName(), signal.getCode()));
} else {
signal.setStation(station);
}
// 所属联锁站
Station interlockStation = ((Station) elementMap.get(signalVO.getInterlockStationCode()));
if (Objects.isNull(interlockStation)) {
@ -886,6 +895,7 @@ public class MapDeviceBuilder {
}
signal.setRouteEnd(signalVO.isRouteEnd());
signal.setIgnoreRouteEnd(signalVO.getIgnoreRouteEnd());
signal.setNoRoute(signalVO.isNoRoute());
signal.setCtc(signalVO.isCtc());
signal.setCallOn(signalVO.isCallOn());
signal.setTurnBack(signalVO.isTurnBack());

View File

@ -379,7 +379,7 @@ public class CalculateService {
if (frequency > 50 || frequency < 0) {//防止寻找过大的站间轨迹
return null;
}
boolean isPathSection = false;
boolean isPathSection;
Float distance = startSection.getLen();
//获取左/右侧区段
Section nextSection = isRight ? startSection.getRightSection() : startSection.getLeftSection();
@ -395,12 +395,12 @@ public class CalculateService {
isPathSection = nextSection.getStandList().stream().anyMatch(stand ->
(!stand.isSmall()) && ((opposite ? !isRight : isRight) == stand.isRight()));
if (opposite
&& !Objects.equals(nextSection, endSection)
&& isPathSection
&& Objects.equals(nextSection.getStation(), endSection.getStation())) {
return null;
}
// if (opposite
// && !Objects.equals(nextSection, endSection)
// && isPathSection
// && Objects.equals(nextSection.getStation(), endSection.getStation())) {
// return null;
// }
//必经之路
if (isPathSection) {
list.addLast(nextSection);
@ -653,6 +653,48 @@ public class CalculateService {
return list;
}
/**
* 查询道岔最少的进路路径
*
* @param preferredSections 优先经过这些区段可以为null
*/
public static RoutePath queryLeastSwitchRoutePath(Section startSection, Section endSection, Collection<Section> preferredSections, boolean toRight) {
List<RoutePath> routePaths = CalculateService.queryRoutePathsOnDirection(startSection, endSection, toRight);
if (CollectionUtils.isEmpty(routePaths)) {
return null;
} else {
if (!CollectionUtils.isEmpty(preferredSections)) { //按经过优先区段的数量和长度筛选最优路径
RoutePath optimalPath = null;
int preferredSectionNum = 0;
int switchNum = 0;
for (RoutePath routePath : routePaths) {
int preferredSectionNumCopy = 0;
for (Section section : preferredSections) {
if (routePath.containsSection(section)) {
preferredSectionNumCopy++;
}
}
if (optimalPath == null) {
optimalPath = routePath;
preferredSectionNum = preferredSectionNumCopy;
switchNum = routePath.getSwitchQuantity();
} else {
if (preferredSectionNumCopy > preferredSectionNum) {
preferredSectionNum = preferredSectionNumCopy;
optimalPath = routePath;
switchNum = routePath.getSwitchQuantity();
} else if (preferredSectionNumCopy == preferredSectionNum && routePath.getSwitchQuantity() < switchNum) {
optimalPath = routePath;
switchNum = routePath.getSwitchQuantity();
}
}
}
return optimalPath;
}
return routePaths.stream().min(Comparator.comparingDouble(RoutePath::getLength)).orElse(null);
}
}
private static void queryRoutePaths(int iter, Section section, RoutePath routePath,
List<RoutePath> list, List<String> warnList) {
if (section == null) {
@ -660,8 +702,8 @@ public class CalculateService {
routePath.debugStr(), routePath.getLastSection().debugStr()));
return;
}
if (iter > 10) {
warnList.add(String.format("进路路径[%s]未找到迭代10次,最后区段为[%s]",
if (iter > 100) {
warnList.add(String.format("进路路径[%s]未找到迭代100次,最后区段为[%s]",
routePath.debugStr(), routePath.getLastSection().debugStr()));
return;
}

View File

@ -1,5 +1,6 @@
package club.joylink.rtss.simulation.cbtc.data.map;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.cbtc.exception.SimulationException;
import club.joylink.rtss.simulation.cbtc.exception.SimulationExceptionType;
import lombok.Getter;
@ -18,6 +19,8 @@ public class DestinationCodeDefinition {
private String description;
//----------- 交路类属性 -----------
private Section startSection;
/**
* 交路类目的地码对应的区段
*/
@ -26,9 +29,9 @@ public class DestinationCodeDefinition {
private Boolean right;
/**
* 运行路径sectionCode
* 必经区段
*/
private List<Section> runPath;
private List<Section> necessarySections;
//----------- 环路类属性 -----------
/**
* 车站A
@ -50,31 +53,34 @@ public class DestinationCodeDefinition {
*/
private Boolean rightFrontTurnBack;
//根据目的地码的定义数据生成路径
/**
* 目的地码代表的运行路径物理区段
*/
private List<Section> runPath;
private List<Route> routes;
public DestinationCodeDefinition(String code, Type type, Section section) {
this(code, type, null, section, null, null, null, null, null, null);
this(code, type, null, null, section, null, null, null, null, null, null, null, null);
}
public DestinationCodeDefinition(String code, Type type, String description, Section section, Boolean right,
List<Section> runPath, Station stationA, Boolean stationAFrontTurnBack, Station stationB, Boolean stationBFrontTurnBack) {
public DestinationCodeDefinition(String code, Type type, String description, Section startSection, Section section, Boolean right,
List<Section> necessarySections, Station leftStation, Boolean leftFrontTurnBack,
Station rightStation, Boolean rightFrontTurnBack, List<Section> runPath, List<Route> routes) {
this.code = code;
this.type = type;
this.description = description;
this.startSection = startSection;
this.section = section;
this.right = right;
this.necessarySections = necessarySections;
this.leftStation = leftStation;
this.leftFrontTurnBack = leftFrontTurnBack;
this.rightStation = rightStation;
this.rightFrontTurnBack = rightFrontTurnBack;
this.runPath = runPath;
if (Objects.nonNull(stationA) && Objects.nonNull(stationB)) {
if (stationA.getSn() > stationB.getSn()) {
this.leftStation = stationB;
this.leftFrontTurnBack = stationBFrontTurnBack;
this.rightStation = stationA;
this.rightFrontTurnBack = stationAFrontTurnBack;
} else {
this.leftStation = stationA;
this.leftFrontTurnBack = stationAFrontTurnBack;
this.rightStation = stationB;
this.rightFrontTurnBack = stationBFrontTurnBack;
}
}
this.routes = routes;
}
/**
@ -93,20 +99,20 @@ public class DestinationCodeDefinition {
* 获取运行路径上最后一个区段
*/
public Section getLastSectionFromRunPath() {
if (!CollectionUtils.isEmpty(runPath)) {
return runPath.get(runPath.size() - 1);
if (!CollectionUtils.isEmpty(necessarySections)) {
return necessarySections.get(necessarySections.size() - 1);
}
return null;
}
/**
* 该区段在运行路径上
* 该区段是必经区段
*/
public boolean isOnThePath(Section section) {
if (CollectionUtils.isEmpty(runPath)) {
public boolean isNecessarySection(Section section) {
if (CollectionUtils.isEmpty(necessarySections)) {
return false;
}
return runPath.stream().anyMatch(path -> Objects.equals(path, section));
return necessarySections.stream().anyMatch(path -> Objects.equals(path, section));
}
public boolean isLoop() {
@ -151,42 +157,47 @@ public class DestinationCodeDefinition {
* 该目的地码定义中是否包含该区段
*/
public boolean containsSection(Section section, boolean right) {
Station station = section.getStation();
if (this.isLoop()) { // 环路判断逻辑是站台轨在范围内或为终点站台轨
if (!section.isNormalStandTrack()) {
return false;
}
if (Objects.equals(this.getEndStationParkSection(right), section)) {
return true;
}
int sn = this.getStationOf(right).getSn();
if (Objects.equals(section.getStandList().get(0).isRight(), right)) {
if ((right && station.getSn() < sn) ||
(!right && station.getSn() > sn)) {
if (!CollectionUtils.isEmpty(runPath)) {
BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.assertNotTrue(Type.OTHER.equals(type), logStr() + "是其它类目的地码,无法判定是否包含某区段");
return runPath.contains(section);
} else {
Station station = section.getStation();
if (this.isLoop()) { // 环路判断逻辑是站台轨在范围内或为终点站台轨
if (!section.isNormalStandTrack()) {
return false;
}
if (Objects.equals(this.getEndStationParkSection(right), section)) {
return true;
}
}
} else {
if (!Objects.equals(this.right, right)) {
return false;
}
// 暂时判断逻辑为或者是runPath中一个或者是范围内车站且是对应方向站台
if (!CollectionUtils.isEmpty(this.runPath)) {
return this.runPath.contains(section);
}
if (Objects.nonNull(station)) {
if (!CollectionUtils.isEmpty(section.getStandList()) &&
Objects.equals(section.getStandList().get(0).isRight(), this.right)) {
int sn = this.section.getStation().getSn();
if ((this.right && station.getSn() <= sn) ||
(!this.right && station.getSn() >= sn)) {
int sn = this.getStationOf(right).getSn();
if (Objects.equals(section.getStandList().get(0).isRight(), right)) {
if ((right && station.getSn() < sn) ||
(!right && station.getSn() > sn)) {
return true;
}
}
} else {
if (!Objects.equals(this.right, right)) {
return false;
}
// 暂时判断逻辑为或者是runPath中一个或者是范围内车站且是对应方向站台
if (!CollectionUtils.isEmpty(this.necessarySections)) {
return this.necessarySections.contains(section);
}
if (Objects.nonNull(station)) {
if (!CollectionUtils.isEmpty(section.getStandList()) &&
Objects.equals(section.getStandList().get(0).isRight(), this.right)) {
int sn = this.section.getStation().getSn();
if ((this.right && station.getSn() <= sn) ||
(!this.right && station.getSn() >= sn)) {
return true;
}
}
}
return Objects.equals(this.section, section);
}
return Objects.equals(this.section, section);
return false;
}
return false;
}
/**
@ -196,6 +207,90 @@ public class DestinationCodeDefinition {
return station.equals(leftStation) || station.equals(rightStation);
}
/**
* 查询下一个功能区段
*/
public Section queryNextTargetSection(Section currentSection) {
if (!CollectionUtils.isEmpty(runPath)) { //有指定路径
int index = runPath.indexOf(currentSection);
if (index == -1) {
return null;
} else if (index == runPath.size() - 1) {
if (!Type.NORMAL_OPERATION.equals(type)) {
return null;
}
}
if (!Type.NORMAL_OPERATION.equals(type)) { //非环路找到路径末就结束
for (int i = index + 1; i < runPath.size(); i++) {
Section section = runPath.get(i);
if (section.isNormalStandTrack()) {
return section;
}
if (section.isFunctionTrack()) {
if (necessarySections.contains(section)) {
return section;
}
}
}
} else { //环路循环找
int next = index + 1;
for (int i = 0; i < runPath.size(); i++) {
if (next == runPath.size()) {
next = 0;
continue;
}
Section section = runPath.get(next);
if (section.isNormalStandTrack()) {
return section;
}
if (section.isFunctionTrack()) {
if (necessarySections.contains(section)) {
return section;
}
}
next++;
}
}
} else { //无指定路径
}
return null;
}
public String logStr() {
return String.format("目的地码[%s]", code);
}
/**
* 查询下一个要办理的进路
*/
public Route queryNextRoute(Section section) {
List<Route> routeList = this.routes;
if (CollectionUtils.isEmpty(routeList)) {
return null;
}
Integer routeIndex = null;
for (int i = 0; i < routeList.size(); i++) {
Route route = routeList.get(i);
if (route.isRouteSection(section)) {
routeIndex = i;
}
}
if (routeIndex == null) {
return null;
}
if (routeIndex < routes.size() - 1) {
return routes.get(routeIndex + 1);
} else {
if (Type.NORMAL_OPERATION.equals(type)) {
return routes.get(0);
} else {
return null;
}
}
}
public enum Type {
/**
* 正常运营环路

View File

@ -201,6 +201,11 @@ public class MapConfig {
*/
private boolean stationPreResetBeforeAxlePreReset;
/**
* 道岔转动操作可以使失表故障恢复
*/
private boolean switchTurnOperationCanRecoverSplitFault;
private Set<SimulationMember.Type> needConfirmConnectMembers =
Stream.of(DISPATCHER, STATION_SUPERVISOR, MAINTAINER, ELECTRIC_DISPATCHER).collect(Collectors.toSet());
@ -242,6 +247,7 @@ public class MapConfig {
setBlockadeCommandOnlyValidInStandbyMode(configVO.isBlockadeCommandOnlyValidInStandbyMode());
setSomeCommandNeedInit(configVO.isSwitchBlockadeCommandNeedInit());
setStationPreResetBeforeAxlePreReset(configVO.isStationPreResetBeforeAxlePreReset());
setSwitchTurnOperationCanRecoverSplitFault(configVO.isSwitchTurnOperationCanRecoverSplitFault());
}
}

View File

@ -391,6 +391,9 @@ public class Section extends MayOutOfOrderDevice {
* 区段列车出清
*/
public void clearOccupy() {
if (AxleFault.CBTC_OCCUPIED_FAULT.equals(this.getFault())) {
return;
}
synchronized (this){
this.ctOccupied = false;
if (this.isAxleCounter()) {
@ -1029,12 +1032,19 @@ public class Section extends MayOutOfOrderDevice {
section.setFault(this);
return true;
}
},
CBTC_OCCUPIED_FAULT{
@Override
public void fix(MayOutOfOrderDevice device) {
public boolean apply(MayOutOfOrderDevice device) {
Section section = (Section) device;
if (!CollectionUtils.isEmpty(section.getLogicList()))
return false;
if (this.equals(section.getFault()))
section.setFault(null);
return false;
section.setFault(this);
section.setCtOccupied(true);
return true;
}
}
}

View File

@ -35,6 +35,11 @@ public class Signal extends MayOutOfOrderDevice {
*/
private Station deviceStation;
/**
* 所属车站
*/
private Station station;
/**
* 联锁站
*/
@ -75,6 +80,11 @@ public class Signal extends MayOutOfOrderDevice {
*/
private List<String> ignoreRouteEnd;
/**
* 不生成以该信号机为始端的进路
*/
private boolean noRoute;
/**
* 是否引导信号机
*/

View File

@ -1,5 +1,6 @@
package club.joylink.rtss.simulation.cbtc.data.map;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.cbtc.constant.SimulationConstants;
import club.joylink.rtss.simulation.cbtc.constant.TurnBackStrategyType;
import club.joylink.rtss.simulation.cbtc.data.support.StationTurnBackStrategyOption;
@ -376,10 +377,10 @@ public class Station extends MayOutOfOrderDevice {
}
/**
* 该区段所属的站台是否右向
* 该区段所属的正常站台是否右向
*/
public boolean isStandOfSectionRight(@NonNull Section section) {
List<Stand> stands = this.getAllStandList();
List<Stand> stands = this.getAllNormalStands();
for (Stand stand : stands) {
if (section.equals(stand.getSection())) {
return stand.isRight();
@ -410,6 +411,26 @@ public class Station extends MayOutOfOrderDevice {
return this.preResetValidDuration != null && this.preResetValidDuration.get() > 0;
}
/**
* 查询优先的折返轨
*/
public Section queryFirstTurnBackSection() {
if (CollectionUtils.isEmpty(this.tbStrategyMap) || this.tbStrategyId == null) {
return null;
}
StationTurnBackStrategyOption strategy = getCurrentTurnBackStrategy();
switch (strategy.getType()) {
case NONE:
case EQUAL:
return null;
case FIRST:
case ONLY:
return strategy.getSectionList().get(0);
default:
throw BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.exception("未知的折返策略类型" + strategy.getType());
}
}
public enum ControlMode {
/**
* 交出未被接收
@ -484,6 +505,13 @@ public class Station extends MayOutOfOrderDevice {
return stands.stream().filter(stand -> !stand.isSmall()).collect(Collectors.toList());
}
/**
* 获取所有正常站台
*/
public List<Stand> getAllNormalStands() {
return getAllStandList().stream().filter(stand -> !stand.isSmall()).collect(Collectors.toList());
}
public String debugStr() {
return String.format("车站[%s]", this.getName());
}

View File

@ -129,6 +129,11 @@ public class Switch extends MayOutOfOrderDevice {
*/
private boolean init;
/**
* 上一次是否是将道岔转向定位
*/
private Boolean lastTurnToNormal;
@Override
public void reset() {
super.reset();
@ -148,6 +153,7 @@ public class Switch extends MayOutOfOrderDevice {
this.interlockReserve = false;
this.blockadeInvalid = false;
this.init = false;
this.lastTurnToNormal = null;
}
/**
@ -407,10 +413,23 @@ public class Switch extends MayOutOfOrderDevice {
return !this.isNormalPosition() && !this.isReversePosition();
}
public void forceUnlock() {
this.routeLock = false;
this.overlapLock = false;
this.fpLock = false;
/**
* 判断道岔转动的方向
*/
public boolean judgeTurnToNormal() {
boolean toNormal;
if (this.reversePosition) {
toNormal = true;
} else if (this.normalPosition) {
toNormal = false;
} else {
if (this.lastTurnToNormal != null) {
toNormal = !this.lastTurnToNormal;
} else {
toNormal = true;
}
}
return toNormal;
}
public enum SwitchFault implements DeviceFault {
@ -493,7 +512,7 @@ public class Switch extends MayOutOfOrderDevice {
/**
* 计轴故障
*/
AXLE_FAULT{
AXLE_FAULT {
@Override
public boolean apply(MayOutOfOrderDevice device) {
Switch aSwitch = (Switch) device;
@ -507,6 +526,23 @@ public class Switch extends MayOutOfOrderDevice {
Section section = aSwitch.getA().getParent();
Section.AxleFault.FAULT.fix(section);
}
},
/**
* 通信车占用故障
*/
CBTC_OCCUPIED_FAULT {
@Override
public boolean apply(MayOutOfOrderDevice device) {
Switch aSwitch = (Switch) device;
return Section.AxleFault.CBTC_OCCUPIED_FAULT.apply(aSwitch.getA());
}
@Override
public void fix(MayOutOfOrderDevice device) {
Switch aSwitch = (Switch) device;
Section.AxleFault.CBTC_OCCUPIED_FAULT.fix(aSwitch.getA());
}
}
}
}

View File

@ -1,6 +1,5 @@
package club.joylink.rtss.simulation.cbtc.data.status;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import club.joylink.rtss.simulation.cbtc.constant.DriveMode;
import club.joylink.rtss.simulation.cbtc.constant.PlanRoutingType;
import club.joylink.rtss.simulation.cbtc.constant.RunLevel;
@ -10,6 +9,7 @@ import club.joylink.rtss.simulation.cbtc.data.vo.DeviceStatusVO;
import club.joylink.rtss.simulation.cbtc.data.vo.TrainInfo;
import club.joylink.rtss.simulation.cbtc.data.vo.TrainStatusVO;
import club.joylink.rtss.util.jsonSerialize.Boolean2NumSerializer;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lombok.Getter;
import lombok.Setter;
@ -103,6 +103,8 @@ public class TrainStatus extends DeviceStatus {
@JsonSerialize(using = Boolean2NumSerializer.class)
private boolean backUp;
private boolean orderStop;
public TrainStatus(TrainInfo train) {
super(train.getGroupNumber(), MapElement.DeviceType.TRAIN);
this.groupNumber = train.getGroupNumber();
@ -128,6 +130,7 @@ public class TrainStatus extends DeviceStatus {
this.hold = train.isHold();
this.dt = train.getDt();
this.backUp = train.isBackUp();
this.orderStop = train.isOrderStop();
}
/**
@ -243,6 +246,11 @@ public class TrainStatus extends DeviceStatus {
status.setDt(this.dt);
change = true;
}
if (!Objects.equals(this.orderStop, train.isOrderStop())) {
this.orderStop = train.isOrderStop();
status.setOrderStop(this.orderStop);
change = true;
}
return change;
}
@ -269,6 +277,7 @@ public class TrainStatus extends DeviceStatus {
statusVO.setDispose(dispose);
statusVO.setStop(stop);
statusVO.setBackUp(backUp);
statusVO.setOrderStop(orderStop);
return statusVO;
}

View File

@ -95,6 +95,7 @@ public class RoutePath {
routePath.addSignal(signal);
}
routePath.addSections(this.sectionList);
routePath.addRoutes(this.routeList);
return routePath;
}
@ -373,10 +374,19 @@ public class RoutePath {
return this.sectionList.get(this.sectionList.size() - 1);
}
public int getSwitchQuantity() {
if (CollectionUtils.isEmpty(routeList)) {
return 0;
}
return routeList.stream().mapToInt(route -> CollectionUtils.isEmpty(route.getSwitchList()) ? 0 : route.getSwitchList().size()).sum();
}
public String debugStr() {
Station startStation = this.start.getStation();
Station endStation = this.end.getStation();
return String.format("%s(%s)->%s(%s)",
this.start.getStation().getName(), this.start.getName(),
this.end.getStation().getName(), this.end.getName());
startStation != null ? startStation.getName() : null, this.start.getName(),
endStation != null ? endStation.getName() : null, this.end.getName());
}
public String debugStr2() {
@ -400,4 +410,11 @@ public class RoutePath {
signals,
routes);
}
/**
* 路径包含的区段是否被占用除了start
*/
public boolean isOccupied() {
return end.isOccupied() || sectionList.stream().anyMatch(Section::isOccupied);
}
}

View File

@ -146,6 +146,9 @@ public class TrainInfo extends MapElement {
@Setter
private List<Section> headPath;
/** 下令停车 */
private boolean orderStop;
public TrainInfo(String groupNumber) {
super(groupNumber, DeviceType.TRAIN);
this.groupNumber = groupNumber;
@ -253,6 +256,7 @@ public class TrainInfo extends MapElement {
this.hold = train.isHold();
this.priorityRouteSet = train.isHold();
this.backUp = train.isBackUp();
this.orderStop = train.isOrderStop();
}
public boolean isCbtcTrack() {

View File

@ -1,13 +1,13 @@
package club.joylink.rtss.simulation.cbtc.data.vo;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import club.joylink.rtss.simulation.cbtc.constant.DriveMode;
import club.joylink.rtss.simulation.cbtc.constant.PlanRoutingType;
import club.joylink.rtss.simulation.cbtc.constant.RunLevel;
import club.joylink.rtss.simulation.cbtc.constant.TrainType;
import club.joylink.rtss.simulation.cbtc.data.map.MapElement;
import club.joylink.rtss.util.jsonSerialize.Boolean2NumSerializer;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@ -102,6 +102,9 @@ public class TrainStatusVO extends DeviceStatusVO {
@JsonSerialize(using = Boolean2NumSerializer.class)
private Boolean backUp;
@JsonSerialize(using = Boolean2NumSerializer.class)
private Boolean orderStop;
public TrainStatusVO(TrainInfo train) {
super(train.getGroupNumber(), MapElement.DeviceType.TRAIN);
}

View File

@ -266,6 +266,11 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
*/
private boolean hold;
/**
* 当前扣车是否是列车扣车联合hold使用
*/
private boolean trainHold;
/**
* 是否自动折返中
*/
@ -373,6 +378,11 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
*/
private RunType runType;
/**
* 下令停车
*/
private boolean orderStop;
public void setRunType(RunType runType) {
this.runType = runType;
switch (runType) {
@ -435,6 +445,7 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
this.nextParking = false;
this.jump = false;
this.hold = false;
this.trainHold = false;
this.terminalStation = null;
this.headPosition = null;
this.robotTargetPosition = null;
@ -466,6 +477,7 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
this.linkTrain = null;
this.lastTwoPassedResponders = new FixedQueue<>(Responders_Record);
this.runType = null;
this.orderStop = false;
}
public boolean isEB() {

View File

@ -75,6 +75,11 @@ public class ATOService {
if (!train.isPowerOn() || !train.isAtoOn()) {
return;
}
//下令停车
if (train.isOrderStop()) {
this.doBreakMax(train);
return;
}
// 计算到目标/授权终点剩余距离根据距离计算速度根据速度控制牵引/制动输出
MovementAuthority ma = train.getMa();
if (Objects.isNull(ma)) {

View File

@ -64,14 +64,14 @@ public interface OnboardAtpApiService {
* @param simulation
* @param groupNumber
*/
void holdTrain(Simulation simulation, String groupNumber);
void standHoldTrain(Simulation simulation, String groupNumber);
/**
* 取消扣车
* @param simulation
* @param groupNumber
*/
void cancelHoldTrain(Simulation simulation, String groupNumber);
void standCancelHoldTrain(Simulation simulation, String groupNumber);
/**
* 设置跳停

View File

@ -131,17 +131,21 @@ public class OnboardAtpApiServiceImpl implements OnboardAtpApiService {
}
@Override
public void holdTrain(Simulation simulation, String groupNumber) {
public void standHoldTrain(Simulation simulation, String groupNumber) {
SimulationDataRepository repository = simulation.getRepository();
VirtualRealityTrain train = repository.getVRByCode(groupNumber, VirtualRealityTrain.class);
train.setHold(true);
if (!train.isTrainHold()) {
train.setHold(true);
}
}
@Override
public void cancelHoldTrain(Simulation simulation, String groupNumber) {
public void standCancelHoldTrain(Simulation simulation, String groupNumber) {
SimulationDataRepository repository = simulation.getRepository();
VirtualRealityTrain train = repository.getVRByCode(groupNumber, VirtualRealityTrain.class);
train.setHold(false);
if (!train.isTrainHold()) {
train.setHold(false);
}
}
@Override

View File

@ -50,24 +50,14 @@ public class DefaultSubscribeManager {
}
wsIdDestMap.put(this.buildWsSessionSubId(wsSessionId, subId), destination);
String sid = Simulation.tryExtractSidFromDestination(destination);
SimulationUser simulationUser = this.tryGetSimulationUser(sid, user.getName());
if (simulationUser == null) {
if (sid == null) {
return;
}
simulationUser.subscribe(wsSessionId, destination);
wsSidMap.put(wsSessionId, sid);
}
private SimulationUser tryGetSimulationUser(String sid, String userId) {
if (sid == null) {
return null;
}
Simulation simulation = this.simulationManager.queryById(sid);
if (simulation == null) {
return null;
if (simulation != null) {
simulation.handleUserSubscribe(user.getName(), wsSessionId, destination);
}
SimulationUser simulationUser = simulation.querySimulationUserById(userId);
return simulationUser;
wsSidMap.put(wsSessionId, sid);
}
private String buildWsSessionSubId(String wsSessionId, String subId) {
@ -77,11 +67,16 @@ public class DefaultSubscribeManager {
public void unsubscribe(WebsocketConfig.MyPrincipal user, String wsSessionId, String subId) {
String key = this.buildWsSessionSubId(wsSessionId, subId);
String destination = wsIdDestMap.remove(key);
String sid = Simulation.tryExtractSidFromDestination(destination);
SimulationUser simulationUser = this.tryGetSimulationUser(sid, user.getName());
if (simulationUser == null) {
if (destination == null) {
return;
}
simulationUser.unsubscribe(wsSessionId, destination);
String sid = Simulation.tryExtractSidFromDestination(destination);
if (sid == null) {
return;
}
Simulation simulation = this.simulationManager.queryById(sid);
if (simulation != null) {
simulation.handleUserUnsubscribe(user.getName(), wsSessionId, destination);
}
}
}

View File

@ -1,14 +1,18 @@
package club.joylink.rtss.simulation.operation;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.Simulation;
import club.joylink.rtss.simulation.SimulationManager;
import club.joylink.rtss.simulation.SimulationMember;
import club.joylink.rtss.simulation.operation.converter.ConvertUtil;
import club.joylink.rtss.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Parameter;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import java.util.Map;
@Slf4j
@ -29,8 +33,8 @@ public class SimulationOperationDispatcher {
return handlerMethod.getMethod().invoke(handlerMethod.getBean(), args);
} catch (Exception e) {
log.error(String.format("仿真[%s]操作[%s]分发异常", id, operation), e);
throw BusinessExceptionAssertEnum.SIMULATION_OPERATION_FAILED.exception(e);
}
return null;
}
private Object[] buildParameters(Simulation simulation, OperationHandlerMethod handlerMethod, Map<String, Object> params) {
@ -43,10 +47,20 @@ public class SimulationOperationDispatcher {
continue;
}
Object o = params.get(parameter.getName());
// 简单对象处理
args[i] = ConvertUtil.convert(o, parameter.getType());
// 复杂对象处理需要再加
// if (args[i] == null && o != null) {
// }
// 复杂对象处理
if (args[i] == null && o != null) {
if (List.class.isAssignableFrom(parameter.getType())) {
ParameterizedType parameterizedType = (ParameterizedType) parameter.getParameterizedType();
Class<?> actualClass = (Class<?>) parameterizedType.getActualTypeArguments()[0];
args[i] = JsonUtils.read(JsonUtils.writeValueAsString(params.get(parameter.getName())),
JsonUtils.getCollectionType(parameter.getType(), actualClass));
} else {
args[i] = JsonUtils.read(JsonUtils.writeValueAsString(params.get(parameter.getName())),
parameter.getType());
}
}
}
return args;
}

View File

@ -1,30 +1,15 @@
package club.joylink.rtss.simulation.rt;
import club.joylink.rtss.simulation.Simulation;
import club.joylink.rtss.simulation.rt.srd.bo.SrdRepository;
import lombok.Getter;
@Getter
public class RtSimulation extends Simulation<RtSimulationUser, RtSimulationMember> {
/**
* 模拟真实设备数据仓库
*/
SrdRepository srdRepository;
public RtSimulation(String id) {
super(id);
}
@Override
protected void initState() {
}
public void setSrdRepository(SrdRepository srdRepository) {
this.srdRepository = srdRepository;
}
@Override
public String debugStr() {
return String.format("轨道交通仿真[%s]", getId());

View File

@ -1,32 +1,42 @@
package club.joylink.rtss.simulation.rt;
import club.joylink.rtss.services.MapService;
import club.joylink.rtss.simulation.SimulationManager;
import club.joylink.rtss.simulation.rt.srd.SrdService;
import club.joylink.rtss.vo.UserVO;
import club.joylink.rtss.vo.client.map.MapVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Objects;
@Component
public class RtSimulationService {
@Autowired
private MapService mapService;
@Autowired
private SimulationManager simulationManager;
@Autowired
private SrdService srdService;
public RtSimulation create(UserVO userVO) {
public RtSimulation create(UserVO userVO, Long mapId) {
Objects.requireNonNull(mapId);
MapVO mapVO = this.mapService.getMapDetail(mapId);
RtSimulation rtSimulation = new RtSimulation(SimulationIdGenerator.buildId());
this.simulationManager.save(rtSimulation);
this.load(rtSimulation);
this.loadData(rtSimulation, mapVO);
this.srdService.addJobs(rtSimulation);
this.simulationManager.save(rtSimulation);
return rtSimulation;
}
/**
* 加载相关数据
* @param rtSimulation
* @param mapVO
*/
private void load(RtSimulation rtSimulation) {
private void loadData(RtSimulation rtSimulation, MapVO mapVO) {
this.srdService.buildRepository(rtSimulation, mapVO);
}
}

View File

@ -1,10 +1,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.SrTrain;
import club.joylink.rtss.simulation.rt.srd.bo.SrdRepository;
import club.joylink.rtss.simulation.rt.srd.bo.SrdRepositoryBuilder;
import club.joylink.rtss.simulation.rt.srd.bo.TrackPosition;
import club.joylink.rtss.simulation.rt.srd.bo.*;
import club.joylink.rtss.vo.client.map.MapVO;
import org.springframework.stereotype.Component;
@ -16,26 +14,88 @@ public class SrdService {
public void buildRepository(RtSimulation rtSimulation, MapVO mapVO) {
SrdRepository srdRepository = SrdRepositoryBuilder.buildFrom(mapVO);
rtSimulation.setSrdRepository(srdRepository);
rtSimulation.addRepository(srdRepository);
}
public void addJobs(RtSimulation rtSimulation) {
rtSimulation.addJob("srTrainRun",
() -> this.srTrainRun(rtSimulation.getSrdRepository()),
() -> this.srTrainRun(rtSimulation.getRepository(SrdRepository.NAME, SrdRepository.class)),
TRAIN_RUN_RATE);
}
public void srTrainRun(SrdRepository repository) {
List<SrTrain> trainList = repository.getTrainList();
for (SrTrain srTrain : trainList) {
if (!srTrain.isUsing()) {
continue;
}
TrackPosition position = srTrain.getPosition();
if (position == null) { // 列车没有位置
continue;
long speed = srTrain.getSpeed();
boolean right = srTrain.isRight();
int cv = this.calculateSpeed(srTrain);
int s = this.calculateLen(cv, TRAIN_RUN_RATE);
TrackPosition np = calculatePosition(position, s, right);
if (np.equals(position) && cv != 0) {
cv = 0;
}
if (srTrain.isNeutralGear()) { // 空挡
continue;
}
srTrain.updatePositionAndSpeed(np, cv);
}
}
private int calculateLen(int cv, int time) {
return cv * time;
}
private int calculateSpeed(SrTrain srTrain) {
long speed = srTrain.getSpeed();
int wa = (int) (10 + speed * 0.001 + speed * speed * 0.0000003); // 阻力所产生的反向加速度
int pa = 0;
if (srTrain.isEb()) {
pa = SrTrain.ES_DEC;
} else {
pa = srTrain.getP() >= 0 ? srTrain.getP() * SrTrain.MAX_ACC : srTrain.getP() * SrTrain.MAX_DEC;
}
int a = pa - wa;
int cv = (int) (speed + a * TRAIN_RUN_RATE); // 当前速度
if (cv < 0) {
cv = 0;
}
return cv;
}
private TrackPosition calculatePosition(TrackPosition position, int s, boolean right) {
if (s == 0) {
return position;
}
SrTrack track = position.getTrack();
int offset = position.getOffset();
if (right) {
offset += s;
} else {
offset -= s;
}
SrTrack base = track;
while (offset < 0 || offset > base.getLen()) {
SrTrack nextTrack = base.queryNextTrack(right);
if (nextTrack == null) {
if (offset < 0) {
offset = 0;
} else {
offset = base.getLen();
}
break;
} else {
if (right) {
BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.assertNotTrue(offset < 0);
offset -= base.getLen();
} else {
BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.assertNotTrue(offset > base.getLen());
offset += nextTrack.getLen();
}
base = nextTrack;
}
}
return new TrackPosition(base, offset);
}
}

View File

@ -25,13 +25,21 @@ public class SrTrack extends SrDevice {
*/
SrAXC axc;
/**
* 左侧轨道可能为null
* 左侧直向轨道可能为null
*/
SrTrack left;
SrTrack leftTrack;
/**
* 左侧侧向轨道非道岔的都为null
*/
SrTrack leftFlankTrack;
/**
* 右侧轨道可能为null
*/
SrTrack right;
SrTrack rightTrack;
/**
* 右侧侧向轨道非道岔的都为null
*/
SrTrack rightFlankTrack;
/**
* 关联的道岔是道岔区段才会关联否则为null
*/
@ -45,17 +53,52 @@ public class SrTrack extends SrDevice {
this.axc = axc;
}
public void setLeft(SrTrack left) {
this.left = left;
left.setRight(this);
public void setLeftTrack(SrTrack left) {
this.leftTrack = left;
left.setRightTrack(this);
}
public void setRight(SrTrack right) {
this.right = right;
right.setLeft(this);
public void setLeftFlankTrack(SrTrack leftFlank) {
this.leftFlankTrack = leftFlank;
leftFlank.setRightTrack(this);
}
public void setRightTrack(SrTrack right) {
this.rightTrack = right;
right.setLeftTrack(this);
}
public void setRightFlankTrack(SrTrack rightFlank) {
this.rightFlankTrack = rightFlank;
rightFlank.setLeftTrack(this);
}
public void setTurnout(SrTurnout turnout) {
this.turnout = turnout;
}
public SrTrack queryNextTrack(boolean right) {
if (this.turnout != null) {
if (this.turnout.isNormalPosition()) {
return right ? this.rightTrack : this.leftTrack;
} else if (this.turnout.isReversePosition()) {
if (right) {
if (this.rightFlankTrack != null) {
return this.rightFlankTrack;
} else {
return this.rightTrack;
}
} else {
if (this.leftFlankTrack != null) {
return this.leftFlankTrack;
} else {
return this.leftTrack;
}
}
}
} else {
return right ? this.rightTrack : this.leftTrack;
}
return null;
}
}

View File

@ -7,6 +7,10 @@ import lombok.Getter;
*/
@Getter
public class SrTrain extends SrDevice {
/**
* 是否使用中
*/
boolean using;
/**
* 列车长度,单位mm
@ -15,13 +19,29 @@ public class SrTrain extends SrDevice {
/**
* 列车质量,单位
*/
int mass = 230;
int mass = 224;
/**
* 牵引力,<0为制动
* 最大加速度, 单位mm/s2
*/
int f;
public static final int MAX_ACC = 1600;
/**
* 列车速度
* 最大常用制动加速度, 单位mm/s2
*/
public static final int MAX_DEC = -1200;
/**
* 紧急制动加速度, 单位mm/s2
*/
public static final int ES_DEC = -1500;
/**
* 功率-100 <= p <= 100
*/
int p;
/**
* 是否紧急制动
*/
boolean eb;
/**
* 列车速度,单位mm/s
*/
int speed;
/**
@ -48,4 +68,9 @@ public class SrTrain extends SrDevice {
public boolean isNeutralGear() {
return NEUTRAL == this.gear;
}
public void updatePositionAndSpeed(TrackPosition position, int v) {
this.position = position;
this.speed = v;
}
}

View File

@ -30,18 +30,27 @@ public class SrTurnout extends SrDevice {
super(id, DeviceType.TURNOUT);
}
public void setA(SrTrack a) {
public void setTracks(SrTrack a, SrTrack b, SrTrack c) {
this.a = a;
a.setTurnout(this);
}
public void setB(SrTrack b) {
this.b = b;
b.setTurnout(this);
this.c = c;
if (this.a.leftTrack == null && this.a.rightTrack == null) {
throw new IllegalStateException("道岔a区段两端都没有关联的区段");
}
if (this.a.leftTrack != null) { // a左侧存在
this.a.setRightTrack(this.b);
this.a.setRightFlankTrack(this.c);
} else { // a右侧存在
this.a.setLeftTrack(this.b);
this.a.setLeftFlankTrack(this.c);
}
}
public void setC(SrTrack c) {
this.c = c;
c.setTurnout(this);
public boolean isNormalPosition() {
return NORMAL == this.state.get();
}
public boolean isReversePosition() {
return REVERSE == this.state.get();
}
}

View File

@ -1,11 +1,14 @@
package club.joylink.rtss.simulation.rt.srd.bo;
import club.joylink.rtss.simulation.SimulationRepository;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class SrdRepository {
public class SrdRepository extends SimulationRepository {
public static final String NAME = "SDR";
Map<String, SrTrack> trackMap;
Map<String, SrAXC> axcMap;
@ -15,6 +18,7 @@ public class SrdRepository {
Map<String, SrTrain> trainMap;
public SrdRepository() {
super(NAME);
this.trackMap = new HashMap<>();
this.axcMap = new HashMap<>();
this.turnoutMap = new HashMap<>();
@ -26,4 +30,9 @@ public class SrdRepository {
public List<SrTrain> getTrainList() {
return new ArrayList<>(this.trainMap.values());
}
@Override
public void initState() {
}
}

View File

@ -43,13 +43,13 @@ public class SrdRepositoryBuilder {
SrTrack left = trackMap.get(sectionVO.getLeftSectionCode());
BusinessExceptionAssertEnum.DATA_ERROR.assertNotNull(left,
String.format("区段[%s]的左关联区段[%s]不存在", srTrack.getId(), sectionVO.getLeftSectionCode()));
srTrack.setLeft(left);
srTrack.setLeftTrack(left);
}
if (StringUtils.hasText(sectionVO.getRightSectionCode())) {
SrTrack right = trackMap.get(sectionVO.getRightSectionCode());
BusinessExceptionAssertEnum.DATA_ERROR.assertNotNull(right,
String.format("区段[%s]的右关联区段[%s]不存在", srTrack.getId(), sectionVO.getRightSectionCode()));
srTrack.setRight(right);
srTrack.setRightTrack(right);
}
// 构建轨道和计轴关系
SrAXC axc;
@ -91,9 +91,7 @@ public class SrdRepositoryBuilder {
BusinessExceptionAssertEnum.DATA_ERROR.assertNotNull(c,
String.format("道岔[%s]关联区段C[%s]不存在", switchVO.getCode(), switchVO.getSectionCCode()));
SrTurnout turnout = turnoutMap.get(switchVO.getCode());
turnout.setA(a);
turnout.setB(b);
turnout.setC(c);
turnout.setTracks(a, b, c);
}
}

View File

@ -3,4 +3,17 @@ package club.joylink.rtss.simulation.rt.srd.bo;
public class TrackPosition {
SrTrack track;
int offset;
public TrackPosition(SrTrack track, int offset) {
this.track = track;
this.offset = offset;
}
public SrTrack getTrack() {
return track;
}
public int getOffset() {
return offset;
}
}

View File

@ -0,0 +1,44 @@
package club.joylink.rtss.vo.client.map;
import club.joylink.rtss.simulation.cbtc.data.map.DestinationCodeDefinition;
import club.joylink.rtss.simulation.cbtc.data.map.MapElement;
import lombok.Getter;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Getter
public class DestinationCodeVO {
private String code;
private String description;
private List<String> runPath;
public DestinationCodeVO(DestinationCodeDefinition definition) {
this.code = definition.getCode();
this.description = definition.getDescription();
if (!CollectionUtils.isEmpty(definition.getRoutes())) {
this.runPath = definition.getRoutes().stream().flatMap(route -> {
return route.getSectionList().stream().flatMap(section -> {
if (!CollectionUtils.isEmpty(section.getLogicList())) {
return section.getLogicList().stream();
} else {
return Stream.of(section);
}
}).map(MapElement::getCode);
}).collect(Collectors.toList());
}
// if (!CollectionUtils.isEmpty(definition.getRunPath())) {
// this.runPath = definition.getRunPath().stream().flatMap(section -> {
// if (!CollectionUtils.isEmpty(section.getLogicList())) {
// return section.getLogicList().stream();
// } else {
// return Stream.of(section);
// }
// }).map(MapElement::getCode).collect(Collectors.toList());
// }
}
}

View File

@ -151,7 +151,7 @@ public class MapVO {
}
@JsonIgnore
public MapSectionNewVO findSectionNew(String code) {
public MapSectionNewVO findSection(String code) {
MapGraphDataNewVO graphData = this.getGraphDataNew();
if (Objects.nonNull(graphData)) {
List<MapSectionNewVO> sectionList = graphData.getSectionList();
@ -163,6 +163,19 @@ public class MapVO {
return null;
}
@JsonIgnore
public MapStationNewVO findStation(String code) {
MapGraphDataNewVO graphData = this.getGraphDataNew();
if (Objects.nonNull(graphData)) {
List<MapStationNewVO> stationList = graphData.getStationList();
if (!CollectionUtils.isEmpty(stationList)) {
MapStationNewVO station = stationList.stream().filter(mapStationNewVO -> mapStationNewVO.getCode().equals(code)).findFirst().orElse(null);
return station;
}
}
return null;
}
@JsonIgnore
public List<MapStationNewVO> findSortedAllStationListNew() {

View File

@ -140,6 +140,11 @@ public class RealLineConfigVO {
*/
private boolean stationPreResetBeforeAxlePreReset;
/**
* 道岔转动操作可以使失表故障恢复
*/
private boolean switchTurnOperationCanRecoverSplitFault;
public static RealLineConfigVO parseJsonStr(String configData) {
if (StringUtils.hasText(configData)) {
return JsonUtils.read(configData, RealLineConfigVO.class);

View File

@ -69,6 +69,9 @@ public class MapCiGenerateConfig {
@ApiModelProperty(value = "若生成进路信号按钮,进路信号按钮是否取最近的一个信号机")
private boolean getNearlySignal;
@ApiModelProperty("是否生成目的地码定义(泰雷兹式)")
private boolean generateDestination;
// @ApiModelProperty(value = "是否分开生成ATP联锁和地面信号联锁")
// private boolean apartGroundAndAtp;

View File

@ -28,6 +28,11 @@ public class MapDestinationCodeDefinitionVO {
private String description;
//----------- 交路类属性 -----------
/**
* 单向目的地码的起始区段
*/
private String startSectionCode;
/**
* 交路类目的地码对应的区段
*/
@ -68,12 +73,27 @@ public class MapDestinationCodeDefinitionVO {
vo.code = definition.getCode();
vo.type = definition.getType();
vo.description = definition.getDescription();
if (definition.getStartSection() != null) {
vo.startSectionCode = definition.getStartSection().getCode();
}
if (definition.getSection() != null) {
vo.sectionCode = definition.getSection().getCode();
}
vo.right = definition.getRight();
if (!CollectionUtils.isEmpty(definition.getRunPath())) {
vo.runPath =definition.getRunPath().stream().map(MapElement::getCode).collect(Collectors.toList());
if (!CollectionUtils.isEmpty(definition.getNecessarySections())) {
vo.runPath =definition.getNecessarySections().stream().map(MapElement::getCode).collect(Collectors.toList());
}
if (definition.getLeftStation() != null) {
vo.stationACode = definition.getLeftStation().getCode();
}
if (definition.getLeftFrontTurnBack() != null) {
vo.stationAFrontTurnBack = definition.getLeftFrontTurnBack();
}
if (definition.getRightStation() != null) {
vo.stationBCode = definition.getRightStation().getCode();
}
if (definition.getRightFrontTurnBack() != null) {
vo.stationBFrontTurnBack = definition.getRightFrontTurnBack();
}
return vo;
}

View File

@ -46,6 +46,9 @@ public class MapSignalNewVO {
@ApiModelProperty(value = "不生成进路的信号机终端")
private List<String> ignoreRouteEnd;
@ApiModelProperty("是否不生成进路")
private boolean noRoute;
/**
* 所属区段编码
*/

View File

@ -1,13 +1,12 @@
package club.joylink.rtss.vo.client.runplan;
import club.joylink.rtss.simulation.cbtc.constant.SimulationConstants;
import club.joylink.rtss.vo.client.map.newmap.MapSectionNewVO;
import club.joylink.rtss.vo.client.runplan.user.RunPlanRoutingVO;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import club.joylink.rtss.simulation.cbtc.data.plan.TripPlan;
import club.joylink.rtss.vo.client.map.MapRoutingVO;
import club.joylink.rtss.vo.client.map.newmap.MapRoutingDataVO;
import club.joylink.rtss.vo.client.runplan.user.RunPlanRoutingVO;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@ -15,7 +14,6 @@ import lombok.Setter;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
@ -120,43 +118,51 @@ public class RunPlanTripVO {
this.timeList = new ArrayList<>();
}
public RunPlanTripVO(RunPlanTripConfigVO tripConfigVO, MapRoutingVO routingVO) {
this.directionCode = routingVO.getDirectionCode();
this.destinationCode = routingVO.getDestinationCode();
this.startSectionCode = routingVO.getStartSectionCode();
this.endSectionCode = routingVO.getEndSectionCode();
this.startTime = tripConfigVO.getStartTime().minusHours(SimulationConstants.RUN_DIAGRAM_TRANS_TIME);
this.endTime = tripConfigVO.getEndTime().minusHours(SimulationConstants.RUN_DIAGRAM_TRANS_TIME);
this.timeList = new ArrayList<>();
}
// public RunPlanTripVO(RunPlanTripConfigVO tripConfigVO, MapRoutingVO routingVO) {
// this.directionCode = routingVO.getDirectionCode();
// this.destinationCode = routingVO.getDestinationCode();
// this.startSectionCode = routingVO.getStartSectionCode();
// this.endSectionCode = routingVO.getEndSectionCode();
// this.startTime = tripConfigVO.getStartTime().minusHours(SimulationConstants.RUN_DIAGRAM_TRANS_TIME);
// this.endTime = tripConfigVO.getEndTime().minusHours(SimulationConstants.RUN_DIAGRAM_TRANS_TIME);
// this.timeList = new ArrayList<>();
// }
//
// public RunPlanTripVO(RunPlanTripConfigVO tripConfigVO, MapRoutingDataVO routingVO) {
// this.right = routingVO.getRight();
// this.destinationCode = routingVO.getDestinationCode();
// this.startSectionCode = routingVO.getStartSectionCode();
// this.endSectionCode = routingVO.getEndSectionCode();
// this.startTime = tripConfigVO.getStartTime().minusHours(SimulationConstants.RUN_DIAGRAM_TRANS_TIME);
// this.endTime = tripConfigVO.getEndTime().minusHours(SimulationConstants.RUN_DIAGRAM_TRANS_TIME);
// this.timeList = new ArrayList<>();
// }
public RunPlanTripVO(RunPlanTripConfigVO tripConfigVO, MapRoutingDataVO routingVO) {
public RunPlanTripVO(RunPlanRoutingVO routingVO) {
this.right = routingVO.getRight();
this.destinationCode = routingVO.getDestinationCode();
this.startSectionCode = routingVO.getStartSectionCode();
this.endSectionCode = routingVO.getEndSectionCode();
this.startTime = tripConfigVO.getStartTime().minusHours(SimulationConstants.RUN_DIAGRAM_TRANS_TIME);
this.endTime = tripConfigVO.getEndTime().minusHours(SimulationConstants.RUN_DIAGRAM_TRANS_TIME);
this.timeList = new ArrayList<>();
}
public RunPlanTripVO(RunPlanTripConfigVO tripConfigVO, RunPlanRoutingVO routingVO , MapSectionNewVO startReentrySection, MapSectionNewVO endReentrySection) {
this.right = routingVO.getRight();
this.destinationCode = Objects.nonNull(endReentrySection) ? endReentrySection.getDestinationCode() : routingVO.getDestinationCode();
this.startSectionCode = Objects.nonNull(startReentrySection) ? startReentrySection.getCode() : routingVO.getStartSectionCode();
this.endSectionCode = Objects.nonNull(endReentrySection) ? endReentrySection.getCode() : routingVO.getEndSectionCode();
this.startTime = tripConfigVO.getStartTime().minusHours(SimulationConstants.RUN_DIAGRAM_TRANS_TIME).minusSeconds(40);
this.endTime = tripConfigVO.getEndTime().minusHours(SimulationConstants.RUN_DIAGRAM_TRANS_TIME).plusSeconds(40);
this.timeList = new ArrayList<>();
}
public RunPlanTripVO(RunPlanRoutingVO routingVO , MapSectionNewVO startReentrySection, MapSectionNewVO endReentrySection) {
this.right = routingVO.getRight();
this.destinationCode = Objects.nonNull(endReentrySection) ? endReentrySection.getDestinationCode() : routingVO.getDestinationCode();
this.startSectionCode = Objects.nonNull(startReentrySection) ? startReentrySection.getCode() : routingVO.getStartSectionCode();
this.endSectionCode = Objects.nonNull(endReentrySection) ? endReentrySection.getCode() : routingVO.getEndSectionCode();
this.timeList = new ArrayList<>();
}
// public RunPlanTripVO(RunPlanTripConfigVO tripConfigVO, RunPlanRoutingVO routingVO , MapSectionNewVO startReentrySection, MapSectionNewVO endReentrySection) {
// this.right = routingVO.getRight();
// this.destinationCode = Objects.nonNull(endReentrySection) ? endReentrySection.getDestinationCode() : routingVO.getDestinationCode();
// this.startSectionCode = Objects.nonNull(startReentrySection) ? startReentrySection.getCode() : routingVO.getStartSectionCode();
// this.endSectionCode = Objects.nonNull(endReentrySection) ? endReentrySection.getCode() : routingVO.getEndSectionCode();
// this.startTime = tripConfigVO.getStartTime().minusHours(SimulationConstants.RUN_DIAGRAM_TRANS_TIME).minusSeconds(40);
// this.endTime = tripConfigVO.getEndTime().minusHours(SimulationConstants.RUN_DIAGRAM_TRANS_TIME).plusSeconds(40);
// this.timeList = new ArrayList<>();
// }
//
// public RunPlanTripVO(RunPlanRoutingVO routingVO , MapSectionNewVO startReentrySection, MapSectionNewVO endReentrySection) {
// this.right = routingVO.getRight();
// this.destinationCode = Objects.nonNull(endReentrySection) ? endReentrySection.getDestinationCode() : routingVO.getDestinationCode();
// this.startSectionCode = Objects.nonNull(startReentrySection) ? startReentrySection.getCode() : routingVO.getStartSectionCode();
// this.endSectionCode = Objects.nonNull(endReentrySection) ? endReentrySection.getCode() : routingVO.getEndSectionCode();
// this.timeList = new ArrayList<>();
// }
public RunPlanTripVO(TripPlan plan) {
this.serviceNumber = plan.getServiceNumber();
@ -179,6 +185,9 @@ public class RunPlanTripVO {
}
public void addTime(RunPlanTripTimeVO timeVO) {
if(Objects.isNull(timeList)){
timeList = new ArrayList<>();
}
this.timeList.add(timeVO);
}

View File

@ -1,17 +1,13 @@
package club.joylink.rtss.vo.client.runplan.user;
import club.joylink.rtss.simulation.cbtc.data.map.Section;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.util.CollectionUtils;
import javax.validation.constraints.NotBlank;
import java.util.ArrayList;
import java.util.List;
@ApiModel(value="交路经停区段草稿")
@NoArgsConstructor
@ -28,13 +24,4 @@ public class RunPlanRoutingSection {
@NotBlank(message = "区段编号不能为空")
private String sectionCode;
public static List<RunPlanRoutingSection> from(List<Section> viaSectionList) {
List<RunPlanRoutingSection> voList = new ArrayList<>();
if (!CollectionUtils.isEmpty(viaSectionList)) {
for (Section section : viaSectionList) {
voList.add(new RunPlanRoutingSection(section.getStation().getCode(), section.getCode()));
}
}
return voList;
}
}

View File

@ -2,6 +2,9 @@ package club.joylink.rtss.vo.client.runplan.user;
import club.joylink.rtss.entity.RunPlanRouting;
import club.joylink.rtss.util.JsonUtils;
import club.joylink.rtss.vo.client.map.MapVO;
import club.joylink.rtss.vo.client.map.newmap.MapSectionNewVO;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
@ -12,7 +15,9 @@ import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@ApiModel(value = "运行图用户交路对象")
@ -67,6 +72,11 @@ public class RunPlanRoutingVO {
@ApiModelProperty(value = "描述")
private String remarks;
/**起始车站是否站前折返站前折返站后折返null 不是折返*/
private Boolean startTbFront;
/**终到车站是否站前折返站前折返站后折返null 不是折返*/
private Boolean endTbFront;
public RunPlanRoutingVO() {
this.parkSectionCodeList = new ArrayList<>();
@ -91,6 +101,26 @@ public class RunPlanRoutingVO {
return routingVO;
}
public static RunPlanRoutingVO convert2VO(RunPlanRouting runPlanRouting, MapVO mapVO ) {
RunPlanRoutingVO routingVO = new RunPlanRoutingVO();
routingVO.setId(runPlanRouting.getId());
routingVO.setMapId(runPlanRouting.getMapId());
routingVO.setUserId(runPlanRouting.getUserId());
routingVO.setName(runPlanRouting.getName());
routingVO.setCode(runPlanRouting.getCode());
routingVO.setRoutingType(UserRoutingType.valueOf(runPlanRouting.getType()));
routingVO.setStartStationCode(runPlanRouting.getStartStationCode());
routingVO.setStartSectionCode(runPlanRouting.getStartSectionCode());
routingVO.setEndStationCode(runPlanRouting.getEndStationCode());
routingVO.setEndSectionCode(runPlanRouting.getEndSectionCode());
routingVO.setRight(runPlanRouting.getRight());
routingVO.setDestinationCode(runPlanRouting.getDestinationCode());
routingVO.setRemarks(runPlanRouting.getRemarks());
routingVO.setParkSectionCodeList(JsonUtils.readCollection(runPlanRouting.getSectionData(), List.class, RunPlanRoutingSection.class));
routingVO.setReentryType(mapVO);
return routingVO;
}
public RunPlanRouting convert2Entity() {
RunPlanRouting routing = new RunPlanRouting();
routing.setId(id);
@ -128,6 +158,34 @@ public class RunPlanRoutingVO {
return runPlanRoutings.stream().map(RunPlanRoutingVO::convert2VO).collect(Collectors.toList());
}
public static List<RunPlanRoutingVO> convert2VOList(List<RunPlanRouting> runPlanRoutings, MapVO mapVO) {
return runPlanRoutings.stream().map(r -> RunPlanRoutingVO.convert2VO(r, mapVO)).collect(Collectors.toList());
}
@JsonIgnore
public boolean isOutBoundRoute(){
return Objects.equals(UserRoutingType.OUTBOUND,routingType);
}
@JsonIgnore
public boolean isInBoundRoute(){
return Objects.equals(UserRoutingType.INBOUND,routingType);
}
@JsonIgnore
public boolean isLoopRoute(){
return Objects.equals(UserRoutingType.LOOP,routingType);
}
@JsonIgnore
private void setReentryType(MapVO mapVO){
if(isOutBoundRoute() || isLoopRoute()){
MapSectionNewVO endReentrySection = mapVO.findSection(endSectionCode);
endTbFront = endReentrySection.isReentryTrack() && endReentrySection.isStandTrack();
}
if(isInBoundRoute() || isLoopRoute()){
MapSectionNewVO startReentrySection = mapVO.findSection(startSectionCode);
startTbFront = startReentrySection.isReentryTrack() && startReentrySection.isStandTrack();
}
}
public enum UserRoutingType{
OUTBOUND,
INBOUND,

View File

@ -148,7 +148,8 @@ public class RunPlanRunlevelVO {
public static List<RunPlanRunlevelVO> runLevelsFromRouting(RunPlanRoutingVO routingVO) {
List<RunPlanRoutingSection> parkSectionList = routingVO.getParkSectionCodeList();
List<RunPlanRunlevelVO> list = new ArrayList<>();
for (int i = 0; i < parkSectionList.size()-1; i++) {
int n = parkSectionList.size()- 1;
for (int i = 0; i < n; i++) {
RunPlanRunlevelVO runlevelVO = new RunPlanRunlevelVO();
runlevelVO.setMapId(routingVO.getMapId());
runlevelVO.setUserId(routingVO.getUserId());

View File

@ -4,13 +4,12 @@ import club.joylink.rtss.entity.RunPlanUserConfig;
import club.joylink.rtss.util.JsonUtils;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import lombok.*;
import org.springframework.util.CollectionUtils;
import javax.validation.constraints.NotEmpty;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@ -19,6 +18,7 @@ import java.util.stream.Collectors;
@ApiModel(value = "运行图用户基础配置对象")
@Getter
@Setter
@NoArgsConstructor
public class RunPlanUserConfigVO {
@ApiModelProperty(hidden = true)
@ -33,8 +33,15 @@ public class RunPlanUserConfigVO {
@ApiModelProperty(value = "交路编号")
@NotNull(message = "交路编号不能为空")
@Valid
private Config config;
public RunPlanUserConfigVO(Long mapId, Long userId, Config config) {
this.mapId = mapId;
this.userId = userId;
this.config = config;
}
public static RunPlanUserConfigVO convert2VO(RunPlanUserConfig runPlanUserConfig) {
RunPlanUserConfigVO routingVO = new RunPlanUserConfigVO();
// routingVO.setId(runPlanUserConfig.getId());
@ -58,7 +65,7 @@ public class RunPlanUserConfigVO {
}
public boolean hasReentryData(){
return Objects.nonNull(config) && !CollectionUtils.isEmpty(config.getRunPlanUserReentryData());
return Objects.nonNull(config) && !CollectionUtils.isEmpty(config.reentryData);
}
@Getter
@ -68,6 +75,22 @@ public class RunPlanUserConfigVO {
/**运行车站折返配置数据:车站code->折返轨code*/
@ApiModelProperty(value = "运行车站折返配置数据")
@NonNull
private Map<String,String> runPlanUserReentryData;
private Map<String,ReentryTime> reentryData=new HashMap<>();
// private Map<String,String> runPlanUserReentryData;
}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public static class ReentryTime{
/**站前折返s*/
private Integer tbFront;
/**站后折返s*/
private Integer tbBack;
/**从股道到折返s*/
private Integer tbFrom;
/**从折返到股道s*/
private Integer tbTo;
}
}

View File

@ -1,11 +1,14 @@
package club.joylink.rtss.vo.client.student;
import club.joylink.rtss.services.OrgUserService;
import io.swagger.annotations.ApiModel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@ApiModel(value = "导出学生信息")
@Getter
@ -27,4 +30,12 @@ public class ExportStudentInfo {
public ExportStudentInfo() {
this.scores = new ArrayList<>();
}
public String getStudentID() {
if(Objects.nonNull(studentID)){
return studentID.substring(0,studentID.indexOf(OrgUserService.companyCodePrefix));
}
return null;
}
}

View File

@ -0,0 +1,79 @@
package club.joylink.rtss.vo.pfp;
import club.joylink.rtss.entity.PfStationParam;
import club.joylink.rtss.entity.PfStationParamWithBLOBs;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.util.CollectionUtils;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Getter
@Setter
@NoArgsConstructor
public class PfpVO {
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
/**
* 名称
*/
private String name;
/**
* 用户id
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long userId;
/**
* 更新时间
*/
private LocalDateTime updateTime;
private String regionData;
private String sceneConfig;
private String simulationConfig;
public PfpVO(PfStationParam param) {
this.id = param.getId();
this.name = param.getName();
this.userId = param.getUserId();
this.updateTime = param.getUpdateTime();
}
public PfpVO(PfStationParamWithBLOBs param) {
this.id = param.getId();
this.name = param.getName();
this.userId = param.getUserId();
this.updateTime = param.getUpdateTime();
this.regionData = param.getRegionData();
this.sceneConfig = param.getSceneConfig();
this.simulationConfig = param.getSimulationConfig();
}
public static List<PfpVO> convert2VOList(List<PfStationParam> list) {
List<PfpVO> voList = new ArrayList<>();
if (!CollectionUtils.isEmpty(list)) {
for (PfStationParam param : list) {
voList.add(new PfpVO(param));
}
}
return voList;
}
public PfStationParamWithBLOBs toDb() {
PfStationParamWithBLOBs db = new PfStationParamWithBLOBs();
db.setName(this.name);
db.setRegionData(this.regionData);
db.setSceneConfig(this.sceneConfig);
db.setSimulationConfig(this.simulationConfig);
return db;
}
}

View File

@ -26,9 +26,9 @@ public class RunPlanInput {
@NotBlank(message= "环路不能为空")
private String runningRouting2;
/**折返时间*/
@ApiModelProperty(value = "折返时间")
private int reentryTime;
// /**折返时间*/
// @ApiModelProperty(value = "折返时间")
// private int reentryTime;
/**运行等级默认-站间运行时间*/
private int runLevel=3;

View File

@ -52,9 +52,9 @@ public class RunPlanInputData {
@ApiModelProperty(value = "发车间隔,s")
private Integer departureInterval ;
/**折返时间*/
@ApiModelProperty(value = "折返时间")
private int reentryTime = 80;
// /**折返时间*/
// @ApiModelProperty(value = "折返时间")
// private int reentryTime = 80;
/**运行等级默认-站间运行时间*/
private int runLevel = 3;

View File

@ -0,0 +1,293 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="club.joylink.rtss.dao.PfStationParamDAO">
<resultMap id="BaseResultMap" type="club.joylink.rtss.entity.PfStationParam">
<id column="id" jdbcType="BIGINT" property="id" />
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="user_id" jdbcType="BIGINT" property="userId" />
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="club.joylink.rtss.entity.PfStationParamWithBLOBs">
<result column="region_data" jdbcType="LONGVARCHAR" property="regionData" />
<result column="scene_config" jdbcType="LONGVARCHAR" property="sceneConfig" />
<result column="simulation_config" jdbcType="LONGVARCHAR" property="simulationConfig" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
<foreach collection="oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Update_By_Example_Where_Clause">
<where>
<foreach collection="example.oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Base_Column_List">
id, `name`, user_id, update_time
</sql>
<sql id="Blob_Column_List">
region_data, scene_config, simulation_config
</sql>
<select id="selectByExampleWithBLOBs" parameterType="club.joylink.rtss.entity.PfStationParamExample" resultMap="ResultMapWithBLOBs">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
from pf_station_param
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
<if test="limit != null">
<if test="offset != null">
limit ${offset}, ${limit}
</if>
<if test="offset == null">
limit ${limit}
</if>
</if>
</select>
<select id="selectByExample" parameterType="club.joylink.rtss.entity.PfStationParamExample" resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
from pf_station_param
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
<if test="limit != null">
<if test="offset != null">
limit ${offset}, ${limit}
</if>
<if test="offset == null">
limit ${limit}
</if>
</if>
</select>
<select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="ResultMapWithBLOBs">
select
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
from pf_station_param
where id = #{id,jdbcType=BIGINT}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
delete from pf_station_param
where id = #{id,jdbcType=BIGINT}
</delete>
<delete id="deleteByExample" parameterType="club.joylink.rtss.entity.PfStationParamExample">
delete from pf_station_param
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</delete>
<insert id="insert" keyColumn="id" keyProperty="id" parameterType="club.joylink.rtss.entity.PfStationParamWithBLOBs" useGeneratedKeys="true">
insert into pf_station_param (`name`, user_id, update_time,
region_data, scene_config, simulation_config
)
values (#{name,jdbcType=VARCHAR}, #{userId,jdbcType=BIGINT}, #{updateTime,jdbcType=TIMESTAMP},
#{regionData,jdbcType=LONGVARCHAR}, #{sceneConfig,jdbcType=LONGVARCHAR}, #{simulationConfig,jdbcType=LONGVARCHAR}
)
</insert>
<insert id="insertSelective" keyColumn="id" keyProperty="id" parameterType="club.joylink.rtss.entity.PfStationParamWithBLOBs" useGeneratedKeys="true">
insert into pf_station_param
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="name != null">
`name`,
</if>
<if test="userId != null">
user_id,
</if>
<if test="updateTime != null">
update_time,
</if>
<if test="regionData != null">
region_data,
</if>
<if test="sceneConfig != null">
scene_config,
</if>
<if test="simulationConfig != null">
simulation_config,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="name != null">
#{name,jdbcType=VARCHAR},
</if>
<if test="userId != null">
#{userId,jdbcType=BIGINT},
</if>
<if test="updateTime != null">
#{updateTime,jdbcType=TIMESTAMP},
</if>
<if test="regionData != null">
#{regionData,jdbcType=LONGVARCHAR},
</if>
<if test="sceneConfig != null">
#{sceneConfig,jdbcType=LONGVARCHAR},
</if>
<if test="simulationConfig != null">
#{simulationConfig,jdbcType=LONGVARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="club.joylink.rtss.entity.PfStationParamExample" resultType="java.lang.Long">
select count(*) from pf_station_param
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</select>
<update id="updateByExampleSelective" parameterType="map">
update pf_station_param
<set>
<if test="record.id != null">
id = #{record.id,jdbcType=BIGINT},
</if>
<if test="record.name != null">
`name` = #{record.name,jdbcType=VARCHAR},
</if>
<if test="record.userId != null">
user_id = #{record.userId,jdbcType=BIGINT},
</if>
<if test="record.updateTime != null">
update_time = #{record.updateTime,jdbcType=TIMESTAMP},
</if>
<if test="record.regionData != null">
region_data = #{record.regionData,jdbcType=LONGVARCHAR},
</if>
<if test="record.sceneConfig != null">
scene_config = #{record.sceneConfig,jdbcType=LONGVARCHAR},
</if>
<if test="record.simulationConfig != null">
simulation_config = #{record.simulationConfig,jdbcType=LONGVARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExampleWithBLOBs" parameterType="map">
update pf_station_param
set id = #{record.id,jdbcType=BIGINT},
`name` = #{record.name,jdbcType=VARCHAR},
user_id = #{record.userId,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=TIMESTAMP},
region_data = #{record.regionData,jdbcType=LONGVARCHAR},
scene_config = #{record.sceneConfig,jdbcType=LONGVARCHAR},
simulation_config = #{record.simulationConfig,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExample" parameterType="map">
update pf_station_param
set id = #{record.id,jdbcType=BIGINT},
`name` = #{record.name,jdbcType=VARCHAR},
user_id = #{record.userId,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=TIMESTAMP}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByPrimaryKeySelective" parameterType="club.joylink.rtss.entity.PfStationParamWithBLOBs">
update pf_station_param
<set>
<if test="name != null">
`name` = #{name,jdbcType=VARCHAR},
</if>
<if test="userId != null">
user_id = #{userId,jdbcType=BIGINT},
</if>
<if test="updateTime != null">
update_time = #{updateTime,jdbcType=TIMESTAMP},
</if>
<if test="regionData != null">
region_data = #{regionData,jdbcType=LONGVARCHAR},
</if>
<if test="sceneConfig != null">
scene_config = #{sceneConfig,jdbcType=LONGVARCHAR},
</if>
<if test="simulationConfig != null">
simulation_config = #{simulationConfig,jdbcType=LONGVARCHAR},
</if>
</set>
where id = #{id,jdbcType=BIGINT}
</update>
<update id="updateByPrimaryKeyWithBLOBs" parameterType="club.joylink.rtss.entity.PfStationParamWithBLOBs">
update pf_station_param
set `name` = #{name,jdbcType=VARCHAR},
user_id = #{userId,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=TIMESTAMP},
region_data = #{regionData,jdbcType=LONGVARCHAR},
scene_config = #{sceneConfig,jdbcType=LONGVARCHAR},
simulation_config = #{simulationConfig,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=BIGINT}
</update>
<update id="updateByPrimaryKey" parameterType="club.joylink.rtss.entity.PfStationParam">
update pf_station_param
set `name` = #{name,jdbcType=VARCHAR},
user_id = #{userId,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=TIMESTAMP}
where id = #{id,jdbcType=BIGINT}
</update>
</mapper>