2025-07-17 15:26:39 +08:00
|
|
|
|
package com.gunshi.project.hsz.service;
|
2024-07-08 17:47:02 +08:00
|
|
|
|
|
|
|
|
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
2025-07-17 15:26:39 +08:00
|
|
|
|
import com.gunshi.project.hsz.mapper.StZvarlBMapper;
|
2025-09-11 14:45:30 +08:00
|
|
|
|
import com.gunshi.project.hsz.model.StZqrlB;
|
2025-07-17 15:26:39 +08:00
|
|
|
|
import com.gunshi.project.hsz.model.StZvarlB;
|
2024-07-08 17:47:02 +08:00
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
|
2025-04-09 14:01:44 +08:00
|
|
|
|
import java.math.BigDecimal;
|
|
|
|
|
|
import java.math.RoundingMode;
|
2025-09-26 17:11:26 +08:00
|
|
|
|
import java.util.Collections;
|
2025-04-09 14:01:44 +08:00
|
|
|
|
import java.util.List;
|
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
|
import java.util.stream.Collectors;
|
2024-07-08 17:47:02 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 描述: 库( 湖)容曲线表
|
|
|
|
|
|
* author: xusan
|
|
|
|
|
|
* date: 2024-07-08 17:30:38
|
|
|
|
|
|
*/
|
|
|
|
|
|
@Service
|
|
|
|
|
|
@Slf4j
|
|
|
|
|
|
@Transactional(rollbackFor = Exception.class)
|
2025-04-09 14:01:44 +08:00
|
|
|
|
public class StZvarlBService extends ServiceImpl<StZvarlBMapper, StZvarlB> {
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 根据水位查表得库容
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param rz 水位
|
|
|
|
|
|
* @return 查表库容
|
|
|
|
|
|
* @author lyf
|
|
|
|
|
|
*/
|
|
|
|
|
|
public BigDecimal getWFromZvarl(BigDecimal rz) {
|
|
|
|
|
|
return getWFromZvarl(rz, BigDecimal.ZERO, list());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 根据水位查表得库容
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param rz 水位
|
|
|
|
|
|
* @param defaultValue 查不到时默认值
|
|
|
|
|
|
* @return 查表库容
|
|
|
|
|
|
* @author lyf
|
|
|
|
|
|
*/
|
|
|
|
|
|
public BigDecimal getWFromZvarl(BigDecimal rz, BigDecimal defaultValue) {
|
|
|
|
|
|
return getWFromZvarl(rz, defaultValue, list());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 根据水位查表得库容
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param rz 水位
|
|
|
|
|
|
* @param defaultValue 查不到时默认值
|
|
|
|
|
|
* @param zvarlList 水位库容关系曲线
|
|
|
|
|
|
* @return 查表库容
|
|
|
|
|
|
* @author lyf
|
|
|
|
|
|
*/
|
|
|
|
|
|
public BigDecimal getWFromZvarl(BigDecimal rz, BigDecimal defaultValue, List<StZvarlB> zvarlList) {
|
|
|
|
|
|
return toMap(zvarlList).getOrDefault(rz.setScale(3, RoundingMode.DOWN), defaultValue);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 将水位库容曲线列表转为字典,水位作为键,注意BigDecimal做键的时候要匹配值和精度
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param zvarlList 水位库容曲线列表
|
|
|
|
|
|
* @return 水位库容曲线字典
|
|
|
|
|
|
* @author lyf
|
|
|
|
|
|
*/
|
|
|
|
|
|
private Map<BigDecimal, BigDecimal> toMap(List<StZvarlB> zvarlList) {
|
|
|
|
|
|
return zvarlList.stream()
|
|
|
|
|
|
.map(item -> Map.entry(item.getRz().setScale(3, RoundingMode.DOWN), item.getW()))
|
|
|
|
|
|
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
|
|
|
|
|
}
|
2024-07-08 17:47:02 +08:00
|
|
|
|
|
2025-09-11 14:45:30 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 分段线性计算水位->库容
|
|
|
|
|
|
* 首先需要保证 水位->库容的数据要按水位从小到大进行排列
|
|
|
|
|
|
* @param zvarlBS
|
|
|
|
|
|
* @param rz
|
|
|
|
|
|
* @return
|
|
|
|
|
|
*/
|
|
|
|
|
|
public BigDecimal getWByZvarl(List<StZvarlB> zvarlBS, BigDecimal rz) {
|
2025-09-26 17:11:26 +08:00
|
|
|
|
//对数据进行排序
|
2025-09-11 14:45:30 +08:00
|
|
|
|
// 1. 参数校验
|
|
|
|
|
|
if (zvarlBS == null || zvarlBS.isEmpty()) {
|
|
|
|
|
|
throw new IllegalArgumentException("水位-库容关系列表不能为空");
|
|
|
|
|
|
}
|
|
|
|
|
|
if (rz == null) {
|
|
|
|
|
|
throw new IllegalArgumentException("水位值不能为空");
|
|
|
|
|
|
}
|
|
|
|
|
|
// 2. 检查边界情况:如果目标水位低于最低水位或高于最高水位
|
|
|
|
|
|
BigDecimal minRz = zvarlBS.get(0).getRz();
|
|
|
|
|
|
BigDecimal maxRz = zvarlBS.get(zvarlBS.size() - 1).getRz();
|
|
|
|
|
|
if (rz.compareTo(minRz) < 0) {
|
|
|
|
|
|
// 低于最低水位,可以选择抛出异常或进行外推(这里选择抛出异常)
|
|
|
|
|
|
return BigDecimal.ZERO;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (rz.compareTo(maxRz) > 0) {
|
|
|
|
|
|
// 高于最高水位,可以选择抛出异常或进行外推(这里选择抛出异常)
|
|
|
|
|
|
return BigDecimal.ZERO;
|
|
|
|
|
|
}
|
|
|
|
|
|
int l = 0;
|
|
|
|
|
|
int r = zvarlBS.size() -1;
|
|
|
|
|
|
//二分查找 由线性On时间复杂度降为Ologn
|
|
|
|
|
|
while (l <= r) {
|
|
|
|
|
|
int mid = l + (r-l) / 2;
|
|
|
|
|
|
BigDecimal midRz = zvarlBS.get(mid).getRz();
|
|
|
|
|
|
int compareResult = midRz.compareTo(rz);
|
|
|
|
|
|
if(compareResult == 0 ){
|
|
|
|
|
|
return zvarlBS.get(mid).getW();
|
|
|
|
|
|
}else if(compareResult < 0){
|
|
|
|
|
|
l = mid + 1;
|
|
|
|
|
|
}else{
|
|
|
|
|
|
r = mid - 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 此时 l 指向第一个大于rz的位置
|
|
|
|
|
|
* r 指向最后一个小于rz的位置
|
|
|
|
|
|
* 既 r为 x1 y1
|
|
|
|
|
|
* l为 x2 y2
|
|
|
|
|
|
*/
|
|
|
|
|
|
if(l < 0 || r >= zvarlBS.size()){
|
|
|
|
|
|
return BigDecimal.ZERO;
|
|
|
|
|
|
}
|
|
|
|
|
|
//获取前后差值的点
|
|
|
|
|
|
StZvarlB lowerPoint = zvarlBS.get(r);
|
|
|
|
|
|
StZvarlB upperPoint = zvarlBS.get(l);
|
|
|
|
|
|
return linearInterpolation(lowerPoint.getRz(),lowerPoint.getW(),upperPoint.getRz(),upperPoint.getW(),rz).setScale(3);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 线性插值辅助方法
|
|
|
|
|
|
* @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);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-07-08 17:47:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|