gunshi-project-ss/src/main/java/com/gunshi/project/hsz/service/RiverWaterService.java

307 lines
11 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package com.gunshi.project.hsz.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.gunshi.project.hsz.entity.so.DataQueryCommonSo;
import com.gunshi.project.hsz.entity.vo.*;
import com.gunshi.project.hsz.mapper.AttResBaseMapper;
import com.gunshi.project.hsz.mapper.StZqRMapper;
import com.gunshi.project.hsz.mapper.StZqrlBMapper;
import com.gunshi.project.hsz.model.*;
import com.gunshi.project.hsz.util.DataHandleUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;
/**
* Description:
* Created by wanyan on 2024/2/21
*
* @author wanyan
* @version 1.0
*/
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class RiverWaterService {
@Resource
private AttResBaseMapper attRvBaseMapper;
@Resource
private StZqrlBMapper stZqrlBMapper;
@Resource
private RainBasinDivisionService rainBasinDivisionService;
@Resource
private AlarmSetService alarmSetService;
@Resource
private StRiverRRealService stRiverRRealService;
@Resource
private StZqRMapper stZqRMapper;//水位-流量关系
public List<AttRvBaseVo> list() {
List<AttRvBaseVo> attRvBaseVos = attRvBaseMapper.queryWaterListUpAndLow();
if(CollectionUtils.isEmpty(attRvBaseVos)){
return attRvBaseVos;
}
return attRvBaseVos;
}
public List<AttRvBaseVo> get(String stcd) {
List<AttRvBaseVo> attRvBaseVos = attRvBaseMapper.queryWaterListByStcd(stcd);
if(CollectionUtils.isEmpty(attRvBaseVos)){
return attRvBaseVos;
}
return attRvBaseVos;
}
public List<StZqrlB> zqrl(String stcd) {
LambdaQueryWrapper<StZqrlB> queryWrapper = Wrappers.lambdaQuery();
queryWrapper.eq(StZqrlB::getStcd, stcd).orderByAsc(StZqrlB::getPtno);
return stZqrlBMapper.selectList(queryWrapper);
}
public BigDecimal getQByRz(List<StZqR> zqr,BigDecimal rz){
// 1. 参数校验
if (zqr == null || zqr.isEmpty()) {
throw new IllegalArgumentException("水位-流量关系列表不能为空");
}
if (rz == null) {
throw new IllegalArgumentException("水位值不能为空");
}
// 2. 检查边界情况:如果目标水位低于最低水位或高于最高水位
BigDecimal minRz = zqr.get(0).getZ();
BigDecimal maxRz = zqr.get(zqr.size() - 1).getZ();
if (rz.compareTo(minRz) < 0) {
// 低于最低水位返回0流量
return BigDecimal.ZERO;
}
if (rz.compareTo(maxRz) > 0) {
// 高于最高水位返回0流量
return BigDecimal.ZERO;
}
// 3. 二分查找水位区间
int l = 0;
int r = zqr.size() - 1;
while (l <= r) {
int mid = l + (r - l) / 2;
BigDecimal midRz = zqr.get(mid).getZ();
int compareResult = midRz.compareTo(rz);
if (compareResult == 0) {
// 找到完全匹配的水位,直接返回对应的流量
return zqr.get(mid).getQ();
} else if (compareResult < 0) {
l = mid + 1;
} else {
r = mid - 1;
}
}
/**
* 此时:
* l 指向第一个大于rz的位置
* r 指向最后一个小于rz的位置
* 即r为 (x1, y1) - 下限水位和流量
* l为 (x2, y2) - 上限水位和流量
*/
if (l >= zqr.size() || r < 0) {
return BigDecimal.ZERO;
}
// 获取前后相邻的两个点
StZqR lowerPoint = zqr.get(r);
StZqR upperPoint = zqr.get(l);
// 使用线性插值计算流量
return linearInterpolation(
lowerPoint.getZ(), lowerPoint.getQ(),
upperPoint.getZ(), upperPoint.getQ(),
rz
).setScale(3, RoundingMode.HALF_UP);
}
/**
* 线性插值辅助方法(可以复用之前的)
* @param x1 已知点1的水位
* @param y1 已知点1的流量
* @param x2 已知点2的水位
* @param y2 已知点2的流量
* @param x 目标水位
* @return 目标水位对应的流量
*/
private BigDecimal linearInterpolation(BigDecimal x1, BigDecimal y1,
BigDecimal x2, BigDecimal y2,
BigDecimal x) {
// 使用公式: y = y1 + ( (y2 - y1) / (x2 - x1) ) * (x - x1)
// 计算斜率: (y2 - y1) / (x2 - x1)
BigDecimal slope = y2.subtract(y1)
.divide(x2.subtract(x1), 10, RoundingMode.HALF_UP);
// 计算: slope * (x - x1)
BigDecimal xDiff = x.subtract(x1);
BigDecimal product = slope.multiply(xDiff);
// 计算最终结果: y1 + product
return y1.add(product);
}
public List<AttRvMonitorVo> monitorData(DataQueryCommonSo dataQueryCommonSo) {
String stcd = dataQueryCommonSo.getStcd();
//雨量数据
List<AttRvMonitorVo> drpData = attRvBaseMapper.drp(dataQueryCommonSo);
//水位数据
List<AttRvMonitorVo> rzData = attRvBaseMapper.rz(dataQueryCommonSo);
//获取水位流量关系,算出转换流量
//List<StZqrlB> zqrl = zqrl(stcd);
List<StZqR> zqr = zqr(stcd);
if(CollectionUtils.isNotEmpty(zqr)){
rzData.stream().forEach(o->{
o.setQ(getQByRz(zqr,o.getZ()));
});
}
//根据监测时间合并雨量和水位数据
return bindData(stcd,drpData,rzData);
}
private List<AttRvMonitorVo> bindData(String stcd, List<AttRvMonitorVo> drpData, List<AttRvMonitorVo> rzData) {
HashSet<Date> strings = new HashSet<>();
drpData.stream().forEach(v1 -> strings.add(v1.getTm()));
rzData.stream().forEach(v1 -> strings.add(v1.getTm()));
ArrayList<AttRvMonitorVo> result = new ArrayList<>();
strings.stream().forEach(v1 -> result.add(AttRvMonitorVo.builder().stcd(stcd).tm(v1).build()));
List<AttRvMonitorVo> list = result.stream().map(v1 -> {
drpData.stream().filter(v2 -> v1.getTm().equals(v2.getTm())).forEach(v2 -> {
v1.setDrp(v2.getDrp());
});
rzData.stream().filter(v2 -> v1.getTm().equals(v2.getTm())).forEach(v2 -> {
v1.setZ(v2.getZ());
v1.setQ(v2.getQ());
v1.setTq(v2.getTq());
});
return v1;
}).collect(Collectors.toList());
return list.stream().sorted(Comparator.comparing(AttRvMonitorVo::getTm).reversed()).collect(Collectors.toList());
}
private void calcTqData(List<AttRvMonitorVo> rzData, List<StZqrlB> zqrl) {
BigDecimal maxRz = zqrl.stream().max(Comparator.comparing(StZqrlB::getZ)).get().getZ();
BigDecimal minRz = zqrl.stream().min(Comparator.comparing(StZqrlB::getZ)).get().getZ();
Map<BigDecimal, BigDecimal> map = zqrl.stream().collect(Collectors.toMap(StZqrlB::getZ, StZqrlB::getQ));
List<BigDecimal> list = zqrl.stream().map(StZqrlB::getZ).collect(Collectors.toList());
for(AttRvMonitorVo vo : rzData){
BigDecimal rz = vo.getZ();
if(rz.compareTo(minRz) < 0 || rz.compareTo(maxRz) > 0){
continue;
}
vo.setTq(DataHandleUtil.calcData(rz,map,list));
}
}
public AttRvMonitorDetailVo detail(String stcd) {
AttRvMonitorDetailVo vo = new AttRvMonitorDetailVo();
StPptnDetailsVo stPptnDetailsVo = rainBasinDivisionService.queryStPptnDetailsByStcd(stcd);
BeanUtils.copyProperties(stPptnDetailsVo,vo,AttRvMonitorDetailVo.class);
//最新水位
AttRvMonitorVo monitorVo = attRvBaseMapper.newRz(stcd);
if(monitorVo == null){
return vo;
}
Date tm = monitorVo.getTm();
BigDecimal rz = monitorVo.getZ();
//最新水位时间往前推24小时水位
LocalDateTime now = LocalDateTime.ofInstant(tm.toInstant(), ZoneId.systemDefault());
LocalDateTime dateTime = now.minusDays(1);
BigDecimal oldRz = attRvBaseMapper.oldRz(stcd,1,Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant()));
if(oldRz != null){
//设置水位涨跌情况
vo.setRzDiff(rz.subtract(oldRz));
}
//本年最高水位
BigDecimal maxYearRz = queryYearRzByStcdAndTime(stcd);
vo.setMaxRz(maxYearRz);
return vo;
}
private BigDecimal queryYearRzByStcdAndTime(String stcd) {
LocalDateTime now = LocalDateTime.ofInstant(new Date().toInstant(), ZoneId.systemDefault());
LocalDateTime startTime;
LocalDateTime endTime;
if (now.getHour() >= 8 || (now.getHour() < 8 && now.getMonthValue() > 1) || (now.getHour() < 8 && now.getMonthValue() == 1 && now.getDayOfMonth() >= 1)){
startTime = LocalDateTime.of(
now.getYear(),
1,
1,
8,
0,
0
);
endTime = now;
return attRvBaseMapper.queryRiverMaxRz(stcd,Date.from(startTime.atZone(ZoneId.systemDefault()).toInstant()), Date.from(endTime.atZone(ZoneId.systemDefault()).toInstant()));
}
return new BigDecimal(0);
}
public AttRiverNowDataVo nowData(String stcd) {
AttRiverNowDataVo vo = new AttRiverNowDataVo();
LambdaQueryWrapper<AlarmSet> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(AlarmSet::getStcd,stcd);
AlarmSet alarmSet = alarmSetService.getBaseMapper().selectOne(queryWrapper);//查询该站点的警告水位配置信息
if(alarmSet == null){
vo.setWaterAlarm(BigDecimal.ZERO);
vo.setWaterPromise(BigDecimal.ZERO);
}else{
vo.setWaterAlarm(alarmSet.getWarnWaterLevel());
vo.setWaterPromise(alarmSet.getPromiseWaterLevel());
}
StPptnRReal stPptnRReal = rainBasinDivisionService.queryStPptnRealByStcd(stcd);//查询该站点的实时降雨
BeanUtils.copyProperties(stPptnRReal,vo);
//查询该站点实时水位
StRiverRReal stRiverRReal = stRiverRRealService.getBaseMapper().queryQByStcd(stcd);
if(stRiverRReal == null){
return vo;
}
BigDecimal z = stRiverRReal.getZ() == null ? BigDecimal.ZERO : stRiverRReal.getZ();
vo.setRz(z);
vo.setWaterAlarmGap(z.subtract(vo.getWaterAlarm()));
vo.setWaterPromiseGap(z.subtract(vo.getWaterPromise()));
return vo;
}
public List<StZqR> zqr(String stcd){
LambdaQueryWrapper<StZqR> queryWrapper = Wrappers.lambdaQuery();
queryWrapper.eq(StZqR::getStcd, stcd).orderByAsc(StZqR::getZ);
return stZqRMapper.selectList(queryWrapper);
}
}