Commit feda485e authored by hanbing's avatar hanbing

[add] 信号评价,评价指标-路口流量

parent aae93b9c
package net.wanji.opt.bo;
import lombok.Data;
@Data
public class CrossDirDataHistAvgBO {
//方向
private Integer dirType;
//平均通行能力
private Integer avgCapacity;
//平均流量
private Integer avgFlow;
}
......@@ -6,8 +6,10 @@ import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import net.wanji.common.dto.CrossIdDTO;
import net.wanji.common.framework.rest.JsonViewObject;
import net.wanji.opt.dto.CrossIdAndMinutesDTO;
import net.wanji.opt.service.EvaluateService;
import net.wanji.opt.vo.EvaluateCrossDetailVO;
import net.wanji.opt.vo.EvaluateMetricsVO;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
......@@ -43,4 +45,16 @@ public class EvaluateController {
return JsonViewObject.newInstance().success(evaluateCrossDetailVO);
}
@ApiOperation(value = "评价指标", notes = "评价指标", response = JsonViewObject.class,
produces = MediaType.APPLICATION_JSON, consumes = MediaType.APPLICATION_JSON)
@PostMapping(value = "/evaluateMetrics",
produces = MediaType.APPLICATION_JSON, consumes = MediaType.APPLICATION_JSON)
@ApiResponses({
@ApiResponse(code = 200, message = "OK", response = EvaluateMetricsVO.class),
})
public JsonViewObject evaluateMetrics(@RequestBody CrossIdAndMinutesDTO crossIdAndMinutesDTO) {
EvaluateMetricsVO evaluateMetricsVO = evaluateService.evaluateMetrics(crossIdAndMinutesDTO);
return JsonViewObject.newInstance().success(evaluateMetricsVO);
}
}
\ No newline at end of file
package net.wanji.opt.dao.mapper;
import net.wanji.common.po.CrossDirDataRealtimePO;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* @author Kent HAN
* @date 2023/1/11 17:25
*/
@Repository
public interface CrossDirDataRealtimeMapper {
CrossDirDataRealtimePO selectByCrossIdAndDirType(String crossId, Integer key);
List<CrossDirDataRealtimePO> selectByCrossIdAndInOutType(String crossId, Integer inOutType);
}
package net.wanji.opt.dao.mapper.trend;
import net.wanji.opt.bo.CrossDirDataHistAvgBO;
import net.wanji.opt.po.trend.CrossDirDataHistPO;
import org.springframework.stereotype.Repository;
......@@ -17,4 +18,6 @@ public interface CrossDirDataHistMapper {
List<CrossDirDataHistPO> selectByCrossIdAndTimestamp(String crossId, long preSeconds);
List<CrossDirDataHistPO> selectByCrossIdDirAndTimestamp(String crossId, Integer dir, long preSeconds);
List<CrossDirDataHistAvgBO> selectByCrossIdInOutTimestamp(String crossId, Integer inOutType, long preSeconds);
}
package net.wanji.opt.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 方案管理-路口配置-获取路口方向列表输入参数
*
* @author Kent HAN
* @date 2022/12/20 10:17
*/
@Data
public class CrossIdAndMinutesDTO {
@ApiModelProperty(value = "路口ID", required = true)
private String crossId;
@ApiModelProperty(value = "对比时间间隔(分钟)", required = true)
private Integer minutes;
}
package net.wanji.opt.service;
import net.wanji.common.dto.CrossIdDTO;
import net.wanji.opt.dto.CrossIdAndMinutesDTO;
import net.wanji.opt.vo.EvaluateCrossDetailVO;
import net.wanji.opt.vo.EvaluateMetricsVO;
/**
* @author hanbing
......@@ -11,4 +13,6 @@ import net.wanji.opt.vo.EvaluateCrossDetailVO;
public interface EvaluateService {
EvaluateCrossDetailVO evaluateCrossDetail(CrossIdDTO crossIdDTO);
EvaluateMetricsVO evaluateMetrics(CrossIdAndMinutesDTO crossIdAndMinutesDTO);
}
package net.wanji.opt.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import lombok.extern.slf4j.Slf4j;
import net.wanji.common.dto.CrossIdDTO;
import net.wanji.common.enums.CrossInOutEnum;
import net.wanji.common.po.CrossDirDataRealtimePO;
import net.wanji.common.utils.tool.CrossUtil;
import net.wanji.opt.bo.CrossDirDataHistAvgBO;
import net.wanji.opt.dao.mapper.CrossDirDataRealtimeMapper;
import net.wanji.opt.dao.mapper.CrossInfoMapper;
import net.wanji.opt.dao.mapper.CrossSchemeOptLogMapper;
import net.wanji.opt.dao.mapper.trend.CrossDataRealtimeMapper;
import net.wanji.opt.dao.mapper.trend.CrossDirDataHistMapper;
import net.wanji.opt.dto.CrossIdAndMinutesDTO;
import net.wanji.opt.dto.OptDataExtend;
import net.wanji.opt.po.base.CrossInfoPO;
import net.wanji.opt.po.base.CrossSchemeOptLogPO;
import net.wanji.opt.po.trend.CrossDataRealtimePO;
import net.wanji.opt.service.EvaluateService;
import net.wanji.opt.vo.EvaluateCrossDetailVO;
import net.wanji.opt.vo.EvaluateMetricsVO;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author Kent HAN
......@@ -30,13 +42,17 @@ public class EvaluateServiceImpl implements EvaluateService {
private final CrossInfoMapper crossInfoMapper;
private final CrossSchemeOptLogMapper crossSchemeOptLogMapper;
private final CrossDataRealtimeMapper crossDataRealtimeMapper;
private final CrossDirDataRealtimeMapper crossDirDataRealtimeMapper;
private final CrossDirDataHistMapper crossDirDataHistMapper;
private Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
public EvaluateServiceImpl(CrossInfoMapper crossInfoMapper, CrossSchemeOptLogMapper crossSchemeOptLogMapper, CrossDataRealtimeMapper crossDataRealtimeMapper) {
public EvaluateServiceImpl(CrossInfoMapper crossInfoMapper, CrossSchemeOptLogMapper crossSchemeOptLogMapper, CrossDataRealtimeMapper crossDataRealtimeMapper, CrossDirDataRealtimeMapper crossDirDataRealtimeMapper, CrossDirDataHistMapper crossDirDataHistMapper) {
this.crossInfoMapper = crossInfoMapper;
this.crossSchemeOptLogMapper = crossSchemeOptLogMapper;
this.crossDataRealtimeMapper = crossDataRealtimeMapper;
this.crossDirDataRealtimeMapper = crossDirDataRealtimeMapper;
this.crossDirDataHistMapper = crossDirDataHistMapper;
}
@Override
......@@ -53,12 +69,72 @@ public class EvaluateServiceImpl implements EvaluateService {
return evaluateCrossDetailVO;
}
@Override
public EvaluateMetricsVO evaluateMetrics(CrossIdAndMinutesDTO crossIdAndMinutesDTO) {
String crossId = crossIdAndMinutesDTO.getCrossId();
Integer minutes = crossIdAndMinutesDTO.getMinutes();
EvaluateMetricsVO evaluateMetricsVO = new EvaluateMetricsVO();
// 路口流量
List<EvaluateMetricsVO.CrossFlowElement> crossFlow = buildCrossFlow(crossId, minutes);
evaluateMetricsVO.setCrossFlow(crossFlow);
// // 路口排队长度
// List<EvaluateMetricsVO.QueueLengthElement> queueLength = buildQueueLength();
// evaluateMetricsVO.setQueueLength(queueLength);
// // 拥堵指数
// List<EvaluateMetricsVO.TrafficIndexElement> trafficIndex = buildTrafficIndex();
// evaluateMetricsVO.setTrafficIndex(trafficIndex);
// // todo 溢流率
// evaluateMetricsVO.setOverFlowRate(null);
return evaluateMetricsVO;
}
private List<EvaluateMetricsVO.CrossFlowElement> buildCrossFlow(String crossId, Integer minutes) {
List<EvaluateMetricsVO.CrossFlowElement> res = new ArrayList<>();
// 实时数据
List<CrossDirDataRealtimePO> crossDirDataRealtimePOList =
crossDirDataRealtimeMapper.selectByCrossIdAndInOutType(crossId, CrossInOutEnum.IN.getCode());
Map<Integer, List<CrossDirDataRealtimePO>> dirObjMapRealtime = crossDirDataRealtimePOList.stream()
.collect(Collectors.groupingBy(CrossDirDataRealtimePO::getDirType));
// 历史数据
// 获取当前时间之前某分钟的10位时间戳
long currentSeconds = DateUtil.currentSeconds();
// todo 测试用 固定当前时间为1676085300
currentSeconds = 1676085300;
long preSeconds = currentSeconds - minutes * 60;
List<CrossDirDataHistAvgBO> crossDirDataHistAvgBOList = crossDirDataHistMapper.selectByCrossIdInOutTimestamp(
crossId, CrossInOutEnum.IN.getCode(), preSeconds);
Map<Integer, List<CrossDirDataHistAvgBO>> dirObjMapHist = crossDirDataHistAvgBOList.stream()
.collect(Collectors.groupingBy(CrossDirDataHistAvgBO::getDirType));
for (Integer dir : dirObjMapRealtime.keySet()) {
EvaluateMetricsVO.CrossFlowElement crossFlowElement = new EvaluateMetricsVO.CrossFlowElement();
crossFlowElement.setDir(dir);
List<CrossDirDataRealtimePO> realtimeObj = dirObjMapRealtime.get(dir);
if (CollectionUtil.isNotEmpty(realtimeObj)) {
CrossDirDataRealtimePO crossDirDataRealtimePO = realtimeObj.get(0);
crossFlowElement.setCurrentCapacity(crossDirDataRealtimePO.getCapacity());
crossFlowElement.setCurrentFlow(crossDirDataRealtimePO.getFlow());
}
List<CrossDirDataHistAvgBO> histObj = dirObjMapHist.get(dir);
if (CollectionUtil.isNotEmpty(histObj)) {
CrossDirDataHistAvgBO crossDirDataHistAvgBO = histObj.get(0);
crossFlowElement.setCompareCapacity(crossDirDataHistAvgBO.getAvgCapacity());
crossFlowElement.setCompareFlow(crossDirDataHistAvgBO.getAvgFlow());
}
res.add(crossFlowElement);
}
return res;
}
private void fillRealtimeData(EvaluateCrossDetailVO evaluateCrossDetailVO, String crossId) {
CrossDataRealtimePO crossDataRealtimePO = crossDataRealtimeMapper.selectByCrossId(crossId);
evaluateCrossDetailVO.setSceneStartTime(crossDataRealtimePO.getStartTime());
evaluateCrossDetailVO.setDuration(crossDataRealtimePO.getDuration());
// todo 服务水平定义
evaluateCrossDetailVO.setServiceLevel("D");
// 计算服务水平
Double sturation = crossDataRealtimePO.getSturation();
String serviceLevel = CrossUtil.getServiceLevel(sturation);
evaluateCrossDetailVO.setServiceLevel(serviceLevel);
evaluateCrossDetailVO.setFlow(crossDataRealtimePO.getFlow());
evaluateCrossDetailVO.setLength(crossDataRealtimePO.getQueueLength());
evaluateCrossDetailVO.setStopTimes(crossDataRealtimePO.getStopTimes());
......
package net.wanji.opt.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @author Kent HAN
* @date 2023/2/9 8:38
*/
@Data
@NoArgsConstructor
@ApiModel(value = "EvaluateMetricsVO", description = "评价指标")
public class EvaluateMetricsVO {
@ApiModelProperty(value = "路口流量")
private List<CrossFlowElement> crossFlow;
@ApiModelProperty(value = "路口排队长度")
private List<QueueLengthElement> queueLength;
@ApiModelProperty(value = "拥堵指数")
private List<TrafficIndexElement> trafficIndex;
@ApiModelProperty(value = "溢流率")
private List<OverFlowRateElement> overFlowRate;
@NoArgsConstructor
@Data
public static class CrossFlowElement {
@ApiModelProperty(value = "方向:1北;2东北;3东;4东南;5南;6西南;7西;8西北")
private Integer dir;
@ApiModelProperty(value = "当前时段通行能力")
private Integer currentCapacity;
@ApiModelProperty(value = "对比时段通行能力")
private Integer compareCapacity;
@ApiModelProperty(value = "当前时段流量")
private Integer currentFlow;
@ApiModelProperty(value = "当前时段流量")
private Integer compareFlow;
}
@NoArgsConstructor
@Data
public static class QueueLengthElement {
@ApiModelProperty(value = "方向:1北;2东北;3东;4东南;5南;6西南;7西;8西北")
private Integer dir;
@ApiModelProperty(value = "当前时段排队长度")
private Double currentLength;
@ApiModelProperty(value = "对比时段排队长度")
private Double compareLength;
}
@NoArgsConstructor
@Data
public static class TrafficIndexElement {
@ApiModelProperty(value = "方向:1北;2东北;3东;4东南;5南;6西南;7西;8西北")
private Integer dir;
@ApiModelProperty(value = "当前时段拥堵指数")
private Double currentIndex;
@ApiModelProperty(value = "对比时段拥堵指数")
private Double compareIndex;
}
@NoArgsConstructor
@Data
public static class OverFlowRateElement {
@ApiModelProperty(value = "方向:1北;2东北;3东;4东南;5南;6西南;7西;8西北")
private Integer dir;
@ApiModelProperty(value = "当前时段溢流率")
private Double currentRate;
@ApiModelProperty(value = "对比时段溢流率")
private Double compareRate;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="net.wanji.opt.dao.mapper.CrossDirDataRealtimeMapper">
<sql id="baseColumnList">
id,dir_type,in_out_type,cross_id,length,status,traffic_index,start_time,capacity,duration,flow,speed,queue_length,
stop_times,delay_time,sturation,batch_time,gmt_create,gmt_modified,effusion_time
</sql>
<select id="selectByCrossIdAndDirType" resultType="net.wanji.common.po.CrossDirDataRealtimePO">
select <include refid="baseColumnList"/>
from t_cross_dir_data_realtime
where cross_id = #{crossId} and dir_type = #{key} and in_out_type = 1
</select>
<select id="selectByCrossIdAndInOutType" resultType="net.wanji.common.po.CrossDirDataRealtimePO">
select <include refid="baseColumnList"/>
from t_cross_dir_data_realtime
where cross_id = #{crossId} and in_out_type = #{inOutType}
</select>
</mapper>
......@@ -24,4 +24,14 @@
and batch_time <![CDATA[ >= ]]> #{preSeconds}
order by batch_time
</select>
<select id="selectByCrossIdInOutTimestamp" resultType="net.wanji.opt.bo.CrossDirDataHistAvgBO">
SELECT dir_type as dirType, avg(capacity) as avgCapacity, avg(flow) as avgFlow
FROM t_cross_dir_data_hist
WHERE cross_id = #{crossId}
AND in_out_type = #{inOutType}
AND batch_time <![CDATA[ >= ]]> #{preSeconds}
GROUP BY dir_type
</select>
</mapper>
package net.wanji.web.common.enums;
package net.wanji.common.enums;
/**
* @author Kent HAN
* @date 2022/11/8 17:20
*/
public enum CrossInOutEnum {
ONE(1, "进口"),
TWO(2, "出口");
IN(1, "进口"),
OUT(2, "出口");
private final int code;
private final String msg;
......@@ -28,4 +28,8 @@ public enum CrossInOutEnum {
public String getMsg() {
return msg;
}
public Integer getCode() {
return code;
}
}
......@@ -18,4 +18,22 @@ public class CrossUtil {
double[] lonLat = {longitude, latitude};
return lonLat;
}
public static String getServiceLevel(Double sturation) {
String res = "";
if (sturation < 0.4) {
res = "A";
} else if (sturation < 0.6) {
res = "B";
} else if (sturation < 0.75) {
res = "C";
} else if (sturation < 0.9) {
res = "D";
} else if (sturation < 1.0) {
res = "E";
} else {
res = "F";
}
return res;
}
}
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