Commit a8673e53 authored by 黄福新's avatar 黄福新

[add] 1、路口失衡优化接口、逻辑定义;2、删除优化服务公共工具类,调用wj-common

parent ab344be5
......@@ -24,6 +24,11 @@
<artifactId>wj-common</artifactId>
<version>0.0.2</version>
</dependency>
<dependency>
<groupId>net.wanji</groupId>
<artifactId>wj-databus</artifactId>
<version>0.0.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
......
......@@ -7,36 +7,6 @@ public class Constants {
*/
public static final String SYSTEM_ABBR = "OPT";
/**
* 否
*/
public static final Integer NO = 0;
/**
* 是
*/
public static final Integer YES = 1;
/**
* 分隔符:下划线
**/
public static final String SEPARATOR_UNDER_LINE = "_";
/**
* 分隔符:逗号
**/
public static final String SEPARATOR_COMMA = ",";
/**
* 分隔符:减号
**/
public static final String SEPARATOR_MINUS = "-";
/**
* 分隔符:冒号
**/
public static final String SEPARATOR_COLON = ":";
/**
* 相位(灯态)锁定
*/
......
package net.wanji.opt.common;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* @Description: [API响应结果封装]
* @author hfx
* @version 1.0
* Created on 2019/4/28 19:45
*/
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class Result implements Serializable {
private Integer status;
private String msg;
private Object data;
public static Result success() {
return new Result(ResultCode.SUCCESS.getStatus(), ResultCode.SUCCESS.getMsg(), null);
}
public static Result fail() {
return new Result(ResultCode.FAIL.getStatus(), ResultCode.FAIL.getMsg(), null);
}
public static Result success(Object data) {
return new Result(ResultCode.SUCCESS.getStatus(), ResultCode.SUCCESS.getMsg(), data);
}
public static Result fail(String msg) {
return new Result(ResultCode.FAIL.getStatus(), msg, null);
}
public static Result fail(Integer status, String msg) {
return new Result(status, msg, null);
}
}
package net.wanji.opt.common;
/**
* 响应码枚举,参考HTTP状态码的语义
*/
public enum ResultCode {
SUCCESS(200, "操作成功"),
FAIL(400, "操作失败"),
UNAUTHORIZED(401, "未认证,签名错误"),
INVALID(403, "token无效"),
NOT_FOUND(404, "接口不存在"),
INTERNAL_SERVER_ERROR(500, "服务器内部错误");
private int status;
private String msg;
ResultCode(int status, String msg) {
this.status = status;
this.msg = msg;
}
public int getStatus() {
return status;
}
public String getMsg() {
return msg;
}
}
package net.wanji.opt.common.enums;
public enum CrossStatusEnum {
NORMAL(0, "正常"),
UNBALANCE(1, "失衡"),
CONGESTION(2, "拥堵"),
SPILLOVER(3, "溢出"),
DEADLOCK(4, "死锁");
private Integer code;
private String name;
private CrossStatusEnum(Integer code, String name) {
this.code = code;
this.name = name;
}
public Integer getCode() {
return this.code;
}
public String getName() {
return this.name;
}
}
......@@ -2,6 +2,7 @@ package net.wanji.opt.dao.mapper;
import net.wanji.opt.po.base.CrossSchedulesPO;
import net.wanji.opt.po.base.CrossSchedulesPlanPO;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
......@@ -24,9 +25,10 @@ public interface CrossSchedulesMapper {
/**
* 查询调度计划信息列表
* @param crossId
* @param status
* @return
*/
List<CrossSchedulesPlanPO> listSchedulesPlan(String crossId, String schedulesId);
List<CrossSchedulesPlanPO> listSchedulesPlan(@Param("crossId") String crossId, @Param("status") Integer status);
}
......@@ -32,11 +32,17 @@ public class CrossPhaseDTO {
private Integer dirType;
@ApiModelProperty(name = "路口转向:u掉头;l左转;s直行;r右转",notes = "")
private Integer turnType;
private String turnType;
@ApiModelProperty(name = "计划号",notes = "")
private String planNo;
@ApiModelProperty(name = "方案ID",notes = "")
private Integer schemeId;
@ApiModelProperty(name = "方案号",notes = "")
private String schemeNo;
@ApiModelProperty(name = "环号",notes = "")
private Integer ringNo;
......
......@@ -26,12 +26,15 @@ public class CrossSectionDTO {
@ApiModelProperty(name = "计划ID",notes = "")
private Integer planId;
@ApiModelProperty(name = "计划号",notes = "")
private String planNo;
@ApiModelProperty(name = "路口ID",notes = "")
private String crossId;
@ApiModelProperty(name = "方案ID",notes = "")
private Integer scemeId;
private Integer schemeId;
@ApiModelProperty(name = "控制模式:1定周期;2绿波协调;3黄闪;4全红;5关灯;6单点自适应;7全感应;8半感应;",notes = "")
private Integer control_mode;
private Integer controlMode;
}
package net.wanji.opt.service;
import net.wanji.opt.dto.CrossDataRealtimeDTO;
import java.util.List;
/**
* @author hfx
* @date 2023/1/10 11:12
......@@ -12,7 +16,7 @@ public interface CrossOptimizeService {
* 路口实时优化
* @return
*/
String realtimeOptimize();
String realtimeOptimize(List<CrossDataRealtimeDTO> abnormalCrossList);
/**
* 路口方案优化
......
......@@ -14,10 +14,11 @@ public interface CrossSchedulesService {
/**
* 获取路口调度详情信息列表
* @param crossId
* @param crossId 路口编号
* @param status 调度状态:1执行;0未执行
* @return
*/
List<CrossSchedulesDTO> listCrossSchedulesDetails(String crossId);
List<CrossSchedulesDTO> listCrossSchedulesDetails(String crossId, Integer status);
......
package net.wanji.opt.service.impl;
import lombok.extern.slf4j.Slf4j;
import net.wanji.opt.common.Constants;
import net.wanji.opt.common.enums.CrossStatusEnum;
import net.wanji.common.enums.ControlModeEnum;
import net.wanji.common.enums.CrossStatusEnum;
import net.wanji.common.enums.TurnConvertEnum;
import net.wanji.common.enums.WeekEnum;
import net.wanji.common.framework.Constants;
import net.wanji.common.utils.tool.DateUtil;
import net.wanji.opt.dto.*;
import net.wanji.opt.po.CrossDataRealtimePO;
import net.wanji.opt.service.CrossOptimizeService;
import net.wanji.opt.service.CrossPhaseService;
import net.wanji.opt.service.CrossSchedulesService;
import net.wanji.opt.service.CrossSchemeService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author hfx
......@@ -24,105 +26,197 @@ import java.util.List;
@Slf4j
public class CrossOptimizeServiceImpl implements CrossOptimizeService {
@Resource
CrossPhaseService crossPhaseService;
@Resource
CrossSchemeService crossSchemeService;
@Resource
CrossSchedulesService crossSchedulesService;
static Set<String> CROSS_OPT = new HashSet<>(); // 记录已优化的路口
public String realtimeOptimize() {
// 获取路口实时数据
List<CrossDataRealtimePO> crossDataRealtimePOList = listCrossDataRealtime();
if(crossDataRealtimePOList.isEmpty()) {
return null;
}
public String realtimeOptimize(List<CrossDataRealtimeDTO> abnormalCrossList) {
try {
// 获取所有信控路口转向实时数据
Map<String, List<CrossTurnDataRealtimeDTO>> turnDataRealtime = listTurnDataRealtime();
// 相位配时信息,key:路口编号_方向类型_转向类型,value 相位配时信息
Map<String, CrossPhaseDTO> phaseMap = listPhaseList();
// 获取路口转向实时数据
List<CrossTurnDataRealtimeDTO> turnDataRealtimeDTOList = listTurnDataRealtime();
// 获取方案详情信息
List<CrossSchemeDTO> schemeDTOList = crossSchemeService.listCrossSchemeDetails(null);
// 获取调度详情信息
// List<CrossSchedulesDTO> schedulesDTOList = crossSchedulesService.listCrossSchedulesDetails(null);
Map<Integer, List<CrossDataRealtimeDTO>> crossDataMap = abnormalCrossList.stream().collect(Collectors.groupingBy(CrossDataRealtimeDTO::getStatus));
abnormalCrossList = crossDataMap.get(CrossStatusEnum.SPILLOVER.getCode()); // 溢出
if(abnormalCrossList != null && !abnormalCrossList.isEmpty()) {
}
abnormalCrossList = crossDataMap.get(CrossStatusEnum.CONGESTION.getCode()); // 拥堵
if(abnormalCrossList != null && !abnormalCrossList.isEmpty()) {
// 获取异常路口数据
List<CrossDataRealtimeDTO> abnormalCrossList = listAbnormalCross(crossDataRealtimePOList);
if(abnormalCrossList.isEmpty()) {
return null;
}
abnormalCrossList = crossDataMap.get(CrossStatusEnum.UNBALANCE.getCode()); // 失衡
if(abnormalCrossList != null && !abnormalCrossList.isEmpty()) {
unbalanceOpt(abnormalCrossList, turnDataRealtime, phaseMap);
}
} catch (Exception e) {
e.printStackTrace();
log.error("实时优化", e.getMessage());
}
log.info("加载异常路口:{}条", abnormalCrossList.size());
for(CrossDataRealtimeDTO dto : abnormalCrossList) {
return null;
}
/**
* 路口失衡优化
* @param abnormalCrossList 失衡路口实时数据
* @param turnDataRealtime 路口转向实时数据
* @param phaseMap 路口相位配时数据
*/
private void unbalanceOpt(List<CrossDataRealtimeDTO> abnormalCrossList, Map<String, List<CrossTurnDataRealtimeDTO>> turnDataRealtime,
Map<String, CrossPhaseDTO> phaseMap) {
String crossId;
for(CrossDataRealtimeDTO cross : abnormalCrossList) {
}
crossId = cross.getCrossId();
// 判断当前路口是否存在特殊控制操作
// 获取相位方案信息
// 计算相位优化配时
// 判断当前路口是否已优化
if(CROSS_OPT.contains(crossId)) {
continue;
}
// 方案下发
// 判断信号机是否在线
/**
* 计算路口各转向所需的通行时长(秒)
* 相位的通行时长需大于等于最小绿灯时长,并且小于等于最大绿灯时长
* 车头间距(米):车间据如果不在20和7之间取9(默认9)
* 车头时距(秒):车时距如果不在2和5之间取2.8(默认2.8)
* 排队车辆 = 排队长度 / 车头间距
* 通行时长 = 排队车辆 * 车头时距
* */
/**
* 计算路口各相位调整时长(秒)
* 相位所需总放行时长 = sum(相位所需放行时长) - 总放行时长
* 相位可减时长 = 相位有效绿灯时长 - 相位所需时长,同时“相位剩余有效绿灯时长”必须介于最小绿时长与最大绿时长之间
* 相位可加时长 = 相位所需时长 - 有效绿灯时长
* 相位可用总时长 = sum(相位可减时长)
* 相位优化时长 = 原相位时长 + 相位调整时长(相位可减时长或相位可加时长)
*
* 结果输出
* 路口编号、计划号、方案号、相位号、原相位时长、优化后相位时长、调整时长
* */
// 方案优化下发
// 记录已优化的路口
CROSS_OPT.add(crossId);
}
return null;
}
/**
* 相位配时信息
* key:路口编号_方向类型_转向类型
* value:相位配时信息
* @return
*/
private Map<String, CrossPhaseDTO> listPhaseList() throws Exception {
Map<String, CrossPhaseDTO> phaseMap = new HashMap<>();
// 获取已执行的调度详情信息
List<CrossSchedulesDTO> schedulesDTOList = crossSchedulesService.listCrossSchedulesDetails(Constants.SystemParam.NULL, Constants.SystemParam.YES);
// 获取当前运行时段信息
List<CrossSectionDTO> sectionInfos = listSection(schedulesDTOList);
// 获取方案详情信息
List<CrossSchemeDTO> schemeDTOList = crossSchemeService.listCrossSchemeDetails(Constants.SystemParam.NULL);
Map<Integer, CrossSchemeDTO> schemeMap = schemeDTOList.stream().collect(Collectors.toMap(CrossSchemeDTO::getId, e -> e));
String key;
String crossId;
Integer dir;
String[] turnArr;
Set<String> turnSet = new HashSet<>();
for(CrossSectionDTO section : sectionInfos) { // 运行时段列表
crossId = section.getCrossId();
CrossSchemeDTO scheme = schemeMap.get(section.getSchemeId()); // 方案信息
for(CrossPhaseDTO phase : scheme.getPhaseInfos()) { // 相位信息列表
for(CrossLightsDTO lights : phase.getLightsInfos()) { // 灯组信息列表
dir = lights.getDir();
for(LaneInfoDTO lane : lights.getLaneInfos()) {
// 车道转向转换为转向类型,并去重
turnArr = TurnConvertEnum.getCodeByKey(lane.getTurn()).split(Constants.SystemParam.SEPARATOR_UNDER_LINE);
turnSet.addAll(Arrays.stream(turnArr).collect(Collectors.toSet()));
}
for(String turn : turnSet) {
key = crossId + Constants.SystemParam.SEPARATOR_UNDER_LINE + dir + Constants.SystemParam.SEPARATOR_UNDER_LINE + turn;
phase.setDirType(dir);
phase.setTurnType(turn);
phaseMap.put(key, phase);
}
turnSet.clear();
}
}
}
return phaseMap;
}
/**
* 获取异常路口数据
* 获取当前运行时段信息
* @param schedulesDTOList 调度列表
* @return
*/
public List<CrossDataRealtimeDTO> listAbnormalCross(List<CrossDataRealtimePO> crossDataRealtimePOList) {
private List<CrossSectionDTO> listSection(List<CrossSchedulesDTO> schedulesDTOList) throws Exception {
List<CrossDataRealtimeDTO> dtoList = new ArrayList<>();
CrossDataRealtimeDTO dto = null;
int status = 0;
for (CrossDataRealtimePO po: crossDataRealtimePOList) {
List<CrossSectionDTO> sectionInfos = new ArrayList<>();
long currentTime = DateUtil.dateToStamp(DateUtil.getTime(), net.wanji.common.framework.Constants.DATE_FORMAT.E_DATE_FORMAT_TIME.getStrFormat()); // 获取当前时间
int week = DateUtil.getWeek(new Date()) == Constants.SystemParam.ZERO ? WeekEnum.SUNDAY.getCode() : DateUtil.getWeek(new Date()); // 获取当前星期
for(CrossSchedulesDTO schedules : schedulesDTOList) {
// 获取失衡、拥堵、溢出路口数据
if(Constants.NO.equals(po.getIsSpillover()) || Constants.NO.equals(po.getIsCongestion()) || Constants.NO.equals(po.getIsUnbalance())) {
if(schedules.getWeek() == Constants.SystemParam.ZERO &&
!DateUtil.getDate().equals(schedules.getSpecialDate())) { // 先判断是否为特殊日期,如果特殊日期与当前日期不相同,则跳过
continue;
} else if(schedules.getWeek() != week) {
continue;
}
if(Constants.YES.equals(po.getIsSpillover())) { // 溢出
status = CrossStatusEnum.SPILLOVER.getCode();
} else if(Constants.YES.equals(po.getIsCongestion())) { // 拥堵
status = CrossStatusEnum.CONGESTION.getCode();
} else if(Constants.YES.equals(po.getIsUnbalance())) { // 失衡
status = CrossStatusEnum.UNBALANCE.getCode();
// 时段信息列表
for(CrossSectionDTO section : schedules.getSectionInfos()) {
// 过滤非当前时段数据
if(currentTime < DateUtil.dateToStamp(section.getStartTime()) || currentTime > DateUtil.dateToStamp(section.getEndTime())) {
continue;
}
// 过滤控制模式为“非定周期”的数据
if(!ControlModeEnum.FIXED_PERIOD.equals(section.getControlMode())) {
continue;
}
section.setPlanNo(schedules.getPlanNo());
sectionInfos.add(section);
}
dto = new CrossDataRealtimeDTO();
dto.setCrossId(po.getCrossId());
dto.setStatus(status);
dto.setDirList(null);
dto.setTurnList(null);
dtoList.add(dto);
}
return dtoList;
return sectionInfos;
}
/**
* 获取转向实时数据
* @return
*/
public List<CrossTurnDataRealtimeDTO> listTurnDataRealtime() {
return new ArrayList<>();
}
/**
* 获取路口实时数据
* 获取所有信控路口转向实时数据
* key 路口编号
* value 转向实时数据
* @return
*/
public List<CrossDataRealtimePO> listCrossDataRealtime() {
public Map<String, List<CrossTurnDataRealtimeDTO>> listTurnDataRealtime() {
Map<String, List<CrossTurnDataRealtimeDTO>> turnDataRealtimeDTOList = new HashMap<>();
return new ArrayList<>();
return turnDataRealtimeDTOList;
}
}
......@@ -32,11 +32,11 @@ public class CrossSchedulesServiceImpl implements CrossSchedulesService {
CrossSectionService crossSectionService;
@Override
public List<CrossSchedulesDTO> listCrossSchedulesDetails(String crossId) {
public List<CrossSchedulesDTO> listCrossSchedulesDetails(String crossId, Integer status) {
List<CrossSchedulesDTO> schedulesDTOList = new ArrayList<>();
// 获取调度计划信息
List<CrossSchedulesPlanPO> schedulesPlanPOList = crossSchedulesMapper.listSchedulesPlan(crossId, null);
List<CrossSchedulesPlanPO> schedulesPlanPOList = crossSchedulesMapper.listSchedulesPlan(crossId, status);
schedulesDTOList = BeanListUtils.populateList(schedulesPlanPOList, schedulesDTOList, CrossSchedulesDTO.class);
// 获取日计划信息
List<CrossSectionDTO> sectionPOList = crossSectionService.listCrossSectionInfo(crossId, null);
......
package net.wanji.opt.task;
import lombok.extern.slf4j.Slf4j;
import net.wanji.common.enums.CrossStatusEnum;
import net.wanji.opt.common.Constants;
import net.wanji.opt.dto.CrossDataRealtimeDTO;
import net.wanji.opt.po.CrossDataRealtimePO;
import net.wanji.opt.service.CrossOptimizeService;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
/**
* @author hfx
* @date 2023/1/16 16:39
* @desc RealtimeOptimizeTask
*/
@Component
@Slf4j
public class CrossMonitorTask {
@Resource
CrossOptimizeService crossOptimizeService;
/**
* 路口实时监测
*/
@Scheduled(cron = "* 0/1 * * * ? ")
public void realtimeMonitor() {
log.info("路口实时监测任务...");
// 获取路口实时监测数据
List<CrossDataRealtimePO> crossDataRealtimePOList = listCrossDataRealtime();
log.info("路口实时数据:{}条", crossDataRealtimePOList.size());
// 测试时无数据暂时注释
// if(crossDataRealtimePOList.isEmpty()) {
// return ;
// }
// 获取所有信控路口异常数据(失衡/拥堵/溢出/死锁)
List<CrossDataRealtimeDTO> abnormalCrossList = listAbnormalCross(crossDataRealtimePOList);
log.info("加载异常路口:{}条", abnormalCrossList.size());
// if(abnormalCrossList.isEmpty()) {
// return ;
// }
// 调用路口实时优化
crossOptimizeService.realtimeOptimize(abnormalCrossList);
}
/**
* 获取异常路口数据
* @return
*/
public List<CrossDataRealtimeDTO> listAbnormalCross(List<CrossDataRealtimePO> crossDataRealtimePOList) {
List<CrossDataRealtimeDTO> dtoList = new ArrayList<>();
CrossDataRealtimeDTO dto = null;
int status = 0;
for (CrossDataRealtimePO po: crossDataRealtimePOList) {
// 获取失衡、拥堵、溢出路口数据
if(Constants.NO.equals(po.getIsSpillover()) || Constants.NO.equals(po.getIsCongestion()) || Constants.NO.equals(po.getIsUnbalance())) {
continue;
}
if(Constants.YES.equals(po.getIsSpillover())) { // 溢出
status = CrossStatusEnum.SPILLOVER.getCode();
} else if(Constants.YES.equals(po.getIsCongestion())) { // 拥堵
status = CrossStatusEnum.CONGESTION.getCode();
} else if(Constants.YES.equals(po.getIsUnbalance())) { // 失衡
status = CrossStatusEnum.UNBALANCE.getCode();
}
dto = new CrossDataRealtimeDTO();
dto.setCrossId(po.getCrossId());
dto.setStatus(status);
dto.setDirList(null);
dto.setTurnList(null);
dtoList.add(dto);
}
return dtoList;
}
/**
* 获取路口实时监测数据
* (暂定从数据中心kafka获取)
* @return
*/
public List<CrossDataRealtimePO> listCrossDataRealtime() {
return new ArrayList<>();
}
}
\ No newline at end of file
package net.wanji.opt.task;
import lombok.extern.slf4j.Slf4j;
import net.wanji.opt.service.CrossOptimizeService;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* @author hfx
* @date 2023/1/16 16:39
* @desc RealtimeOptimizeTask
*/
@Component
@Slf4j
public class RealtimeOptimizeTask {
@Resource
CrossOptimizeService crossOptimizeService;
@Scheduled(cron = "* 0/1 * * * ? ")
public void run() {
log.info("RealtimeOptimizeTask ...");
crossOptimizeService.realtimeOptimize();
}
}
\ No newline at end of file
......@@ -55,10 +55,10 @@
s.id = sp.schedules_id
AND p.id = sp.plan_id
<if test="crossId != null and crossId != ''">
and cross_id = #{crossId}
and s.cross_id = #{crossId}
</if>
<if test="schedulesId != null and schedulesId != ''">
and s.id = #{schedulesId}
<if test="status != null and status != ''">
and s.status = #{status}
</if>
</select>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment