diff --git a/src/main/java/club/joylink/rtss/controller/PassengerFlowParamController.java b/src/main/java/club/joylink/rtss/controller/PassengerFlowParamController.java new file mode 100644 index 000000000..e51e4dc07 --- /dev/null +++ b/src/main/java/club/joylink/rtss/controller/PassengerFlowParamController.java @@ -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 queryList(@RequestAttribute(name = AuthenticateInterceptor.LOGIN_USER_KEY) + UserVO userVO) { + List 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); + } +} diff --git a/src/main/java/club/joylink/rtss/controller/runplan/RunPlanUserDataController.java b/src/main/java/club/joylink/rtss/controller/runplan/RunPlanUserDataController.java index 4d10c0731..12bf01485 100644 --- a/src/main/java/club/joylink/rtss/controller/runplan/RunPlanUserDataController.java +++ b/src/main/java/club/joylink/rtss/controller/runplan/RunPlanUserDataController.java @@ -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 = "分页获取用户交路") diff --git a/src/main/java/club/joylink/rtss/controller/simulation/SimulationV1Controller.java b/src/main/java/club/joylink/rtss/controller/simulation/SimulationV1Controller.java index d78321009..3a387029d 100644 --- a/src/main/java/club/joylink/rtss/controller/simulation/SimulationV1Controller.java +++ b/src/main/java/club/joylink/rtss/controller/simulation/SimulationV1Controller.java @@ -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 getAllDestinationCode(@PathVariable String group) { + public List getAllDestinationCode(@PathVariable String group) { return this.groupSimulationService.getAllDestinationCode(group); } diff --git a/src/main/java/club/joylink/rtss/dao/PfStationParamDAO.java b/src/main/java/club/joylink/rtss/dao/PfStationParamDAO.java new file mode 100644 index 000000000..7ab94e1f2 --- /dev/null +++ b/src/main/java/club/joylink/rtss/dao/PfStationParamDAO.java @@ -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 selectByExampleWithBLOBs(PfStationParamExample example); + + List 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); +} \ No newline at end of file diff --git a/src/main/java/club/joylink/rtss/entity/PfStationParam.java b/src/main/java/club/joylink/rtss/entity/PfStationParam.java new file mode 100644 index 000000000..1339ce557 --- /dev/null +++ b/src/main/java/club/joylink/rtss/entity/PfStationParam.java @@ -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; +} \ No newline at end of file diff --git a/src/main/java/club/joylink/rtss/entity/PfStationParamExample.java b/src/main/java/club/joylink/rtss/entity/PfStationParamExample.java new file mode 100644 index 000000000..2a84b7201 --- /dev/null +++ b/src/main/java/club/joylink/rtss/entity/PfStationParamExample.java @@ -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 oredCriteria; + + private Integer limit; + + private Long offset; + + public PfStationParamExample() { + oredCriteria = new ArrayList(); + } + + 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 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 criteria; + + protected GeneratedCriteria() { + super(); + criteria = new ArrayList(); + } + + public boolean isValid() { + return criteria.size() > 0; + } + + public List getAllCriteria() { + return criteria; + } + + public List 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 values) { + addCriterion("id in", values, "id"); + return (Criteria) this; + } + + public Criteria andIdNotIn(List 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 values) { + addCriterion("`name` in", values, "name"); + return (Criteria) this; + } + + public Criteria andNameNotIn(List 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 values) { + addCriterion("user_id in", values, "userId"); + return (Criteria) this; + } + + public Criteria andUserIdNotIn(List 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 values) { + addCriterion("update_time in", values, "updateTime"); + return (Criteria) this; + } + + public Criteria andUpdateTimeNotIn(List 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); + } + } +} \ No newline at end of file diff --git a/src/main/java/club/joylink/rtss/entity/PfStationParamWithBLOBs.java b/src/main/java/club/joylink/rtss/entity/PfStationParamWithBLOBs.java new file mode 100644 index 000000000..26a6d3654 --- /dev/null +++ b/src/main/java/club/joylink/rtss/entity/PfStationParamWithBLOBs.java @@ -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; +} \ No newline at end of file diff --git a/src/main/java/club/joylink/rtss/exception/BusinessExceptionAssertEnum.java b/src/main/java/club/joylink/rtss/exception/BusinessExceptionAssertEnum.java index cd0a1c57f..1102df8ec 100644 --- a/src/main/java/club/joylink/rtss/exception/BusinessExceptionAssertEnum.java +++ b/src/main/java/club/joylink/rtss/exception/BusinessExceptionAssertEnum.java @@ -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"), diff --git a/src/main/java/club/joylink/rtss/services/DraftMapService.java b/src/main/java/club/joylink/rtss/services/DraftMapService.java index 1a259c6df..bc6c253d4 100644 --- a/src/main/java/club/joylink/rtss/services/DraftMapService.java +++ b/src/main/java/club/joylink/rtss/services/DraftMapService.java @@ -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 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; + } + } } diff --git a/src/main/java/club/joylink/rtss/services/RunPlanDraftService.java b/src/main/java/club/joylink/rtss/services/RunPlanDraftService.java index 798769ad1..90bcc7b9d 100644 --- a/src/main/java/club/joylink/rtss/services/RunPlanDraftService.java +++ b/src/main/java/club/joylink/rtss/services/RunPlanDraftService.java @@ -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 tripVOList; - List 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 tripVOList = runPlanStrategy.parseRunPlanImport(runPlanImportList, sectionMap, upDirection); // 生成计划对象 RunPlanDraft plan = new RunPlanDraft(); plan.setMapId(mapId); @@ -393,56 +390,54 @@ public class RunPlanDraftService implements IRunPlanDraftService { List newTripList = new ArrayList<>(); RunPlanUserConfigVO config = runPlanUserConfigService.getConfig(userVO.getId(), mapVO.getId()); BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertTrue(Objects.nonNull(config) && config.hasReentryData(), "运行图-用户缺少配置或没有配置车站折返数据"); - Map userReentryData = config.getConfig().getRunPlanUserReentryData(); + Map userReentryData = config.getConfig().getReentryData(); List userRoutings = runPlanRoutingService.getUserRoutingBy(userVO.getId(), mapVO.getId()); Map 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 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 userReentryData = config.getConfig().getRunPlanUserReentryData(); + Map userReentryData = config.getConfig().getReentryData(); List userRoutings = runPlanRoutingService.getUserRoutingBy(userVO.getId(), mapVO.getId()); Map 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<>()); diff --git a/src/main/java/club/joylink/rtss/services/SysUserService.java b/src/main/java/club/joylink/rtss/services/SysUserService.java index cc376ef83..fa71bba74 100644 --- a/src/main/java/club/joylink/rtss/services/SysUserService.java +++ b/src/main/java/club/joylink/rtss/services/SysUserService.java @@ -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); diff --git a/src/main/java/club/joylink/rtss/services/draftData/DraftMapCiDataGeneratorImpl.java b/src/main/java/club/joylink/rtss/services/draftData/DraftMapCiDataGeneratorImpl.java index 7641e0512..0b53ac0a1 100644 --- a/src/main/java/club/joylink/rtss/services/draftData/DraftMapCiDataGeneratorImpl.java +++ b/src/main/java/club/joylink/rtss/services/draftData/DraftMapCiDataGeneratorImpl.java @@ -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 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> overlapMap = new HashMap<>(); List approachList = new ArrayList<>(); @@ -296,58 +302,6 @@ public class DraftMapCiDataGeneratorImpl implements DraftMapCiDataGenerator { // // 生成交路数据 // List generateRoutingList = this.generateRoutings(deviceMap, generatedRouteList, autoSignalList, errorList); - -// // 获取所有转换轨或者折返轨 -// List
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 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 generatedStationRunLevelList = new ArrayList<>(); // generateRunLevel(deviceMap, errorList, generateRoutingList, generatedStationRunLevelList); @@ -355,21 +309,132 @@ public class DraftMapCiDataGeneratorImpl implements DraftMapCiDataGenerator { //目的地码生成 List 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
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
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
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
queryFrontTurnBackList(List stations, Station station, boolean right) { + List
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
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
queryAfterTurnBackList(Station station, boolean right) { + List
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 generateRouteLikeHa1(Signal signal, CodeGenerator routeCodeGenerator, Map> 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); } diff --git a/src/main/java/club/joylink/rtss/services/pfp/PfpService.java b/src/main/java/club/joylink/rtss/services/pfp/PfpService.java new file mode 100644 index 000000000..498f3ab31 --- /dev/null +++ b/src/main/java/club/joylink/rtss/services/pfp/PfpService.java @@ -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 queryEntityList(UserVO userVO); + + PfpVO getById(Long id); + + String create(PfpVO param, UserVO userVO); + + void update(Long id, PfpVO param); + + void delete(Long id); +} diff --git a/src/main/java/club/joylink/rtss/services/pfp/PfpServiceImpl.java b/src/main/java/club/joylink/rtss/services/pfp/PfpServiceImpl.java new file mode 100644 index 000000000..cc4dd1ac0 --- /dev/null +++ b/src/main/java/club/joylink/rtss/services/pfp/PfpServiceImpl.java @@ -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 queryEntityList(UserVO userVO) { + PfStationParamExample example = new PfStationParamExample(); + example.createCriteria() + .andUserIdEqualTo(userVO.getId()); + List list = this.pfStationParamDAO.selectByExample(example); + List 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); + } +} diff --git a/src/main/java/club/joylink/rtss/services/runplan/IRunPlanRoutingService.java b/src/main/java/club/joylink/rtss/services/runplan/IRunPlanRoutingService.java index 09e773a92..9e2a99f7a 100644 --- a/src/main/java/club/joylink/rtss/services/runplan/IRunPlanRoutingService.java +++ b/src/main/java/club/joylink/rtss/services/runplan/IRunPlanRoutingService.java @@ -30,5 +30,5 @@ public interface IRunPlanRoutingService { List getRoutingSectionDataBy(Long userId, Long planId, String routingCode); - RunPlanRoutingVO generateUserRouting(RunPlanRoutingVO routingVO); + RunPlanRoutingVO generateUserRoutingSections(RunPlanRoutingVO routingVO); } diff --git a/src/main/java/club/joylink/rtss/services/runplan/RunPlanGenerator.java b/src/main/java/club/joylink/rtss/services/runplan/RunPlanGenerator.java deleted file mode 100644 index b2769e56c..000000000 --- a/src/main/java/club/joylink/rtss/services/runplan/RunPlanGenerator.java +++ /dev/null @@ -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 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 levels = runPlanRunlevelService.queryUserRunLevels(userId, mapVO.getId()); - Map runLevelTime = levels.stream().collect(Collectors.toMap(runLevelVO -> String.format("%s-%s", runLevelVO.getStartSectionCode(), runLevelVO.getEndSectionCode()), runLevelVO -> runLevelVO.getLevelTime(runPlanInput.getRunLevel()))); - //查停站时间 - List parkTimes = runPlanParktimeService.queryUserParktimes(userId, mapVO.getId()); - Map 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 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 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 tripList, ServiceTempResult tempResult, boolean isRight, Map runLevelTime, Map parkTime, Map userReentryData) { - String serviceNumber = String.format("%03d", initialServiceNum); - //初始化车次号,右行偶数,左行奇数 - int initTripNumber = isRight ? 0 : 1; - LocalTime lastTripEndTime = null;//一个车次终点时间 - LinkedList 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 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) 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 tripTimeList = (LinkedList) 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 tripList, Map runLevelTime, Map parkTime, Map 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 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 levels = runPlanRunlevelService.queryUserRunLevels(userId, mapVO.getId()); - Map runLevelMap = levels.stream().collect(Collectors.toMap(runLevelVO -> String.format("%s-%s", runLevelVO.getStartSectionCode(), runLevelVO.getEndSectionCode()), runLevelVO -> runLevelVO.getLevelTime(inputData.getRunLevel()))); - //查停站时间 - List parktimes = runPlanParktimeService.queryUserParktimes(userId, mapVO.getId()); - Map 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 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 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 runLevelMap, Map parkTimeMap, Map userReentryData, List tripList, ServiceTempResult serviceResult) { - LinkedList 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 runLevelMap, Map parkTimeMap, Map userReentryData, - LinkedList 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 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 tripTimeList, int reentryTime) { - setTripStartTime(runPlanTripVO, tripTimeList, reentryTime); - setTripEndTime(runPlanTripVO, tripTimeList, reentryTime); - } - - private void setTripEndTime(RunPlanTripVO lastRunPlanTrip, LinkedList 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 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; - } - -} diff --git a/src/main/java/club/joylink/rtss/services/runplan/RunPlanGenerator1.java b/src/main/java/club/joylink/rtss/services/runplan/RunPlanGenerator1.java new file mode 100644 index 000000000..aa85803b1 --- /dev/null +++ b/src/main/java/club/joylink/rtss/services/runplan/RunPlanGenerator1.java @@ -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 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 levels = runPlanRunlevelService.queryUserRunLevels(userId, mapVO.getId()); + Map runLevelTime = levels.stream().collect(Collectors.toMap(runLevelVO -> String.format("%s-%s", runLevelVO.getStartSectionCode(), runLevelVO.getEndSectionCode()), runLevelVO -> runLevelVO.getLevelTime(runPlanInput.getRunLevel()))); + //查停站时间 + List parkTimes = runPlanParktimeService.queryUserParktimes(userId, mapVO.getId()); + Map parkTime = parkTimes.stream().collect(Collectors.toMap(RunPlanParkingTimeVO::getSectionCode, RunPlanParkingTimeVO::getParkingTime)); + //查折返 + RunPlanUserConfigVO config = runPlanUserConfigService.getConfig(userId, mapVO.getId()); + Map userReentryData = checkStationReentry(mapVO, running1Routing, config); + //生成车次 + LinkedList 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 tripList, ServiceTempResult serviceTempResult, boolean isRight, Map runLevelMap, Map parkTimeMap, Map reentryData) { + String serviceNumber = String.format("%03d", initialServiceNum); + //初始化车次号,右行偶数,左行奇数 + int initTripNumber = isRight ? 0 : 1; + LocalTime lastTripEndTime;//一个车次终点时间 + LinkedList 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 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 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 tripList, Map runLevelTime, Map parkTime, Map 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 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 levels = runPlanRunlevelService.queryUserRunLevels(userId, mapVO.getId()); + Map runLevelMap = levels.stream().collect(Collectors.toMap(runLevelVO -> String.format("%s-%s", runLevelVO.getStartSectionCode(), runLevelVO.getEndSectionCode()), runLevelVO -> runLevelVO.getLevelTime(inputData.getRunLevel()))); + //查停站时间 + List parktimes = runPlanParktimeService.queryUserParktimes(userId, mapVO.getId()); + Map parkTimeMap = parktimes.stream().collect(Collectors.toMap(RunPlanParkingTimeVO::getSectionCode, RunPlanParkingTimeVO::getParkingTime)); + //查折返 + RunPlanUserConfigVO config = runPlanUserConfigService.getConfig(userId, mapVO.getId()); + Map reentryData = checkStationReentry(mapVO, running1Routing, config); + List 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 checkStationReentry(MapVO mapVO, RunPlanRoutingVO running1Routing, RunPlanUserConfigVO config) { + BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertTrue(Objects.nonNull(config) && config.hasReentryData(), "请配置所选运行线路折返数据"); + Map 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 runLevelMap, Map parkTimeMap, Map reentryData, List tripList, ServiceTempResult serviceResult) { + LinkedList 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 runLevelMap, Map parkTimeMap, Map reentryData, + LinkedList 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 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 tripTimeList, Map reentryData) { + setTripStartTime(runPlanTripVO, routing.getStartStationCode(),tripTimeList, reentryData); + setTripEndTime(runPlanTripVO, routing.getEndStationCode(),tripTimeList, reentryData); + } + + private void setTripStartTime(RunPlanTripVO runPlanTripVO, String startStation,LinkedList tripTimeList, Map 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 tripTimeList, Map 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; + } + +} diff --git a/src/main/java/club/joylink/rtss/services/runplan/RunPlanRoutingService.java b/src/main/java/club/joylink/rtss/services/runplan/RunPlanRoutingService.java index 2fd400479..ea4545410 100644 --- a/src/main/java/club/joylink/rtss/services/runplan/RunPlanRoutingService.java +++ b/src/main/java/club/joylink/rtss/services/runplan/RunPlanRoutingService.java @@ -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 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 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 deviceMap) { List 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 deviceMap) { - List 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 deviceMap) { + RunPlanUserConfigVO userConfig = planConfigService.getConfig(routingVO.getUserId(), routingVO.getMapId()); + Map 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 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 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 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 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 runPlanRoutings = runPlanRoutingDAO.selectByExampleWithBLOBs(example); - if (CollectionUtils.isEmpty(runPlanRoutings)) return Collections.emptyList(); - return RunPlanRoutingVO.convert2VO(runPlanRoutings.get(0)).getParkSectionCodeList(); + List list = runPlanRoutingDAO.selectByExampleWithBLOBs(example); + if (CollectionUtils.isEmpty(list)) return Collections.emptyList(); + return RunPlanRoutingVO.convert2VO(list.get(0)).getParkSectionCodeList(); } diff --git a/src/main/java/club/joylink/rtss/services/training/generatornew/GeneratorNew.java b/src/main/java/club/joylink/rtss/services/training/generatornew/GeneratorNew.java index b814f6e68..e07fe7b80 100644 --- a/src/main/java/club/joylink/rtss/services/training/generatornew/GeneratorNew.java +++ b/src/main/java/club/joylink/rtss/services/training/generatornew/GeneratorNew.java @@ -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 placeholderVOMap, MapElement mapDevice, Object mapButton, MapVO map) { + default String replacePlaceholder(String str, Map placeholderVOMap, MapElement mapDevice, Object mapButton, MapVO map) { Pattern pattern = Pattern.compile(".*?(\\{(\\d+)}).*?"); Matcher matcher = pattern.matcher(str); while (matcher.find()) { diff --git a/src/main/java/club/joylink/rtss/services/training/generatornew/base/SpeedLimitGeneratorNew.java b/src/main/java/club/joylink/rtss/services/training/generatornew/base/SpeedLimitGeneratorNew.java index e2e15ff99..17d5bdaf0 100644 --- a/src/main/java/club/joylink/rtss/services/training/generatornew/base/SpeedLimitGeneratorNew.java +++ b/src/main/java/club/joylink/rtss/services/training/generatornew/base/SpeedLimitGeneratorNew.java @@ -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 generate(GenerateConfig config, Simulation simulation, OperateDefinitionVO operateDefinitionVO) { List 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 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 stepList = operateDefinitionVO.getStepVOList(); + stepList.get(0).setDeviceCode(((MapTempSpeedLimitVO) mapButton).getCode()); + Map 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 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; + } } diff --git a/src/main/java/club/joylink/rtss/services/training/generatornew/base/StationGeneratorNew.java b/src/main/java/club/joylink/rtss/services/training/generatornew/base/StationGeneratorNew.java index ffb84547a..97c71a179 100644 --- a/src/main/java/club/joylink/rtss/services/training/generatornew/base/StationGeneratorNew.java +++ b/src/main/java/club/joylink/rtss/services/training/generatornew/base/StationGeneratorNew.java @@ -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
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; diff --git a/src/main/java/club/joylink/rtss/simulation/Simulation.java b/src/main/java/club/joylink/rtss/simulation/Simulation.java index 03bb67cc8..a3a5bec3b 100644 --- a/src/main/java/club/joylink/rtss/simulation/Simulation.java +++ b/src/main/java/club/joylink/rtss/simulation/Simulation.java @@ -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 destinationMap = new HashMap<>(); + private static final PropertyPlaceholderHelper placeholderHelper = new PropertyPlaceholderHelper("{", "}"); + private List subscribeMessageServiceList; private SimulationMessagePublisher publisher; + private Map repositoryMap = new ConcurrentHashMap<>(); private Map simulationMemberMap = new ConcurrentHashMap<>(); private Map simulationUserMap = new ConcurrentHashMap<>(); @@ -78,25 +82,40 @@ public abstract class Simulation 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 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 T getRepository(String name, Class 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 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 params) { - + return this.simulationOperationDispatcher.doDispatch(id, memberId, type, params); } @PutMapping("/{id}/member/{memberId}/playby/{userId}") diff --git a/src/main/java/club/joylink/rtss/simulation/SimulationDelayJob.java b/src/main/java/club/joylink/rtss/simulation/SimulationDelayJob.java index 726b11936..24c6971ac 100644 --- a/src/main/java/club/joylink/rtss/simulation/SimulationDelayJob.java +++ b/src/main/java/club/joylink/rtss/simulation/SimulationDelayJob.java @@ -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) { diff --git a/src/main/java/club/joylink/rtss/simulation/SimulationJob.java b/src/main/java/club/joylink/rtss/simulation/SimulationJob.java index b5baf179f..2daa0bae2 100644 --- a/src/main/java/club/joylink/rtss/simulation/SimulationJob.java +++ b/src/main/java/club/joylink/rtss/simulation/SimulationJob.java @@ -2,5 +2,5 @@ package club.joylink.rtss.simulation; public interface SimulationJob { - void run() throws InterruptedException; + void run(); } diff --git a/src/main/java/club/joylink/rtss/simulation/SimulationRepository.java b/src/main/java/club/joylink/rtss/simulation/SimulationRepository.java index 78edd8aba..59662ce46 100644 --- a/src/main/java/club/joylink/rtss/simulation/SimulationRepository.java +++ b/src/main/java/club/joylink/rtss/simulation/SimulationRepository.java @@ -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(); } diff --git a/src/main/java/club/joylink/rtss/simulation/SimulationScheduledJob.java b/src/main/java/club/joylink/rtss/simulation/SimulationScheduledJob.java index c82accde5..eee49acf5 100644 --- a/src/main/java/club/joylink/rtss/simulation/SimulationScheduledJob.java +++ b/src/main/java/club/joylink/rtss/simulation/SimulationScheduledJob.java @@ -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) { diff --git a/src/main/java/club/joylink/rtss/simulation/SimulationSubscribeMessageService.java b/src/main/java/club/joylink/rtss/simulation/SimulationSubscribeMessageService.java new file mode 100644 index 000000000..0f9c1d00e --- /dev/null +++ b/src/main/java/club/joylink/rtss/simulation/SimulationSubscribeMessageService.java @@ -0,0 +1,8 @@ +package club.joylink.rtss.simulation; + +public interface SimulationSubscribeMessageService { + + boolean acceptedSubscribePath(String destination); + + Object buildMessageOfSubscribe(String destination); +} diff --git a/src/main/java/club/joylink/rtss/simulation/SimulationSubscribePathChecker.java b/src/main/java/club/joylink/rtss/simulation/SimulationSubscribePathChecker.java deleted file mode 100644 index 5fc8cb4a6..000000000 --- a/src/main/java/club/joylink/rtss/simulation/SimulationSubscribePathChecker.java +++ /dev/null @@ -1,6 +0,0 @@ -package club.joylink.rtss.simulation; - -public interface SimulationSubscribePathChecker { - - boolean acceptedSubscribePath(String destination); -} diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/ATP/ground/GroundAtpApiServiceImpl.java b/src/main/java/club/joylink/rtss/simulation/cbtc/ATP/ground/GroundAtpApiServiceImpl.java index 79b1b8c60..4be510510 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/ATP/ground/GroundAtpApiServiceImpl.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/ATP/ground/GroundAtpApiServiceImpl.java @@ -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
allSections = aSwitch.getAllSections(); + if (aSwitch.isLoss()) { + allSections.forEach(section -> section.setCtOccupied(true)); + } else { + List
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()); } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/ATP/ground/ZCLogicLoop.java b/src/main/java/club/joylink/rtss/simulation/cbtc/ATP/ground/ZCLogicLoop.java index 81749a6c9..6445d615f 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/ATP/ground/ZCLogicLoop.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/ATP/ground/ZCLogicLoop.java @@ -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)) { diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/AtsOperationDispatcher.java b/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/AtsOperationDispatcher.java index 8ba562de3..d7a641582 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/AtsOperationDispatcher.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/AtsOperationDispatcher.java @@ -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); } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/Operation.java b/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/Operation.java index d50946d09..df52e3f48 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/Operation.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/Operation.java @@ -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 } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/handler/SignalOperateHandler.java b/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/handler/SignalOperateHandler.java index eea1c314e..68abb1851 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/handler/SignalOperateHandler.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/handler/SignalOperateHandler.java @@ -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); } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/handler/StandOperateHandler.java b/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/handler/StandOperateHandler.java index b90391f8a..6d46c0ace 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/handler/StandOperateHandler.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/handler/StandOperateHandler.java @@ -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); } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/handler/StationOperateHandler.java b/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/handler/StationOperateHandler.java index b103d233c..59768939d 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/handler/StationOperateHandler.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/handler/StationOperateHandler.java @@ -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()); + } + }); } /**关区信号*/ diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/handler/SwitchOperateHandler.java b/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/handler/SwitchOperateHandler.java index b188813f9..482755b6b 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/handler/SwitchOperateHandler.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/handler/SwitchOperateHandler.java @@ -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); } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/handler/TrainOperateHandler.java b/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/handler/TrainOperateHandler.java index deeb6b1a9..64b710df2 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/handler/TrainOperateHandler.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/operation/handler/TrainOperateHandler.java @@ -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); + } } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/service/AtsPlanService.java b/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/service/AtsPlanService.java index c17f975c7..42aa9200b 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/service/AtsPlanService.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/service/AtsPlanService.java @@ -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); diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/service/AtsRouteSettingService.java b/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/service/AtsRouteSettingService.java index 651c952f8..394c7cf54 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/service/AtsRouteSettingService.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/service/AtsRouteSettingService.java @@ -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 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 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 paths = repository.queryRoutePathsByEnd(eaStandSection); + for (RoutePath path : paths) { + if (path.containsSection(headSection) && path.isRight() == right) { + routePaths.add(path); + } + } + // 如果预计到达不是终点,尝试查询从预计到达开始的路径 + if (!destDefinition.isEndSection(eaStandSection, right)) { + List 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 paths = repository.queryRoutePathsByEnd(eaStandSection); - for (RoutePath path : paths) { - if (path.containsSection(headSection) && path.isRight() == right) { - routePaths.add(path); - } - } - // 如果预计到达不是终点,尝试查询从预计到达开始的路径 - if (!destDefinition.isEndSection(eaStandSection, right)) { - List 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 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 paths = repository.queryRoutePathsByEnd(eaStandSection); +// for (RoutePath path : paths) { +// if (path.containsSection(headSection) && path.isRight() == right) { +// routePaths.add(path); +// } +// } +// // 如果预计到达不是终点,尝试查询从预计到达开始的路径 +// if (!destDefinition.isEndSection(eaStandSection, right)) { +// List 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 getTrain2SignalOfSetRoute(Simulation simulation, List 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; } } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/service/AtsStandService.java b/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/service/AtsStandService.java index 943349fb0..b923e7eb2 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/service/AtsStandService.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/service/AtsStandService.java @@ -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()); } } } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/service/AtsTrainService.java b/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/service/AtsTrainService.java index e4fdded5c..2dbf1012c 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/service/AtsTrainService.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/service/AtsTrainService.java @@ -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 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
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 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 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 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 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); + } } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/CI/CiApiServiceImpl.java b/src/main/java/club/joylink/rtss/simulation/cbtc/CI/CiApiServiceImpl.java index 98e6b8091..da5e54e82 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/CI/CiApiServiceImpl.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/CI/CiApiServiceImpl.java @@ -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 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
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 diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/CI/service/SignalService.java b/src/main/java/club/joylink/rtss/simulation/cbtc/CI/service/SignalService.java index 3519e9c7c..d42e41682 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/CI/service/SignalService.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/CI/service/SignalService.java @@ -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() + "因信号机封锁且有锁闭的进路而重复封锁"); + } } } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/CI/service/SwitchService.java b/src/main/java/club/joylink/rtss/simulation/cbtc/CI/service/SwitchService.java index dc9a7a6d2..0394700ef 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/CI/service/SwitchService.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/CI/service/SwitchService.java @@ -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)) { diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/GroupSimulationService.java b/src/main/java/club/joylink/rtss/simulation/cbtc/GroupSimulationService.java index 1c34e46df..1bf8c3764 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/GroupSimulationService.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/GroupSimulationService.java @@ -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 getAllDestinationCode(String group); + List getAllDestinationCode(String group); /** * 获取仿真报警列表 diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/GroupSimulationServiceImpl.java b/src/main/java/club/joylink/rtss/simulation/cbtc/GroupSimulationServiceImpl.java index 2ea612c1f..1a478e981 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/GroupSimulationServiceImpl.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/GroupSimulationServiceImpl.java @@ -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 getAllDestinationCode(String group) { + public List getAllDestinationCode(String group) { Simulation simulation = groupSimulationCache.getSimulationByGroup(group); - return simulation.getBuildParams().getMap().getLogicDataNew().getDestinationCodeDefinitionList(); + Map destinationMap = simulation.getRepository().getDestinationMap(); + return simulation.getBuildParams().getMap().getLogicDataNew().getDestinationCodeDefinitionList() + .stream().map(vo -> new DestinationCodeVO(destinationMap.get(vo.getCode()))).collect(Collectors.toList()); } @Override diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/build/InterlockBuilder2.java b/src/main/java/club/joylink/rtss/simulation/cbtc/build/InterlockBuilder2.java index 73d4a75cc..07d37c946 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/build/InterlockBuilder2.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/build/InterlockBuilder2.java @@ -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 checkCodeDuplicateSet = new HashSet<>(); //用于检查code重复 +// List 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
necessarySections = new ArrayList<>(); + Station leftStation = null; + Station rightStation = null; + Boolean leftFrontTurnBack = null; + Boolean rightFrontTurnBack = null; List
runPath = null; - Station stationA = null; - Boolean stationAFrontTurnBack = vo.getStationAFrontTurnBack(); - Station stationB = null; - Boolean stationBFrontTurnBack = vo.getStationBFrontTurnBack(); + List 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
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
preferredSections, boolean right) { + Section section; + if (ftb) { + Optional
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
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 checkAndBuildRouting(List routingVOList, Map elementMap, List errMsgList) { List routingList = new ArrayList<>(); if (CollectionUtils.isEmpty(routingVOList)) { diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/build/MapDeviceBuilder.java b/src/main/java/club/joylink/rtss/simulation/cbtc/build/MapDeviceBuilder.java index 06e8d70fe..56a8f149d 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/build/MapDeviceBuilder.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/build/MapDeviceBuilder.java @@ -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()); diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/data/CalculateService.java b/src/main/java/club/joylink/rtss/simulation/cbtc/data/CalculateService.java index 651377185..2f95cf0e4 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/data/CalculateService.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/data/CalculateService.java @@ -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
preferredSections, boolean toRight) { + List 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 list, List 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; } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/DestinationCodeDefinition.java b/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/DestinationCodeDefinition.java index c6bd3cf0a..39939313f 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/DestinationCodeDefinition.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/DestinationCodeDefinition.java @@ -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
runPath; + private List
necessarySections; //----------- 环路类属性 ----------- /** * 车站A @@ -50,31 +53,34 @@ public class DestinationCodeDefinition { */ private Boolean rightFrontTurnBack; + //根据目的地码的定义数据,生成路径 + /** + * 目的地码代表的运行路径(物理区段) + */ + private List
runPath; + + private List 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
runPath, Station stationA, Boolean stationAFrontTurnBack, Station stationB, Boolean stationBFrontTurnBack) { + public DestinationCodeDefinition(String code, Type type, String description, Section startSection, Section section, Boolean right, + List
necessarySections, Station leftStation, Boolean leftFrontTurnBack, + Station rightStation, Boolean rightFrontTurnBack, List
runPath, List 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 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 { /** * 正常运营(环路) diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/MapConfig.java b/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/MapConfig.java index aa8c80a15..e913d4690 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/MapConfig.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/MapConfig.java @@ -201,6 +201,11 @@ public class MapConfig { */ private boolean stationPreResetBeforeAxlePreReset; + /** + * 道岔转动操作可以使失表故障恢复 + */ + private boolean switchTurnOperationCanRecoverSplitFault; + private Set 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()); } } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/Section.java b/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/Section.java index beb921716..280c1b311 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/Section.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/Section.java @@ -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; } } } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/Signal.java b/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/Signal.java index 8f6790087..eac424dde 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/Signal.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/Signal.java @@ -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 ignoreRouteEnd; + /** + * 不生成以该信号机为始端的进路 + */ + private boolean noRoute; + /** * 是否引导信号机 */ diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/Station.java b/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/Station.java index 176b55d6c..d891433b0 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/Station.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/Station.java @@ -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 stands = this.getAllStandList(); + List 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 getAllNormalStands() { + return getAllStandList().stream().filter(stand -> !stand.isSmall()).collect(Collectors.toList()); + } + public String debugStr() { return String.format("车站[%s]", this.getName()); } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/Switch.java b/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/Switch.java index 10988c836..49c3edf96 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/Switch.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/Switch.java @@ -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()); + } } } } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/data/status/TrainStatus.java b/src/main/java/club/joylink/rtss/simulation/cbtc/data/status/TrainStatus.java index 670a892ac..361797c87 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/data/status/TrainStatus.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/data/status/TrainStatus.java @@ -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; } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/data/support/RoutePath.java b/src/main/java/club/joylink/rtss/simulation/cbtc/data/support/RoutePath.java index 0ad1f3e2d..c424dd9fd 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/data/support/RoutePath.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/data/support/RoutePath.java @@ -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); + } } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/data/vo/TrainInfo.java b/src/main/java/club/joylink/rtss/simulation/cbtc/data/vo/TrainInfo.java index e2db59f15..27fa91057 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/data/vo/TrainInfo.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/data/vo/TrainInfo.java @@ -146,6 +146,9 @@ public class TrainInfo extends MapElement { @Setter private List
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() { diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/data/vo/TrainStatusVO.java b/src/main/java/club/joylink/rtss/simulation/cbtc/data/vo/TrainStatusVO.java index e167ca4aa..2cb3f61bd 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/data/vo/TrainStatusVO.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/data/vo/TrainStatusVO.java @@ -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); } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/data/vr/VirtualRealityTrain.java b/src/main/java/club/joylink/rtss/simulation/cbtc/data/vr/VirtualRealityTrain.java index 537665562..38a9b2c17 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/data/vr/VirtualRealityTrain.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/data/vr/VirtualRealityTrain.java @@ -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() { diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/onboard/ATO/service/ATOService.java b/src/main/java/club/joylink/rtss/simulation/cbtc/onboard/ATO/service/ATOService.java index 3060a0f71..f6cd0bf29 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/onboard/ATO/service/ATOService.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/onboard/ATO/service/ATOService.java @@ -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)) { diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/onboard/ATP/OnboardAtpApiService.java b/src/main/java/club/joylink/rtss/simulation/cbtc/onboard/ATP/OnboardAtpApiService.java index 6ce154809..18ffb01bc 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/onboard/ATP/OnboardAtpApiService.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/onboard/ATP/OnboardAtpApiService.java @@ -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); /** * 设置跳停 diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/onboard/ATP/OnboardAtpApiServiceImpl.java b/src/main/java/club/joylink/rtss/simulation/cbtc/onboard/ATP/OnboardAtpApiServiceImpl.java index f8e3819d7..af7d22da4 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/onboard/ATP/OnboardAtpApiServiceImpl.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/onboard/ATP/OnboardAtpApiServiceImpl.java @@ -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 diff --git a/src/main/java/club/joylink/rtss/simulation/messaging/websocket/DefaultSubscribeManager.java b/src/main/java/club/joylink/rtss/simulation/messaging/websocket/DefaultSubscribeManager.java index 8f20760d1..70c197ec2 100644 --- a/src/main/java/club/joylink/rtss/simulation/messaging/websocket/DefaultSubscribeManager.java +++ b/src/main/java/club/joylink/rtss/simulation/messaging/websocket/DefaultSubscribeManager.java @@ -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); + } } } diff --git a/src/main/java/club/joylink/rtss/simulation/operation/SimulationOperationDispatcher.java b/src/main/java/club/joylink/rtss/simulation/operation/SimulationOperationDispatcher.java index 70786ec2e..55e1cccaf 100644 --- a/src/main/java/club/joylink/rtss/simulation/operation/SimulationOperationDispatcher.java +++ b/src/main/java/club/joylink/rtss/simulation/operation/SimulationOperationDispatcher.java @@ -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 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; } diff --git a/src/main/java/club/joylink/rtss/simulation/rt/RtSimulation.java b/src/main/java/club/joylink/rtss/simulation/rt/RtSimulation.java index a9b2dc4e0..a9c1f2fe0 100644 --- a/src/main/java/club/joylink/rtss/simulation/rt/RtSimulation.java +++ b/src/main/java/club/joylink/rtss/simulation/rt/RtSimulation.java @@ -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 { - /** - * 模拟真实设备数据仓库 - */ - 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()); diff --git a/src/main/java/club/joylink/rtss/simulation/rt/RtSimulationService.java b/src/main/java/club/joylink/rtss/simulation/rt/RtSimulationService.java index 032f4af3b..ff565df1e 100644 --- a/src/main/java/club/joylink/rtss/simulation/rt/RtSimulationService.java +++ b/src/main/java/club/joylink/rtss/simulation/rt/RtSimulationService.java @@ -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); } } diff --git a/src/main/java/club/joylink/rtss/simulation/rt/srd/SrdService.java b/src/main/java/club/joylink/rtss/simulation/rt/srd/SrdService.java index 871d9b2aa..0f72efb3b 100644 --- a/src/main/java/club/joylink/rtss/simulation/rt/srd/SrdService.java +++ b/src/main/java/club/joylink/rtss/simulation/rt/srd/SrdService.java @@ -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 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); + } + } diff --git a/src/main/java/club/joylink/rtss/simulation/rt/srd/bo/SrTrack.java b/src/main/java/club/joylink/rtss/simulation/rt/srd/bo/SrTrack.java index e1047b7be..fc0319c54 100644 --- a/src/main/java/club/joylink/rtss/simulation/rt/srd/bo/SrTrack.java +++ b/src/main/java/club/joylink/rtss/simulation/rt/srd/bo/SrTrack.java @@ -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; + } } diff --git a/src/main/java/club/joylink/rtss/simulation/rt/srd/bo/SrTrain.java b/src/main/java/club/joylink/rtss/simulation/rt/srd/bo/SrTrain.java index 512f7edf2..9e6e71309 100644 --- a/src/main/java/club/joylink/rtss/simulation/rt/srd/bo/SrTrain.java +++ b/src/main/java/club/joylink/rtss/simulation/rt/srd/bo/SrTrain.java @@ -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; + } } diff --git a/src/main/java/club/joylink/rtss/simulation/rt/srd/bo/SrTurnout.java b/src/main/java/club/joylink/rtss/simulation/rt/srd/bo/SrTurnout.java index d1ce898e2..a2aa90b8e 100644 --- a/src/main/java/club/joylink/rtss/simulation/rt/srd/bo/SrTurnout.java +++ b/src/main/java/club/joylink/rtss/simulation/rt/srd/bo/SrTurnout.java @@ -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(); } } diff --git a/src/main/java/club/joylink/rtss/simulation/rt/srd/bo/SrdRepository.java b/src/main/java/club/joylink/rtss/simulation/rt/srd/bo/SrdRepository.java index 5f843bd12..607ee244e 100644 --- a/src/main/java/club/joylink/rtss/simulation/rt/srd/bo/SrdRepository.java +++ b/src/main/java/club/joylink/rtss/simulation/rt/srd/bo/SrdRepository.java @@ -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 trackMap; Map axcMap; @@ -15,6 +18,7 @@ public class SrdRepository { Map 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 getTrainList() { return new ArrayList<>(this.trainMap.values()); } + + @Override + public void initState() { + + } } diff --git a/src/main/java/club/joylink/rtss/simulation/rt/srd/bo/SrdRepositoryBuilder.java b/src/main/java/club/joylink/rtss/simulation/rt/srd/bo/SrdRepositoryBuilder.java index cc1d30af3..da737e772 100644 --- a/src/main/java/club/joylink/rtss/simulation/rt/srd/bo/SrdRepositoryBuilder.java +++ b/src/main/java/club/joylink/rtss/simulation/rt/srd/bo/SrdRepositoryBuilder.java @@ -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); } } diff --git a/src/main/java/club/joylink/rtss/simulation/rt/srd/bo/TrackPosition.java b/src/main/java/club/joylink/rtss/simulation/rt/srd/bo/TrackPosition.java index 085912da4..087442a85 100644 --- a/src/main/java/club/joylink/rtss/simulation/rt/srd/bo/TrackPosition.java +++ b/src/main/java/club/joylink/rtss/simulation/rt/srd/bo/TrackPosition.java @@ -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; + } } diff --git a/src/main/java/club/joylink/rtss/vo/client/map/DestinationCodeVO.java b/src/main/java/club/joylink/rtss/vo/client/map/DestinationCodeVO.java new file mode 100644 index 000000000..88a8e1092 --- /dev/null +++ b/src/main/java/club/joylink/rtss/vo/client/map/DestinationCodeVO.java @@ -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 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()); +// } + } +} diff --git a/src/main/java/club/joylink/rtss/vo/client/map/MapVO.java b/src/main/java/club/joylink/rtss/vo/client/map/MapVO.java index d2ba7bb80..6f6e834e9 100644 --- a/src/main/java/club/joylink/rtss/vo/client/map/MapVO.java +++ b/src/main/java/club/joylink/rtss/vo/client/map/MapVO.java @@ -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 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 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 findSortedAllStationListNew() { diff --git a/src/main/java/club/joylink/rtss/vo/client/map/RealLineConfigVO.java b/src/main/java/club/joylink/rtss/vo/client/map/RealLineConfigVO.java index 61388bf74..06872fd3b 100644 --- a/src/main/java/club/joylink/rtss/vo/client/map/RealLineConfigVO.java +++ b/src/main/java/club/joylink/rtss/vo/client/map/RealLineConfigVO.java @@ -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); diff --git a/src/main/java/club/joylink/rtss/vo/client/map/newmap/MapCiGenerateConfig.java b/src/main/java/club/joylink/rtss/vo/client/map/newmap/MapCiGenerateConfig.java index e4a25c568..960d54057 100644 --- a/src/main/java/club/joylink/rtss/vo/client/map/newmap/MapCiGenerateConfig.java +++ b/src/main/java/club/joylink/rtss/vo/client/map/newmap/MapCiGenerateConfig.java @@ -69,6 +69,9 @@ public class MapCiGenerateConfig { @ApiModelProperty(value = "若生成进路信号按钮,进路信号按钮是否取最近的一个信号机") private boolean getNearlySignal; + @ApiModelProperty("是否生成目的地码定义(泰雷兹式)") + private boolean generateDestination; + // @ApiModelProperty(value = "是否分开生成ATP联锁和地面信号联锁") // private boolean apartGroundAndAtp; diff --git a/src/main/java/club/joylink/rtss/vo/client/map/newmap/MapDestinationCodeDefinitionVO.java b/src/main/java/club/joylink/rtss/vo/client/map/newmap/MapDestinationCodeDefinitionVO.java index f15945cac..f58fd91cc 100644 --- a/src/main/java/club/joylink/rtss/vo/client/map/newmap/MapDestinationCodeDefinitionVO.java +++ b/src/main/java/club/joylink/rtss/vo/client/map/newmap/MapDestinationCodeDefinitionVO.java @@ -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; } diff --git a/src/main/java/club/joylink/rtss/vo/client/map/newmap/MapSignalNewVO.java b/src/main/java/club/joylink/rtss/vo/client/map/newmap/MapSignalNewVO.java index 96d8ae5f0..e713e3816 100644 --- a/src/main/java/club/joylink/rtss/vo/client/map/newmap/MapSignalNewVO.java +++ b/src/main/java/club/joylink/rtss/vo/client/map/newmap/MapSignalNewVO.java @@ -46,6 +46,9 @@ public class MapSignalNewVO { @ApiModelProperty(value = "不生成进路的信号机终端") private List ignoreRouteEnd; + @ApiModelProperty("是否不生成进路") + private boolean noRoute; + /** * 所属区段编码 */ diff --git a/src/main/java/club/joylink/rtss/vo/client/runplan/RunPlanTripVO.java b/src/main/java/club/joylink/rtss/vo/client/runplan/RunPlanTripVO.java index d67716bf8..e1540dd5e 100644 --- a/src/main/java/club/joylink/rtss/vo/client/runplan/RunPlanTripVO.java +++ b/src/main/java/club/joylink/rtss/vo/client/runplan/RunPlanTripVO.java @@ -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); } diff --git a/src/main/java/club/joylink/rtss/vo/client/runplan/user/RunPlanRoutingSection.java b/src/main/java/club/joylink/rtss/vo/client/runplan/user/RunPlanRoutingSection.java index 7c3917ff5..e080944f3 100644 --- a/src/main/java/club/joylink/rtss/vo/client/runplan/user/RunPlanRoutingSection.java +++ b/src/main/java/club/joylink/rtss/vo/client/runplan/user/RunPlanRoutingSection.java @@ -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 from(List
viaSectionList) { - List voList = new ArrayList<>(); - if (!CollectionUtils.isEmpty(viaSectionList)) { - for (Section section : viaSectionList) { - voList.add(new RunPlanRoutingSection(section.getStation().getCode(), section.getCode())); - } - } - return voList; - } } diff --git a/src/main/java/club/joylink/rtss/vo/client/runplan/user/RunPlanRoutingVO.java b/src/main/java/club/joylink/rtss/vo/client/runplan/user/RunPlanRoutingVO.java index 81c78d162..67cfd23d7 100644 --- a/src/main/java/club/joylink/rtss/vo/client/runplan/user/RunPlanRoutingVO.java +++ b/src/main/java/club/joylink/rtss/vo/client/runplan/user/RunPlanRoutingVO.java @@ -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 convert2VOList(List 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, diff --git a/src/main/java/club/joylink/rtss/vo/client/runplan/user/RunPlanRunlevelVO.java b/src/main/java/club/joylink/rtss/vo/client/runplan/user/RunPlanRunlevelVO.java index 05897446f..b4aba6fc9 100644 --- a/src/main/java/club/joylink/rtss/vo/client/runplan/user/RunPlanRunlevelVO.java +++ b/src/main/java/club/joylink/rtss/vo/client/runplan/user/RunPlanRunlevelVO.java @@ -148,7 +148,8 @@ public class RunPlanRunlevelVO { public static List runLevelsFromRouting(RunPlanRoutingVO routingVO) { List parkSectionList = routingVO.getParkSectionCodeList(); List 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()); diff --git a/src/main/java/club/joylink/rtss/vo/client/runplan/user/RunPlanUserConfigVO.java b/src/main/java/club/joylink/rtss/vo/client/runplan/user/RunPlanUserConfigVO.java index 344fe81d1..fdb177b3f 100644 --- a/src/main/java/club/joylink/rtss/vo/client/runplan/user/RunPlanUserConfigVO.java +++ b/src/main/java/club/joylink/rtss/vo/client/runplan/user/RunPlanUserConfigVO.java @@ -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 runPlanUserReentryData; + private Map reentryData=new HashMap<>(); +// private Map 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; } } diff --git a/src/main/java/club/joylink/rtss/vo/client/student/ExportStudentInfo.java b/src/main/java/club/joylink/rtss/vo/client/student/ExportStudentInfo.java index b8f91f119..9afc666e3 100644 --- a/src/main/java/club/joylink/rtss/vo/client/student/ExportStudentInfo.java +++ b/src/main/java/club/joylink/rtss/vo/client/student/ExportStudentInfo.java @@ -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; + } + } diff --git a/src/main/java/club/joylink/rtss/vo/pfp/PfpVO.java b/src/main/java/club/joylink/rtss/vo/pfp/PfpVO.java new file mode 100644 index 000000000..c06a775e0 --- /dev/null +++ b/src/main/java/club/joylink/rtss/vo/pfp/PfpVO.java @@ -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 convert2VOList(List list) { + List 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; + } +} diff --git a/src/main/java/club/joylink/rtss/vo/runplan/RunPlanInput.java b/src/main/java/club/joylink/rtss/vo/runplan/RunPlanInput.java index 822bda98c..8d1fd7d8d 100644 --- a/src/main/java/club/joylink/rtss/vo/runplan/RunPlanInput.java +++ b/src/main/java/club/joylink/rtss/vo/runplan/RunPlanInput.java @@ -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; diff --git a/src/main/java/club/joylink/rtss/vo/runplan/RunPlanInputData.java b/src/main/java/club/joylink/rtss/vo/runplan/RunPlanInputData.java index 622e02c62..44952ff65 100644 --- a/src/main/java/club/joylink/rtss/vo/runplan/RunPlanInputData.java +++ b/src/main/java/club/joylink/rtss/vo/runplan/RunPlanInputData.java @@ -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; diff --git a/src/main/resources/mybatis/mapper/PfStationParamDAO.xml b/src/main/resources/mybatis/mapper/PfStationParamDAO.xml new file mode 100644 index 000000000..11a495ff1 --- /dev/null +++ b/src/main/resources/mybatis/mapper/PfStationParamDAO.xml @@ -0,0 +1,293 @@ + + + + + + + + + + + + + + + + + + + + + + + and ${criterion.condition} + + + and ${criterion.condition} #{criterion.value} + + + and ${criterion.condition} #{criterion.value} and #{criterion.secondValue} + + + and ${criterion.condition} + + #{listItem} + + + + + + + + + + + + + + + + + + and ${criterion.condition} + + + and ${criterion.condition} #{criterion.value} + + + and ${criterion.condition} #{criterion.value} and #{criterion.secondValue} + + + and ${criterion.condition} + + #{listItem} + + + + + + + + + + + id, `name`, user_id, update_time + + + region_data, scene_config, simulation_config + + + + + + delete from pf_station_param + where id = #{id,jdbcType=BIGINT} + + + delete from pf_station_param + + + + + + 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 into pf_station_param + + + `name`, + + + user_id, + + + update_time, + + + region_data, + + + scene_config, + + + simulation_config, + + + + + #{name,jdbcType=VARCHAR}, + + + #{userId,jdbcType=BIGINT}, + + + #{updateTime,jdbcType=TIMESTAMP}, + + + #{regionData,jdbcType=LONGVARCHAR}, + + + #{sceneConfig,jdbcType=LONGVARCHAR}, + + + #{simulationConfig,jdbcType=LONGVARCHAR}, + + + + + + update pf_station_param + + + 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}, + + + + + + + + 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} + + + + + + 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} + + + + + + update pf_station_param + + + `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 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 pf_station_param + set `name` = #{name,jdbcType=VARCHAR}, + user_id = #{userId,jdbcType=BIGINT}, + update_time = #{updateTime,jdbcType=TIMESTAMP} + where id = #{id,jdbcType=BIGINT} + + \ No newline at end of file