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

165 lines
5.4 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.extension.service.impl.ServiceImpl;
import com.gunshi.project.hsz.mapper.StZvarlBMapper;
import com.gunshi.project.hsz.model.StZqrlB;
import com.gunshi.project.hsz.model.StZvarlB;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 描述: 库( 湖)容曲线表
* author: xusan
* date: 2024-07-08 17:30:38
*/
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
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));
}
/**
* 分段线性计算水位->库容
* 首先需要保证 水位->库容的数据要按水位从小到大进行排列
* @param zvarlBS
* @param rz
* @return
*/
public BigDecimal getWByZvarl(List<StZvarlB> zvarlBS, BigDecimal rz) {
//对数据进行排序
// 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);
}
}